@ojiepermana/angular 21.1.9 → 21.1.12
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 +13 -0
- package/brand/etos/README.md +16 -69
- package/etos/styles/color.css +52 -0
- package/etos/styles/layout.css +0 -165
- package/fesm2022/ojiepermana-angular-brand-etos.mjs +398 -234
- package/fesm2022/ojiepermana-angular-brand-etos.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-chart.mjs +72 -72
- package/fesm2022/ojiepermana-angular-chart.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-component.mjs +306 -296
- package/fesm2022/ojiepermana-angular-component.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-layout.mjs +75 -56
- package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-navigation.mjs +279 -258
- package/fesm2022/ojiepermana-angular-navigation.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-theme.mjs +3 -3
- package/fesm2022/ojiepermana-angular-theme.mjs.map +1 -1
- package/generator/api/README.md +17 -10
- package/generator/api/bin/schematics/sdk/index.js +18 -0
- package/generator/api/bin/src/layout/per-domain.js +15 -7
- package/generator/api/bin/src/writer/index.js +24 -11
- package/package.json +1 -1
- package/theme/styles/themes/taildwind.css +3 -0
- package/types/ojiepermana-angular-brand-etos.d.ts +30 -53
- package/types/ojiepermana-angular-component.d.ts +2 -1
- package/types/ojiepermana-angular-layout.d.ts +18 -11
- package/types/ojiepermana-angular-navigation.d.ts +28 -15
package/README.md
CHANGED
|
@@ -33,6 +33,19 @@ If you install the package with `npm install`, `bun add`, `pnpm add`, or `yarn
|
|
|
33
33
|
add` directly, peer dependency installation falls back to the package
|
|
34
34
|
manager's own behavior.
|
|
35
35
|
|
|
36
|
+
## Navigation primitives
|
|
37
|
+
|
|
38
|
+
`@ojiepermana/angular/navigation` exports the shared sidebar and topbar building blocks used by the demo shells. The vertical navigation selector is now `sidebar` and the projected sidebar slots use `sidebar-header` and `sidebar-footer`.
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<sidebar [ariaLabel]="'Primary'" [appearance]="'default'">
|
|
42
|
+
<div sidebar-header>Brand</div>
|
|
43
|
+
<div sidebar-footer>Footer actions</div>
|
|
44
|
+
</sidebar>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Register items through `NavigationService.registerItems(...)`, or pass them directly with the `items` input when composing a local navigation tree.
|
|
48
|
+
|
|
36
49
|
## SDK generator in a consumer workspace
|
|
37
50
|
|
|
38
51
|
After `@ojiepermana/angular` is installed, a consumer workspace can scaffold an
|
package/brand/etos/README.md
CHANGED
|
@@ -6,7 +6,6 @@ Use this folder for Etos-specific implementation:
|
|
|
6
6
|
|
|
7
7
|
- `core/` contains Etos provider composition and brand defaults.
|
|
8
8
|
- `themes/` contains Etos color, style, layout, and component-facing CSS.
|
|
9
|
-
- `layouts/` contains Etos shell components.
|
|
10
9
|
- `navigation/`, `components/`, `assets/`, and `docs/` can be added when Etos needs brand-specific behavior beyond shared primitives.
|
|
11
10
|
|
|
12
11
|
Shared services, types, and primitives stay in the generic libraries:
|
|
@@ -20,14 +19,7 @@ Shared services, types, and primitives stay in the generic libraries:
|
|
|
20
19
|
Published consumers should import Etos through the short public entrypoint:
|
|
21
20
|
|
|
22
21
|
```ts
|
|
23
|
-
import {
|
|
24
|
-
type EtosBrandOptions,
|
|
25
|
-
EtosHorizontalLayoutComponent,
|
|
26
|
-
EtosThemeSwitcherComponent,
|
|
27
|
-
EtosVerticalLayoutComponent,
|
|
28
|
-
provideEtosBrand,
|
|
29
|
-
} from '@ojiepermana/angular/etos';
|
|
30
|
-
import { LayoutService } from '@ojiepermana/angular/layout';
|
|
22
|
+
import { type EtosBrandOptions, EtosThemeSwitcherComponent, provideEtosBrand } from '@ojiepermana/angular/etos';
|
|
31
23
|
|
|
32
24
|
export const etosBrandConfig = {
|
|
33
25
|
theme: {
|
|
@@ -36,7 +28,7 @@ export const etosBrandConfig = {
|
|
|
36
28
|
},
|
|
37
29
|
layout: {
|
|
38
30
|
mode: 'vertical',
|
|
39
|
-
width: '
|
|
31
|
+
width: 'container',
|
|
40
32
|
},
|
|
41
33
|
} satisfies EtosBrandOptions;
|
|
42
34
|
|
|
@@ -45,60 +37,7 @@ export const appConfig = {
|
|
|
45
37
|
};
|
|
46
38
|
```
|
|
47
39
|
|
|
48
|
-
`provideEtosBrand()` applies the Etos brand tokens and wires the shared `ThemeService` and `LayoutService` defaults for the app.
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
@Component({
|
|
52
|
-
imports: [EtosHorizontalLayoutComponent, EtosThemeSwitcherComponent, EtosVerticalLayoutComponent],
|
|
53
|
-
template: `
|
|
54
|
-
@switch (layoutMode()) {
|
|
55
|
-
@case ('horizontal') {
|
|
56
|
-
<etos-horizontal-layout>
|
|
57
|
-
<div ui-layout-profile>
|
|
58
|
-
<etos-theme-switcher
|
|
59
|
-
[userInfo]="profileInfo"
|
|
60
|
-
[quickActions]="horizontalQuickActions"
|
|
61
|
-
[notificationShortcut]="horizontalNotificationShortcut" />
|
|
62
|
-
</div>
|
|
63
|
-
</etos-horizontal-layout>
|
|
64
|
-
}
|
|
65
|
-
@default {
|
|
66
|
-
<etos-vertical-layout>
|
|
67
|
-
<div ui-sidebar-footer class="flex items-center gap-3">
|
|
68
|
-
<etos-theme-switcher [userInfo]="profileInfo" [quickActions]="verticalQuickActions" popoverAlign="start" />
|
|
69
|
-
|
|
70
|
-
<div class="flex flex-col gap-px">
|
|
71
|
-
<span>Ojie Permana</span>
|
|
72
|
-
<span>Etos design system navigator</span>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</etos-vertical-layout>
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
`,
|
|
79
|
-
})
|
|
80
|
-
export class Pages {
|
|
81
|
-
protected readonly layoutMode = inject(LayoutService).mode;
|
|
82
|
-
protected readonly profileInfo = {
|
|
83
|
-
name: 'Ojie Permana',
|
|
84
|
-
subtitle: 'Etos design system navigator',
|
|
85
|
-
avatarSrc: '/avatar-ojie.svg',
|
|
86
|
-
avatarAlt: 'Portrait of Ojie Permana',
|
|
87
|
-
};
|
|
88
|
-
protected readonly horizontalQuickActions = [
|
|
89
|
-
{ value: 'sign-out', label: 'Logout', icon: 'logout', tone: 'destructive' },
|
|
90
|
-
];
|
|
91
|
-
protected readonly verticalQuickActions = [
|
|
92
|
-
{ value: 'notifications', label: 'Notifications', icon: 'notifications' },
|
|
93
|
-
{ value: 'sign-out', label: 'Logout', icon: 'logout', tone: 'destructive' },
|
|
94
|
-
];
|
|
95
|
-
protected readonly horizontalNotificationShortcut = {
|
|
96
|
-
value: 'notifications',
|
|
97
|
-
icon: 'notifications',
|
|
98
|
-
ariaLabel: 'Open notifications for Ojie Permana',
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
```
|
|
40
|
+
`provideEtosBrand()` applies the Etos brand tokens and wires the shared `ThemeService` and `LayoutService` defaults for the app. `EtosThemeSwitcherComponent` remains the Etos-owned UI component exported from this entrypoint.
|
|
102
41
|
|
|
103
42
|
## Using the brand theme
|
|
104
43
|
|
|
@@ -127,7 +66,7 @@ export const etosBrandConfig = {
|
|
|
127
66
|
},
|
|
128
67
|
layout: {
|
|
129
68
|
mode: 'vertical',
|
|
130
|
-
width: '
|
|
69
|
+
width: 'container',
|
|
131
70
|
},
|
|
132
71
|
} satisfies EtosBrandOptions;
|
|
133
72
|
|
|
@@ -136,7 +75,7 @@ export const appConfig = {
|
|
|
136
75
|
};
|
|
137
76
|
```
|
|
138
77
|
|
|
139
|
-
From there,
|
|
78
|
+
From there, mount Etos-specific UI such as `EtosThemeSwitcherComponent` inside your existing application shell.
|
|
140
79
|
|
|
141
80
|
## Using the theme switcher
|
|
142
81
|
|
|
@@ -166,7 +105,7 @@ In this mode the trigger shows only the avatar or initials plus the standalone n
|
|
|
166
105
|
Vertical usage:
|
|
167
106
|
|
|
168
107
|
```html
|
|
169
|
-
<div
|
|
108
|
+
<div sidebar-footer class="flex h-full w-full min-w-0 items-center justify-start gap-3 px-0 py-0">
|
|
170
109
|
<etos-theme-switcher [userInfo]="profileInfo" [quickActions]="verticalQuickActions" popoverAlign="start" />
|
|
171
110
|
|
|
172
111
|
<div class="min-w-0 flex flex-col gap-px">
|
|
@@ -178,6 +117,15 @@ Vertical usage:
|
|
|
178
117
|
|
|
179
118
|
Use `popoverAlign="start"` in the vertical sidebar so the popup opens toward the content area instead of clipping against the left viewport edge.
|
|
180
119
|
|
|
120
|
+
When composing the shared navigation shell directly, use the renamed sidebar API:
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<sidebar [ariaLabel]="'Primary'">
|
|
124
|
+
<div sidebar-header>Brand</div>
|
|
125
|
+
<div sidebar-footer>Footer actions</div>
|
|
126
|
+
</sidebar>
|
|
127
|
+
```
|
|
128
|
+
|
|
181
129
|
Input shape examples:
|
|
182
130
|
|
|
183
131
|
```ts
|
|
@@ -225,10 +173,9 @@ onThemeSwitcherAction(action: string): void {
|
|
|
225
173
|
|
|
226
174
|
## Workspace usage in this repository
|
|
227
175
|
|
|
228
|
-
The Etos demo under `projects/demo/etos` already uses the short TypeScript entrypoint:
|
|
176
|
+
The Etos demo under `projects/demo/etos` already uses the short TypeScript entrypoint for provider setup:
|
|
229
177
|
|
|
230
178
|
- `src/app/app.config.ts` imports `provideEtosBrand` from `@ojiepermana/angular/etos`.
|
|
231
|
-
- `src/pages/pages.ts` imports `EtosHorizontalLayoutComponent`, `EtosVerticalLayoutComponent`, and `EtosThemeSwitcherComponent` from `@ojiepermana/angular/etos`.
|
|
232
179
|
|
|
233
180
|
For CSS, the workspace demo currently imports the Etos source stylesheet directly:
|
|
234
181
|
|
package/etos/styles/color.css
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
*/
|
|
4
4
|
@layer tokens {
|
|
5
5
|
[theme-brand='etos'] {
|
|
6
|
+
--brand: 0 0% 64%;
|
|
7
|
+
--brand-border-alpha: 0.7;
|
|
8
|
+
--brand-background-alpha: 0.7;
|
|
9
|
+
|
|
10
|
+
--background: 210 38% 98%;
|
|
11
|
+
--surface: 0 0% 89.8%;
|
|
12
|
+
--surface-foreground: 211 56% 12%;
|
|
13
|
+
--foreground: 211 56% 12%;
|
|
14
|
+
|
|
15
|
+
--card: 0 0% 100%;
|
|
16
|
+
--card-foreground: 211 56% 12%;
|
|
17
|
+
|
|
18
|
+
--popover: 0 0% 100%;
|
|
19
|
+
--popover-foreground: 211 56% 12%;
|
|
20
|
+
|
|
21
|
+
--muted: 211 34% 94%;
|
|
22
|
+
--muted-foreground: 211 24% 38%;
|
|
23
|
+
|
|
24
|
+
--border: 211 28% 82%;
|
|
25
|
+
--input: 211 28% 82%;
|
|
26
|
+
|
|
6
27
|
--primary: 211 95% 29%;
|
|
7
28
|
--primary-foreground: 0 0% 100%;
|
|
8
29
|
--accent: 211 95% 96%;
|
|
@@ -13,9 +34,40 @@
|
|
|
13
34
|
}
|
|
14
35
|
|
|
15
36
|
[data-mode='dark'][theme-brand='etos'] {
|
|
37
|
+
--brand: 0 0% 64%;
|
|
38
|
+
--brand-border-alpha: 0.45;
|
|
39
|
+
--brand-background-alpha: 0.55;
|
|
40
|
+
|
|
41
|
+
--background: 211 38% 9%;
|
|
42
|
+
--surface: 211 22% 18%;
|
|
43
|
+
--surface-foreground: 210 40% 96%;
|
|
44
|
+
--foreground: 210 40% 96%;
|
|
45
|
+
|
|
46
|
+
--card: 211 34% 11%;
|
|
47
|
+
--card-foreground: 210 40% 96%;
|
|
48
|
+
|
|
49
|
+
--popover: 211 34% 11%;
|
|
50
|
+
--popover-foreground: 210 40% 96%;
|
|
51
|
+
|
|
52
|
+
--muted: 211 22% 18%;
|
|
53
|
+
--muted-foreground: 211 18% 70%;
|
|
54
|
+
|
|
55
|
+
--border: 211 24% 24%;
|
|
56
|
+
--input: 211 24% 24%;
|
|
57
|
+
|
|
16
58
|
--accent: 211 58% 18%;
|
|
17
59
|
--accent-foreground: 211 90% 84%;
|
|
18
60
|
--secondary: 211 24% 18%;
|
|
19
61
|
--secondary-foreground: 211 82% 84%;
|
|
20
62
|
}
|
|
21
63
|
}
|
|
64
|
+
|
|
65
|
+
@layer utilities {
|
|
66
|
+
.border-brand {
|
|
67
|
+
border-color: hsl(var(--brand, var(--border)) / var(--brand-border-alpha, 0.7));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.bg-brand {
|
|
71
|
+
background-color: hsl(var(--brand, var(--border)) / var(--brand-background-alpha, 0.7));
|
|
72
|
+
}
|
|
73
|
+
}
|
package/etos/styles/layout.css
CHANGED
|
@@ -19,168 +19,3 @@
|
|
|
19
19
|
--etos-layout-frame-shadow: 0 0 0 1px hsl(var(--border));
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
@layer components {
|
|
24
|
-
.etos-layout-host {
|
|
25
|
-
display: block;
|
|
26
|
-
height: 100dvh;
|
|
27
|
-
width: 100%;
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
background: hsl(var(--background));
|
|
30
|
-
color: hsl(var(--foreground));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.etos-layout-host--fixed {
|
|
34
|
-
box-sizing: border-box;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.etos-layout-frame {
|
|
38
|
-
display: flex;
|
|
39
|
-
height: 100%;
|
|
40
|
-
width: 100%;
|
|
41
|
-
overflow: hidden;
|
|
42
|
-
background: hsl(var(--background));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.etos-layout-frame--horizontal {
|
|
46
|
-
flex-direction: column;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.etos-layout-main {
|
|
50
|
-
min-width: 0;
|
|
51
|
-
flex: 1 1 0%;
|
|
52
|
-
overflow: auto;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.etos-layout-main--fixed {
|
|
56
|
-
width: 100%;
|
|
57
|
-
max-width: var(--etos-layout-main-max-width);
|
|
58
|
-
margin-inline: auto;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.etos-layout-topbar {
|
|
62
|
-
width: 100%;
|
|
63
|
-
flex-shrink: 0;
|
|
64
|
-
border-bottom: var(--border-width) solid hsl(var(--border));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.etos-layout-topbar-slot {
|
|
68
|
-
display: flex;
|
|
69
|
-
min-width: 0;
|
|
70
|
-
align-items: center;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.etos-layout-topbar-slot--end {
|
|
74
|
-
justify-content: flex-end;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.etos-layout-empty-host {
|
|
78
|
-
display: flex;
|
|
79
|
-
min-height: 100dvh;
|
|
80
|
-
width: 100%;
|
|
81
|
-
align-items: center;
|
|
82
|
-
justify-content: center;
|
|
83
|
-
padding: var(--etos-layout-empty-padding);
|
|
84
|
-
background: hsl(var(--background));
|
|
85
|
-
color: hsl(var(--foreground));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.etos-layout-empty-main {
|
|
89
|
-
width: 100%;
|
|
90
|
-
max-width: var(--etos-layout-empty-max-width);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.etos-brand-link,
|
|
94
|
-
.etos-profile-trigger {
|
|
95
|
-
display: inline-flex;
|
|
96
|
-
align-items: center;
|
|
97
|
-
gap: 0.75rem;
|
|
98
|
-
min-height: 2.5rem;
|
|
99
|
-
padding: 0.375rem 0.5rem;
|
|
100
|
-
color: hsl(var(--foreground));
|
|
101
|
-
text-decoration: none;
|
|
102
|
-
transition:
|
|
103
|
-
color 160ms ease,
|
|
104
|
-
background-color 160ms ease;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.etos-brand-link:focus-visible,
|
|
108
|
-
.etos-profile-trigger:focus-visible {
|
|
109
|
-
outline: 2px solid hsl(var(--ring));
|
|
110
|
-
outline-offset: 2px;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.etos-brand-mark,
|
|
114
|
-
.etos-profile-mark {
|
|
115
|
-
display: inline-flex;
|
|
116
|
-
height: var(--etos-layout-brand-mark-size);
|
|
117
|
-
width: var(--etos-layout-brand-mark-size);
|
|
118
|
-
align-items: center;
|
|
119
|
-
justify-content: center;
|
|
120
|
-
border-radius: var(--radius-md);
|
|
121
|
-
background: hsl(var(--primary));
|
|
122
|
-
color: hsl(var(--primary-foreground));
|
|
123
|
-
font-size: 0.7rem;
|
|
124
|
-
font-weight: 700;
|
|
125
|
-
letter-spacing: 0.18em;
|
|
126
|
-
line-height: 1;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.etos-profile-mark {
|
|
130
|
-
border-radius: 999px;
|
|
131
|
-
letter-spacing: 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.etos-brand-copy {
|
|
135
|
-
display: none;
|
|
136
|
-
min-width: 0;
|
|
137
|
-
flex-direction: column;
|
|
138
|
-
gap: 0.125rem;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.etos-brand-name {
|
|
142
|
-
font-size: var(--text-sm);
|
|
143
|
-
font-weight: 700;
|
|
144
|
-
line-height: 1;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.etos-brand-subtitle,
|
|
148
|
-
.etos-profile-name {
|
|
149
|
-
font-size: var(--text-xs);
|
|
150
|
-
line-height: 1;
|
|
151
|
-
color: hsl(var(--muted-foreground));
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.etos-profile-name {
|
|
155
|
-
display: none;
|
|
156
|
-
font-weight: 600;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
@media (min-width: 40rem) {
|
|
160
|
-
.etos-brand-copy,
|
|
161
|
-
.etos-profile-name {
|
|
162
|
-
display: flex;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
@media (min-width: 64rem) {
|
|
167
|
-
.etos-layout-host--fixed {
|
|
168
|
-
padding: var(--etos-layout-shell-padding);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.etos-layout-frame--vertical-fixed {
|
|
172
|
-
max-width: var(--etos-layout-vertical-shell-max-width);
|
|
173
|
-
margin-inline: auto;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.etos-layout-frame--fixed {
|
|
177
|
-
border: var(--border-width) solid hsl(var(--border));
|
|
178
|
-
border-radius: var(--etos-layout-frame-radius);
|
|
179
|
-
box-shadow: var(--etos-layout-frame-shadow);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.etos-layout-main--vertical-fixed {
|
|
183
|
-
margin-inline: 0;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|