From aef5a8657061aada20321ad1cf61512a54ded8bc Mon Sep 17 00:00:00 2001 From: RasmusKjeldgaard Date: Tue, 3 Dec 2024 15:10:09 +0100 Subject: [PATCH] Housekeeping: improve docs side and top nav (#3724) --- apps/cookbook/src/app/app.routes.ts | 12 ++ .../cookbook/src/app/home/home.component.scss | 7 +- .../src/app/page/header/header.component.html | 162 ++++++++---------- .../src/app/page/header/header.component.scss | 49 +++--- .../src/app/page/header/header.component.ts | 26 +-- .../app/page/side-nav/side-nav.component.html | 130 ++++++++------ .../app/page/side-nav/side-nav.component.scss | 140 ++++++++------- .../app/page/side-nav/side-nav.component.ts | 54 +++--- 8 files changed, 295 insertions(+), 285 deletions(-) diff --git a/apps/cookbook/src/app/app.routes.ts b/apps/cookbook/src/app/app.routes.ts index 8427daf7cc..a446a6df3e 100644 --- a/apps/cookbook/src/app/app.routes.ts +++ b/apps/cookbook/src/app/app.routes.ts @@ -24,6 +24,9 @@ export const routes: Routes = [ { path: 'intro', component: IntroComponent, + data: { + resourceLink: 'Introduction', + }, }, { path: 'showcase', @@ -32,10 +35,16 @@ export const routes: Routes = [ { path: 'guides', loadChildren: () => import('./guides/guides.module').then((m) => m.GuideModule), + data: { + resourceLink: 'Guides', + }, }, { path: 'accessibility-in-kirby', component: AccessibilityGuidelinesComponent, + data: { + resourceLink: 'Accessibility', + }, }, { path: 'component-overview', @@ -44,6 +53,9 @@ export const routes: Routes = [ { path: 'extensions', component: ExtensionsLandingPageComponent, + data: { + resourceLink: 'Extensions', + }, }, ], }, diff --git a/apps/cookbook/src/app/home/home.component.scss b/apps/cookbook/src/app/home/home.component.scss index a6a7f19b82..24d7952ad8 100644 --- a/apps/cookbook/src/app/home/home.component.scss +++ b/apps/cookbook/src/app/home/home.component.scss @@ -2,7 +2,7 @@ /* stylelint-disable declaration-block-no-redundant-longhand-properties */ -$header-height-mobile: utils.size('xxxl'); +$header-height-mobile: auto; $header-height-desktop: 2 * utils.size('xxl'); $footer-height: 3 * utils.size('xxl'); $sidebar-width: 5 * utils.size('xxl'); @@ -16,7 +16,7 @@ $desktop-gutter: minmax(utils.size('m'), 1fr); grid-template-columns: $mobile-gutter minmax(0, 1fr) $mobile-gutter; grid-template-rows: $header-height-mobile minmax(0, 1fr) $footer-height; grid-template-areas: - '. header .' + 'header header header' '. main .' 'footer footer footer'; gap: utils.size('m'); @@ -29,7 +29,8 @@ $desktop-gutter: minmax(utils.size('m'), 1fr); '. header header .' '. sidebar main .' 'footer footer footer footer'; - gap: utils.size('xl'); + column-gap: utils.size('xl'); + row-gap: utils.size('m'); } } diff --git a/apps/cookbook/src/app/page/header/header.component.html b/apps/cookbook/src/app/page/header/header.component.html index e1f0bc5fa4..7ffb6477e4 100644 --- a/apps/cookbook/src/app/page/header/header.component.html +++ b/apps/cookbook/src/app/page/header/header.component.html @@ -1,120 +1,92 @@
- - + + - - - -
diff --git a/apps/cookbook/src/app/page/header/header.component.scss b/apps/cookbook/src/app/page/header/header.component.scss index 1001101d31..c30909272a 100644 --- a/apps/cookbook/src/app/page/header/header.component.scss +++ b/apps/cookbook/src/app/page/header/header.component.scss @@ -8,52 +8,47 @@ $medium-rect-delay: $large-rect-delay + 300ms; $small-rect-delay: $medium-rect-delay + 200ms; :host { - display: flex; grid-area: header; - align-items: flex-end; -} - -header { - display: flex; - justify-content: space-between; - align-items: flex-start; - flex-grow: 1; -} + z-index: utils.z('sticky-content') + 1; // above side-nav + position: sticky; + top: 0; + background-color: utils.get-color('light'); + border-bottom: 1px solid utils.get-color('medium'); -.menu-button { @include utils.media('>=large') { - display: none; + position: static; + background-color: transparent; + border-bottom: none; } } -nav { - display: none; +header { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + align-items: center; + width: 100%; + padding: var(--kirby-spacing-xxs); @include utils.media('>=large') { - display: block; - } - - ul { - display: flex; - column-gap: utils.size('xxxl'); - list-style: none; - padding: 0; - margin: 0; - line-height: normal; + padding-block: var(--kirby-spacing-m) 0; + align-items: start; - li { - margin-block-start: 0; + .menu-button { + display: none; } } } -.logo { +.logo-anchor { width: $logo-size-mobile; height: $logo-size-mobile; + justify-self: center; @include utils.media('>=large') { width: $logo-size-desktop; height: $logo-size-desktop; + margin-inline-start: var(--kirby-spacing-m); + justify-self: start; } svg { diff --git a/apps/cookbook/src/app/page/header/header.component.ts b/apps/cookbook/src/app/page/header/header.component.ts index 592f047b73..1517c1c433 100644 --- a/apps/cookbook/src/app/page/header/header.component.ts +++ b/apps/cookbook/src/app/page/header/header.component.ts @@ -1,26 +1,4 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; - -interface HeaderLink { - text: string; - route?: string; - externalUrl?: string; - showAsActive?: boolean; -} - -export const navigationItems: HeaderLink[] = [ - { text: 'Introduction', route: '/home/intro' }, - { text: 'Components', route: '/home/component-overview' }, - { text: 'Guides', route: '/home/guides' }, - { text: 'Accessibility', route: '/home/accessibility-in-kirby' }, - { text: 'Extensions', route: '/home/extensions' }, - { - text: 'Changelog', - externalUrl: 'https://github.com/kirbydesign/designsystem/releases', - }, - - { text: 'GitHub', externalUrl: 'https://github.com/kirbydesign/designsystem' }, -]; - @Component({ selector: 'cookbook-header', templateUrl: './header.component.html', @@ -30,10 +8,8 @@ export class HeaderComponent { @Input() isMenuOpen = false; @Output() menuToggle = new EventEmitter(); - navigationItems = navigationItems; - get menuIcon(): string { - return this.isMenuOpen ? 'close' : 'more'; + return this.isMenuOpen ? 'close' : 'navigation'; } onToggleMenu() { diff --git a/apps/cookbook/src/app/page/side-nav/side-nav.component.html b/apps/cookbook/src/app/page/side-nav/side-nav.component.html index 1f5cd4e049..341d574e10 100644 --- a/apps/cookbook/src/app/page/side-nav/side-nav.component.html +++ b/apps/cookbook/src/app/page/side-nav/side-nav.component.html @@ -1,57 +1,89 @@
- -
- - - - -
+ +

Resources

+
+ +
- - +

Components

+
All + +
+
+ + + + +
+
diff --git a/apps/cookbook/src/app/page/side-nav/side-nav.component.scss b/apps/cookbook/src/app/page/side-nav/side-nav.component.scss index f070c6fc2d..f990c15470 100644 --- a/apps/cookbook/src/app/page/side-nav/side-nav.component.scss +++ b/apps/cookbook/src/app/page/side-nav/side-nav.component.scss @@ -1,85 +1,101 @@ @use '@kirbydesign/core/src/scss/utils'; @use '@kirbydesign/core/src/scss/opt-out'; -$link-padding: 5px; +$link-padding-block: var(--kirby-spacing-xxxs); +$link-padding-inline: var(--kirby-spacing-s); $link-border-radius: 3px; -$menu-padding-mobile: utils.size('m'); -$divider-inset: utils.size('xxxxs'); -$divider-spacing: utils.size('xxs'); +$menu-padding-mobile: var(--kirby-spacing-m); +$divider-inset: var(--kirby-spacing-xxxxs); +$divider-spacing: var(--kirby-spacing-xxs); +$logo-size-mobile: var(--kirby-spacing-xl); :host { - @include utils.media('>=large') { - grid-area: sidebar; - } -} - -nav { - @include utils.media('>=large') { - display: none; - } -} - -section { display: none; + z-index: utils.z('sticky-content'); + padding: $menu-padding-mobile; position: absolute; - min-height: 100vh; - top: 0; - z-index: utils.z('modal'); - background-color: utils.get-color('white'); - padding: 0 $menu-padding-mobile; - box-shadow: utils.get-elevation(4); - - @include utils.media('=large') { + position: static; + grid-area: sidebar; box-shadow: none; display: block; - position: static; - background-color: transparent; padding: 0; min-height: unset; + + &.is-open { + background-color: transparent; + box-shadow: none; + } } +} - &.is-open { - display: block; +ul { + list-style: none; + padding: 0; + margin: 0; + line-height: normal; + + li { + margin-block-start: 0; } +} - a { - @include opt-out.link; +kirby-card:not(:last-child) { + margin-bottom: var(--kirby-spacing-s); +} +a { + &.list-item-link { text-decoration: none; + } + + position: relative; + display: block; + padding: $link-padding-block $link-padding-inline; + border-radius: $link-border-radius; + line-height: 1.5rem; + + &:hover, + &:focus { color: utils.get-text-color('semi-dark'); - display: block; - padding: $link-padding; - margin: 0 utils.size('xxxxs'); - border-radius: $link-border-radius; - - &:hover, - &:focus { - color: utils.get-text-color('black'); - background-color: utils.get-color('light'); - } + z-index: utils.z('default'); + } - &.is-selected { - color: utils.get-text-color('black'); - font-weight: bold; - background-color: utils.get-color('semi-light'); - } + &.is-selected { + color: utils.get-text-color('black'); + font-weight: bold; + background-color: utils.get-color('semi-light'); + } - &.is-hidden { - opacity: 0; - max-height: 0; - padding: 0; - pointer-events: none; - } + &.is-hidden { + opacity: 0; + max-height: 0; + padding: 0; + pointer-events: none; } } +h2 { + margin-inline-start: $link-padding-inline; + margin-bottom: 0; +} + .filter { position: relative; + + kirby-form-field { + margin-bottom: var(--kirby-spacing-s); + } } .clear-button { @@ -88,14 +104,22 @@ section { top: 0; } +.menu-button { + margin-top: var(--kirby-spacing-xs); + @include utils.media('>=large') { + display: none; + } +} + +.components-heading-container { + display: flex; + justify-content: space-between; + align-items: center; +} + hr { - margin: utils.size('xxxs'), 0; border: solid 1px utils.get-color('light'); border-bottom: none; margin-block: $divider-spacing; margin-inline: $divider-inset; - - &:last-child { - border-color: transparent; - } } diff --git a/apps/cookbook/src/app/page/side-nav/side-nav.component.ts b/apps/cookbook/src/app/page/side-nav/side-nav.component.ts index 040207437d..1190ddca97 100644 --- a/apps/cookbook/src/app/page/side-nav/side-nav.component.ts +++ b/apps/cookbook/src/app/page/side-nav/side-nav.component.ts @@ -2,6 +2,7 @@ import { Component, ElementRef, EventEmitter, + HostBinding, Input, OnInit, Output, @@ -13,15 +14,14 @@ import { filter } from 'rxjs/operators'; import { kebabToTitleCase } from '@kirbydesign/designsystem'; -import { routes } from '../../showcase/showcase.routes'; -import { navigationItems } from '../header/header.component'; +import { routes as showcaseRoutes } from '../../showcase/showcase.routes'; +import { routes as appRoutes } from '../../app.routes'; const KEY_DOWN = 'ArrowDown'; interface SideNavLink { path: string; name: string; - active: boolean; } @Component({ @@ -32,17 +32,22 @@ interface SideNavLink { export class SideNavComponent implements OnInit { private allShowcaseRoutes: SideNavLink[]; filteredShowcaseRoutes: SideNavLink[][]; + filteredResourceRoutes: Route[]; filter: string = ''; + @ViewChildren('componentLink') componentLinks!: QueryList>; + @ViewChildren('resourceLink') resourceLinks!: QueryList>; + @Output() menuToggle = new EventEmitter(); - @Input() isMenuOpen = false; + @HostBinding('class.is-open') + @Input() + isMenuOpen = false; constructor(private router: Router) {} - navigationLinks = navigationItems; - ngOnInit() { - this.mapRoutes(); + this.mapShowcaseRoutes(); + this.mapResourcesRoutes(); this.router.events .pipe(filter((event): event is NavigationEnd => event instanceof NavigationEnd)) @@ -53,8 +58,8 @@ export class SideNavComponent implements OnInit { }); } - private mapRoutes() { - const routesWithPath = routes[0].children.filter((r) => r.path); + private mapShowcaseRoutes() { + const routesWithPath = showcaseRoutes[0].children.filter((r) => r.path); const navigableRoutes = routesWithPath.filter((r) => !r.data?.hide); navigableRoutes.sort(this.sortByPath); @@ -69,12 +74,17 @@ export class SideNavComponent implements OnInit { this.applyComponentFilter(''); } + private mapResourcesRoutes() { + const routesWithPath = appRoutes.find((r) => r.path === 'home')?.children || []; + const resourceLinks = routesWithPath.filter((r) => r.data?.['resourceLink']); + + this.filteredResourceRoutes = resourceLinks; + } + private sortByPath(a: Route, b: Route): number { return a.path < b.path ? -1 : a.path > b.path ? 1 : 0; } - @ViewChildren('componentLink') componentLinks: QueryList>; - onFilterChange(value: string) { this.applyComponentFilter(value); } @@ -87,9 +97,11 @@ export class SideNavComponent implements OnInit { } } - onLinksArrowUpDown(event: KeyboardEvent) { + onLinksArrowUpDown(event: KeyboardEvent, sideNavGroupKey: string) { event.preventDefault(); - const listElements: HTMLAnchorElement[] = this.componentLinks.map((link) => link.nativeElement); + const listElements: HTMLAnchorElement[] = ( + sideNavGroupKey === 'resources' ? this.resourceLinks : this.componentLinks + ).map((link) => link.nativeElement); const currentlyFocused = listElements.findIndex((link) => link === document.activeElement); if (currentlyFocused === -1) { @@ -103,12 +115,7 @@ export class SideNavComponent implements OnInit { linkToFocus.focus(); } - onComponentLinkClick(path: string) { - this.setRouteActive(path); - this.closeMenu(); - } - - private closeMenu() { + closeMenu() { this.isMenuOpen = false; this.menuToggle.emit(this.isMenuOpen); } @@ -133,7 +140,6 @@ export class SideNavComponent implements OnInit { private distributeSideNavLinksAlphabetically(links: SideNavLink[]): SideNavLink[][] { const distributed: { [key: string]: SideNavLink[] } = links.reduce((accumulator, link) => { const firstLetter = link.name[0]; - link.active = this.router.url.endsWith(link.path); accumulator[firstLetter] = accumulator[firstLetter] === undefined ? [link] : [...accumulator[firstLetter], link]; return accumulator; @@ -141,12 +147,4 @@ export class SideNavComponent implements OnInit { return Object.keys(distributed).map((groupKey) => distributed[groupKey]); } - - private setRouteActive(path) { - this.filteredShowcaseRoutes = this.filteredShowcaseRoutes.map((group) => { - return group.map((link) => { - return { ...link, active: link.path === path }; - }); - }); - } }