@dnax/ui 0.0.42 → 0.0.44

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/styles/main.css CHANGED
@@ -203,31 +203,66 @@ body {
203
203
  border-color: rgb(244 67 54 / 0.4);
204
204
  }
205
205
 
206
- /* ===== Tokens de couleur (palette Material façon Quasar) ===== */
207
- :root {
208
- --primary: #1976d2;
209
- --primary-foreground: #fff;
210
- --secondary: #26a69a;
211
- --secondary-foreground: #fff;
212
- --accent: #9c27b0;
213
- --accent-foreground: #fff;
214
- --dark: #1d1d1d;
215
- --dark-foreground: #fff;
216
- --positive: #21ba45;
217
- --positive-foreground: #fff;
218
- --negative: #c10015;
219
- --negative-foreground: #fff;
220
- --info: #31ccec;
221
- --info-foreground: #fff;
222
- --warning: #f2c037;
223
- --warning-foreground: #1d1d1d;
224
-
225
- /* Tokens sémantiques (utilisés par le mode sombre) */
226
- --background: #ffffff;
227
- --foreground: #1d1d1d;
228
- --card: #ffffff;
229
- --muted: #f4f6f9;
230
- --border: rgb(0 0 0 / 0.12);
206
+ /* ===== Tokens de couleur (palette Material façon Quasar) =====
207
+ Déclarés dans `@layer dnax-tokens` : une règle hors couche (le thème de
208
+ l'application hôte) gagne toujours sur une règle en couche, quelle que soit
209
+ la spécificité et l'ordre d'émission. Sans cette couche, ce `:root` — émis
210
+ *après* le CSS de l'hôte — écrasait ses tokens de même nom (`--primary`,
211
+ `--accent`, `--muted`, `--border`…). C'est ce qui faisait apparaître le
212
+ violet `--accent: #9c27b0` dans les docs à thème bleu (Docd/Docus).
213
+ Attention : les noms shadcn n'ont pas le même sens ici (`--accent` = couleur
214
+ d'accent Material, pas la surface de survol shadcn). */
215
+ @layer dnax-tokens {
216
+ :root {
217
+ --primary: #1976d2;
218
+ --primary-foreground: #fff;
219
+ --secondary: #26a69a;
220
+ --secondary-foreground: #fff;
221
+ --accent: #9c27b0;
222
+ --accent-foreground: #fff;
223
+ --dark: #1d1d1d;
224
+ --dark-foreground: #fff;
225
+ --positive: #21ba45;
226
+ --positive-foreground: #fff;
227
+ --negative: #c10015;
228
+ --negative-foreground: #fff;
229
+ --info: #31ccec;
230
+ --info-foreground: #fff;
231
+ --warning: #f2c037;
232
+ --warning-foreground: #1d1d1d;
233
+
234
+ /* Tokens sémantiques (utilisés par le mode sombre) */
235
+ --background: #ffffff;
236
+ --foreground: #1d1d1d;
237
+ --card: #ffffff;
238
+ --muted: #f4f6f9;
239
+ --border: rgb(0 0 0 / 0.12);
240
+
241
+ /* Palette des séries de <q-chart> (convention `--chart-N`, reprise de shadcn) :
242
+ ce sont les SEULES couleurs de la palette Material à être faites pour ça —
243
+ `--secondary` et `--accent` sont des surfaces chez shadcn-vue, pas des
244
+ couleurs de série (une ligne de leur couleur serait invisible). */
245
+ --chart-1: #1976d2;
246
+ --chart-2: #26a69a;
247
+ --chart-3: #9c27b0;
248
+ --chart-4: #31ccec;
249
+ --chart-5: #21ba45;
250
+ --chart-6: #f2c037;
251
+ }
252
+
253
+ /* Mode sombre : mêmes règles de priorité que ci-dessus. */
254
+ .dark {
255
+ --background: #0f1115;
256
+ --foreground: #e6edf3;
257
+ --card: #161b22;
258
+ --muted: #1c2128;
259
+ --border: rgb(255 255 255 / 0.12);
260
+ --q-table-border: rgb(255 255 255 / 0.12);
261
+ --q-table-header-bg: rgb(255 255 255 / 0.04);
262
+ --q-table-hover-bg: rgb(255 255 255 / 0.06);
263
+ --q-sidebar-border: rgb(255 255 255 / 0.12);
264
+ --q-translucent-bg: #0f1115;
265
+ }
231
266
  }
232
267
 
233
268
  /* ===== Mode sombre (QConfigProvider mode="dark" | "system") =====
@@ -235,16 +270,6 @@ body {
235
270
  Les overlays téléportés au body (dialog, sheets) sont couverts via html.dark. */
236
271
  .dark {
237
272
  color-scheme: dark;
238
- --background: #0f1115;
239
- --foreground: #e6edf3;
240
- --card: #161b22;
241
- --muted: #1c2128;
242
- --border: rgb(255 255 255 / 0.12);
243
- --q-table-border: rgb(255 255 255 / 0.12);
244
- --q-table-header-bg: rgb(255 255 255 / 0.04);
245
- --q-table-hover-bg: rgb(255 255 255 / 0.06);
246
- --q-sidebar-border: rgb(255 255 255 / 0.12);
247
- --q-translucent-bg: #0f1115;
248
273
  }
249
274
 
250
275
  /* Surface de base : le conteneur et la page (html.dark body) */
@@ -5541,6 +5566,57 @@ a.q-breadcrumbs__el:hover {
5541
5566
  overflow-y: auto;
5542
5567
  }
5543
5568
 
5569
+ /* — mode popover : panneau ancré au champ, sans voile — */
5570
+ /* `top`/`bottom`/`left` sont posés en inline par `positionPopover()` : le panneau
5571
+ suit le champ au scroll et bascule au-dessus quand la place manque. */
5572
+ .q-date-picker__overlay--popover {
5573
+ inset: auto;
5574
+ display: block;
5575
+ width: max-content;
5576
+ background-color: transparent;
5577
+ }
5578
+
5579
+ /* Flèche (caret) : portée par le voile et non par le panneau — `.q-date-picker__sheet`
5580
+ est en `overflow: hidden` et la rognerait. Elle est peinte *avant* le panneau (ordre
5581
+ du DOM) : seule sa moitié dépassante reste visible, le reste passe sous le bord. */
5582
+ .q-date-picker__overlay--popover::before {
5583
+ content: "";
5584
+ position: absolute;
5585
+ top: -5px;
5586
+ left: var(--q-date-picker-caret, 24px);
5587
+ width: 10px;
5588
+ height: 10px;
5589
+ margin-left: -5px;
5590
+ background-color: #fff;
5591
+ border-top: 1px solid rgb(0 0 0 / 0.08);
5592
+ border-left: 1px solid rgb(0 0 0 / 0.08);
5593
+ transform: rotate(45deg);
5594
+ }
5595
+
5596
+ .q-date-picker__overlay--popover-up::before {
5597
+ top: auto;
5598
+ bottom: -5px;
5599
+ border: none;
5600
+ border-right: 1px solid rgb(0 0 0 / 0.08);
5601
+ border-bottom: 1px solid rgb(0 0 0 / 0.08);
5602
+ }
5603
+
5604
+ .q-date-picker__sheet--popover {
5605
+ width: 360px;
5606
+ max-width: calc(100vw - 16px);
5607
+ border: 1px solid rgb(0 0 0 / 0.08);
5608
+ box-shadow: 0 10px 32px rgb(0 0 0 / 0.16);
5609
+ }
5610
+
5611
+ .dark .q-date-picker__overlay--popover::before {
5612
+ background-color: var(--card);
5613
+ border-color: rgb(255 255 255 / 0.12);
5614
+ }
5615
+
5616
+ .dark .q-date-picker__sheet--popover {
5617
+ border-color: rgb(255 255 255 / 0.12);
5618
+ }
5619
+
5544
5620
  /* — calendrier — */
5545
5621
  .q-date-calendar {
5546
5622
  display: flex;
@@ -5561,6 +5637,34 @@ a.q-breadcrumbs__el:hover {
5561
5637
  font-weight: 600;
5562
5638
  }
5563
5639
 
5640
+ /* En-tête cliquable (prop `month-dropdown`) : même poids que le libellé simple */
5641
+ .q-date-calendar__nav-label--button {
5642
+ display: inline-flex;
5643
+ align-items: center;
5644
+ gap: 4px;
5645
+ padding: 4px 8px;
5646
+ border: none;
5647
+ border-radius: 8px;
5648
+ background: transparent;
5649
+ color: inherit;
5650
+ font: inherit;
5651
+ font-size: 14px;
5652
+ font-weight: 600;
5653
+ cursor: pointer;
5654
+ transition: background-color 0.15s ease;
5655
+ }
5656
+
5657
+ .q-date-calendar__nav-label--button:hover,
5658
+ .q-date-calendar__nav-label--open {
5659
+ background-color: rgb(0 0 0 / 0.06);
5660
+ }
5661
+
5662
+ .q-date-calendar__nav-caret {
5663
+ width: 14px;
5664
+ height: 14px;
5665
+ opacity: 0.65;
5666
+ }
5667
+
5564
5668
  .q-date-calendar__nav-btn {
5565
5669
  display: inline-flex;
5566
5670
  align-items: center;
@@ -5659,6 +5763,88 @@ a.q-breadcrumbs__el:hover {
5659
5763
  background-color: var(--primary);
5660
5764
  }
5661
5765
 
5766
+ /* — choix du mois / de l'année (en-tête cliquable) — */
5767
+ .q-date-calendar__picker {
5768
+ display: flex;
5769
+ flex-direction: column;
5770
+ gap: 8px;
5771
+ padding: 2px 0;
5772
+ }
5773
+
5774
+ .q-date-calendar__picker-year {
5775
+ display: flex;
5776
+ align-items: center;
5777
+ justify-content: space-between;
5778
+ }
5779
+
5780
+ .q-date-calendar__picker-year-label {
5781
+ font-size: 14px;
5782
+ font-weight: 600;
5783
+ }
5784
+
5785
+ .q-date-calendar__picker-months {
5786
+ display: grid;
5787
+ grid-template-columns: repeat(3, 1fr);
5788
+ gap: 4px;
5789
+ }
5790
+
5791
+ .q-date-calendar__picker-month {
5792
+ padding: 8px 0;
5793
+ border: none;
5794
+ border-radius: 8px;
5795
+ background: transparent;
5796
+ color: inherit;
5797
+ font: inherit;
5798
+ font-size: 13px;
5799
+ cursor: pointer;
5800
+ transition: background-color 0.15s ease;
5801
+ }
5802
+
5803
+ .q-date-calendar__picker-month:hover {
5804
+ background-color: rgb(0 0 0 / 0.06);
5805
+ }
5806
+
5807
+ .q-date-calendar__picker-month--current {
5808
+ background-color: var(--primary);
5809
+ color: var(--primary-foreground);
5810
+ font-weight: 600;
5811
+ }
5812
+
5813
+ .q-date-calendar__picker-month--current:hover {
5814
+ background-color: var(--primary);
5815
+ }
5816
+
5817
+ /* — raccourci « Today » (prop `today-btn`) : bord à bord dans le panneau — */
5818
+ .q-date-calendar__footer {
5819
+ display: flex;
5820
+ justify-content: flex-end;
5821
+ margin: 0 -12px -12px;
5822
+ padding: 8px 12px;
5823
+ border-top: 1px solid rgb(0 0 0 / 0.08);
5824
+ }
5825
+
5826
+ .q-date-calendar__today {
5827
+ padding: 2px 6px;
5828
+ border: none;
5829
+ border-radius: 6px;
5830
+ background: transparent;
5831
+ color: var(--primary);
5832
+ font: inherit;
5833
+ font-size: 13px;
5834
+ font-weight: 500;
5835
+ cursor: pointer;
5836
+ transition: background-color 0.15s ease;
5837
+ }
5838
+
5839
+ .q-date-calendar__today:hover {
5840
+ background-color: rgb(0 0 0 / 0.04);
5841
+ }
5842
+
5843
+ .q-date-calendar__today:disabled {
5844
+ opacity: 0.4;
5845
+ cursor: default;
5846
+ }
5847
+
5662
5848
  /* — transition panneau — */
5663
5849
  .q-date-modal-enter-active,
5664
5850
  .q-date-modal-leave-active {
@@ -5678,6 +5864,36 @@ a.q-breadcrumbs__el:hover {
5678
5864
  animation: q-sheet-pop-out 0.2s ease forwards;
5679
5865
  }
5680
5866
 
5867
+ /* — transition popover : le panneau entre par le bas (ou par le haut s'il est basculé) — */
5868
+ .q-date-popover-enter-active,
5869
+ .q-date-popover-leave-active {
5870
+ transition: opacity 0.12s ease;
5871
+ }
5872
+
5873
+ .q-date-popover-enter-from,
5874
+ .q-date-popover-leave-to {
5875
+ opacity: 0;
5876
+ }
5877
+
5878
+ .q-date-popover-enter-active .q-date-picker__sheet {
5879
+ animation: q-popup-in 0.12s ease;
5880
+ }
5881
+
5882
+ .q-date-popover-leave-active .q-date-picker__sheet {
5883
+ animation: q-date-popover-out 0.1s ease forwards;
5884
+ }
5885
+
5886
+ .q-date-picker__overlay--popover-up.q-date-popover-enter-active .q-date-picker__sheet {
5887
+ animation: q-popup-in-up 0.12s ease;
5888
+ }
5889
+
5890
+ @keyframes q-date-popover-out {
5891
+ to {
5892
+ opacity: 0;
5893
+ transform: translateY(-4px);
5894
+ }
5895
+ }
5896
+
5681
5897
  /* ===== QCountryPicker : panneaux sheet / modal / dialog ===== */
5682
5898
  .q-country-picker__overlay {
5683
5899
  position: fixed;
@@ -9416,101 +9632,6 @@ a.q-breadcrumbs__el:hover {
9416
9632
  border-radius: 50%;
9417
9633
  }
9418
9634
 
9419
- /* ===== QEditorJs (Editor.js, éditeur par blocs) ===== */
9420
- .q-editor-js {
9421
- border: 1px solid var(--border, rgb(0 0 0 / 0.12));
9422
- border-radius: var(--q-radius, 12px);
9423
- background: var(--card, #ffffff);
9424
- color: var(--foreground, #1d1d1d);
9425
- overflow: hidden;
9426
- transition: border-color 0.15s ease;
9427
- }
9428
- .q-editor-js:focus-within {
9429
- border-color: var(--primary, #1976d2);
9430
- }
9431
- .q-editor-js--disable {
9432
- opacity: 0.7;
9433
- pointer-events: none;
9434
- }
9435
- .q-editor-js__holder {
9436
- padding: 14px 16px;
9437
- }
9438
- .q-editor-js .codex-editor__redactor {
9439
- padding-bottom: 40px;
9440
- }
9441
- .q-editor-js .ce-block__content,
9442
- .q-editor-js .ce-toolbar__content {
9443
- max-width: none;
9444
- }
9445
- .q-editor-js .ce-block {
9446
- margin-bottom: 8px;
9447
- }
9448
- .q-editor-js .ce-paragraph {
9449
- color: var(--foreground, #1d1d1d);
9450
- font-size: 14px;
9451
- line-height: 1.7;
9452
- outline: none;
9453
- }
9454
- .q-editor-js .ce-paragraph[data-placeholder]:empty::before {
9455
- color: var(--muted, #8b93a1);
9456
- }
9457
- .q-editor-js .ce-header {
9458
- color: var(--foreground, #1d1d1d);
9459
- font-weight: 700;
9460
- line-height: 1.3;
9461
- }
9462
- .q-editor-js h1.ce-header {
9463
- font-size: 1.55em;
9464
- }
9465
- .q-editor-js h2.ce-header {
9466
- font-size: 1.3em;
9467
- }
9468
- .q-editor-js h3.ce-header {
9469
- font-size: 1.1em;
9470
- }
9471
- .q-editor-js .cdx-list {
9472
- color: var(--foreground, #1d1d1d);
9473
- line-height: 1.7;
9474
- }
9475
- .q-editor-js .cdx-checklist {
9476
- color: var(--foreground, #1d1d1d);
9477
- }
9478
- .q-editor-js .ce-code__textarea {
9479
- background: color-mix(in srgb, var(--foreground, #1d1d1d) 6%, transparent);
9480
- color: var(--foreground, #1d1d1d);
9481
- border: 1px solid var(--border, rgb(0 0 0 / 0.12));
9482
- border-radius: 8px;
9483
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
9484
- }
9485
- .q-editor-js .cdx-quote {
9486
- margin: 0;
9487
- padding: 10px 14px;
9488
- border-left: 3px solid var(--primary, #1976d2);
9489
- background: color-mix(in srgb, var(--primary, #1976d2) 8%, transparent);
9490
- color: var(--foreground, #1d1d1d);
9491
- border-radius: 0 8px 8px 0;
9492
- }
9493
- .q-editor-js .ce-toolbar__plus,
9494
- .q-editor-js .ce-toolbar__settings-btn {
9495
- color: var(--foreground, #1d1d1d);
9496
- }
9497
- .q-editor-js .ce-toolbar__plus:hover,
9498
- .q-editor-js .ce-toolbar__settings-btn:hover {
9499
- color: var(--primary, #1976d2);
9500
- }
9501
- .q-editor-js .ce-inline-toolbar,
9502
- .q-editor-js .ce-conv-toolbar,
9503
- .q-editor-js .ce-toolbox__button,
9504
- .q-editor-js .ce-popover {
9505
- background: var(--card, #ffffff);
9506
- color: var(--foreground, #1d1d1d);
9507
- border: 1px solid var(--border, rgb(0 0 0 / 0.12));
9508
- }
9509
- .q-editor-js .ce-toolbox__button--active,
9510
- .q-editor-js .ce-inline-tool--active {
9511
- color: var(--primary, #1976d2);
9512
- }
9513
-
9514
9635
  /* NodeView Vue de la table : wrapper + table + tbody (contentDOM) */
9515
9636
  .q-tiptap__editor .ProseMirror .q-tiptap__table-wrapper {
9516
9637
  position: relative;
@@ -1,146 +0,0 @@
1
- <script setup lang="ts">
2
- // QEditorJs — éditeur par blocs basé sur Editor.js (https://editorjs.io).
3
- // v-model = données JSON : { time?, blocks: [{ type, data }], version? }.
4
- // Tools par défaut : paragraph, header (H1-H3), list (bullet/ordered),
5
- // checklist, quote, code, delimiter. Extensible via la prop `tools`.
6
- // SSR-safe : l'instance Editor.js n'est créée qu'au montage (client).
7
- // Note : Editor.js v2 injecte lui-même ses styles à l'init (aucun import CSS
8
- // nécessaire) ; les surcharges de thème vivent dans styles/main.css.
9
- import { onBeforeUnmount, onMounted, ref, watch } from "vue"
10
-
11
- interface QEditorJsBlock {
12
- type: string
13
- data: Record<string, unknown>
14
- }
15
-
16
- interface QEditorJsData {
17
- time?: number
18
- blocks: QEditorJsBlock[]
19
- version?: string
20
- }
21
-
22
- interface Props {
23
- /** Données du document (v-model) — { blocks: [{ type, data }] } */
24
- data?: QEditorJsData | null
25
- /** Placeholder du bloc par défaut */
26
- placeholder?: string
27
- /** Hauteur minimale de la zone d'édition (défaut : 220px) */
28
- minHeight?: string
29
- /** Lecture seule */
30
- readonly?: boolean
31
- /** Désactivé (lecture seule + style grisé) */
32
- disable?: boolean
33
- /** Tools supplémentaires (défaut : paragraph, header, list, checklist, quote, code, delimiter) */
34
- tools?: Record<string, any>
35
- }
36
-
37
- const props = withDefaults(defineProps<Props>(), {
38
- data: null,
39
- placeholder: "Write something…",
40
- minHeight: "220px",
41
- readonly: false,
42
- disable: false,
43
- tools: () => ({}),
44
- })
45
-
46
- const emit = defineEmits<{
47
- "update:modelValue": [data: QEditorJsData]
48
- ready: [editor: unknown]
49
- }>()
50
-
51
- const holderEl = ref<HTMLElement | null>(null)
52
- let editor: any = null
53
- let lastJson = ""
54
- let internal = false
55
-
56
- const isEditable = () => !props.readonly && !props.disable
57
-
58
- const emitData = async () => {
59
- if (!editor) return
60
- try {
61
- const saved: QEditorJsData = (await editor.save()) as QEditorJsData
62
- internal = true
63
- lastJson = JSON.stringify(saved)
64
- emit("update:modelValue", saved)
65
- internal = false
66
- }
67
- catch {
68
- /* document invalide — ignoré */
69
- }
70
- }
71
-
72
- onMounted(async () => {
73
- const mod = await import("@editorjs/editorjs")
74
- const EditorJS = mod.default
75
- // Les packages tools Editor.js n'embarquent pas tous des types TS
76
- // @ts-ignore
77
- const Header = (await import("@editorjs/header")).default
78
- // @ts-ignore
79
- const Paragraph = (await import("@editorjs/paragraph")).default
80
- // @ts-ignore
81
- const List = (await import("@editorjs/list")).default
82
- // @ts-ignore
83
- const Checklist = (await import("@editorjs/checklist")).default
84
- // @ts-ignore
85
- const Quote = (await import("@editorjs/quote")).default
86
- // @ts-ignore
87
- const Code = (await import("@editorjs/code")).default
88
- // @ts-ignore
89
- const Delimiter = (await import("@editorjs/delimiter")).default
90
-
91
- const defaults: Record<string, any> = {
92
- paragraph: { class: Paragraph },
93
- header: { class: Header, inlineToolbar: true, config: { levels: [1, 2, 3] } },
94
- list: { class: List, inlineToolbar: true },
95
- checklist: { class: Checklist, inlineToolbar: true },
96
- quote: { class: Quote, inlineToolbar: true },
97
- code: { class: Code },
98
- delimiter: { class: Delimiter },
99
- }
100
-
101
- editor = new EditorJS({
102
- holder: holderEl.value as HTMLElement,
103
- tools: { ...defaults, ...props.tools },
104
- data: props.data ?? undefined,
105
- placeholder: props.placeholder,
106
- readOnly: !isEditable(),
107
- onChange: () => { emitData() },
108
- onReady: () => { emit("ready", editor) },
109
- })
110
- emit("ready", editor)
111
- })
112
-
113
- // Changement externe → render (sans boucle : on compare au dernier JSON émis)
114
- watch(
115
- () => props.data,
116
- (value) => {
117
- if (internal || !editor) return
118
- const json = value ? JSON.stringify(value) : ""
119
- if (json === lastJson) return
120
- editor.render(value ?? { time: Date.now(), blocks: [], version: "2.31.6" })
121
- .then(() => { lastJson = json })
122
- .catch(() => { /* ignore */ })
123
- },
124
- )
125
-
126
- onBeforeUnmount(() => {
127
- if (editor && typeof editor.destroy === "function") editor.destroy()
128
- editor = null
129
- })
130
-
131
- // — Méthodes exposées —
132
- const save = () => editor?.save() as Promise<QEditorJsData> | undefined
133
- const clear = () => editor?.clear()
134
- const getEditor = () => editor
135
-
136
- defineExpose({ save, clear, getEditor })
137
- </script>
138
-
139
- <template>
140
- <div
141
- class="q-editor-js"
142
- :class="{ 'q-editor-js--readonly': readonly || disable, 'q-editor-js--disable': disable }"
143
- >
144
- <div ref="holderEl" class="q-editor-js__holder" :style="{ minHeight }" />
145
- </div>
146
- </template>