Просмотр исходного кода

feat(admin-ui): Migrated modal service

David Höck 11 месяцев назад
Родитель
Сommit
58622bdb85
23 измененных файлов с 284 добавлено и 186 удалено
  1. 16 0
      package-lock.json
  2. 1 0
      packages/admin-ui/package.json
  3. 4 4
      packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.html
  4. 35 31
      packages/admin-ui/src/lib/core/src/components/channel-switcher/channel-switcher.component.html
  5. 1 1
      packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.html
  6. 66 49
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.html
  7. 4 1
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.ts
  8. 29 16
      packages/admin-ui/src/lib/core/src/providers/modal/modal.service.ts
  9. 1 1
      packages/admin-ui/src/lib/core/src/shared/components/card/card.component.html
  10. 6 8
      packages/admin-ui/src/lib/core/src/shared/components/form-field/form-field.component.html
  11. 2 2
      packages/admin-ui/src/lib/core/src/shared/components/labeled-data/labeled-data.component.html
  12. 18 13
      packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.html
  13. 13 8
      packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.ts
  14. 13 11
      packages/admin-ui/src/lib/core/src/shared/components/page-entity-info/page-entity-info.component.html
  15. 1 1
      packages/admin-ui/src/lib/core/src/shared/components/page-title/page-title.component.html
  16. 1 1
      packages/admin-ui/src/lib/core/src/shared/components/page/page.component.html
  17. 20 22
      packages/admin-ui/src/lib/core/src/shared/components/tabbed-custom-fields/tabbed-custom-fields.component.html
  18. 2 4
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/number-form-input/number-form-input.component.html
  19. 2 5
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/text-form-input/text-form-input.component.html
  20. 12 0
      packages/admin-ui/src/lib/core/src/shared/shared.module.ts
  21. 8 7
      packages/admin-ui/src/lib/settings/src/components/profile/profile.component.html
  22. 9 0
      packages/admin-ui/tsconfig.json
  23. 20 1
      packages/dev-server/dev-config.ts

+ 16 - 0
package-lock.json

@@ -31177,6 +31177,21 @@
         "@angular/core": ">=13.0.0"
       }
     },
+    "node_modules/ngx-scrollbar": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/ngx-scrollbar/-/ngx-scrollbar-18.0.0.tgz",
+      "integrity": "sha512-+ykmY491x+nzXvnecJvZHvDz0YWuX1r7SYMxNG4RVHXm5Z68P/8kd/3ryLD6DXdNWmJawd4NGvqq2ZkUKb/g3A==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/cdk": ">=19.0.0",
+        "@angular/common": ">=19.0.0",
+        "@angular/core": ">=19.0.0",
+        "rxjs": ">=7.0.0"
+      }
+    },
     "node_modules/ngx-translate-messageformat-compiler": {
       "version": "6.5.1",
       "resolved": "https://registry.npmjs.org/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-6.5.1.tgz",
@@ -41542,6 +41557,7 @@
         "just-extend": "^6.2.0",
         "messageformat": "2.3.0",
         "ngx-pagination": "^6.0.3",
+        "ngx-scrollbar": ">=16.0.0",
         "ngx-translate-messageformat-compiler": "^6.5.0",
         "prosemirror-commands": "^1.5.2",
         "prosemirror-dropcursor": "^1.8.1",

+ 1 - 0
packages/admin-ui/package.json

@@ -61,6 +61,7 @@
     "just-extend": "^6.2.0",
     "messageformat": "2.3.0",
     "ngx-pagination": "^6.0.3",
+    "ngx-scrollbar": ">=16.0.0",
     "ngx-translate-messageformat-compiler": "^6.5.0",
     "prosemirror-commands": "^1.5.2",
     "prosemirror-dropcursor": "^1.8.1",

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

@@ -3,7 +3,7 @@
         class="bg-background w-[250px] flex flex-col border-border border-e"
         [class.expanded]="mainNavExpanded$ | async"
     >
-        <div class="h-14 flex items-center px-4 border-b border-border">
+        <div class="h-14 flex items-center px-4 border-b border-border shrink-0">
             <a [routerLink]="['/']" *ngIf="!hideVendureBranding">
                 <vdr-logo-full class="h-6 w-auto text-accent-400"></vdr-logo-full>
             </a>
@@ -16,11 +16,11 @@
         <div class="mx-4 mt-4 mb-2">
             <vdr-channel-switcher *vdrIfMultichannel></vdr-channel-switcher>
         </div>
-        <div class="overflow-y-auto grow">
+        <ng-scrollbar hlm class="grow mx-4">
             <vdr-main-nav (itemClick)="collapseNav()"></vdr-main-nav>
-        </div>
+        </ng-scrollbar>
         <div
-            class="relative pt-4 border-t border-dashed border-border before:block before:-top-[1px] before:-translate-y-full before:left-0 before:absolute before:h-20 before:bg-gradient-to-t before:from-muted before:to-transparent before:w-full"
+            class="relative pt-4 border-t border-dashed border-border before:block before:-top-[1px] before:-translate-y-full before:left-0 before:absolute before:h-20 before:bg-gradient-to-t before:from-background before:to-transparent before:w-full"
         >
             <vdr-main-nav displayMode="settings" (itemClick)="collapseNav()"></vdr-main-nav>
         </div>

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

@@ -1,39 +1,43 @@
 <ng-container>
-    <vdr-dropdown>
-        <button
-            class="w-full justify-between text-muted-foreground"
-            hlmBtn
-            variant="outline"
-            vdrDropdownTrigger
-            size="sm"
-        >
-            <span>
-                <vdr-channel-badge
-                    class="mr-2"
-                    size="sm"
-                    [channelCode]="activeChannelCode$ | async"
-                ></vdr-channel-badge>
-                {{ activeChannelCode$ | async | channelCodeToLabel | translate }}
-            </span>
-            <ng-icon class="ml-1" hlm name="lucideEllipsisVertical" size="sm"></ng-icon>
-        </button>
-        <vdr-dropdown-menu vdrPosition="bottom-right">
-            <input
-                *ngIf="((channelCount$ | async) || 0) >= displayFilterThreshold"
-                [formControl]="filterControl"
-                type="text"
-                class="ml2 mr2"
-                [placeholder]="'common.filter' | translate"
-            />
+    <button
+        class="w-full justify-between text-muted-foreground"
+        hlmBtn
+        variant="outline"
+        [brnMenuTriggerFor]="channelSwitcher"
+        size="sm"
+    >
+        <span class="flex items-center">
+            <vdr-channel-badge
+                class="mr-2 flex items-center"
+                size="sm"
+                [channelCode]="activeChannelCode$ | async"
+            ></vdr-channel-badge>
+            {{ activeChannelCode$ | async | channelCodeToLabel | translate }}
+        </span>
+        <ng-icon class="ml-1" hlm name="lucideEllipsisVertical" size="sm"></ng-icon>
+    </button>
+    <ng-template #channelSwitcher>
+        <hlm-menu>
+            <div hlmMenuItem *ngIf="((channelCount$ | async) || 0) >= displayFilterThreshold">
+                <input
+                    hlmInput
+                    [formControl]="filterControl"
+                    type="text"
+                    [placeholder]="'common.filter' | translate"
+                />
+            </div>
             <button
+                hlmMenuItem
                 *ngFor="let channel of channels$ | async"
-                type="button"
-                vdrDropdownItem
                 (click)="setActiveChannel(channel.id)"
             >
-                <vdr-channel-badge [channelCode]="channel.code"></vdr-channel-badge>
+                <vdr-channel-badge
+                    class="flex items-center"
+                    hlmMenuIcon
+                    [channelCode]="channel.code"
+                ></vdr-channel-badge>
                 {{ channel.code | channelCodeToLabel | translate }}
             </button>
-        </vdr-dropdown-menu>
-    </vdr-dropdown>
+        </hlm-menu>
+    </ng-template>
 </ng-container>

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

@@ -1,4 +1,4 @@
-<nav class="main-nav pr-6 pl-4">
+<nav class="h-full">
     <ng-container *ngFor="let section of mainMenuConfig$ | async">
         <div
             class="overflow-hidden transition-all pb-2 nav-group"

+ 66 - 49
packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.html

@@ -1,67 +1,84 @@
 <ng-template vdrDialogTitle>{{ 'common.select-display-language' | translate }}</ng-template>
 
 <ng-container *ngIf="isLoading">
-    <div class="progress loop"></div>
+    <div class="w-[400px] h-40 flex justify-center items-center">
+        <hlm-spinner />
+    </div>
 </ng-container>
 
 <ng-container *ngIf="!isLoading">
-    <div class="clr-row">
-        <div class="flex pl-2 mb-2">
-            <vdr-form-field [label]="'common.language' | translate" class="mr-2">
-                <select name="options" [(ngModel)]="currentLanguage" (ngModelChange)="updatePreviewLocale()">
-                    <option *ngFor="let code of availableLanguages | sort" [value]="code">
-                        {{ code | uppercase }} ({{ code | localeLanguageName }})
-                    </option>
-                </select>
+    <div class="w-[500px]">
+        <div class="space-y-2 pb-4 border-b border-border">
+            <vdr-form-field [label]="'common.language' | translate">
+                <hlm-select
+                    name="options"
+                    placeholder="Select language"
+                    [(ngModel)]="currentLanguage"
+                    (ngModelChange)="updatePreviewLocale()"
+                >
+                    <hlm-select-trigger class="w-full">
+                        <hlm-select-value />
+                    </hlm-select-trigger>
+                    <hlm-select-content>
+                        <hlm-option *ngFor="let code of availableLanguages | sort" [value]="code">
+                            {{ code | uppercase }} ({{ code | localeLanguageName }})
+                        </hlm-option>
+                    </hlm-select-content>
+                </hlm-select>
             </vdr-form-field>
             <vdr-form-field [label]="'common.locale' | translate">
-                <ng-select appendTo="body" [items]="availableLocales" [(ngModel)]="currentLocale"
-                    (ngModelChange)="updatePreviewLocale()" [placeholder]="'common.browser-default' | translate">
-                    <ng-template ng-label-tmp let-item="item" let-clear="clear">
-                        {{ item }} ({{ item | localeRegionName }})
-                    </ng-template>
-                    <ng-template ng-option-tmp let-item="item">
-                        {{ item }} ({{ item | localeRegionName }})
-                    </ng-template>
-                </ng-select>
+                <hlm-select
+                    [(ngModel)]="currentLocale"
+                    (ngModelChange)="updatePreviewLocale()"
+                    [placeholder]="'common.browser-default' | translate"
+                >
+                    <hlm-select-trigger class="w-full">
+                        <hlm-select-value />
+                    </hlm-select-trigger>
+                    <hlm-select-content>
+                        <hlm-option *ngFor="let item of availableLocales" [value]="item">
+                            {{ item }} ({{ item | localeRegionName }})
+                        </hlm-option>
+                    </hlm-select-content>
+                </hlm-select>
+            </vdr-form-field>
+            <vdr-form-field [label]="'common.currency' | translate">
+                <hlm-select
+                    [(ngModel)]="selectedCurrencyCode"
+                    [placeholder]="'common.browser-default' | translate"
+                >
+                    <hlm-select-trigger class="w-full">
+                        <hlm-select-value />
+                    </hlm-select-trigger>
+                    <hlm-select-content>
+                        <hlm-option *ngFor="let code of availableCurrencyCodes | sort" [value]="code">
+                            {{ code | uppercase }} ({{ code | localeCurrencyName: 'full' : previewLocale }})
+                        </hlm-option>
+                    </hlm-select-content>
+                </hlm-select>
             </vdr-form-field>
         </div>
-    </div>
-    <div class="card">
-        <div class="card-header">
-            <span class="pr-1">{{ 'common.sample-formatting' | translate }}:</span><strong>{{ previewLocale |
-                localeLanguageName : previewLocale }}</strong>
-        </div>
-        <div class="card-block">
-            <div class="clr-row">
-                <div class="clr-col-sm-4">
-                    <vdr-labeled-data [label]="'common.medium-date' | translate">
-                        {{ now | localeDate : 'medium' : previewLocale }}
-                    </vdr-labeled-data>
-                    <vdr-labeled-data [label]="'common.short-date' | translate">
-                        {{ now | localeDate : 'short' : previewLocale }}
-                    </vdr-labeled-data>
-                </div>
-                <div class="clr-col-sm-4">
-                    <select name="currency" class="currency" [(ngModel)]="selectedCurrencyCode">
-                        <option *ngFor="let code of availableCurrencyCodes | sort" [value]="code">
-                            {{ code | uppercase }} ({{ code | localeCurrencyName : 'full' : previewLocale }})
-                        </option>
-                    </select>
-                </div>
-                <div class="clr-col-sm-4">
-                    <vdr-labeled-data [label]="'common.price' | translate">
-                        {{ 12345 | localeCurrency : selectedCurrencyCode : previewLocale }}
-                    </vdr-labeled-data>
-                </div>
+        <div class="pt-4">
+            <div class="flex items-center justify-start gap-2 mb-4">
+                <span>{{ 'common.sample-formatting' | translate }}:</span>
+                <span class="font-semibold">{{ previewLocale | localeLanguageName: previewLocale }}</span>
             </div>
+            <vdr-labeled-data [label]="'common.medium-date' | translate">
+                {{ now | localeDate: 'medium' : previewLocale }}
+            </vdr-labeled-data>
+            <vdr-labeled-data [label]="'common.short-date' | translate">
+                {{ now | localeDate: 'short' : previewLocale }}
+            </vdr-labeled-data>
+            <vdr-labeled-data [label]="'common.price' | translate">
+                {{ 12345 | localeCurrency: selectedCurrencyCode : previewLocale }}
+            </vdr-labeled-data>
         </div>
     </div>
 </ng-container>
 
 <ng-template vdrDialogButtons>
-    <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
-    <button type="submit" (click)="setLanguage()" class="btn btn-primary">
+    <button hlmBtn type="button" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
+    <button hlmBtn type="submit" (click)="setLanguage()" variant="accent">
         {{ 'common.set-language' | translate }}
     </button>
-</ng-template>
+</ng-template>

+ 4 - 1
packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.ts

@@ -28,7 +28,10 @@ export class UiLanguageSwitcherDialogComponent
     readonly browserDefaultLocale: string | undefined;
     readonly now = new Date().toISOString();
 
-    constructor(private dataService: DataService, private changeDetector: ChangeDetectorRef) {
+    constructor(
+        private dataService: DataService,
+        private changeDetector: ChangeDetectorRef,
+    ) {
         const browserLanguage = navigator.language.split('-');
         this.browserDefaultLocale = browserLanguage.length === 1 ? undefined : browserLanguage[1];
     }

+ 29 - 16
packages/admin-ui/src/lib/core/src/providers/modal/modal.service.ts

@@ -8,6 +8,7 @@ import { SimpleDialogComponent } from '../../shared/components/simple-dialog/sim
 import { OverlayHostService } from '../overlay-host/overlay-host.service';
 
 import { Dialog, DialogConfig, ModalOptions } from './modal.types';
+import { HlmDialogService } from '@spartan-ng/ui-dialog-helm';
 
 /**
  * @description
@@ -22,7 +23,7 @@ import { Dialog, DialogConfig, ModalOptions } from './modal.types';
     providedIn: 'root',
 })
 export class ModalService {
-    constructor(private overlayHostService: OverlayHostService) {}
+    constructor(private hlmDialogService: HlmDialogService) {}
 
     /**
      * @description
@@ -69,22 +70,34 @@ export class ModalService {
         component: Type<T> & Type<Dialog<R>>,
         options?: ModalOptions<T>,
     ): Observable<R | undefined> {
-        return from(this.overlayHostService.getHostView()).pipe(
-            mergeMap(hostView => {
-                const modalComponentRef = hostView.createComponent(ModalDialogComponent);
-                const modalInstance: ModalDialogComponent<any> = modalComponentRef.instance;
-                modalInstance.childComponentType = component;
-                modalInstance.options = options;
+        const contentClass = () => {
+            switch (options?.size) {
+                case 'sm':
+                    return 'sm:!max-w-[450px]';
+                case 'lg':
+                    return 'sm:!max-w-[750px]';
+                case 'xl':
+                    return 'sm:!max-w-[900px]';
+                default:
+                    return 'sm:!max-w-[550px]';
+            }
+        };
 
-                return new Observable<R>(subscriber => {
-                    modalInstance.closeModal = (result: R) => {
-                        modalComponentRef.destroy();
-                        subscriber.next(result);
-                        subscriber.complete();
-                    };
-                });
-            }),
-        );
+        const dialogRef = this.hlmDialogService.open(ModalDialogComponent, {
+            context: {
+                options: options,
+                childComponentType: component,
+            },
+            contentClass: contentClass(),
+        });
+
+        return new Observable<R>(subscriber => {
+            dialogRef.closed$.subscribe(res => {
+                console.log({ res });
+                subscriber.next(res);
+                subscriber.complete();
+            });
+        });
     }
 
     /**

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/card/card.component.html

@@ -1,4 +1,4 @@
-<div class="rounded-md py-4 px-6 bg-white shadow-sm border border-slate-200 transition-all" [class.padding-x]="paddingX">
+<div class="rounded-md py-4 px-6 bg-white border border-border transition-all" [class.padding-x]="paddingX">
     <div *ngIf="title || controlsTemplate" class="title-row">
         <span class="text-lg font-semibold text-slate-800">{{ title }}</span>
         <div class="controls" *ngIf="controlsTemplate">

+ 6 - 8
packages/admin-ui/src/lib/core/src/shared/components/form-field/form-field.component.html

@@ -1,8 +1,4 @@
-<div
-    class="form-group"
-    [class.no-label]="!label"
-    [class.clr-error]="formFieldControl?.formControlName?.invalid"
->
+<div [class.no-label]="!label" [class.clr-error]="formFieldControl?.formControlName?.invalid">
     <label *ngIf="label" [for]="for" hlmLabel>
         {{ label }}
     </label>
@@ -18,13 +14,15 @@
         <ng-content></ng-content>
         <button
             *ngIf="readOnlyToggle"
-            type="button"
+            hlmBtn
             [title]="'common.edit-field' | translate"
-            class="btn edit-button"
+            variant="secondary"
+            size="icon"
+            class="bg-border rounded-s-none"
             [class.enabled]="!isReadOnly"
             (click)="setReadOnly(!isReadOnly)"
         >
-            <ng-icon hlm name="lucidePencil"></ng-icon>
+            <ng-icon hlm size="sm" name="lucidePencil"></ng-icon>
         </button>
     </div>
     <div class="error-message" *ngIf="getErrorMessage()">{{ getErrorMessage() }}</div>

+ 2 - 2
packages/admin-ui/src/lib/core/src/shared/components/labeled-data/labeled-data.component.html

@@ -1,4 +1,4 @@
-<div class="label-title">{{ label }}</div>
-<div class="content">
+<div class="text-sm text-muted-foreground">{{ label }}</div>
+<div class="text-accent-foreground">
     <ng-content></ng-content>
 </div>

+ 18 - 13
packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.html

@@ -1,14 +1,19 @@
+<!--        [clrModalClosable]="options?.closable"-->
+<!--        [clrModalSize]="options?.size"-->
+<!--[ngClass]="'modal-valign-' + (options?.verticalAlign || 'center')"-->
 <div [dir]="direction$ | async">
-    <clr-modal [clrModalOpen]="true" (clrModalOpenChange)="modalOpenChange($event)"
-        [clrModalClosable]="options?.closable" [clrModalSize]="options?.size"
-        [ngClass]="'modal-valign-' + (options?.verticalAlign || 'center')">
-        <h3 class="modal-title"><ng-container *ngTemplateOutlet="(titleTemplateRef$ | async)"></ng-container></h3>
-        <div class="modal-body">
-            <vdr-dialog-component-outlet [component]="childComponentType"
-                (create)="onCreate($event)"></vdr-dialog-component-outlet>
-        </div>
-        <div class="modal-footer">
-            <ng-container *ngTemplateOutlet="(buttonsTemplateRef$ | async)"></ng-container>
-        </div>
-    </clr-modal>
-</div>
+    <hlm-dialog-header>
+        <h3 hlmDialogTitle>
+            <ng-container *ngTemplateOutlet="titleTemplateRef$ | async"></ng-container>
+        </h3>
+    </hlm-dialog-header>
+    <div class="py-4">
+        <vdr-dialog-component-outlet
+            [component]="childComponentType"
+            (create)="onCreate($event)"
+        ></vdr-dialog-component-outlet>
+    </div>
+    <hlm-dialog-footer>
+        <ng-container *ngTemplateOutlet="buttonsTemplateRef$ | async"></ng-container>
+    </hlm-dialog-footer>
+</div>

+ 13 - 8
packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.ts

@@ -1,5 +1,6 @@
-import { Component, OnInit, TemplateRef, Type } from '@angular/core';
+import { Component, inject, OnInit, TemplateRef, Type } from '@angular/core';
 import { Subject } from 'rxjs';
+import { BrnDialogRef, injectBrnDialogContext } from '@spartan-ng/brain/dialog';
 
 import {
     LocalizationDirectionType,
@@ -21,11 +22,17 @@ import { DialogButtonsDirective } from './dialog-buttons.directive';
 export class ModalDialogComponent<T extends Dialog<any>> implements OnInit {
     direction$: LocalizationDirectionType;
 
-    childComponentType: Type<T>;
-    closeModal: (result?: any) => void;
     titleTemplateRef$ = new Subject<TemplateRef<any>>();
     buttonsTemplateRef$ = new Subject<TemplateRef<any>>();
-    options?: ModalOptions<T>;
+
+    private readonly _dialogRef = inject<BrnDialogRef<T>>(BrnDialogRef);
+    private readonly _dialogContext = injectBrnDialogContext<{
+        options?: ModalOptions<T>;
+        childComponentType: Type<T>;
+    }>();
+
+    options = this._dialogContext.options;
+    childComponentType = this._dialogContext.childComponentType;
 
     /**
      *
@@ -44,7 +51,7 @@ export class ModalDialogComponent<T extends Dialog<any>> implements OnInit {
      */
     onCreate(componentInstance: T) {
         componentInstance.resolveWith = (result?: any) => {
-            this.closeModal(result);
+            this._dialogRef.close(result);
         };
         if (this.options && this.options.locals) {
             // eslint-disable-next-line
@@ -72,8 +79,6 @@ export class ModalDialogComponent<T extends Dialog<any>> implements OnInit {
      * Called when the modal is closed by clicking the X or the mask.
      */
     modalOpenChange(status: any) {
-        if (status === false) {
-            this.closeModal();
-        }
+        this._dialogRef.close();
     }
 }

+ 13 - 11
packages/admin-ui/src/lib/core/src/shared/components/page-entity-info/page-entity-info.component.html

@@ -1,12 +1,14 @@
-<div class="property">
-    <div class="prop-label">{{ 'common.ID' | translate }}:</div>
-    <div class="value">{{ entity.id }}</div>
-</div>
-<div class="property" *ngIf="entity.createdAt">
-    <div class="prop-label">{{ 'common.created-at' | translate }}:</div>
-    <div class="value">{{ entity.createdAt | localeDate : 'short' }}</div>
-</div>
-<div class="property" *ngIf="entity.updatedAt">
-    <div class="prop-label">{{ 'common.updated-at' | translate }}:</div>
-    <div class="value">{{ entity.updatedAt | localeDate : 'short' }}</div>
+<div class="flex flex-col space-y-1 text-xs text-muted-foreground">
+    <div class="flex items-center justify-between">
+        <span class="text-accent-foreground">{{ 'common.ID' | translate }}:</span>
+        <div>{{ entity.id }}</div>
+    </div>
+    <div class="flex items-center justify-between" *ngIf="entity.createdAt">
+        <span class="text-accent-foreground">{{ 'common.created-at' | translate }}:</span>
+        <div>{{ entity.createdAt | localeDate: 'short' }}</div>
+    </div>
+    <div class="flex items-center justify-between" *ngIf="entity.updatedAt">
+        <span class="text-accent-foreground">{{ 'common.updated-at' | translate }}:</span>
+        <div>{{ entity.updatedAt | localeDate: 'short' }}</div>
+    </div>
 </div>

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/page-title/page-title.component.html

@@ -1,4 +1,4 @@
-<div class="page-title text-2xl font-semibold">
+<div class="text-lg font-semibold py-2">
     <h1>{{ (title$ | async) ?? '' | translate }}</h1>
     <div class="title-actions"><ng-content></ng-content></div>
 </div>

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/page/page.component.html

@@ -3,6 +3,6 @@
     <vdr-page-header-description *ngIf="description">{{ description }}</vdr-page-header-description>
     <vdr-page-header-tabs *ngIf="headerTabs.length > 1" [tabs]="headerTabs"></vdr-page-header-tabs>
 </vdr-page-header>
-<vdr-page-body>
+<vdr-page-body class="px-4">
     <router-outlet />
 </vdr-page-body>

+ 20 - 22
packages/admin-ui/src/lib/core/src/shared/components/tabbed-custom-fields/tabbed-custom-fields.component.html

@@ -1,34 +1,32 @@
 <ng-container *ngIf="1 < tabbedCustomFields.length; else singleGroup">
-    <clr-tabs>
-        <clr-tab *ngFor="let group of tabbedCustomFields">
-            <button clrTabLink>
+    <hlm-tabs [tab]="tabbedCustomFields[0].tabName">
+        <hlm-tabs-list class="flex items-center justify-start">
+            <button [hlmTabsTrigger]="group.tabName" *ngFor="let group of tabbedCustomFields">
                 {{
                     group.tabName === defaultTabName
                         ? ('common.general' | translate)
                         : (group.tabName | translate)
                 }}
             </button>
-            <clr-tab-content *clrIfActive>
-                <div class="mt-2 form-grid">
-                    <ng-container *ngFor="let customField of group.customFields">
-                        <vdr-custom-field-control
-                            *ngIf="customFieldIsSet(customField.name)"
-                            [entityName]="entityName"
-                            [class.form-grid-span]="componentShouldSpanGrid(customField)"
-                            [customFieldsFormGroup]="customFieldsFormGroup"
-                            [customField]="customField"
-                            [readonly]="readonly"
-                            [compact]="compact"
-                            [showLabel]="showLabel"
-                        ></vdr-custom-field-control>
-                    </ng-container>
-                </div>
-            </clr-tab-content>
-        </clr-tab>
-    </clr-tabs>
+        </hlm-tabs-list>
+        <div *ngFor="let group of tabbedCustomFields" class="space-y-4" [hlmTabsContent]="group.tabName">
+            <ng-container *ngFor="let customField of group.customFields">
+                <vdr-custom-field-control
+                    *ngIf="customFieldIsSet(customField.name)"
+                    [entityName]="entityName"
+                    [class.form-grid-span]="componentShouldSpanGrid(customField)"
+                    [customFieldsFormGroup]="customFieldsFormGroup"
+                    [customField]="customField"
+                    [readonly]="readonly"
+                    [compact]="compact"
+                    [showLabel]="showLabel"
+                ></vdr-custom-field-control>
+            </ng-container>
+        </div>
+    </hlm-tabs>
 </ng-container>
 <ng-template #singleGroup>
-    <div class="form-grid">
+    <div class="space-y-4">
         <ng-container *ngFor="let customField of tabbedCustomFields[0]?.customFields">
             <vdr-custom-field-control
                 *ngIf="customFieldIsSet(customField.name)"

+ 2 - 4
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/number-form-input/number-form-input.component.html

@@ -1,8 +1,6 @@
-<vdr-affixed-input
-    [suffix]="suffix"
-    [prefix]="prefix"
->
+<vdr-affixed-input [suffix]="suffix" [prefix]="prefix">
     <input
+        hlmInput
         type="number"
         [readonly]="readonly"
         [min]="min"

+ 2 - 5
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/text-form-input/text-form-input.component.html

@@ -1,6 +1,3 @@
-<vdr-affixed-input
-    [suffix]="suffix"
-    [prefix]="prefix"
->
-    <input type="text" [readonly]="readonly" [formControl]="formControl" />
+<vdr-affixed-input [suffix]="suffix" [prefix]="prefix">
+    <input hlmInput type="text" [readonly]="readonly" [formControl]="formControl" />
 </vdr-affixed-input>

+ 12 - 0
packages/admin-ui/src/lib/core/src/shared/shared.module.ts

@@ -204,6 +204,7 @@ import {
     lucidePanelLeftClose,
     lucidePanelLeftOpen,
     lucidePanelRightOpen,
+    lucidePencil,
     lucideShoppingCart,
     lucideSun,
     lucideTag,
@@ -216,6 +217,11 @@ import {
 import { HlmMenuModule } from '@spartan-ng/ui-menu-helm';
 import { BrnMenuModule } from '@spartan-ng/brain/menu';
 import { HlmBreadCrumbModule } from '@spartan-ng/ui-breadcrumb-helm';
+import { HlmScrollAreaModule } from '@spartan-ng/ui-scrollarea-helm';
+import { HlmDialogModule } from '@spartan-ng/ui-dialog-helm';
+import { BrnDialogModule } from '@spartan-ng/brain/dialog';
+import { HlmSelectModule } from '@spartan-ng/ui-select-helm';
+import { BrnSelectModule } from '@spartan-ng/brain/select';
 
 const IMPORTS = [
     CommonModule,
@@ -243,6 +249,11 @@ const IMPORTS = [
     HlmMenuModule,
     BrnMenuModule,
     HlmBreadCrumbModule,
+    HlmScrollAreaModule,
+    HlmDialogModule,
+    BrnDialogModule,
+    HlmSelectModule,
+    BrnSelectModule,
 ];
 
 const DECLARATIONS = [
@@ -444,6 +455,7 @@ const DYNAMIC_FORM_INPUTS = [
             lucideLanguages,
             lucideMoon,
             lucideSun,
+            lucidePencil,
         }),
     ],
     schemas: [CUSTOM_ELEMENTS_SCHEMA],

+ 8 - 7
packages/admin-ui/src/lib/settings/src/components/profile/profile.component.html

@@ -4,7 +4,8 @@
         <vdr-ab-right>
             <vdr-action-bar-items locationId="profile"></vdr-action-bar-items>
             <button
-                class="btn btn-primary"
+                hlmBtn
+                variant="accent"
                 (click)="save()"
                 [disabled]="detailForm.invalid || detailForm.pristine"
             >
@@ -23,29 +24,29 @@
         </vdr-page-detail-sidebar>
         <vdr-page-block>
             <vdr-card>
-                <div class="form-grid">
+                <div class="space-y-4">
                     <vdr-form-field [label]="'settings.email-address' | translate" for="emailAddress">
-                        <input id="emailAddress" type="text" formControlName="emailAddress" />
+                        <input hlmInput id="emailAddress" type="text" formControlName="emailAddress" />
                     </vdr-form-field>
                     <vdr-form-field [label]="'settings.first-name' | translate" for="firstName">
-                        <input id="firstName" type="text" formControlName="firstName" />
+                        <input hlmInput id="firstName" type="text" formControlName="firstName" />
                     </vdr-form-field>
                     <vdr-form-field [label]="'settings.last-name' | translate" for="lastName">
-                        <input id="lastName" type="text" formControlName="lastName" />
+                        <input hlmInput id="lastName" type="text" formControlName="lastName" />
                     </vdr-form-field>
                     <vdr-form-field
                         *ngIf="isNew$ | async"
                         [label]="'settings.password' | translate"
                         for="password"
                     >
-                        <input id="password" type="password" formControlName="password" />
+                        <input hlmInput id="password" type="password" formControlName="password" />
                     </vdr-form-field>
                     <vdr-form-field
                         [label]="'settings.password' | translate"
                         for="password"
                         [readOnlyToggle]="true"
                     >
-                        <input id="password" type="password" formControlName="password" />
+                        <input hlmInput id="password" type="password" formControlName="password" />
                     </vdr-form-field>
                 </div>
             </vdr-card>

+ 9 - 0
packages/admin-ui/tsconfig.json

@@ -98,6 +98,15 @@
       ],
       "@spartan-ng/ui-breadcrumb-helm": [
         "./src/lib/ui/ui-breadcrumb-helm/src/index.ts"
+      ],
+      "@spartan-ng/ui-scrollarea-helm": [
+        "./src/lib/ui/ui-scrollarea-helm/src/index.ts"
+      ],
+      "@spartan-ng/ui-dialog-helm": [
+        "./src/lib/ui/ui-dialog-helm/src/index.ts"
+      ],
+      "@spartan-ng/ui-select-helm": [
+        "./src/lib/ui/ui-select-helm/src/index.ts"
       ]
     },
     "useDefineForClassFields": false

+ 20 - 1
packages/dev-server/dev-config.ts

@@ -63,7 +63,26 @@ export const devConfig: VendureConfig = {
         paymentMethodHandlers: [dummyPaymentHandler],
     },
 
-    customFields: {},
+    customFields: {
+        Administrator: [
+            {
+                name: 'shortCode',
+                type: 'string',
+                nullable: true,
+            },
+            {
+                name: 'birthday',
+                type: 'datetime',
+                nullable: true,
+            },
+            {
+                name: 'erpId',
+                type: 'int',
+                nullable: true,
+                ui: { tab: 'ERP System' },
+            },
+        ],
+    },
     logger: new DefaultLogger({ level: LogLevel.Info }),
     importExportOptions: {
         importAssetsDir: path.join(__dirname, 'import-assets'),