Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Добавляет рецепт приготовления многоуровневого меню. #4992

Merged
merged 24 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
025465a
Добавляет рецепт приготовления многоуровневого меню. Пытается в досту…
s-dudko Nov 18, 2023
3abc96b
Правит путь к картинке
s-dudko Nov 18, 2023
2600a1d
Добавляет мобильные стили для демо
s-dudko Nov 18, 2023
6960777
Добавляет упоминание о мобильно меню черзе бургер
s-dudko Nov 18, 2023
223fece
Правит отступы в js примере
s-dudko Nov 18, 2023
032930c
Удаляет role list с тегов ul
s-dudko Nov 24, 2023
6f45aea
Редачит текст
TatianaFokina Nov 27, 2023
b7a030f
Форматирует код демки, объединяет файлы
TatianaFokina Nov 27, 2023
6787427
Снова редачит текст
TatianaFokina Nov 27, 2023
7738f12
Удаляет табы
TatianaFokina Nov 27, 2023
b97cfbf
Исправляет ошибки, улучшает текст
TatianaFokina Nov 27, 2023
ebf82fb
Причёсывает демку
TatianaFokina Nov 27, 2023
eafdc1c
Немного улучшает демку
TatianaFokina Nov 27, 2023
06620e4
Добавляет в индекс раздела
TatianaFokina Nov 27, 2023
29695db
Добавляет контрибьютеров, укорачивает строки
TatianaFokina Nov 27, 2023
326f0b6
Update recipes/dropdown-menu/index.md
s-dudko Nov 30, 2023
2922463
Update recipes/dropdown-menu/index.md
s-dudko Nov 30, 2023
a07ddfb
Правит кавычки
s-dudko Nov 30, 2023
ec0e777
Добавляет связанные статьи
s-dudko Nov 30, 2023
e781d27
Правит ссылку
s-dudko Nov 30, 2023
cec97a0
Тюнит демку
skorobaeus Nov 30, 2023
81c484e
Merge branch 'feature/2737' of https://github.com/s-dudko/doka-conten…
skorobaeus Nov 30, 2023
1133f84
Обновляет схему
skorobaeus Dec 1, 2023
36f9ea9
Обновляет пример css стилей в статье
s-dudko Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
382 changes: 382 additions & 0 deletions recipes/dropdown-menu/demos/menu/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,382 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Реализация выпадающего меню — Выпадающее меню — Дока</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap">
<style>
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html {
font-size: 18px;
color-scheme: dark;
}

body {
min-height: 100vh;
margin: 0;
padding: 50px;
background-color: #18191c;
text-align: center;
font-family: "Roboto", sans-serif;
}

ul, li {
list-style: none;
padding: 0;
margin: 0;
text-align: start;
}

button:focus-visible,
a:focus-visible {
outline: 2px solid;
outline-offset: 2px;
}

.header {
display: flex;
gap: 2rem;
align-items: center;
background-color: #C56FFF;
padding: .7rem;
}

.menu {
display: flex;
gap: 64px;
min-width: max-content;
background: #C56FFF;
color: #000000;
}

.menu-submenu {
background: #FFFFFF;
}

.menu__btn,
.menu__link {
display: flex;
width: 100%;
gap: .5em;
align-items: center;
padding: .75rem 1.5rem;
font-size: 1.125rem;
color: #000000;
cursor: pointer;
border: none;
background: transparent;
transition: background-color 0.2s linear;
}

.menu__link:hover,
.menu__btn:hover,
.menu__btn[aria-expanded="true"] {
background-color: #FFFFFF;
}

.menu-submenu .menu__link:hover,
.menu-submenu .menu__btn:hover,
.menu-submenu .menu__btn[aria-expanded="true"] {
background-color: #C56FFF;
}

.menu-submenu .menu__link:focus-visible,
.menu-submenu .menu__btn:focus-visible {
outline-width: 2px;
outline-offset: -3px;
outline-style: solid;
outline-color: #000000;
}

.menu__btn-icon {
color: inherit;
transition: transform .1s linear;
}

.menu__btn[aria-expanded="true"] .menu__btn-icon {
transform: rotate(180deg);
}

.menu__item {
position: relative;
}

.menu__link {
text-decoration: none;
}

a[aria-current="page"] {
font-weight: 500;
color: #000000;
}

/* Вложенное меню */
.menu .menu {
display: flex;
flex-direction: column;
gap: 8px;
padding-inline-start: 3rem;
}

/* Первый уровень вложенности */
.enhanced .menu .menu {
position: absolute;
top: 110%;
left: 0;
padding-inline-start: 0;
}

/* Второй уровень вложенности */
.enhanced .menu .menu .menu {
top: 0;
left: 104%;
}

.menu[hidden] {
display: none;
}

.main {
display: flex;
flex-direction: column;
align-items: start;
width: 100%;
padding-block-start: 64px;
}

h1 {
margin-bottom: 17px;
font-weight: 500;
font-size: 1.625rem;
}

.main a {
border-radius: 3px;
color: inherit;
-webkit-text-decoration-color: #C56FFF;
text-decoration-color: #C56FFF;
text-decoration-thickness: 2px;
transition: background-color 0.2s linear;
}

.main a:hover, .main a:focus {
color: #000000;
background-color: #C56FFF;
transition: background-color 0.2s linear;
outline-width: 0;
}

@media all and (max-width: 768px) {
body {
padding: 30px;
}

.site-nav {
width: 100%;
}

.menu {
display: flex;
flex-direction: column;
width: 100%;
gap: 16px;
}

.menu__btn {
width: 100%;
justify-content: space-between;
}

/* Первый уровень вложенности */
.enhanced .menu .menu,
.enhanced .menu .menu .menu {
position: relative;
top: 0;
left: 0;
padding-inline-start: 1em;
padding-inline-end: 1em;
}
}
</style>
</head>
<body>
<header class="header">
<nav class="site-nav" aria-label="Сайт">
<ul class="menu">
<li class="menu__item" data-has-children>
<span data-controls="doka-submenu">Дока</span>

<ul class="menu menu-submenu" id="doka-submenu">
<li class="menu__item">
<a href="#" class="menu__link" aria-current="page">Рецепты</a>
</li>
<li class="menu__item" data-has-children>
<span data-controls="html-submenu">HTML</span>

<ul class="menu menu-submenu" id="html-submenu">
<li class="menu__item">
<a href="#" class="menu__link">Основы</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Форматирование</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Семантика</a>
</li>
</ul>
</li>
<li class="menu__item" data-has-children>
<span data-controls="css-submenu">CSS</span>

<ul class="menu menu-submenu" id="css-submenu">
<li class="menu__item">
<a href="#" class="menu__link">Основы</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Селекторы</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Псевдоклассы</a>
</li>
</ul>
</li>
<li class="menu__item">
<a href="#" class="menu__link">JavaScript</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Доступность</a>
</li>
</ul>
</li>

<li class="menu__item">
<a href="#" class="menu__link">Новости</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Блог</a>
</li>
<li class="menu__item">
<a href="#" class="menu__link">Архив</a>
</li>
</ul>
</nav>
</header>

<main class="main">
<h1>Рецепты</h1>
<a href="#">Как приготовить меню 👨‍🍳</a>
</main>

<script>
// Следуем принципам прогрессивного улучшения.
// Показываем пользователю простую навигацию в случае, если не удаётся загрузить JavaScript.
// Если JavaScript-файл загружен, заменяем span на кнопки и вешаем дополнительные ARIA-атрибуты.

const nav = document.querySelector('.site-nav')
nav.classList.add("enhanced")

const submenus = document.querySelectorAll(".menu__item[data-has-children]")
const dropdowns = document.querySelectorAll(".menu__item[data-has-children] > .menu")

const icon = `
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
aria-hidden="true"
class="menu__btn-icon"
>
<path fill="currentColor" d="M5.293 9.707l6 6c0.391 0.391 1.024 0.391 1.414 0l6-6c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"></path>
</svg>
`

// Находим подменю, заменяем в нём span на кнопку
submenus.forEach((item) => {
const dropdown = item.querySelector(":scope > .menu")
dropdown.setAttribute("hidden", "")

const span = item.querySelector(":scope > span")
const text = span.innerText
const ariaControlsId = span.dataset.controls

const button = document.createElement("button")

// Добавляем класс и необходимые ARIA-атрибуты
button.classList.add("menu__btn")
button.setAttribute("aria-expanded", "false")
button.setAttribute("aria-controls", ariaControlsId)

button.innerText = text

// Добавляем иконку к кнопке, чтобы визуально было понятно открыто меню или нет
button.innerHTML += icon

span.replaceWith(button)

button.addEventListener("click", function (e) {
toggleDropdown(button, dropdown)
})

// Обрабатываем нажатие на Esc
dropdown.addEventListener("keydown", (e) => {
e.stopImmediatePropagation()

if (e.keyCode === 27 && focusIsInside(dropdown)) {
toggleDropdown(button, dropdown)
button.focus()
}
}, false)
})

function toggleDropdown(button, dropdown) {
if (button.getAttribute("aria-expanded") === "true") {
button.setAttribute("aria-expanded", "false")
dropdown.setAttribute("hidden", "")
} else {
button.setAttribute("aria-expanded", "true")
dropdown.removeAttribute("hidden")
}
}

function focusIsInside(element) {
return element.contains(document.activeElement)
}

function collapseDropdownsWhenTabbingOutsideNav(e) {
if (e.keyCode === 9 && !focusIsInside(nav)) {
dropdowns.forEach(function (dropdown) {
dropdown.setAttribute("hidden", "")
const btn = dropdown.parentNode.querySelector("button")
btn.setAttribute("aria-expanded", "false")
})
}
}

function collapseDropdownsWhenClickingOutsideNav(e) {
const target = e.target

dropdowns.forEach(function (dropdown) {
if (!dropdown.parentNode.contains(target)) {
dropdown.setAttribute("hidden", "")
const btn = dropdown.parentNode.querySelector("button")
btn.setAttribute("aria-expanded", "false")
}
})
}

// Закрываем навигацию, если протапались за её пределы
document.addEventListener("keyup", collapseDropdownsWhenTabbingOutsideNav)

// Закрываем навигацию, если кликнули вне навигации
window.addEventListener("click", collapseDropdownsWhenClickingOutsideNav)
</script>
</body>
</html>
Binary file added recipes/dropdown-menu/images/pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading