@ojiepermana/angular-theme 22.0.35 → 22.0.41
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/README.md +54 -22
- package/fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs +74 -20
- package/fesm2022/ojiepermana-angular-theme-layout.mjs +14 -2
- package/fesm2022/ojiepermana-angular-theme-page.mjs +251 -101
- package/fesm2022/ojiepermana-angular-theme-styles.mjs +375 -53
- package/layout/README.md +21 -19
- package/package.json +3 -3
- package/page/README.md +53 -15
- package/styles/README.md +18 -3
- package/styles/css/{seasonal/base → base}/tailwind.css +9 -5
- package/styles/css/{seasonal/base → base}/theme.css +27 -52
- package/styles/css/{seasonal/base → base}/tokens.css +62 -44
- package/styles/css/color/amber.css +52 -0
- package/styles/css/color/blue.css +52 -0
- package/styles/css/color/brand.css +16 -0
- package/styles/css/color/cyan.css +52 -0
- package/styles/css/color/emerald.css +52 -0
- package/styles/css/color/fuchsia.css +52 -0
- package/styles/css/color/green.css +52 -0
- package/styles/css/color/index.css +19 -0
- package/styles/css/color/indigo.css +52 -0
- package/styles/css/color/lime.css +52 -0
- package/styles/css/color/orange.css +52 -0
- package/styles/css/color/pink.css +52 -0
- package/styles/css/color/purple.css +52 -0
- package/styles/css/color/red.css +52 -0
- package/styles/css/color/rose.css +52 -0
- package/styles/css/color/sky.css +52 -0
- package/styles/css/color/teal.css +52 -0
- package/styles/css/color/violet.css +52 -0
- package/styles/css/color/yellow.css +52 -0
- package/styles/css/index.css +15 -6
- package/styles/css/neutral/gray.css +36 -0
- package/styles/css/neutral/index.css +11 -0
- package/styles/css/neutral/mauve.css +36 -0
- package/styles/css/neutral/mist.css +36 -0
- package/styles/css/neutral/neutral.css +36 -0
- package/styles/css/neutral/olive.css +36 -0
- package/styles/css/neutral/slate.css +36 -0
- package/styles/css/neutral/stone.css +36 -0
- package/styles/css/neutral/taupe.css +36 -0
- package/styles/css/neutral/zinc.css +36 -0
- package/styles/css/radius/index.css +29 -0
- package/styles/css/space/index.css +24 -0
- package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +43 -10
- package/types/ojiepermana-angular-theme-layout.d.ts +1 -0
- package/types/ojiepermana-angular-theme-page.d.ts +88 -36
- package/types/ojiepermana-angular-theme-styles.d.ts +169 -37
- package/styles/css/seasonal/ied/package.css +0 -4
- package/styles/css/seasonal/ied/theme.css +0 -78
- package/styles/css/seasonal/imlek/components.css +0 -87
- package/styles/css/seasonal/imlek/package.css +0 -6
- package/styles/css/seasonal/imlek/tailwind.css +0 -144
- package/styles/css/seasonal/imlek/theme.css +0 -95
- package/styles/css/seasonal/imlek/tokens.css +0 -152
- package/styles/css/seasonal/index.css +0 -6
- package/styles/css/seasonal/natal/package.css +0 -4
- package/styles/css/seasonal/natal/theme.css +0 -78
- package/styles/css/seasonal/new-year/package.css +0 -4
- package/styles/css/seasonal/new-year/theme.css +0 -78
- package/styles/css/seasonal/ramadhan/package.css +0 -4
- package/styles/css/seasonal/ramadhan/theme.css +0 -78
- /package/styles/css/{seasonal/base → base}/components.css +0 -0
- /package/styles/css/{seasonal/base → base}/package.css +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @ojiepermana/angular-theme
|
|
2
2
|
|
|
3
3
|
Theme layer for the `@ojiepermana/angular` design system: a runtime provider
|
|
4
|
-
(mode /
|
|
5
|
-
styled against.
|
|
4
|
+
(mode / color / neutral / brand), design tokens, and the Tailwind v4 CSS that the
|
|
5
|
+
components are styled against.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
bun add @ojiepermana/angular-theme
|
|
@@ -11,13 +11,13 @@ bun add @ojiepermana/angular-theme
|
|
|
11
11
|
|
|
12
12
|
## Entry points
|
|
13
13
|
|
|
14
|
-
| Import path
|
|
15
|
-
|
|
|
16
|
-
| `@ojiepermana/angular-theme/styles`
|
|
17
|
-
| `@ojiepermana/angular-theme/layout`
|
|
18
|
-
| `@ojiepermana/angular-theme/page`
|
|
19
|
-
| `@ojiepermana/angular-theme/theme.css`
|
|
20
|
-
| `@ojiepermana/angular-theme/styles/css
|
|
14
|
+
| Import path | Contents |
|
|
15
|
+
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| `@ojiepermana/angular-theme/styles` | `provideUiTheme`, `ThemeModeService`, `ThemeColorService`, `ThemeBrandService`, `ThemeRadiusService`, `ThemeSpaceService`, … |
|
|
17
|
+
| `@ojiepermana/angular-theme/layout` | Layout shell building blocks |
|
|
18
|
+
| `@ojiepermana/angular-theme/page` | Page-level scaffolding |
|
|
19
|
+
| `@ojiepermana/angular-theme/theme.css` | Base tokens + component styles (CSS) |
|
|
20
|
+
| `@ojiepermana/angular-theme/styles/css/*` | Raw CSS assets (color + neutral palettes, Tailwind map) |
|
|
21
21
|
|
|
22
22
|
## Tailwind v4 setup
|
|
23
23
|
|
|
@@ -26,9 +26,9 @@ stylesheet:
|
|
|
26
26
|
|
|
27
27
|
```css
|
|
28
28
|
/* styles.css */
|
|
29
|
-
@import '@ojiepermana/angular-theme/
|
|
29
|
+
@import '@ojiepermana/angular-theme/styles/css/index.css'; /* base + all color + neutral palettes */
|
|
30
30
|
@import 'tailwindcss';
|
|
31
|
-
@import '@ojiepermana/angular-theme/styles/css/
|
|
31
|
+
@import '@ojiepermana/angular-theme/styles/css/base/tailwind.css'; /* maps tokens → bg-primary, bg-brand, text-foreground, … */
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Requires Tailwind CSS `^4.3.0`.
|
|
@@ -39,20 +39,52 @@ Requires Tailwind CSS `^4.3.0`.
|
|
|
39
39
|
import { provideUiTheme } from '@ojiepermana/angular-theme/styles';
|
|
40
40
|
|
|
41
41
|
export const appConfig = {
|
|
42
|
-
providers: [
|
|
42
|
+
providers: [
|
|
43
|
+
provideUiTheme({
|
|
44
|
+
mode: 'light',
|
|
45
|
+
color: 'base', // accent palette (base, red…rose, brand)
|
|
46
|
+
neutral: 'base', // gray family (base, slate, gray, zinc, …)
|
|
47
|
+
radius: 'md', // corner radius preset (none, sm, md, lg, xl, full)
|
|
48
|
+
space: 'normal', // spacing density preset (compact, normal, relaxed, spacious)
|
|
49
|
+
brand: { color: '221 83% 53%', foreground: '0 0% 100%' }, // consumer brand
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
43
52
|
};
|
|
44
53
|
```
|
|
45
54
|
|
|
46
|
-
- `mode` — bootstraps `ThemeModeService` and persists the default mode.
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
- `mode` — bootstraps `ThemeModeService` and persists the default mode (`light` / `dark` / `system`).
|
|
56
|
+
- `color` — bootstraps `ThemeColorService`; initial accent palette (`<html theme-color>`).
|
|
57
|
+
- `neutral` — initial neutral family (`<html theme-neutral>`); composes with any accent.
|
|
58
|
+
- `radius` — bootstraps `ThemeRadiusService`; initial corner-radius preset (`<html theme-radius>`).
|
|
59
|
+
Drives the single `--radius-base` knob so the whole `--radius-*` scale and `rounded-*`
|
|
60
|
+
utilities follow. Values: `none`, `sm`, `md` (default), `lg`, `xl`, `full`.
|
|
61
|
+
- `space` — bootstraps `ThemeSpaceService`; initial spacing-density preset (`<html theme-space>`).
|
|
62
|
+
Drives the single `--spacing-base` knob so every `p-*` / `m-*` / `gap-*` / `w-*` / `h-*`
|
|
63
|
+
utility follows. Values: `compact`, `normal` (default), `relaxed`, `spacious`.
|
|
64
|
+
- `brand` — bootstraps `ThemeBrandService`; sets `--brand` / `bg-brand` and the
|
|
65
|
+
`theme-color='brand'` accent preset. Accepts an HSL triplet string (`'221 83% 53%'`)
|
|
66
|
+
or `{ color, foreground }`. Settable at runtime via `setBrand()`.
|
|
67
|
+
|
|
68
|
+
A persisted choice (localStorage `theme-color` / `theme-neutral` / `theme-radius` /
|
|
69
|
+
`theme-space` / `theme-brand`) always wins over the configured default.
|
|
70
|
+
|
|
71
|
+
### Color system (FluxUI-style)
|
|
72
|
+
|
|
73
|
+
Four independent axes switch at runtime via attribute selectors on `<html>`:
|
|
74
|
+
|
|
75
|
+
- **accent** (`theme-color`) — `base` (core), `red … rose`, and `brand`. Each
|
|
76
|
+
re-tints the full palette. `base` = no override.
|
|
77
|
+
- **neutral** (`theme-neutral`) — `base` (core), `slate`, `gray`, `zinc`, `neutral`,
|
|
78
|
+
`stone`, `mauve`, `olive`, `mist`, `taupe`. Overrides only the gray family and is
|
|
79
|
+
layered after accent so it wins the shared neutral tokens — letting you pair any
|
|
80
|
+
accent with any neutral.
|
|
81
|
+
- **radius** (`theme-radius`) — `none`, `sm`, `md` (default), `lg`, `xl`, `full`.
|
|
82
|
+
Sets the `--radius-base` knob; the full `--radius-*` scale and `rounded-*` utilities follow.
|
|
83
|
+
- **space** (`theme-space`) — `compact`, `normal` (default), `relaxed`, `spacious`.
|
|
84
|
+
Sets the `--spacing-base` knob; every `p-*` / `m-*` / `gap-*` / `w-*` / `h-*` utility follows.
|
|
85
|
+
|
|
86
|
+
`styles/css/index.css` bundles the core base theme plus every accent and neutral
|
|
87
|
+
palette, so switching needs no runtime CSS loading.
|
|
56
88
|
|
|
57
89
|
### Material Symbols icons (opt-in)
|
|
58
90
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, booleanAttribute, Component, computed } from '@angular/core';
|
|
2
|
+
import { signal, Service, input, booleanAttribute, Component, computed, inject, effect } from '@angular/core';
|
|
3
3
|
import { NavigationHeaderInitialComponent, NavigationHeaderTitleComponent, NavigationFooterActionComponent, NavigationFooterInitialComponent, NavigationFooterTitleComponent, NavigationSidebarComponent, NavigationHeaderComponent, NavigationFooterComponent, NavigationDockbarComponent, NavigationNavbarComponent, NavigationFlyoutComponent, NavigationContainerComponent } from '@ojiepermana/angular-navigation';
|
|
4
4
|
import { IconComponent } from '@ojiepermana/angular-component/icon';
|
|
5
5
|
import { NgTemplateOutlet } from '@angular/common';
|
|
6
|
+
import { cn } from '@ojiepermana/angular-component/utils';
|
|
6
7
|
import { LayoutComponent, LayoutVerticalComponent, LayoutHorizontalComponent, LayoutEmptyComponent, LayoutFluidComponent, LayoutNavigationComponent, LayoutContentComponent } from '@ojiepermana/angular-theme/layout';
|
|
7
8
|
import { LAYOUT_DEFAULT_SURFACE, LAYOUT_DEFAULT_APPEARANCE, LAYOUT_DEFAULT_WIDTH, LAYOUT_DEFAULT_TYPE } from '@ojiepermana/angular-theme/layout/types';
|
|
8
9
|
|
|
@@ -11,6 +12,31 @@ import { LAYOUT_DEFAULT_SURFACE, LAYOUT_DEFAULT_APPEARANCE, LAYOUT_DEFAULT_WIDTH
|
|
|
11
12
|
* strukturnya; nilai konkret (brand/user) disediakan consumer sebagai input.
|
|
12
13
|
*/
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Registry identitas brand/user yang dipublikasikan shell (mis. `LayoutWrapperDefault`).
|
|
17
|
+
* Surface lain — seperti apps-launcher di `Page` — membacanya agar menampilkan brand/user
|
|
18
|
+
* yang sama dengan flyout nav tanpa menerima input langsung.
|
|
19
|
+
*/
|
|
20
|
+
class LayoutIdentityService {
|
|
21
|
+
brandState = signal(null, /* @ts-ignore */
|
|
22
|
+
...(ngDevMode ? [{ debugName: "brandState" }] : /* istanbul ignore next */ []));
|
|
23
|
+
userState = signal(null, /* @ts-ignore */
|
|
24
|
+
...(ngDevMode ? [{ debugName: "userState" }] : /* istanbul ignore next */ []));
|
|
25
|
+
brand = this.brandState.asReadonly();
|
|
26
|
+
user = this.userState.asReadonly();
|
|
27
|
+
setBrand(brand) {
|
|
28
|
+
this.brandState.set(brand);
|
|
29
|
+
}
|
|
30
|
+
setUser(user) {
|
|
31
|
+
this.userState.set(user);
|
|
32
|
+
}
|
|
33
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: LayoutIdentityService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
34
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.3", ngImport: i0, type: LayoutIdentityService });
|
|
35
|
+
}
|
|
36
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: LayoutIdentityService, decorators: [{
|
|
37
|
+
type: Service
|
|
38
|
+
}] });
|
|
39
|
+
|
|
14
40
|
/**
|
|
15
41
|
* Slot brand untuk `<NavigationHeader>`: inisial/logo + judul. Murni input-driven.
|
|
16
42
|
*
|
|
@@ -129,19 +155,27 @@ class LayoutNavSidebar {
|
|
|
129
155
|
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
130
156
|
user = input.required(/* @ts-ignore */
|
|
131
157
|
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
132
|
-
/** Appearance dari shell (`[appearance]`);
|
|
158
|
+
/** Appearance dari shell (`[appearance]`); menentukan ketebalan border pemisah. */
|
|
133
159
|
appearance = input('flat', /* @ts-ignore */
|
|
134
160
|
...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
isBorderRail = computed(() => this.appearance() === 'border-rail', /* @ts-ignore */
|
|
162
|
+
...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
|
|
163
|
+
/** Border kanan pemisah; ketebalan ikut appearance: `border-rail` 1.5px, `flat` 1px. */
|
|
164
|
+
shellClass = computed(() => this.isBorderRail() ? 'border-r-[1.5px] border-border' : 'border-r border-border', /* @ts-ignore */
|
|
137
165
|
...(ngDevMode ? [{ debugName: "shellClass" }] : /* istanbul ignore next */ []));
|
|
166
|
+
/** Header divider menebal jadi 1.5px di `border-rail` (selaras nav/shell); `flat` pakai default. */
|
|
167
|
+
headerClass = computed(() => this.isBorderRail() ? 'border-b-[1.5px] border-border' : '', /* @ts-ignore */
|
|
168
|
+
...(ngDevMode ? [{ debugName: "headerClass" }] : /* istanbul ignore next */ []));
|
|
169
|
+
/** Footer divider menebal jadi 1.5px di `border-rail`; `px-3` tetap dipertahankan. */
|
|
170
|
+
footerClass = computed(() => this.isBorderRail() ? 'px-3 border-t-[1.5px] border-border' : 'px-3', /* @ts-ignore */
|
|
171
|
+
...(ngDevMode ? [{ debugName: "footerClass" }] : /* istanbul ignore next */ []));
|
|
138
172
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: LayoutNavSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
139
173
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.3", 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 }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
140
174
|
<NavigationSidebar nav-sidebar-collapse [class]="shellClass()">
|
|
141
|
-
<NavigationHeader>
|
|
175
|
+
<NavigationHeader [class]="headerClass()">
|
|
142
176
|
<LayoutBrand [brand]="brand()" />
|
|
143
177
|
</NavigationHeader>
|
|
144
|
-
<NavigationFooter class="
|
|
178
|
+
<NavigationFooter [class]="footerClass()">
|
|
145
179
|
<LayoutUser [user]="user()" detailed />
|
|
146
180
|
</NavigationFooter>
|
|
147
181
|
</NavigationSidebar>
|
|
@@ -161,10 +195,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
|
|
|
161
195
|
host: { class: 'contents' },
|
|
162
196
|
template: `
|
|
163
197
|
<NavigationSidebar nav-sidebar-collapse [class]="shellClass()">
|
|
164
|
-
<NavigationHeader>
|
|
198
|
+
<NavigationHeader [class]="headerClass()">
|
|
165
199
|
<LayoutBrand [brand]="brand()" />
|
|
166
200
|
</NavigationHeader>
|
|
167
|
-
<NavigationFooter class="
|
|
201
|
+
<NavigationFooter [class]="footerClass()">
|
|
168
202
|
<LayoutUser [user]="user()" detailed />
|
|
169
203
|
</NavigationFooter>
|
|
170
204
|
</NavigationSidebar>
|
|
@@ -181,19 +215,27 @@ class LayoutNavDockbar {
|
|
|
181
215
|
...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
|
|
182
216
|
user = input.required(/* @ts-ignore */
|
|
183
217
|
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
184
|
-
/** Appearance dari shell (`[appearance]`);
|
|
218
|
+
/** Appearance dari shell (`[appearance]`); menentukan ketebalan border pemisah. */
|
|
185
219
|
appearance = input('flat', /* @ts-ignore */
|
|
186
220
|
...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
187
|
-
|
|
188
|
-
|
|
221
|
+
isBorderRail = computed(() => this.appearance() === 'border-rail', /* @ts-ignore */
|
|
222
|
+
...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
|
|
223
|
+
/** Border kanan pemisah; ketebalan ikut appearance: `border-rail` 1.5px, `flat` 1px. */
|
|
224
|
+
shellClass = computed(() => this.isBorderRail() ? 'border-r-[1.5px] border-border' : 'border-r border-border', /* @ts-ignore */
|
|
189
225
|
...(ngDevMode ? [{ debugName: "shellClass" }] : /* istanbul ignore next */ []));
|
|
226
|
+
/** Header divider menebal jadi 1.5px di `border-rail` (selaras nav/shell); `flat` pakai default. */
|
|
227
|
+
headerClass = computed(() => this.isBorderRail() ? 'border-b-[1.5px] border-border' : '', /* @ts-ignore */
|
|
228
|
+
...(ngDevMode ? [{ debugName: "headerClass" }] : /* istanbul ignore next */ []));
|
|
229
|
+
/** Footer divider menebal jadi 1.5px di `border-rail`; `px-3` tetap dipertahankan. */
|
|
230
|
+
footerClass = computed(() => this.isBorderRail() ? 'px-3 border-t-[1.5px] border-border' : 'px-3', /* @ts-ignore */
|
|
231
|
+
...(ngDevMode ? [{ debugName: "footerClass" }] : /* istanbul ignore next */ []));
|
|
190
232
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: LayoutNavDockbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
191
233
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.3", 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 }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
192
234
|
<NavigationDockbar [class]="shellClass()">
|
|
193
|
-
<NavigationHeader>
|
|
235
|
+
<NavigationHeader [class]="headerClass()">
|
|
194
236
|
<LayoutBrand [brand]="brand()" compact />
|
|
195
237
|
</NavigationHeader>
|
|
196
|
-
<NavigationFooter class="
|
|
238
|
+
<NavigationFooter [class]="footerClass()">
|
|
197
239
|
<LayoutUser [user]="user()" />
|
|
198
240
|
</NavigationFooter>
|
|
199
241
|
</NavigationDockbar>
|
|
@@ -213,10 +255,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
|
|
|
213
255
|
host: { class: 'contents' },
|
|
214
256
|
template: `
|
|
215
257
|
<NavigationDockbar [class]="shellClass()">
|
|
216
|
-
<NavigationHeader>
|
|
258
|
+
<NavigationHeader [class]="headerClass()">
|
|
217
259
|
<LayoutBrand [brand]="brand()" compact />
|
|
218
260
|
</NavigationHeader>
|
|
219
|
-
<NavigationFooter class="
|
|
261
|
+
<NavigationFooter [class]="footerClass()">
|
|
220
262
|
<LayoutUser [user]="user()" />
|
|
221
263
|
</NavigationFooter>
|
|
222
264
|
</NavigationDockbar>
|
|
@@ -406,6 +448,18 @@ class LayoutWrapperDefault {
|
|
|
406
448
|
/** Identitas user. */
|
|
407
449
|
user = input.required(/* @ts-ignore */
|
|
408
450
|
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
451
|
+
identity = inject(LayoutIdentityService);
|
|
452
|
+
constructor() {
|
|
453
|
+
// Publikasikan identitas ke registry agar surface lain (mis. apps-launcher di `Page`)
|
|
454
|
+
// menampilkan brand/user yang sama dengan flyout nav.
|
|
455
|
+
effect(() => this.identity.setBrand(this.brand()));
|
|
456
|
+
effect(() => this.identity.setUser(this.user()));
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Kelas `<LayoutContent>` yang diatur consumer (mis. padding). Default kosong —
|
|
460
|
+
* library tidak lagi memaksa `p-6`; consumer/`<Page>` yang menentukan spacing.
|
|
461
|
+
*/
|
|
462
|
+
contentClassInput = input('', { ...(ngDevMode ? { debugName: "contentClassInput" } : /* istanbul ignore next */ {}), alias: 'content-class' });
|
|
409
463
|
/** Wrapper layout & nilai `<Layout [layout-type]>`: navbar/flyout = horizontal, sisanya vertical. */
|
|
410
464
|
effectiveLayoutType = computed(() => {
|
|
411
465
|
const layoutType = this.layoutType();
|
|
@@ -424,11 +478,11 @@ class LayoutWrapperDefault {
|
|
|
424
478
|
/** Lebar host `<Navigation>`: penuh-tinggi (vertical) atau penuh-lebar (horizontal). */
|
|
425
479
|
navClass = computed(() => this.effectiveLayoutType() === 'horizontal' ? 'w-full' : 'h-full', /* @ts-ignore */
|
|
426
480
|
...(ngDevMode ? [{ debugName: "navClass" }] : /* istanbul ignore next */ []));
|
|
427
|
-
/** Kelas `<LayoutContent>`: `fluid` membatasi lebar & memusatkan;
|
|
428
|
-
contentClass = computed(() => this.effectiveLayoutType() === 'fluid' ? 'w-full max-w-3xl
|
|
481
|
+
/** Kelas `<LayoutContent>`: `fluid` membatasi lebar & memusatkan; padding diserahkan ke consumer. */
|
|
482
|
+
contentClass = computed(() => cn(this.effectiveLayoutType() === 'fluid' ? 'w-full max-w-3xl' : '', this.contentClassInput()), /* @ts-ignore */
|
|
429
483
|
...(ngDevMode ? [{ debugName: "contentClass" }] : /* istanbul ignore next */ []));
|
|
430
484
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: LayoutWrapperDefault, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
431
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", 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: `
|
|
485
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", 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 }, contentClassInput: { classPropertyName: "contentClassInput", publicName: "content-class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
432
486
|
<Layout
|
|
433
487
|
[surface]="surface()"
|
|
434
488
|
[layout-appearance]="appearance()"
|
|
@@ -571,7 +625,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
|
|
|
571
625
|
</Layout>
|
|
572
626
|
`,
|
|
573
627
|
}]
|
|
574
|
-
}], 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 }] }] } });
|
|
628
|
+
}], ctorParameters: () => [], 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 }] }], contentClassInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "content-class", required: false }] }] } });
|
|
575
629
|
|
|
576
630
|
/*
|
|
577
631
|
* Public API of @ojiepermana/angular-theme/layout/wrapper
|
|
@@ -586,4 +640,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
|
|
|
586
640
|
* Generated bundle index. Do not edit.
|
|
587
641
|
*/
|
|
588
642
|
|
|
589
|
-
export { LayoutBrand, LayoutNavDockbar, LayoutNavFlyout, LayoutNavMinimal, LayoutNavNavbar, LayoutNavSidebar, LayoutUser, LayoutWrapperDefault };
|
|
643
|
+
export { LayoutBrand, LayoutIdentityService, LayoutNavDockbar, LayoutNavFlyout, LayoutNavMinimal, LayoutNavNavbar, LayoutNavSidebar, LayoutUser, LayoutWrapperDefault };
|
|
@@ -116,6 +116,8 @@ class LayoutComponent {
|
|
|
116
116
|
...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
|
|
117
117
|
isFluidFrame = computed(() => this.resolvedWidth() === 'fluid' && this.resolvedType() === 'fluid', /* @ts-ignore */
|
|
118
118
|
...(ngDevMode ? [{ debugName: "isFluidFrame" }] : /* istanbul ignore next */ []));
|
|
119
|
+
isFullFlat = computed(() => this.resolvedWidth() === 'full' && !this.isBorderRail(), /* @ts-ignore */
|
|
120
|
+
...(ngDevMode ? [{ debugName: "isFullFlat" }] : /* istanbul ignore next */ []));
|
|
119
121
|
showsInsetRails = computed(() => {
|
|
120
122
|
const layoutType = this.resolvedType();
|
|
121
123
|
return this.isBorderRail() && (layoutType === 'horizontal' || layoutType === 'vertical');
|
|
@@ -129,7 +131,15 @@ class LayoutComponent {
|
|
|
129
131
|
...(ngDevMode ? [{ debugName: "contentShellClasses" }] : /* istanbul ignore next */ []));
|
|
130
132
|
hostClasses = computed(() => cn('relative isolate h-dvh w-full min-w-0 box-border overflow-hidden text-foreground', this.isFluidFrame() ? 'grid place-items-center' : 'block', this.surfaceClasses(), this.widthPaddingClasses(), this.class()), /* @ts-ignore */
|
|
131
133
|
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
132
|
-
frameClasses = computed(() => cn('relative min-h-0 min-w-0 border-border bg-background/55 backdrop-blur-xs', this.frameSizeClasses(),
|
|
134
|
+
frameClasses = computed(() => cn('relative min-h-0 min-w-0 border-border bg-background/55 backdrop-blur-xs', this.frameSizeClasses(),
|
|
135
|
+
// flat: the outer frame rounds with the active theme-radius
|
|
136
|
+
// (--layout-frame-radius → --radius-lg → --radius-base). border-rail keeps
|
|
137
|
+
// square corners for its grid-rail aesthetic.
|
|
138
|
+
this.isBorderRail()
|
|
139
|
+
? 'overflow-visible border-[1.5px]'
|
|
140
|
+
: this.isFullFlat()
|
|
141
|
+
? 'overflow-hidden'
|
|
142
|
+
: 'overflow-hidden border rounded-[var(--layout-frame-radius)]'), /* @ts-ignore */
|
|
133
143
|
...(ngDevMode ? [{ debugName: "frameClasses" }] : /* istanbul ignore next */ []));
|
|
134
144
|
frameLayerClasses = computed(() => cn('col-start-1 row-start-1', this.frameClasses()), /* @ts-ignore */
|
|
135
145
|
...(ngDevMode ? [{ debugName: "frameLayerClasses" }] : /* istanbul ignore next */ []));
|
|
@@ -180,6 +190,8 @@ class LayoutComponent {
|
|
|
180
190
|
}
|
|
181
191
|
}
|
|
182
192
|
widthPaddingClasses() {
|
|
193
|
+
if (this.isFullFlat())
|
|
194
|
+
return '';
|
|
183
195
|
switch (this.resolvedWidth()) {
|
|
184
196
|
case 'wide':
|
|
185
197
|
return 'p-4 lg:p-12';
|
|
@@ -188,7 +200,7 @@ class LayoutComponent {
|
|
|
188
200
|
case 'fluid':
|
|
189
201
|
return 'p-4 sm:p-6 lg:p-8';
|
|
190
202
|
default:
|
|
191
|
-
return 'p-4';
|
|
203
|
+
return 'p-4'; // full + border-rail
|
|
192
204
|
}
|
|
193
205
|
}
|
|
194
206
|
frameSizeClasses() {
|