@ojiepermana/angular 0.0.2
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 +237 -0
- package/fesm2022/ojiepermana-angular-internal.mjs +58 -0
- package/fesm2022/ojiepermana-angular-internal.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-layout.mjs +471 -0
- package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-shell.mjs +14 -0
- package/fesm2022/ojiepermana-angular-shell.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-theme-component.mjs +249 -0
- package/fesm2022/ojiepermana-angular-theme-component.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-theme-directive.mjs +29 -0
- package/fesm2022/ojiepermana-angular-theme-directive.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-theme-service.mjs +243 -0
- package/fesm2022/ojiepermana-angular-theme-service.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-theme.mjs +6 -0
- package/fesm2022/ojiepermana-angular-theme.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular.mjs +6 -0
- package/fesm2022/ojiepermana-angular.mjs.map +1 -0
- package/layout/README.md +143 -0
- package/layout/styles/index.css +157 -0
- package/package.json +59 -0
- package/shell/README.md +37 -0
- package/styles/index.css +2 -0
- package/styles/resets.css +22 -0
- package/theme/README.md +382 -0
- package/theme/styles/adapters/material-ui/index.css +210 -0
- package/theme/styles/index.css +8 -0
- package/theme/styles/layout/index.css +1 -0
- package/theme/styles/modes/dark.css +84 -0
- package/theme/styles/presets/colors/blue.css +10 -0
- package/theme/styles/presets/colors/brand.css +11 -0
- package/theme/styles/presets/colors/cyan.css +10 -0
- package/theme/styles/presets/colors/green.css +10 -0
- package/theme/styles/presets/colors/index.css +7 -0
- package/theme/styles/presets/colors/orange.css +10 -0
- package/theme/styles/presets/colors/purple.css +10 -0
- package/theme/styles/presets/colors/red.css +10 -0
- package/theme/styles/presets/styles/flat.css +30 -0
- package/theme/styles/presets/styles/glass.css +34 -0
- package/theme/styles/presets/styles/index.css +2 -0
- package/theme/styles/roles/index.css +49 -0
- package/theme/styles/tokens/foundation.css +139 -0
- package/theme/styles/tokens/semantic.css +87 -0
- package/theme/styles/utilities/index.css +88 -0
- package/types/ojiepermana-angular-internal.d.ts +26 -0
- package/types/ojiepermana-angular-layout.d.ts +90 -0
- package/types/ojiepermana-angular-shell.d.ts +12 -0
- package/types/ojiepermana-angular-theme-component.d.ts +46 -0
- package/types/ojiepermana-angular-theme-directive.d.ts +10 -0
- package/types/ojiepermana-angular-theme-service.d.ts +68 -0
- package/types/ojiepermana-angular-theme.d.ts +2 -0
- package/types/ojiepermana-angular.d.ts +2 -0
package/theme/README.md
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# Theme Library
|
|
2
|
+
|
|
3
|
+
Reusable theme state, theme controls, and shared styling tokens for `@ojiepermana/angular/theme`.
|
|
4
|
+
|
|
5
|
+
Layout runtime and shell components now live in `@ojiepermana/angular/layout`.
|
|
6
|
+
|
|
7
|
+
## Package Shape
|
|
8
|
+
|
|
9
|
+
`@ojiepermana/angular/theme` is intentionally a namespace marker and exports nothing.
|
|
10
|
+
|
|
11
|
+
Import from the secondary entry points instead:
|
|
12
|
+
|
|
13
|
+
- `@ojiepermana/angular/theme/service`
|
|
14
|
+
- `@ojiepermana/angular/theme/component`
|
|
15
|
+
- `@ojiepermana/angular/theme/directive`
|
|
16
|
+
|
|
17
|
+
If you want one convenience provider that wires theme and layout together, use `@ojiepermana/angular/shell`.
|
|
18
|
+
|
|
19
|
+
Use `@ojiepermana/angular/layout` for layout state, layout controls, layout host mirroring, and shell components.
|
|
20
|
+
Use `@ojiepermana/angular/styles/index.css` for styles in consumer applications.
|
|
21
|
+
If a consumer wants the library's optional application-level reset helpers, they can additionally import `@ojiepermana/angular/styles/resets.css`.
|
|
22
|
+
|
|
23
|
+
## What This Library Owns
|
|
24
|
+
|
|
25
|
+
- Global theme state with Angular signals through `ThemeService`
|
|
26
|
+
- Theme runtime DOM contract on `document.documentElement`
|
|
27
|
+
- Standalone theme controls for scheme, color, and style
|
|
28
|
+
- Shared semantic tokens and the Angular Material adapter layer
|
|
29
|
+
- Optional theme-only host mirroring through `ThemeHostDirective`
|
|
30
|
+
|
|
31
|
+
## Styling Rules
|
|
32
|
+
|
|
33
|
+
- Semantic tokens are the visual source of truth.
|
|
34
|
+
- Angular Material acts as the behavior layer and reads from shared semantic tokens.
|
|
35
|
+
- Style presets feed a role-token layer so shell, navigation, overlay, data, and control groups can change material treatment without duplicating per-component selectors.
|
|
36
|
+
- Style presets now also own the active typeface tokens, so `flat` and `glass` can ship different font stacks while still flowing through shared runtime variables.
|
|
37
|
+
- In application code, prefer Tailwind utility classes directly in templates.
|
|
38
|
+
- In library code, shared and cross-cutting styles belong in CSS token layers, utilities, or adapters.
|
|
39
|
+
- Dark mode must resolve through the global runtime contract and shared variables, not component-local dark-mode classes.
|
|
40
|
+
- The shared bundle includes reduced-motion-aware chrome transitions so scheme, preset, and style changes feel smoother without animating structural layout geometry.
|
|
41
|
+
- The legacy `_*.css` files and the old `styles/overrides/` tree have been removed.
|
|
42
|
+
|
|
43
|
+
## Token Usage Model
|
|
44
|
+
|
|
45
|
+
Use tokens from the most specific stable layer available.
|
|
46
|
+
|
|
47
|
+
1. Raw palette tokens: `--theme-*` and `--theme-on-*`
|
|
48
|
+
Use for swatches, previews, charts, and theme-picking UI where the preset color itself must stay stable.
|
|
49
|
+
2. Semantic intent tokens: `--*-solid`, `--*-container`, and their `*-foreground` companions
|
|
50
|
+
Use for reusable application or library components that need semantic meaning without being tied to one shell role.
|
|
51
|
+
3. Role tokens: `--nav-*`, `--sidebar-*`, `--container-*`, `--overlay-*`, `--data-*`, `--control-*`
|
|
52
|
+
Use for shipped shell/layout primitives and larger component groups.
|
|
53
|
+
4. Typography tokens: `--typeface-plain`, `--typeface-brand`, `--typeface-mono`
|
|
54
|
+
Use for base body text, emphasis or heading text, and code text. The active style preset decides their concrete font stacks.
|
|
55
|
+
|
|
56
|
+
Compatibility aliases remain available:
|
|
57
|
+
|
|
58
|
+
- `--primary` maps to `--primary-solid`
|
|
59
|
+
- `--secondary` maps to `--secondary-container`
|
|
60
|
+
- `--tertiary` maps to `--tertiary-container`
|
|
61
|
+
- `--neutral` maps to `--neutral-container`
|
|
62
|
+
- `--accent` maps to `--tertiary-container`
|
|
63
|
+
- `--destructive` remains the destructive solid token
|
|
64
|
+
|
|
65
|
+
Additional semantic families are available for future system work:
|
|
66
|
+
|
|
67
|
+
- `success`
|
|
68
|
+
- `warning`
|
|
69
|
+
- `info`
|
|
70
|
+
- `disabled`
|
|
71
|
+
- `inverse`
|
|
72
|
+
|
|
73
|
+
## Runtime Contract
|
|
74
|
+
|
|
75
|
+
When `ThemeService` is active, it writes the current state to `document.documentElement`.
|
|
76
|
+
|
|
77
|
+
- `.dark` is added when the resolved scheme is dark.
|
|
78
|
+
- `style.color-scheme` is set to the resolved browser scheme.
|
|
79
|
+
- `data-theme-scheme` stores the selected scheme: `light`, `dark`, or `system`.
|
|
80
|
+
- `data-theme-color` stores the active preset color.
|
|
81
|
+
- `data-theme-style` stores the active style preset.
|
|
82
|
+
|
|
83
|
+
`ThemeHostDirective` mirrors the same theme-only contract onto any host element with `ngtThemeHost`.
|
|
84
|
+
|
|
85
|
+
## Supported Values
|
|
86
|
+
|
|
87
|
+
- `ThemeScheme`: `light`, `dark`, `system`
|
|
88
|
+
- `ThemeColor`: `brand`, `blue`, `green`, `red`, `cyan`, `purple`, `orange`
|
|
89
|
+
- `ThemeStyle`: `flat`, `glass`
|
|
90
|
+
|
|
91
|
+
## Public API
|
|
92
|
+
|
|
93
|
+
### Service Entry Point
|
|
94
|
+
|
|
95
|
+
Import from `@ojiepermana/angular/theme/service`.
|
|
96
|
+
|
|
97
|
+
- `ThemeService`
|
|
98
|
+
- `provideNgTheme`
|
|
99
|
+
- `NG_THEME_CONFIG`
|
|
100
|
+
- `ThemeScheme`
|
|
101
|
+
- `ThemeColor`
|
|
102
|
+
- `ThemeColorOption`
|
|
103
|
+
- `ThemeStyle`
|
|
104
|
+
- `NgThemeConfig`
|
|
105
|
+
|
|
106
|
+
`provideNgTheme()` currently defaults to:
|
|
107
|
+
|
|
108
|
+
- `defaultScheme: 'system'`
|
|
109
|
+
- `defaultColor: 'brand'`
|
|
110
|
+
- `defaultStyle: 'flat'`
|
|
111
|
+
|
|
112
|
+
Persistence keys are fixed by the runtime. Deprecated config fields such as `storageKey` and `storageVersion` have been removed from `NgThemeConfig`.
|
|
113
|
+
|
|
114
|
+
Use the optional `colors` config to limit the available color presets exposed by `ThemeService.colorOptions()` and `ColorPickerComponent`.
|
|
115
|
+
Use `colorLabels` to relabel the built-in color presets for localized or product-specific UI copy.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
provideNgTheme({
|
|
119
|
+
colors: ['brand', 'green'],
|
|
120
|
+
colorLabels: {
|
|
121
|
+
brand: 'Merek',
|
|
122
|
+
green: 'Hijau',
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`colorLabels` only relabels the built-in preset IDs. If you need a brand-new preset value, add the corresponding CSS token preset first and keep the runtime contract aligned with the supported `ThemeColor` union.
|
|
128
|
+
|
|
129
|
+
`ThemeService` also exposes `reset()` to clear persisted theme state and restore the configured defaults.
|
|
130
|
+
|
|
131
|
+
### Component Entry Point
|
|
132
|
+
|
|
133
|
+
Import from `@ojiepermana/angular/theme/component`.
|
|
134
|
+
|
|
135
|
+
- `StyleSwitcherComponent` with selector `style-switcher`. Toggles `flat` and `glass`.
|
|
136
|
+
- `ColorPickerComponent` with selector `color-picker`. Renders the configured preset list from `ThemeService.colorOptions()`.
|
|
137
|
+
- `SchemeSwitcherComponent` with selector `scheme-switcher`. Switches between `light`, `dark`, and `system`.
|
|
138
|
+
|
|
139
|
+
All built-in controls are standalone components with no required inputs.
|
|
140
|
+
|
|
141
|
+
## SSR Notes
|
|
142
|
+
|
|
143
|
+
- Providers can be registered on the server safely.
|
|
144
|
+
- Theme DOM writes and `localStorage` persistence remain no-op until the browser runtime is available.
|
|
145
|
+
- `system` scheme resolves from `matchMedia('(prefers-color-scheme: dark)')` only in the browser.
|
|
146
|
+
|
|
147
|
+
## Troubleshooting
|
|
148
|
+
|
|
149
|
+
- If theme changes do not appear visually, verify that `@ojiepermana/angular/styles/index.css` is actually imported by the consuming application.
|
|
150
|
+
- If a color never becomes active, make sure `defaultColor` is included in the configured `colors` list. The provider now normalizes invalid combinations back to a safe default.
|
|
151
|
+
- If consumer-facing labels need localization, use `colorLabels` instead of wrapping `ColorPickerComponent` just to rename built-in presets.
|
|
152
|
+
- If a custom design needs a new preset beyond the built-in IDs, add the CSS preset first; `colorLabels` only renames existing preset keys.
|
|
153
|
+
|
|
154
|
+
### Directive Entry Point
|
|
155
|
+
|
|
156
|
+
Import from `@ojiepermana/angular/theme/directive`.
|
|
157
|
+
|
|
158
|
+
- `ThemeHostDirective` with selector `[ngtThemeHost]`. Mirrors the current theme contract onto the host element.
|
|
159
|
+
|
|
160
|
+
## Related Layout Package
|
|
161
|
+
|
|
162
|
+
Import from `@ojiepermana/angular/layout`.
|
|
163
|
+
|
|
164
|
+
- `LayoutService`
|
|
165
|
+
- `provideNgLayout`
|
|
166
|
+
- `NG_LAYOUT_CONFIG`
|
|
167
|
+
- `LayoutMode`
|
|
168
|
+
- `LayoutContainer`
|
|
169
|
+
- `NgLayoutConfig`
|
|
170
|
+
- `LayoutHostDirective` with selector `[ngtLayoutHost]`
|
|
171
|
+
- `LayoutVerticalComponent` with selector `vertical`
|
|
172
|
+
- `LayoutHorizontalComponent` with selector `horizontal`
|
|
173
|
+
- `LayoutContainerSwitcherComponent` with selector `layout-container-switcher`
|
|
174
|
+
- `LayoutModeSwitcherComponent` with selector `layout-mode-switcher`
|
|
175
|
+
|
|
176
|
+
## Active Stylesheet Bundles
|
|
177
|
+
|
|
178
|
+
The theme stylesheet source remains `projects/library/theme/styles/index.css` inside this workspace.
|
|
179
|
+
|
|
180
|
+
It imports the current structure in this order:
|
|
181
|
+
|
|
182
|
+
- `tokens/foundation.css`
|
|
183
|
+
- `tokens/semantic.css`
|
|
184
|
+
- `modes/dark.css`
|
|
185
|
+
- `presets/colors/index.css`
|
|
186
|
+
- `presets/styles/index.css`
|
|
187
|
+
- `roles/index.css`
|
|
188
|
+
- `utilities/index.css`
|
|
189
|
+
- `adapters/material-ui/index.css`
|
|
190
|
+
|
|
191
|
+
Layout selectors now live in `projects/library/layout/styles/index.css` inside this workspace.
|
|
192
|
+
|
|
193
|
+
For applications that consume the published package, use the aggregate bundle at `projects/library/styles/index.css` in this workspace or `@ojiepermana/angular/styles/index.css` from the published package. The aggregate bundle imports theme first, then layout.
|
|
194
|
+
|
|
195
|
+
Application-level resets are intentionally opt-in. If a consumer wants them, import `projects/library/styles/resets.css` in this workspace or `@ojiepermana/angular/styles/resets.css` from the published package in addition to the aggregate bundle.
|
|
196
|
+
|
|
197
|
+
Preset coverage currently includes:
|
|
198
|
+
|
|
199
|
+
- Colors: `brand`, `blue`, `green`, `red`, `cyan`, `purple`, `orange`
|
|
200
|
+
- Styles: `flat`, `glass`
|
|
201
|
+
|
|
202
|
+
Style presets also control typography. The shared bundle maps the active style to:
|
|
203
|
+
|
|
204
|
+
- `--typeface-plain`
|
|
205
|
+
- `--typeface-brand`
|
|
206
|
+
- `--typeface-mono`
|
|
207
|
+
|
|
208
|
+
Those runtime tokens are then forwarded to Tailwind font tokens (`font-sans`, `font-display`, `font-mono`) and Angular Material typography tokens.
|
|
209
|
+
|
|
210
|
+
Consumers can override each style preset independently without changing the `ThemeStyle` union:
|
|
211
|
+
|
|
212
|
+
```css
|
|
213
|
+
:root {
|
|
214
|
+
--theme-style-flat-plain-font: 'Segoe UI', sans-serif;
|
|
215
|
+
--theme-style-flat-brand-font: 'Segoe UI', sans-serif;
|
|
216
|
+
--theme-style-glass-plain-font: 'Avenir Next', 'Helvetica Neue', sans-serif;
|
|
217
|
+
--theme-style-glass-brand-font: ui-rounded, 'Avenir Next', sans-serif;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The active color preset exposes these raw palette variables on the root contract:
|
|
222
|
+
|
|
223
|
+
- `--theme-primary`
|
|
224
|
+
- `--theme-on-primary`
|
|
225
|
+
- `--theme-secondary`
|
|
226
|
+
- `--theme-on-secondary`
|
|
227
|
+
- `--theme-tertiary`
|
|
228
|
+
- `--theme-on-tertiary`
|
|
229
|
+
- `--theme-neutral`
|
|
230
|
+
- `--theme-on-neutral`
|
|
231
|
+
|
|
232
|
+
The semantic layer maps them to `--primary`, `--secondary`, `--tertiary`, and `--neutral`.
|
|
233
|
+
`--accent` remains as a compatibility alias for `--tertiary`.
|
|
234
|
+
|
|
235
|
+
Use the raw palette pair when you need a direct preset swatch that does not change with the
|
|
236
|
+
light or dark semantic surface mapping:
|
|
237
|
+
|
|
238
|
+
```css
|
|
239
|
+
.theme-chip {
|
|
240
|
+
background: var(--theme-secondary);
|
|
241
|
+
color: var(--theme-on-secondary);
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Use `--secondary-container`, `--tertiary-container`, `--neutral-container`, or the compatibility
|
|
246
|
+
aliases `--secondary`, `--tertiary`, and `--neutral` when you need scheme-aware semantic surfaces.
|
|
247
|
+
|
|
248
|
+
For stronger emphasis, use the semantic solid tokens directly:
|
|
249
|
+
|
|
250
|
+
```css
|
|
251
|
+
.status-badge {
|
|
252
|
+
background: var(--success-solid);
|
|
253
|
+
color: var(--success-solid-foreground);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.callout {
|
|
257
|
+
background: var(--info-container);
|
|
258
|
+
color: var(--info-container-foreground);
|
|
259
|
+
border: 1px solid color-mix(in oklab, var(--info-solid) 24%, var(--border));
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Usage
|
|
264
|
+
|
|
265
|
+
### 1. Register the Providers
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
|
269
|
+
import { provideRouter } from '@angular/router';
|
|
270
|
+
import { provideNgLayout } from '@ojiepermana/angular/layout';
|
|
271
|
+
import { provideNgTheme } from '@ojiepermana/angular/theme/service';
|
|
272
|
+
|
|
273
|
+
import { routes } from './app.routes';
|
|
274
|
+
|
|
275
|
+
export const appConfig: ApplicationConfig = {
|
|
276
|
+
providers: [
|
|
277
|
+
provideBrowserGlobalErrorListeners(),
|
|
278
|
+
provideRouter(routes),
|
|
279
|
+
provideNgTheme({
|
|
280
|
+
defaultScheme: 'system',
|
|
281
|
+
defaultColor: 'brand',
|
|
282
|
+
defaultStyle: 'flat',
|
|
283
|
+
}),
|
|
284
|
+
provideNgLayout({
|
|
285
|
+
defaultMode: 'vertical',
|
|
286
|
+
defaultContainer: 'boxed',
|
|
287
|
+
}),
|
|
288
|
+
],
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### 2. Register the Shared Styles
|
|
293
|
+
|
|
294
|
+
Inside this workspace, a consuming application can wire the aggregate source bundle through its Angular build config:
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"styles": ["projects/library/styles/index.css"]
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
For a package consumer, use the published aggregate bundle instead:
|
|
303
|
+
|
|
304
|
+
```css
|
|
305
|
+
@import '@ojiepermana/angular/styles/index.css';
|
|
306
|
+
@import 'tailwindcss';
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 3. Compose a Shell and Controls
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
313
|
+
import {
|
|
314
|
+
LayoutContainerSwitcherComponent,
|
|
315
|
+
LayoutVerticalComponent,
|
|
316
|
+
} from '@ojiepermana/angular/layout';
|
|
317
|
+
import {
|
|
318
|
+
StyleSwitcherComponent,
|
|
319
|
+
ColorPickerComponent,
|
|
320
|
+
SchemeSwitcherComponent,
|
|
321
|
+
} from '@ojiepermana/angular/theme/component';
|
|
322
|
+
|
|
323
|
+
@Component({
|
|
324
|
+
selector: 'app-shell',
|
|
325
|
+
imports: [
|
|
326
|
+
StyleSwitcherComponent,
|
|
327
|
+
ColorPickerComponent,
|
|
328
|
+
LayoutContainerSwitcherComponent,
|
|
329
|
+
LayoutVerticalComponent,
|
|
330
|
+
SchemeSwitcherComponent,
|
|
331
|
+
],
|
|
332
|
+
template: `
|
|
333
|
+
<vertical>
|
|
334
|
+
<nav navigation class="flex h-full w-full flex-col gap-6 px-4 py-5">
|
|
335
|
+
<div class="flex items-center gap-1">
|
|
336
|
+
<style-switcher />
|
|
337
|
+
<layout-container-switcher />
|
|
338
|
+
<scheme-switcher />
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<color-picker />
|
|
342
|
+
</nav>
|
|
343
|
+
</vertical>
|
|
344
|
+
`,
|
|
345
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
346
|
+
})
|
|
347
|
+
export class AppShellComponent {}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 4. Mirror Theme and Layout State to a Subtree
|
|
351
|
+
|
|
352
|
+
```html
|
|
353
|
+
<section ngtThemeHost ngtLayoutHost>
|
|
354
|
+
<ng-content />
|
|
355
|
+
</section>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Persistence
|
|
359
|
+
|
|
360
|
+
Theme state is persisted in `localStorage` per axis using fixed flat keys.
|
|
361
|
+
|
|
362
|
+
The theme package owns these keys:
|
|
363
|
+
|
|
364
|
+
- `theme-scheme`
|
|
365
|
+
- `theme-color`
|
|
366
|
+
- `theme-style`
|
|
367
|
+
|
|
368
|
+
The layout package owns:
|
|
369
|
+
|
|
370
|
+
- `layout-mode`
|
|
371
|
+
- `layout-container`
|
|
372
|
+
|
|
373
|
+
Legacy `ng-theme:v2:*` entries are migrated automatically to the flat keys when they are read by their owning runtime service.
|
|
374
|
+
|
|
375
|
+
## Notes for Contributors
|
|
376
|
+
|
|
377
|
+
- Do not add exports to `@ojiepermana/angular/theme` unless the package contract changes intentionally.
|
|
378
|
+
- Keep imports domain-based through the secondary entry points.
|
|
379
|
+
- Use `@ojiepermana/angular/layout` for layout runtime, layout controls, and shell components.
|
|
380
|
+
- Prefer Tailwind utility classes in templates before adding local or shared CSS.
|
|
381
|
+
- Put shared visual decisions in semantic tokens or shared stylesheets instead of Angular Material tokens.
|
|
382
|
+
- If a new theme axis or preset is added, update the types, service validation, styles, tests, and this README together.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--mat-sys-primary: var(--primary);
|
|
3
|
+
--mat-sys-on-primary: var(--primary-foreground);
|
|
4
|
+
--mat-sys-secondary: var(--secondary-solid);
|
|
5
|
+
--mat-sys-on-secondary: var(--secondary-solid-foreground);
|
|
6
|
+
--mat-sys-tertiary: var(--tertiary-solid);
|
|
7
|
+
--mat-sys-on-tertiary: var(--tertiary-solid-foreground);
|
|
8
|
+
--mat-sys-brand-font-family: var(--typeface-brand);
|
|
9
|
+
--mat-sys-plain-font-family: var(--typeface-plain);
|
|
10
|
+
--mat-sys-body-large-font: var(--mat-sys-plain-font-family);
|
|
11
|
+
--mat-sys-body-medium-font: var(--mat-sys-plain-font-family);
|
|
12
|
+
--mat-sys-body-small-font: var(--mat-sys-plain-font-family);
|
|
13
|
+
--mat-sys-label-large-font: var(--mat-sys-plain-font-family);
|
|
14
|
+
--mat-sys-label-medium-font: var(--mat-sys-plain-font-family);
|
|
15
|
+
--mat-sys-label-small-font: var(--mat-sys-plain-font-family);
|
|
16
|
+
--mat-sys-title-large-font: var(--mat-sys-brand-font-family);
|
|
17
|
+
--mat-sys-title-medium-font: var(--mat-sys-plain-font-family);
|
|
18
|
+
--mat-sys-title-small-font: var(--mat-sys-plain-font-family);
|
|
19
|
+
--mat-sys-headline-large-font: var(--mat-sys-brand-font-family);
|
|
20
|
+
--mat-sys-headline-medium-font: var(--mat-sys-brand-font-family);
|
|
21
|
+
--mat-sys-headline-small-font: var(--mat-sys-brand-font-family);
|
|
22
|
+
--mat-sys-display-large-font: var(--mat-sys-brand-font-family);
|
|
23
|
+
--mat-sys-display-medium-font: var(--mat-sys-brand-font-family);
|
|
24
|
+
--mat-sys-display-small-font: var(--mat-sys-brand-font-family);
|
|
25
|
+
--mat-sys-background: var(--background);
|
|
26
|
+
--mat-sys-on-background: var(--foreground);
|
|
27
|
+
--mat-sys-surface: var(--container-surface);
|
|
28
|
+
--mat-sys-on-surface: var(--container-foreground);
|
|
29
|
+
--mat-sys-surface-container: var(--overlay-surface);
|
|
30
|
+
--mat-sys-surface-container-high: var(--overlay-surface);
|
|
31
|
+
--mat-sys-surface-container-highest: color-mix(
|
|
32
|
+
in oklab,
|
|
33
|
+
var(--overlay-surface) 90%,
|
|
34
|
+
var(--muted)
|
|
35
|
+
);
|
|
36
|
+
--mat-sys-surface-variant: var(--data-header-surface);
|
|
37
|
+
--mat-sys-on-surface-variant: var(--data-header-foreground);
|
|
38
|
+
--mat-sys-inverse-surface: var(--inverse);
|
|
39
|
+
--mat-sys-inverse-on-surface: var(--inverse-foreground);
|
|
40
|
+
--mat-sys-outline: var(--container-border);
|
|
41
|
+
--mat-sys-outline-variant: var(--data-border);
|
|
42
|
+
--mat-sys-error: var(--destructive);
|
|
43
|
+
--mat-sys-on-error: var(--destructive-foreground);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.mat-mdc-icon-button.ngt-icon-button {
|
|
47
|
+
inline-size: 2.5rem;
|
|
48
|
+
block-size: 2.5rem;
|
|
49
|
+
padding: 0.625rem;
|
|
50
|
+
font-family: var(--mat-sys-plain-font-family);
|
|
51
|
+
border: 1px solid var(--control-border);
|
|
52
|
+
border-radius: var(--radius-md);
|
|
53
|
+
background: var(--control-surface);
|
|
54
|
+
color: var(--control-foreground);
|
|
55
|
+
box-shadow: var(--control-shadow);
|
|
56
|
+
backdrop-filter: var(--control-backdrop);
|
|
57
|
+
-webkit-backdrop-filter: var(--control-backdrop);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.mat-mdc-icon-button.ngt-icon-button:hover {
|
|
61
|
+
background: var(--control-hover-surface);
|
|
62
|
+
color: var(--control-hover-foreground);
|
|
63
|
+
transform: translateY(-1px);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.mat-mdc-icon-button.ngt-icon-button[aria-pressed='true'] {
|
|
67
|
+
border-color: color-mix(in oklab, var(--control-focus-ring) 48%, var(--control-border));
|
|
68
|
+
background: var(--control-active-surface);
|
|
69
|
+
color: var(--control-active-foreground);
|
|
70
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--control-focus-ring) 42%, transparent);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.mat-mdc-icon-button.ngt-icon-button:focus-visible {
|
|
74
|
+
outline: 2px solid var(--control-focus-ring);
|
|
75
|
+
outline-offset: 2px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.mat-mdc-menu-panel,
|
|
79
|
+
.mat-mdc-select-panel,
|
|
80
|
+
.mat-datepicker-content,
|
|
81
|
+
.mat-mdc-dialog-surface {
|
|
82
|
+
border: 1px solid var(--overlay-border);
|
|
83
|
+
border-radius: var(--radius-lg);
|
|
84
|
+
background: var(--overlay-surface);
|
|
85
|
+
color: var(--overlay-foreground);
|
|
86
|
+
box-shadow: var(--overlay-shadow);
|
|
87
|
+
backdrop-filter: var(--overlay-backdrop);
|
|
88
|
+
-webkit-backdrop-filter: var(--overlay-backdrop);
|
|
89
|
+
transition: var(--ngt-chrome-transition);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.mat-mdc-menu-content {
|
|
93
|
+
padding: 0.375rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.mat-mdc-menu-item {
|
|
97
|
+
min-block-size: 2.5rem;
|
|
98
|
+
border-radius: var(--radius-md);
|
|
99
|
+
color: inherit;
|
|
100
|
+
transition:
|
|
101
|
+
background-color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard),
|
|
102
|
+
color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.mat-mdc-menu-item .lucide {
|
|
106
|
+
inline-size: 1rem;
|
|
107
|
+
block-size: 1rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.mat-mdc-menu-item:hover,
|
|
111
|
+
.mat-mdc-menu-item.cdk-program-focused,
|
|
112
|
+
.mat-mdc-menu-item.cdk-keyboard-focused {
|
|
113
|
+
background: var(--tertiary-container);
|
|
114
|
+
color: var(--tertiary-container-foreground);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mat-mdc-menu-item[aria-checked='true'] {
|
|
118
|
+
background: var(--secondary-container);
|
|
119
|
+
color: var(--secondary-container-foreground);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.mat-mdc-tooltip-surface,
|
|
123
|
+
.mat-mdc-snack-bar-container .mdc-snackbar__surface {
|
|
124
|
+
border: 1px solid var(--overlay-border);
|
|
125
|
+
border-radius: var(--radius-md);
|
|
126
|
+
background: var(--overlay-surface);
|
|
127
|
+
color: var(--overlay-foreground);
|
|
128
|
+
box-shadow: var(--overlay-shadow);
|
|
129
|
+
backdrop-filter: var(--overlay-backdrop);
|
|
130
|
+
-webkit-backdrop-filter: var(--overlay-backdrop);
|
|
131
|
+
transition: var(--ngt-chrome-transition);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.mat-mdc-card,
|
|
135
|
+
.mat-expansion-panel,
|
|
136
|
+
.mat-drawer,
|
|
137
|
+
.mat-tree {
|
|
138
|
+
background: var(--container-surface);
|
|
139
|
+
color: var(--container-foreground);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.mat-mdc-card,
|
|
143
|
+
.mat-expansion-panel,
|
|
144
|
+
.mat-drawer,
|
|
145
|
+
.mat-tree {
|
|
146
|
+
border: 1px solid var(--container-border);
|
|
147
|
+
border-radius: var(--radius-lg);
|
|
148
|
+
box-shadow: var(--container-shadow);
|
|
149
|
+
transition: var(--ngt-shell-transition);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.mat-mdc-table {
|
|
153
|
+
background: var(--data-surface);
|
|
154
|
+
color: var(--data-foreground);
|
|
155
|
+
transition: var(--ngt-chrome-transition);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.mat-toolbar {
|
|
159
|
+
background: var(--nav-surface);
|
|
160
|
+
color: var(--nav-foreground);
|
|
161
|
+
transition: var(--ngt-chrome-transition);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.mat-mdc-header-row {
|
|
165
|
+
background: var(--data-header-surface);
|
|
166
|
+
color: var(--data-header-foreground);
|
|
167
|
+
transition: var(--ngt-chrome-transition);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.mat-mdc-row:hover {
|
|
171
|
+
background: var(--data-row-hover-surface);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.mat-mdc-header-row,
|
|
175
|
+
.mat-mdc-row,
|
|
176
|
+
.mat-mdc-paginator,
|
|
177
|
+
.mat-divider,
|
|
178
|
+
.mat-drawer,
|
|
179
|
+
.mat-expansion-panel-header {
|
|
180
|
+
border-color: var(--data-border);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.mat-mdc-row,
|
|
184
|
+
.mat-mdc-paginator,
|
|
185
|
+
.mat-divider,
|
|
186
|
+
.mat-expansion-panel-header,
|
|
187
|
+
.mat-mdc-form-field .mat-mdc-text-field-wrapper,
|
|
188
|
+
.mat-mdc-form-field .mat-mdc-floating-label,
|
|
189
|
+
.mat-mdc-select-trigger,
|
|
190
|
+
.mat-mdc-chip,
|
|
191
|
+
.mat-mdc-tab,
|
|
192
|
+
.mat-mdc-slide-toggle {
|
|
193
|
+
transition: var(--ngt-chrome-transition);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.mat-mdc-unelevated-button,
|
|
197
|
+
.mat-mdc-raised-button,
|
|
198
|
+
.mat-mdc-fab,
|
|
199
|
+
.mat-mdc-mini-fab {
|
|
200
|
+
border-radius: var(--radius-md);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.mat-mdc-form-field .mat-mdc-text-field-wrapper,
|
|
204
|
+
.mat-mdc-form-field .mat-mdc-floating-label,
|
|
205
|
+
.mat-mdc-select-trigger,
|
|
206
|
+
.mat-mdc-chip,
|
|
207
|
+
.mat-mdc-tab,
|
|
208
|
+
.mat-mdc-slide-toggle {
|
|
209
|
+
color: inherit;
|
|
210
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
@import './tokens/foundation.css';
|
|
2
|
+
@import './tokens/semantic.css';
|
|
3
|
+
@import './modes/dark.css';
|
|
4
|
+
@import './presets/colors/index.css';
|
|
5
|
+
@import './presets/styles/index.css';
|
|
6
|
+
@import './roles/index.css';
|
|
7
|
+
@import './utilities/index.css';
|
|
8
|
+
@import './adapters/material-ui/index.css';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import '../../../layout/styles/index.css';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
.dark {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
--background: oklch(0.19 0.014 286.1);
|
|
4
|
+
--foreground: oklch(0.966 0.003 286.3);
|
|
5
|
+
--card: oklch(0.236 0.013 286.3);
|
|
6
|
+
--card-foreground: var(--foreground);
|
|
7
|
+
--popover: oklch(0.245 0.013 286.2);
|
|
8
|
+
--popover-foreground: var(--foreground);
|
|
9
|
+
--primary-solid: color-mix(in oklab, var(--theme-primary) 86%, white 14%);
|
|
10
|
+
--primary-solid-foreground: oklch(0.19 0.014 286.1);
|
|
11
|
+
--primary-container: color-mix(in oklab, var(--primary-solid) 22%, var(--background));
|
|
12
|
+
--primary-container-foreground: var(--foreground);
|
|
13
|
+
--primary: var(--primary-solid);
|
|
14
|
+
--primary-foreground: var(--primary-solid-foreground);
|
|
15
|
+
--secondary-solid: color-mix(in oklab, var(--theme-secondary) 84%, white 16%);
|
|
16
|
+
--secondary-solid-foreground: oklch(0.19 0.014 286.1);
|
|
17
|
+
--secondary-container: color-mix(in oklab, var(--secondary-solid) 16%, var(--background));
|
|
18
|
+
--secondary-container-foreground: var(--foreground);
|
|
19
|
+
--secondary: var(--secondary-container);
|
|
20
|
+
--secondary-foreground: var(--secondary-container-foreground);
|
|
21
|
+
--tertiary-solid: color-mix(in oklab, var(--theme-tertiary) 84%, white 16%);
|
|
22
|
+
--tertiary-solid-foreground: oklch(0.19 0.014 286.1);
|
|
23
|
+
--tertiary-container: color-mix(in oklab, var(--tertiary-solid) 20%, var(--background));
|
|
24
|
+
--tertiary-container-foreground: var(--foreground);
|
|
25
|
+
--tertiary: var(--tertiary-container);
|
|
26
|
+
--tertiary-foreground: var(--tertiary-container-foreground);
|
|
27
|
+
--neutral-solid: color-mix(in oklab, var(--theme-neutral) 78%, white 22%);
|
|
28
|
+
--neutral-solid-foreground: oklch(0.19 0.014 286.1);
|
|
29
|
+
--neutral-container: color-mix(in oklab, var(--neutral-solid) 26%, var(--background));
|
|
30
|
+
--neutral-container-foreground: var(--foreground);
|
|
31
|
+
--neutral: var(--neutral-container);
|
|
32
|
+
--neutral-foreground: var(--neutral-container-foreground);
|
|
33
|
+
--muted: oklch(0.28 0.012 286.4);
|
|
34
|
+
--muted-foreground: oklch(0.74 0.01 286.4);
|
|
35
|
+
--accent: var(--tertiary-container);
|
|
36
|
+
--accent-foreground: var(--tertiary-container-foreground);
|
|
37
|
+
--destructive-solid: color-mix(in oklab, oklch(0.637 0.237 25.5) 86%, white 14%);
|
|
38
|
+
--destructive-solid-foreground: oklch(0.19 0.014 286.1);
|
|
39
|
+
--destructive-container: color-mix(in oklab, var(--destructive-solid) 18%, var(--background));
|
|
40
|
+
--destructive-container-foreground: var(--foreground);
|
|
41
|
+
--destructive: var(--destructive-solid);
|
|
42
|
+
--destructive-foreground: var(--destructive-solid-foreground);
|
|
43
|
+
--success-solid: color-mix(in oklab, oklch(0.673 0.152 151.5) 84%, white 16%);
|
|
44
|
+
--success-solid-foreground: oklch(0.19 0.014 286.1);
|
|
45
|
+
--success-container: color-mix(in oklab, var(--success-solid) 18%, var(--background));
|
|
46
|
+
--success-container-foreground: var(--foreground);
|
|
47
|
+
--success: var(--success-container);
|
|
48
|
+
--success-foreground: var(--success-container-foreground);
|
|
49
|
+
--warning-solid: color-mix(in oklab, oklch(0.796 0.136 82.4) 82%, white 18%);
|
|
50
|
+
--warning-solid-foreground: oklch(0.19 0.014 286.1);
|
|
51
|
+
--warning-container: color-mix(in oklab, var(--warning-solid) 20%, var(--background));
|
|
52
|
+
--warning-container-foreground: var(--foreground);
|
|
53
|
+
--warning: var(--warning-container);
|
|
54
|
+
--warning-foreground: var(--warning-container-foreground);
|
|
55
|
+
--info-solid: color-mix(in oklab, oklch(0.69 0.116 239.4) 84%, white 16%);
|
|
56
|
+
--info-solid-foreground: oklch(0.19 0.014 286.1);
|
|
57
|
+
--info-container: color-mix(in oklab, var(--info-solid) 18%, var(--background));
|
|
58
|
+
--info-container-foreground: var(--foreground);
|
|
59
|
+
--info: var(--info-container);
|
|
60
|
+
--info-foreground: var(--info-container-foreground);
|
|
61
|
+
--disabled: color-mix(in oklab, var(--neutral-solid) 18%, var(--background));
|
|
62
|
+
--disabled-foreground: color-mix(in oklab, var(--foreground) 52%, var(--background));
|
|
63
|
+
--disabled-border: color-mix(in oklab, var(--border) 84%, var(--background));
|
|
64
|
+
--inverse: var(--foreground);
|
|
65
|
+
--inverse-foreground: var(--background);
|
|
66
|
+
--inverse-border: color-mix(in oklab, var(--inverse) 84%, var(--inverse-foreground));
|
|
67
|
+
--border: oklch(1 0 0 / 0.12);
|
|
68
|
+
--input: oklch(1 0 0 / 0.16);
|
|
69
|
+
--ring: color-mix(in oklab, var(--primary-solid) 78%, white 22%);
|
|
70
|
+
--sidebar: oklch(0.214 0.014 286.2);
|
|
71
|
+
--sidebar-foreground: var(--foreground);
|
|
72
|
+
--sidebar-primary: var(--primary);
|
|
73
|
+
--sidebar-primary-foreground: var(--primary-foreground);
|
|
74
|
+
--sidebar-accent: color-mix(in oklab, var(--tertiary-solid) 16%, var(--sidebar));
|
|
75
|
+
--sidebar-accent-foreground: var(--sidebar-foreground);
|
|
76
|
+
--sidebar-border: var(--border);
|
|
77
|
+
--sidebar-ring: var(--ring);
|
|
78
|
+
/* Shell surfaces continue to derive from the active style preset and semantic card tokens. */
|
|
79
|
+
--shell-shadow: var(--shadow-sm);
|
|
80
|
+
--surface-elevated: oklch(0.262 0.012 286.3);
|
|
81
|
+
--surface-elevated-foreground: var(--foreground);
|
|
82
|
+
--surface-elevated-border: var(--border);
|
|
83
|
+
--surface-elevated-shadow: var(--shadow-md);
|
|
84
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
[data-theme-color='blue'] {
|
|
2
|
+
--theme-primary: oklch(0.58 0.16 248.8);
|
|
3
|
+
--theme-on-primary: oklch(0.985 0 0);
|
|
4
|
+
--theme-secondary: oklch(0.647 0.122 251.04);
|
|
5
|
+
--theme-on-secondary: oklch(0.205 0.012 285.9);
|
|
6
|
+
--theme-tertiary: oklch(0.715 0.085 253.037);
|
|
7
|
+
--theme-on-tertiary: oklch(0.205 0.012 285.9);
|
|
8
|
+
--theme-neutral: oklch(0.735 0.031 260.347);
|
|
9
|
+
--theme-on-neutral: oklch(0.205 0.012 285.9);
|
|
10
|
+
}
|