Skip to content

Commit

Permalink
chore(admin-ui): Add more spartan components
Browse files Browse the repository at this point in the history
  • Loading branch information
dlhck committed Jan 31, 2025
1 parent 58622bd commit 97648b9
Show file tree
Hide file tree
Showing 22 changed files with 578 additions and 0 deletions.
37 changes: 37 additions & 0 deletions packages/admin-ui/src/lib/ui/ui-dialog-helm/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';

import { HlmDialogCloseDirective } from './lib/hlm-dialog-close.directive';
import { HlmDialogContentComponent } from './lib/hlm-dialog-content.component';
import { HlmDialogDescriptionDirective } from './lib/hlm-dialog-description.directive';
import { HlmDialogFooterComponent } from './lib/hlm-dialog-footer.component';
import { HlmDialogHeaderComponent } from './lib/hlm-dialog-header.component';
import { HlmDialogOverlayDirective } from './lib/hlm-dialog-overlay.directive';
import { HlmDialogTitleDirective } from './lib/hlm-dialog-title.directive';
import { HlmDialogComponent } from './lib/hlm-dialog.component';

export * from './lib/hlm-dialog-close.directive';
export * from './lib/hlm-dialog-content.component';
export * from './lib/hlm-dialog-description.directive';
export * from './lib/hlm-dialog-footer.component';
export * from './lib/hlm-dialog-header.component';
export * from './lib/hlm-dialog-overlay.directive';
export * from './lib/hlm-dialog-title.directive';
export * from './lib/hlm-dialog.component';
export * from './lib/hlm-dialog.service';

export const HlmDialogImports = [
HlmDialogComponent,
HlmDialogCloseDirective,
HlmDialogContentComponent,
HlmDialogDescriptionDirective,
HlmDialogFooterComponent,
HlmDialogHeaderComponent,
HlmDialogOverlayDirective,
HlmDialogTitleDirective,
] as const;

@NgModule({
imports: [...HlmDialogImports],
exports: [...HlmDialogImports],
})
export class HlmDialogModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Directive, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

@Directive({
selector: '[hlmDialogClose],[brnDialogClose][hlm]',
standalone: true,
host: {
'[class]': '_computedClass()',
},
})
export class HlmDialogCloseDirective {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected _computedClass = computed(() =>
hlm(
'absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground',
this.userClass(),
),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { NgComponentOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, ViewEncapsulation, computed, inject, input } from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideX } from '@ng-icons/lucide';
import { hlm } from '@spartan-ng/brain/core';
import { BrnDialogCloseDirective, BrnDialogRef, injectBrnDialogContext } from '@spartan-ng/brain/dialog';
import { HlmIconDirective } from '@spartan-ng/ui-icon-helm';
import type { ClassValue } from 'clsx';
import { HlmDialogCloseDirective } from './hlm-dialog-close.directive';

@Component({
selector: 'hlm-dialog-content',
standalone: true,
imports: [NgComponentOutlet, BrnDialogCloseDirective, HlmDialogCloseDirective, NgIcon, HlmIconDirective],
providers: [provideIcons({ lucideX })],
host: {
'[class]': '_computedClass()',
'[attr.data-state]': 'state()',
},
template: `
@if (component) {
<ng-container [ngComponentOutlet]="component" />
} @else {
<ng-content />
}
<button brnDialogClose hlm>
<span class="sr-only">Close</span>
<ng-icon hlm size="sm" name="lucideX" />
</button>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class HlmDialogContentComponent {
private readonly _dialogRef = inject(BrnDialogRef);
private readonly _dialogContext = injectBrnDialogContext({ optional: true });

public readonly state = computed(() => this._dialogRef?.state() ?? 'closed');

public readonly component = this._dialogContext?.$component;
private readonly _dynamicComponentClass = this._dialogContext?.$dynamicComponentClass;

public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected readonly _computedClass = computed(() =>
hlm(
'border-border grid w-full max-w-lg relative gap-4 border bg-background p-6 shadow-lg [animation-duration:200] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[2%] data-[state=open]:slide-in-from-top-[2%] sm:rounded-lg md:w-full',
this.userClass(),
this._dynamicComponentClass,
),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Directive, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import { BrnDialogDescriptionDirective } from '@spartan-ng/brain/dialog';
import type { ClassValue } from 'clsx';

@Directive({
selector: '[hlmDialogDescription]',
standalone: true,
host: {
'[class]': '_computedClass()',
},
hostDirectives: [BrnDialogDescriptionDirective],
})
export class HlmDialogDescriptionDirective {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected _computedClass = computed(() => hlm('text-sm text-muted-foreground', this.userClass()));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

@Component({
selector: 'hlm-dialog-footer',
standalone: true,
template: `
<ng-content />
`,
host: {
'[class]': '_computedClass()',
},
})
export class HlmDialogFooterComponent {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected _computedClass = computed(() =>
hlm('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', this.userClass()),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

@Component({
selector: 'hlm-dialog-header',
standalone: true,
template: `
<ng-content />
`,
host: {
'[class]': '_computedClass()',
},
})
export class HlmDialogHeaderComponent {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected _computedClass = computed(() =>
hlm('flex flex-col space-y-1.5 text-center sm:text-left', this.userClass()),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Directive, computed, effect, input } from '@angular/core';
import { hlm, injectCustomClassSettable } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

export const hlmDialogOverlayClass =
'bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0';

@Directive({
selector: '[hlmDialogOverlay],brn-dialog-overlay[hlm]',
standalone: true,
})
export class HlmDialogOverlayDirective {
private readonly _classSettable = injectCustomClassSettable({ optional: true, host: true });

public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected readonly _computedClass = computed(() => hlm(hlmDialogOverlayClass, this.userClass()));

constructor() {
effect(() => {
this._classSettable?.setClassToCustomElement(this._computedClass());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Directive, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import { BrnDialogTitleDirective } from '@spartan-ng/brain/dialog';
import type { ClassValue } from 'clsx';

@Directive({
selector: '[hlmDialogTitle]',
standalone: true,
host: {
'[class]': '_computedClass()',
},
hostDirectives: [BrnDialogTitleDirective],
})
export class HlmDialogTitleDirective {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected _computedClass = computed(() => hlm('text-lg font-semibold leading-none tracking-tight', this.userClass()));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation, forwardRef } from '@angular/core';
import { BrnDialogComponent, BrnDialogOverlayComponent } from '@spartan-ng/brain/dialog';
import { HlmDialogOverlayDirective } from './hlm-dialog-overlay.directive';

@Component({
selector: 'hlm-dialog',
standalone: true,
imports: [BrnDialogOverlayComponent, HlmDialogOverlayDirective],
providers: [
{
provide: BrnDialogComponent,
useExisting: forwardRef(() => HlmDialogComponent),
},
],
template: `
<brn-dialog-overlay hlm />
<ng-content />
`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
exportAs: 'hlmDialog',
})
export class HlmDialogComponent extends BrnDialogComponent {
constructor() {
super();
this.closeDelay = 100;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { ComponentType } from '@angular/cdk/portal';
import { Injectable, type TemplateRef, inject } from '@angular/core';
import {
type BrnDialogOptions,
BrnDialogService,
DEFAULT_BRN_DIALOG_OPTIONS,
cssClassesToArray,
} from '@spartan-ng/brain/dialog';
import { HlmDialogContentComponent } from './hlm-dialog-content.component';
import { hlmDialogOverlayClass } from './hlm-dialog-overlay.directive';

export type HlmDialogOptions<DialogContext = unknown> = BrnDialogOptions & {
contentClass?: string;
context?: DialogContext;
};

@Injectable({
providedIn: 'root',
})
export class HlmDialogService {
private readonly _brnDialogService = inject(BrnDialogService);

public open(component: ComponentType<unknown> | TemplateRef<unknown>, options?: Partial<HlmDialogOptions>) {
const mergedOptions = {
...DEFAULT_BRN_DIALOG_OPTIONS,
closeDelay: 100,

...(options ?? {}),
backdropClass: cssClassesToArray(`${hlmDialogOverlayClass} ${options?.backdropClass ?? ''}`),
context: { ...(options?.context ?? {}), $component: component, $dynamicComponentClass: options?.contentClass },
};

return this._brnDialogService.open(HlmDialogContentComponent, undefined, mergedOptions.context, mergedOptions);
}
}
10 changes: 10 additions & 0 deletions packages/admin-ui/src/lib/ui/ui-scrollarea-helm/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { HlmScrollAreaDirective } from './lib/hlm-scroll-area.directive';

export * from './lib/hlm-scroll-area.directive';

@NgModule({
imports: [HlmScrollAreaDirective],
exports: [HlmScrollAreaDirective],
})
export class HlmScrollAreaModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Directive, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

@Directive({
selector: 'ng-scrollbar[hlm]',
standalone: true,
host: {
'[class]': '_computedClass()',
'[style.--scrollbar-border-radius.px]': '100',
'[style.--scrollbar-offset]': '3',
'[style.--scrollbar-thumb-color]': '"hsl(var(--border))"',
'[style.--scrollbar-thumb-hover-color]': '"hsl(var(--border))"',
'[style.--scrollbar-thickness]': '7',
},
})
export class HlmScrollAreaDirective {
protected readonly _computedClass = computed(() => hlm('block', this.userClass()));
public readonly userClass = input<ClassValue>('', { alias: 'class' });
}
38 changes: 38 additions & 0 deletions packages/admin-ui/src/lib/ui/ui-select-helm/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NgModule } from '@angular/core';
import { HlmSelectContentDirective } from './lib/hlm-select-content.directive';
import { HlmSelectGroupDirective } from './lib/hlm-select-group.directive';
import { HlmSelectLabelDirective } from './lib/hlm-select-label.directive';
import { HlmSelectOptionComponent } from './lib/hlm-select-option.component';
import { HlmSelectScrollDownComponent } from './lib/hlm-select-scroll-down.component';
import { HlmSelectScrollUpComponent } from './lib/hlm-select-scroll-up.component';
import { HlmSelectTriggerComponent } from './lib/hlm-select-trigger.component';
import { HlmSelectValueDirective } from './lib/hlm-select-value.directive';
import { HlmSelectDirective } from './lib/hlm-select.directive';

export * from './lib/hlm-select-content.directive';
export * from './lib/hlm-select-group.directive';
export * from './lib/hlm-select-label.directive';
export * from './lib/hlm-select-option.component';
export * from './lib/hlm-select-scroll-down.component';
export * from './lib/hlm-select-scroll-up.component';
export * from './lib/hlm-select-trigger.component';
export * from './lib/hlm-select-value.directive';
export * from './lib/hlm-select.directive';

export const HlmSelectImports = [
HlmSelectContentDirective,
HlmSelectTriggerComponent,
HlmSelectOptionComponent,
HlmSelectValueDirective,
HlmSelectDirective,
HlmSelectScrollUpComponent,
HlmSelectScrollDownComponent,
HlmSelectLabelDirective,
HlmSelectGroupDirective,
] as const;

@NgModule({
imports: [...HlmSelectImports],
exports: [...HlmSelectImports],
})
export class HlmSelectModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Directive, computed, input } from '@angular/core';
import { hlm, injectExposedSideProvider, injectExposesStateProvider } from '@spartan-ng/brain/core';
import type { ClassValue } from 'clsx';

@Directive({
selector: '[hlmSelectContent], hlm-select-content',
standalone: true,
host: {
'[class]': '_computedClass()',
'[attr.data-state]': '_stateProvider?.state() ?? "open"',
'[attr.data-side]': '_sideProvider?.side() ?? "bottom"',
},
})
export class HlmSelectContentDirective {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
public readonly stickyLabels = input<boolean>(false);
protected readonly _stateProvider = injectExposesStateProvider({ optional: true });
protected readonly _sideProvider = injectExposedSideProvider({ optional: true });

protected readonly _computedClass = computed(() =>
hlm(
'w-full relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md p-1 data-[side=bottom]:top-[2px] data-[side=top]:bottom-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
this.userClass(),
),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Directive, computed, input } from '@angular/core';
import { hlm } from '@spartan-ng/brain/core';
import { BrnSelectGroupDirective } from '@spartan-ng/brain/select';
import type { ClassValue } from 'clsx';

@Directive({
selector: '[hlmSelectGroup], hlm-select-group',
hostDirectives: [BrnSelectGroupDirective],
standalone: true,
host: {
'[class]': '_computedClass()',
},
})
export class HlmSelectGroupDirective {
public readonly userClass = input<ClassValue>('', { alias: 'class' });
protected readonly _computedClass = computed(() => hlm(this.userClass()));
}
Loading

0 comments on commit 97648b9

Please sign in to comment.