Преглед на файлове

feat(admin-ui): Style left nav surface

Michael Bromley преди 2 години
родител
ревизия
8c41f33511

+ 7 - 10
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.html

@@ -1,22 +1,19 @@
 <div class="app-container">
     <div class="left-nav">
-        <div class="branding py-2 px-2">
+        <div class="branding py-4 px-4">
             <a [routerLink]="['/']"
-                ><img src="assets/logo-75px.png" class="logo" /><span
-                    class="wordmark md:hidden"
-                    *ngIf="!hideVendureBranding"
-                    >vendure</span
-                ></a
+                ><img src="assets/logo.webp" class="logo" /></a
             >
         </div>
-        <div class="mx-2">
+        <div class="mx-4">
             <vdr-channel-switcher *vdrIfMultichannel></vdr-channel-switcher>
         </div>
-        <div class="px-2 mt-4 main-nav-container">
+        <div class="main-nav-container">
             <vdr-main-nav></vdr-main-nav>
         </div>
-        <div class="m-2">
-            <vdr-settings-nav></vdr-settings-nav>
+        <div class="settings-nav-container">
+            <hr />
+            <vdr-main-nav displayMode="settings"></vdr-main-nav>
         </div>
         <div class="mx-2"></div>
     </div>

+ 13 - 3
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.scss

@@ -12,11 +12,11 @@
     display: flex;
     flex-direction: column;
     height: 100%;
-    border-right: 1px solid var(--color-component-border-200);
+    border-right: 1px solid var(--color-weight-150);
     //box-shadow: -3px 1px 10px 0px rgb(0 0 0 / 18%);
     z-index: 1;
     @media screen and (min-width: $breakpoint-medium) {
-        width: 260px;
+        width: 300px;
     }
 }
 
@@ -38,6 +38,16 @@
     flex: 1;
 }
 
+.settings-nav-container {
+    margin: calc(var(--space-unit) * 3) 0;
+    hr {
+        margin: 0 calc(var(--space-unit) * 4);
+        margin-bottom: calc(var(--space-unit) * 4);
+        border: 1px solid #D9D9D9;
+        box-shadow: 0px 1px 0px #FFFFFF;
+    }
+}
+
 .surface {
     display: flex;
     flex-direction: column;
@@ -56,7 +66,7 @@
 }
 
 .logo {
-    width: 40px;
+    max-width: 100%;
 }
 
 .wordmark {

+ 1 - 1
packages/admin-ui/src/lib/core/src/components/channel-switcher/channel-switcher.component.html

@@ -5,7 +5,7 @@
             <span class="md:hidden channel-label">{{
                 activeChannelCode$ | async | channelCodeToLabel | translate
             }}</span>
-            <span class="trigger md:hidden"><clr-icon shape="caret down"></clr-icon></span>
+            <span class="trigger md:hidden"><clr-icon shape="ellipsis-vertical"></clr-icon></span>
         </button>
         <vdr-dropdown-menu vdrPosition="bottom-right">
             <input

+ 6 - 5
packages/admin-ui/src/lib/core/src/components/channel-switcher/channel-switcher.component.scss

@@ -8,16 +8,16 @@
 
 .active-channel {
     display: flex;
-    align-items: center;
     justify-content: space-between;
+    align-items: center;
     font-size: var(--font-size-xs);
     color: var(--color-left-nav-text);
-    background-color: var(--color-component-bg-200);
-    border: 1px solid var(--color-component-border-200);
+    background-color: var(--color-weight-150);
+    border: none;
     cursor: pointer;
     width: 100%;
-    border-radius: var(--border-radius);
-    padding: var(--space-unit);
+    border-radius: var(--border-radius-lg);
+    padding: var(--space-unit) calc(var(--space-unit) * 2);
 
     &:hover {
         background-color: var(--color-component-bg-100);
@@ -35,6 +35,7 @@
 .channel-label {
     margin: 0 3px;
     overflow: hidden;
+    flex: 1;
     max-width: 100px;
     text-overflow: ellipsis;
     @media screen and (max-width: $breakpoint-medium) {

+ 40 - 13
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.html

@@ -5,24 +5,47 @@
                 class="nav-group"
                 [attr.data-section-id]="section.id"
                 [class.collapsible]="section.collapsible"
+                [class.collapsed]="section.collapsible && !expandedSections.includes(section.id)"
+                routerLinkActive="active"
                 *ngIf="shouldDisplayLink(section)"
             >
-                <vdr-ui-extension-point [locationId]="section.id" api="navMenu" [topPx]="-6" [leftPx]="8" display="block">
-                    <ng-container *ngIf="navBuilderService.sectionBadges[section.id] | async as sectionBadge">
-                        <vdr-status-badge
-                            *ngIf="sectionBadge !== 'none'"
-                            [type]="sectionBadge"
-                        ></vdr-status-badge>
-                    </ng-container>
-                    <label class="nav-group-header md:hidden" [for]="section.id">{{ section.label | translate }}</label>
-                    <div class="nav-list">
+                <vdr-ui-extension-point
+                    [locationId]="section.id"
+                    api="navMenu"
+                    [topPx]="-6"
+                    [leftPx]="8"
+                    display="block"
+                >
+                    <div class="section-header">
+                        <ng-container
+                            *ngIf="navBuilderService.sectionBadges[section.id] | async as sectionBadge"
+                        >
+                            <vdr-status-badge
+                                *ngIf="sectionBadge !== 'none'"
+                                [type]="sectionBadge"
+                            ></vdr-status-badge>
+                        </ng-container>
+                        <label class="nav-group-header md:hidden mx-4" [for]="section.id">{{
+                            section.label | translate
+                        }}</label>
+                        <button *ngIf="section.collapsible" class="button-small bg-weight-150" (click)="toggleExpand(section)">
+                            <clr-icon
+                                [attr.shape]="expandedSections.includes(section.id) ? 'caret up' : 'caret down'"
+                                size="12"
+                                [title]="'common.expand-entries' | translate"
+                            ></clr-icon>
+                        </button>
+                    </div>
+                    <div class="nav-list" [ngStyle]="getStyleForSection(section)">
                         <ng-container *ngFor="let item of section.items">
-                            <div *ngIf="shouldDisplayLink(item)">
+                            <div
+                                *ngIf="shouldDisplayLink(item)"
+                                class="nav-link px-4"
+                                routerLinkActive="active"
+                            >
                                 <a
-                                    class="nav-link"
                                     [attr.data-item-id]="section.id"
                                     [routerLink]="getRouterLink(item)"
-                                    routerLinkActive="active"
                                     (click)="item.onClick && item.onClick($event)"
                                 >
                                     <ng-container *ngIf="item.statusBadge | async as itemBadge">
@@ -31,7 +54,11 @@
                                             [type]="itemBadge.type"
                                         ></vdr-status-badge>
                                     </ng-container>
-                                    <clr-icon [attr.shape]="item.icon || 'block'" size="18" [title]="item.label | translate"></clr-icon>
+                                    <clr-icon
+                                        [attr.shape]="item.icon || 'block'"
+                                        size="16"
+                                        [title]="item.label | translate"
+                                    ></clr-icon>
                                     <span class="md:hidden">{{ item.label | translate }}</span>
                                 </a>
                             </div>

+ 39 - 15
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.scss

@@ -11,35 +11,59 @@ nav.main-nav {
 
 .main-nav .nav-group {
     margin-bottom: calc(var(--space-unit) * 2);
+    padding: calc(var(--space-unit) * 2) 0;
+    overflow: hidden;
+    transition: padding 0.2s ease-in-out, margin-bottom 0.2s ease-in-out;
+    &.collapsible.collapsed {
+        padding: 3px 0;
+        margin-bottom: calc(var(--space-unit) * 1);
+    }
+
+    &.active:not(.collapsible.collapsed) {
+        background-color: var(--color-weight-125);
+    }
     .nav-list {
         margin: 0;
+        transition: max-height 0.2s ease-in-out, opacity 0.2s ease-in-out;
+    }
+    .section-header {
+        display: flex;
+        align-items: flex-start;
+        justify-content: space-between;
+        padding-right: calc(var(--space-unit) * 4);
     }
     .nav-group-header {
-        margin: 0;
-        line-height: 1.2;
+        display: block;
+        margin: 0 0 var(--space-unit);
         font-size: var(--font-size-xs);
-        padding-left: calc(var(--space-unit) * 1);
-        //font-weight: bold;
-        color: var(--color-left-nav-text);
-        opacity: 0.7;
+        letter-spacing: 0.05em;
+        color: var(--color-weight-700);
         text-transform: uppercase;
     }
     .nav-link {
         display: flex;
-        line-height: 1rem;
+        align-items: center;
+        line-height: 100%;
+        border-right: 2px solid transparent;
         font-size: var(--font-size-sm);
-        padding: var(--space-unit);
-        border-radius: var(--border-radius);
-        &:link,
-        &:visited {
-            color: var(--color-text-600);
+        padding: var(--space-unit) 0;
+        transition: border 0.1s, color 0.1s;
+
+        a:link,
+        a:visited {
+            color: var(--color-weight-700);
         }
         &:hover {
             color: var(--color-left-nav-text-hover);
+            border-right-color: var(--color-weight-300);
         }
 
-        &.active {
-            color: var(--color-primary-600);
+        &.active, &.active a:link, &.active a:visited {
+            color: var(--color-primary-800);
+            border-right-color: var(--color-primary-500);
+            clr-icon {
+                color: var(--color-primary-500);
+            }
         }
         @media screen and (max-width: $breakpoint-medium) {
             justify-content: center;
@@ -50,7 +74,7 @@ nav.main-nav {
 .nav-list clr-icon {
     flex-shrink: 0;
     @media screen and (min-width: $breakpoint-medium) {
-        margin-right: 12px;
+        margin-right: var(--space-unit);
     }
 }
 

+ 26 - 2
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.ts

@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
 import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { NavMenuSection } from '../../providers/nav-builder/nav-builder-types';
@@ -10,13 +10,37 @@ import { BaseNavComponent } from '../base-nav/base-nav.component';
     styleUrls: ['./main-nav.component.scss'],
 })
 export class MainNavComponent extends BaseNavComponent implements OnInit {
+    @Input() displayMode: string | undefined;
     mainMenuConfig$: Observable<NavMenuSection[]>;
+    expandedSections: string[] = [];
 
     override ngOnInit(): void {
         super.ngOnInit();
 
         this.mainMenuConfig$ = this.navBuilderService.menuConfig$.pipe(
-            map(sections => sections.filter(s => s.displayMode === 'regular' || !s.displayMode)),
+            map(sections =>
+                sections.filter(s =>
+                    this.displayMode ? s.displayMode === this.displayMode : !s.displayMode,
+                ),
+            ),
         );
     }
+
+    toggleExpand(section: NavMenuSection) {
+        if (this.expandedSections.includes(section.id)) {
+            this.expandedSections = this.expandedSections.filter(id => id !== section.id);
+        } else {
+            this.expandedSections.push(section.id);
+        }
+    }
+
+    getStyleForSection(section: NavMenuSection) {
+        if (section.collapsible) {
+            if (this.expandedSections.includes(section.id)) {
+                return { maxHeight: `${section.items.length * 33}px`, opacity: 1, visibility: 'visible' };
+            } else {
+                return { maxHeight: '0px', opacity: 0, visibility: 'hidden' };
+            }
+        }
+    }
 }

BIN
packages/admin-ui/src/lib/static/assets/logo.webp


+ 12 - 0
packages/admin-ui/src/lib/static/styles/global/_buttons.scss

@@ -0,0 +1,12 @@
+.button-small {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    align-items: center;
+    padding: 0 var(--space-unit);
+    height: calc(var(--space-unit) * 3);
+    gap: 12px;
+    border: none;
+    border-radius: var(--border-radius-lg);
+    cursor: pointer;
+}

+ 27 - 1
packages/admin-ui/src/lib/static/styles/global/_utilities.scss

@@ -1,7 +1,7 @@
 @use 'sass:math';
 
 // spacing
-$space-unit: 6px;
+$space-unit: 8px;
 
 $space-1: math.div($space-unit, 2);
 $space-2: $space-unit;
@@ -421,3 +421,29 @@ $breakpoint-glue: '\\:' !default;
         }
     }
 }
+
+// colour classes
+$colors: (
+    'weight',
+    'primary',
+    'secondary',
+    'success',
+    'warning',
+    'error'
+);
+$scale: (100,  125,  150,  200,  300,  400,  500,  600,  700,  800,  900,  950,  975,  1000);
+$properties: (
+    'color': 'color',
+    'bg': 'background-color',
+    'border': 'border-color',
+);
+// create the classes
+@each $color in $colors {
+    @each $scale in $scale {
+        @each $property, $cssProperty in $properties {
+            .#{$property}-#{$color}-#{$scale} {
+                #{$cssProperty}: var(--color-#{$color}-#{$scale});
+            }
+        }
+    }
+}

+ 1 - 0
packages/admin-ui/src/lib/static/styles/styles.scss

@@ -3,6 +3,7 @@
 @import "@clr/ui/src/utils/components.clarity";
 @import "@ng-select/ng-select/themes/default.theme.css";
 @import '@angular/cdk/overlay-prebuilt.css';
+@import "global/buttons";
 @import "global/forms";
 @import "global/overrides";
 @import "global/utilities";

+ 100 - 5
packages/admin-ui/src/lib/static/styles/theme/default.scss

@@ -71,13 +71,11 @@
     --color-text-300: var(--color-grey-400);
     --color-text-inverse: white;
 
+
+
     // Component-specific colors
     --color-top-bar-bg: white;
 
-    --color-left-nav-bg: var(--color-component-bg-100);
-    --color-left-nav-text: var(--color-text);
-    --color-left-nav-text-hover: var(--color-primary-700);
-
     --color-icon-button: var(--color-grey-600);
     --color-form-input-bg: white;
     --color-timeline-thread: var(--color-primary-100);
@@ -101,6 +99,103 @@
     --color-json-editor-key: var(--color-success-500);
     --color-json-editor-error: var(--color-error-500);
 
+
+    --color-white: #fff;
+    --color-black: #000;
+    --color-weight-100: hsl(0 0% 95%);
+    --color-weight-125: hsl(0 0% 93%);
+    --color-weight-150: hsl(0 0% 90%);
+    --color-weight-200: hsl(0 0% 85%);
+    --color-weight-300: hsl(0 0% 75%);
+    --color-weight-400: hsl(0 0% 65%);
+    --color-weight-500: hsl(0 0% 55%);
+    --color-weight-600: hsl(0 0% 45%);
+    --color-weight-700: hsl(0 0% 35%);
+    --color-weight-800: hsl(0 0% 25%);
+    --color-weight-900: hsl(0 0% 15%);
+    --color-weight-950: hsl(0 0% 10%);
+    --color-weight-975: hsl(0 0% 7%);
+    --color-weight-1000: hsl(0 0% 5%);
+
+    --color-primary-100: hsl(196 100% 95%);
+    --color-primary-125: hsl(196 100% 93%);
+    --color-primary-150: hsl(196 100% 90%);
+    --color-primary-200: hsl(196 100% 85%);
+    --color-primary-300: hsl(196 100% 75%);
+    --color-primary-400: hsl(196 100% 65%);
+    --color-primary-500: hsl(196 100% 55%);
+    --color-primary-600: hsl(196 100% 45%);
+    --color-primary-700: hsl(196 100% 35%);
+    --color-primary-800: hsl(196 100% 25%);
+    --color-primary-900: hsl(196 100% 15%);
+    --color-primary-950: hsl(196 100% 10%);
+    --color-primary-975: hsl(196 100% 7%);
+    --color-primary-1000: hsl(196 100 5%);
+
+    --color-accent-100: hsl(35 100% 95%);
+    --color-accent-125: hsl(35 100% 93%);
+    --color-accent-150: hsl(35 100% 90%);
+    --color-accent-200: hsl(35 100% 85%);
+    --color-accent-300: hsl(35 100% 75%);
+    --color-accent-400: hsl(35 100% 65%);
+    --color-accent-500: hsl(35 100% 55%);
+    --color-accent-600: hsl(35 100% 45%);
+    --color-accent-700: hsl(35 100% 35%);
+    --color-accent-800: hsl(35 100% 25%);
+    --color-accent-900: hsl(35 100% 15%);
+    --color-accent-950: hsl(35 100% 10%);
+    --color-accent-975: hsl(35 100% 7%);
+    --color-accent-1000: hsl(35 100% 5%);
+
+    --color-success-100: hsl(158 76% 95%);
+    --color-success-125: hsl(158 76% 93%);
+    --color-success-150: hsl(158 76% 90%);
+    --color-success-200: hsl(158 76% 85%);
+    --color-success-300: hsl(158 76% 75%);
+    --color-success-400: hsl(158 76% 65%);
+    --color-success-500: hsl(158 76% 55%);
+    --color-success-600: hsl(158 76% 45%);
+    --color-success-700: hsl(158 76% 35%);
+    --color-success-800: hsl(158 76% 25%);
+    --color-success-900: hsl(158 76% 15%);
+    --color-success-950: hsl(158 76% 10%);
+    --color-success-975: hsl(158 76% 7%);
+    --color-success-1000: hsl(158 76% 5%);
+
+    --color-warning-100: hsl(53 100% 95%);
+    --color-warning-125: hsl(53 100% 93%);
+    --color-warning-150: hsl(53 100% 90%);
+    --color-warning-200: hsl(53 100% 85%);
+    --color-warning-300: hsl(53 100% 75%);
+    --color-warning-400: hsl(53 100% 65%);
+    --color-warning-500: hsl(53, 100%, 47%);
+    --color-warning-600: hsl(53 100% 45%);
+    --color-warning-700: hsl(53 100% 35%);
+    --color-warning-800: hsl(53 100% 25%);
+    --color-warning-900: hsl(53 100% 15%);
+    --color-warning-950: hsl(53 100% 10%);
+    --color-warning-975: hsl(53 100% 7%);
+    --color-warning-1000: hsl(53 100% 5%);
+
+    --color-error-100: hsl(4 100% 95%);
+    --color-error-125: hsl(4 100% 93%);
+    --color-error-150: hsl(4 100% 90%);
+    --color-error-200: hsl(4 100% 85%);
+    --color-error-300: hsl(4 100% 75%);
+    --color-error-400: hsl(4 100% 65%);
+    --color-error-500: hsl(4, 73%, 51%);
+    --color-error-600: hsl(4 100% 45%);
+    --color-error-700: hsl(4 100% 35%);
+    --color-error-800: hsl(4 100% 25%);
+    --color-error-900: hsl(4 100% 15%);
+    --color-error-950: hsl(4 100% 10%);
+    --color-error-975: hsl(4 100% 7%);
+    --color-error-1000: hsl(4 100% 5%);
+
+    --color-left-nav-bg: var(--color-weight-100);
+    --color-left-nav-text: var(--color-text);
+    --color-left-nav-text-hover: var(--color-primary-700);
+
     // Layout
     --layout-content-max-width: 1200px;
 
@@ -116,7 +211,7 @@
     // Border radius
     --border-radius-sm: div(var(--clr-global-borderradius), 2);
     --border-radius: var(--clr-global-borderradius);
-    --border-radius-lg: var(--clr-global-borderradius) * 2;
+    --border-radius-lg: calc(var(--space-unit) * 3);
     --border-radius-img: var(--clr-global-borderradius);
     --border-radius-input: var(--clr-global-borderradius);