@ojiepermana/angular-theme 22.0.41 → 22.0.43
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/fesm2022/ojiepermana-angular-theme-layout-types.mjs +10 -1
- package/fesm2022/ojiepermana-angular-theme-layout.mjs +112 -52
- package/layout/README.md +20 -17
- package/package.json +3 -3
- package/styles/css/base/components.css +212 -0
- package/styles/css/base/theme.css +91 -3
- package/styles/css/base/tokens.css +50 -8
- package/styles/css/space/index.css +6 -3
- package/types/ojiepermana-angular-theme-layout-services.d.ts +1 -1
- package/types/ojiepermana-angular-theme-layout-types.d.ts +1 -1
- package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +1 -1
- package/types/ojiepermana-angular-theme-layout.d.ts +3 -2
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
const LAYOUT_TYPES = ['vertical', 'horizontal', 'empty', 'fluid'];
|
|
2
|
-
const LAYOUT_SURFACES = [
|
|
2
|
+
const LAYOUT_SURFACES = [
|
|
3
|
+
'flat',
|
|
4
|
+
'grid',
|
|
5
|
+
'grid-line',
|
|
6
|
+
'honeycomb',
|
|
7
|
+
'matrix',
|
|
8
|
+
'circuit',
|
|
9
|
+
'line-vertical',
|
|
10
|
+
'line-horizontal',
|
|
11
|
+
];
|
|
3
12
|
const LAYOUT_APPEARANCES = ['flat', 'border-rail'];
|
|
4
13
|
const LAYOUT_WIDTHS = ['full', 'wide', 'container', 'fluid'];
|
|
5
14
|
const LAYOUT_DEFAULT_SURFACE = 'flat';
|
|
@@ -118,6 +118,11 @@ class LayoutComponent {
|
|
|
118
118
|
...(ngDevMode ? [{ debugName: "isFluidFrame" }] : /* istanbul ignore next */ []));
|
|
119
119
|
isFullFlat = computed(() => this.resolvedWidth() === 'full' && !this.isBorderRail(), /* @ts-ignore */
|
|
120
120
|
...(ngDevMode ? [{ debugName: "isFullFlat" }] : /* istanbul ignore next */ []));
|
|
121
|
+
// The `grid-line` surface forces square frame corners (like `border-rail`) so
|
|
122
|
+
// the mosaic grid runs cleanly to the edges instead of being clipped by the
|
|
123
|
+
// theme-radius curve.
|
|
124
|
+
isGridLineSurface = computed(() => this.resolvedSurface() === 'grid-line', /* @ts-ignore */
|
|
125
|
+
...(ngDevMode ? [{ debugName: "isGridLineSurface" }] : /* istanbul ignore next */ []));
|
|
121
126
|
showsInsetRails = computed(() => {
|
|
122
127
|
const layoutType = this.resolvedType();
|
|
123
128
|
return this.isBorderRail() && (layoutType === 'horizontal' || layoutType === 'vertical');
|
|
@@ -131,15 +136,35 @@ class LayoutComponent {
|
|
|
131
136
|
...(ngDevMode ? [{ debugName: "contentShellClasses" }] : /* istanbul ignore next */ []));
|
|
132
137
|
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 */
|
|
133
138
|
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
134
|
-
frameClasses = computed(() =>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
frameClasses = computed(() => {
|
|
140
|
+
const gridLine = this.isGridLineSurface();
|
|
141
|
+
return cn('relative min-h-0 min-w-0 bg-background/55 backdrop-blur-xs', this.frameSizeClasses(),
|
|
142
|
+
// Frame border color:
|
|
143
|
+
// • border-rail → the rail color var (--layout-rail-color / -opacity), so the
|
|
144
|
+
// 1.5px frame border matches the rail lines. Defaults resolve to --border
|
|
145
|
+
// at full opacity (unchanged for most surfaces); the `grid-line` host
|
|
146
|
+
// raises them to the accent (see [data-surface='grid-line'] in
|
|
147
|
+
// base/components.css), so grid-line's rails read brighter + theme-tinted.
|
|
148
|
+
// • grid-line flat → the accent at --layout-grid-line-border-opacity (~0.666).
|
|
149
|
+
// • everything else → --border.
|
|
150
|
+
this.isBorderRail()
|
|
151
|
+
? 'border-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]'
|
|
152
|
+
: gridLine
|
|
153
|
+
? 'border-[hsl(var(--accent-foreground)/var(--layout-grid-line-border-opacity))]'
|
|
154
|
+
: 'border-border',
|
|
155
|
+
// flat: the outer frame rounds with the active theme-radius
|
|
156
|
+
// (--layout-frame-radius → --radius-lg → --radius-base). border-rail keeps
|
|
157
|
+
// square corners for its grid-rail aesthetic. `grid-line` is always a clearly
|
|
158
|
+
// bordered square box (rounded-none + a visible border in every width) so the
|
|
159
|
+
// mosaic reads as a framed panel.
|
|
160
|
+
this.isBorderRail()
|
|
161
|
+
? 'overflow-visible border-[length:var(--layout-rail-width)]'
|
|
162
|
+
: gridLine
|
|
163
|
+
? 'overflow-hidden border rounded-none'
|
|
164
|
+
: this.isFullFlat()
|
|
165
|
+
? 'overflow-hidden'
|
|
166
|
+
: 'overflow-hidden border rounded-[var(--layout-frame-radius)]');
|
|
167
|
+
}, /* @ts-ignore */
|
|
143
168
|
...(ngDevMode ? [{ debugName: "frameClasses" }] : /* istanbul ignore next */ []));
|
|
144
169
|
frameLayerClasses = computed(() => cn('col-start-1 row-start-1', this.frameClasses()), /* @ts-ignore */
|
|
145
170
|
...(ngDevMode ? [{ debugName: "frameLayerClasses" }] : /* istanbul ignore next */ []));
|
|
@@ -178,9 +203,44 @@ class LayoutComponent {
|
|
|
178
203
|
surfaceClasses() {
|
|
179
204
|
switch (this.resolvedSurface()) {
|
|
180
205
|
case 'grid':
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
206
|
+
// `grid`: two-axis 1px gradient. The line color is --layout-grid-color,
|
|
207
|
+
// which follows the accent (hue from --accent-foreground at the grid's
|
|
208
|
+
// pinned lightness) where CSS relative color is supported, else falls back
|
|
209
|
+
// to the neutral --layout-grid-line — both at --layout-grid-line-opacity
|
|
210
|
+
// (see base/theme.css). So the grid stays as faint as before but tints with
|
|
211
|
+
// the theme-color.
|
|
212
|
+
return '[--layout-grid-size:2rem] bg-background bg-[linear-gradient(var(--layout-grid-color)_1px,transparent_1px),linear-gradient(to_right,var(--layout-grid-color)_1px,transparent_1px)] bg-position-[center_center] bg-size-[var(--layout-grid-size)_var(--layout-grid-size)]';
|
|
213
|
+
case 'grid-line':
|
|
214
|
+
// `grid-line`: a richer "mosaic" cousin of `grid`, painted by the
|
|
215
|
+
// `.layout-surface-grid-line` mask layer (base/components.css). One mask
|
|
216
|
+
// carries the faint uniform grid PLUS scattered bright highlight squares
|
|
217
|
+
// and a few subtly-lit cells, so the layers stay pixel-aligned. The glow
|
|
218
|
+
// FOLLOWS THE ACCENT (accent hue from --accent-foreground, lightness pinned
|
|
219
|
+
// to --layout-grid-highlight-l so brightness stays put — grayscale in the
|
|
220
|
+
// base theme, tinted under a color theme), like the frame border.
|
|
221
|
+
return 'bg-background layout-surface-grid-line';
|
|
222
|
+
case 'honeycomb':
|
|
223
|
+
// True honeycomb: tileable hexagon outline painted by the
|
|
224
|
+
// `.layout-surface-honeycomb` mask layer (base/components.css), so it
|
|
225
|
+
// stays token-colored across themes. `bg-background` is the base.
|
|
226
|
+
return 'bg-background layout-surface-honeycomb';
|
|
227
|
+
case 'matrix':
|
|
228
|
+
// `matrix`: a scattered binary (0/1) field painted by the
|
|
229
|
+
// `.layout-surface-matrix` mask layer (base/components.css). Unlike
|
|
230
|
+
// the neutral grid surfaces, the glyphs are tinted with the brand
|
|
231
|
+
// `--primary` accent and carry baked-in per-glyph opacity, so the field
|
|
232
|
+
// reads as a soft "digital" signature that recolors with the theme.
|
|
233
|
+
return 'bg-background layout-surface-matrix';
|
|
234
|
+
case 'circuit':
|
|
235
|
+
// `circuit`: a tileable PCB / circuit-board texture — routed traces with
|
|
236
|
+
// 45° bends, via nodes, and concentric ring pads. Painted by the
|
|
237
|
+
// `.layout-surface-circuit` class (base/components.css) as TWO stacked,
|
|
238
|
+
// pixel-aligned mask layers (a single mask only carries alpha, so two
|
|
239
|
+
// colors need two layers): `::before` strokes the neutral copper traces
|
|
240
|
+
// (`--layout-grid-line`) and `::after` paints the via nodes/pads in the
|
|
241
|
+
// brand `--primary` accent — so the board is grayscale but its nodes glow
|
|
242
|
+
// with the theme. Both recolor across themes + dark mode.
|
|
243
|
+
return 'bg-background layout-surface-circuit';
|
|
184
244
|
case 'line-vertical':
|
|
185
245
|
return 'bg-background bg-[linear-gradient(to_right,hsl(var(--layout-grid-line)/var(--layout-grid-dot-opacity))_1px,transparent_1px)] bg-position-[center_center] bg-size-[2rem_2rem]';
|
|
186
246
|
case 'line-horizontal':
|
|
@@ -225,86 +285,86 @@ class LayoutComponent {
|
|
|
225
285
|
<div data-layout-rail-anchor [class]="railAnchorClasses()">
|
|
226
286
|
<div
|
|
227
287
|
data-layout-rail-top-left-horizontal
|
|
228
|
-
class="absolute top-0 right-full h-[
|
|
288
|
+
class="absolute top-0 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
229
289
|
></div>
|
|
230
290
|
<div
|
|
231
291
|
data-layout-rail-top-left-vertical
|
|
232
|
-
class="absolute bottom-full left-0 h-[calc((100dvh-100%)/2)] w-[
|
|
292
|
+
class="absolute bottom-full left-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
233
293
|
></div>
|
|
234
294
|
<div
|
|
235
295
|
data-layout-rail-top-right-horizontal
|
|
236
|
-
class="absolute top-0 left-full h-[
|
|
296
|
+
class="absolute top-0 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
237
297
|
></div>
|
|
238
298
|
<div
|
|
239
299
|
data-layout-rail-top-right-vertical
|
|
240
|
-
class="absolute bottom-full right-0 h-[calc((100dvh-100%)/2)] w-[
|
|
300
|
+
class="absolute bottom-full right-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
241
301
|
></div>
|
|
242
302
|
<div
|
|
243
303
|
data-layout-rail-bottom-left-horizontal
|
|
244
|
-
class="absolute bottom-0 right-full h-[
|
|
304
|
+
class="absolute bottom-0 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
245
305
|
></div>
|
|
246
306
|
<div
|
|
247
307
|
data-layout-rail-bottom-left-vertical
|
|
248
|
-
class="absolute top-full left-0 h-[calc((100dvh-100%)/2)] w-[
|
|
308
|
+
class="absolute top-full left-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
249
309
|
></div>
|
|
250
310
|
<div
|
|
251
311
|
data-layout-rail-bottom-right-horizontal
|
|
252
|
-
class="absolute bottom-0 left-full h-[
|
|
312
|
+
class="absolute bottom-0 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
253
313
|
></div>
|
|
254
314
|
<div
|
|
255
315
|
data-layout-rail-bottom-right-vertical
|
|
256
|
-
class="absolute top-full right-0 h-[calc((100dvh-100%)/2)] w-[
|
|
316
|
+
class="absolute top-full right-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
257
317
|
></div>
|
|
258
318
|
|
|
259
319
|
@if (showsInsetRails()) {
|
|
260
320
|
<div
|
|
261
321
|
data-layout-horizontal-top-rail
|
|
262
|
-
class="absolute inset-x-0 top-12 h-[
|
|
322
|
+
class="absolute inset-x-0 top-12 h-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
263
323
|
></div>
|
|
264
324
|
<div
|
|
265
325
|
data-layout-horizontal-top-left-extension
|
|
266
|
-
class="absolute top-12 right-full h-[
|
|
326
|
+
class="absolute top-12 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
267
327
|
></div>
|
|
268
328
|
<div
|
|
269
329
|
data-layout-horizontal-top-right-extension
|
|
270
|
-
class="absolute top-12 left-full h-[
|
|
330
|
+
class="absolute top-12 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
271
331
|
></div>
|
|
272
332
|
<div
|
|
273
333
|
data-layout-horizontal-bottom-rail
|
|
274
|
-
class="absolute inset-x-0 bottom-12 h-[
|
|
334
|
+
class="absolute inset-x-0 bottom-12 h-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
275
335
|
></div>
|
|
276
336
|
<div
|
|
277
337
|
data-layout-horizontal-bottom-left-extension
|
|
278
|
-
class="absolute bottom-12 right-full h-[
|
|
338
|
+
class="absolute bottom-12 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
279
339
|
></div>
|
|
280
340
|
<div
|
|
281
341
|
data-layout-horizontal-bottom-right-extension
|
|
282
|
-
class="absolute bottom-12 left-full h-[
|
|
342
|
+
class="absolute bottom-12 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
283
343
|
></div>
|
|
284
344
|
|
|
285
345
|
<div
|
|
286
346
|
data-layout-vertical-left-rail
|
|
287
|
-
class="absolute inset-y-0 -left-4 w-[
|
|
347
|
+
class="absolute inset-y-0 -left-4 w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
288
348
|
></div>
|
|
289
349
|
<div
|
|
290
350
|
data-layout-vertical-left-top-extension
|
|
291
|
-
class="absolute bottom-full -left-4 h-[calc((100dvh-100%)/2)] w-[
|
|
351
|
+
class="absolute bottom-full -left-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
292
352
|
></div>
|
|
293
353
|
<div
|
|
294
354
|
data-layout-vertical-left-bottom-extension
|
|
295
|
-
class="absolute top-full -left-4 h-[calc((100dvh-100%)/2)] w-[
|
|
355
|
+
class="absolute top-full -left-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
296
356
|
></div>
|
|
297
357
|
<div
|
|
298
358
|
data-layout-vertical-right-rail
|
|
299
|
-
class="absolute inset-y-0 -right-4 w-[
|
|
359
|
+
class="absolute inset-y-0 -right-4 w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
300
360
|
></div>
|
|
301
361
|
<div
|
|
302
362
|
data-layout-vertical-right-top-extension
|
|
303
|
-
class="absolute bottom-full -right-4 h-[calc((100dvh-100%)/2)] w-[
|
|
363
|
+
class="absolute bottom-full -right-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
304
364
|
></div>
|
|
305
365
|
<div
|
|
306
366
|
data-layout-vertical-right-bottom-extension
|
|
307
|
-
class="absolute top-full -right-4 h-[calc((100dvh-100%)/2)] w-[
|
|
367
|
+
class="absolute top-full -right-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
308
368
|
></div>
|
|
309
369
|
}
|
|
310
370
|
</div>
|
|
@@ -345,86 +405,86 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
|
|
|
345
405
|
<div data-layout-rail-anchor [class]="railAnchorClasses()">
|
|
346
406
|
<div
|
|
347
407
|
data-layout-rail-top-left-horizontal
|
|
348
|
-
class="absolute top-0 right-full h-[
|
|
408
|
+
class="absolute top-0 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
349
409
|
></div>
|
|
350
410
|
<div
|
|
351
411
|
data-layout-rail-top-left-vertical
|
|
352
|
-
class="absolute bottom-full left-0 h-[calc((100dvh-100%)/2)] w-[
|
|
412
|
+
class="absolute bottom-full left-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
353
413
|
></div>
|
|
354
414
|
<div
|
|
355
415
|
data-layout-rail-top-right-horizontal
|
|
356
|
-
class="absolute top-0 left-full h-[
|
|
416
|
+
class="absolute top-0 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
357
417
|
></div>
|
|
358
418
|
<div
|
|
359
419
|
data-layout-rail-top-right-vertical
|
|
360
|
-
class="absolute bottom-full right-0 h-[calc((100dvh-100%)/2)] w-[
|
|
420
|
+
class="absolute bottom-full right-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
361
421
|
></div>
|
|
362
422
|
<div
|
|
363
423
|
data-layout-rail-bottom-left-horizontal
|
|
364
|
-
class="absolute bottom-0 right-full h-[
|
|
424
|
+
class="absolute bottom-0 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
365
425
|
></div>
|
|
366
426
|
<div
|
|
367
427
|
data-layout-rail-bottom-left-vertical
|
|
368
|
-
class="absolute top-full left-0 h-[calc((100dvh-100%)/2)] w-[
|
|
428
|
+
class="absolute top-full left-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
369
429
|
></div>
|
|
370
430
|
<div
|
|
371
431
|
data-layout-rail-bottom-right-horizontal
|
|
372
|
-
class="absolute bottom-0 left-full h-[
|
|
432
|
+
class="absolute bottom-0 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
373
433
|
></div>
|
|
374
434
|
<div
|
|
375
435
|
data-layout-rail-bottom-right-vertical
|
|
376
|
-
class="absolute top-full right-0 h-[calc((100dvh-100%)/2)] w-[
|
|
436
|
+
class="absolute top-full right-0 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
377
437
|
></div>
|
|
378
438
|
|
|
379
439
|
@if (showsInsetRails()) {
|
|
380
440
|
<div
|
|
381
441
|
data-layout-horizontal-top-rail
|
|
382
|
-
class="absolute inset-x-0 top-12 h-[
|
|
442
|
+
class="absolute inset-x-0 top-12 h-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
383
443
|
></div>
|
|
384
444
|
<div
|
|
385
445
|
data-layout-horizontal-top-left-extension
|
|
386
|
-
class="absolute top-12 right-full h-[
|
|
446
|
+
class="absolute top-12 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
387
447
|
></div>
|
|
388
448
|
<div
|
|
389
449
|
data-layout-horizontal-top-right-extension
|
|
390
|
-
class="absolute top-12 left-full h-[
|
|
450
|
+
class="absolute top-12 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
391
451
|
></div>
|
|
392
452
|
<div
|
|
393
453
|
data-layout-horizontal-bottom-rail
|
|
394
|
-
class="absolute inset-x-0 bottom-12 h-[
|
|
454
|
+
class="absolute inset-x-0 bottom-12 h-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
395
455
|
></div>
|
|
396
456
|
<div
|
|
397
457
|
data-layout-horizontal-bottom-left-extension
|
|
398
|
-
class="absolute bottom-12 right-full h-[
|
|
458
|
+
class="absolute bottom-12 right-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
399
459
|
></div>
|
|
400
460
|
<div
|
|
401
461
|
data-layout-horizontal-bottom-right-extension
|
|
402
|
-
class="absolute bottom-12 left-full h-[
|
|
462
|
+
class="absolute bottom-12 left-full h-[var(--layout-rail-width)] w-[calc((100vw-100%)/2)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
403
463
|
></div>
|
|
404
464
|
|
|
405
465
|
<div
|
|
406
466
|
data-layout-vertical-left-rail
|
|
407
|
-
class="absolute inset-y-0 -left-4 w-[
|
|
467
|
+
class="absolute inset-y-0 -left-4 w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
408
468
|
></div>
|
|
409
469
|
<div
|
|
410
470
|
data-layout-vertical-left-top-extension
|
|
411
|
-
class="absolute bottom-full -left-4 h-[calc((100dvh-100%)/2)] w-[
|
|
471
|
+
class="absolute bottom-full -left-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
412
472
|
></div>
|
|
413
473
|
<div
|
|
414
474
|
data-layout-vertical-left-bottom-extension
|
|
415
|
-
class="absolute top-full -left-4 h-[calc((100dvh-100%)/2)] w-[
|
|
475
|
+
class="absolute top-full -left-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
416
476
|
></div>
|
|
417
477
|
<div
|
|
418
478
|
data-layout-vertical-right-rail
|
|
419
|
-
class="absolute inset-y-0 -right-4 w-[
|
|
479
|
+
class="absolute inset-y-0 -right-4 w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
420
480
|
></div>
|
|
421
481
|
<div
|
|
422
482
|
data-layout-vertical-right-top-extension
|
|
423
|
-
class="absolute bottom-full -right-4 h-[calc((100dvh-100%)/2)] w-[
|
|
483
|
+
class="absolute bottom-full -right-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
424
484
|
></div>
|
|
425
485
|
<div
|
|
426
486
|
data-layout-vertical-right-bottom-extension
|
|
427
|
-
class="absolute top-full -right-4 h-[calc((100dvh-100%)/2)] w-[
|
|
487
|
+
class="absolute top-full -right-4 h-[calc((100dvh-100%)/2)] w-[var(--layout-rail-width)] bg-[hsl(var(--layout-rail-color)/var(--layout-rail-opacity))]"
|
|
428
488
|
></div>
|
|
429
489
|
}
|
|
430
490
|
</div>
|
package/layout/README.md
CHANGED
|
@@ -324,8 +324,11 @@ Nilai `surface` yang tersedia berasal dari `LAYOUT_SURFACES`.
|
|
|
324
324
|
| Nilai | Efek visual |
|
|
325
325
|
| ------------------- | -------------------------------------------------------------------------- |
|
|
326
326
|
| `'flat'` | Background polos `bg-background`. |
|
|
327
|
-
| `'grid'` | Pola grid tipis dua arah.
|
|
328
|
-
| `'
|
|
327
|
+
| `'grid'` | Pola grid tipis dua arah; warna garis (`--layout-grid-color`) mengikuti Accent dengan kecerahan tetap (fallback neutral). |
|
|
328
|
+
| `'grid-line'` | Mosaik kotak: grid tipis + kotak highlight menyala. Mengikuti warna Accent (hue dari `--accent-foreground`, kecerahan dikunci `--layout-grid-highlight-l`), invert light/dark. Memaksa sudut frame kotak (`rounded-none`, seperti `border-rail`) + border frame warna Accent. Pada appearance `border-rail`, garis rail + border frame (tebal `--layout-rail-width` = 1.21px) ikut warna Accent (`--layout-rail-color`) dengan kecerahan dinaikkan (`--layout-rail-opacity`), bukan `--border` yang soft. |
|
|
329
|
+
| `'honeycomb'` | Pola heksagon honeycomb tipis (outline), token-colored mengikuti tema. |
|
|
330
|
+
| `'matrix'` | Field biner (0/1) acak tipis, tinted brand `--primary`, recolor mengikuti tema. |
|
|
331
|
+
| `'circuit'` | Tekstur PCB / papan sirkuit yang ter-tile: jalur (trace) berbelok 45°, node via, dan pad cincin konsentris. Dua lapisan mask — trace tembaga netral (`--layout-grid-line`) + node aksen brand (`--primary`) — jadi papannya grayscale tapi node-nya menyala mengikuti tema; recolor light/dark. |
|
|
329
332
|
| `'line-vertical'` | Garis vertikal berulang. |
|
|
330
333
|
| `'line-horizontal'` | Garis horizontal berulang. |
|
|
331
334
|
|
|
@@ -431,27 +434,27 @@ Seluruh symbol berikut diekspor dari `@ojiepermana/angular-theme/layout/types`.
|
|
|
431
434
|
| Symbol | Nilai |
|
|
432
435
|
| -------------------- | -------------------------------------------------------------------------------------------------- |
|
|
433
436
|
| `LayoutType` | `vertical`, `horizontal`, `empty`, `fluid` |
|
|
434
|
-
| `LayoutSurface` | `flat`, `grid`, `
|
|
437
|
+
| `LayoutSurface` | `flat`, `grid`, `grid-line`, `honeycomb`, `matrix`, `circuit`, `line-vertical`, `line-horizontal` |
|
|
435
438
|
| `LayoutAppearance` | `flat`, `border-rail` |
|
|
436
439
|
| `LayoutWidth` | `full`, `wide`, `container`, `fluid` |
|
|
437
440
|
| `LayoutContextValue` | Objekt berbentuk `{ surface, type, appearance, width }` yang masing-masing berupa readonly signal. |
|
|
438
441
|
|
|
439
442
|
### Constants
|
|
440
443
|
|
|
441
|
-
| Symbol | Nilai
|
|
442
|
-
| ------------------------------- |
|
|
443
|
-
| `LAYOUT_TYPES` | `['vertical', 'horizontal', 'empty', 'fluid']`
|
|
444
|
-
| `LAYOUT_SURFACES` | `['flat', 'grid', '
|
|
445
|
-
| `LAYOUT_APPEARANCES` | `['flat', 'border-rail']`
|
|
446
|
-
| `LAYOUT_WIDTHS` | `['full', 'wide', 'container', 'fluid']`
|
|
447
|
-
| `LAYOUT_DEFAULT_SURFACE` | `'flat'`
|
|
448
|
-
| `LAYOUT_DEFAULT_TYPE` | `'vertical'`
|
|
449
|
-
| `LAYOUT_DEFAULT_APPEARANCE` | `'flat'`
|
|
450
|
-
| `LAYOUT_DEFAULT_WIDTH` | `'full'`
|
|
451
|
-
| `LAYOUT_SURFACE_STORAGE_KEY` | `'layout-surface'`
|
|
452
|
-
| `LAYOUT_APPEARANCE_STORAGE_KEY` | `'layout-appearance'`
|
|
453
|
-
| `LAYOUT_TYPE_STORAGE_KEY` | `'layout-type'`
|
|
454
|
-
| `LAYOUT_WIDTH_STORAGE_KEY` | `'layout-width'`
|
|
444
|
+
| Symbol | Nilai |
|
|
445
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
446
|
+
| `LAYOUT_TYPES` | `['vertical', 'horizontal', 'empty', 'fluid']` |
|
|
447
|
+
| `LAYOUT_SURFACES` | `['flat', 'grid', 'grid-line', 'honeycomb', 'matrix', 'circuit', 'line-vertical', 'line-horizontal']` |
|
|
448
|
+
| `LAYOUT_APPEARANCES` | `['flat', 'border-rail']` |
|
|
449
|
+
| `LAYOUT_WIDTHS` | `['full', 'wide', 'container', 'fluid']` |
|
|
450
|
+
| `LAYOUT_DEFAULT_SURFACE` | `'flat'` |
|
|
451
|
+
| `LAYOUT_DEFAULT_TYPE` | `'vertical'` |
|
|
452
|
+
| `LAYOUT_DEFAULT_APPEARANCE` | `'flat'` |
|
|
453
|
+
| `LAYOUT_DEFAULT_WIDTH` | `'full'` |
|
|
454
|
+
| `LAYOUT_SURFACE_STORAGE_KEY` | `'layout-surface'` |
|
|
455
|
+
| `LAYOUT_APPEARANCE_STORAGE_KEY` | `'layout-appearance'` |
|
|
456
|
+
| `LAYOUT_TYPE_STORAGE_KEY` | `'layout-type'` |
|
|
457
|
+
| `LAYOUT_WIDTH_STORAGE_KEY` | `'layout-width'` |
|
|
455
458
|
|
|
456
459
|
### Guards
|
|
457
460
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ojiepermana/angular-theme",
|
|
3
|
-
"version": "22.0.
|
|
3
|
+
"version": "22.0.43",
|
|
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.43",
|
|
17
|
+
"@ojiepermana/angular-component": "^22.0.43",
|
|
18
18
|
"rxjs": ">=7.8.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -126,4 +126,216 @@
|
|
|
126
126
|
line-height: var(--nav-badge-line-height, var(--text-sm--line-height));
|
|
127
127
|
font-weight: var(--nav-badge-weight, 500);
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
/* Layout `honeycomb` surface — a TRUE tessellated flat-top hexagon grid drawn
|
|
131
|
+
* as a token-colored mask layer, so it recolors with the active theme/neutral
|
|
132
|
+
* (light + dark) like the other `<Layout surface>` patterns. Adjacent hexagons
|
|
133
|
+
* SHARE a single edge (no gaps), and `vector-effect: non-scaling-stroke` pins
|
|
134
|
+
* every line to a fixed 1px regardless of cell size. The SVG tile is exactly
|
|
135
|
+
* one lattice period (width 3s × height s√3, s=24px) so `mask-repeat` tiles it
|
|
136
|
+
* seamlessly; the path is solid-stroke and faintness is owned by
|
|
137
|
+
* --layout-grid-line-opacity (the dense `grid` tier, since honeycomb is
|
|
138
|
+
* multi-axis). Tune cell size via --layout-hex-size — keep the √3 (≈1.732)
|
|
139
|
+
* width:height ratio or the hexagons stretch. Edit the pattern here, not
|
|
140
|
+
* per-theme. */
|
|
141
|
+
.layout-surface-honeycomb {
|
|
142
|
+
position: relative;
|
|
143
|
+
--layout-hex-size: 43.2px 24.941px;
|
|
144
|
+
--layout-hex-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='72' height='41.569' viewBox='0 0 72 41.569'><path d='M-12 -62.354L-24 -83.138L-48 -83.138L-60 -62.354L-48 -41.569L-24 -41.569ZM-12 -20.785L-24 -41.569L-48 -41.569L-60 -20.785L-48 0L-24 0ZM-12 20.785L-24 0L-48 0L-60 20.785L-48 41.569L-24 41.569ZM-12 62.354L-24 41.569L-48 41.569L-60 62.354L-48 83.138L-24 83.138ZM-12 103.923L-24 83.138L-48 83.138L-60 103.923L-48 124.708L-24 124.708ZM-12 145.492L-24 124.708L-48 124.708L-60 145.492L-48 166.277L-24 166.277ZM24 -83.138L12 -103.923L-12 -103.923L-24 -83.138L-12 -62.354L12 -62.354ZM24 -41.569L12 -62.354L-12 -62.354L-24 -41.569L-12 -20.785L12 -20.785ZM24 0L12 -20.785L-12 -20.785L-24 0L-12 20.785L12 20.785ZM24 41.569L12 20.785L-12 20.785L-24 41.569L-12 62.354L12 62.354ZM24 83.138L12 62.354L-12 62.354L-24 83.138L-12 103.923L12 103.923ZM24 124.708L12 103.923L-12 103.923L-24 124.708L-12 145.492L12 145.492ZM60 -62.354L48 -83.138L24 -83.138L12 -62.354L24 -41.569L48 -41.569ZM60 -20.785L48 -41.569L24 -41.569L12 -20.785L24 0L48 0ZM60 20.785L48 0L24 0L12 20.785L24 41.569L48 41.569ZM60 62.354L48 41.569L24 41.569L12 62.354L24 83.138L48 83.138ZM60 103.923L48 83.138L24 83.138L12 103.923L24 124.708L48 124.708ZM60 145.492L48 124.708L24 124.708L12 145.492L24 166.277L48 166.277ZM96 -83.138L84 -103.923L60 -103.923L48 -83.138L60 -62.354L84 -62.354ZM96 -41.569L84 -62.354L60 -62.354L48 -41.569L60 -20.785L84 -20.785ZM96 0L84 -20.785L60 -20.785L48 0L60 20.785L84 20.785ZM96 41.569L84 20.785L60 20.785L48 41.569L60 62.354L84 62.354ZM96 83.138L84 62.354L60 62.354L48 83.138L60 103.923L84 103.923ZM96 124.708L84 103.923L60 103.923L48 124.708L60 145.492L84 145.492ZM132 -62.354L120 -83.138L96 -83.138L84 -62.354L96 -41.569L120 -41.569ZM132 -20.785L120 -41.569L96 -41.569L84 -20.785L96 0L120 0ZM132 20.785L120 0L96 0L84 20.785L96 41.569L120 41.569ZM132 62.354L120 41.569L96 41.569L84 62.354L96 83.138L120 83.138ZM132 103.923L120 83.138L96 83.138L84 103.923L96 124.708L120 124.708ZM132 145.492L120 124.708L96 124.708L84 145.492L96 166.277L120 166.277Z' fill='none' stroke='%23000' stroke-width='1' vector-effect='non-scaling-stroke'/></svg>");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.layout-surface-honeycomb::before {
|
|
148
|
+
content: '';
|
|
149
|
+
position: absolute;
|
|
150
|
+
inset: 0;
|
|
151
|
+
z-index: 0;
|
|
152
|
+
pointer-events: none;
|
|
153
|
+
background-color: hsl(var(--layout-grid-line) / var(--layout-grid-line-opacity));
|
|
154
|
+
-webkit-mask-image: var(--layout-hex-mask);
|
|
155
|
+
mask-image: var(--layout-hex-mask);
|
|
156
|
+
-webkit-mask-repeat: repeat;
|
|
157
|
+
mask-repeat: repeat;
|
|
158
|
+
-webkit-mask-position: center;
|
|
159
|
+
mask-position: center;
|
|
160
|
+
-webkit-mask-size: var(--layout-hex-size);
|
|
161
|
+
mask-size: var(--layout-hex-size);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Layout `matrix` surface — a scattered field of binary digits (0/1) at
|
|
165
|
+
* varied sizes with per-glyph opacity baked into the SVG, painted as a mask
|
|
166
|
+
* layer so it recolors with the active theme like the other `<Layout surface>`
|
|
167
|
+
* patterns. Unlike the neutral grid surfaces it is tinted with the brand
|
|
168
|
+
* --primary accent (--layout-matrix-opacity is the global faintness knob, toned
|
|
169
|
+
* down for dark mode in base/tokens.css), giving a soft "digital" signature
|
|
170
|
+
* behind content. The SVG tile is one square period (--layout-matrix-size) and
|
|
171
|
+
* `mask-repeat` tiles it seamlessly; every glyph sits inside the tile so the
|
|
172
|
+
* seam never cuts a digit. Edit the field here, not per-theme. */
|
|
173
|
+
.layout-surface-matrix {
|
|
174
|
+
position: relative;
|
|
175
|
+
--layout-matrix-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'><g font-family='monospace' fill='black' text-anchor='middle' dominant-baseline='middle'><text x='14' y='12' font-size='13' fill-opacity='.35'>0</text><text x='43' y='11' font-size='12' fill-opacity='.85'>0</text><text x='59' y='11' font-size='11' fill-opacity='.45'>0</text><text x='80' y='15' font-size='12' fill-opacity='.45'>0</text><text x='110' y='17' font-size='8' fill-opacity='.3'>1</text><text x='137' y='11' font-size='9' fill-opacity='.6'>1</text><text x='150' y='11' font-size='10' fill-opacity='.35'>0</text><text x='179' y='18' font-size='10' fill-opacity='.85'>0</text><text x='203' y='17' font-size='12' fill-opacity='.7'>0</text><text x='226' y='15' font-size='10' fill-opacity='1'>1</text><text x='21' y='37' font-size='10' fill-opacity='.45'>0</text><text x='34' y='37' font-size='11' fill-opacity='.7'>1</text><text x='60' y='45' font-size='9' fill-opacity='.4'>1</text><text x='88' y='35' font-size='11' fill-opacity='.3'>1</text><text x='114' y='34' font-size='12' fill-opacity='.55'>1</text><text x='134' y='40' font-size='12' fill-opacity='.35'>1</text><text x='159' y='44' font-size='11' fill-opacity='.3'>0</text><text x='181' y='37' font-size='12' fill-opacity='.5'>1</text><text x='203' y='44' font-size='10' fill-opacity='.7'>0</text><text x='222' y='40' font-size='11' fill-opacity='.45'>0</text><text x='19' y='58' font-size='10' fill-opacity='.6'>1</text><text x='44' y='62' font-size='9' fill-opacity='.6'>1</text><text x='63' y='67' font-size='11' fill-opacity='.6'>1</text><text x='91' y='64' font-size='11' fill-opacity='.4'>0</text><text x='103' y='58' font-size='13' fill-opacity='.3'>0</text><text x='131' y='63' font-size='10' fill-opacity='.3'>1</text><text x='150' y='63' font-size='12' fill-opacity='.4'>1</text><text x='180' y='62' font-size='12' fill-opacity='.7'>0</text><text x='206' y='66' font-size='13' fill-opacity='.6'>1</text><text x='223' y='57' font-size='13' fill-opacity='.3'>1</text><text x='12' y='91' font-size='11' fill-opacity='.35'>0</text><text x='37' y='80' font-size='8' fill-opacity='.85'>0</text><text x='57' y='84' font-size='8' fill-opacity='.45'>0</text><text x='87' y='81' font-size='10' fill-opacity='1'>1</text><text x='107' y='81' font-size='11' fill-opacity='.7'>1</text><text x='131' y='80' font-size='9' fill-opacity='.5'>1</text><text x='154' y='88' font-size='12' fill-opacity='.45'>0</text><text x='183' y='86' font-size='9' fill-opacity='.85'>0</text><text x='198' y='87' font-size='9' fill-opacity='.85'>1</text><text x='222' y='81' font-size='15' fill-opacity='.85'>0</text><text x='16' y='108' font-size='13' fill-opacity='1'>0</text><text x='43' y='114' font-size='10' fill-opacity='.6'>0</text><text x='65' y='105' font-size='12' fill-opacity='.55'>1</text><text x='88' y='114' font-size='15' fill-opacity='.7'>1</text><text x='106' y='111' font-size='10' fill-opacity='.55'>1</text><text x='137' y='107' font-size='10' fill-opacity='.45'>0</text><text x='154' y='106' font-size='11' fill-opacity='.7'>0</text><text x='183' y='107' font-size='13' fill-opacity='.35'>0</text><text x='206' y='112' font-size='15' fill-opacity='.7'>0</text><text x='229' y='108' font-size='13' fill-opacity='.35'>1</text><text x='20' y='137' font-size='11' fill-opacity='.6'>1</text><text x='42' y='127' font-size='9' fill-opacity='.4'>0</text><text x='57' y='133' font-size='11' fill-opacity='1'>0</text><text x='89' y='137' font-size='13' fill-opacity='.4'>1</text><text x='109' y='127' font-size='8' fill-opacity='.85'>0</text><text x='135' y='127' font-size='10' fill-opacity='.3'>0</text><text x='152' y='129' font-size='10' fill-opacity='.5'>1</text><text x='178' y='136' font-size='8' fill-opacity='.7'>1</text><text x='203' y='135' font-size='12' fill-opacity='.85'>1</text><text x='220' y='127' font-size='12' fill-opacity='.7'>0</text><text x='19' y='156' font-size='15' fill-opacity='.4'>0</text><text x='35' y='156' font-size='9' fill-opacity='.55'>0</text><text x='64' y='155' font-size='11' fill-opacity='.85'>0</text><text x='80' y='151' font-size='8' fill-opacity='.85'>0</text><text x='108' y='149' font-size='9' fill-opacity='.55'>1</text><text x='133' y='155' font-size='12' fill-opacity='.5'>0</text><text x='154' y='155' font-size='11' fill-opacity='.85'>0</text><text x='182' y='160' font-size='10' fill-opacity='.7'>0</text><text x='197' y='150' font-size='11' fill-opacity='.35'>1</text><text x='226' y='154' font-size='10' fill-opacity='.35'>1</text><text x='21' y='174' font-size='14' fill-opacity='.4'>1</text><text x='36' y='173' font-size='11' fill-opacity='.35'>0</text><text x='61' y='178' font-size='13' fill-opacity='.4'>0</text><text x='88' y='184' font-size='11' fill-opacity='.6'>1</text><text x='105' y='176' font-size='14' fill-opacity='.3'>1</text><text x='130' y='177' font-size='14' fill-opacity='.6'>0</text><text x='153' y='179' font-size='12' fill-opacity='.35'>0</text><text x='184' y='181' font-size='9' fill-opacity='.5'>0</text><text x='198' y='183' font-size='9' fill-opacity='.4'>1</text><text x='228' y='182' font-size='13' fill-opacity='.6'>1</text><text x='12' y='206' font-size='12' fill-opacity='.55'>1</text><text x='34' y='196' font-size='14' fill-opacity='.6'>0</text><text x='67' y='198' font-size='8' fill-opacity='.5'>0</text><text x='80' y='205' font-size='9' fill-opacity='.35'>1</text><text x='108' y='199' font-size='12' fill-opacity='.5'>1</text><text x='133' y='195' font-size='14' fill-opacity='.35'>0</text><text x='160' y='198' font-size='9' fill-opacity='.5'>0</text><text x='179' y='201' font-size='10' fill-opacity='.7'>1</text><text x='201' y='197' font-size='10' fill-opacity='.5'>0</text><text x='218' y='195' font-size='12' fill-opacity='.85'>0</text><text x='16' y='229' font-size='9' fill-opacity='.7'>1</text><text x='40' y='229' font-size='12' fill-opacity='.45'>1</text><text x='68' y='222' font-size='14' fill-opacity='.6'>0</text><text x='91' y='230' font-size='9' fill-opacity='.35'>0</text><text x='110' y='229' font-size='11' fill-opacity='.3'>0</text><text x='127' y='228' font-size='12' fill-opacity='1'>1</text><text x='152' y='222' font-size='11' fill-opacity='.4'>0</text><text x='175' y='218' font-size='10' fill-opacity='.85'>1</text><text x='199' y='218' font-size='10' fill-opacity='.55'>0</text><text x='220' y='222' font-size='9' fill-opacity='.5'>1</text></g></svg>");
|
|
176
|
+
/* Glow layer mask — ~10% of the digits (10 of 100), placed only in the tile's
|
|
177
|
+
* EDGE bands (never the center). Each is drawn twice through a `feGaussianBlur`
|
|
178
|
+
* filter (soft bloom halo) plus once sharp (lit core); painted brighter than the
|
|
179
|
+
* field via --layout-matrix-glow-opacity on `::after`. Static — no animation. */
|
|
180
|
+
--layout-matrix-glow-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'><defs><filter id='g' x='-80%' y='-80%' width='260%' height='260%'><feGaussianBlur stdDeviation='2.2'/></filter></defs><g font-family='monospace' fill='black' text-anchor='middle' dominant-baseline='middle'><g filter='url(%23g)'><text x='43' y='11' font-size='12' fill-opacity='1'>0</text><text x='203' y='17' font-size='12' fill-opacity='1'>0</text><text x='12' y='91' font-size='11' fill-opacity='1'>0</text><text x='12' y='206' font-size='12' fill-opacity='1'>1</text><text x='226' y='154' font-size='10' fill-opacity='1'>1</text><text x='229' y='108' font-size='13' fill-opacity='1'>1</text><text x='40' y='229' font-size='12' fill-opacity='1'>1</text><text x='175' y='218' font-size='10' fill-opacity='1'>1</text><text x='179' y='18' font-size='10' fill-opacity='1'>0</text><text x='16' y='108' font-size='13' fill-opacity='1'>0</text></g><g filter='url(%23g)'><text x='43' y='11' font-size='12' fill-opacity='1'>0</text><text x='203' y='17' font-size='12' fill-opacity='1'>0</text><text x='12' y='91' font-size='11' fill-opacity='1'>0</text><text x='12' y='206' font-size='12' fill-opacity='1'>1</text><text x='226' y='154' font-size='10' fill-opacity='1'>1</text><text x='229' y='108' font-size='13' fill-opacity='1'>1</text><text x='40' y='229' font-size='12' fill-opacity='1'>1</text><text x='175' y='218' font-size='10' fill-opacity='1'>1</text><text x='179' y='18' font-size='10' fill-opacity='1'>0</text><text x='16' y='108' font-size='13' fill-opacity='1'>0</text></g><g><text x='43' y='11' font-size='12' fill-opacity='1'>0</text><text x='203' y='17' font-size='12' fill-opacity='1'>0</text><text x='12' y='91' font-size='11' fill-opacity='1'>0</text><text x='12' y='206' font-size='12' fill-opacity='1'>1</text><text x='226' y='154' font-size='10' fill-opacity='1'>1</text><text x='229' y='108' font-size='13' fill-opacity='1'>1</text><text x='40' y='229' font-size='12' fill-opacity='1'>1</text><text x='175' y='218' font-size='10' fill-opacity='1'>1</text><text x='179' y='18' font-size='10' fill-opacity='1'>0</text><text x='16' y='108' font-size='13' fill-opacity='1'>0</text></g></g></svg>");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.layout-surface-matrix::before {
|
|
184
|
+
content: '';
|
|
185
|
+
position: absolute;
|
|
186
|
+
inset: 0;
|
|
187
|
+
z-index: 0;
|
|
188
|
+
pointer-events: none;
|
|
189
|
+
background-color: hsl(var(--primary) / var(--layout-matrix-opacity));
|
|
190
|
+
-webkit-mask-image: var(--layout-matrix-mask);
|
|
191
|
+
mask-image: var(--layout-matrix-mask);
|
|
192
|
+
-webkit-mask-repeat: repeat;
|
|
193
|
+
mask-repeat: repeat;
|
|
194
|
+
-webkit-mask-position: center;
|
|
195
|
+
mask-position: center;
|
|
196
|
+
-webkit-mask-size: var(--layout-matrix-size);
|
|
197
|
+
mask-size: var(--layout-matrix-size);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Sparse edge-glow accents: the glow glyph mask (repeating) intersected with a
|
|
201
|
+
* radial edge-vignette so the lit digits appear only toward the layout edges
|
|
202
|
+
* and fade out behind centered content (`hindari di tengah`). `intersect`
|
|
203
|
+
* (std) / `source-in` (-webkit-) keep both masks ANDed. */
|
|
204
|
+
.layout-surface-matrix::after {
|
|
205
|
+
content: '';
|
|
206
|
+
position: absolute;
|
|
207
|
+
inset: 0;
|
|
208
|
+
z-index: 0;
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
background-color: hsl(var(--primary) / var(--layout-matrix-glow-opacity));
|
|
211
|
+
-webkit-mask-image: var(--layout-matrix-glow-mask),
|
|
212
|
+
radial-gradient(ellipse 78% 78% at center, transparent 36%, #000 80%);
|
|
213
|
+
mask-image: var(--layout-matrix-glow-mask),
|
|
214
|
+
radial-gradient(ellipse 78% 78% at center, transparent 36%, #000 80%);
|
|
215
|
+
-webkit-mask-repeat: repeat, no-repeat;
|
|
216
|
+
mask-repeat: repeat, no-repeat;
|
|
217
|
+
-webkit-mask-position: center, center;
|
|
218
|
+
mask-position: center, center;
|
|
219
|
+
-webkit-mask-size: var(--layout-matrix-size), 100% 100%;
|
|
220
|
+
mask-size: var(--layout-matrix-size), 100% 100%;
|
|
221
|
+
-webkit-mask-composite: source-in;
|
|
222
|
+
mask-composite: intersect;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* Layout `grid-line` surface — a dark mosaic of 2rem square cells; a richer
|
|
226
|
+
* cousin of `grid`. A faint uniform grid with scattered BRIGHT highlight
|
|
227
|
+
* squares + L-corners and a few subtly-lit cells, all painted as ONE
|
|
228
|
+
* token-colored mask layer (same mechanism as `.layout-surface-honeycomb` /
|
|
229
|
+
* `.layout-surface-matrix`). EVERYTHING lives in the single mask — base
|
|
230
|
+
* grid, glows, and cell fills — so the layers stay pixel-aligned. The glow
|
|
231
|
+
* FOLLOWS THE ACCENT: the ::before paints with the accent hue+saturation (from
|
|
232
|
+
* --accent-foreground) but pins lightness to --layout-grid-highlight-l, so the
|
|
233
|
+
* surface tracks the active theme-color while its brightness stays put (in the
|
|
234
|
+
* base/neutral theme the accent is achromatic → the same grayscale as before).
|
|
235
|
+
* --layout-grid-highlight-opacity is the global faintness knob. Every fill /
|
|
236
|
+
* stroke is white (%23fff) and serves only as an ALPHA mask: low alpha = faint
|
|
237
|
+
* grid/cell, high alpha = bright glow. `vector-effect: non-scaling-stroke`
|
|
238
|
+
* pins every line to a fixed 1px regardless of cell size.
|
|
239
|
+
*
|
|
240
|
+
* The tile is 6x6 cells (viewBox 0 0 192 192 = 32 units/cell) so mask-size is
|
|
241
|
+
* 9.96rem (one cell ≈ 1.66rem — 17% smaller than the 2rem `grid` family size;
|
|
242
|
+
* tune via --layout-grid-line-size). SEAMLESS: the grid is drawn
|
|
243
|
+
* at 0..192 on BOTH edges. A 1px non-scaling stroke centered on a tile edge has
|
|
244
|
+
* its outer half clipped by the SVG viewBox, so under `mask-repeat: repeat` each
|
|
245
|
+
* seam gets one half-stroke from the tile on each side ([191.5,192] + [192,192.5])
|
|
246
|
+
* which combine into a single full 1px line — an even grid with no doubling and
|
|
247
|
+
* no thinned seam. Every highlight/fill stays in the interior (>=32, <=160) so
|
|
248
|
+
* no glow is ever clipped at a tile edge. Edit the pattern here, not per-theme. */
|
|
249
|
+
.layout-surface-grid-line {
|
|
250
|
+
position: relative;
|
|
251
|
+
--layout-grid-line-size: 9.96rem 9.96rem;
|
|
252
|
+
--layout-grid-line-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='192' height='192' viewBox='0 0 192 192'><path d='M0 0V192M32 0V192M64 0V192M96 0V192M128 0V192M160 0V192M192 0V192M0 0H192M0 32H192M0 64H192M0 96H192M0 128H192M0 160H192M0 192H192' fill='none' stroke='%23fff' stroke-width='1' stroke-opacity='0.25' vector-effect='non-scaling-stroke'/><g fill='%23fff'><rect x='66' y='34' width='28' height='28' fill-opacity='0.1'/><rect x='130' y='34' width='28' height='28' fill-opacity='0.06'/><rect x='34' y='66' width='28' height='28' fill-opacity='0.12'/><rect x='98' y='66' width='28' height='28' fill-opacity='0.07'/><rect x='66' y='98' width='28' height='28' fill-opacity='0.09'/><rect x='130' y='98' width='28' height='28' fill-opacity='0.05'/><rect x='34' y='130' width='28' height='28' fill-opacity='0.11'/><rect x='98' y='130' width='28' height='28' fill-opacity='0.06'/></g><g fill='none' stroke='%23fff' stroke-width='1' vector-effect='non-scaling-stroke'><rect x='32' y='32' width='32' height='32' stroke-opacity='0.85'/><rect x='128' y='64' width='32' height='32' stroke-opacity='0.8'/><rect x='32' y='96' width='32' height='32' stroke-opacity='0.9'/><rect x='128' y='128' width='32' height='32' stroke-opacity='0.82'/><path d='M128 32L96 32L96 64' stroke-opacity='0.7'/><path d='M64 96L96 96L96 64' stroke-opacity='0.75'/><path d='M96 96L128 96L128 128' stroke-opacity='0.72'/><path d='M64 128L64 160L96 160' stroke-opacity='0.68'/></g></svg>");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.layout-surface-grid-line::before {
|
|
256
|
+
content: '';
|
|
257
|
+
position: absolute;
|
|
258
|
+
inset: 0;
|
|
259
|
+
z-index: 0;
|
|
260
|
+
pointer-events: none;
|
|
261
|
+
/* Accent-tinted glow: take the accent hue+saturation (from --accent-foreground)
|
|
262
|
+
* but PIN the lightness to --layout-grid-highlight-l, so the surface follows
|
|
263
|
+
* the active theme-color while its brightness stays exactly as before. In the
|
|
264
|
+
* base/neutral theme the accent is achromatic, so it resolves to the same
|
|
265
|
+
* grayscale. The first declaration is a grayscale fallback for browsers without
|
|
266
|
+
* CSS relative color; the second tints it where supported. */
|
|
267
|
+
background-color: hsl(0 0% var(--layout-grid-highlight-l) / var(--layout-grid-highlight-opacity));
|
|
268
|
+
background-color: hsl(
|
|
269
|
+
from hsl(var(--accent-foreground)) h s var(--layout-grid-highlight-l) /
|
|
270
|
+
var(--layout-grid-highlight-opacity)
|
|
271
|
+
);
|
|
272
|
+
-webkit-mask-image: var(--layout-grid-line-mask);
|
|
273
|
+
mask-image: var(--layout-grid-line-mask);
|
|
274
|
+
-webkit-mask-repeat: repeat;
|
|
275
|
+
mask-repeat: repeat;
|
|
276
|
+
-webkit-mask-position: center;
|
|
277
|
+
mask-position: center;
|
|
278
|
+
-webkit-mask-size: var(--layout-grid-line-size);
|
|
279
|
+
mask-size: var(--layout-grid-line-size);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Layout `circuit` surface — a tileable PCB / circuit-board texture: routed
|
|
283
|
+
* copper traces with 45° chamfered bends, via nodes, and concentric ring pads,
|
|
284
|
+
* echoing a printed circuit board. Built as the same kind of token-colored mask
|
|
285
|
+
* layer as `.layout-surface-honeycomb` / `.layout-surface-matrix`, but with TWO
|
|
286
|
+
* stacked layers because a mask only carries ALPHA (one color per layer):
|
|
287
|
+
* ::before — the neutral copper TRACES, painted in --layout-grid-line (the
|
|
288
|
+
* same neutral the grid family uses, so the board recolors per
|
|
289
|
+
* theme + dark mode). Faintness = --layout-circuit-opacity × the
|
|
290
|
+
* per-trace alpha baked into the SVG (ghost 0.22 · trace 0.55-0.6 ·
|
|
291
|
+
* trunk 0.9), giving the copper-weight variation of a real board.
|
|
292
|
+
* ::after — the via NODES + concentric pads, painted in the brand --primary
|
|
293
|
+
* accent (like `matrix`) so the connection points GLOW with the
|
|
294
|
+
* theme while the traces stay grayscale. Faintness =
|
|
295
|
+
* --layout-circuit-node-opacity (toned down for dark mode in
|
|
296
|
+
* base/tokens.css, since --primary inverts to near-white and blooms).
|
|
297
|
+
* Both layers share ONE tile geometry (--layout-circuit-size) and `mask-position:
|
|
298
|
+
* center`, so traces and nodes stay pixel-aligned. `vector-effect:
|
|
299
|
+
* non-scaling-stroke` pins every line to its authored px width at any scale.
|
|
300
|
+
*
|
|
301
|
+
* SEAMLESS BY CONSTRUCTION (240x240 tile): every horizontal bus enters at x=0
|
|
302
|
+
* and exits at x=240 at the SAME y (wraps left/right) and every vertical bus
|
|
303
|
+
* enters at y=0 / exits at y=240 at the SAME x (wraps top/bottom); the long
|
|
304
|
+
* buses bridge each seam so the board reads continuous. All interior branches,
|
|
305
|
+
* vias, and rings stay inside an 18px edge keep-out, so tiling never clips a
|
|
306
|
+
* node. Edit the board in scratchpad/circuit-gen.mjs (the parametric generator
|
|
307
|
+
* with a built-in seam check), not by hand. */
|
|
308
|
+
.layout-surface-circuit {
|
|
309
|
+
position: relative;
|
|
310
|
+
--layout-circuit-size: 240px;
|
|
311
|
+
--layout-circuit-traces: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'><path d='M20 70L38 70L48.24 65.76L56 58' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.22' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M210 150L210 172L205.76 182.24L196 192' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.22' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M28 150L28 176' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.22' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M212 40L224 40' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.22' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M0 40L54 40L64.24 35.76L75.76 24.24L86 20L114 20L124.24 24.24L135.76 35.76L146 40L240 40' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.6' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M0 120L34 120L44.24 115.76L55.76 104.24L66 100L94 100L104.24 104.24L115.76 115.76L126 120L154 120L164.24 124.24L175.76 135.76L186 140L194 140L204.24 135.76L215.76 124.24L226 120L240 120' fill='none' stroke='%23000' stroke-width='1.5' stroke-opacity='0.9' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M0 200L94 200L104.24 204.24L115.76 215.76L126 220L154 220L164.24 215.76L175.76 204.24L186 200L240 200' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.6' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M60 0L60 54L64.24 64.24L75.76 75.76L80 86L80 154L75.76 164.24L64.24 175.76L60 186L60 240' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.55' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M180 0L180 64L175.76 74.24L164.24 85.76L160 96L160 144L164.24 154.24L175.76 165.76L180 176L180 240' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.55' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M100 100L100 64' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.4' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M160 120L194 120L200 114L200 84' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.4' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M80 120L80 96' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.4' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/><path d='M140 200L140 164' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.4' stroke-linejoin='round' stroke-linecap='round' vector-effect='non-scaling-stroke'/></svg>");
|
|
312
|
+
--layout-circuit-nodes: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'><circle cx='60' cy='40' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='140' cy='40' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='100' cy='200' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='180' cy='200' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='60' cy='100' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='120' cy='120' r='3.2' fill='%23000' fill-opacity='0.85'/><circle cx='180' cy='140' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='80' cy='80' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='80' cy='160' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='160' cy='90' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='160' cy='150' r='3' fill='%23000' fill-opacity='0.85'/><circle cx='100' cy='100' r='2.6' fill='%23000' fill-opacity='0.85'/><circle cx='200' cy='120' r='2.6' fill='%23000' fill-opacity='0.85'/><circle cx='140' cy='200' r='2.6' fill='%23000' fill-opacity='0.85'/><circle cx='100' cy='60' r='6' fill='none' stroke='%23000' stroke-width='1.2' stroke-opacity='0.7' vector-effect='non-scaling-stroke'/><circle cx='100' cy='60' r='2' fill='%23000' fill-opacity='0.85'/><circle cx='200' cy='80' r='6' fill='none' stroke='%23000' stroke-width='1.2' stroke-opacity='0.7' vector-effect='non-scaling-stroke'/><circle cx='200' cy='80' r='2' fill='%23000' fill-opacity='0.85'/><circle cx='140' cy='160' r='6' fill='none' stroke='%23000' stroke-width='1.2' stroke-opacity='0.7' vector-effect='non-scaling-stroke'/><circle cx='140' cy='160' r='2' fill='%23000' fill-opacity='0.85'/><circle cx='40' cy='160' r='4.5' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.55' vector-effect='non-scaling-stroke'/><circle cx='215' cy='40' r='4' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.55' vector-effect='non-scaling-stroke'/><circle cx='25' cy='200' r='4' fill='none' stroke='%23000' stroke-width='1' stroke-opacity='0.55' vector-effect='non-scaling-stroke'/></svg>");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.layout-surface-circuit::before,
|
|
316
|
+
.layout-surface-circuit::after {
|
|
317
|
+
content: '';
|
|
318
|
+
position: absolute;
|
|
319
|
+
inset: 0;
|
|
320
|
+
z-index: 0;
|
|
321
|
+
pointer-events: none;
|
|
322
|
+
-webkit-mask-repeat: repeat;
|
|
323
|
+
mask-repeat: repeat;
|
|
324
|
+
-webkit-mask-position: center;
|
|
325
|
+
mask-position: center;
|
|
326
|
+
-webkit-mask-size: var(--layout-circuit-size);
|
|
327
|
+
mask-size: var(--layout-circuit-size);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.layout-surface-circuit::before {
|
|
331
|
+
background-color: hsl(var(--layout-grid-line) / var(--layout-circuit-opacity));
|
|
332
|
+
-webkit-mask-image: var(--layout-circuit-traces);
|
|
333
|
+
mask-image: var(--layout-circuit-traces);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.layout-surface-circuit::after {
|
|
337
|
+
background-color: hsl(var(--primary) / var(--layout-circuit-node-opacity));
|
|
338
|
+
-webkit-mask-image: var(--layout-circuit-nodes);
|
|
339
|
+
mask-image: var(--layout-circuit-nodes);
|
|
340
|
+
}
|
|
129
341
|
}
|
|
@@ -160,9 +160,82 @@
|
|
|
160
160
|
/* --layout-grid-line is defined per-mode in base/tokens.css and per-neutral
|
|
161
161
|
* by the generated theme-neutral CSS, so the surface grid keeps constant
|
|
162
162
|
* contrast across every neutral — not just base. Opacity is the global
|
|
163
|
-
*
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
* visibility knob shared by all grid surfaces:
|
|
164
|
+
* --layout-grid-line-opacity → the `grid` + `honeycomb` surfaces
|
|
165
|
+
* (multi-axis patterns)
|
|
166
|
+
* --layout-grid-dot-opacity → `line-vertical` / `line-horizontal`
|
|
167
|
+
* (single-axis rules)
|
|
168
|
+
* The multi-axis patterns are denser so they sit a step below the
|
|
169
|
+
* single-axis lines. Raised from 0.18/0.22 so the pattern actually reads
|
|
170
|
+
* on-screen against the ~16-point line/background lightness gap. */
|
|
171
|
+
--layout-grid-line-opacity: 0.4;
|
|
172
|
+
--layout-grid-dot-opacity: 0.5;
|
|
173
|
+
|
|
174
|
+
/* `grid` surface line color. DEFAULT (fallback) = the neutral --layout-grid-line
|
|
175
|
+
* at --layout-grid-line-opacity (unchanged behavior). Where CSS relative color
|
|
176
|
+
* is supported it's overridden below to FOLLOW THE ACCENT: accent hue+saturation
|
|
177
|
+
* (from --accent-foreground) at the grid's own lightness (82% light / 24% dark,
|
|
178
|
+
* pinned so brightness stays put — grayscale in the base theme, tinted under a
|
|
179
|
+
* color theme). Only the `grid` surface uses this; honeycomb/line-* stay neutral. */
|
|
180
|
+
--layout-grid-color: hsl(var(--layout-grid-line) / var(--layout-grid-line-opacity));
|
|
181
|
+
|
|
182
|
+
/* `grid-line` surface — global faintness of its accent-tinted glow (accent hue
|
|
183
|
+
* from --accent-foreground at lightness --layout-grid-highlight-l, composed in
|
|
184
|
+
* base/components.css). Per-element alpha (faint base grid, faint cell fills,
|
|
185
|
+
* bright glow squares) is baked into the SVG mask, so this multiplies it: lower
|
|
186
|
+
* for a quieter surface, raise for a more assertive glow. */
|
|
187
|
+
--layout-grid-highlight-opacity: 0.55;
|
|
188
|
+
|
|
189
|
+
/* `grid-line` frame border opacity. The square layout frame borders with the
|
|
190
|
+
* accent color (--accent-foreground — the STRONG member of the accent family,
|
|
191
|
+
* so it follows the active theme-color and inverts dark-on-light / light-on-
|
|
192
|
+
* dark). Now that the SURFACE also tints with the accent, the border was too
|
|
193
|
+
* strong — toned down to 0.484, but kept ABOVE the surface's strongest line
|
|
194
|
+
* (≈ --layout-grid-highlight-opacity 0.55 × the brightest baked stroke 0.9 ≈
|
|
195
|
+
* 0.5) so the layout edge still reads as the strongest line. */
|
|
196
|
+
--layout-grid-line-border-opacity: 0.484;
|
|
197
|
+
|
|
198
|
+
/* border-rail appearance — color, opacity, and THICKNESS of the layout's rail
|
|
199
|
+
* lines AND its frame border (all read these). Color/opacity follow the ACCENT
|
|
200
|
+
* (--accent-foreground) globally, so every border-rail layout picks up the
|
|
201
|
+
* active theme-color and reads bright, not the soft neutral --border.
|
|
202
|
+
* --accent-foreground inverts dark-on-light / light-on-dark automatically.
|
|
203
|
+
* --layout-rail-width is the single thickness knob for the layout rails. */
|
|
204
|
+
--layout-rail-color: var(--accent-foreground);
|
|
205
|
+
--layout-rail-opacity: 0.9;
|
|
206
|
+
--layout-rail-width: 1.21px;
|
|
207
|
+
|
|
208
|
+
/* `matrix` surface — a scattered binary (0/1) field tinted with the brand
|
|
209
|
+
* --primary accent (not the neutral --layout-grid-line), so it reads as a soft
|
|
210
|
+
* "digital" signature that recolors with the active theme. Two knobs:
|
|
211
|
+
* --layout-matrix-opacity → global faintness of the field. Per-glyph opacity
|
|
212
|
+
* is baked into the SVG mask, so this multiplies it;
|
|
213
|
+
* toned down for dark mode in base/tokens.css so the
|
|
214
|
+
* inverted (near-white) accent never shouts.
|
|
215
|
+
* --layout-matrix-size → the SVG tile period (square). Larger = sparser.
|
|
216
|
+
* --layout-matrix-glow-opacity → brightness of the sparse edge-glow accents
|
|
217
|
+
* (the `::after` lit digits). Sits ABOVE the field
|
|
218
|
+
* opacity so the ~10% lit digits read as a glow;
|
|
219
|
+
* raised in dark mode (base/tokens.css) so the
|
|
220
|
+
* inverted accent actually blooms. */
|
|
221
|
+
--layout-matrix-opacity: 0.26;
|
|
222
|
+
--layout-matrix-size: 240px;
|
|
223
|
+
|
|
224
|
+
/* `circuit` surface — a tileable PCB / circuit-board texture drawn as two
|
|
225
|
+
* mask layers (base/components.css). Two faintness knobs, one per layer:
|
|
226
|
+
* --layout-circuit-opacity → the neutral copper TRACES (--layout-grid-line).
|
|
227
|
+
* Per-trace alpha (ghost/trace/trunk) is baked
|
|
228
|
+
* into the SVG, so this multiplies it. Sits in
|
|
229
|
+
* the dense multi-axis tier (like `honeycomb`),
|
|
230
|
+
* so it matches --layout-grid-line-opacity.
|
|
231
|
+
* --layout-circuit-node-opacity → the accent via NODES / pads (--primary).
|
|
232
|
+
* Toned down for dark mode in base/tokens.css
|
|
233
|
+
* (the inverted near-white accent blooms). Kept
|
|
234
|
+
* a touch above the trace tier so the sparse
|
|
235
|
+
* nodes read as quiet glints, not noise. */
|
|
236
|
+
--layout-circuit-opacity: 0.4;
|
|
237
|
+
--layout-circuit-node-opacity: 0.5;
|
|
238
|
+
--layout-matrix-glow-opacity: 0.55;
|
|
166
239
|
|
|
167
240
|
--overlay-backdrop: 0 0% 3.9% / 0.5;
|
|
168
241
|
--overlay-backdrop-strong: 0 0% 3.9% / 0.4;
|
|
@@ -187,6 +260,21 @@
|
|
|
187
260
|
--theme-shadow-xl: var(--shadow-xl-base);
|
|
188
261
|
}
|
|
189
262
|
|
|
263
|
+
/* `grid` surface accent tint — applied only where CSS relative color is
|
|
264
|
+
* supported (otherwise the neutral fallback set on :root above stands). Follows
|
|
265
|
+
* the accent hue+saturation (from --accent-foreground) at the grid's own
|
|
266
|
+
* lightness (--layout-grid-l, per-mode), so brightness is unchanged while the
|
|
267
|
+
* tint tracks the theme-color. --layout-grid-l is per-mode, so this single rule
|
|
268
|
+
* covers light + dark. */
|
|
269
|
+
@supports (color: hsl(from white h s l)) {
|
|
270
|
+
:root {
|
|
271
|
+
--layout-grid-color: hsl(
|
|
272
|
+
from hsl(var(--accent-foreground)) h s var(--layout-grid-l) /
|
|
273
|
+
var(--layout-grid-line-opacity)
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
190
278
|
:root,
|
|
191
279
|
[data-mode='light'] {
|
|
192
280
|
color-scheme: light;
|
|
@@ -28,6 +28,19 @@
|
|
|
28
28
|
* grid keeps the same ~16-point lightness gap vs --background that every
|
|
29
29
|
* generated neutral targets — base is no longer a special case. */
|
|
30
30
|
--layout-grid-line: 0 0% 82%;
|
|
31
|
+
/* LIGHTNESS of the `grid` surface lines — used to pin lightness when the grid
|
|
32
|
+
* follows the accent (see --layout-grid-color in base/theme.css), so the tint
|
|
33
|
+
* tracks the theme-color while brightness stays at the current ~82% (light). */
|
|
34
|
+
--layout-grid-l: 82%;
|
|
35
|
+
|
|
36
|
+
/* `grid-line` surface highlight LIGHTNESS. The glow now FOLLOWS the accent:
|
|
37
|
+
* the surface paints with the accent hue+saturation (from --accent-foreground,
|
|
38
|
+
* via CSS relative color in base/components.css) but pins lightness to this
|
|
39
|
+
* value, so the brightness stays exactly as before while the tint tracks the
|
|
40
|
+
* active theme-color. Medium-dark in light mode so the mosaic reads as soft
|
|
41
|
+
* darker lines on a light surface; inverts to near-white in dark (dark block).
|
|
42
|
+
* Global faintness lives in --layout-grid-highlight-opacity (base/theme.css). */
|
|
43
|
+
--layout-grid-highlight-l: 45%;
|
|
31
44
|
|
|
32
45
|
/* Base accent = near-black neutral (FluxUI "base"); inverts to near-white in
|
|
33
46
|
* dark mode (see :root[data-mode='dark'] below). Accent palettes
|
|
@@ -85,21 +98,28 @@
|
|
|
85
98
|
--line-height-base: 1.5;
|
|
86
99
|
--control-height-base: 2.25rem;
|
|
87
100
|
--nav-font-family: var(--font-sans);
|
|
88
|
-
|
|
89
|
-
--nav-text-
|
|
101
|
+
/* Item labels — the nav baseline tier (14px, snug line-height). */
|
|
102
|
+
--nav-text-size: var(--text-sm);
|
|
103
|
+
--nav-text-line-height: var(--text-sm--line-height);
|
|
90
104
|
--nav-heading-font-family: var(--font-sans);
|
|
91
|
-
|
|
92
|
-
|
|
105
|
+
/* Section/group headings — a distinct micro-label tier *below* item labels:
|
|
106
|
+
* smaller (11px), uppercase, heavier weight, restrained tracking. Keeping it
|
|
107
|
+
* smaller than --nav-text-size is what gives the sidebar a clear hierarchy. */
|
|
108
|
+
--nav-heading-size: var(--text-2xs-plus);
|
|
109
|
+
--nav-heading-line-height: var(--text-2xs-plus--line-height);
|
|
93
110
|
--nav-heading-weight: 600;
|
|
94
|
-
--nav-heading-letter-spacing: 0.
|
|
111
|
+
--nav-heading-letter-spacing: 0.08em;
|
|
95
112
|
--nav-badge-font-family: var(--font-sans);
|
|
96
|
-
|
|
97
|
-
--nav-badge-
|
|
113
|
+
/* Badges/counters — compact pill tier (11px), aligned with the heading tier. */
|
|
114
|
+
--nav-badge-size: var(--text-2xs-plus);
|
|
115
|
+
--nav-badge-line-height: var(--text-2xs-plus--line-height);
|
|
98
116
|
--nav-badge-weight: 500;
|
|
99
117
|
--letter-spacing: 0;
|
|
100
118
|
--spacing-base: 0.25rem;
|
|
101
119
|
--space-unit: var(--spacing-base);
|
|
102
|
-
|
|
120
|
+
/* Matches the actual shell bar height (h-12 = 3rem) used by the navigation
|
|
121
|
+
* header/footer/navbar and page header/footer. */
|
|
122
|
+
--layout-topbar-height: 3rem;
|
|
103
123
|
|
|
104
124
|
--layout-shell-padding: clamp(1rem, 2vw, 2rem);
|
|
105
125
|
--layout-frame-radius: var(--radius-lg);
|
|
@@ -138,6 +158,28 @@
|
|
|
138
158
|
|
|
139
159
|
/* Surface-grid line for the base neutral (dark). See light block. */
|
|
140
160
|
--layout-grid-line: 0 0% 24%;
|
|
161
|
+
/* `grid` surface line lightness (dark) — see light block. */
|
|
162
|
+
--layout-grid-l: 24%;
|
|
163
|
+
|
|
164
|
+
/* `grid-line` highlight lightness inverts to near-white so the glow squares
|
|
165
|
+
* read bright on the dark surface, matching the dark mosaic reference; the
|
|
166
|
+
* accent hue is mixed in via relative color (see light block). */
|
|
167
|
+
--layout-grid-highlight-l: 88%;
|
|
168
|
+
|
|
169
|
+
/* `matrix` is tinted with --primary, which inverts to near-white on dark
|
|
170
|
+
* — so tone the field down here to keep it as faint behind content as it is in
|
|
171
|
+
* light mode (see --layout-matrix-opacity in base/theme.css). The edge-glow
|
|
172
|
+
* accents are raised instead: near-white on near-black actually blooms, so the
|
|
173
|
+
* lit digits read as a glow against the dark surface. */
|
|
174
|
+
--layout-matrix-opacity: 0.19;
|
|
175
|
+
--layout-matrix-glow-opacity: 0.7;
|
|
176
|
+
|
|
177
|
+
/* `circuit` via nodes are tinted with --primary, which inverts to near-white
|
|
178
|
+
* on dark and blooms — so tone the node layer down here to keep the glints as
|
|
179
|
+
* quiet as they are in light mode (same treatment as --layout-matrix-opacity).
|
|
180
|
+
* The neutral traces use --layout-grid-line (already per-mode), so they need
|
|
181
|
+
* no dark override. */
|
|
182
|
+
--layout-circuit-node-opacity: 0.4;
|
|
141
183
|
|
|
142
184
|
/* Base accent inverts: near-white primary on dark. */
|
|
143
185
|
--primary: 0 0% 98%;
|
|
@@ -9,16 +9,19 @@
|
|
|
9
9
|
* html[theme-space='x'] (0,1,1) beats the :root default (0,1,0).
|
|
10
10
|
*/
|
|
11
11
|
@layer tokens {
|
|
12
|
+
/* Even ~16% steps around the 0.25rem baseline so each preset is a perceptible,
|
|
13
|
+
* proportional change rather than an uneven nudge. normal stays the Tailwind
|
|
14
|
+
* default (no-op). */
|
|
12
15
|
html[theme-space='compact'] {
|
|
13
|
-
--spacing-base: 0.
|
|
16
|
+
--spacing-base: 0.215rem;
|
|
14
17
|
}
|
|
15
18
|
html[theme-space='normal'] {
|
|
16
19
|
--spacing-base: 0.25rem;
|
|
17
20
|
}
|
|
18
21
|
html[theme-space='relaxed'] {
|
|
19
|
-
--spacing-base: 0.
|
|
22
|
+
--spacing-base: 0.29rem;
|
|
20
23
|
}
|
|
21
24
|
html[theme-space='spacious'] {
|
|
22
|
-
--spacing-base: 0.
|
|
25
|
+
--spacing-base: 0.33rem;
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -11,7 +11,7 @@ declare class LayoutService {
|
|
|
11
11
|
private readonly typeState;
|
|
12
12
|
private readonly appearanceState;
|
|
13
13
|
private readonly widthState;
|
|
14
|
-
readonly surface: _angular_core.Signal<"flat" | "grid" | "
|
|
14
|
+
readonly surface: _angular_core.Signal<"flat" | "grid" | "grid-line" | "honeycomb" | "matrix" | "circuit" | "line-vertical" | "line-horizontal">;
|
|
15
15
|
readonly type: _angular_core.Signal<"vertical" | "horizontal" | "empty" | "fluid">;
|
|
16
16
|
readonly appearance: _angular_core.Signal<"flat" | "border-rail">;
|
|
17
17
|
readonly width: _angular_core.Signal<"fluid" | "full" | "wide" | "container">;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Signal } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
declare const LAYOUT_TYPES: readonly ["vertical", "horizontal", "empty", "fluid"];
|
|
4
|
-
declare const LAYOUT_SURFACES: readonly ["flat", "grid", "
|
|
4
|
+
declare const LAYOUT_SURFACES: readonly ["flat", "grid", "grid-line", "honeycomb", "matrix", "circuit", "line-vertical", "line-horizontal"];
|
|
5
5
|
declare const LAYOUT_APPEARANCES: readonly ["flat", "border-rail"];
|
|
6
6
|
declare const LAYOUT_WIDTHS: readonly ["full", "wide", "container", "fluid"];
|
|
7
7
|
type LayoutType = (typeof LAYOUT_TYPES)[number];
|
|
@@ -178,7 +178,7 @@ type NavKind = NavigationType | 'brand';
|
|
|
178
178
|
*/
|
|
179
179
|
declare class LayoutWrapperDefault {
|
|
180
180
|
/** Surface latar shell (mis. `grid`, `flat`). */
|
|
181
|
-
readonly surface: _angular_core.InputSignal<"flat" | "grid" | "
|
|
181
|
+
readonly surface: _angular_core.InputSignal<"flat" | "grid" | "grid-line" | "honeycomb" | "matrix" | "circuit" | "line-vertical" | "line-horizontal">;
|
|
182
182
|
/** Appearance shell & nav (`flat | border-rail`). */
|
|
183
183
|
readonly appearance: _angular_core.InputSignal<"flat" | "border-rail">;
|
|
184
184
|
/** Lebar frame (`full`, `container`, dst.). */
|
|
@@ -6,7 +6,7 @@ export { LAYOUT_APPEARANCES, LAYOUT_APPEARANCE_STORAGE_KEY, LAYOUT_DEFAULT_APPEA
|
|
|
6
6
|
|
|
7
7
|
declare class LayoutComponent {
|
|
8
8
|
protected readonly layout: LayoutService;
|
|
9
|
-
readonly surface: _angular_core.InputSignal<"flat" | "grid" | "
|
|
9
|
+
readonly surface: _angular_core.InputSignal<"flat" | "grid" | "grid-line" | "honeycomb" | "matrix" | "circuit" | "line-vertical" | "line-horizontal" | null>;
|
|
10
10
|
readonly appearance: _angular_core.InputSignal<"flat" | "border-rail" | null>;
|
|
11
11
|
readonly layoutAppearanceAttribute: _angular_core.InputSignal<"flat" | "border-rail" | null>;
|
|
12
12
|
readonly width: _angular_core.InputSignal<"full" | "wide" | "container" | "fluid" | null>;
|
|
@@ -17,13 +17,14 @@ declare class LayoutComponent {
|
|
|
17
17
|
readonly type: _angular_core.InputSignal<"fluid" | "vertical" | "horizontal" | "empty" | null>;
|
|
18
18
|
readonly class: _angular_core.InputSignal<string>;
|
|
19
19
|
protected readonly appearanceInput: _angular_core.Signal<"flat" | "border-rail" | null>;
|
|
20
|
-
protected readonly resolvedSurface: _angular_core.Signal<"flat" | "grid" | "
|
|
20
|
+
protected readonly resolvedSurface: _angular_core.Signal<"flat" | "grid" | "grid-line" | "honeycomb" | "matrix" | "circuit" | "line-vertical" | "line-horizontal">;
|
|
21
21
|
protected readonly resolvedAppearance: _angular_core.Signal<"flat" | "border-rail">;
|
|
22
22
|
protected readonly resolvedWidth: _angular_core.Signal<"full" | "wide" | "container" | "fluid">;
|
|
23
23
|
protected readonly resolvedType: _angular_core.Signal<"fluid" | "vertical" | "horizontal" | "empty">;
|
|
24
24
|
protected readonly isBorderRail: _angular_core.Signal<boolean>;
|
|
25
25
|
protected readonly isFluidFrame: _angular_core.Signal<boolean>;
|
|
26
26
|
protected readonly isFullFlat: _angular_core.Signal<boolean>;
|
|
27
|
+
protected readonly isGridLineSurface: _angular_core.Signal<boolean>;
|
|
27
28
|
protected readonly showsInsetRails: _angular_core.Signal<boolean>;
|
|
28
29
|
protected readonly frameStageClasses: _angular_core.Signal<string>;
|
|
29
30
|
protected readonly railAnchorClasses: _angular_core.Signal<string>;
|