Browse Source

side bar menu styles

master
rdrew 2 weeks ago
parent
commit
e92ffbef0b
  1. 9
      css/base.css
  2. 110
      css/components/menu.css
  3. 122
      css/components/unsorted.css
  4. 23
      css/layout.css
  5. 8
      druid.libraries.yml
  6. 59
      druid.theme
  7. 86
      js/druid.behaviors.js

9
css/base.css

@ -31,18 +31,19 @@
} }
h1 { h1 {
font-size: var(--font-size-6); font-size: var(--font-size-6);
font-weight: normal;
} }
h2 { h2 {
font-size: var(--font-size-5); font-size: var(--font-size-4);
} }
h3 { h3 {
font-size: var(--font-size-4); font-size: var(--font-size-3);
} }
h4 { h4 {
font-size: var(--font-size-3); font-size: var(--font-size-2);
} }
h5 { h5 {
font-size: var(--font-size-2); font-size: var(--font-size-1);
} }
h6 { h6 {
font-size: var(--font-size-1); font-size: var(--font-size-1);

110
css/components/menu.css

@ -1,38 +1,86 @@
@layer components { @layer components {
/**
/**
* @file * @file
* Visual styles for menu. * Visual styles for menu.
*/ */
ul.menu { ul.menu {
margin-left: 1em; /* LTR */ margin-left: 1em; /* LTR */
padding: 0; padding: 0;
list-style: none outside; list-style: none outside;
text-align: left; /* LTR */ text-align: left; /* LTR */
} }
[dir="rtl"] ul.menu { [dir="rtl"] ul.menu {
margin-right: 1em; margin-right: 1em;
margin-left: 0; margin-left: 0;
text-align: right; text-align: right;
} }
.menu-item--expanded { .menu-item--expanded {
list-style-type: circle; list-style-type: circle;
list-style-image: url(../../images/icons/menu-expanded.png); list-style-image: url(../../images/icons/menu-expanded.png);
} }
.menu-item--collapsed { .menu-item--collapsed {
list-style-type: disc; list-style-type: disc;
list-style-image: url(../../images/icons/menu-collapsed.png); /* LTR */ list-style-image: url(../../images/icons/menu-collapsed.png); /* LTR */
} }
[dir="rtl"] .menu-item--collapsed { [dir="rtl"] .menu-item--collapsed {
list-style-image: url(../../images/icons/menu-collapsed-rtl.png); list-style-image: url(../../images/icons/menu-collapsed-rtl.png);
} }
.menu-item { .menu-item {
margin: 0; margin: 0;
padding-top: 0.2em; padding-top: 0.2em;
} }
ul.menu a.is-active { ul.menu a.is-active {
color: #000; color: #000;
} }
/* dropdown behaviours */
/* add the region with a menu in it to convert to a dropdown */
/* check the menu js behaviour when adding new dropdowns */
header {
.menu {
display: flex;
}
.menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.menu > ul {
display: flex;
gap: 1rem;
}
.menu li {
position: relative;
}
/* Hide submenus */
.menu li ul {
position: absolute;
top: 100%;
left: 0;
display: none;
min-width: 200px;
background: white;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
/* Show submenu on hover */
.menu li:hover > ul {
display: block;
}
/* Optional styling */
.menu a {
display: block;
padding: 0.75rem 1rem;
text-decoration: none;
}
.menu li ul li a {
padding: 0.5rem 1rem;
}
}
} }

122
css/components/unsorted.css

@ -0,0 +1,122 @@
@layer components {
/* ======================================= */
/* sidebar menu styles */
/* ======================================= */
/* sliding yellow links, no dropdowns */
.null.region-sidebar-second {
.menu {
margin: 0;
}
.menu a {
text-decoration: none;
display: block;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAARCAYAAADkIz3lAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNpi/PPnz//Xb98xMDMy7mFgYHBlgAImZiYGZMB0++59Bke/SIbKlm4XBkbGbUDMAMZogOnps+cv//3/y7Bq0zaGsoZ2z1+/fq4DYkyFP3/+MK0vyXkiLS7KsGL9Vob6zomBzMzMK4BybMgKmSMiIj+xs7JuNtbX8bl9/5Hg7oNHGd6+fa9jY26szMbKugvoiF8ghzAnpaQwsLKyvuPj5dmtpa7scvPWPRGQ4u8/f+o62FjIsbOz7wPa8JM5OjqG4f+/fyD8hpeba7++jqbdw8fPxDbv3sfw4eMnPUtTQ1mgwgPM0bFxyE55zcPNdVhJXsby0ZPnkrsPHmP4+vWbnrG+rjzDi+fPsOHSurae/yxiKv8ZBOX+r1y/+T8Lv6AgekgY3bn3MPHYmQsMf/78ZvB1d2bgZGWZy/Dp0ydkbHD2wuXbdj5h/xmEFf4Hxqb+37Zrz+xde/fzsfz+8wdmku7Dx083FtW2yB0+fprB3cGGISLAa/avnz8LfjEwfGOBRpbGo6fP9uRWNoidPHORwdfDmSEjIWIuEyNjNlDuNzRmfik8ePzsWHZZvdi5i1cZnG3MGWKDfBZ9/fQlBaYIBFjevv9wMbO0hu/ajdsMTjYWDPnpCauA4vEgyX///sJ9yPLp02e+p89eMFgY6zMkRwZv+vLpczhMkouHC66Q8efPn/9v3r7L8PPXr+1AvhdyOL199xbOBggwAPE+9T0FxGv+AAAAAElFTkSuQmCC);
background-position: 96% 10px;
background-repeat: no-repeat;
padding: 6px 20px 6px 0;
background-color: transparent;
color: #192a36;
/* display: inline-block; */
/* padding: 0 3px; */
margin-left: 0;
margin-right: -3px;
position: relative;
text-decoration: none;
transition: color ease 0.3s;
z-index: 0;
}
li.menu-item {
border-bottom: 2px solid var(--upei-orange);
font-size: 16px;
padding-top: 0;
a:before {
content: "";
position: absolute;
z-index: -1;
width: 0;
height: 100%;
left: 0;
bottom: 0;
background-color: var(--upei-orange);
transition: all ease 0.3s;
}
a:hover:before {
width: 100%;
}
}
}
/* sidebar block menu with dropdowns (may need to adjust .block-menu and/or regions) */
/* *see the associated behavior */
.region-sidebar-second {
nav h2 {
margin-bottom: 0;
}
nav ul.menu li a {
text-decoration: none;
padding: 7px 0 7px 10px;
display: block;
border-bottom: 2px solid #8c2004;
color: #192a36;
}
.menu {
margin: 0;
/* margin-bottom: 1rem; */
}
.menu-item {
padding: 0;
}
.menu-item--expanded .menu a {
margin-left: 1em;
border: none;
}
/* Hide nested menus by default */
.block-menu .menu-item--expanded > ul {
display: none;
}
/* Show when open */
.block-menu .menu-item--expanded.open > ul {
display: block;
}
/* Position container */
.block-menu .menu-item--expanded {
position: relative;
list-style-type: none;
list-style-image: none;
}
/* Caret button */
.block-menu .menu-caret {
position: absolute;
right: 0.5rem;
top: 0.75rem;
cursor: pointer;
font-size: 0.8rem;
user-select: none;
}
/* Optional caret icon (triangle) */
.block-menu .menu-caret::after {
content: "▼";
}
/* Rotate when open */
.block-menu .menu-item--expanded.open > .menu-caret::after {
transform: rotate(180deg);
display: inline-block;
}
.block-menu .menu-item--expanded > ul {
display: block;
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease;
}
.block-menu .menu-item--expanded.open > ul {
max-height: 500px;
}
}
}

23
css/layout.css

@ -18,7 +18,6 @@
* responsiveness see todo.md for the rationale. * responsiveness see todo.md for the rationale.
*/ */
@layer layout { @layer layout {
.content-rail { .content-rail {
max-width: var(--content-max-width); max-width: var(--content-max-width);
margin-inline: auto; margin-inline: auto;
@ -36,6 +35,7 @@
padding-block: var(--size-3); padding-block: var(--size-3);
} }
.region-header,
.top-nav__inner { .top-nav__inner {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -65,7 +65,9 @@
No-sidebar pages skip the grid entirely; .layout-content just fills No-sidebar pages skip the grid entirely; .layout-content just fills
its parent rail. */ its parent rail. */
body:is(.layout-sidebar-first, .layout-sidebar-second, .layout-two-sidebars) main > .content-rail { body:is(.layout-sidebar-first, .layout-sidebar-second, .layout-two-sidebars)
main
> .content-rail {
display: grid; display: grid;
gap: var(--size-4); gap: var(--size-4);
grid-template-columns: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr);
@ -81,9 +83,15 @@
grid-template-areas: "content" "first" "second"; grid-template-areas: "content" "first" "second";
} }
.layout-content { grid-area: content; } .layout-content {
.layout-sidebar-first { grid-area: first; } grid-area: content;
.layout-sidebar-second { grid-area: second; } }
.layout-sidebar-first {
grid-area: first;
}
.layout-sidebar-second {
grid-area: second;
}
/* Tablet+: single-sidebar layouts side-by-side. */ /* Tablet+: single-sidebar layouts side-by-side. */
@media (min-width: 768px) { @media (min-width: 768px) {
@ -100,9 +108,10 @@
/* Small-desktop+: two-sidebar layout becomes three columns. */ /* Small-desktop+: two-sidebar layout becomes three columns. */
@media (min-width: 1024px) { @media (min-width: 1024px) {
body.layout-two-sidebars main > .content-rail { body.layout-two-sidebars main > .content-rail {
grid-template-columns: var(--sidebar-width) minmax(0, 1fr) var(--sidebar-width); grid-template-columns: var(--sidebar-width) minmax(0, 1fr) var(
--sidebar-width
);
grid-template-areas: "first content second"; grid-template-areas: "first content second";
} }
} }
} }

8
druid.libraries.yml

@ -122,6 +122,8 @@ components:
weight: -10 weight: -10
css/components/ui-dialog.css: css/components/ui-dialog.css:
weight: -10 weight: -10
css/components/unsorted.css:
weight: -10
dialog: dialog:
version: VERSION version: VERSION
css: css:
@ -144,12 +146,12 @@ image-widget:
version: VERSION version: VERSION
css: css:
component: component:
css/components/image-widget.css: { } css/components/image-widget.css: {}
indented: indented:
version: VERSION version: VERSION
css: css:
component: component:
css/components/indented.css: { } css/components/indented.css: {}
messages: messages:
version: VERSION version: VERSION
css: css:
@ -184,7 +186,7 @@ search-results:
version: VERSION version: VERSION
css: css:
component: component:
css/components/search-results.css: { } css/components/search-results.css: {}
user: user:
version: VERSION version: VERSION
css: css:

59
druid.theme

@ -15,37 +15,44 @@
* - layout-one-sidebar + layout-sidebar-second (only sidebar_second has content) * - layout-one-sidebar + layout-sidebar-second (only sidebar_second has content)
* - layout-two-sidebars * - layout-two-sidebars
*/ */
function druid_preprocess_html(array &$variables): void { function druid_preprocess_html(array &$variables): void
$has_first = !empty($variables['page']['sidebar_first']); {
$has_second = !empty($variables['page']['sidebar_second']); $has_first = !empty($variables['page']['sidebar_first']);
$has_second = !empty($variables['page']['sidebar_second']);
if ($has_first && $has_second) { if ($has_first && $has_second) {
$variables['attributes']['class'][] = 'layout-two-sidebars'; $variables['attributes']['class'][] = 'layout-two-sidebars';
} } elseif ($has_first) {
elseif ($has_first) { $variables['attributes']['class'][] = 'layout-one-sidebar';
$variables['attributes']['class'][] = 'layout-one-sidebar'; $variables['attributes']['class'][] = 'layout-sidebar-first';
$variables['attributes']['class'][] = 'layout-sidebar-first'; } elseif ($has_second) {
} $variables['attributes']['class'][] = 'layout-one-sidebar';
elseif ($has_second) { $variables['attributes']['class'][] = 'layout-sidebar-second';
$variables['attributes']['class'][] = 'layout-one-sidebar'; } else {
$variables['attributes']['class'][] = 'layout-sidebar-second'; $variables['attributes']['class'][] = 'layout-no-sidebars';
} }
else {
$variables['attributes']['class'][] = 'layout-no-sidebars';
}
} }
/** /**
* Implements hook_preprocess_image_widget(). * Implements hook_preprocess_image_widget().
*/ */
function druid_preprocess_image_widget(array &$variables): void { function druid_preprocess_image_widget(array &$variables): void
$data = &$variables['data']; {
$data = &$variables['data'];
// This prevents image widget templates from rendering preview container HTML // This prevents image widget templates from rendering preview container HTML
// to users that do not have permission to access these previews. // to users that do not have permission to access these previews.
// @todo revisit in https://drupal.org/node/953034 // @todo revisit in https://drupal.org/node/953034
// @todo revisit in https://drupal.org/node/3114318 // @todo revisit in https://drupal.org/node/3114318
if (isset($data['preview']['#access']) && $data['preview']['#access'] === FALSE) { if (isset($data['preview']['#access']) && $data['preview']['#access'] === false) {
unset($data['preview']); unset($data['preview']);
} }
}
function druid_preprocess_menu(&$variables)
{
foreach ($variables['items'] as &$item) {
if (!empty($item['below'])) {
$item['attributes']->addClass('has-dropdown');
}
}
} }

86
js/druid.behaviors.js

@ -68,4 +68,90 @@
// }); // });
// }, // },
// }; // };
Drupal.behaviors.mainMenuToggle = {
attach(context) {
once(
"dropdown-menu-toggle",
"nav .menu li.menu-item--expanded > a",
context
).forEach((link) => {
let touched = false;
const handler = function (e) {
// Prevent duplicate firing (touch + click)
if (e.type === "click" && touched) {
touched = false;
return;
}
if (e.type === "touchstart") {
touched = true;
}
const parent = this.parentElement;
const submenu = parent.querySelector("ul");
// Only toggle if submenu exists
if (submenu) {
e.preventDefault();
parent.classList.toggle("open");
}
};
// Mobile-first interaction
link.addEventListener("touchstart", handler, { passive: true });
// Desktop + accessibility fallback
link.addEventListener("click", handler);
});
},
};
})(Drupal, once);
((Drupal, once) => {
Drupal.behaviors.sidebarMenuDropdown = {
attach(context) {
once(
"sidebar-menu-dropdown",
".block-menu .menu-item--expanded",
context
).forEach((item) => {
const link = item.querySelector("a");
const submenu = item.querySelector("ul");
if (!submenu || !link) return;
// ✅ Create caret element
const caret = document.createElement("span");
caret.className = "menu-caret";
caret.setAttribute("aria-expanded", "false");
// Insert caret after link
link.insertAdjacentElement("afterend", caret);
let touched = false;
const toggleMenu = (e) => {
// Prevent touch + click double fire
if (e.type === "click" && touched) {
touched = false;
return;
}
if (e.type === "touchstart") {
touched = true;
}
e.preventDefault();
e.stopPropagation();
const isOpen = item.classList.toggle("open");
caret.setAttribute("aria-expanded", isOpen);
};
// ✅ Only caret toggles menu (link still navigates)
caret.addEventListener("touchstart", toggleMenu, { passive: false });
caret.addEventListener("click", toggleMenu);
});
},
};
})(Drupal, once); })(Drupal, once);

Loading…
Cancel
Save