@jjlmoya/utils-home 1.1.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.
Files changed (77) hide show
  1. package/package.json +62 -0
  2. package/src/category/i18n/en.ts +24 -0
  3. package/src/category/i18n/es.ts +24 -0
  4. package/src/category/i18n/fr.ts +24 -0
  5. package/src/category/index.ts +12 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +26 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/seo_length.test.ts +22 -0
  21. package/src/tests/tool_validation.test.ts +17 -0
  22. package/src/tool/dewPointCalculator/bibliography.astro +14 -0
  23. package/src/tool/dewPointCalculator/component.astro +443 -0
  24. package/src/tool/dewPointCalculator/i18n/en.ts +183 -0
  25. package/src/tool/dewPointCalculator/i18n/es.ts +183 -0
  26. package/src/tool/dewPointCalculator/i18n/fr.ts +183 -0
  27. package/src/tool/dewPointCalculator/index.ts +34 -0
  28. package/src/tool/dewPointCalculator/logic.ts +16 -0
  29. package/src/tool/dewPointCalculator/seo.astro +14 -0
  30. package/src/tool/dewPointCalculator/ui.ts +13 -0
  31. package/src/tool/ledSavingCalculator/bibliography.astro +14 -0
  32. package/src/tool/ledSavingCalculator/component.astro +520 -0
  33. package/src/tool/ledSavingCalculator/i18n/en.ts +217 -0
  34. package/src/tool/ledSavingCalculator/i18n/es.ts +217 -0
  35. package/src/tool/ledSavingCalculator/i18n/fr.ts +217 -0
  36. package/src/tool/ledSavingCalculator/index.ts +34 -0
  37. package/src/tool/ledSavingCalculator/logic.ts +31 -0
  38. package/src/tool/ledSavingCalculator/seo.astro +14 -0
  39. package/src/tool/ledSavingCalculator/ui.ts +32 -0
  40. package/src/tool/projectorCalculator/bibliography.astro +14 -0
  41. package/src/tool/projectorCalculator/component.astro +569 -0
  42. package/src/tool/projectorCalculator/i18n/en.ts +181 -0
  43. package/src/tool/projectorCalculator/i18n/es.ts +181 -0
  44. package/src/tool/projectorCalculator/i18n/fr.ts +181 -0
  45. package/src/tool/projectorCalculator/index.ts +34 -0
  46. package/src/tool/projectorCalculator/logic.ts +21 -0
  47. package/src/tool/projectorCalculator/seo.astro +14 -0
  48. package/src/tool/projectorCalculator/ui.ts +16 -0
  49. package/src/tool/qrGenerator/bibliography.astro +14 -0
  50. package/src/tool/qrGenerator/component.astro +499 -0
  51. package/src/tool/qrGenerator/i18n/en.ts +233 -0
  52. package/src/tool/qrGenerator/i18n/es.ts +233 -0
  53. package/src/tool/qrGenerator/i18n/fr.ts +233 -0
  54. package/src/tool/qrGenerator/index.ts +34 -0
  55. package/src/tool/qrGenerator/logic.ts +27 -0
  56. package/src/tool/qrGenerator/seo.astro +14 -0
  57. package/src/tool/qrGenerator/ui.ts +23 -0
  58. package/src/tool/solarCalculator/bibliography.astro +14 -0
  59. package/src/tool/solarCalculator/component.astro +532 -0
  60. package/src/tool/solarCalculator/i18n/en.ts +176 -0
  61. package/src/tool/solarCalculator/i18n/es.ts +176 -0
  62. package/src/tool/solarCalculator/i18n/fr.ts +176 -0
  63. package/src/tool/solarCalculator/index.ts +34 -0
  64. package/src/tool/solarCalculator/logic.ts +31 -0
  65. package/src/tool/solarCalculator/seo.astro +14 -0
  66. package/src/tool/solarCalculator/ui.ts +11 -0
  67. package/src/tool/tariffComparator/bibliography.astro +14 -0
  68. package/src/tool/tariffComparator/component.astro +595 -0
  69. package/src/tool/tariffComparator/i18n/en.ts +192 -0
  70. package/src/tool/tariffComparator/i18n/es.ts +192 -0
  71. package/src/tool/tariffComparator/i18n/fr.ts +192 -0
  72. package/src/tool/tariffComparator/index.ts +34 -0
  73. package/src/tool/tariffComparator/logic.ts +47 -0
  74. package/src/tool/tariffComparator/seo.astro +14 -0
  75. package/src/tool/tariffComparator/ui.ts +25 -0
  76. package/src/tools.ts +9 -0
  77. package/src/types.ts +72 -0
@@ -0,0 +1,233 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { QRGeneratorUI } from '../ui';
4
+
5
+ const slug = 'generateur-qr';
6
+ const title = 'Générateur de Codes QR Hors Ligne';
7
+ const description =
8
+ 'Générez des codes QR pour WiFi, URLs et Contacts de façon 100% sécurisée dans votre navigateur. Vos données ne quittent jamais votre appareil.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Ces codes QR expirent-ils ?',
13
+ answer:
14
+ 'Non. Les codes générés ici sont statiques. L\'information est encodée directement dans l\'image et ne dépend d\'aucun lien externe ni redirection. Ils fonctionneront toujours.',
15
+ },
16
+ {
17
+ question: 'Conservez-vous mes données ?',
18
+ answer:
19
+ 'Absolument pas. Tout le processus se déroule dans votre navigateur (côté client). Aucune donnée n\'est envoyée à nos serveurs. C\'est 100% privé et sécurisé.',
20
+ },
21
+ {
22
+ question: 'Fonctionne-t-il sur iPhone et Android ?',
23
+ answer:
24
+ 'Oui. La plupart des appareils photo modernes d\'iOS et Android lisent les codes QR nativement et suggèrent l\'action correspondante (connexion WiFi, ouverture de lien, etc.).',
25
+ },
26
+ {
27
+ question: 'Puis-je l\'utiliser sans internet ?',
28
+ answer:
29
+ 'Oui. Une fois la page chargée, vous pouvez couper le WiFi ou les données et le générateur continuera à fonctionner parfaitement car il ne dépend pas de serveurs externes.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Choisir le type de QR',
36
+ text: 'Sélectionnez si vous voulez un code pour un réseau WiFi, un lien URL ou un contact (vCard).',
37
+ },
38
+ {
39
+ name: 'Saisir les données',
40
+ text: 'Remplissez les champs nécessaires, comme le nom du réseau et le mot de passe, ou l\'adresse web.',
41
+ },
42
+ {
43
+ name: 'Générer et vérifier',
44
+ text: 'Le code est généré instantanément. Vous pouvez essayer de le scanner directement depuis l\'écran.',
45
+ },
46
+ {
47
+ name: 'Télécharger',
48
+ text: 'Enregistrez le code QR en image (.webp) pour l\'imprimer ou le partager numériquement.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowTo> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step) => ({
68
+ '@type': 'HowToStep',
69
+ name: step.name,
70
+ text: step.text,
71
+ })),
72
+ };
73
+
74
+ const appSchema: WithContext<SoftwareApplication> = {
75
+ '@context': 'https://schema.org',
76
+ '@type': 'SoftwareApplication',
77
+ name: title,
78
+ description,
79
+ applicationCategory: 'UtilityApplication',
80
+ operatingSystem: 'All',
81
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
82
+ inLanguage: 'fr',
83
+ };
84
+
85
+ export const content: ToolLocaleContent<QRGeneratorUI> = {
86
+ slug,
87
+ title,
88
+ description,
89
+ faqTitle: 'Questions Fréquentes',
90
+ faq: faqData,
91
+ bibliographyTitle: 'Bibliographie',
92
+ bibliography: [
93
+ {
94
+ name: 'node-qrcode: bibliothèque de génération de codes QR',
95
+ url: 'https://github.com/soldair/node-qrcode',
96
+ },
97
+ {
98
+ name: 'RFC 6350: Spécification du format vCard',
99
+ url: 'https://www.rfc-editor.org/rfc/rfc6350',
100
+ },
101
+ {
102
+ name: 'ZXing: Barcode Contents — WiFi, vCard et URL',
103
+ url: 'https://github.com/zxing/zxing/wiki/Barcode-Contents',
104
+ },
105
+ ],
106
+ howTo: howToData,
107
+ schemas: [faqSchema, howToSchema, appSchema],
108
+ seo: [
109
+ {
110
+ type: 'title',
111
+ text: 'Pourquoi Hors Ligne ? La Confidentialité Avant Tout',
112
+ level: 2,
113
+ },
114
+ {
115
+ type: 'paragraph',
116
+ html: 'La plupart des générateurs QR en ligne envoient vos données à un serveur. C\'est un risque, surtout pour les <strong>mots de passe WiFi</strong> ou les <strong>données personnelles</strong>. Cet outil utilise JavaScript pour générer le code QR directement sur votre appareil. Vous pouvez même couper internet et il continuera à fonctionner.',
117
+ },
118
+ {
119
+ type: 'stats',
120
+ items: [
121
+ { value: '100%', label: 'Privé', icon: 'mdi:shield-lock' },
122
+ { value: 'Offline', label: 'Sans Serveur', icon: 'mdi:wifi-off' },
123
+ { value: 'WebP', label: 'Téléchargement Direct', icon: 'mdi:download' },
124
+ ],
125
+ columns: 3,
126
+ },
127
+ {
128
+ type: 'diagnostic',
129
+ variant: 'success',
130
+ title: 'Code Source Ouvert et Transparent',
131
+ icon: 'mdi:github',
132
+ badge: 'Open Source',
133
+ html: '<p>Vous ne nous faites pas confiance ? Le code de cet outil est 100% open source. Vous pouvez vérifier son fonctionnement ou le télécharger pour l\'exécuter sur votre propre ordinateur sans internet.</p>',
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: 'Cas d\'Utilisation',
138
+ level: 3,
139
+ },
140
+ {
141
+ type: 'comparative',
142
+ items: [
143
+ {
144
+ title: 'QR WiFi',
145
+ description: 'Partagez votre réseau WiFi avec des invités sans avoir à dicter le mot de passe. Ils scannent et se connectent automatiquement.',
146
+ icon: 'mdi:wifi',
147
+ points: ['Pris en charge nativement par iOS et Android', 'Compatible WPA2, WEP et réseaux ouverts'],
148
+ },
149
+ {
150
+ title: 'QR URL',
151
+ description: 'Transformez n\'importe quel lien web en code scannable. Idéal pour l\'impression sur des supports physiques.',
152
+ icon: 'mdi:link',
153
+ points: ['Toute URL valide', 'Pas de date d\'expiration'],
154
+ },
155
+ {
156
+ title: 'QR vCard',
157
+ description: 'Carte de visite numérique. En scannant, le téléphone suggère "Ajouter un contact" avec tous les champs pré-remplis.',
158
+ icon: 'mdi:card-account-details',
159
+ points: ['Nom, téléphone, email et entreprise', 'Format standard vCard 3.0'],
160
+ },
161
+ ],
162
+ columns: 3,
163
+ },
164
+ {
165
+ type: 'title',
166
+ text: 'Guide d\'Utilisation',
167
+ level: 3,
168
+ },
169
+ {
170
+ type: 'paragraph',
171
+ html: '<strong>Pour la maison (WiFi) :</strong> Fatigué de chercher le papier avec le mot de passe WiFi à chaque fois que des amis viennent ? Générez un QR avec le SSID et le mot de passe. Imprimez-le et collez-le dans un endroit visible. Vos invités n\'ont qu\'à ouvrir l\'appareil photo, pointer et voilà, ils se connectent sans rien taper.',
172
+ },
173
+ {
174
+ type: 'paragraph',
175
+ html: '<strong>Pour les Professionnels (vCard) :</strong> Lors d\'événements de networking, les cartes de visite papier appartiennent au passé. Générez un QR avec vos coordonnées. Gardez-le sur votre téléphone ou imprimez-le au dos de votre badge. En le scannant, votre nouveau contact peut enregistrer votre nom, téléphone, email et entreprise directement dans son carnet d\'adresses.',
176
+ },
177
+ {
178
+ type: 'glossary',
179
+ items: [
180
+ {
181
+ term: 'Code QR',
182
+ definition: 'Code-barres 2D pouvant stocker jusqu\'à 4 296 caractères alphanumériques. Les appareils photo modernes le lisent en moins d\'une seconde.',
183
+ },
184
+ {
185
+ term: 'vCard',
186
+ definition: 'Format standard pour les cartes de contact numériques (RFC 6350). Compatible avec iOS, Android, Outlook et la plupart des gestionnaires de contacts.',
187
+ },
188
+ {
189
+ term: 'SSID',
190
+ definition: 'Service Set Identifier. Le nom visible d\'un réseau WiFi qui apparaît lors de la recherche de réseaux disponibles sur votre appareil.',
191
+ },
192
+ {
193
+ term: 'WPA2',
194
+ definition: 'Wi-Fi Protected Access 2. Le protocole de sécurité WiFi le plus répandu. Utilise le chiffrement AES pour protéger les communications.',
195
+ },
196
+ ],
197
+ },
198
+ {
199
+ type: 'summary',
200
+ title: 'Clés pour Bien Utiliser cet Outil',
201
+ items: [
202
+ 'Toutes les données sont traitées dans votre navigateur, jamais sur un serveur externe.',
203
+ 'Le QR WiFi nécessite le SSID et le mot de passe exacts (sensible à la casse).',
204
+ 'Les codes QR générés sont statiques : si vous changez votre mot de passe WiFi, générez-en un nouveau.',
205
+ 'Téléchargez en WebP pour une qualité maximale lors de l\'impression ou du partage.',
206
+ 'Essayez de scanner le QR depuis l\'écran avant de l\'imprimer.',
207
+ ],
208
+ },
209
+ ],
210
+ ui: {
211
+ tabWifi: 'WiFi',
212
+ tabUrl: 'URL',
213
+ tabContact: 'Contact',
214
+ labelSsid: 'Nom du Réseau (SSID)',
215
+ labelPassword: 'Mot de Passe',
216
+ labelEncryption: 'Sécurité',
217
+ labelHidden: 'Réseau Caché',
218
+ labelUrl: 'Adresse Web (URL)',
219
+ labelName: 'Prénom',
220
+ labelSurname: 'Nom de Famille',
221
+ labelPhone: 'Téléphone',
222
+ labelEmail: 'Email',
223
+ labelOrg: 'Organisation / Entreprise',
224
+ encWpa: 'WPA/WPA2',
225
+ encWep: 'WEP',
226
+ encNone: 'Aucune',
227
+ downloadBtn: 'Télécharger PNG',
228
+ privacyMsg: 'Généré 100% dans votre navigateur. Vos données ne voyagent jamais sur Internet.',
229
+ placeholderSsid: 'MaBox_5G',
230
+ placeholderUrl: 'https://exemple.com',
231
+ placeholderPassword: '••••••••',
232
+ },
233
+ };
@@ -0,0 +1,34 @@
1
+ import type { HomeToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
+ import QRGeneratorComponent from './component.astro';
3
+ import QRGeneratorSEO from './seo.astro';
4
+ import QRGeneratorBibliography from './bibliography.astro';
5
+
6
+ import type { QRGeneratorUI } from './ui';
7
+
8
+ export type QRGeneratorLocaleContent = ToolLocaleContent<QRGeneratorUI>;
9
+
10
+ import { content as es } from './i18n/es';
11
+ import { content as en } from './i18n/en';
12
+ import { content as fr } from './i18n/fr';
13
+
14
+ export const qrGenerator: HomeToolEntry<QRGeneratorUI> = {
15
+ id: 'qr-generator',
16
+ icons: {
17
+ bg: 'mdi:qrcode',
18
+ fg: 'mdi:wifi',
19
+ },
20
+ i18n: {
21
+ es: async () => es,
22
+ en: async () => en,
23
+ fr: async () => fr,
24
+ },
25
+ };
26
+
27
+ export { QRGeneratorComponent, QRGeneratorSEO, QRGeneratorBibliography };
28
+
29
+ export const QR_GENERATOR_TOOL: ToolDefinition = {
30
+ entry: qrGenerator,
31
+ Component: QRGeneratorComponent,
32
+ SEOComponent: QRGeneratorSEO,
33
+ BibliographyComponent: QRGeneratorBibliography,
34
+ };
@@ -0,0 +1,27 @@
1
+ export function wifi(
2
+ ssid: string,
3
+ password: string,
4
+ encryption: string,
5
+ hidden: boolean
6
+ ): string {
7
+ if (!ssid) return '';
8
+ const esc = (s: string) => s.replace(/([\\;,:])/g, '\\$1');
9
+ return `WIFI:S:${esc(ssid)};T:${encryption};P:${esc(password)};H:${hidden};;`;
10
+ }
11
+
12
+ export function url(value: string): string {
13
+ return value;
14
+ }
15
+
16
+ export interface VCardData {
17
+ name: string;
18
+ surname: string;
19
+ phone: string;
20
+ email: string;
21
+ org: string;
22
+ }
23
+
24
+ export function vcard(data: VCardData): string {
25
+ if (!Object.values(data).some((v) => v)) return '';
26
+ return `BEGIN:VCARD\nVERSION:3.0\nN:${data.surname};${data.name}\nFN:${data.name} ${data.surname}\nORG:${data.org}\nTEL:${data.phone}\nEMAIL:${data.email}\nEND:VCARD`;
27
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { qrGenerator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await qrGenerator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+ <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
@@ -0,0 +1,23 @@
1
+ export interface QRGeneratorUI extends Record<string, string> {
2
+ tabWifi: string;
3
+ tabUrl: string;
4
+ tabContact: string;
5
+ labelSsid: string;
6
+ labelPassword: string;
7
+ labelEncryption: string;
8
+ labelHidden: string;
9
+ labelUrl: string;
10
+ labelName: string;
11
+ labelSurname: string;
12
+ labelPhone: string;
13
+ labelEmail: string;
14
+ labelOrg: string;
15
+ encWpa: string;
16
+ encWep: string;
17
+ encNone: string;
18
+ downloadBtn: string;
19
+ privacyMsg: string;
20
+ placeholderSsid: string;
21
+ placeholderUrl: string;
22
+ placeholderPassword: string;
23
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { solarCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await solarCalculator.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SharedBibliography links={content.bibliography} />}