@tekkare/romulus 0.1.78 → 0.1.80
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/dist/module.json +1 -1
- package/dist/runtime/components/ComplexSelect.vue +70 -31
- package/dist/runtime/components/DropdownSelect.vue +6 -5
- package/dist/runtime/components/FilterBar.vue +1 -1
- package/dist/runtime/components/Icon.vue +47 -13
- package/dist/runtime/components/MultipleSelect.vue +9 -8
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
-->
|
|
28
28
|
<script setup lang="ts">
|
|
29
29
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
30
|
+
import { PhCaretDown, PhInfo, PhMagnifyingGlass, PhMinusCircle, PhPlusCircle } from '@phosphor-icons/vue'
|
|
30
31
|
import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
|
|
31
32
|
|
|
32
33
|
export interface RmComplexSelectPreset {
|
|
@@ -34,10 +35,20 @@ export interface RmComplexSelectPreset {
|
|
|
34
35
|
values: string[]
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Une option dont le libelle differe de la valeur retenue : la liste montre
|
|
40
|
+
* « KEYTRUDA », le filtre porte sur le code. Une chaine seule vaut pour les
|
|
41
|
+
* deux.
|
|
42
|
+
*/
|
|
43
|
+
export interface RmComplexSelectOption {
|
|
44
|
+
label: string
|
|
45
|
+
value: string
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
const props = withDefaults(defineProps<{
|
|
38
49
|
/** Intitule pose au-dessus du champ. */
|
|
39
50
|
label: string
|
|
40
|
-
options: string[]
|
|
51
|
+
options: (string | RmComplexSelectOption)[]
|
|
41
52
|
loading?: boolean
|
|
42
53
|
disabled?: boolean
|
|
43
54
|
/** Selections rapides. Vides, la section ne sort pas. */
|
|
@@ -95,6 +106,18 @@ const emit = defineEmits<{
|
|
|
95
106
|
}>()
|
|
96
107
|
|
|
97
108
|
const selected = defineModel<string[]>({ default: () => [] })
|
|
109
|
+
/**
|
|
110
|
+
* Saisie de la colonne « ajouter ». Exposee pour que la page aille chercher
|
|
111
|
+
* les options correspondantes quand la liste vient du serveur.
|
|
112
|
+
*/
|
|
113
|
+
const addSearch = defineModel<string>('search', { default: '' })
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Ce qui est tape, avant amortissement. Le modele `search` ne recoit la
|
|
117
|
+
* saisie qu'une fois la frappe finie : la page s'en sert pour interroger
|
|
118
|
+
* l'index, et une requete par lettre le noierait.
|
|
119
|
+
*/
|
|
120
|
+
const addInput = ref('')
|
|
98
121
|
|
|
99
122
|
const WORDS = {
|
|
100
123
|
fr: {
|
|
@@ -130,7 +153,6 @@ const WORDS = {
|
|
|
130
153
|
const t = computed(() => WORDS[props.lang])
|
|
131
154
|
|
|
132
155
|
const isOpen = ref(false)
|
|
133
|
-
const addSearch = ref('')
|
|
134
156
|
const removeSearch = ref('')
|
|
135
157
|
const activePreset = ref<string>()
|
|
136
158
|
const alignRight = ref(false)
|
|
@@ -151,23 +173,37 @@ function placePanel() {
|
|
|
151
173
|
alignRight.value = rect.left + PANEL_WIDTH > window.innerWidth - 8
|
|
152
174
|
}
|
|
153
175
|
|
|
176
|
+
/** Les chaines nues valent libelle et valeur a la fois. */
|
|
177
|
+
const allOptions = computed<RmComplexSelectOption[]>(() =>
|
|
178
|
+
props.options.map(option =>
|
|
179
|
+
typeof option === 'string' ? { label: option, value: option } : option,
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
/** Le libelle d'une valeur retenue, meme si elle a quitte la liste. */
|
|
184
|
+
const labelOf = computed(() => {
|
|
185
|
+
const map = new Map(allOptions.value.map(option => [option.value, option.label]))
|
|
186
|
+
return (value: string) => map.get(value) ?? value
|
|
187
|
+
})
|
|
188
|
+
|
|
154
189
|
/** La colonne de gauche ne propose que ce qui n'est pas deja retenu. */
|
|
155
190
|
const addOptions = computed(() => {
|
|
156
|
-
const needle =
|
|
191
|
+
const needle = addInput.value.trim().toLowerCase()
|
|
157
192
|
const parts = needle && props.filterSearch ? needle.split(' ').filter(Boolean) : []
|
|
158
|
-
return
|
|
159
|
-
.filter(option => !selected.value.includes(option))
|
|
160
|
-
.filter(option => parts.every(part => option.toLowerCase().includes(part)))
|
|
193
|
+
return allOptions.value
|
|
194
|
+
.filter(option => !selected.value.includes(option.value))
|
|
195
|
+
.filter(option => parts.every(part => option.label.toLowerCase().includes(part)))
|
|
161
196
|
.slice(0, props.maxOptions)
|
|
162
197
|
})
|
|
163
198
|
|
|
164
|
-
const removeOptions = computed(() => {
|
|
199
|
+
const removeOptions = computed<RmComplexSelectOption[]>(() => {
|
|
200
|
+
const chosen = selected.value.map(value => ({ label: labelOf.value(value), value }))
|
|
165
201
|
const needle = removeSearch.value.trim().toLowerCase()
|
|
166
|
-
if (!needle) return
|
|
167
|
-
return
|
|
202
|
+
if (!needle) return chosen
|
|
203
|
+
return chosen.filter(option => option.label.toLowerCase().includes(needle))
|
|
168
204
|
})
|
|
169
205
|
|
|
170
|
-
const summary = computed(() => selected.value.join(', '))
|
|
206
|
+
const summary = computed(() => selected.value.map(value => labelOf.value(value)).join(', '))
|
|
171
207
|
|
|
172
208
|
const selectAllLabel = computed(() => {
|
|
173
209
|
if (!props.selectAllCount) return t.value.all
|
|
@@ -176,9 +212,12 @@ const selectAllLabel = computed(() => {
|
|
|
176
212
|
})
|
|
177
213
|
|
|
178
214
|
let debounceId: ReturnType<typeof setTimeout> | undefined
|
|
179
|
-
watch(
|
|
215
|
+
watch(addInput, (value) => {
|
|
180
216
|
clearTimeout(debounceId)
|
|
181
|
-
debounceId = setTimeout(() =>
|
|
217
|
+
debounceId = setTimeout(() => {
|
|
218
|
+
addSearch.value = value
|
|
219
|
+
emit('search', value)
|
|
220
|
+
}, 500)
|
|
182
221
|
})
|
|
183
222
|
|
|
184
223
|
function close() {
|
|
@@ -207,19 +246,19 @@ function commit(values: string[]) {
|
|
|
207
246
|
emit('change', values)
|
|
208
247
|
}
|
|
209
248
|
|
|
210
|
-
function add(
|
|
249
|
+
function add(value: string) {
|
|
211
250
|
activePreset.value = undefined
|
|
212
|
-
commit([...selected.value,
|
|
251
|
+
commit([...selected.value, value])
|
|
213
252
|
}
|
|
214
253
|
|
|
215
|
-
function remove(
|
|
254
|
+
function remove(value: string) {
|
|
216
255
|
activePreset.value = undefined
|
|
217
|
-
commit(selected.value.filter(
|
|
256
|
+
commit(selected.value.filter(kept => kept !== value))
|
|
218
257
|
}
|
|
219
258
|
|
|
220
259
|
function addAll() {
|
|
221
260
|
activePreset.value = undefined
|
|
222
|
-
commit([...selected.value, ...addOptions.value])
|
|
261
|
+
commit([...selected.value, ...addOptions.value.map(option => option.value)])
|
|
223
262
|
}
|
|
224
263
|
|
|
225
264
|
function clearAll() {
|
|
@@ -254,7 +293,7 @@ onUnmounted(() => {
|
|
|
254
293
|
<p class="rm-csel__label">
|
|
255
294
|
{{ label }}
|
|
256
295
|
<button v-if="labelInfo" type="button" class="rm-csel__info" @click="emit('openInfo')">
|
|
257
|
-
<
|
|
296
|
+
<PhInfo :size="14" />
|
|
258
297
|
</button>
|
|
259
298
|
</p>
|
|
260
299
|
|
|
@@ -275,7 +314,7 @@ onUnmounted(() => {
|
|
|
275
314
|
<span v-if="showAmount && selected.length > 0" class="rm-csel__count">
|
|
276
315
|
{{ selected.length > 99 ? '99+' : selected.length }}
|
|
277
316
|
</span>
|
|
278
|
-
<
|
|
317
|
+
<PhCaretDown :size="16" />
|
|
279
318
|
</button>
|
|
280
319
|
|
|
281
320
|
<div
|
|
@@ -316,10 +355,10 @@ onUnmounted(() => {
|
|
|
316
355
|
</div>
|
|
317
356
|
|
|
318
357
|
<div class="rm-csel__search">
|
|
319
|
-
<
|
|
358
|
+
<PhMagnifyingGlass :size="14" />
|
|
320
359
|
<input
|
|
321
360
|
ref="addRef"
|
|
322
|
-
v-model="
|
|
361
|
+
v-model="addInput"
|
|
323
362
|
type="search"
|
|
324
363
|
class="rm-csel__search-input"
|
|
325
364
|
:placeholder="addPlaceholder || t.searchAdd"
|
|
@@ -337,13 +376,13 @@ onUnmounted(() => {
|
|
|
337
376
|
<div v-else class="rm-csel__list">
|
|
338
377
|
<button
|
|
339
378
|
v-for="option in addOptions"
|
|
340
|
-
:key="option"
|
|
379
|
+
:key="option.value"
|
|
341
380
|
type="button"
|
|
342
381
|
class="rm-csel__option rm-csel__option--add"
|
|
343
|
-
@click="add(option)"
|
|
382
|
+
@click="add(option.value)"
|
|
344
383
|
>
|
|
345
|
-
<
|
|
346
|
-
<span>{{ option }}</span>
|
|
384
|
+
<PhPlusCircle :size="16" weight="fill" />
|
|
385
|
+
<span>{{ option.label }}</span>
|
|
347
386
|
</button>
|
|
348
387
|
</div>
|
|
349
388
|
</div>
|
|
@@ -362,7 +401,7 @@ onUnmounted(() => {
|
|
|
362
401
|
</div>
|
|
363
402
|
|
|
364
403
|
<div class="rm-csel__search">
|
|
365
|
-
<
|
|
404
|
+
<PhMagnifyingGlass :size="14" />
|
|
366
405
|
<input
|
|
367
406
|
v-model="removeSearch"
|
|
368
407
|
type="search"
|
|
@@ -379,13 +418,13 @@ onUnmounted(() => {
|
|
|
379
418
|
<div v-else class="rm-csel__list">
|
|
380
419
|
<button
|
|
381
420
|
v-for="option in removeOptions"
|
|
382
|
-
:key="option"
|
|
421
|
+
:key="option.value"
|
|
383
422
|
type="button"
|
|
384
423
|
class="rm-csel__option rm-csel__option--remove"
|
|
385
|
-
@click="remove(option)"
|
|
424
|
+
@click="remove(option.value)"
|
|
386
425
|
>
|
|
387
|
-
<
|
|
388
|
-
<span>{{ option }}</span>
|
|
426
|
+
<PhMinusCircle :size="16" weight="fill" />
|
|
427
|
+
<span>{{ option.label }}</span>
|
|
389
428
|
</button>
|
|
390
429
|
</div>
|
|
391
430
|
</div>
|
|
@@ -394,5 +433,5 @@ onUnmounted(() => {
|
|
|
394
433
|
</template>
|
|
395
434
|
|
|
396
435
|
<style scoped>
|
|
397
|
-
.rm-csel{align-items:
|
|
436
|
+
.rm-csel{align-items:stretch;display:flex;flex-direction:column;gap:4px;position:relative;width:196px}.rm-csel__label{align-items:center;color:var(--text-secondary);display:flex;font-size:var(--font-12,12px);gap:4px;line-height:14px}.rm-csel__info{background:none;border:none;color:var(--text-muted);cursor:pointer;display:flex;padding:0}.rm-csel__field{align-items:center;background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);font-weight:700;gap:4px;line-height:16px;padding:12px;text-align:left;width:100%}.rm-csel__field:hover:not(.is-disabled){border-color:rgba(var(--brand-rgb),.3)}.rm-csel__field.is-open{border-color:var(--color-primary)}.rm-csel__field.is-disabled{background:var(--bg-surface-2);color:var(--text-muted);cursor:not-allowed}.rm-csel__field:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.rm-csel__value-slot{display:block;flex:1;min-width:0}.rm-csel__value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-csel__value.is-empty{color:var(--text-muted);font-style:italic;font-weight:400}.rm-csel__field :deep(svg){color:var(--text-secondary);flex-shrink:0}.rm-csel__count{align-items:center;background:rgba(var(--brand-rgb),.1);border-radius:50%;color:var(--color-primary);display:flex;flex-shrink:0;font-size:var(--font-12,12px);font-weight:600;height:20px;justify-content:center;width:20px}.rm-csel__panel{background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-lg,12px);box-shadow:var(--r-shadow-lg,0 8px 24px rgba(0,0,0,.12));box-sizing:border-box;display:flex;left:0;margin-top:8px;max-width:calc(100vw - 32px);position:absolute;right:auto;top:100%;width:820px;z-index:12}.rm-csel__panel--right{left:auto;right:0}.rm-csel__column{display:flex;flex:1;flex-direction:column;gap:8px;min-width:0;padding:16px}.rm-csel__column--right{border-left:1px solid var(--border-soft);flex:0 0 300px}.rm-csel__presets{border-bottom:1px solid var(--border-soft);display:flex;flex-direction:column;gap:8px;padding-bottom:8px}.rm-csel__pills{display:flex;flex-wrap:wrap;gap:4px}.rm-csel__pill{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:9999px;color:var(--text-secondary);cursor:pointer;font-family:inherit;font-size:var(--font-12,12px);padding:4px 10px}.rm-csel__pill.is-active,.rm-csel__pill:hover{border-color:var(--color-primary);color:var(--color-primary)}.rm-csel__pill.is-active{background:rgba(var(--brand-rgb),.1);font-weight:700}.rm-csel__head{align-items:center;display:flex;gap:8px;justify-content:space-between}.rm-csel__section{color:var(--text-secondary);font-size:var(--font-12,12px);font-weight:700;margin:0}.rm-csel__action{background:none;border:none;color:var(--color-primary);cursor:pointer;font-family:inherit;font-size:var(--font-12,12px);font-weight:600;padding:0}.rm-csel__action:disabled{color:var(--text-muted);cursor:not-allowed}.rm-csel__action:hover:not(:disabled){text-decoration:underline}.rm-csel__action--clear:not(:disabled){color:var(--color-danger)}.rm-csel__search{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-md,8px);display:flex;gap:8px;padding:6px 10px}.rm-csel__search :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-csel__search-input{background:none;border:none;color:var(--text-primary);font-family:inherit;font-size:var(--font-13,13px);width:100%}.rm-csel__search-input::-moz-placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-csel__search-input::placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-csel__search-input:focus-visible{outline:none}.rm-csel__state{color:var(--text-secondary);font-size:var(--font-13,13px);font-style:italic;padding-top:8px}.rm-csel__loading{display:flex;flex-direction:column;gap:10px;padding-top:8px}.rm-csel__sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}.rm-csel__list{display:flex;flex-direction:column;gap:4px;height:260px;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin}.rm-csel__option{align-items:flex-start;background:none;border:none;border-radius:var(--radius-sm,4px);color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-13,13px);gap:8px;line-height:150%;min-width:0;padding:2px 4px;text-align:left}.rm-csel__option span{min-width:0;overflow-wrap:anywhere}.rm-csel__option :deep(svg){background:var(--bg-surface);border-radius:50%;flex-shrink:0;margin-top:3px}.rm-csel__option:hover{background:rgba(var(--brand-rgb),.05)}.rm-csel__option:focus-visible{outline:2px solid var(--color-primary);outline-offset:-2px}.rm-csel__option--add :deep(svg){color:var(--color-primary)}.rm-csel__option--remove :deep(svg){color:var(--color-danger)}@media (max-width:767px){.rm-csel__panel{flex-direction:column;width:calc(100vw - 32px)}.rm-csel__column--right{border-left:none;border-top:1px solid var(--border-soft)}.rm-csel__list{height:180px}}
|
|
398
437
|
</style>
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
-->
|
|
28
28
|
<script setup lang="ts">
|
|
29
29
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
30
|
+
import { PhCaretDown, PhCaretUpDown, PhCheckCircle, PhCircle, PhMagnifyingGlass } from '@phosphor-icons/vue'
|
|
30
31
|
import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
|
|
31
32
|
|
|
32
33
|
const props = withDefaults(defineProps<{
|
|
@@ -187,12 +188,12 @@ onUnmounted(() => {
|
|
|
187
188
|
{{ selected || emptyLabel || t.empty }}
|
|
188
189
|
</span>
|
|
189
190
|
</RmTooltip>
|
|
190
|
-
<
|
|
191
|
+
<component :is="sortIcon ? PhCaretUpDown : PhCaretDown" :size="16" />
|
|
191
192
|
</button>
|
|
192
193
|
|
|
193
194
|
<div v-show="isOpen" class="rm-dsel__panel" @click.stop>
|
|
194
195
|
<div v-if="search" class="rm-dsel__search">
|
|
195
|
-
<
|
|
196
|
+
<PhMagnifyingGlass :size="16" />
|
|
196
197
|
<input
|
|
197
198
|
ref="searchRef"
|
|
198
199
|
v-model="searchTerm"
|
|
@@ -222,8 +223,8 @@ onUnmounted(() => {
|
|
|
222
223
|
@click="pick(option)"
|
|
223
224
|
@mousemove="activeIndex = index"
|
|
224
225
|
>
|
|
225
|
-
<
|
|
226
|
-
:
|
|
226
|
+
<component
|
|
227
|
+
:is="option === selected ? PhCheckCircle : PhCircle"
|
|
227
228
|
:size="16"
|
|
228
229
|
:weight="option === selected ? 'fill' : 'regular'"
|
|
229
230
|
/>
|
|
@@ -235,5 +236,5 @@ onUnmounted(() => {
|
|
|
235
236
|
</template>
|
|
236
237
|
|
|
237
238
|
<style scoped>
|
|
238
|
-
.rm-dsel{align-items:
|
|
239
|
+
.rm-dsel{align-items:stretch;display:flex;flex-direction:column;gap:4px;position:relative;width:196px}.rm-dsel__label{color:var(--text-secondary);font-size:var(--font-12,12px);line-height:14px}.rm-dsel__field{align-items:center;background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);font-weight:700;gap:4px;line-height:16px;padding:12px;text-align:left;width:100%}.rm-dsel__field:hover:not(.is-disabled){border-color:rgba(var(--brand-rgb),.3)}.rm-dsel__field.is-open{border-color:var(--color-primary)}.rm-dsel__field.is-disabled{background:var(--bg-surface-2);color:var(--text-muted);cursor:not-allowed}.rm-dsel__field:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.rm-dsel__value-slot{display:block;flex:1;min-width:0}.rm-dsel__value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-dsel__value.is-empty{color:var(--text-muted);font-style:italic;font-weight:400}.rm-dsel__field :deep(svg){color:var(--text-secondary);flex-shrink:0}.rm-dsel__panel{border:1.5px solid var(--border-default);border-radius:var(--radius-lg,12px);box-shadow:var(--r-shadow-lg,0 8px 24px rgba(0,0,0,.12));box-sizing:border-box;flex-direction:column;left:0;margin-top:8px;max-height:500px;max-width:320px;min-width:230px;padding:16px;position:absolute;top:100%;z-index:12}.rm-dsel__panel,.rm-dsel__search{background:var(--bg-surface);display:flex}.rm-dsel__search{align-items:center;border:1px solid var(--border-default);border-radius:var(--radius-md,8px);gap:8px;padding:8px 12px}.rm-dsel__search :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-dsel__search-input{background:none;border:none;color:var(--text-primary);font-family:inherit;font-size:var(--font-14,14px);width:100%}.rm-dsel__search-input::-moz-placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-dsel__search-input::placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-dsel__search-input:focus-visible{outline:none}.rm-dsel__loading{display:flex;flex-direction:column;gap:10px;padding-top:8px}.rm-dsel__sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}.rm-dsel__state{color:var(--text-secondary);font-size:var(--font-14,14px);font-style:italic;padding-top:16px;text-align:center}.rm-dsel__list{display:flex;flex-direction:column;list-style:none;margin:0;min-height:10px;overflow-y:auto;padding:0}.rm-dsel__list:not(:only-child){margin-top:16px}.rm-dsel__option{align-items:center;border-radius:var(--radius-sm,4px);cursor:pointer;display:flex;font-size:var(--font-14,14px);gap:8px;line-height:160%;margin:4px 0;min-height:24px;padding:2px 4px}.rm-dsel__option :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-dsel__option.is-active{background:rgba(var(--brand-rgb),.05)}.rm-dsel__option.is-selected{font-weight:700}.rm-dsel__option.is-active :deep(svg),.rm-dsel__option.is-selected :deep(svg){color:var(--color-primary)}
|
|
239
240
|
</style>
|
|
@@ -275,5 +275,5 @@ onBeforeUnmount(() => {
|
|
|
275
275
|
</template>
|
|
276
276
|
|
|
277
277
|
<style scoped>
|
|
278
|
-
.rm-fbar{margin-inline:calc((min(var(--oip-content-max, 100%), 100%) - var(--oip-main-w, 100%))/2);position:sticky;width:var(--oip-main-w,100%);z-index:91;--rm-fbar-field-h:32px;backdrop-filter:blur(12px);background:rgba(245,245,249,.8);border-bottom:1px solid var(--border-default);display:flex;flex-direction:column;font-family:var(--font-sans)}.rm-fbar__views{align-items:center;display:flex;flex:0 0 auto}.rm-fbar__views:empty{display:none}.rm-fbar__row{align-items:flex-start;display:flex;gap:12px;padding-block:8px;padding-inline:max(32px,(100% - var(--oip-content-max,100%))/2 + 32px)}.rm-fbar--open .rm-fbar__row:not(:has(~.rm-fbar__rail-row)){border-bottom:1px solid var(--border-default)}.rm-fbar__toggle :deep(p),.rm-fbar__toggle :deep(span){font-size:inherit;font-weight:inherit;line-height:inherit;margin:0}.rm-fbar__toggle{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-pill);color:var(--text-primary);cursor:pointer;display:flex;flex:0 0 auto;font-family:inherit;font-size:var(--font-14);font-weight:var(--weight-medium);gap:6px;height:var(--rm-fbar-field-h);justify-content:center;padding:0 14px}.rm-fbar__toggle:hover{background:var(--bg-surface-3)}.rm-fbar__toggle.is-active,.rm-fbar__toggle.is-active:hover{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-text-inverse)}.rm-fbar__toggle.is-active .rm-fbar__badge{background:var(--color-text-inverse);color:var(--color-primary)}.rm-fbar__badge{align-items:center;background:var(--color-primary);border-radius:16px;color:var(--color-text-inverse);display:inline-flex;font-size:var(--font-11);font-weight:var(--weight-bold);justify-content:center;min-width:18px;padding:0 5px}.rm-fbar__view{align-items:center;display:flex;flex:0 0 auto}.rm-fbar__advanced{align-items:center;background:none;border:none;border-left:1px solid var(--border-default);color:var(--color-primary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--font-13);font-weight:var(--weight-medium);height:var(--rm-fbar-field-h);padding:0 0 0 12px;position:absolute;right:14px;text-decoration-line:underline;top:0;white-space:nowrap;z-index:2}.rm-fbar__advanced.is-active,.rm-fbar__advanced:hover{color:var(--color-primary-hover,var(--color-primary));text-decoration-thickness:2px}.rm-fbar__rail-row{display:flex;padding-bottom:8px;padding-inline:max(32px,(100% - var(--oip-content-max,100%))/2 + 32px)}.rm-fbar--open .rm-fbar__rail-row{border-bottom:1px solid var(--border-default)}.rm-fbar__rail{align-items:center;display:flex;flex:0 1 auto;min-width:0;overflow-x:auto;scrollbar-width:thin}.rm-fbar__rail:empty{display:none}.rm-fbar__search{align-items:center;display:flex;flex:1 1 auto;gap:8px;min-width:0;position:relative}.rm-fbar__search:empty{display:none}.rm-fbar__search :deep(.search-bar-wrapper){flex:1 1 auto;min-width:0}.rm-fbar__search :deep(.search-bar){background:var(--bg-surface);box-sizing:border-box;display:flex;height:var(--rm-fbar-field-h);width:100%}.rm-fbar__search :deep(.filters_input_search){border-radius:var(--radius-pill);box-sizing:border-box;height:auto;min-height:var(--rm-fbar-field-h);padding-right:calc(var(--rm-fbar-advanced-w, 0px) + 12px);width:100%}.rm-fbar__search :deep(.research_tags:not(:has(*))){display:none}.rm-fbar__search :deep(.select_shortcut){box-sizing:border-box;font-size:var(--font-11);height:24px;padding-block:0}.rm-fbar__search :deep(.select_shortcut:hover){background:var(--bg-surface-3)!important;border-color:var(--border-default)!important;color:inherit!important}.rm-fbar__search :deep(.select_shortcut:hover svg){color:inherit!important}.rm-fbar__search :deep(.remove_search_section){border-left:none;border-radius:0 var(--radius-pill) var(--radius-pill) 0}.rm-fbar__search :deep(.remove_search_section:hover){background:transparent!important}.rm-fbar__search :deep(.remove_search_section:hover svg){color:var(--text-primary)!important}.rm-fbar__search :deep(.filters_input_search.no_bottom){border-bottom:1.5px solid var(--color-primary)!important;border-radius:var(--radius-pill)}.rm-fbar__search :deep(.search_suggestions){border:1px solid var(--border-default);border-radius:var(--radius-2xl);box-shadow:var(--shadow-lg);left:0;padding:6px;right:0;top:calc(100% + 6px);width:auto}.rm-fbar__search :deep(.sugg_container>*){border-radius:var(--radius-lg)}.rm-fbar__search :deep(.sugg_container>.selected){background:color-mix(in srgb,var(--color-primary) 6%,transparent)!important}.rm-fbar__panel{--rm-filter-col:224px;--rm-fbar-panel-field-h:40px;align-items:end;display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(0,var(--rm-filter-col)));justify-content:center;padding-block:16px 20px;padding-inline:56px}.rm-fbar__panel--wide{align-items:stretch;display:flex;flex-direction:column;gap:12px}.rm-fbar__filters{display:contents}.rm-fbar__filters :deep(.filter-chip),.rm-fbar__filters :deep(.filter-complex__trigger),.rm-fbar__filters :deep(.rm-number__box){border-radius:var(--radius-lg);height:var(--rm-fbar-panel-field-h);width:100%}.rm-fbar__panel-head{align-items:baseline;display:flex;gap:16px;grid-column:1/-1;width:100%}.rm-fbar__customize{grid-column:1/-1}.rm-fbar__panel :deep(.filters_row_break){grid-column:1/-1}.rm-fbar__panel-title{font-size:var(--font-18);font-weight:800;margin:0}.rm-fbar__action{background:none;border:none;cursor:pointer;font-family:inherit;font-size:var(--font-14);font-weight:var(--weight-medium);padding:0;text-decoration-line:underline}.rm-fbar__action--save{color:var(--color-primary)}.rm-fbar__action--clear{color:var(--color-danger)}.rm-fbar__action--clear:hover{opacity:.8;text-decoration-thickness:2px}
|
|
278
|
+
.rm-fbar{margin-inline:calc((min(var(--oip-content-max, 100%), 100%) - var(--oip-main-w, 100%))/2);position:sticky;width:var(--oip-main-w,100%);z-index:91;--rm-fbar-field-h:32px;backdrop-filter:blur(12px);background:rgba(245,245,249,.8);border-bottom:1px solid var(--border-default);display:flex;flex-direction:column;font-family:var(--font-sans)}.rm-fbar__views{align-items:center;display:flex;flex:0 0 auto}.rm-fbar__views:empty{display:none}.rm-fbar__row{align-items:flex-start;display:flex;gap:12px;padding-block:8px;padding-inline:max(32px,(100% - var(--oip-content-max,100%))/2 + 32px)}.rm-fbar--open .rm-fbar__row:not(:has(~.rm-fbar__rail-row)){border-bottom:1px solid var(--border-default)}.rm-fbar__toggle :deep(p),.rm-fbar__toggle :deep(span){font-size:inherit;font-weight:inherit;line-height:inherit;margin:0}.rm-fbar__toggle{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-pill);color:var(--text-primary);cursor:pointer;display:flex;flex:0 0 auto;font-family:inherit;font-size:var(--font-14);font-weight:var(--weight-medium);gap:6px;height:var(--rm-fbar-field-h);justify-content:center;padding:0 14px}.rm-fbar__toggle:hover{background:var(--bg-surface-3)}.rm-fbar__toggle.is-active,.rm-fbar__toggle.is-active:hover{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-text-inverse)}.rm-fbar__toggle.is-active .rm-fbar__badge{background:var(--color-text-inverse);color:var(--color-primary)}.rm-fbar__badge{align-items:center;background:var(--color-primary);border-radius:16px;color:var(--color-text-inverse);display:inline-flex;font-size:var(--font-11);font-weight:var(--weight-bold);justify-content:center;min-width:18px;padding:0 5px}.rm-fbar__view{align-items:center;display:flex;flex:0 0 auto}.rm-fbar__advanced{align-items:center;background:none;border:none;border-left:1px solid var(--border-default);color:var(--color-primary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--font-13);font-weight:var(--weight-medium);height:var(--rm-fbar-field-h);padding:0 0 0 12px;position:absolute;right:14px;text-decoration-line:underline;top:0;white-space:nowrap;z-index:2}.rm-fbar__advanced.is-active,.rm-fbar__advanced:hover{color:var(--color-primary-hover,var(--color-primary));text-decoration-thickness:2px}.rm-fbar__rail-row{display:flex;padding-bottom:8px;padding-inline:max(32px,(100% - var(--oip-content-max,100%))/2 + 32px)}.rm-fbar--open .rm-fbar__rail-row{border-bottom:1px solid var(--border-default)}.rm-fbar__rail{align-items:center;display:flex;flex:0 1 auto;min-width:0;overflow-x:auto;scrollbar-width:thin}.rm-fbar__rail:empty{display:none}.rm-fbar__search{align-items:center;display:flex;flex:1 1 auto;gap:8px;min-width:0;position:relative}.rm-fbar__search:empty{display:none}.rm-fbar__search :deep(.search-bar-wrapper){flex:1 1 auto;min-width:0}.rm-fbar__search :deep(.search-bar){background:var(--bg-surface);box-sizing:border-box;display:flex;height:var(--rm-fbar-field-h);width:100%}.rm-fbar__search :deep(.filters_input_search){border-radius:var(--radius-pill);box-sizing:border-box;height:auto;min-height:var(--rm-fbar-field-h);padding-right:calc(var(--rm-fbar-advanced-w, 0px) + 12px);width:100%}.rm-fbar__search :deep(.research_tags:not(:has(*))){display:none}.rm-fbar__search :deep(.select_shortcut){box-sizing:border-box;font-size:var(--font-11);height:24px;padding-block:0}.rm-fbar__search :deep(.select_shortcut:hover){background:var(--bg-surface-3)!important;border-color:var(--border-default)!important;color:inherit!important}.rm-fbar__search :deep(.select_shortcut:hover svg){color:inherit!important}.rm-fbar__search :deep(.remove_search_section){border-left:none;border-radius:0 var(--radius-pill) var(--radius-pill) 0}.rm-fbar__search :deep(.remove_search_section:hover){background:transparent!important}.rm-fbar__search :deep(.remove_search_section:hover svg){color:var(--text-primary)!important}.rm-fbar__search :deep(.filters_input_search.no_bottom){border-bottom:1.5px solid var(--color-primary)!important;border-radius:var(--radius-pill)}.rm-fbar__search :deep(.search_suggestions){border:1px solid var(--border-default);border-radius:var(--radius-2xl);box-shadow:var(--shadow-lg);left:0;padding:6px;right:0;top:calc(100% + 6px);width:auto}.rm-fbar__search :deep(.sugg_container>*){border-radius:var(--radius-lg)}.rm-fbar__search :deep(.sugg_container>.selected){background:color-mix(in srgb,var(--color-primary) 6%,transparent)!important}.rm-fbar__panel{--rm-filter-col:224px;--rm-fbar-panel-field-h:40px;align-items:end;display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(0,var(--rm-filter-col)));justify-content:center;padding-block:16px 20px;padding-inline:56px}.rm-fbar__panel--wide{align-items:stretch;display:flex;flex-direction:column;gap:12px}.rm-fbar__filters{display:contents}.rm-fbar__filters :deep(.filter-chip),.rm-fbar__filters :deep(.filter-complex__trigger),.rm-fbar__filters :deep(.rm-csel__field),.rm-fbar__filters :deep(.rm-dsel__field),.rm-fbar__filters :deep(.rm-msel__field),.rm-fbar__filters :deep(.rm-number__box){border-radius:var(--radius-lg);height:var(--rm-fbar-panel-field-h);width:100%}.rm-fbar__filters :deep(.rm-csel),.rm-fbar__filters :deep(.rm-dsel),.rm-fbar__filters :deep(.rm-msel){align-items:stretch;width:100%}.rm-fbar__panel-head{align-items:baseline;display:flex;gap:16px;grid-column:1/-1;width:100%}.rm-fbar__customize{grid-column:1/-1}.rm-fbar__panel :deep(.filters_row_break){grid-column:1/-1}.rm-fbar__panel-title{font-size:var(--font-18);font-weight:800;margin:0}.rm-fbar__action{background:none;border:none;cursor:pointer;font-family:inherit;font-size:var(--font-14);font-weight:var(--weight-medium);padding:0;text-decoration-line:underline}.rm-fbar__action--save{color:var(--color-primary)}.rm-fbar__action--clear{color:var(--color-danger)}.rm-fbar__action--clear:hover{opacity:.8;text-decoration-thickness:2px}
|
|
279
279
|
</style>
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
RmIcon - une icone Phosphor designee par son nom.
|
|
3
|
+
|
|
4
|
+
Le composant charge le paquet d'icones a la demande : l'embarquer en entier
|
|
5
|
+
dans le premier rendu pesait plus lourd que tout le reste du panneau.
|
|
6
|
+
|
|
7
|
+
Les composants resolus sont gardes dans un cache commun a la page. Sans lui,
|
|
8
|
+
chaque instance fabriquait son propre composant asynchrone, meme pour une
|
|
9
|
+
icone deja chargee : une liste de trois cents lignes posait trois cents
|
|
10
|
+
attentes, et les icones apparaissaient apres le texte.
|
|
11
|
+
-->
|
|
1
12
|
<script setup lang="ts">
|
|
2
|
-
import { computed, defineAsyncComponent, type Component } from 'vue'
|
|
13
|
+
import { computed, defineAsyncComponent, shallowRef, type Component } from 'vue'
|
|
3
14
|
|
|
4
15
|
export interface RmIconProps {
|
|
5
|
-
/** Phosphor
|
|
16
|
+
/** Nom Phosphor sans le prefixe « Ph » (« House », « Gear », « ChartBar »). */
|
|
6
17
|
name: string
|
|
7
|
-
/**
|
|
18
|
+
/** Taille en pixels. */
|
|
8
19
|
size?: number
|
|
9
|
-
/**
|
|
20
|
+
/** Graisse du trait. `fill` donne la forme pleine. */
|
|
10
21
|
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
|
|
11
|
-
/** Icon color */
|
|
12
22
|
color?: string
|
|
13
23
|
}
|
|
14
24
|
|
|
@@ -18,14 +28,36 @@ const props = withDefaults(defineProps<RmIconProps>(), {
|
|
|
18
28
|
color: undefined,
|
|
19
29
|
})
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Un composant asynchrone par nom d'icone, partage par toutes les instances.
|
|
33
|
+
* Une fois le paquet charge, le composant garde sa resolution et se pose sans
|
|
34
|
+
* attente au montage suivant.
|
|
35
|
+
*/
|
|
36
|
+
const cache = new Map<string, Component>()
|
|
37
|
+
|
|
38
|
+
/** Le module, demande une seule fois quel que soit le nombre d'icones. */
|
|
39
|
+
const iconModule = shallowRef<Promise<Record<string, Component>>>()
|
|
40
|
+
|
|
41
|
+
function loadIcons() {
|
|
42
|
+
if (!iconModule.value) {
|
|
43
|
+
iconModule.value = import('@phosphor-icons/vue') as unknown as Promise<Record<string, Component>>
|
|
44
|
+
}
|
|
45
|
+
return iconModule.value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolve(name: string) {
|
|
49
|
+
const key = `Ph${name}`
|
|
50
|
+
let component = cache.get(key)
|
|
51
|
+
if (!component) {
|
|
52
|
+
component = defineAsyncComponent(() =>
|
|
53
|
+
loadIcons().then(mod => mod[key] || mod.PhQuestion),
|
|
54
|
+
)
|
|
55
|
+
cache.set(key, component)
|
|
56
|
+
}
|
|
57
|
+
return component
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const iconComponent = computed(() => resolve(props.name))
|
|
29
61
|
</script>
|
|
30
62
|
|
|
31
63
|
<template>
|
|
@@ -36,6 +68,8 @@ const iconComponent = computed<Component>(() => {
|
|
|
36
68
|
:weight="weight"
|
|
37
69
|
:color="color"
|
|
38
70
|
/>
|
|
71
|
+
<!-- La place est reservee des le premier rendu : sans elle, le texte se
|
|
72
|
+
decale lateralement quand l'icone arrive. -->
|
|
39
73
|
<template #fallback>
|
|
40
74
|
<span :style="{ display: 'inline-block', width: size + 'px', height: size + 'px' }" />
|
|
41
75
|
</template>
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
-->
|
|
26
26
|
<script setup lang="ts">
|
|
27
27
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
28
|
+
import { PhCaretDown, PhCheckSquare, PhInfo, PhMagnifyingGlass, PhSquare } from '@phosphor-icons/vue'
|
|
28
29
|
import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
|
|
29
30
|
|
|
30
31
|
const props = withDefaults(defineProps<{
|
|
@@ -175,7 +176,7 @@ onUnmounted(() => {
|
|
|
175
176
|
<p class="rm-msel__label">
|
|
176
177
|
{{ label }}
|
|
177
178
|
<button v-if="labelInfo" type="button" class="rm-msel__info" @click="emit('openInfo')">
|
|
178
|
-
<
|
|
179
|
+
<PhInfo :size="14" />
|
|
179
180
|
</button>
|
|
180
181
|
</p>
|
|
181
182
|
|
|
@@ -196,12 +197,12 @@ onUnmounted(() => {
|
|
|
196
197
|
<span v-if="showAmount && selected.length > 0" class="rm-msel__count">
|
|
197
198
|
{{ selected.length > 99 ? '99+' : selected.length }}
|
|
198
199
|
</span>
|
|
199
|
-
<
|
|
200
|
+
<PhCaretDown :size="16" />
|
|
200
201
|
</button>
|
|
201
202
|
|
|
202
203
|
<div v-show="isOpen" class="rm-msel__panel" @click.stop>
|
|
203
204
|
<div v-if="search" class="rm-msel__search">
|
|
204
|
-
<
|
|
205
|
+
<PhMagnifyingGlass :size="16" />
|
|
205
206
|
<input
|
|
206
207
|
ref="searchRef"
|
|
207
208
|
v-model="searchTerm"
|
|
@@ -230,8 +231,8 @@ onUnmounted(() => {
|
|
|
230
231
|
:aria-checked="allSelected"
|
|
231
232
|
@click="toggleAll"
|
|
232
233
|
>
|
|
233
|
-
<
|
|
234
|
-
:
|
|
234
|
+
<component
|
|
235
|
+
:is="allSelected ? PhCheckSquare : PhSquare"
|
|
235
236
|
:size="16"
|
|
236
237
|
:weight="allSelected ? 'fill' : 'regular'"
|
|
237
238
|
/>
|
|
@@ -249,8 +250,8 @@ onUnmounted(() => {
|
|
|
249
250
|
:aria-checked="selected.includes(option)"
|
|
250
251
|
@click="toggleOption(option)"
|
|
251
252
|
>
|
|
252
|
-
<
|
|
253
|
-
:
|
|
253
|
+
<component
|
|
254
|
+
:is="selected.includes(option) ? PhCheckSquare : PhSquare"
|
|
254
255
|
:size="16"
|
|
255
256
|
:weight="selected.includes(option) ? 'fill' : 'regular'"
|
|
256
257
|
/>
|
|
@@ -263,5 +264,5 @@ onUnmounted(() => {
|
|
|
263
264
|
</template>
|
|
264
265
|
|
|
265
266
|
<style scoped>
|
|
266
|
-
.rm-msel{align-items:
|
|
267
|
+
.rm-msel{align-items:stretch;display:flex;flex-direction:column;gap:4px;position:relative;width:196px}.rm-msel__label{align-items:center;color:var(--text-secondary);display:flex;font-size:var(--font-12,12px);gap:4px;line-height:14px}.rm-msel__info{background:none;border:none;color:var(--text-muted);cursor:pointer;display:flex;padding:0}.rm-msel__field{align-items:center;background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);font-weight:700;gap:4px;line-height:16px;padding:12px;text-align:left;width:100%}.rm-msel__field:hover:not(.is-disabled){border-color:rgba(var(--brand-rgb),.3)}.rm-msel__field.is-open{border-color:var(--color-primary)}.rm-msel__field.is-disabled{background:var(--bg-surface-2);color:var(--text-muted);cursor:not-allowed}.rm-msel__field:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.rm-msel__value-slot{display:block;flex:1;min-width:0}.rm-msel__value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-msel__value.is-empty{color:var(--text-muted);font-style:italic;font-weight:400}.rm-msel__field :deep(svg){color:var(--text-secondary);flex-shrink:0}.rm-msel__count{align-items:center;background:rgba(var(--brand-rgb),.1);border-radius:50%;color:var(--color-primary);display:flex;flex-shrink:0;font-size:var(--font-12,12px);font-weight:600;height:20px;justify-content:center;width:20px}.rm-msel__panel{border:1.5px solid var(--border-default);border-radius:var(--radius-lg,12px);box-shadow:var(--r-shadow-lg,0 8px 24px rgba(0,0,0,.12));box-sizing:border-box;flex-direction:column;left:0;margin-top:8px;max-height:500px;max-width:320px;min-width:230px;padding:16px;position:absolute;top:100%;z-index:12}.rm-msel__panel,.rm-msel__search{background:var(--bg-surface);display:flex}.rm-msel__search{align-items:center;border:1px solid var(--border-default);border-radius:var(--radius-md,8px);gap:8px;padding:8px 12px}.rm-msel__search :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-msel__search-input{background:none;border:none;color:var(--text-primary);font-family:inherit;font-size:var(--font-14,14px);width:100%}.rm-msel__search-input::-moz-placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-msel__search-input::placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-msel__search-input:focus-visible{outline:none}.rm-msel__loading{display:flex;flex-direction:column;gap:10px;padding-top:8px}.rm-msel__sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}.rm-msel__state{color:var(--text-secondary);font-size:var(--font-14,14px);font-style:italic;padding-top:16px;text-align:center}.rm-msel__list{display:flex;flex-direction:column;min-height:10px;overflow-y:auto}.rm-msel__list:not(:only-child){margin-top:16px}.rm-msel__indent{margin-left:16px}.rm-msel__option{align-items:center;background:none;border:none;border-radius:var(--radius-sm,4px);color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);gap:8px;line-height:160%;margin:4px 0;min-height:24px;padding:2px 4px;text-align:left;width:100%}.rm-msel__option :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-msel__option:hover{background:rgba(var(--brand-rgb),.05)}.rm-msel__option:focus-visible{outline:2px solid var(--color-primary);outline-offset:-2px}.rm-msel__option.is-checked{font-weight:700}.rm-msel__option.is-checked :deep(svg),.rm-msel__option:hover :deep(svg){color:var(--color-primary)}
|
|
267
268
|
</style>
|