You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/components/navigation-menu/navigation-menu.css

269 lines
8.2 KiB

/*
* NavigationMenu recipe — top-level site navigation with mega-menus.
*
* [data-navigation-menu] → root bar
* [data-navigation-menu-list] → <ul> of items
* [data-navigation-menu-item] → wrapper for each trigger+content pair
* [data-navigation-menu-trigger] → in-bar button that opens Content
* [data-navigation-menu-content] → mega-menu panel (per Item)
* [data-navigation-menu-link] → one-shot anchor (no Content)
* [data-navigation-menu-indicator] → arrow / underline tracking the active trigger
*
* Sizes — sm | md | lg via `data-size` on the root.
*
* Distinct from dropdown-menu (floating click-driven) and menubar
* (roving tabindex bar). NavigationMenu is an INLINE list that
* persists in the page chrome; per-item Content panels render via
* Floating layer but are conceptually attached to the bar, not
* portaled away.
*/
[data-navigation-menu] {
--_navigation-menu-trigger-px: var(--space-3);
--_navigation-menu-list-gap: var(--space-1);
--_navigation-menu-font-size: var(--font-size-sm);
--_navigation-menu-radius: var(--radius-md);
position: relative;
display: inline-flex;
flex-direction: column;
align-items: stretch;
font-family: var(--font-ui);
font-size: var(--_navigation-menu-font-size);
line-height: var(--leading-ui);
}
[data-navigation-menu][data-size='sm'] {
--_navigation-menu-trigger-px: var(--space-2);
--_navigation-menu-list-gap: 0;
--_navigation-menu-font-size: var(--font-size-xs);
--_navigation-menu-radius: var(--radius-sm);
}
[data-navigation-menu][data-size='lg'] {
--_navigation-menu-trigger-px: var(--space-4);
--_navigation-menu-list-gap: var(--space-2);
--_navigation-menu-font-size: var(--font-size-md);
--_navigation-menu-radius: var(--radius-lg);
}
/* ── List ─ */
[data-navigation-menu-list] {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--_navigation-menu-list-gap);
margin: 0;
padding: 0;
list-style: none;
}
[data-navigation-menu][data-orientation='vertical'] [data-navigation-menu-list] {
flex-direction: column;
align-items: stretch;
}
/* ── Item ─
*
* `position: relative` makes the Item the positioning anchor for its
* Content panel — Content is `position: absolute` below so opening it
* doesn't push the bar. The Item only lays out its Trigger / Link
* inline.
*/
[data-navigation-menu-item] {
position: relative;
display: inline-flex;
align-items: center;
}
/* ── Trigger (and Link share the same in-bar chrome) ─ */
[data-navigation-menu-trigger],
[data-navigation-menu-link] {
display: inline-flex;
align-items: center;
gap: var(--space-1);
padding-block: var(--space-2);
padding-inline: var(--_navigation-menu-trigger-px);
border: none;
border-radius: var(--_navigation-menu-radius);
background: transparent;
color: var(--color-content-primary);
font: inherit;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
outline: none;
transition:
background var(--duration-fast) var(--ease-default),
color var(--duration-fast) var(--ease-default);
}
[data-navigation-menu-trigger]:hover:not([data-disabled]),
[data-navigation-menu-link]:hover:not([data-disabled]) {
background: var(--color-surface-overlay);
}
[data-navigation-menu-trigger][data-state='open'],
[data-navigation-menu-trigger][data-state='open']:hover {
background: var(--color-primary-element);
color: var(--color-content-primary);
}
[data-navigation-menu-link][aria-current='page'],
[data-navigation-menu-link][data-active] {
background: var(--color-primary-element);
color: var(--color-content-primary);
}
[data-navigation-menu-trigger]:focus-visible,
[data-navigation-menu-link]:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: 1px;
}
[data-navigation-menu-trigger][data-disabled],
[data-navigation-menu-link][data-disabled] {
color: var(--color-content-muted);
pointer-events: none;
cursor: default;
}
/* Trigger chevron — points down by default, rotates when open. */
[data-navigation-menu-trigger]::after {
content: '';
display: inline-block;
inline-size: 0.5rem;
block-size: 0.5rem;
margin-inline-start: var(--space-1);
border-block-end: 1.5px solid currentColor;
border-inline-end: 1.5px solid currentColor;
transform: translateY(-1px) rotate(45deg);
opacity: 0.65;
transition: transform var(--duration-fast) var(--ease-default);
}
[data-navigation-menu-trigger][data-state='open']::after {
transform: translateY(2px) rotate(-135deg);
}
/* ── Content panel (mega-menu) ─
*
* Soma renders Content via the Floating layer below the trigger. The
* recipe paints the panel chrome (border, shadow, padding) and the
* directional slide animation per `data-motion` (from / to).
*/
[data-navigation-menu-content] {
/* Floats below the parent Item — taken out of the bar's flex flow so
* opening the mega-menu doesn't push siblings. `top: 100%` anchors
* it just below the trigger row; `inset-inline-start: 0` left-aligns
* to the Item, but the panel itself has a `min-inline-size` so it
* extends past the trigger if needed. */
position: absolute;
inset-block-start: calc(100% + var(--space-1));
inset-inline-start: 0;
z-index: 50;
min-inline-size: 14rem;
padding: var(--space-4);
border: 1px solid var(--color-border-default);
border-radius: var(--radius-lg);
background: var(--color-surface-overlay);
color: var(--color-content-primary);
box-shadow: var(--shadow-floating);
outline: none;
}
/* Vertical orientation flips the anchor — Content opens to the right
* of the trigger column instead of below. */
[data-navigation-menu][data-orientation='vertical'] [data-navigation-menu-content] {
inset-block-start: 0;
inset-inline-start: calc(100% + var(--space-1));
}
[data-navigation-menu-content][data-state='open'] {
animation: navigation-menu-enter var(--duration-fast) var(--ease-out);
}
[data-navigation-menu-content][data-state='closed'] {
opacity: 0;
pointer-events: none;
}
@keyframes navigation-menu-enter {
from {
opacity: 0;
transform: translateY(-4px) scale(0.985);
}
to {
opacity: 1;
transform: none;
}
}
/* `data-motion` — soma writes 'from-start' / 'from-end' / 'to-start' /
* 'to-end' when the active item swaps to a sibling. The directional
* slide makes the swap feel like a horizontal scroll, not a flicker. */
[data-navigation-menu-content][data-motion='from-start'] {
animation: navigation-menu-from-start var(--duration-fast) var(--ease-out);
}
[data-navigation-menu-content][data-motion='from-end'] {
animation: navigation-menu-from-end var(--duration-fast) var(--ease-out);
}
[data-navigation-menu-content][data-motion='to-start'] {
animation: navigation-menu-to-start var(--duration-fast) var(--ease-default);
}
[data-navigation-menu-content][data-motion='to-end'] {
animation: navigation-menu-to-end var(--duration-fast) var(--ease-default);
}
@keyframes navigation-menu-from-start {
from { opacity: 0; transform: translateX(-12px); }
}
@keyframes navigation-menu-from-end {
from { opacity: 0; transform: translateX(12px); }
}
@keyframes navigation-menu-to-start {
to { opacity: 0; transform: translateX(-12px); }
}
@keyframes navigation-menu-to-end {
to { opacity: 0; transform: translateX(12px); }
}
/* ── Indicator (underline under active Trigger) ─
*
* Soma writes the active-trigger rect into CSS vars on the indicator:
* --navigation-menu-indicator-x / -y / -w / -h
* The recipe consumes them to position a 2px underline that slides
* between triggers. The indicator itself stays inside the navigation
* bar; it's NOT in the floating layer.
*/
[data-navigation-menu-indicator] {
position: absolute;
inset-inline-start: 0;
inset-block-end: 0;
z-index: 1;
pointer-events: none;
inline-size: var(--navigation-menu-indicator-w, 0px);
block-size: 2px;
transform: translateX(var(--navigation-menu-indicator-x, 0px));
background: var(--color-primary-solid);
border-radius: 1px;
opacity: 0;
transition:
transform var(--duration-fast) var(--ease-default),
inline-size var(--duration-fast) var(--ease-default),
opacity var(--duration-fast) var(--ease-default);
}
[data-navigation-menu-indicator][data-state='visible'] {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
[data-navigation-menu-content],
[data-navigation-menu-indicator] {
animation: none !important;
transition: none !important;
}
}

Powered by TurnKey Linux.