mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
feat: add InfoButton component with styling and functionality; update process schemas to include tags
This commit is contained in:
49
apps/isa-app/stories/ui/buttons/ui-info-button.stories.ts
Normal file
49
apps/isa-app/stories/ui/buttons/ui-info-button.stories.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { InfoButtonComponent } from '@isa/ui/buttons';
|
||||
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
import * as IsaIcons from '@isa/icons';
|
||||
import { argsToTemplate, moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
|
||||
|
||||
type InfoButtonComponentInputs = {
|
||||
icon: string;
|
||||
pending: boolean;
|
||||
label: string;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
const meta: Meta<InfoButtonComponentInputs> = {
|
||||
component: InfoButtonComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [NgIconComponent],
|
||||
providers: [provideIcons(IsaIcons)],
|
||||
}),
|
||||
],
|
||||
title: 'ui/buttons/InfoButton',
|
||||
args: {},
|
||||
argTypes: {
|
||||
icon: { control: 'select', options: Object.keys(IsaIcons) },
|
||||
label: { control: 'text' },
|
||||
disabled: { control: 'boolean' },
|
||||
pending: {
|
||||
control: 'boolean',
|
||||
},
|
||||
},
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `<ui-info-button ${argsToTemplate(args, { exclude: ['disabled', 'icon'] })} ${args.disabled ? 'disabled' : ''}>
|
||||
<span>${args.label}</span>
|
||||
<ng-icon name="${args.icon}"></ng-icon>
|
||||
</ui-info-button>`,
|
||||
}),
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<InfoButtonComponentInputs>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
icon: 'isaNavigationLogout',
|
||||
label: 'STA',
|
||||
},
|
||||
};
|
||||
@@ -2,8 +2,10 @@ import { z } from 'zod';
|
||||
|
||||
export const AddProcessSchema = z.object({
|
||||
name: z.string().nonempty(),
|
||||
tags: z.array(z.string()),
|
||||
});
|
||||
|
||||
export const PatchProcessSchema = z.object({
|
||||
name: z.string().nonempty().optional(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
@@ -34,10 +34,12 @@ export const ProcessService = signalStore(
|
||||
})),
|
||||
withMethods((store) => ({
|
||||
addProcess(add: z.infer<typeof AddProcessSchema>) {
|
||||
const parsed = AddProcessSchema.parse(add);
|
||||
const process: Process = {
|
||||
name: AddProcessSchema.parse(add).name,
|
||||
name: parsed.name,
|
||||
id: store.nextId(),
|
||||
createdAt: Date.now(),
|
||||
tags: parsed.tags,
|
||||
};
|
||||
patchState(store, addEntity(process));
|
||||
return process;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export interface Process {
|
||||
id: number;
|
||||
name: string;
|
||||
tags: string[];
|
||||
createdAt: number;
|
||||
activatedAt?: number;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './lib/button.component';
|
||||
export * from './lib/icon-button.component';
|
||||
export * from './lib/info-button.component';
|
||||
export * from './lib/text-button.component';
|
||||
export * from './lib/types';
|
||||
|
||||
6
libs/ui/buttons/src/lib/info-button.component.html
Normal file
6
libs/ui/buttons/src/lib/info-button.component.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<ng-content></ng-content>
|
||||
@if (pending()) {
|
||||
<ng-icon class="animate-spin" name="isaLoading"></ng-icon>
|
||||
} @else {
|
||||
<ng-content select="ng-icon"></ng-content>
|
||||
}
|
||||
35
libs/ui/buttons/src/lib/info-button.component.scss
Normal file
35
libs/ui/buttons/src/lib/info-button.component.scss
Normal file
@@ -0,0 +1,35 @@
|
||||
.ui-info-button {
|
||||
display: inline-flex;
|
||||
padding-left: 1rem;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
||||
@apply rounded-full cursor-pointer bg-isa-neutral-100 isa-text-body-1-bold text-isa-neutral-900;
|
||||
|
||||
ng-icon {
|
||||
display: flex;
|
||||
padding: 0.75rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@apply rounded-full bg-isa-neutral-300 size-12;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
ng-icon {
|
||||
@apply bg-isa-neutral-400;
|
||||
}
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
ng-icon {
|
||||
@apply text-isa-white bg-isa-neutral-500;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&[disabled] {
|
||||
@apply bg-isa-neutral-200 text-isa-neutral-500 cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
27
libs/ui/buttons/src/lib/info-button.component.ts
Normal file
27
libs/ui/buttons/src/lib/info-button.component.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
input,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { isaLoading } from '@isa/icons';
|
||||
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-info-button, [uiInfoButton]',
|
||||
templateUrl: './info-button.component.html',
|
||||
styleUrls: ['./info-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [NgIconComponent],
|
||||
providers: [provideIcons({ isaLoading })],
|
||||
host: {
|
||||
'[class]': '["ui-info-button", pendingClass()]',
|
||||
},
|
||||
})
|
||||
export class InfoButtonComponent {
|
||||
pending = input<boolean>(false);
|
||||
|
||||
pendingClass = computed(() => (this.pending() ? 'ui-info-button--pending' : ''));
|
||||
}
|
||||
Reference in New Issue
Block a user