vanilla-jui 1.7.31 → 1.7.32

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.
Files changed (44) hide show
  1. package/dist/index.d.ts +24 -4
  2. package/dist/index.js +1 -1
  3. package/dist/index.umd.js +1 -1
  4. package/dist/style.css +1 -1
  5. package/package.json +1 -1
  6. package/src/components/accordion.ts +22 -8
  7. package/src/components/flow.ts +1 -1
  8. package/src/components/form.ts +1 -1
  9. package/src/components/modal.ts +1 -1
  10. package/src/components/offcanvas.ts +2 -2
  11. package/src/components/pagination.ts +5 -5
  12. package/src/components/tabs.ts +132 -16
  13. package/src/css/animation.css +7 -3
  14. package/src/css/card.css +10 -10
  15. package/src/css/font.css +3 -6
  16. package/src/css/icon.css +3 -20
  17. package/src/css/layout.css +11 -18
  18. package/src/css/status.css +39 -3
  19. package/src/css/themes/default/accordion.css +13 -45
  20. package/src/css/themes/default/avatar.css +2 -3
  21. package/src/css/themes/default/badge.css +14 -22
  22. package/src/css/themes/default/breadcrumb.css +11 -12
  23. package/src/css/themes/default/button.css +101 -159
  24. package/src/css/themes/default/editor.css +36 -36
  25. package/src/css/themes/default/flow.css +4 -4
  26. package/src/css/themes/default/form.css +110 -217
  27. package/src/css/themes/default/loading.css +48 -63
  28. package/src/css/themes/default/menu.css +17 -17
  29. package/src/css/themes/default/modal.css +9 -9
  30. package/src/css/themes/default/offcanvas.css +3 -3
  31. package/src/css/themes/default/swiper.css +18 -18
  32. package/src/css/themes/default/tabs.css +38 -24
  33. package/src/css/themes/default/theme-palette.css +22 -18
  34. package/src/css/themes/default/tip.css +24 -13
  35. package/src/css/themes/default/toast.css +65 -45
  36. package/src/css/themes/default/toolbar.css +2 -2
  37. package/src/css/themes/default/tooltip.css +2 -3
  38. package/src/css/tokens.css +89 -59
  39. package/src/css/tokens_/345/211/257/346/234/254.css +4 -4
  40. package/src/icons/index.ts +9 -7
  41. package/src/locales/index.ts +3 -1
  42. package/src/primitives/theme.ts +7 -10
  43. package/src/primitives/toast.ts +191 -107
  44. package/src/utilities/browser.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-jui",
3
- "version": "1.7.31",
3
+ "version": "1.7.32",
4
4
  "private": false,
5
5
  "description": "A lightweight, reactive, and fully customizable vanilla JS UI library.",
6
6
  "keywords": [
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  For,
3
+ Show,
3
4
  createDeepStore,
4
5
  createEffect,
5
6
  createSignal,
@@ -14,7 +15,11 @@ import {
14
15
  } from '../core/component.ts';
15
16
  import { createLoading } from '../primitives/loading.ts';
16
17
  import { icon } from '../primitives/icons.ts';
17
- import { asRenderable, type RenderableContent } from '../utilities/dom.ts';
18
+ import {
19
+ asRenderable,
20
+ joinClasses,
21
+ type RenderableContent,
22
+ } from '../utilities/dom.ts';
18
23
  import { randomId } from '../utilities/id.ts';
19
24
  import {
20
25
  type CollapseMotionController,
@@ -124,7 +129,7 @@ const DEFAULT_CLASS_NAMES: AccordionClassNames = {
124
129
  root: 'j-accordion',
125
130
  header: 'accordion-header',
126
131
  title: 'header-title',
127
- arrow: 'header-arrow j-button is-ghost is-sm is-icon',
132
+ arrow: 'header-arrow j-btn is-ghost is-sm is-icon',
128
133
  panel: 'accordion-panel',
129
134
  content: 'panel-content',
130
135
  };
@@ -622,10 +627,17 @@ export function createAccordion(props: AccordionProps): AccordionInstance {
622
627
  return asRenderable(titleView(item.title, item, indexAccessor()));
623
628
  },
624
629
  }),
625
- jsx('span', {
626
- className: resolvedProps.className.arrow,
627
- 'data-accordion-arrow': name,
628
- children: icon('arrow-down'),
630
+ Show({
631
+ when: () => resolvedProps.direction !== 'horizontal',
632
+ children: jsx('span', {
633
+ className: resolvedProps.className.arrow,
634
+ 'data-accordion-arrow': name,
635
+ children: Show({
636
+ when: () => isActive(name),
637
+ children: icon('minus'),
638
+ fallback: icon('add'),
639
+ }),
640
+ }),
629
641
  }),
630
642
  ],
631
643
  }),
@@ -673,10 +685,12 @@ export function createAccordion(props: AccordionProps): AccordionInstance {
673
685
  },
674
686
  view: () => {
675
687
  const root = jsx('div', {
676
- className: resolvedProps.className.root,
688
+ className: joinClasses(
689
+ resolvedProps.className.root,
690
+ resolvedProps.direction === 'horizontal' && 'is-horizontal'
691
+ ),
677
692
  id: resolvedProps.id,
678
693
  'data-accordion': 'root',
679
- 'data-direction': resolvedProps.direction,
680
694
  children: For({
681
695
  each: () => state.data,
682
696
  key: (item: AccordionItem) => itemName(item),
@@ -327,7 +327,7 @@ const DEFAULT_CLASS_NAMES: FlowClassNames = {
327
327
  stepTitle: 'flow-step-title',
328
328
  body: 'flow-body',
329
329
  footer: 'flow-footer',
330
- button: 'j-button',
330
+ button: 'j-btn',
331
331
  reset: 'is-ghost flow-reset',
332
332
  back: 'is-ghost flow-back',
333
333
  next: 'is-solid flow-next',
@@ -198,7 +198,7 @@ const DEFAULT_CLASS_NAMES: FormClassNames = {
198
198
  control: 'field-control',
199
199
  helpInvalid: 'is-invalid',
200
200
  buttons: 'form-buttons',
201
- button: 'j-button',
201
+ button: 'j-btn',
202
202
  submitBtn: 'is-solid',
203
203
  resetBtn: 'is-ghost',
204
204
  input: 'j-input',
@@ -136,7 +136,7 @@ const DEFAULT_CLASS_NAMES: ModalClassNames = {
136
136
  body: 'modal-body',
137
137
  footer: 'modal-footer',
138
138
  title: 'modal-title',
139
- button: 'j-button',
139
+ button: 'j-btn',
140
140
  closeBtn: 'is-icon is-sm is-ghost',
141
141
  cancelBtn: 'is-ghost',
142
142
  confirmBtn: 'is-solid',
@@ -99,7 +99,7 @@ interface OffcanvasRuntimeExtras {
99
99
  const DEFAULT_CLASS_NAMES: OffcanvasClassNames = {
100
100
  root: 'j-offcanvas',
101
101
  overlay: 'j-offcanvas-overlay',
102
- content: 'offcanvas-content',
102
+ content: 'offcanvas-panel',
103
103
  };
104
104
 
105
105
  const OFFCANVAS_HIDDEN_TRANSFORM: Record<OffcanvasDirection, string> = {
@@ -450,7 +450,7 @@ export function createOffcanvas(input: OffcanvasProps = {}): Offcanvas {
450
450
  },
451
451
  children: jsx('div', {
452
452
  className: props.className.content,
453
- 'data-offcanvas-content': props.id,
453
+ 'data-offcanvas-panel': props.id,
454
454
  children: () =>
455
455
  asRenderable(
456
456
  state.loading ? createLoading() : renderResolvedContent()
@@ -100,9 +100,9 @@ const DEFAULT_CLASS_NAMES: PaginationClassNames = {
100
100
  root: 'j-pagination',
101
101
  list: 'pagination',
102
102
  item: 'item',
103
- button: 'j-button is-ghost is-icon',
104
- currentBtn: 'j-button is-outline is-icon is-active',
105
- moreBtn: 'j-button is-ghost is-icon',
103
+ button: 'j-btn is-ghost is-icon',
104
+ currentBtn: 'j-btn is-default is-icon is-active',
105
+ moreBtn: 'j-btn is-ghost is-icon',
106
106
  loading: 'animate-spin',
107
107
  };
108
108
 
@@ -371,10 +371,10 @@ export function createPagination(input: PaginationProps = {}): Pagination {
371
371
  className: props.className.item,
372
372
  'data-pagination-more': () =>
373
373
  itemAccessor().type === 'more' ? itemAccessor().key : null,
374
- children: jsx('span', {
374
+ children: jsx('button', {
375
375
  className: props.className.moreBtn,
376
376
  'aria-disabled': true,
377
- disabled: '',
377
+ disabled: true,
378
378
  children: icon('more'),
379
379
  }),
380
380
  }) as HTMLElement;
@@ -13,6 +13,7 @@ import {
13
13
  type FunctionalComponent,
14
14
  defineComponent,
15
15
  } from '../core/component.ts';
16
+ import { createTransition, type TransitionDefinition } from '../core/motion.ts';
16
17
  import { createLoading } from '../primitives/loading.ts';
17
18
  import {
18
19
  asRenderable,
@@ -35,6 +36,7 @@ export interface TabsClassNames {
35
36
  wrap: string;
36
37
  list: string;
37
38
  tab: string;
39
+ indicator: string;
38
40
  panelWrap: string;
39
41
  panel: string;
40
42
  dragging: string;
@@ -130,9 +132,10 @@ type PointerDragEvent = MouseEvent | TouchEvent;
130
132
  const DEFAULT_CLASS_NAMES: TabsClassNames = {
131
133
  root: 'j-tabs',
132
134
  wrap: 'tab-wrap',
133
- list: 'tab-list',
135
+ list: 'tab-nav',
134
136
  tab: 'tab-item',
135
- panelWrap: 'panel-list',
137
+ indicator: 'tab-indicator',
138
+ panelWrap: 'tab-panel',
136
139
  panel: 'panel-item',
137
140
  dragging: 'dragging',
138
141
  };
@@ -240,6 +243,7 @@ export function createTabs(input: TabsProps = {}): Tabs {
240
243
  const events = createEventManager();
241
244
  const wrapRef = createElementRef<HTMLElement>();
242
245
  const listRef = createElementRef<HTMLElement>();
246
+ const indicatorRef = createElementRef<HTMLElement>();
243
247
  const tabs = createKeyedElementRefs<string, HTMLElement>();
244
248
  const panels = createKeyedElementRefs<string, HTMLElement>();
245
249
  const cache = new Map<string, TabsPanelCacheEntry>();
@@ -250,6 +254,21 @@ export function createTabs(input: TabsProps = {}): Tabs {
250
254
  let inertiaFrame = 0;
251
255
  let resizeFrame = 0;
252
256
  let velocity = 0;
257
+ let indicatorName: string | null = null;
258
+ let resizeObserver: ResizeObserver | null = null;
259
+ const observed = new Set<Element>();
260
+ const indicatorTransition: TransitionDefinition = {
261
+ keyframes: [],
262
+ options: {
263
+ duration: 240,
264
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
265
+ fill: 'none',
266
+ },
267
+ };
268
+ const indicatorMotion = createTransition(
269
+ () => indicatorRef.current,
270
+ indicatorTransition
271
+ );
253
272
 
254
273
  const getIndex = (value: TabsValue): number =>
255
274
  typeof value === 'number'
@@ -299,7 +318,72 @@ export function createTabs(input: TabsProps = {}): Tabs {
299
318
  });
300
319
  }
301
320
  };
302
- const refreshTask = createScheduledTask(refreshDrag);
321
+ const refreshIndicator = (): void => {
322
+ const indicator = indicatorRef.current;
323
+ const list = listRef.current;
324
+ const name = current().name;
325
+ const tab = name ? tabs.get(name) : null;
326
+ if (!indicator || !list) return;
327
+ if (!tab || !list.isConnected) {
328
+ indicatorMotion.cancel();
329
+ indicator.style.display = 'none';
330
+ indicatorName = null;
331
+ return;
332
+ }
333
+ const target = tab.getBoundingClientRect();
334
+ const origin = list.getBoundingClientRect();
335
+ if (!target.width || !target.height) return;
336
+ // Read the visible position before cancelling an interrupted animation.
337
+ const previous = indicator.getBoundingClientRect();
338
+ const animate =
339
+ indicatorName !== null &&
340
+ indicatorName !== name &&
341
+ previous.width > 0 &&
342
+ previous.height > 0;
343
+ const x = target.left - origin.left + list.scrollLeft - list.clientLeft;
344
+ const y = target.top - origin.top + list.scrollTop - list.clientTop;
345
+ const transform = `translate3d(${x}px, ${y}px, 0)`;
346
+ indicatorMotion.cancel();
347
+ Object.assign(indicator.style, {
348
+ display: 'block',
349
+ width: `${target.width}px`,
350
+ height: `${target.height}px`,
351
+ transform,
352
+ });
353
+ indicatorName = name;
354
+ if (animate) {
355
+ indicatorTransition.keyframes = [
356
+ {
357
+ transform: `translate3d(${previous.left - origin.left + list.scrollLeft - list.clientLeft}px, ${previous.top - origin.top + list.scrollTop - list.clientTop}px, 0) scale(${previous.width / target.width}, ${previous.height / target.height})`,
358
+ },
359
+ { transform },
360
+ ];
361
+ void indicatorMotion.enter();
362
+ }
363
+ };
364
+ const refreshTask = createScheduledTask(() => {
365
+ refreshDrag();
366
+ refreshIndicator();
367
+ if (!resizeObserver) return;
368
+ const targets = new Set<Element>([
369
+ ...(listRef.current ? [listRef.current] : []),
370
+ ...(wrapRef.current ? [wrapRef.current] : []),
371
+ ...state.data.flatMap((item) => {
372
+ const tab = tabs.get(item.name as string);
373
+ return tab ? [tab] : [];
374
+ }),
375
+ ]);
376
+ for (const target of observed) {
377
+ if (!targets.has(target)) {
378
+ resizeObserver.unobserve(target);
379
+ observed.delete(target);
380
+ }
381
+ }
382
+ for (const target of targets) {
383
+ if (!observed.has(target)) resizeObserver.observe(target);
384
+ observed.add(target);
385
+ }
386
+ });
303
387
 
304
388
  const startInertia = (): void => {
305
389
  const wrap = wrapRef.current;
@@ -526,6 +610,9 @@ export function createTabs(input: TabsProps = {}): Tabs {
526
610
  };
527
611
  return typeof value === 'function' ? value(context) : value;
528
612
  };
613
+ const text = jsx('span', {
614
+ children: () => asRenderable(title()),
615
+ });
529
616
  return jsx('div', {
530
617
  className: props.className.tab,
531
618
  'data-tabs-tab': name,
@@ -533,7 +620,7 @@ export function createTabs(input: TabsProps = {}): Tabs {
533
620
  'aria-selected': () => (isActive(name) ? 'true' : 'false'),
534
621
  'aria-disabled': () => (isDisabled(name) ? 'true' : 'false'),
535
622
  ref: tabs.bind(name),
536
- children: () => asRenderable(title()),
623
+ children: text,
537
624
  }) as HTMLElement;
538
625
  };
539
626
 
@@ -578,16 +665,37 @@ export function createTabs(input: TabsProps = {}): Tabs {
578
665
  }
579
666
  },
580
667
  view: () => {
668
+ const indicator = jsx('div', {
669
+ className: props.className.indicator,
670
+ 'data-tabs-indicator': '',
671
+ 'aria-hidden': 'true',
672
+ ref: indicatorRef.set,
673
+ style: {
674
+ position: 'absolute',
675
+ top: '0',
676
+ left: '0',
677
+ pointerEvents: 'none',
678
+ transformOrigin: '0 0',
679
+ display: 'none',
680
+ },
681
+ });
682
+ const tabList = For({
683
+ each: renderableData,
684
+ key: (item: TabItem) => item.name,
685
+ children: (item: () => TabItem, index: () => number) =>
686
+ tabView(item, index),
687
+ });
581
688
  createEffect(() => {
582
- const dataLength = state.data.length;
689
+ const names = state.data.map((item) => item.name);
690
+ const active = state.active;
583
691
  refreshTask.schedule();
584
- return dataLength;
692
+ return { names, active };
585
693
  });
586
694
  return jsx('div', {
587
695
  className: props.className.root,
588
696
  id: props.id,
589
697
  'data-tabs': 'root',
590
- 'data-tabs-direction': props.direction,
698
+ 'data-direction': props.direction,
591
699
  children: [
592
700
  jsx('div', {
593
701
  className: props.className.wrap,
@@ -599,19 +707,14 @@ export function createTabs(input: TabsProps = {}): Tabs {
599
707
  props.className.list,
600
708
  state.dragging && props.className.dragging
601
709
  ),
602
- 'data-tabs-list': '',
710
+ 'data-tabs-nav': '',
603
711
  ref: listRef.set,
604
- children: For({
605
- each: renderableData,
606
- key: (item: TabItem) => item.name,
607
- children: (item: () => TabItem, index: () => number) =>
608
- tabView(item, index),
609
- }),
712
+ children: () => [indicator, tabList],
610
713
  }),
611
714
  }),
612
715
  jsx('div', {
613
716
  className: props.className.panelWrap,
614
- 'data-tabs-panel-wrap': '',
717
+ 'data-tabs-panels': '',
615
718
  children: For({
616
719
  each: renderableData,
617
720
  key: (item: TabItem) => item.name,
@@ -633,8 +736,16 @@ export function createTabs(input: TabsProps = {}): Tabs {
633
736
  });
634
737
  events.on('resize', window, 'resize', () => {
635
738
  cancelAnimationFrame(resizeFrame);
636
- resizeFrame = requestAnimationFrame(refreshDrag);
739
+ resizeFrame = requestAnimationFrame(() => refreshTask.schedule());
637
740
  });
741
+ if (typeof ResizeObserver !== 'undefined') {
742
+ resizeObserver = new ResizeObserver(() => refreshTask.schedule());
743
+ context.own(() => {
744
+ resizeObserver?.disconnect();
745
+ resizeObserver = null;
746
+ observed.clear();
747
+ });
748
+ }
638
749
  bindDrag();
639
750
  context.own(() => events.clear());
640
751
  refreshTask.schedule();
@@ -643,8 +754,13 @@ export function createTabs(input: TabsProps = {}): Tabs {
643
754
  onMount() {
644
755
  refreshTask.schedule();
645
756
  },
757
+ onUnmount() {
758
+ indicatorMotion.cancel();
759
+ indicatorName = null;
760
+ },
646
761
  onDestroy() {
647
762
  loadId += 1;
763
+ indicatorMotion.cancel();
648
764
  refreshTask.dispose();
649
765
  cancelAnimationFrame(inertiaFrame);
650
766
  cancelAnimationFrame(resizeFrame);
@@ -1,4 +1,5 @@
1
1
  @layer animation {
2
+
2
3
  /* none */
3
4
  .animate-none {
4
5
  animation: none;
@@ -21,6 +22,7 @@
21
22
  }
22
23
 
23
24
  @keyframes animate-ping {
25
+
24
26
  75%,
25
27
  100% {
26
28
  transform: scale(2);
@@ -45,6 +47,7 @@
45
47
  }
46
48
 
47
49
  @keyframes animate-bounce {
50
+
48
51
  0%,
49
52
  100% {
50
53
  transform: translateY(-25%);
@@ -53,12 +56,12 @@
53
56
 
54
57
  50% {
55
58
  transform: translateY(0);
56
-
57
59
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
58
60
  }
59
61
  }
60
62
 
61
63
  @keyframes animate-bounce {
64
+
62
65
  0%,
63
66
  100% {
64
67
  transform: translateY(-25%);
@@ -67,7 +70,6 @@
67
70
 
68
71
  50% {
69
72
  transform: translateY(0);
70
-
71
73
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
72
74
  }
73
75
  }
@@ -112,6 +114,7 @@
112
114
  }
113
115
 
114
116
  @keyframes animate-shake {
117
+
115
118
  0%,
116
119
  100% {
117
120
  transform: translateX(0);
@@ -131,6 +134,7 @@
131
134
  }
132
135
 
133
136
  @keyframes animate-shake {
137
+
134
138
  0%,
135
139
  100% {
136
140
  transform: translateX(0);
@@ -242,4 +246,4 @@
242
246
  transform: translateY(0);
243
247
  }
244
248
  }
245
- }
249
+ }
package/src/css/card.css CHANGED
@@ -31,7 +31,7 @@
31
31
  color: var(--ui-fg);
32
32
  font-size: var(--font-size-md);
33
33
  font-weight: var(--font-medium);
34
- padding: var(--s3) var(--s4);
34
+ padding: 12px 16px;
35
35
  margin: 0;
36
36
  }
37
37
 
@@ -45,7 +45,7 @@
45
45
  border: none;
46
46
  margin: 0;
47
47
  padding: 0;
48
- padding: var(--space) var(--s2);
48
+ padding: 4px 8px;
49
49
  appearance: none;
50
50
  cursor: pointer;
51
51
  }
@@ -85,7 +85,7 @@
85
85
  }
86
86
 
87
87
  .j-card .card-content {
88
- padding: var(--s4);
88
+ padding: 16px;
89
89
  }
90
90
 
91
91
  .j-card .card-content:last-child,
@@ -106,7 +106,7 @@
106
106
  display: flex;
107
107
  align-items: stretch;
108
108
  overflow: hidden;
109
- gap: var(--s2);
109
+ gap: 8px;
110
110
  }
111
111
 
112
112
  /* vertical */
@@ -117,8 +117,8 @@
117
117
  .j-card.is-vertical .card-header {
118
118
  flex-direction: column;
119
119
  align-items: flex-start;
120
- gap: var(--s2);
121
- padding: var(--s4) var(--s4) 0;
120
+ gap: 8px;
121
+ padding: 16px 16px 0;
122
122
  }
123
123
 
124
124
  .j-card.is-vertical .card-header .header-title {
@@ -137,14 +137,14 @@
137
137
 
138
138
  .j-card .card-footer {
139
139
  border-top: none;
140
- padding: var(--s4);
140
+ padding: 16px;
141
141
  }
142
142
 
143
- .j-card .card-content + .card-footer {
143
+ .j-card .card-content+.card-footer {
144
144
  padding-top: 0;
145
145
  }
146
146
 
147
- .j-card .card-footer:has(.j-button-group) {
147
+ .j-card .card-footer:has(.j-btns) {
148
148
  padding-top: 4px;
149
149
  }
150
- }
150
+ }
package/src/css/font.css CHANGED
@@ -12,13 +12,10 @@
12
12
  }
13
13
 
14
14
  .font-mono {
15
- font-family:
16
- Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
15
+ font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
17
16
  }
18
17
 
19
18
  .font-math {
20
- font-family:
21
- Cambria Math,
22
- Latin Modern Math;
19
+ font-family: Cambria Math, Latin Modern Math;
23
20
  }
24
- }
21
+ }
package/src/css/icon.css CHANGED
@@ -5,21 +5,17 @@
5
5
 
6
6
  /* close icon */
7
7
  .icon-close {
8
- box-sizing: border-box;
9
8
  position: relative;
10
9
  display: block;
11
- transform: scale(1);
12
10
  width: var(--font-size-xl);
13
11
  height: var(--font-size-xl);
14
12
  color: inherit;
15
- cursor: pointer;
16
13
  }
17
14
 
18
15
  .icon-close::after,
19
16
  .icon-close::before {
20
17
  content: '';
21
18
  position: absolute;
22
- box-sizing: border-box;
23
19
  top: 50%;
24
20
  left: 50%;
25
21
  width: 12px;
@@ -37,20 +33,7 @@
37
33
  transform: translate(-50%, -50%) rotate(-45deg);
38
34
  }
39
35
 
40
- .icon-close:active {
41
- transform: translateY(1px);
42
- }
43
-
44
- .icon-close:focus-within {
36
+ /* .icon-close:focus-within {
45
37
  background-color: var(--tone-subtle);
46
- }
47
-
48
- /* icon status */
49
- .el-icon[data-action='close'] {
50
- cursor: pointer;
51
- }
52
-
53
- .el-icon[data-action='close']:active {
54
- transform: scale(0.85);
55
- }
56
- }
38
+ } */
39
+ }
@@ -104,11 +104,9 @@
104
104
  linear-gradient(to right, var(--ui-surface-subtle) 1px, transparent 1px),
105
105
  linear-gradient(to bottom, var(--ui-surface-subtle) 1px, transparent 1px);
106
106
  background-size: 40px 56px;
107
- mask-image: radial-gradient(
108
- ellipse 25% 10% at 50% 0%,
109
- #000 60%,
110
- transparent 300%
111
- );
107
+ mask-image: radial-gradient(ellipse 25% 10% at 50% 0%,
108
+ #000 60%,
109
+ transparent 300%);
112
110
  pointer-events: none;
113
111
  user-select: none;
114
112
  }
@@ -123,11 +121,9 @@
123
121
  .placeholder-image {
124
122
  width: 100%;
125
123
  height: 100%;
126
- background: linear-gradient(
127
- 135deg,
128
- var(--ui-bg-muted) 0%,
129
- var(--ui-surface-subtle) 100%
130
- );
124
+ background: linear-gradient(135deg,
125
+ var(--ui-bg-muted) 0%,
126
+ var(--ui-surface-subtle) 100%);
131
127
  color: var(--ui-fg-subtle);
132
128
  font-size: var(--font-size-sm);
133
129
  display: flex;
@@ -155,7 +151,7 @@
155
151
  /* 容器:居中 + 最大宽度 */
156
152
  .container {
157
153
  width: 100%;
158
- max-width: var(--screen-xl, 1200px);
154
+ max-width: var(--screen-xl);
159
155
  /* margin-inline: auto; */
160
156
  /* padding-inline: 1rem; */
161
157
  margin: 0 auto;
@@ -267,10 +263,7 @@
267
263
  .flex-col-10,
268
264
  .flex-col-11,
269
265
  .flex-col-12 {
270
- width: calc(
271
- (100% + var(--flex-container-gap, 1rem)) / var(--cols) * var(--span) -
272
- var(--flex-container-gap, 1rem)
273
- );
266
+ width: calc((100% + var(--flex-container-gap, 1rem)) / var(--cols) * var(--span) - var(--flex-container-gap, 1rem));
274
267
  }
275
268
 
276
269
  /* 关键:禁用 flex-basis 的自动收缩/拉伸,仅用 width 控制 */
@@ -553,7 +546,7 @@
553
546
  /* Grid 容器:自动 gap + 响应式列 */
554
547
  .grid-container {
555
548
  display: grid;
556
- gap: var(--grid-container-gap, var(--s2));
549
+ gap: var(--grid-container-gap, 8px);
557
550
  width: 100%;
558
551
  /* 默认:单列(移动端友好) */
559
552
  grid-template-columns: 1fr;
@@ -972,7 +965,7 @@
972
965
  .j-popup-layout {
973
966
  background: var(--ui-popup-bg);
974
967
  backdrop-filter: blur(4px);
975
- padding: var(--s4);
968
+ padding: 16px;
976
969
 
977
970
  display: flex;
978
971
  position: fixed;
@@ -1037,4 +1030,4 @@
1037
1030
  justify-content: flex-end;
1038
1031
  align-items: flex-end;
1039
1032
  }
1040
- }
1033
+ }