@mostajs/qrpanel 0.2.0 → 0.3.0

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/themes.js ADDED
@@ -0,0 +1,186 @@
1
+ // @mostajs/qrpanel/themes — built-in theme registry
2
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
3
+ //
4
+ // Chaque thème = un petit motif SVG répliqué aux 4 coins du composite,
5
+ // laissant le centre libre pour le cartouche blanc + QR. Style ligne
6
+ // minimaliste mono-color via `currentColor` (le composer pilote la
7
+ // couleur via CSS sur le <g> wrapper).
8
+ //
9
+ // Création maison — design original, libre de droits.
10
+ // viewBox local du motif : centré sur l'origine, ~14 unités d'envergure.
11
+ /** Communs à tous les motifs (style ligne fine et propre). */
12
+ const STROKE = 'stroke="currentColor" stroke-width="2.4" fill="none" stroke-linecap="round" stroke-linejoin="round"';
13
+ const FILL = 'fill="currentColor"';
14
+ export const THEMES = {
15
+ // ─── 1. baby — sucette + cœur ─────────────────────────────────
16
+ baby: {
17
+ key: 'baby', label: 'Bébé',
18
+ motif: `
19
+ <circle cx="-2" cy="-3" r="4.5" ${STROKE}/>
20
+ <line x1="-2" y1="1.5" x2="-2" y2="6" ${STROKE}/>
21
+ <path d="M 5 -2 c 0.8 -1.2 2.5 -1.2 2.5 0.4 c 0 1.4 -2.5 2.8 -2.5 2.8 c 0 0 -2.5 -1.4 -2.5 -2.8 c 0 -1.6 1.7 -1.6 2.5 -0.4 z" ${FILL} opacity="0.9"/>
22
+ `,
23
+ },
24
+ // ─── 2. animals — empreinte de patte (4 doigts + pad) ─────────
25
+ animals: {
26
+ key: 'animals', label: 'Animaux',
27
+ motif: `
28
+ <ellipse cx="-3.5" cy="-3" rx="1.3" ry="1.8" ${FILL}/>
29
+ <ellipse cx="-1" cy="-5" rx="1.2" ry="1.7" ${FILL}/>
30
+ <ellipse cx="1.8" cy="-5" rx="1.2" ry="1.7" ${FILL}/>
31
+ <ellipse cx="4.3" cy="-3" rx="1.3" ry="1.8" ${FILL}/>
32
+ <ellipse cx="0.5" cy="2" rx="3.5" ry="3.2" ${FILL}/>
33
+ `,
34
+ },
35
+ // ─── 3. science — éprouvette + bulles ─────────────────────────
36
+ science: {
37
+ key: 'science', label: 'Science',
38
+ motif: `
39
+ <path d="M -2 -6 L -2 4 a 2.5 2.5 0 0 0 5 0 L 3 -6" ${STROKE}/>
40
+ <line x1="-3" y1="-6" x2="4" y2="-6" ${STROKE}/>
41
+ <circle cx="-0.5" cy="2" r="0.7" ${FILL}/>
42
+ <circle cx="1.4" cy="0" r="0.5" ${FILL}/>
43
+ <circle cx="0.4" cy="-2" r="0.4" ${FILL}/>
44
+ `,
45
+ },
46
+ // ─── 4. physics — atome (noyau + 2 orbites croisées) ──────────
47
+ physics: {
48
+ key: 'physics', label: 'Physique',
49
+ motif: `
50
+ <ellipse cx="0" cy="0" rx="6" ry="2.4" ${STROKE}/>
51
+ <ellipse cx="0" cy="0" rx="6" ry="2.4" transform="rotate(60)" ${STROKE}/>
52
+ <ellipse cx="0" cy="0" rx="6" ry="2.4" transform="rotate(-60)" ${STROKE}/>
53
+ <circle cx="0" cy="0" r="1.4" ${FILL}/>
54
+ `,
55
+ },
56
+ // ─── 5. chemistry — bécher avec graduation et liquide ─────────
57
+ chemistry: {
58
+ key: 'chemistry', label: 'Chimie',
59
+ motif: `
60
+ <path d="M -3.5 -5 L -3.5 4 a 1.5 1.5 0 0 0 1.5 1.5 L 2 5.5 a 1.5 1.5 0 0 0 1.5 -1.5 L 3.5 -5" ${STROKE}/>
61
+ <line x1="-4" y1="-5" x2="4" y2="-5" ${STROKE}/>
62
+ <line x1="-2.7" y1="-2.5" x2="-1.4" y2="-2.5" ${STROKE}/>
63
+ <line x1="-2.7" y1="0" x2="-1.4" y2="0" ${STROKE}/>
64
+ <path d="M -3.5 1.5 L 3.5 1.5 L 3.5 4 a 1.5 1.5 0 0 1 -1.5 1.5 L -2 5.5 a 1.5 1.5 0 0 1 -1.5 -1.5 z" ${FILL} opacity="0.35"/>
65
+ `,
66
+ },
67
+ // ─── 6. math — symbole π et signe = ───────────────────────────
68
+ math: {
69
+ key: 'math', label: 'Mathématique',
70
+ motif: `
71
+ <line x1="-5" y1="-3.5" x2="5" y2="-3.5" ${STROKE}/>
72
+ <line x1="-2.5" y1="-3.5" x2="-2.5" y2="3.5" ${STROKE}/>
73
+ <line x1="2.5" y1="-3.5" x2="2.5" y2="3.5" ${STROKE}/>
74
+ <line x1="-5" y1="5.5" x2="5" y2="5.5" ${STROKE}/>
75
+ <line x1="-5" y1="7.2" x2="5" y2="7.2" ${STROKE}/>
76
+ `,
77
+ },
78
+ // ─── 7. nature — feuille + tige ───────────────────────────────
79
+ nature: {
80
+ key: 'nature', label: 'Nature',
81
+ motif: `
82
+ <path d="M 0 6 C -6 4 -6 -4 0 -6 C 6 -4 6 4 0 6 Z" ${STROKE}/>
83
+ <line x1="0" y1="-6" x2="0" y2="6" ${STROKE}/>
84
+ <line x1="0" y1="-3" x2="-3" y2="-1" ${STROKE}/>
85
+ <line x1="0" y1="0" x2="-3.5" y2="2" ${STROKE}/>
86
+ <line x1="0" y1="-3" x2="3" y2="-1" ${STROKE}/>
87
+ <line x1="0" y1="0" x2="3.5" y2="2" ${STROKE}/>
88
+ `,
89
+ },
90
+ // ─── 8. tech — engrenage 8 dents ──────────────────────────────
91
+ tech: {
92
+ key: 'tech', label: 'Tech',
93
+ motif: `
94
+ <path d="
95
+ M -1 -5.6 L 1 -5.6 L 1.4 -4 L 3 -3.4 L 4.2 -4.5 L 5.5 -3.2 L 4.4 -2 L 5 -0.4 L 6.6 0 L 6.6 2
96
+ L 5 2.4 L 4.4 4 L 5.5 5.2 L 4.2 6.5 L 3 5.4 L 1.4 6 L 1 7.6 L -1 7.6 L -1.4 6 L -3 5.4
97
+ L -4.2 6.5 L -5.5 5.2 L -4.4 4 L -5 2.4 L -6.6 2 L -6.6 0 L -5 -0.4 L -4.4 -2 L -5.5 -3.2
98
+ L -4.2 -4.5 L -3 -3.4 L -1.4 -4 Z" transform="translate(0 -1) scale(0.7)" ${STROKE}/>
99
+ <circle cx="0" cy="-1" r="1.5" transform="scale(0.7)" ${STROKE}/>
100
+ `,
101
+ },
102
+ // ─── 9. space — planète saturne + étoile ──────────────────────
103
+ space: {
104
+ key: 'space', label: 'Espace',
105
+ motif: `
106
+ <circle cx="-1" cy="0" r="3.2" ${STROKE}/>
107
+ <ellipse cx="-1" cy="0" rx="6" ry="1.4" transform="rotate(-20 -1 0)" ${STROKE}/>
108
+ <path d="M 5 -5 L 5.6 -3.5 L 7.2 -3.5 L 6 -2.6 L 6.5 -1.1 L 5 -2 L 3.5 -1.1 L 4 -2.6 L 2.8 -3.5 L 4.4 -3.5 Z" ${FILL}/>
109
+ `,
110
+ },
111
+ // ─── 10. music — note + portée ────────────────────────────────
112
+ music: {
113
+ key: 'music', label: 'Musique',
114
+ motif: `
115
+ <ellipse cx="-2" cy="4" rx="2.2" ry="1.7" transform="rotate(-22 -2 4)" ${FILL}/>
116
+ <line x1="0" y1="3" x2="0" y2="-6" ${STROKE}/>
117
+ <path d="M 0 -6 C 3 -5 4 -2 1.5 -1" ${STROKE}/>
118
+ <ellipse cx="3.5" cy="2.5" rx="1.7" ry="1.3" transform="rotate(-22 3.5 2.5)" ${FILL} opacity="0.6"/>
119
+ <line x1="5" y1="1.5" x2="5" y2="-4" ${STROKE} opacity="0.6"/>
120
+ `,
121
+ },
122
+ // ─── 11. book — livre ouvert ──────────────────────────────────
123
+ book: {
124
+ key: 'book', label: 'Livre',
125
+ motif: `
126
+ <path d="M -6 -4 L 0 -3 L 6 -4 L 6 4 L 0 5 L -6 4 Z" ${STROKE}/>
127
+ <line x1="0" y1="-3" x2="0" y2="5" ${STROKE}/>
128
+ <line x1="-4.5" y1="-2" x2="-1.5" y2="-1.5" ${STROKE} opacity="0.6"/>
129
+ <line x1="-4.5" y1="0" x2="-1.5" y2="0.5" ${STROKE} opacity="0.6"/>
130
+ <line x1="1.5" y1="-1.5" x2="4.5" y2="-2" ${STROKE} opacity="0.6"/>
131
+ <line x1="1.5" y1="0.5" x2="4.5" y2="0" ${STROKE} opacity="0.6"/>
132
+ `,
133
+ },
134
+ // ─── 12. health — croix médicale + battement ──────────────────
135
+ health: {
136
+ key: 'health', label: 'Santé',
137
+ motif: `
138
+ <rect x="-1.8" y="-6" width="3.6" height="12" rx="0.8" ${FILL}/>
139
+ <rect x="-6" y="-1.8" width="12" height="3.6" rx="0.8" ${FILL}/>
140
+ <path d="M -8 7 L -5 7 L -3.5 4 L -1.5 9 L 0 6 L 2 8 L 4 7 L 8 7" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round" transform="translate(0 2)"/>
141
+ `,
142
+ },
143
+ };
144
+ /** Liste des clés thèmes natifs (ordre fixe pour itération déterministe). */
145
+ export const THEME_KEYS = [
146
+ 'baby', 'animals', 'science', 'physics', 'chemistry', 'math',
147
+ 'nature', 'tech', 'space', 'music', 'book', 'health',
148
+ ];
149
+ /** Renvoie la liste des clés thèmes natifs. */
150
+ export function listThemes() {
151
+ return [...THEME_KEYS];
152
+ }
153
+ /** Récupère un thème par clé. Lance si inconnu. */
154
+ export function getTheme(key) {
155
+ const theme = THEMES[key];
156
+ if (!theme)
157
+ throw new Error(`[qrpanel] unknown theme: "${key}". Available: ${THEME_KEYS.join(', ')}`);
158
+ return theme;
159
+ }
160
+ /**
161
+ * Tire un thème au hasard dans le pool fourni (ou tous les thèmes si pool absent).
162
+ * Utilise Math.random() — pas de seed (déterminisme = à la charge du caller s'il
163
+ * en a besoin).
164
+ */
165
+ export function pickRandomTheme(pool) {
166
+ const candidates = pool && pool.length > 0 ? pool : THEME_KEYS;
167
+ return candidates[Math.floor(Math.random() * candidates.length)];
168
+ }
169
+ export function buildThemeFrameSvg(theme, opts) {
170
+ const w = opts.width;
171
+ const pad = (opts.framePadding ?? 0.13) * w;
172
+ const color = opts.color ?? '#1e293b';
173
+ const opacity = opts.opacity ?? 1;
174
+ // Auto-scale : à w=600 et padding 13% → motif dimensionné pour rester
175
+ // dans le cadre 0..pad (~78px). Motif local ~14 unités → scale ~5.5.
176
+ const scale = opts.motifScale ?? (pad * 0.45);
177
+ const corners = [
178
+ [pad, pad], // top-left
179
+ [w - pad, pad], // top-right
180
+ [pad, w - pad], // bottom-left
181
+ [w - pad, w - pad], // bottom-right
182
+ ];
183
+ const groups = corners.map(([cx, cy]) => `<g transform="translate(${cx} ${cy}) scale(${scale})" style="color:${color};opacity:${opacity}">${theme.motif}</g>`).join('');
184
+ return groups;
185
+ }
186
+ //# sourceMappingURL=themes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themes.js","sourceRoot":"","sources":["../src/themes.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@mostajs/qrpanel",
3
- "version": "0.2.0",
4
- "description": "QR code panel — server-side PNG generator (qrcode npm, cross-OS, no chromium) + React client component <QrPanel> with copy/share/mailto.",
3
+ "version": "0.3.0",
4
+ "description": "QR code panel — server-side PNG/SVG generator with 12 built-in themes (image-as-frame composite, ECC=H), config-driven (.qrconfig.json), cross-OS no chromium, + React <QrPanel> client with copy/share/mailto.",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "AGPL-3.0-or-later",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "qrpanel": "dist/cli.js"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "types": "./dist/index.d.ts",
@@ -22,6 +25,16 @@
22
25
  "types": "./dist/client.d.ts",
23
26
  "import": "./dist/client.js",
24
27
  "default": "./dist/client.js"
28
+ },
29
+ "./themes": {
30
+ "types": "./dist/themes.d.ts",
31
+ "import": "./dist/themes.js",
32
+ "default": "./dist/themes.js"
33
+ },
34
+ "./config": {
35
+ "types": "./dist/config.d.ts",
36
+ "import": "./dist/config.js",
37
+ "default": "./dist/config.js"
25
38
  }
26
39
  },
27
40
  "files": [
@@ -32,18 +45,22 @@
32
45
  "keywords": [
33
46
  "qrcode",
34
47
  "qr",
48
+ "themes",
49
+ "branded-qr",
35
50
  "react",
36
51
  "invite",
37
- "magic-link"
52
+ "magic-link",
53
+ "config-driven"
38
54
  ],
39
55
  "scripts": {
40
- "build": "tsc",
56
+ "build": "tsc && chmod +x dist/cli.js 2>/dev/null || true",
41
57
  "dev": "tsc --watch",
42
58
  "prepublishOnly": "npm run build"
43
59
  },
44
60
  "dependencies": {
45
61
  "qrcode": "^1.5.4",
46
- "@mostajs/auth": "^3.2.0"
62
+ "@mostajs/auth": "^3.2.0",
63
+ "@resvg/resvg-js": "^2.6.2"
47
64
  },
48
65
  "peerDependencies": {
49
66
  "react": ">=18 <20"