@ojiepermana/angular-theme 22.0.33 → 22.0.34
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.
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, booleanAttribute, Component, computed } from '@angular/core';
|
|
3
|
+
import { NavigationHeaderInitialComponent, NavigationHeaderTitleComponent, NavigationFooterActionComponent, NavigationFooterInitialComponent, NavigationFooterTitleComponent, NavigationSidebarComponent, NavigationHeaderComponent, NavigationFooterComponent, NavigationDockbarComponent, NavigationNavbarComponent, NavigationFlyoutComponent, NavigationContainerComponent } from '@ojiepermana/angular-navigation';
|
|
4
|
+
import { IconComponent } from '@ojiepermana/angular-component/icon';
|
|
5
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
6
|
+
import { LayoutComponent, LayoutVerticalComponent, LayoutHorizontalComponent, LayoutEmptyComponent, LayoutFluidComponent, LayoutNavigationComponent, LayoutContentComponent } from '@ojiepermana/angular-theme/layout';
|
|
7
|
+
import { LAYOUT_DEFAULT_SURFACE, LAYOUT_DEFAULT_APPEARANCE, LAYOUT_DEFAULT_WIDTH, LAYOUT_DEFAULT_TYPE } from '@ojiepermana/angular-theme/layout/types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Bentuk identitas yang dikonsumsi wrapper layout. Library hanya mendefinisikan
|
|
11
|
+
* strukturnya; nilai konkret (brand/user) disediakan consumer sebagai input.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Slot brand untuk `<NavigationHeader>`: inisial/logo + judul. Murni input-driven.
|
|
16
|
+
*
|
|
17
|
+
* `compact` (dockbar / rail ikon-only) menyembunyikan judul. `host.class = 'contents'`
|
|
18
|
+
* membuat `NavigationHeaderInitial` + `NavigationHeaderTitle` tetap menjadi flex-child
|
|
19
|
+
* langsung baris header; auto-hide judul saat sidebar collapsed (via `NAVIGATION_SHELL`)
|
|
20
|
+
* tetap berlaku karena DI mengalir lewat live tree ke `<Navigation>`.
|
|
21
|
+
*/
|
|
22
|
+
class LayoutBrand {
|
|
23
|
+
/** Identitas brand (nama, ikon, judul, subjudul). */
|
|
24
|
+
brand = input.required(/* @ts-ignore */
|
|
25
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
26
|
+
/** Sembunyikan judul, sisakan inisial saja (dockbar / rail ikon-only). */
|
|
27
|
+
compact = input(false, { ...(ngDevMode ? { debugName: "compact" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
28
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutBrand, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
29
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: LayoutBrand, isStandalone: true, selector: "LayoutBrand", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
30
|
+
<NavigationHeaderInitial [name]="brand().name" [icon]="brand().icon" />
|
|
31
|
+
@if (!compact()) {
|
|
32
|
+
<NavigationHeaderTitle [title]="brand().title" [subtitle]="brand().subtitle" />
|
|
33
|
+
}
|
|
34
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationHeaderInitialComponent, selector: "NavigationHeaderInitial", inputs: ["name", "src", "initials", "icon", "class"] }, { kind: "component", type: NavigationHeaderTitleComponent, selector: "NavigationHeaderTitle", inputs: ["title", "subtitle", "class"] }] });
|
|
35
|
+
}
|
|
36
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutBrand, decorators: [{
|
|
37
|
+
type: Component,
|
|
38
|
+
args: [{
|
|
39
|
+
selector: 'LayoutBrand',
|
|
40
|
+
imports: [NavigationHeaderInitialComponent, NavigationHeaderTitleComponent],
|
|
41
|
+
host: { class: 'contents' },
|
|
42
|
+
template: `
|
|
43
|
+
<NavigationHeaderInitial [name]="brand().name" [icon]="brand().icon" />
|
|
44
|
+
@if (!compact()) {
|
|
45
|
+
<NavigationHeaderTitle [title]="brand().title" [subtitle]="brand().subtitle" />
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
}]
|
|
49
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }] } });
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Slot user untuk `<NavigationFooter>`: identitas (opsional) + aksi logout. Murni input-driven.
|
|
53
|
+
*
|
|
54
|
+
* `detailed` menampilkan inisial + nama (sidebar penuh); tanpanya hanya tombol logout.
|
|
55
|
+
* `host.class = 'contents'` membuat anak menjadi flex-child langsung footer — `ml-auto` &
|
|
56
|
+
* auto-hide saat collapsed (via `NAVIGATION_SHELL`) tetap berlaku.
|
|
57
|
+
*/
|
|
58
|
+
class LayoutUser {
|
|
59
|
+
/** Identitas user (nama + email). */
|
|
60
|
+
user = input.required(/* @ts-ignore */
|
|
61
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
62
|
+
/** Tampilkan identitas user (inisial + nama), bukan hanya tombol logout. */
|
|
63
|
+
detailed = input(false, { ...(ngDevMode ? { debugName: "detailed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
64
|
+
/** Label aksesibilitas tombol logout. */
|
|
65
|
+
logoutLabel = input('Logout', /* @ts-ignore */
|
|
66
|
+
...(ngDevMode ? [{ debugName: "logoutLabel" }] : /* istanbul ignore next */ []));
|
|
67
|
+
/** Material symbol untuk tombol logout. */
|
|
68
|
+
logoutIcon = input('logout', /* @ts-ignore */
|
|
69
|
+
...(ngDevMode ? [{ debugName: "logoutIcon" }] : /* istanbul ignore next */ []));
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutUser, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: LayoutUser, isStandalone: true, selector: "LayoutUser", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null }, detailed: { classPropertyName: "detailed", publicName: "detailed", isSignal: true, isRequired: false, transformFunction: null }, logoutLabel: { classPropertyName: "logoutLabel", publicName: "logoutLabel", isSignal: true, isRequired: false, transformFunction: null }, logoutIcon: { classPropertyName: "logoutIcon", publicName: "logoutIcon", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
72
|
+
@if (detailed()) {
|
|
73
|
+
<NavigationFooterInitial [name]="user().name" />
|
|
74
|
+
<NavigationFooterTitle [title]="user().name" [subtitle]="user().email" />
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
<NavigationFooterAction>
|
|
78
|
+
<button
|
|
79
|
+
type="button"
|
|
80
|
+
[attr.aria-label]="logoutLabel()"
|
|
81
|
+
[attr.title]="logoutLabel()"
|
|
82
|
+
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
83
|
+
>
|
|
84
|
+
<Icon [name]="logoutIcon()" [size]="18" />
|
|
85
|
+
</button>
|
|
86
|
+
</NavigationFooterAction>
|
|
87
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationFooterActionComponent, selector: "NavigationFooterAction", inputs: ["class"] }, { kind: "component", type: NavigationFooterInitialComponent, selector: "NavigationFooterInitial", inputs: ["name", "src", "initials", "icon", "class"] }, { kind: "component", type: NavigationFooterTitleComponent, selector: "NavigationFooterTitle", inputs: ["title", "subtitle", "class"] }] });
|
|
88
|
+
}
|
|
89
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutUser, decorators: [{
|
|
90
|
+
type: Component,
|
|
91
|
+
args: [{
|
|
92
|
+
selector: 'LayoutUser',
|
|
93
|
+
imports: [
|
|
94
|
+
IconComponent,
|
|
95
|
+
NavigationFooterActionComponent,
|
|
96
|
+
NavigationFooterInitialComponent,
|
|
97
|
+
NavigationFooterTitleComponent,
|
|
98
|
+
],
|
|
99
|
+
host: { class: 'contents' },
|
|
100
|
+
template: `
|
|
101
|
+
@if (detailed()) {
|
|
102
|
+
<NavigationFooterInitial [name]="user().name" />
|
|
103
|
+
<NavigationFooterTitle [title]="user().name" [subtitle]="user().email" />
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
<NavigationFooterAction>
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
[attr.aria-label]="logoutLabel()"
|
|
110
|
+
[attr.title]="logoutLabel()"
|
|
111
|
+
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
112
|
+
>
|
|
113
|
+
<Icon [name]="logoutIcon()" [size]="18" />
|
|
114
|
+
</button>
|
|
115
|
+
</NavigationFooterAction>
|
|
116
|
+
`,
|
|
117
|
+
}]
|
|
118
|
+
}], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }], detailed: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailed", required: false }] }], logoutLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoutLabel", required: false }] }], logoutIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoutIcon", required: false }] }] } });
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Tipe nav: sidebar vertikal collapsible (default). Brand header + identitas user di footer.
|
|
122
|
+
*
|
|
123
|
+
* `host.class = 'contents'` membuat `<NavigationSidebar>` menjadi anak efektif `<Navigation>`
|
|
124
|
+
* (h-full, shell-classes), sementara DI `NAVIGATION_SHELL` tetap mengalir lewat live tree dan
|
|
125
|
+
* `<NavigationHeader>` tetap direct child untuk content-projection library.
|
|
126
|
+
*/
|
|
127
|
+
class LayoutNavSidebar {
|
|
128
|
+
brand = input.required(/* @ts-ignore */
|
|
129
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
130
|
+
user = input.required(/* @ts-ignore */
|
|
131
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
132
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
133
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: LayoutNavSidebar, isStandalone: true, selector: "LayoutNavSidebar", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
134
|
+
<NavigationSidebar nav-sidebar-collapse>
|
|
135
|
+
<NavigationHeader>
|
|
136
|
+
<LayoutBrand [brand]="brand()" />
|
|
137
|
+
</NavigationHeader>
|
|
138
|
+
<NavigationFooter class="px-3">
|
|
139
|
+
<LayoutUser [user]="user()" detailed />
|
|
140
|
+
</NavigationFooter>
|
|
141
|
+
</NavigationSidebar>
|
|
142
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationSidebarComponent, selector: "NavigationSidebar", inputs: ["position", "collapsed", "nav-sidebar-collapse", "previewExpanded", "class"] }, { kind: "component", type: NavigationHeaderComponent, selector: "NavigationHeader", inputs: ["toggle", "class"] }, { kind: "component", type: NavigationFooterComponent, selector: "NavigationFooter", inputs: ["class"] }, { kind: "component", type: LayoutBrand, selector: "LayoutBrand", inputs: ["brand", "compact"] }, { kind: "component", type: LayoutUser, selector: "LayoutUser", inputs: ["user", "detailed", "logoutLabel", "logoutIcon"] }] });
|
|
143
|
+
}
|
|
144
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavSidebar, decorators: [{
|
|
145
|
+
type: Component,
|
|
146
|
+
args: [{
|
|
147
|
+
selector: 'LayoutNavSidebar',
|
|
148
|
+
imports: [
|
|
149
|
+
NavigationSidebarComponent,
|
|
150
|
+
NavigationHeaderComponent,
|
|
151
|
+
NavigationFooterComponent,
|
|
152
|
+
LayoutBrand,
|
|
153
|
+
LayoutUser,
|
|
154
|
+
],
|
|
155
|
+
host: { class: 'contents' },
|
|
156
|
+
template: `
|
|
157
|
+
<NavigationSidebar nav-sidebar-collapse>
|
|
158
|
+
<NavigationHeader>
|
|
159
|
+
<LayoutBrand [brand]="brand()" />
|
|
160
|
+
</NavigationHeader>
|
|
161
|
+
<NavigationFooter class="px-3">
|
|
162
|
+
<LayoutUser [user]="user()" detailed />
|
|
163
|
+
</NavigationFooter>
|
|
164
|
+
</NavigationSidebar>
|
|
165
|
+
`,
|
|
166
|
+
}]
|
|
167
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }] } });
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Tipe nav: rail ikon vertikal (dockbar). Brand compact (inisial saja) + aksi logout.
|
|
171
|
+
* Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
172
|
+
*/
|
|
173
|
+
class LayoutNavDockbar {
|
|
174
|
+
brand = input.required(/* @ts-ignore */
|
|
175
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
176
|
+
user = input.required(/* @ts-ignore */
|
|
177
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
178
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavDockbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
179
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: LayoutNavDockbar, isStandalone: true, selector: "LayoutNavDockbar", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
180
|
+
<NavigationDockbar>
|
|
181
|
+
<NavigationHeader>
|
|
182
|
+
<LayoutBrand [brand]="brand()" compact />
|
|
183
|
+
</NavigationHeader>
|
|
184
|
+
<NavigationFooter class="px-3">
|
|
185
|
+
<LayoutUser [user]="user()" />
|
|
186
|
+
</NavigationFooter>
|
|
187
|
+
</NavigationDockbar>
|
|
188
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationDockbarComponent, selector: "NavigationDockbar", inputs: ["mode", "position", "class"] }, { kind: "component", type: NavigationHeaderComponent, selector: "NavigationHeader", inputs: ["toggle", "class"] }, { kind: "component", type: NavigationFooterComponent, selector: "NavigationFooter", inputs: ["class"] }, { kind: "component", type: LayoutBrand, selector: "LayoutBrand", inputs: ["brand", "compact"] }, { kind: "component", type: LayoutUser, selector: "LayoutUser", inputs: ["user", "detailed", "logoutLabel", "logoutIcon"] }] });
|
|
189
|
+
}
|
|
190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavDockbar, decorators: [{
|
|
191
|
+
type: Component,
|
|
192
|
+
args: [{
|
|
193
|
+
selector: 'LayoutNavDockbar',
|
|
194
|
+
imports: [
|
|
195
|
+
NavigationDockbarComponent,
|
|
196
|
+
NavigationHeaderComponent,
|
|
197
|
+
NavigationFooterComponent,
|
|
198
|
+
LayoutBrand,
|
|
199
|
+
LayoutUser,
|
|
200
|
+
],
|
|
201
|
+
host: { class: 'contents' },
|
|
202
|
+
template: `
|
|
203
|
+
<NavigationDockbar>
|
|
204
|
+
<NavigationHeader>
|
|
205
|
+
<LayoutBrand [brand]="brand()" compact />
|
|
206
|
+
</NavigationHeader>
|
|
207
|
+
<NavigationFooter class="px-3">
|
|
208
|
+
<LayoutUser [user]="user()" />
|
|
209
|
+
</NavigationFooter>
|
|
210
|
+
</NavigationDockbar>
|
|
211
|
+
`,
|
|
212
|
+
}]
|
|
213
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }] } });
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Tipe nav: top bar item inline (navbar, horizontal). `appearance` selaras shell
|
|
217
|
+
* (`flat | border-rail`). Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
218
|
+
*/
|
|
219
|
+
class LayoutNavNavbar {
|
|
220
|
+
brand = input.required(/* @ts-ignore */
|
|
221
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
222
|
+
user = input.required(/* @ts-ignore */
|
|
223
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
224
|
+
/** Appearance dari shell (`[nav-appearance]`). */
|
|
225
|
+
appearance = input('flat', /* @ts-ignore */
|
|
226
|
+
...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
227
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavNavbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
228
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: LayoutNavNavbar, isStandalone: true, selector: "LayoutNavNavbar", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
229
|
+
<NavigationNavbar [nav-appearance]="appearance()" class="border-b-[1.5px] border-border">
|
|
230
|
+
<NavigationHeader>
|
|
231
|
+
<LayoutBrand [brand]="brand()" />
|
|
232
|
+
</NavigationHeader>
|
|
233
|
+
<NavigationFooter class="px-3">
|
|
234
|
+
<LayoutUser [user]="user()" />
|
|
235
|
+
</NavigationFooter>
|
|
236
|
+
</NavigationNavbar>
|
|
237
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationNavbarComponent, selector: "NavigationNavbar", inputs: ["nav-position", "nav-appearance", "class"] }, { kind: "component", type: NavigationHeaderComponent, selector: "NavigationHeader", inputs: ["toggle", "class"] }, { kind: "component", type: NavigationFooterComponent, selector: "NavigationFooter", inputs: ["class"] }, { kind: "component", type: LayoutBrand, selector: "LayoutBrand", inputs: ["brand", "compact"] }, { kind: "component", type: LayoutUser, selector: "LayoutUser", inputs: ["user", "detailed", "logoutLabel", "logoutIcon"] }] });
|
|
238
|
+
}
|
|
239
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavNavbar, decorators: [{
|
|
240
|
+
type: Component,
|
|
241
|
+
args: [{
|
|
242
|
+
selector: 'LayoutNavNavbar',
|
|
243
|
+
imports: [
|
|
244
|
+
NavigationNavbarComponent,
|
|
245
|
+
NavigationHeaderComponent,
|
|
246
|
+
NavigationFooterComponent,
|
|
247
|
+
LayoutBrand,
|
|
248
|
+
LayoutUser,
|
|
249
|
+
],
|
|
250
|
+
host: { class: 'contents' },
|
|
251
|
+
template: `
|
|
252
|
+
<NavigationNavbar [nav-appearance]="appearance()" class="border-b-[1.5px] border-border">
|
|
253
|
+
<NavigationHeader>
|
|
254
|
+
<LayoutBrand [brand]="brand()" />
|
|
255
|
+
</NavigationHeader>
|
|
256
|
+
<NavigationFooter class="px-3">
|
|
257
|
+
<LayoutUser [user]="user()" />
|
|
258
|
+
</NavigationFooter>
|
|
259
|
+
</NavigationNavbar>
|
|
260
|
+
`,
|
|
261
|
+
}]
|
|
262
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }] } });
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Tipe nav: top bar dengan tombol trigger flyout (horizontal). `appearance` selaras shell.
|
|
266
|
+
* Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
267
|
+
*/
|
|
268
|
+
class LayoutNavFlyout {
|
|
269
|
+
brand = input.required(/* @ts-ignore */
|
|
270
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
271
|
+
user = input.required(/* @ts-ignore */
|
|
272
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
273
|
+
/** Appearance dari shell (`[nav-appearance]`). */
|
|
274
|
+
appearance = input('flat', /* @ts-ignore */
|
|
275
|
+
...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
276
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavFlyout, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
277
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: LayoutNavFlyout, isStandalone: true, selector: "LayoutNavFlyout", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
278
|
+
<NavigationFlyout
|
|
279
|
+
[nav-appearance]="appearance()"
|
|
280
|
+
label="Menu"
|
|
281
|
+
icon="apps"
|
|
282
|
+
class="border-b-[1.5px] border-border"
|
|
283
|
+
>
|
|
284
|
+
<NavigationHeader>
|
|
285
|
+
<LayoutBrand [brand]="brand()" />
|
|
286
|
+
</NavigationHeader>
|
|
287
|
+
<NavigationFooter class="px-3">
|
|
288
|
+
<LayoutUser [user]="user()" />
|
|
289
|
+
</NavigationFooter>
|
|
290
|
+
</NavigationFlyout>
|
|
291
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationFlyoutComponent, selector: "NavigationFlyout", inputs: ["label", "icon", "icon-only", "icon-position", "trigger-variant", "trigger-floating", "trigger-class", "nav-position", "nav-appearance", "class"] }, { kind: "component", type: NavigationHeaderComponent, selector: "NavigationHeader", inputs: ["toggle", "class"] }, { kind: "component", type: NavigationFooterComponent, selector: "NavigationFooter", inputs: ["class"] }, { kind: "component", type: LayoutBrand, selector: "LayoutBrand", inputs: ["brand", "compact"] }, { kind: "component", type: LayoutUser, selector: "LayoutUser", inputs: ["user", "detailed", "logoutLabel", "logoutIcon"] }] });
|
|
292
|
+
}
|
|
293
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavFlyout, decorators: [{
|
|
294
|
+
type: Component,
|
|
295
|
+
args: [{
|
|
296
|
+
selector: 'LayoutNavFlyout',
|
|
297
|
+
imports: [
|
|
298
|
+
NavigationFlyoutComponent,
|
|
299
|
+
NavigationHeaderComponent,
|
|
300
|
+
NavigationFooterComponent,
|
|
301
|
+
LayoutBrand,
|
|
302
|
+
LayoutUser,
|
|
303
|
+
],
|
|
304
|
+
host: { class: 'contents' },
|
|
305
|
+
template: `
|
|
306
|
+
<NavigationFlyout
|
|
307
|
+
[nav-appearance]="appearance()"
|
|
308
|
+
label="Menu"
|
|
309
|
+
icon="apps"
|
|
310
|
+
class="border-b-[1.5px] border-border"
|
|
311
|
+
>
|
|
312
|
+
<NavigationHeader>
|
|
313
|
+
<LayoutBrand [brand]="brand()" />
|
|
314
|
+
</NavigationHeader>
|
|
315
|
+
<NavigationFooter class="px-3">
|
|
316
|
+
<LayoutUser [user]="user()" />
|
|
317
|
+
</NavigationFooter>
|
|
318
|
+
</NavigationFlyout>
|
|
319
|
+
`,
|
|
320
|
+
}]
|
|
321
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }] } });
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Tipe nav: sidebar brand-only untuk varian `empty` / `fluid` (nav disembunyikan oleh
|
|
325
|
+
* `LayoutNavigation`, jadi tanpa collapse & footer). Lihat {@link LayoutNavSidebar} untuk
|
|
326
|
+
* alasan `host.class = 'contents'`.
|
|
327
|
+
*/
|
|
328
|
+
class LayoutNavMinimal {
|
|
329
|
+
brand = input.required(/* @ts-ignore */
|
|
330
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
331
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavMinimal, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
332
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: LayoutNavMinimal, isStandalone: true, selector: "LayoutNavMinimal", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
333
|
+
<NavigationSidebar>
|
|
334
|
+
<NavigationHeader>
|
|
335
|
+
<LayoutBrand [brand]="brand()" />
|
|
336
|
+
</NavigationHeader>
|
|
337
|
+
</NavigationSidebar>
|
|
338
|
+
`, isInline: true, dependencies: [{ kind: "component", type: NavigationSidebarComponent, selector: "NavigationSidebar", inputs: ["position", "collapsed", "nav-sidebar-collapse", "previewExpanded", "class"] }, { kind: "component", type: NavigationHeaderComponent, selector: "NavigationHeader", inputs: ["toggle", "class"] }, { kind: "component", type: LayoutBrand, selector: "LayoutBrand", inputs: ["brand", "compact"] }] });
|
|
339
|
+
}
|
|
340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutNavMinimal, decorators: [{
|
|
341
|
+
type: Component,
|
|
342
|
+
args: [{
|
|
343
|
+
selector: 'LayoutNavMinimal',
|
|
344
|
+
imports: [NavigationSidebarComponent, NavigationHeaderComponent, LayoutBrand],
|
|
345
|
+
host: { class: 'contents' },
|
|
346
|
+
template: `
|
|
347
|
+
<NavigationSidebar>
|
|
348
|
+
<NavigationHeader>
|
|
349
|
+
<LayoutBrand [brand]="brand()" />
|
|
350
|
+
</NavigationHeader>
|
|
351
|
+
</NavigationSidebar>
|
|
352
|
+
`,
|
|
353
|
+
}]
|
|
354
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }] } });
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Wrapper layout shell siap pakai — consumer cukup memberi data input, tidak perlu merakit
|
|
358
|
+
* `Layout > LayoutVertical/Horizontal/Empty/Fluid > LayoutNavigation > Navigation > tipe-nav`.
|
|
359
|
+
*
|
|
360
|
+
* ```html
|
|
361
|
+
* <LayoutWrapperDefault
|
|
362
|
+
* [surface]="surface" [layout-appearance]="appearance" [width]="width"
|
|
363
|
+
* [layout-type]="layoutType" [nav-type]="navType"
|
|
364
|
+
* [data]="navItems" [brand]="brand" [user]="user"
|
|
365
|
+
* >
|
|
366
|
+
* <router-outlet /> <!-- konten halaman diproyeksikan ke LayoutContent -->
|
|
367
|
+
* </LayoutWrapperDefault>
|
|
368
|
+
* ```
|
|
369
|
+
*
|
|
370
|
+
* `register*` default (LayoutService) tetap tanggung jawab consumer; wrapper ini murni
|
|
371
|
+
* presentational — dua sumbu (`effectiveLayoutType` → wrapper, `navKind` → tipe nav) di atas
|
|
372
|
+
* satu skeleton bersama. DI aman: `<Navigation>` mem-*provide* `NAVIGATION_SHELL` di dalam
|
|
373
|
+
* `#body`; tipe nav `display:contents` sehingga `<NavigationXxx>` jadi anak efektif `<Navigation>`.
|
|
374
|
+
*/
|
|
375
|
+
class LayoutWrapperDefault {
|
|
376
|
+
/** Surface latar shell (mis. `grid`, `flat`). */
|
|
377
|
+
surface = input(LAYOUT_DEFAULT_SURFACE, /* @ts-ignore */
|
|
378
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
379
|
+
/** Appearance shell & nav (`flat | border-rail`). */
|
|
380
|
+
appearance = input(LAYOUT_DEFAULT_APPEARANCE, { ...(ngDevMode ? { debugName: "appearance" } : /* istanbul ignore next */ {}), alias: 'layout-appearance' });
|
|
381
|
+
/** Lebar frame (`full`, `container`, dst.). */
|
|
382
|
+
width = input(LAYOUT_DEFAULT_WIDTH, /* @ts-ignore */
|
|
383
|
+
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
384
|
+
/** Tipe layout dasar (`vertical | horizontal | empty | fluid`); `empty`/`fluid` override nav. */
|
|
385
|
+
layoutType = input(LAYOUT_DEFAULT_TYPE, { ...(ngDevMode ? { debugName: "layoutType" } : /* istanbul ignore next */ {}), alias: 'layout-type' });
|
|
386
|
+
/** Tipe navigasi (`sidebar | dockbar | navbar | flyout`); diabaikan saat `empty`/`fluid`. */
|
|
387
|
+
navType = input('sidebar', { ...(ngDevMode ? { debugName: "navType" } : /* istanbul ignore next */ {}), alias: 'nav-type' });
|
|
388
|
+
/** Item navigasi. */
|
|
389
|
+
data = input.required(/* @ts-ignore */
|
|
390
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
391
|
+
/** Identitas brand. */
|
|
392
|
+
brand = input.required(/* @ts-ignore */
|
|
393
|
+
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
394
|
+
/** Identitas user. */
|
|
395
|
+
user = input.required(/* @ts-ignore */
|
|
396
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
397
|
+
/** Wrapper layout & nilai `<Layout [layout-type]>`: navbar/flyout = horizontal, sisanya vertical. */
|
|
398
|
+
effectiveLayoutType = computed(() => {
|
|
399
|
+
const layoutType = this.layoutType();
|
|
400
|
+
if (layoutType === 'empty' || layoutType === 'fluid') {
|
|
401
|
+
return layoutType;
|
|
402
|
+
}
|
|
403
|
+
return this.navType() === 'navbar' || this.navType() === 'flyout' ? 'horizontal' : 'vertical';
|
|
404
|
+
}, /* @ts-ignore */
|
|
405
|
+
...(ngDevMode ? [{ debugName: "effectiveLayoutType" }] : /* istanbul ignore next */ []));
|
|
406
|
+
/** Tipe nav di dalam `#body`: `empty`/`fluid` → `brand` (header-only); selain itu `nav-type`. */
|
|
407
|
+
navKind = computed(() => {
|
|
408
|
+
const layoutType = this.layoutType();
|
|
409
|
+
return layoutType === 'empty' || layoutType === 'fluid' ? 'brand' : this.navType();
|
|
410
|
+
}, /* @ts-ignore */
|
|
411
|
+
...(ngDevMode ? [{ debugName: "navKind" }] : /* istanbul ignore next */ []));
|
|
412
|
+
/** Lebar host `<Navigation>`: penuh-tinggi (vertical) atau penuh-lebar (horizontal). */
|
|
413
|
+
navClass = computed(() => this.effectiveLayoutType() === 'horizontal' ? 'w-full' : 'h-full', /* @ts-ignore */
|
|
414
|
+
...(ngDevMode ? [{ debugName: "navClass" }] : /* istanbul ignore next */ []));
|
|
415
|
+
/** Kelas `<LayoutContent>`: `fluid` membatasi lebar & memusatkan; selain itu padding biasa. */
|
|
416
|
+
contentClass = computed(() => this.effectiveLayoutType() === 'fluid' ? 'w-full max-w-3xl p-6' : 'p-6', /* @ts-ignore */
|
|
417
|
+
...(ngDevMode ? [{ debugName: "contentClass" }] : /* istanbul ignore next */ []));
|
|
418
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutWrapperDefault, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
419
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: LayoutWrapperDefault, isStandalone: true, selector: "LayoutWrapperDefault", inputs: { surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "layout-appearance", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, layoutType: { classPropertyName: "layoutType", publicName: "layout-type", isSignal: true, isRequired: false, transformFunction: null }, navType: { classPropertyName: "navType", publicName: "nav-type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
420
|
+
<Layout
|
|
421
|
+
[surface]="surface()"
|
|
422
|
+
[layout-appearance]="appearance()"
|
|
423
|
+
[width]="width()"
|
|
424
|
+
[layout-type]="effectiveLayoutType()"
|
|
425
|
+
>
|
|
426
|
+
<!-- Skeleton bersama: dipakai ulang oleh setiap wrapper di @switch bawah. -->
|
|
427
|
+
<ng-template #body>
|
|
428
|
+
<LayoutNavigation ariaLabel="Primary navigation">
|
|
429
|
+
<Navigation id="main" [data]="data()" [class]="navClass()">
|
|
430
|
+
@switch (navKind()) {
|
|
431
|
+
@case ('navbar') {
|
|
432
|
+
<LayoutNavNavbar [brand]="brand()" [user]="user()" [appearance]="appearance()" />
|
|
433
|
+
}
|
|
434
|
+
@case ('flyout') {
|
|
435
|
+
<LayoutNavFlyout [brand]="brand()" [user]="user()" [appearance]="appearance()" />
|
|
436
|
+
}
|
|
437
|
+
@case ('dockbar') {
|
|
438
|
+
<LayoutNavDockbar [brand]="brand()" [user]="user()" />
|
|
439
|
+
}
|
|
440
|
+
@case ('brand') {
|
|
441
|
+
<LayoutNavMinimal [brand]="brand()" />
|
|
442
|
+
}
|
|
443
|
+
@default {
|
|
444
|
+
<LayoutNavSidebar [brand]="brand()" [user]="user()" />
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
</Navigation>
|
|
448
|
+
</LayoutNavigation>
|
|
449
|
+
|
|
450
|
+
<LayoutContent [class]="contentClass()">
|
|
451
|
+
<ng-content />
|
|
452
|
+
</LayoutContent>
|
|
453
|
+
</ng-template>
|
|
454
|
+
|
|
455
|
+
@switch (effectiveLayoutType()) {
|
|
456
|
+
@case ('empty') {
|
|
457
|
+
<LayoutEmpty>
|
|
458
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
459
|
+
</LayoutEmpty>
|
|
460
|
+
}
|
|
461
|
+
@case ('fluid') {
|
|
462
|
+
<LayoutFluid>
|
|
463
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
464
|
+
</LayoutFluid>
|
|
465
|
+
}
|
|
466
|
+
@case ('horizontal') {
|
|
467
|
+
<LayoutHorizontal>
|
|
468
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
469
|
+
</LayoutHorizontal>
|
|
470
|
+
}
|
|
471
|
+
@default {
|
|
472
|
+
<LayoutVertical>
|
|
473
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
474
|
+
</LayoutVertical>
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
</Layout>
|
|
478
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LayoutComponent, selector: "Layout", inputs: ["surface", "appearance", "layout-appearance", "width", "layout-type", "class"] }, { kind: "component", type: LayoutVerticalComponent, selector: "LayoutVertical", inputs: ["class"] }, { kind: "component", type: LayoutHorizontalComponent, selector: "LayoutHorizontal", inputs: ["class"] }, { kind: "component", type: LayoutEmptyComponent, selector: "LayoutEmpty", inputs: ["class"] }, { kind: "component", type: LayoutFluidComponent, selector: "LayoutFluid", inputs: ["class"] }, { kind: "component", type: LayoutNavigationComponent, selector: "LayoutNavigation", inputs: ["ariaLabel", "railOffset", "class"] }, { kind: "component", type: LayoutContentComponent, selector: "LayoutContent", inputs: ["class"] }, { kind: "component", type: NavigationContainerComponent, selector: "Navigation", inputs: ["id", "data", "ariaLabel", "compact", "collapse-tree", "class", "itemClass", "nav-group-class", "activeIds", "activeUrl", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: LayoutNavSidebar, selector: "LayoutNavSidebar", inputs: ["brand", "user"] }, { kind: "component", type: LayoutNavDockbar, selector: "LayoutNavDockbar", inputs: ["brand", "user"] }, { kind: "component", type: LayoutNavNavbar, selector: "LayoutNavNavbar", inputs: ["brand", "user", "appearance"] }, { kind: "component", type: LayoutNavFlyout, selector: "LayoutNavFlyout", inputs: ["brand", "user", "appearance"] }, { kind: "component", type: LayoutNavMinimal, selector: "LayoutNavMinimal", inputs: ["brand"] }] });
|
|
479
|
+
}
|
|
480
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: LayoutWrapperDefault, decorators: [{
|
|
481
|
+
type: Component,
|
|
482
|
+
args: [{
|
|
483
|
+
selector: 'LayoutWrapperDefault',
|
|
484
|
+
host: { class: 'contents' },
|
|
485
|
+
imports: [
|
|
486
|
+
NgTemplateOutlet,
|
|
487
|
+
LayoutComponent,
|
|
488
|
+
LayoutVerticalComponent,
|
|
489
|
+
LayoutHorizontalComponent,
|
|
490
|
+
LayoutEmptyComponent,
|
|
491
|
+
LayoutFluidComponent,
|
|
492
|
+
LayoutNavigationComponent,
|
|
493
|
+
LayoutContentComponent,
|
|
494
|
+
NavigationContainerComponent,
|
|
495
|
+
LayoutNavSidebar,
|
|
496
|
+
LayoutNavDockbar,
|
|
497
|
+
LayoutNavNavbar,
|
|
498
|
+
LayoutNavFlyout,
|
|
499
|
+
LayoutNavMinimal,
|
|
500
|
+
],
|
|
501
|
+
template: `
|
|
502
|
+
<Layout
|
|
503
|
+
[surface]="surface()"
|
|
504
|
+
[layout-appearance]="appearance()"
|
|
505
|
+
[width]="width()"
|
|
506
|
+
[layout-type]="effectiveLayoutType()"
|
|
507
|
+
>
|
|
508
|
+
<!-- Skeleton bersama: dipakai ulang oleh setiap wrapper di @switch bawah. -->
|
|
509
|
+
<ng-template #body>
|
|
510
|
+
<LayoutNavigation ariaLabel="Primary navigation">
|
|
511
|
+
<Navigation id="main" [data]="data()" [class]="navClass()">
|
|
512
|
+
@switch (navKind()) {
|
|
513
|
+
@case ('navbar') {
|
|
514
|
+
<LayoutNavNavbar [brand]="brand()" [user]="user()" [appearance]="appearance()" />
|
|
515
|
+
}
|
|
516
|
+
@case ('flyout') {
|
|
517
|
+
<LayoutNavFlyout [brand]="brand()" [user]="user()" [appearance]="appearance()" />
|
|
518
|
+
}
|
|
519
|
+
@case ('dockbar') {
|
|
520
|
+
<LayoutNavDockbar [brand]="brand()" [user]="user()" />
|
|
521
|
+
}
|
|
522
|
+
@case ('brand') {
|
|
523
|
+
<LayoutNavMinimal [brand]="brand()" />
|
|
524
|
+
}
|
|
525
|
+
@default {
|
|
526
|
+
<LayoutNavSidebar [brand]="brand()" [user]="user()" />
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
</Navigation>
|
|
530
|
+
</LayoutNavigation>
|
|
531
|
+
|
|
532
|
+
<LayoutContent [class]="contentClass()">
|
|
533
|
+
<ng-content />
|
|
534
|
+
</LayoutContent>
|
|
535
|
+
</ng-template>
|
|
536
|
+
|
|
537
|
+
@switch (effectiveLayoutType()) {
|
|
538
|
+
@case ('empty') {
|
|
539
|
+
<LayoutEmpty>
|
|
540
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
541
|
+
</LayoutEmpty>
|
|
542
|
+
}
|
|
543
|
+
@case ('fluid') {
|
|
544
|
+
<LayoutFluid>
|
|
545
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
546
|
+
</LayoutFluid>
|
|
547
|
+
}
|
|
548
|
+
@case ('horizontal') {
|
|
549
|
+
<LayoutHorizontal>
|
|
550
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
551
|
+
</LayoutHorizontal>
|
|
552
|
+
}
|
|
553
|
+
@default {
|
|
554
|
+
<LayoutVertical>
|
|
555
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
556
|
+
</LayoutVertical>
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
</Layout>
|
|
560
|
+
`,
|
|
561
|
+
}]
|
|
562
|
+
}], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout-appearance", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], layoutType: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout-type", required: false }] }], navType: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-type", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }] } });
|
|
563
|
+
|
|
564
|
+
/*
|
|
565
|
+
* Public API of @ojiepermana/angular-theme/layout/wrapper
|
|
566
|
+
*
|
|
567
|
+
* Wrapper blok-jadi untuk layout shell: consumer cukup menyediakan data input
|
|
568
|
+
* (surface, appearance, width, layout-type, nav-type, navigation data, brand, user)
|
|
569
|
+
* tanpa merakit komponen bersarang. `register*` default tetap di consumer.
|
|
570
|
+
*/
|
|
571
|
+
// Identitas (bentuk data yang disediakan consumer)
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Generated bundle index. Do not edit.
|
|
575
|
+
*/
|
|
576
|
+
|
|
577
|
+
export { LayoutBrand, LayoutNavDockbar, LayoutNavFlyout, LayoutNavMinimal, LayoutNavNavbar, LayoutNavSidebar, LayoutUser, LayoutWrapperDefault };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ojiepermana/angular-theme",
|
|
3
|
-
"version": "22.0.
|
|
3
|
+
"version": "22.0.34",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/edsis/angular.git"
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"@angular/common": ">=22.0.0",
|
|
14
14
|
"@angular/core": ">=22.0.0",
|
|
15
15
|
"@angular/router": ">=22.0.0",
|
|
16
|
-
"@ojiepermana/angular-navigation": "^22.0.
|
|
17
|
-
"@ojiepermana/angular-component": "^22.0.
|
|
16
|
+
"@ojiepermana/angular-navigation": "^22.0.34",
|
|
17
|
+
"@ojiepermana/angular-component": "^22.0.34",
|
|
18
18
|
"rxjs": ">=7.8.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"types": "./types/ojiepermana-angular-theme-layout-types.d.ts",
|
|
49
49
|
"default": "./fesm2022/ojiepermana-angular-theme-layout-types.mjs"
|
|
50
50
|
},
|
|
51
|
+
"./layout/wrapper": {
|
|
52
|
+
"types": "./types/ojiepermana-angular-theme-layout-wrapper.d.ts",
|
|
53
|
+
"default": "./fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs"
|
|
54
|
+
},
|
|
51
55
|
"./page": {
|
|
52
56
|
"types": "./types/ojiepermana-angular-theme-page.d.ts",
|
|
53
57
|
"default": "./fesm2022/ojiepermana-angular-theme-page.mjs"
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { NavigationType, NavigationItem } from '@ojiepermana/angular-navigation';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Bentuk identitas yang dikonsumsi wrapper layout. Library hanya mendefinisikan
|
|
6
|
+
* strukturnya; nilai konkret (brand/user) disediakan consumer sebagai input.
|
|
7
|
+
*/
|
|
8
|
+
interface BrandIdentity {
|
|
9
|
+
/** Nama untuk inisial/aria pada slot header. */
|
|
10
|
+
readonly name: string;
|
|
11
|
+
/** Material symbol untuk logo; `null` → pakai inisial dari `name`. */
|
|
12
|
+
readonly icon: string | null;
|
|
13
|
+
/** Judul brand. */
|
|
14
|
+
readonly title: string;
|
|
15
|
+
/** Subjudul brand. */
|
|
16
|
+
readonly subtitle: string;
|
|
17
|
+
}
|
|
18
|
+
interface UserIdentity {
|
|
19
|
+
/** Nama lengkap user (inisial + judul footer). */
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/** Email / baris sekunder footer. */
|
|
22
|
+
readonly email: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Slot brand untuk `<NavigationHeader>`: inisial/logo + judul. Murni input-driven.
|
|
27
|
+
*
|
|
28
|
+
* `compact` (dockbar / rail ikon-only) menyembunyikan judul. `host.class = 'contents'`
|
|
29
|
+
* membuat `NavigationHeaderInitial` + `NavigationHeaderTitle` tetap menjadi flex-child
|
|
30
|
+
* langsung baris header; auto-hide judul saat sidebar collapsed (via `NAVIGATION_SHELL`)
|
|
31
|
+
* tetap berlaku karena DI mengalir lewat live tree ke `<Navigation>`.
|
|
32
|
+
*/
|
|
33
|
+
declare class LayoutBrand {
|
|
34
|
+
/** Identitas brand (nama, ikon, judul, subjudul). */
|
|
35
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
36
|
+
/** Sembunyikan judul, sisakan inisial saja (dockbar / rail ikon-only). */
|
|
37
|
+
readonly compact: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
38
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutBrand, never>;
|
|
39
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutBrand, "LayoutBrand", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Slot user untuk `<NavigationFooter>`: identitas (opsional) + aksi logout. Murni input-driven.
|
|
44
|
+
*
|
|
45
|
+
* `detailed` menampilkan inisial + nama (sidebar penuh); tanpanya hanya tombol logout.
|
|
46
|
+
* `host.class = 'contents'` membuat anak menjadi flex-child langsung footer — `ml-auto` &
|
|
47
|
+
* auto-hide saat collapsed (via `NAVIGATION_SHELL`) tetap berlaku.
|
|
48
|
+
*/
|
|
49
|
+
declare class LayoutUser {
|
|
50
|
+
/** Identitas user (nama + email). */
|
|
51
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
52
|
+
/** Tampilkan identitas user (inisial + nama), bukan hanya tombol logout. */
|
|
53
|
+
readonly detailed: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
54
|
+
/** Label aksesibilitas tombol logout. */
|
|
55
|
+
readonly logoutLabel: _angular_core.InputSignal<string>;
|
|
56
|
+
/** Material symbol untuk tombol logout. */
|
|
57
|
+
readonly logoutIcon: _angular_core.InputSignal<string>;
|
|
58
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutUser, never>;
|
|
59
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutUser, "LayoutUser", never, { "user": { "alias": "user"; "required": true; "isSignal": true; }; "detailed": { "alias": "detailed"; "required": false; "isSignal": true; }; "logoutLabel": { "alias": "logoutLabel"; "required": false; "isSignal": true; }; "logoutIcon": { "alias": "logoutIcon"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Tipe nav: sidebar vertikal collapsible (default). Brand header + identitas user di footer.
|
|
64
|
+
*
|
|
65
|
+
* `host.class = 'contents'` membuat `<NavigationSidebar>` menjadi anak efektif `<Navigation>`
|
|
66
|
+
* (h-full, shell-classes), sementara DI `NAVIGATION_SHELL` tetap mengalir lewat live tree dan
|
|
67
|
+
* `<NavigationHeader>` tetap direct child untuk content-projection library.
|
|
68
|
+
*/
|
|
69
|
+
declare class LayoutNavSidebar {
|
|
70
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
71
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
72
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutNavSidebar, never>;
|
|
73
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutNavSidebar, "LayoutNavSidebar", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "user": { "alias": "user"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Tipe nav: rail ikon vertikal (dockbar). Brand compact (inisial saja) + aksi logout.
|
|
78
|
+
* Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
79
|
+
*/
|
|
80
|
+
declare class LayoutNavDockbar {
|
|
81
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
82
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
83
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutNavDockbar, never>;
|
|
84
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutNavDockbar, "LayoutNavDockbar", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "user": { "alias": "user"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Tipe nav: top bar item inline (navbar, horizontal). `appearance` selaras shell
|
|
89
|
+
* (`flat | border-rail`). Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
90
|
+
*/
|
|
91
|
+
declare class LayoutNavNavbar {
|
|
92
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
93
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
94
|
+
/** Appearance dari shell (`[nav-appearance]`). */
|
|
95
|
+
readonly appearance: _angular_core.InputSignal<"flat" | "border-rail">;
|
|
96
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutNavNavbar, never>;
|
|
97
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutNavNavbar, "LayoutNavNavbar", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "user": { "alias": "user"; "required": true; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Tipe nav: top bar dengan tombol trigger flyout (horizontal). `appearance` selaras shell.
|
|
102
|
+
* Lihat {@link LayoutNavSidebar} untuk alasan `host.class = 'contents'`.
|
|
103
|
+
*/
|
|
104
|
+
declare class LayoutNavFlyout {
|
|
105
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
106
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
107
|
+
/** Appearance dari shell (`[nav-appearance]`). */
|
|
108
|
+
readonly appearance: _angular_core.InputSignal<"flat" | "border-rail">;
|
|
109
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutNavFlyout, never>;
|
|
110
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutNavFlyout, "LayoutNavFlyout", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "user": { "alias": "user"; "required": true; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Tipe nav: sidebar brand-only untuk varian `empty` / `fluid` (nav disembunyikan oleh
|
|
115
|
+
* `LayoutNavigation`, jadi tanpa collapse & footer). Lihat {@link LayoutNavSidebar} untuk
|
|
116
|
+
* alasan `host.class = 'contents'`.
|
|
117
|
+
*/
|
|
118
|
+
declare class LayoutNavMinimal {
|
|
119
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
120
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutNavMinimal, never>;
|
|
121
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutNavMinimal, "LayoutNavMinimal", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Tipe nav yang dirender `@switch (navKind())`. `brand` = sidebar header-only (empty/fluid). */
|
|
125
|
+
type NavKind = NavigationType | 'brand';
|
|
126
|
+
/**
|
|
127
|
+
* Wrapper layout shell siap pakai — consumer cukup memberi data input, tidak perlu merakit
|
|
128
|
+
* `Layout > LayoutVertical/Horizontal/Empty/Fluid > LayoutNavigation > Navigation > tipe-nav`.
|
|
129
|
+
*
|
|
130
|
+
* ```html
|
|
131
|
+
* <LayoutWrapperDefault
|
|
132
|
+
* [surface]="surface" [layout-appearance]="appearance" [width]="width"
|
|
133
|
+
* [layout-type]="layoutType" [nav-type]="navType"
|
|
134
|
+
* [data]="navItems" [brand]="brand" [user]="user"
|
|
135
|
+
* >
|
|
136
|
+
* <router-outlet /> <!-- konten halaman diproyeksikan ke LayoutContent -->
|
|
137
|
+
* </LayoutWrapperDefault>
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* `register*` default (LayoutService) tetap tanggung jawab consumer; wrapper ini murni
|
|
141
|
+
* presentational — dua sumbu (`effectiveLayoutType` → wrapper, `navKind` → tipe nav) di atas
|
|
142
|
+
* satu skeleton bersama. DI aman: `<Navigation>` mem-*provide* `NAVIGATION_SHELL` di dalam
|
|
143
|
+
* `#body`; tipe nav `display:contents` sehingga `<NavigationXxx>` jadi anak efektif `<Navigation>`.
|
|
144
|
+
*/
|
|
145
|
+
declare class LayoutWrapperDefault {
|
|
146
|
+
/** Surface latar shell (mis. `grid`, `flat`). */
|
|
147
|
+
readonly surface: _angular_core.InputSignal<"flat" | "grid" | "honeycome" | "line-vertical" | "line-horizontal">;
|
|
148
|
+
/** Appearance shell & nav (`flat | border-rail`). */
|
|
149
|
+
readonly appearance: _angular_core.InputSignal<"flat" | "border-rail">;
|
|
150
|
+
/** Lebar frame (`full`, `container`, dst.). */
|
|
151
|
+
readonly width: _angular_core.InputSignal<"full" | "wide" | "container" | "fluid">;
|
|
152
|
+
/** Tipe layout dasar (`vertical | horizontal | empty | fluid`); `empty`/`fluid` override nav. */
|
|
153
|
+
readonly layoutType: _angular_core.InputSignal<"fluid" | "vertical" | "horizontal" | "empty">;
|
|
154
|
+
/** Tipe navigasi (`sidebar | dockbar | navbar | flyout`); diabaikan saat `empty`/`fluid`. */
|
|
155
|
+
readonly navType: _angular_core.InputSignal<NavigationType>;
|
|
156
|
+
/** Item navigasi. */
|
|
157
|
+
readonly data: _angular_core.InputSignal<readonly NavigationItem[]>;
|
|
158
|
+
/** Identitas brand. */
|
|
159
|
+
readonly brand: _angular_core.InputSignal<BrandIdentity>;
|
|
160
|
+
/** Identitas user. */
|
|
161
|
+
readonly user: _angular_core.InputSignal<UserIdentity>;
|
|
162
|
+
/** Wrapper layout & nilai `<Layout [layout-type]>`: navbar/flyout = horizontal, sisanya vertical. */
|
|
163
|
+
protected readonly effectiveLayoutType: _angular_core.Signal<"fluid" | "vertical" | "horizontal" | "empty">;
|
|
164
|
+
/** Tipe nav di dalam `#body`: `empty`/`fluid` → `brand` (header-only); selain itu `nav-type`. */
|
|
165
|
+
protected readonly navKind: _angular_core.Signal<NavKind>;
|
|
166
|
+
/** Lebar host `<Navigation>`: penuh-tinggi (vertical) atau penuh-lebar (horizontal). */
|
|
167
|
+
protected readonly navClass: _angular_core.Signal<"w-full" | "h-full">;
|
|
168
|
+
/** Kelas `<LayoutContent>`: `fluid` membatasi lebar & memusatkan; selain itu padding biasa. */
|
|
169
|
+
protected readonly contentClass: _angular_core.Signal<"w-full max-w-3xl p-6" | "p-6">;
|
|
170
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LayoutWrapperDefault, never>;
|
|
171
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LayoutWrapperDefault, "LayoutWrapperDefault", never, { "surface": { "alias": "surface"; "required": false; "isSignal": true; }; "appearance": { "alias": "layout-appearance"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "layoutType": { "alias": "layout-type"; "required": false; "isSignal": true; }; "navType": { "alias": "nav-type"; "required": false; "isSignal": true; }; "data": { "alias": "data"; "required": true; "isSignal": true; }; "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "user": { "alias": "user"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { LayoutBrand, LayoutNavDockbar, LayoutNavFlyout, LayoutNavMinimal, LayoutNavNavbar, LayoutNavSidebar, LayoutUser, LayoutWrapperDefault };
|
|
175
|
+
export type { BrandIdentity, UserIdentity };
|