pdm-ui-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FIGMA_COMPONENT_AUDIT.md +154 -0
- package/README.md +72 -0
- package/ng-package.json +7 -0
- package/package.json +29 -0
- package/src/lib/components/accordion/accordion.component.html +34 -0
- package/src/lib/components/accordion/accordion.component.ts +38 -0
- package/src/lib/components/alert/alert.component.html +52 -0
- package/src/lib/components/alert/alert.component.ts +25 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.html +41 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.ts +45 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.html +11 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.ts +18 -0
- package/src/lib/components/avatar/avatar.component.html +21 -0
- package/src/lib/components/avatar/avatar.component.ts +32 -0
- package/src/lib/components/badge/badge.component.html +28 -0
- package/src/lib/components/badge/badge.component.ts +23 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.html +39 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.ts +26 -0
- package/src/lib/components/button/button.component.html +15 -0
- package/src/lib/components/button/button.component.ts +84 -0
- package/src/lib/components/button-group/button-group.component.html +39 -0
- package/src/lib/components/button-group/button-group.component.ts +15 -0
- package/src/lib/components/calendar/calendar.component.html +73 -0
- package/src/lib/components/calendar/calendar.component.ts +78 -0
- package/src/lib/components/card/card.component.html +77 -0
- package/src/lib/components/card/card.component.ts +39 -0
- package/src/lib/components/carousel/carousel.component.html +86 -0
- package/src/lib/components/carousel/carousel.component.ts +100 -0
- package/src/lib/components/chart/chart.component.html +143 -0
- package/src/lib/components/chart/chart.component.ts +147 -0
- package/src/lib/components/checkbox/checkbox.component.html +38 -0
- package/src/lib/components/checkbox/checkbox.component.ts +32 -0
- package/src/lib/components/collapsible/collapsible.component.html +26 -0
- package/src/lib/components/collapsible/collapsible.component.ts +29 -0
- package/src/lib/components/combobox/combobox.component.html +42 -0
- package/src/lib/components/combobox/combobox.component.ts +32 -0
- package/src/lib/components/command/command.component.html +55 -0
- package/src/lib/components/command/command.component.ts +67 -0
- package/src/lib/components/context-menu/context-menu.component.html +47 -0
- package/src/lib/components/context-menu/context-menu.component.ts +67 -0
- package/src/lib/components/data-table/data-table.component.html +63 -0
- package/src/lib/components/data-table/data-table.component.ts +78 -0
- package/src/lib/components/date-picker/date-picker.component.html +38 -0
- package/src/lib/components/date-picker/date-picker.component.ts +34 -0
- package/src/lib/components/dialog/dialog.component.html +78 -0
- package/src/lib/components/dialog/dialog.component.ts +55 -0
- package/src/lib/components/drawer/drawer.component.html +56 -0
- package/src/lib/components/drawer/drawer.component.ts +43 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.html +56 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.ts +126 -0
- package/src/lib/components/empty/empty.component.html +29 -0
- package/src/lib/components/empty/empty.component.ts +35 -0
- package/src/lib/components/field/field.component.html +22 -0
- package/src/lib/components/field/field.component.ts +28 -0
- package/src/lib/components/hover-card/hover-card.component.html +24 -0
- package/src/lib/components/hover-card/hover-card.component.ts +36 -0
- package/src/lib/components/icon/icon.component.html +286 -0
- package/src/lib/components/icon/icon.component.ts +133 -0
- package/src/lib/components/input/input.component.html +22 -0
- package/src/lib/components/input/input.component.ts +33 -0
- package/src/lib/components/input-group/input-group.component.html +31 -0
- package/src/lib/components/input-group/input-group.component.ts +26 -0
- package/src/lib/components/input-otp/input-otp.component.html +25 -0
- package/src/lib/components/input-otp/input-otp.component.ts +146 -0
- package/src/lib/components/input-password/input-password.component.html +64 -0
- package/src/lib/components/input-password/input-password.component.ts +46 -0
- package/src/lib/components/item/item.component.html +10 -0
- package/src/lib/components/item/item.component.ts +12 -0
- package/src/lib/components/kbd/kbd.component.html +3 -0
- package/src/lib/components/kbd/kbd.component.ts +10 -0
- package/src/lib/components/label/label.component.html +7 -0
- package/src/lib/components/label/label.component.ts +12 -0
- package/src/lib/components/menubar/menubar.component.html +16 -0
- package/src/lib/components/menubar/menubar.component.ts +29 -0
- package/src/lib/components/native-select/native-select.component.html +17 -0
- package/src/lib/components/native-select/native-select.component.ts +28 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.html +15 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.ts +17 -0
- package/src/lib/components/pagination/pagination.component.html +30 -0
- package/src/lib/components/pagination/pagination.component.ts +37 -0
- package/src/lib/components/popover/popover.component.html +6 -0
- package/src/lib/components/popover/popover.component.ts +40 -0
- package/src/lib/components/progress/progress.component.html +9 -0
- package/src/lib/components/progress/progress.component.ts +20 -0
- package/src/lib/components/radio-group/radio-group.component.html +25 -0
- package/src/lib/components/radio-group/radio-group.component.ts +30 -0
- package/src/lib/components/scroll-area/scroll-area.component.html +5 -0
- package/src/lib/components/scroll-area/scroll-area.component.ts +11 -0
- package/src/lib/components/select/select.component.html +14 -0
- package/src/lib/components/select/select.component.ts +27 -0
- package/src/lib/components/separator/separator.component.html +5 -0
- package/src/lib/components/separator/separator.component.ts +16 -0
- package/src/lib/components/sheet/sheet.component.html +10 -0
- package/src/lib/components/sheet/sheet.component.ts +28 -0
- package/src/lib/components/sidebar/sidebar.component.html +3 -0
- package/src/lib/components/sidebar/sidebar.component.ts +11 -0
- package/src/lib/components/skeleton/skeleton.component.html +1 -0
- package/src/lib/components/skeleton/skeleton.component.ts +10 -0
- package/src/lib/components/slider/slider.component.html +15 -0
- package/src/lib/components/slider/slider.component.ts +31 -0
- package/src/lib/components/sonner/sonner.component.html +10 -0
- package/src/lib/components/sonner/sonner.component.ts +25 -0
- package/src/lib/components/spinner/spinner.component.html +6 -0
- package/src/lib/components/spinner/spinner.component.ts +11 -0
- package/src/lib/components/switch/switch.component.html +14 -0
- package/src/lib/components/switch/switch.component.ts +20 -0
- package/src/lib/components/table/table.component.html +5 -0
- package/src/lib/components/table/table.component.ts +10 -0
- package/src/lib/components/tabs/tabs.component.html +21 -0
- package/src/lib/components/tabs/tabs.component.ts +26 -0
- package/src/lib/components/textarea/textarea.component.html +21 -0
- package/src/lib/components/textarea/textarea.component.ts +28 -0
- package/src/lib/components/toggle/toggle.component.html +16 -0
- package/src/lib/components/toggle/toggle.component.ts +29 -0
- package/src/lib/components/toggle-group/toggle-group.component.html +17 -0
- package/src/lib/components/toggle-group/toggle-group.component.ts +26 -0
- package/src/lib/components/tooltip/tooltip.component.html +6 -0
- package/src/lib/components/tooltip/tooltip.component.ts +20 -0
- package/src/lib/pdm-ui-kit.module.ts +126 -0
- package/src/public-api.ts +58 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import type { PdmIconName } from '../icon/icon.component';
|
|
3
|
+
|
|
4
|
+
export interface PdmCommandItem {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
group?: string;
|
|
8
|
+
icon?: PdmIconName;
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'pdm-command',
|
|
15
|
+
templateUrl: './command.component.html',
|
|
16
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
17
|
+
})
|
|
18
|
+
export class PdmCommandComponent {
|
|
19
|
+
@Input() open = true;
|
|
20
|
+
@Input() hintLabel = 'Press';
|
|
21
|
+
@Input() hintKey = 'J';
|
|
22
|
+
@Input() placeholder = 'Type a command or search...';
|
|
23
|
+
@Input() emptyMessage = 'No results found.';
|
|
24
|
+
@Input() items: PdmCommandItem[] = [
|
|
25
|
+
{ label: 'Calendar', value: 'calendar', group: 'Suggestions', icon: 'calendar' },
|
|
26
|
+
{ label: 'Search emoji', value: 'emoji', group: 'Suggestions', icon: 'smile' },
|
|
27
|
+
{ label: 'Calculator', value: 'calculator', group: 'Suggestions', icon: 'calculator', disabled: true },
|
|
28
|
+
{ label: 'Profile', value: 'profile', group: 'Settings', icon: 'user', shortcut: '⌘P' },
|
|
29
|
+
{ label: 'Billing', value: 'billing', group: 'Settings', icon: 'credit-card', shortcut: '⌘B' },
|
|
30
|
+
{ label: 'Settings', value: 'settings', group: 'Settings', icon: 'settings', shortcut: '⌘S' }
|
|
31
|
+
];
|
|
32
|
+
@Input() className = '';
|
|
33
|
+
|
|
34
|
+
@Output() itemSelect = new EventEmitter<string>();
|
|
35
|
+
@Output() openChange = new EventEmitter<boolean>();
|
|
36
|
+
|
|
37
|
+
query = '';
|
|
38
|
+
|
|
39
|
+
get filteredItems(): PdmCommandItem[] {
|
|
40
|
+
const q = this.query.toLowerCase().trim();
|
|
41
|
+
if (!q) return this.items;
|
|
42
|
+
return this.items.filter((item) => item.label.toLowerCase().includes(q));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get groupedItems(): { name: string; items: PdmCommandItem[] }[] {
|
|
46
|
+
const map = new Map<string, PdmCommandItem[]>();
|
|
47
|
+
for (const item of this.filteredItems) {
|
|
48
|
+
const key = item.group || '';
|
|
49
|
+
const arr = map.get(key) ?? [];
|
|
50
|
+
arr.push(item);
|
|
51
|
+
map.set(key, arr);
|
|
52
|
+
}
|
|
53
|
+
return Array.from(map.entries()).map(([name, items]) => ({ name, items }));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onQueryChange(event: Event): void {
|
|
57
|
+
this.query = (event.target as HTMLInputElement).value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toggleOpen(): void {
|
|
61
|
+
this.openChange.emit(!this.open);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
select(value: string): void {
|
|
65
|
+
this.itemSelect.emit(value);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<div class="relative" [ngClass]="className" (contextmenu)="onContextMenu($event)">
|
|
2
|
+
<div
|
|
3
|
+
class="flex items-center justify-center rounded-[8px] border border-dashed border-[#e5e5e5]"
|
|
4
|
+
[style.width.px]="width"
|
|
5
|
+
[style.height.px]="height"
|
|
6
|
+
>
|
|
7
|
+
<span class="text-[14px] font-medium leading-5 text-[#0a0a0a]">{{ triggerLabel }}</span>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
*ngIf="open"
|
|
12
|
+
class="fixed z-50 w-[208px] rounded-[8px] border border-[#e5e5e5] bg-white shadow-[0_2px_4px_-2px_rgba(0,0,0,0.1),0_4px_6px_-1px_rgba(0,0,0,0.1)]"
|
|
13
|
+
[style.left.px]="x + 4"
|
|
14
|
+
[style.top.px]="y + 2"
|
|
15
|
+
>
|
|
16
|
+
<div class="px-1 pt-1">
|
|
17
|
+
<ng-container *ngFor="let item of items">
|
|
18
|
+
<div *ngIf="item.type === 'separator'" class="my-1 border-t border-[#e5e5e5]"></div>
|
|
19
|
+
|
|
20
|
+
<div *ngIf="item.type === 'label'" class="h-8 px-8 py-[6px] text-[14px] font-semibold leading-5 text-[#0a0a0a]">
|
|
21
|
+
{{ item.label }}
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<button
|
|
25
|
+
*ngIf="!item.type || item.type === 'item'"
|
|
26
|
+
type="button"
|
|
27
|
+
[disabled]="item.disabled"
|
|
28
|
+
class="flex h-8 w-full items-center rounded-[6px] py-[6px] pr-2 text-left disabled:opacity-50"
|
|
29
|
+
[ngClass]="item.inset ? 'pl-8' : 'px-2'"
|
|
30
|
+
(click)="select(item)"
|
|
31
|
+
>
|
|
32
|
+
<span class="mr-2 inline-flex w-4 shrink-0 items-center justify-center text-[#0a0a0a]">
|
|
33
|
+
<svg *ngIf="item.checked" viewBox="0 0 24 24" class="h-3.5 w-3.5" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
34
|
+
<path d="M5 12.5L9.2 16.7L19 7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
35
|
+
</svg>
|
|
36
|
+
<span *ngIf="item.selectedDot" class="h-2 w-2 rounded-full bg-[#0a0a0a]"></span>
|
|
37
|
+
</span>
|
|
38
|
+
<span class="min-w-0 flex-1 truncate text-[14px] leading-5 text-[#0a0a0a]">{{ item.label }}</span>
|
|
39
|
+
<span *ngIf="item.shortcut" class="text-[12px] leading-4 text-[#737373]">{{ item.shortcut }}</span>
|
|
40
|
+
<svg *ngIf="item.showChevron" viewBox="0 0 24 24" class="h-3.5 w-3.5 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
41
|
+
<path d="M9 6L15 12L9 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
44
|
+
</ng-container>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
|
2
|
+
import { PdmMenuItem } from '../dropdown-menu/dropdown-menu.component';
|
|
3
|
+
|
|
4
|
+
export interface PdmContextMenuItem extends PdmMenuItem {
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
selectedDot?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'pdm-context-menu',
|
|
11
|
+
templateUrl: './context-menu.component.html',
|
|
12
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
13
|
+
})
|
|
14
|
+
export class PdmContextMenuComponent {
|
|
15
|
+
@Input() items: PdmContextMenuItem[] = [
|
|
16
|
+
{ type: 'item', label: 'Back', value: 'back', inset: true, shortcut: '⌘[' },
|
|
17
|
+
{ type: 'item', label: 'Forward', value: 'forward', inset: true, shortcut: '⌘]', disabled: true },
|
|
18
|
+
{ type: 'item', label: 'Reload', value: 'reload', inset: true, shortcut: '⌘R' },
|
|
19
|
+
{ type: 'item', label: 'More Tools', value: 'more-tools', inset: true, showChevron: true },
|
|
20
|
+
{ type: 'separator' },
|
|
21
|
+
{ type: 'item', label: 'Show Bookmarks Bar', value: 'show-bookmarks', checked: true },
|
|
22
|
+
{ type: 'item', label: 'Show Full URLs', value: 'show-urls', inset: true },
|
|
23
|
+
{ type: 'separator' },
|
|
24
|
+
{ type: 'label', label: 'People' },
|
|
25
|
+
{ type: 'separator' },
|
|
26
|
+
{ type: 'item', label: 'Pedro Duarte', value: 'pedro', selectedDot: true },
|
|
27
|
+
{ type: 'item', label: 'Colm Tuite', value: 'colm', inset: true }
|
|
28
|
+
];
|
|
29
|
+
@Input() className = '';
|
|
30
|
+
@Input() triggerLabel = 'Right click here';
|
|
31
|
+
@Input() width = 300;
|
|
32
|
+
@Input() height = 150;
|
|
33
|
+
@Output() itemSelect = new EventEmitter<string>();
|
|
34
|
+
|
|
35
|
+
open = false;
|
|
36
|
+
x = 0;
|
|
37
|
+
y = 0;
|
|
38
|
+
|
|
39
|
+
constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
|
|
40
|
+
|
|
41
|
+
onContextMenu(event: MouseEvent): void {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
this.x = event.clientX;
|
|
44
|
+
this.y = event.clientY;
|
|
45
|
+
this.open = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
select(item: PdmContextMenuItem): void {
|
|
49
|
+
if (item.disabled || item.type === 'separator' || item.type === 'label' || !item.value) return;
|
|
50
|
+
this.itemSelect.emit(item.value);
|
|
51
|
+
this.open = false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@HostListener('document:keydown.escape')
|
|
55
|
+
onEsc(): void {
|
|
56
|
+
this.open = false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@HostListener('document:click', ['$event'])
|
|
60
|
+
onDocumentClick(event: MouseEvent): void {
|
|
61
|
+
if (!this.open) return;
|
|
62
|
+
const target = event.target as Node | null;
|
|
63
|
+
if (target && !this.elementRef.nativeElement.contains(target)) {
|
|
64
|
+
this.open = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<section [ngClass]="['flex w-[590px] flex-col items-end', className]">
|
|
2
|
+
<div class="flex w-full items-center justify-between py-4">
|
|
3
|
+
<input
|
|
4
|
+
type="text"
|
|
5
|
+
[placeholder]="filterPlaceholder"
|
|
6
|
+
[value]="query"
|
|
7
|
+
(input)="onQueryInput($event)"
|
|
8
|
+
class="h-9 w-[384px] rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 text-[16px] leading-6 text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)] placeholder:text-[#737373] outline-none"
|
|
9
|
+
/>
|
|
10
|
+
|
|
11
|
+
<button type="button" class="inline-flex h-9 items-center gap-2 rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-2 shadow-[0_1px_2px_rgba(0,0,0,0.1)]">
|
|
12
|
+
<span class="text-[14px] font-medium leading-5 text-[#0a0a0a]">{{ columnsLabel }}</span>
|
|
13
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
14
|
+
<path d="M7 10L12 15L17 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
15
|
+
</svg>
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="w-full overflow-hidden rounded-[8px] border border-[#e5e5e5] bg-white">
|
|
20
|
+
<table class="w-full border-collapse text-[14px] leading-5 text-[#0a0a0a]">
|
|
21
|
+
<thead>
|
|
22
|
+
<tr class="border-b border-[#e5e5e5]">
|
|
23
|
+
<th class="w-[32px] px-2 text-left font-medium"><input type="checkbox" class="h-4 w-4 rounded-[4px] border border-[#e5e5e5]" /></th>
|
|
24
|
+
<th class="w-[120px] px-2 py-2 text-left font-medium">Status</th>
|
|
25
|
+
<th class="w-[270px] px-2 py-2 text-left font-medium">
|
|
26
|
+
<button type="button" class="inline-flex items-center gap-1 rounded-[6px] px-3 py-2">
|
|
27
|
+
<span>Email</span>
|
|
28
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
29
|
+
<path d="M8 6L4 10L8 14M16 18L20 14L16 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
30
|
+
</svg>
|
|
31
|
+
</button>
|
|
32
|
+
</th>
|
|
33
|
+
<th class="w-[100px] px-2 py-2 text-right font-medium">Amount</th>
|
|
34
|
+
<th class="px-2 py-2"></th>
|
|
35
|
+
</tr>
|
|
36
|
+
</thead>
|
|
37
|
+
|
|
38
|
+
<tbody>
|
|
39
|
+
<tr *ngFor="let row of pagedRows" class="border-b border-[#e5e5e5] last:border-b-0">
|
|
40
|
+
<td class="px-2 py-2"><input type="checkbox" [checked]="row.selected" (change)="onToggleRow(row, $event)" class="h-4 w-4 rounded-[4px] border border-[#e5e5e5]" /></td>
|
|
41
|
+
<td class="px-2 py-2">{{ row.status }}</td>
|
|
42
|
+
<td class="px-2 py-2">{{ row.email }}</td>
|
|
43
|
+
<td class="px-2 py-2 text-right">{{ row.amount }}</td>
|
|
44
|
+
<td class="px-2 py-2">
|
|
45
|
+
<button type="button" class="inline-flex h-8 w-8 items-center justify-center" (click)="onAction(row)">
|
|
46
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
47
|
+
<circle cx="6" cy="12" r="1.5" fill="currentColor"></circle>
|
|
48
|
+
<circle cx="12" cy="12" r="1.5" fill="currentColor"></circle>
|
|
49
|
+
<circle cx="18" cy="12" r="1.5" fill="currentColor"></circle>
|
|
50
|
+
</svg>
|
|
51
|
+
</button>
|
|
52
|
+
</td>
|
|
53
|
+
</tr>
|
|
54
|
+
</tbody>
|
|
55
|
+
</table>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="flex w-full items-center gap-2 py-4">
|
|
59
|
+
<p class="flex-1 pr-2 text-[14px] leading-5 text-[#737373]">{{ selectedCount }} of {{ rows.length }} row(s) selected.</p>
|
|
60
|
+
<button type="button" class="h-9 rounded-[10px] border border-[#e5e5e5] bg-white px-4 text-[14px] font-medium text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)] disabled:opacity-50" [disabled]="page <= 1" (click)="previous()">Previous</button>
|
|
61
|
+
<button type="button" class="h-9 rounded-[10px] border border-[#e5e5e5] bg-white px-4 text-[14px] font-medium text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)] disabled:opacity-50" [disabled]="page >= totalPages" (click)="next()">Next</button>
|
|
62
|
+
</div>
|
|
63
|
+
</section>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export interface PdmDataTableRow {
|
|
4
|
+
id: string;
|
|
5
|
+
status: string;
|
|
6
|
+
email: string;
|
|
7
|
+
amount: string;
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'pdm-data-table',
|
|
13
|
+
templateUrl: './data-table.component.html',
|
|
14
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
15
|
+
})
|
|
16
|
+
export class PdmDataTableComponent {
|
|
17
|
+
@Input() className = '';
|
|
18
|
+
@Input() filterPlaceholder = 'Filter emails...';
|
|
19
|
+
@Input() columnsLabel = 'Columns';
|
|
20
|
+
@Input() rows: PdmDataTableRow[] = [
|
|
21
|
+
{ id: '1', status: 'Success', email: 'ken99@yahoo.com', amount: '$316.00' },
|
|
22
|
+
{ id: '2', status: 'Success', email: 'abe45@gmail.com', amount: '$242.00' },
|
|
23
|
+
{ id: '3', status: 'Processing', email: 'monserrat44@gmail.com', amount: '$837.00' },
|
|
24
|
+
{ id: '4', status: 'Success', email: 'silas22@gmail.com', amount: '$874.00' },
|
|
25
|
+
{ id: '5', status: 'Failed', email: 'carmella@hotmail.com', amount: '$721.00' }
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
@Input() page = 1;
|
|
29
|
+
@Input() pageSize = 5;
|
|
30
|
+
@Input() query = '';
|
|
31
|
+
|
|
32
|
+
@Output() queryChange = new EventEmitter<string>();
|
|
33
|
+
@Output() rowAction = new EventEmitter<string>();
|
|
34
|
+
@Output() pageChange = new EventEmitter<number>();
|
|
35
|
+
@Output() selectionChange = new EventEmitter<{ id: string; selected: boolean }>();
|
|
36
|
+
|
|
37
|
+
get filteredRows(): PdmDataTableRow[] {
|
|
38
|
+
const q = this.query.trim().toLowerCase();
|
|
39
|
+
if (!q) return this.rows;
|
|
40
|
+
return this.rows.filter((r) => r.email.toLowerCase().includes(q));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get pagedRows(): PdmDataTableRow[] {
|
|
44
|
+
const start = (this.page - 1) * this.pageSize;
|
|
45
|
+
return this.filteredRows.slice(start, start + this.pageSize);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get totalPages(): number {
|
|
49
|
+
return Math.max(1, Math.ceil(this.filteredRows.length / this.pageSize));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get selectedCount(): number {
|
|
53
|
+
return this.rows.filter((row) => row.selected).length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onQueryInput(event: Event): void {
|
|
57
|
+
const value = (event.target as HTMLInputElement).value;
|
|
58
|
+
this.queryChange.emit(value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onToggleRow(row: PdmDataTableRow, event: Event): void {
|
|
62
|
+
this.selectionChange.emit({ id: row.id, selected: (event.target as HTMLInputElement).checked });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
previous(): void {
|
|
66
|
+
if (this.page <= 1) return;
|
|
67
|
+
this.pageChange.emit(this.page - 1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
next(): void {
|
|
71
|
+
if (this.page >= this.totalPages) return;
|
|
72
|
+
this.pageChange.emit(this.page + 1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onAction(row: PdmDataTableRow): void {
|
|
76
|
+
this.rowAction.emit(row.id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<section [ngClass]="['flex flex-col gap-3', className]" class="w-[250px]">
|
|
2
|
+
<label class="text-[14px] font-medium leading-5 text-[#0a0a0a]">{{ label }}</label>
|
|
3
|
+
|
|
4
|
+
<div class="flex items-center gap-2" *ngIf="variant === 'date-time'">
|
|
5
|
+
<button type="button" class="flex h-9 w-[150px] items-center justify-between rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 shadow-[0_1px_2px_rgba(0,0,0,0.1)]" (click)="toggle()">
|
|
6
|
+
<span class="truncate text-[12px] leading-4 text-[#0a0a0a]">{{ value }}</span>
|
|
7
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 10L12 15L17 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
|
8
|
+
</button>
|
|
9
|
+
<div class="flex h-9 w-[92px] items-center rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 text-[12px] leading-4 text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">{{ time }}</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div *ngIf="variant !== 'date-time'" class="flex flex-col gap-2">
|
|
13
|
+
<button type="button" class="flex h-9 w-[192px] items-center justify-between rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 shadow-[0_1px_2px_rgba(0,0,0,0.1)]" (click)="toggle()">
|
|
14
|
+
<span class="truncate text-[16px] leading-6 text-[#0a0a0a]">{{ variant === 'natural-language' ? naturalLanguageValue : value }}</span>
|
|
15
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 10L12 15L17 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
|
16
|
+
</button>
|
|
17
|
+
|
|
18
|
+
<p *ngIf="variant === 'natural-language'" class="max-w-[192px] text-[12px] leading-4 text-[#737373]">{{ naturalLanguageHint }}</p>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div *ngIf="open" class="w-[250px] rounded-[10px] border border-[#e5e5e5] bg-white p-3 shadow-[0_1px_3px_rgba(0,0,0,0.1)]">
|
|
22
|
+
<div class="mb-4 flex items-center justify-between">
|
|
23
|
+
<button type="button" class="h-8 w-8 rounded-[6px] text-[#0a0a0a]">‹</button>
|
|
24
|
+
<div class="flex items-center gap-1.5">
|
|
25
|
+
<button type="button" class="inline-flex h-8 items-center gap-1 rounded-[6px] border border-[#e5e5e5] px-2 text-[14px] font-medium text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">{{ month }} <span>˅</span></button>
|
|
26
|
+
<button type="button" class="inline-flex h-8 items-center gap-1 rounded-[6px] border border-[#e5e5e5] px-2 text-[14px] font-medium text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">{{ year }} <span>˅</span></button>
|
|
27
|
+
</div>
|
|
28
|
+
<button type="button" class="h-8 w-8 rounded-[6px] text-[#0a0a0a]">›</button>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<pdm-calendar [month]="month" [year]="year" [selectedDay]="selectedDay" mode="single"></pdm-calendar>
|
|
32
|
+
|
|
33
|
+
<div *ngIf="variant === 'with-input' || variant === 'natural-language'" class="mt-3 flex gap-2">
|
|
34
|
+
<button type="button" class="h-8 rounded-[8px] border border-[#e5e5e5] px-3 text-[12px] text-[#0a0a0a]" (click)="selectPreset('Today')">Today</button>
|
|
35
|
+
<button type="button" class="h-8 rounded-[8px] border border-[#e5e5e5] px-3 text-[12px] text-[#0a0a0a]" (click)="selectPreset('Tomorrow')">Tomorrow</button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmDatePickerVariant = 'default' | 'with-input' | 'date-time' | 'natural-language';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-date-picker',
|
|
7
|
+
templateUrl: './date-picker.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmDatePickerComponent {
|
|
11
|
+
@Input() variant: PdmDatePickerVariant = 'default';
|
|
12
|
+
@Input() className = '';
|
|
13
|
+
@Input() open = false;
|
|
14
|
+
|
|
15
|
+
@Input() label = 'Date of Birth';
|
|
16
|
+
@Input() value = 'Select a date';
|
|
17
|
+
@Input() month = 'Jun';
|
|
18
|
+
@Input() year = 2025;
|
|
19
|
+
@Input() selectedDay = 25;
|
|
20
|
+
@Input() time = '10:30:00';
|
|
21
|
+
@Input() naturalLanguageValue = 'In 2 days';
|
|
22
|
+
@Input() naturalLanguageHint = 'Your post will be published on June 21, 2025.';
|
|
23
|
+
|
|
24
|
+
@Output() openChange = new EventEmitter<boolean>();
|
|
25
|
+
@Output() valueChange = new EventEmitter<string>();
|
|
26
|
+
|
|
27
|
+
toggle(): void {
|
|
28
|
+
this.openChange.emit(!this.open);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
selectPreset(value: string): void {
|
|
32
|
+
this.valueChange.emit(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<div *ngIf="open" class="fixed inset-0 z-50 flex items-center justify-center p-4">
|
|
2
|
+
<div class="absolute inset-0 bg-[rgba(0,0,0,0.3)]" (click)="onBackdropClick()"></div>
|
|
3
|
+
<section
|
|
4
|
+
role="dialog"
|
|
5
|
+
aria-modal="true"
|
|
6
|
+
[ngClass]="[
|
|
7
|
+
'relative z-10 w-full max-w-[423px] rounded-[10px] border border-[#e5e5e5] bg-white p-6 shadow-[0_10px_15px_rgba(0,0,0,0.1),0_4px_6px_rgba(0,0,0,0.1)]',
|
|
8
|
+
className
|
|
9
|
+
]"
|
|
10
|
+
>
|
|
11
|
+
<div class="flex items-start justify-between gap-3">
|
|
12
|
+
<div class="min-w-0">
|
|
13
|
+
<h2 class="m-0 text-[18px] font-semibold leading-7 text-[#0a0a0a]">{{ title }}</h2>
|
|
14
|
+
<p *ngIf="description" class="m-0 mt-2 text-[14px] leading-5 text-[#737373]">{{ description }}</p>
|
|
15
|
+
</div>
|
|
16
|
+
<button
|
|
17
|
+
*ngIf="showCloseButton"
|
|
18
|
+
type="button"
|
|
19
|
+
class="inline-flex h-6 w-6 items-center justify-center text-[#0a0a0a] opacity-70"
|
|
20
|
+
(click)="close()"
|
|
21
|
+
aria-label="Close dialog"
|
|
22
|
+
>
|
|
23
|
+
<svg viewBox="0 0 24 24" class="h-4 w-4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
24
|
+
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path>
|
|
25
|
+
</svg>
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<ng-container *ngIf="variant === 'default'; else customCloseDialog">
|
|
30
|
+
<div class="mt-4 flex flex-col gap-4">
|
|
31
|
+
<div class="flex flex-col gap-3">
|
|
32
|
+
<label class="text-[14px] font-medium leading-5 text-[#0a0a0a]">{{ nameLabel }}</label>
|
|
33
|
+
<div class="h-9 rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 text-[16px] leading-6 text-[#737373] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">{{ nameValue }}</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="flex flex-col gap-3">
|
|
36
|
+
<label class="text-[14px] font-medium leading-5 text-[#0a0a0a]">{{ usernameLabel }}</label>
|
|
37
|
+
<div class="h-9 rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 text-[16px] leading-6 text-[#737373] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">{{ usernameValue }}</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="mt-4 flex justify-end gap-2">
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
class="h-9 rounded-[10px] border border-[#e5e5e5] bg-white px-4 text-[14px] font-medium leading-5 text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]"
|
|
45
|
+
(click)="onSecondaryAction()"
|
|
46
|
+
>
|
|
47
|
+
{{ secondaryActionText }}
|
|
48
|
+
</button>
|
|
49
|
+
<button
|
|
50
|
+
type="button"
|
|
51
|
+
class="h-9 rounded-[10px] bg-[#171717] px-4 text-[14px] font-medium leading-5 text-[#fafafa] shadow-[0_1px_2px_rgba(0,0,0,0.1)]"
|
|
52
|
+
(click)="onPrimaryAction()"
|
|
53
|
+
>
|
|
54
|
+
{{ primaryActionText }}
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</ng-container>
|
|
58
|
+
|
|
59
|
+
<ng-template #customCloseDialog>
|
|
60
|
+
<div class="mt-4 h-9 rounded-[8px] border border-[#e5e5e5] bg-white px-3 py-1 text-[16px] leading-6 text-[#737373] shadow-[0_1px_2px_rgba(0,0,0,0.1)]">
|
|
61
|
+
{{ linkValue }}
|
|
62
|
+
</div>
|
|
63
|
+
<div class="mt-4 flex">
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
class="h-9 rounded-[10px] bg-[#f5f5f5] px-4 text-[14px] font-medium leading-5 text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]"
|
|
67
|
+
(click)="onSecondaryAction()"
|
|
68
|
+
>
|
|
69
|
+
Close
|
|
70
|
+
</button>
|
|
71
|
+
</div>
|
|
72
|
+
</ng-template>
|
|
73
|
+
|
|
74
|
+
<div class="mt-4">
|
|
75
|
+
<ng-content></ng-content>
|
|
76
|
+
</div>
|
|
77
|
+
</section>
|
|
78
|
+
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmDialogVariant = 'default' | 'custom-close';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-dialog',
|
|
7
|
+
templateUrl: './dialog.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmDialogComponent {
|
|
11
|
+
@Input() open = false;
|
|
12
|
+
@Input() variant: PdmDialogVariant = 'default';
|
|
13
|
+
@Input() title = 'Edit profile';
|
|
14
|
+
@Input() description = 'Make changes to your profile here. Click save when you\'re done.';
|
|
15
|
+
@Input() closeOnBackdrop = true;
|
|
16
|
+
@Input() closeOnEsc = true;
|
|
17
|
+
@Input() showCloseButton = true;
|
|
18
|
+
@Input() primaryActionText = 'Save changes';
|
|
19
|
+
@Input() secondaryActionText = 'Cancel';
|
|
20
|
+
@Input() nameLabel = 'Name';
|
|
21
|
+
@Input() nameValue = 'Pedro Duarte';
|
|
22
|
+
@Input() usernameLabel = 'Username';
|
|
23
|
+
@Input() usernameValue = '@peduarte';
|
|
24
|
+
@Input() linkValue = 'https://ui.shadcn.com/docs/installation';
|
|
25
|
+
@Input() className = '';
|
|
26
|
+
|
|
27
|
+
@Output() openChange = new EventEmitter<boolean>();
|
|
28
|
+
@Output() primaryAction = new EventEmitter<void>();
|
|
29
|
+
@Output() secondaryAction = new EventEmitter<void>();
|
|
30
|
+
|
|
31
|
+
@HostListener('document:keydown.escape')
|
|
32
|
+
onEsc(): void {
|
|
33
|
+
if (this.open && this.closeOnEsc) {
|
|
34
|
+
this.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
close(): void {
|
|
39
|
+
this.openChange.emit(false);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onPrimaryAction(): void {
|
|
43
|
+
this.primaryAction.emit();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onSecondaryAction(): void {
|
|
47
|
+
this.secondaryAction.emit();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onBackdropClick(): void {
|
|
51
|
+
if (this.closeOnBackdrop) {
|
|
52
|
+
this.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<div *ngIf="open" class="fixed inset-0 z-50" [ngClass]="className">
|
|
2
|
+
<div class="absolute inset-0 bg-[rgba(0,0,0,0.3)]" (click)="close()"></div>
|
|
3
|
+
|
|
4
|
+
<section
|
|
5
|
+
*ngIf="variant === 'drawer'; else responsiveDialog"
|
|
6
|
+
class="absolute inset-x-0 bottom-0 mx-auto w-full max-w-[1229px] rounded-t-[10px] border border-[#e5e5e5] bg-white p-6 shadow-[0_10px_15px_rgba(0,0,0,0.1),0_4px_6px_rgba(0,0,0,0.1)]"
|
|
7
|
+
>
|
|
8
|
+
<div class="mx-auto mb-4 h-1 w-10 rounded-full bg-[#e5e5e5]"></div>
|
|
9
|
+
|
|
10
|
+
<div class="mx-auto flex max-w-[320px] flex-col items-center">
|
|
11
|
+
<h3 class="m-0 text-[14px] font-semibold leading-5 text-[#0a0a0a]">{{ title }}</h3>
|
|
12
|
+
<p class="m-0 mt-1 text-[12px] leading-4 text-[#737373]">{{ description }}</p>
|
|
13
|
+
|
|
14
|
+
<div class="mt-3 flex w-full items-center justify-center gap-4">
|
|
15
|
+
<button type="button" class="inline-flex h-6 w-6 items-center justify-center rounded-full border border-[#e5e5e5] text-[#737373]">-</button>
|
|
16
|
+
<div class="text-center">
|
|
17
|
+
<div class="text-[48px] font-semibold leading-none text-[#0a0a0a]">{{ value }}</div>
|
|
18
|
+
<div class="mt-1 text-[10px] tracking-wide text-[#737373]">{{ unit }}</div>
|
|
19
|
+
</div>
|
|
20
|
+
<button type="button" class="inline-flex h-6 w-6 items-center justify-center rounded-full border border-[#e5e5e5] text-[#737373]">+</button>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="mt-3 flex h-[58px] w-full items-end gap-[3px]">
|
|
24
|
+
<div *ngFor="let bar of bars" class="flex-1 bg-[#171717]" [style.height.px]="bar"></div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<button type="button" class="mt-3 h-9 w-full rounded-[10px] bg-[#171717] text-[14px] font-medium text-[#fafafa]" (click)="onPrimaryAction()">Submit</button>
|
|
28
|
+
<button type="button" class="mt-2 h-9 w-full rounded-[10px] border border-[#e5e5e5] bg-white text-[14px] font-medium text-[#0a0a0a]" (click)="onSecondaryAction()">Cancel</button>
|
|
29
|
+
</div>
|
|
30
|
+
</section>
|
|
31
|
+
|
|
32
|
+
<ng-template #responsiveDialog>
|
|
33
|
+
<section class="absolute left-1/2 top-1/2 w-full max-w-[423px] -translate-x-1/2 -translate-y-1/2 rounded-[10px] border border-[#e5e5e5] bg-white p-4 shadow-[0_10px_15px_rgba(0,0,0,0.1),0_4px_6px_rgba(0,0,0,0.1)]">
|
|
34
|
+
<div class="flex items-start justify-between">
|
|
35
|
+
<div>
|
|
36
|
+
<h3 class="m-0 text-[18px] font-semibold leading-7 text-[#0a0a0a]">{{ profileTitle }}</h3>
|
|
37
|
+
<p class="m-0 mt-1 text-[12px] leading-4 text-[#737373]">{{ profileDescription }}</p>
|
|
38
|
+
</div>
|
|
39
|
+
<button type="button" class="h-5 w-5 text-[#737373]" (click)="close()">×</button>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="mt-3 flex flex-col gap-3">
|
|
43
|
+
<div>
|
|
44
|
+
<label class="mb-1 block text-[12px] font-medium leading-4 text-[#0a0a0a]">{{ nameLabel }}</label>
|
|
45
|
+
<div class="h-8 rounded-[6px] border border-[#e5e5e5] bg-white px-2 py-1 text-[12px] leading-4 text-[#0a0a0a]">{{ nameValue }}</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div>
|
|
48
|
+
<label class="mb-1 block text-[12px] font-medium leading-4 text-[#0a0a0a]">{{ usernameLabel }}</label>
|
|
49
|
+
<div class="h-8 rounded-[6px] border border-[#e5e5e5] bg-white px-2 py-1 text-[12px] leading-4 text-[#0a0a0a]">{{ usernameValue }}</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<button type="button" class="mt-3 h-8 w-full rounded-[8px] bg-[#171717] text-[12px] font-medium text-[#fafafa]" (click)="onPrimaryAction()">Save changes</button>
|
|
54
|
+
</section>
|
|
55
|
+
</ng-template>
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmDrawerVariant = 'drawer' | 'responsive-dialog';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-drawer',
|
|
7
|
+
templateUrl: './drawer.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmDrawerComponent {
|
|
11
|
+
@Input() open = false;
|
|
12
|
+
@Input() variant: PdmDrawerVariant = 'drawer';
|
|
13
|
+
@Input() className = '';
|
|
14
|
+
@Input() title = 'Move Goal';
|
|
15
|
+
@Input() description = 'Set your daily activity goal.';
|
|
16
|
+
@Input() value = 350;
|
|
17
|
+
@Input() unit = 'CALORIES/DAY';
|
|
18
|
+
|
|
19
|
+
@Input() profileTitle = 'Edit profile';
|
|
20
|
+
@Input() profileDescription = 'Make changes to your profile here. Click save when you\'re done.';
|
|
21
|
+
@Input() nameLabel = 'Name';
|
|
22
|
+
@Input() nameValue = 'Pedro Duarte';
|
|
23
|
+
@Input() usernameLabel = 'Username';
|
|
24
|
+
@Input() usernameValue = '@peduarte';
|
|
25
|
+
|
|
26
|
+
@Output() openChange = new EventEmitter<boolean>();
|
|
27
|
+
@Output() primaryAction = new EventEmitter<void>();
|
|
28
|
+
@Output() secondaryAction = new EventEmitter<void>();
|
|
29
|
+
|
|
30
|
+
readonly bars = [72, 54, 58, 49, 60, 65, 44, 53, 61, 52, 63, 48, 66];
|
|
31
|
+
|
|
32
|
+
close(): void {
|
|
33
|
+
this.openChange.emit(false);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
onPrimaryAction(): void {
|
|
37
|
+
this.primaryAction.emit();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onSecondaryAction(): void {
|
|
41
|
+
this.secondaryAction.emit();
|
|
42
|
+
}
|
|
43
|
+
}
|