@dnax/ui 0.0.73 → 0.0.76
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/components/QBtnDropdown.vue +8 -1
- package/components/QCard.vue +3 -3
- package/components/QDialog.vue +2 -2
- package/components/QFilePicker.vue +22 -65
- package/components/QGridItem.vue +1 -1
- package/components/QImg.vue +3 -1
- package/components/QInputOtp.vue +2 -0
- package/components/QSpreadsheet.vue +593 -65
- package/components/QSyntax.vue +2 -2
- package/components/QTable.vue +2 -2
- package/index.ts +18 -0
- package/lib/cellSize.test.ts +52 -0
- package/lib/cellSize.ts +43 -0
- package/lib/fileList.test.ts +119 -0
- package/lib/fileList.ts +159 -0
- package/lib/iconSet.test.ts +61 -0
- package/lib/iconSet.ts +91 -0
- package/lib/iconSetScrape.ts +139 -0
- package/lib/icons.ts +16 -0
- package/lib/pagination.test.ts +77 -0
- package/lib/pagination.ts +50 -0
- package/lib/registerIcons.ts +37 -0
- package/lib/useComponentProps.test.ts +55 -1
- package/lib/useComponentProps.ts +15 -0
- package/module.ts +124 -6
- package/package.json +4 -2
- package/runtime.ts +5 -0
- package/scripts/gen-icon-set.ts +110 -0
- package/scripts/generate-exports.ts +46 -69
- package/styles/main.css +191 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Génère un **sous-ensemble** de la collection `lucide` contenant uniquement les
|
|
3
|
+
* icônes réellement référencées dans le code, sous forme d'un module TS prêt à être
|
|
4
|
+
* embarqué dans le bundle.
|
|
5
|
+
*
|
|
6
|
+
* C'est ce qui produit `lib/iconSet.ts` (icônes du design system, figées et testées).
|
|
7
|
+
* Le module Nuxt fait la même chose **à la volée** pour les sources de l'app hôte
|
|
8
|
+
* (option `icons.scan`) ; ce script sert quand on veut un fichier committé, ou sans Nuxt.
|
|
9
|
+
*
|
|
10
|
+
* Usage :
|
|
11
|
+
* # design system (composants + lib) → packages/ui/lib/iconSet.ts
|
|
12
|
+
* bun scripts/gen-icon-set.ts --out ./lib/iconSet.ts --src ./components --src ./lib
|
|
13
|
+
*
|
|
14
|
+
* # app / site de docs → ./app/iconSet.ts
|
|
15
|
+
* bun scripts/gen-icon-set.ts --out ./app/iconSet.ts --src ./app --src ./content \
|
|
16
|
+
* --type-import @dnax/ui
|
|
17
|
+
*
|
|
18
|
+
* `--src` est récursif (`.vue`, `.ts`, `.js`, `.mjs`, `.md`), les dossiers
|
|
19
|
+
* `node_modules` / `.nuxt` / `.output` / `dist` / `public` sont ignorés. Un nom absent
|
|
20
|
+
* de la collection est signalé (faute de frappe le plus souvent).
|
|
21
|
+
*/
|
|
22
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises"
|
|
23
|
+
import { dirname, resolve } from "node:path"
|
|
24
|
+
import {
|
|
25
|
+
buildIconSet,
|
|
26
|
+
scrapeIconNames,
|
|
27
|
+
type IconifySourceCollection,
|
|
28
|
+
} from "../lib/iconSetScrape"
|
|
29
|
+
|
|
30
|
+
// — Arguments ------------------------------------------------------------------
|
|
31
|
+
let outFile = ""
|
|
32
|
+
let typeImport = "./icons"
|
|
33
|
+
const sources: string[] = []
|
|
34
|
+
|
|
35
|
+
const args = process.argv.slice(2)
|
|
36
|
+
for (let i = 0; i < args.length; i++) {
|
|
37
|
+
const arg = args[i]!
|
|
38
|
+
if (arg === "--out") outFile = args[++i] ?? ""
|
|
39
|
+
else if (arg === "--src") sources.push(args[++i] ?? "")
|
|
40
|
+
else if (arg === "--type-import") typeImport = args[++i] ?? "./icons"
|
|
41
|
+
else {
|
|
42
|
+
console.error(`Argument inconnu : ${arg}`)
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!outFile || sources.length === 0) {
|
|
48
|
+
console.error(
|
|
49
|
+
"Usage : bun scripts/gen-icon-set.ts --out <fichier.ts> --src <dossier> [--src <dossier>…] [--type-import <specifier>]",
|
|
50
|
+
)
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// — Relevé + résolution --------------------------------------------------------
|
|
55
|
+
const resolvedSources = sources.map((src) => resolve(process.cwd(), src))
|
|
56
|
+
const names = scrapeIconNames(resolvedSources)
|
|
57
|
+
|
|
58
|
+
if (names.length === 0) {
|
|
59
|
+
console.error("Aucune icône `lucide:` trouvée dans les sources fournies.")
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const collectionUrl = import.meta.resolve("@iconify-json/lucide/icons.json")
|
|
64
|
+
const collection = JSON.parse(await readFile(new URL(collectionUrl), "utf8")) as IconifySourceCollection
|
|
65
|
+
const { set, missing } = buildIconSet(collection, names)
|
|
66
|
+
|
|
67
|
+
// — Écriture -------------------------------------------------------------------
|
|
68
|
+
const iconNames = Object.keys(set.icons).sort()
|
|
69
|
+
const aliasNames = Object.keys(set.aliases ?? {}).sort()
|
|
70
|
+
|
|
71
|
+
const iconLines = iconNames
|
|
72
|
+
.map((name) => ` ${JSON.stringify(name)}: { body: ${JSON.stringify(set.icons[name]!.body)} },`)
|
|
73
|
+
.join("\n")
|
|
74
|
+
const aliasLines = aliasNames
|
|
75
|
+
.map(
|
|
76
|
+
(name) =>
|
|
77
|
+
` ${JSON.stringify(name)}: { parent: ${JSON.stringify(set.aliases![name]!.parent)} },`,
|
|
78
|
+
)
|
|
79
|
+
.join("\n")
|
|
80
|
+
|
|
81
|
+
const sourceLabel = sources.map((src) => `\`${src}\``).join(", ")
|
|
82
|
+
const header = `// ⚠️ FICHIER GÉNÉRÉ — ne pas éditer à la main.
|
|
83
|
+
// Commande : bun scripts/gen-icon-set.ts --out ${outFile} --src ${sources.join(" --src ")}${typeImport === "./icons" ? "" : ` --type-import ${typeImport}`}
|
|
84
|
+
//
|
|
85
|
+
// Sous-ensemble de la collection \`lucide\` : ${iconNames.length} icônes${aliasNames.length ? ` + ${aliasNames.length} alias` : ""}, relevées dans
|
|
86
|
+
// ${sourceLabel}. Embarqué dans le bundle, il est enregistré auprès d'Iconify par
|
|
87
|
+
// \`registerIcons()\` (ou par le module Nuxt \`@dnax/ui\`) via \`addCollection()\` :
|
|
88
|
+
// ces icônes ne déclenchent **aucune** requête vers l'API Iconify et sont rendues
|
|
89
|
+
// dès le SSR. Les noms absents de ce fichier continuent de passer par l'API.
|
|
90
|
+
import type { IconSetJson } from "${typeImport}"
|
|
91
|
+
|
|
92
|
+
export const lucideIconSet: IconSetJson = {
|
|
93
|
+
prefix: "lucide",
|
|
94
|
+
width: ${set.width ?? 24},
|
|
95
|
+
height: ${set.height ?? 24},
|
|
96
|
+
icons: {
|
|
97
|
+
${iconLines}
|
|
98
|
+
},
|
|
99
|
+
${aliasLines ? ` aliases: {\n${aliasLines}\n },\n` : ""}}
|
|
100
|
+
`
|
|
101
|
+
|
|
102
|
+
const outPath = resolve(process.cwd(), outFile)
|
|
103
|
+
await mkdir(dirname(outPath), { recursive: true })
|
|
104
|
+
await writeFile(outPath, header)
|
|
105
|
+
|
|
106
|
+
const kb = (Buffer.byteLength(header) / 1024).toFixed(1)
|
|
107
|
+
console.log(`✓ ${iconNames.length} icône(s) + ${aliasNames.length} alias → ${outFile} (${kb} Ko)`)
|
|
108
|
+
if (missing.length) {
|
|
109
|
+
console.warn(`⚠️ ${missing.length} nom(s) introuvable(s) dans lucide : ${missing.join(", ")}`)
|
|
110
|
+
}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Regénère `index.ts` : une ligne d'export par composant, puis le **bloc manuel**
|
|
3
|
+
* (composables, helpers, types de `lib/`) recopié **tel quel**.
|
|
3
4
|
* Run with: bun scripts/generate-exports.ts
|
|
5
|
+
*
|
|
6
|
+
* ⚠️ Ne jamais figer le bloc manuel dans ce script. Une version précédente le
|
|
7
|
+
* contenait en dur ; il avait pris du retard sur `index.ts` et une exécution a
|
|
8
|
+
* silencieusement supprimé `network`, `wakeLock`, `chartFormat`, `chartStats`,
|
|
9
|
+
* `chartTable`… (cf. `.memory/warnings.md`). Ici le bloc manuel est **relu** depuis
|
|
10
|
+
* `index.ts` : tout ce qui suit le dernier export de composant est conservé, donc le
|
|
11
|
+
* script est idempotent et ne peut plus rien perdre.
|
|
4
12
|
*/
|
|
5
|
-
import { readdir } from "node:fs/promises"
|
|
13
|
+
import { readdir, readFile } from "node:fs/promises"
|
|
6
14
|
|
|
7
15
|
const componentsDir = new URL("../components/", import.meta.url)
|
|
8
16
|
const indexFile = new URL("../index.ts", import.meta.url)
|
|
9
17
|
|
|
18
|
+
/** Ligne produite pour un composant : `export { default as QX } from "./components/QX.vue"` */
|
|
19
|
+
const COMPONENT_EXPORT_LINE = /^export \{ default as [\w$]+ \} from "\.\/components\/[\w$]+\.vue"$/
|
|
20
|
+
|
|
10
21
|
const toPascalCase = (name: string) =>
|
|
11
22
|
name
|
|
12
23
|
.split(/[-_]/)
|
|
@@ -17,78 +28,44 @@ const files = (await readdir(componentsDir))
|
|
|
17
28
|
.filter((file) => file.endsWith(".vue") && !file.startsWith("_"))
|
|
18
29
|
.sort()
|
|
19
30
|
|
|
20
|
-
const
|
|
31
|
+
const componentExports = files
|
|
21
32
|
.map(
|
|
22
33
|
(file) =>
|
|
23
34
|
`export { default as ${toPascalCase(file.replace(/\.vue$/, ""))} } from "./components/${file}"`,
|
|
24
35
|
)
|
|
25
36
|
.join("\n")
|
|
26
37
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export { placePopover } from "./lib/datePicker"
|
|
58
|
-
export type {
|
|
59
|
-
PlacePopoverOptions,
|
|
60
|
-
PopoverAnchor,
|
|
61
|
-
PopoverPlacement,
|
|
62
|
-
PopoverViewport,
|
|
63
|
-
} from "./lib/datePicker"
|
|
64
|
-
export { DEFAULT_LAYOUT_VIEW, parseView, qLayoutKey } from "./lib/layout"
|
|
65
|
-
export type { LayoutView, LayoutZone, LayoutZonePlacement, QLayoutContext } from "./lib/layout"
|
|
66
|
-
export { vRipple } from "./lib/ripple"
|
|
67
|
-
export type { RippleOptions, RippleValue } from "./lib/ripple"
|
|
68
|
-
export { chartToECharts, channelValue, pickFromEvent, tableModel, textValue } from "./lib/chart"
|
|
69
|
-
export type {
|
|
70
|
-
QChartAxis,
|
|
71
|
-
QChartChannel,
|
|
72
|
-
QChartColumn,
|
|
73
|
-
QChartConfig,
|
|
74
|
-
QChartLegend,
|
|
75
|
-
QChartMark,
|
|
76
|
-
QChartMarkType,
|
|
77
|
-
QChartOrientation,
|
|
78
|
-
QChartTable,
|
|
79
|
-
QChartPick,
|
|
80
|
-
} from "./lib/chart"
|
|
81
|
-
export { vTouchPan } from "./lib/touchPan"
|
|
82
|
-
export type { PanDetails, TouchPanHandler, PanDirection } from "./lib/touchPan"
|
|
83
|
-
export { vTouchHold } from "./lib/touchHold"
|
|
84
|
-
export type { TouchHoldDetails, TouchHoldHandler } from "./lib/touchHold"
|
|
85
|
-
export { vTouchSwipe } from "./lib/touchSwipe"
|
|
86
|
-
export type { TouchSwipeDetails, TouchSwipeHandler, SwipeDirection } from "./lib/touchSwipe"
|
|
87
|
-
export { vTouchRepeat } from "./lib/touchRepeat"
|
|
88
|
-
export type { TouchRepeatDetails, TouchRepeatHandler } from "./lib/touchRepeat"
|
|
89
|
-
export { vIntersection } from "./lib/intersection"
|
|
90
|
-
export type { IntersectionValue } from "./lib/intersection"
|
|
91
|
-
`
|
|
38
|
+
// — Bloc manuel : relu dans l'`index.ts` courant -------------------------------
|
|
39
|
+
let current = ""
|
|
40
|
+
try {
|
|
41
|
+
current = await readFile(indexFile, "utf8")
|
|
42
|
+
} catch {
|
|
43
|
+
throw new Error(
|
|
44
|
+
"packages/ui/index.ts est introuvable : le bloc manuel (exports de `lib/`) ne peut pas être conservé. " +
|
|
45
|
+
"Recréez le fichier avec ses exports manuels avant de lancer ce script.",
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const lines = current.split("\n")
|
|
50
|
+
let lastComponentLine = -1
|
|
51
|
+
lines.forEach((line, i) => {
|
|
52
|
+
if (COMPONENT_EXPORT_LINE.test(line)) lastComponentLine = i
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// Fichier sans aucun export de composant (création manuelle) : tout est conservé.
|
|
56
|
+
const manualExports = (lastComponentLine === -1 ? current : lines.slice(lastComponentLine + 1).join("\n"))
|
|
57
|
+
.trim()
|
|
58
|
+
|
|
59
|
+
if (lastComponentLine === -1 && /\bexport\b/.test(manualExports)) {
|
|
60
|
+
console.warn(
|
|
61
|
+
"⚠️ Aucun export de composant reconnu dans index.ts : tout son contenu est traité comme bloc manuel.",
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const output = manualExports ? `${componentExports}\n\n${manualExports}\n` : `${componentExports}\n`
|
|
66
|
+
|
|
67
|
+
await Bun.write(indexFile, output)
|
|
92
68
|
|
|
93
|
-
|
|
69
|
+
const kept = manualExports ? manualExports.split("\n").length : 0
|
|
94
70
|
console.log(`✓ ${files.length} composant(s) exporté(s) dans index.ts`)
|
|
71
|
+
console.log(`✓ ${kept} ligne(s) d'exports manuels conservées (bloc relu depuis index.ts)`)
|
package/styles/main.css
CHANGED
|
@@ -2972,6 +2972,11 @@ html.dark body {
|
|
|
2972
2972
|
border-radius: var(--q-radius);
|
|
2973
2973
|
}
|
|
2974
2974
|
|
|
2975
|
+
/* `radius` (booléen) : forme pilule, cf. JSDoc de la prop. */
|
|
2976
|
+
.q-img--rounded {
|
|
2977
|
+
border-radius: 9999px;
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2975
2980
|
.q-img__image {
|
|
2976
2981
|
position: absolute;
|
|
2977
2982
|
inset: 0;
|
|
@@ -6877,6 +6882,11 @@ a.q-breadcrumbs__el:hover {
|
|
|
6877
6882
|
background-color: rgb(0 0 0 / 0.6);
|
|
6878
6883
|
color: #fff;
|
|
6879
6884
|
}
|
|
6885
|
+
/* Thème sombre : le voile blanc codé en dur éblouit (même convention que les champs) */
|
|
6886
|
+
.dark .q-inner-loading {
|
|
6887
|
+
background-color: rgb(0 0 0 / 0.55);
|
|
6888
|
+
color: var(--foreground);
|
|
6889
|
+
}
|
|
6880
6890
|
|
|
6881
6891
|
.q-inner-loading__icon {
|
|
6882
6892
|
animation: q-btn-spin 0.7s linear infinite;
|
|
@@ -9254,6 +9264,13 @@ a.q-breadcrumbs__el:hover {
|
|
|
9254
9264
|
.q-input-otp__box--error {
|
|
9255
9265
|
border-color: var(--negative);
|
|
9256
9266
|
}
|
|
9267
|
+
|
|
9268
|
+
/* `radius` (booléen) : forme pilule — même intention que `.q-field--rounded` (20px).
|
|
9269
|
+
Les cases font 48px : 20px les rend nettement arrondies sans les transformer en
|
|
9270
|
+
cercles, ce qui laisserait des trous entre les caractères. */
|
|
9271
|
+
.q-input-otp--rounded .q-input-otp__box {
|
|
9272
|
+
border-radius: 20px;
|
|
9273
|
+
}
|
|
9257
9274
|
.q-input-otp__box--error:focus {
|
|
9258
9275
|
border-color: var(--negative);
|
|
9259
9276
|
box-shadow: 0 0 0 1px var(--negative);
|
|
@@ -9625,6 +9642,20 @@ a.q-breadcrumbs__el:hover {
|
|
|
9625
9642
|
overflow: auto;
|
|
9626
9643
|
outline: none;
|
|
9627
9644
|
}
|
|
9645
|
+
|
|
9646
|
+
/* Chargement distant : spinner du design system, teinté par le thème */
|
|
9647
|
+
.q-spreadsheet__loader {
|
|
9648
|
+
width: 30px;
|
|
9649
|
+
height: 30px;
|
|
9650
|
+
border-width: 3px;
|
|
9651
|
+
color: var(--primary, #1976d2);
|
|
9652
|
+
}
|
|
9653
|
+
|
|
9654
|
+
/* Le voile passe au-dessus de l'éditeur (z-index 20) et de la poignée de remplissage :
|
|
9655
|
+
on ne doit pas éditer une page en cours de remplacement. */
|
|
9656
|
+
.q-spreadsheet > .q-inner-loading {
|
|
9657
|
+
z-index: 40;
|
|
9658
|
+
}
|
|
9628
9659
|
.q-spreadsheet__table {
|
|
9629
9660
|
/* PAS de `min-width: 100%` : avec `table-layout: fixed`, un tableau étiré au-delà
|
|
9630
9661
|
de la somme de ses colonnes RÉPARTIT l'espace libre sur toutes les colonnes
|
|
@@ -9636,7 +9667,8 @@ a.q-breadcrumbs__el:hover {
|
|
|
9636
9667
|
border-collapse: separate;
|
|
9637
9668
|
border-spacing: 0;
|
|
9638
9669
|
table-layout: fixed;
|
|
9639
|
-
|
|
9670
|
+
/* Suit `sizeCell` (la police grandit avec la cellule) ; 13px = taille historique */
|
|
9671
|
+
font-size: var(--q-spreadsheet-font, 13px);
|
|
9640
9672
|
}
|
|
9641
9673
|
|
|
9642
9674
|
/* Grille sans aucune colonne : un seul message → il doit occuper toute la largeur */
|
|
@@ -9856,6 +9888,132 @@ a.q-breadcrumbs__el:hover {
|
|
|
9856
9888
|
vertical-align: middle;
|
|
9857
9889
|
}
|
|
9858
9890
|
|
|
9891
|
+
/* ─── Fichiers joints (type `attachment`) ─── */
|
|
9892
|
+
/* Une « puce » par fichier : vignette (image) ou icône typée, nom tronqué, bouton de retrait.
|
|
9893
|
+
Les puces passent à la ligne dans une cellule étroite, comme les badges. */
|
|
9894
|
+
.q-spreadsheet__attachments {
|
|
9895
|
+
display: inline-flex;
|
|
9896
|
+
flex-wrap: wrap;
|
|
9897
|
+
align-items: center;
|
|
9898
|
+
gap: 4px;
|
|
9899
|
+
max-width: 100%;
|
|
9900
|
+
vertical-align: middle;
|
|
9901
|
+
}
|
|
9902
|
+
|
|
9903
|
+
.q-spreadsheet__attachment {
|
|
9904
|
+
display: inline-flex;
|
|
9905
|
+
align-items: center;
|
|
9906
|
+
gap: 4px;
|
|
9907
|
+
max-width: 100%;
|
|
9908
|
+
padding: 1px 4px 1px 2px;
|
|
9909
|
+
border: 1px solid rgb(0 0 0 / 0.12);
|
|
9910
|
+
border-radius: 999px;
|
|
9911
|
+
background: rgb(0 0 0 / 0.04);
|
|
9912
|
+
font-size: 11.5px;
|
|
9913
|
+
line-height: 1.6;
|
|
9914
|
+
white-space: nowrap;
|
|
9915
|
+
/* La puce est cliquable : elle émet `attachment-click` (aperçu côté app) */
|
|
9916
|
+
cursor: pointer;
|
|
9917
|
+
}
|
|
9918
|
+
.q-spreadsheet__attachment:hover {
|
|
9919
|
+
border-color: rgb(0 0 0 / 0.24);
|
|
9920
|
+
background: rgb(0 0 0 / 0.08);
|
|
9921
|
+
}
|
|
9922
|
+
|
|
9923
|
+
.q-spreadsheet__attachment-thumb {
|
|
9924
|
+
width: 18px;
|
|
9925
|
+
height: 18px;
|
|
9926
|
+
flex: 0 0 auto;
|
|
9927
|
+
border-radius: 4px;
|
|
9928
|
+
object-fit: cover;
|
|
9929
|
+
}
|
|
9930
|
+
|
|
9931
|
+
.q-spreadsheet__attachment-icon {
|
|
9932
|
+
width: 14px;
|
|
9933
|
+
height: 14px;
|
|
9934
|
+
flex: 0 0 auto;
|
|
9935
|
+
color: rgb(0 0 0 / 0.55);
|
|
9936
|
+
}
|
|
9937
|
+
|
|
9938
|
+
.q-spreadsheet__attachment-name {
|
|
9939
|
+
max-width: 140px;
|
|
9940
|
+
overflow: hidden;
|
|
9941
|
+
text-overflow: ellipsis;
|
|
9942
|
+
}
|
|
9943
|
+
|
|
9944
|
+
.q-spreadsheet__attachment-x {
|
|
9945
|
+
display: inline-flex;
|
|
9946
|
+
align-items: center;
|
|
9947
|
+
justify-content: center;
|
|
9948
|
+
width: 14px;
|
|
9949
|
+
height: 14px;
|
|
9950
|
+
padding: 0;
|
|
9951
|
+
border: none;
|
|
9952
|
+
border-radius: 50%;
|
|
9953
|
+
background: transparent;
|
|
9954
|
+
color: rgb(0 0 0 / 0.45);
|
|
9955
|
+
cursor: pointer;
|
|
9956
|
+
flex: 0 0 auto;
|
|
9957
|
+
}
|
|
9958
|
+
.q-spreadsheet__attachment-x:hover {
|
|
9959
|
+
background: rgb(0 0 0 / 0.12);
|
|
9960
|
+
color: var(--negative, #c10015);
|
|
9961
|
+
}
|
|
9962
|
+
.q-spreadsheet__attachment-x svg {
|
|
9963
|
+
width: 10px;
|
|
9964
|
+
height: 10px;
|
|
9965
|
+
}
|
|
9966
|
+
|
|
9967
|
+
/* Bouton d'ajout : discret, visible dès qu'on survole / sélectionne la cellule */
|
|
9968
|
+
.q-spreadsheet__attachment-add {
|
|
9969
|
+
display: inline-flex;
|
|
9970
|
+
align-items: center;
|
|
9971
|
+
justify-content: center;
|
|
9972
|
+
width: 18px;
|
|
9973
|
+
height: 18px;
|
|
9974
|
+
padding: 0;
|
|
9975
|
+
border: 1px dashed rgb(0 0 0 / 0.25);
|
|
9976
|
+
border-radius: 50%;
|
|
9977
|
+
background: transparent;
|
|
9978
|
+
color: rgb(0 0 0 / 0.45);
|
|
9979
|
+
cursor: pointer;
|
|
9980
|
+
flex: 0 0 auto;
|
|
9981
|
+
}
|
|
9982
|
+
.q-spreadsheet__attachment-add:hover {
|
|
9983
|
+
border-color: var(--primary, #1976d2);
|
|
9984
|
+
color: var(--primary, #1976d2);
|
|
9985
|
+
}
|
|
9986
|
+
.q-spreadsheet__attachment-add svg {
|
|
9987
|
+
width: 10px;
|
|
9988
|
+
height: 10px;
|
|
9989
|
+
}
|
|
9990
|
+
|
|
9991
|
+
/* Input `type=file` masqué (piloté par `openAttachments`) */
|
|
9992
|
+
.q-spreadsheet__attach-input {
|
|
9993
|
+
position: absolute;
|
|
9994
|
+
width: 0;
|
|
9995
|
+
height: 0;
|
|
9996
|
+
opacity: 0;
|
|
9997
|
+
pointer-events: none;
|
|
9998
|
+
}
|
|
9999
|
+
|
|
10000
|
+
.dark .q-spreadsheet__attachment {
|
|
10001
|
+
border-color: rgb(255 255 255 / 0.16);
|
|
10002
|
+
background: rgb(255 255 255 / 0.06);
|
|
10003
|
+
}
|
|
10004
|
+
.dark .q-spreadsheet__attachment:hover {
|
|
10005
|
+
border-color: rgb(255 255 255 / 0.3);
|
|
10006
|
+
background: rgb(255 255 255 / 0.11);
|
|
10007
|
+
}
|
|
10008
|
+
.dark .q-spreadsheet__attachment-icon,
|
|
10009
|
+
.dark .q-spreadsheet__attachment-x,
|
|
10010
|
+
.dark .q-spreadsheet__attachment-add {
|
|
10011
|
+
color: rgb(255 255 255 / 0.6);
|
|
10012
|
+
}
|
|
10013
|
+
.dark .q-spreadsheet__attachment-add {
|
|
10014
|
+
border-color: rgb(255 255 255 / 0.24);
|
|
10015
|
+
}
|
|
10016
|
+
|
|
9859
10017
|
/* ─── Éditeur overlay ─── */
|
|
9860
10018
|
.q-spreadsheet__editor {
|
|
9861
10019
|
position: absolute;
|
|
@@ -10746,6 +10904,38 @@ a.q-breadcrumbs__el:hover {
|
|
|
10746
10904
|
.q-spreadsheet__status-spacer {
|
|
10747
10905
|
flex: 1;
|
|
10748
10906
|
}
|
|
10907
|
+
|
|
10908
|
+
/* Pagination distante : ‹ lignes 401–800 sur 12 000 · 2 / 30 › */
|
|
10909
|
+
.q-spreadsheet__pager {
|
|
10910
|
+
display: inline-flex;
|
|
10911
|
+
align-items: center;
|
|
10912
|
+
gap: 4px;
|
|
10913
|
+
padding-right: 8px;
|
|
10914
|
+
border-right: 1px solid rgb(0 0 0 / 0.1);
|
|
10915
|
+
margin-right: 2px;
|
|
10916
|
+
}
|
|
10917
|
+
.q-spreadsheet__pager .q-spreadsheet__tool {
|
|
10918
|
+
width: 22px;
|
|
10919
|
+
height: 20px;
|
|
10920
|
+
}
|
|
10921
|
+
.q-spreadsheet__pager-range {
|
|
10922
|
+
font-variant-numeric: tabular-nums;
|
|
10923
|
+
white-space: nowrap;
|
|
10924
|
+
}
|
|
10925
|
+
.q-spreadsheet__pager-page {
|
|
10926
|
+
padding: 0 6px;
|
|
10927
|
+
border-radius: 999px;
|
|
10928
|
+
background: rgb(0 0 0 / 0.06);
|
|
10929
|
+
font-weight: 600;
|
|
10930
|
+
font-variant-numeric: tabular-nums;
|
|
10931
|
+
white-space: nowrap;
|
|
10932
|
+
}
|
|
10933
|
+
.dark .q-spreadsheet__pager {
|
|
10934
|
+
border-right-color: rgb(255 255 255 / 0.14);
|
|
10935
|
+
}
|
|
10936
|
+
.dark .q-spreadsheet__pager-page {
|
|
10937
|
+
background: rgb(255 255 255 / 0.12);
|
|
10938
|
+
}
|
|
10749
10939
|
.q-spreadsheet__status-zoom {
|
|
10750
10940
|
display: inline-flex;
|
|
10751
10941
|
align-items: center;
|