@jjlmoya/utils-social 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 (85) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +23 -0
  3. package/src/category/i18n/es.ts +23 -0
  4. package/src/category/i18n/fr.ts +23 -0
  5. package/src/category/index.ts +13 -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 +27 -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/redditFormatter/bibliography.astro +14 -0
  23. package/src/tool/redditFormatter/component.astro +246 -0
  24. package/src/tool/redditFormatter/i18n/en.ts +193 -0
  25. package/src/tool/redditFormatter/i18n/es.ts +193 -0
  26. package/src/tool/redditFormatter/i18n/fr.ts +193 -0
  27. package/src/tool/redditFormatter/index.ts +34 -0
  28. package/src/tool/redditFormatter/logic.ts +24 -0
  29. package/src/tool/redditFormatter/seo.astro +14 -0
  30. package/src/tool/redditFormatter/ui.ts +13 -0
  31. package/src/tool/safeZones/bibliography.astro +14 -0
  32. package/src/tool/safeZones/component.astro +857 -0
  33. package/src/tool/safeZones/i18n/en.ts +244 -0
  34. package/src/tool/safeZones/i18n/es.ts +244 -0
  35. package/src/tool/safeZones/i18n/fr.ts +244 -0
  36. package/src/tool/safeZones/index.ts +34 -0
  37. package/src/tool/safeZones/logic.ts +137 -0
  38. package/src/tool/safeZones/seo.astro +14 -0
  39. package/src/tool/safeZones/ui.ts +34 -0
  40. package/src/tool/socialImageResizer/bibliography.astro +14 -0
  41. package/src/tool/socialImageResizer/component.astro +498 -0
  42. package/src/tool/socialImageResizer/i18n/en.ts +211 -0
  43. package/src/tool/socialImageResizer/i18n/es.ts +211 -0
  44. package/src/tool/socialImageResizer/i18n/fr.ts +211 -0
  45. package/src/tool/socialImageResizer/index.ts +34 -0
  46. package/src/tool/socialImageResizer/logic.ts +133 -0
  47. package/src/tool/socialImageResizer/seo.astro +14 -0
  48. package/src/tool/socialImageResizer/ui.ts +7 -0
  49. package/src/tool/socialValueCalculator/bibliography.astro +14 -0
  50. package/src/tool/socialValueCalculator/component.astro +829 -0
  51. package/src/tool/socialValueCalculator/i18n/en.ts +310 -0
  52. package/src/tool/socialValueCalculator/i18n/es.ts +310 -0
  53. package/src/tool/socialValueCalculator/i18n/fr.ts +310 -0
  54. package/src/tool/socialValueCalculator/index.ts +34 -0
  55. package/src/tool/socialValueCalculator/logic.ts +60 -0
  56. package/src/tool/socialValueCalculator/seo.astro +14 -0
  57. package/src/tool/socialValueCalculator/ui.ts +31 -0
  58. package/src/tool/tinderPhotoOptimizer/bibliography.astro +14 -0
  59. package/src/tool/tinderPhotoOptimizer/component.astro +1514 -0
  60. package/src/tool/tinderPhotoOptimizer/i18n/en.ts +248 -0
  61. package/src/tool/tinderPhotoOptimizer/i18n/es.ts +248 -0
  62. package/src/tool/tinderPhotoOptimizer/i18n/fr.ts +248 -0
  63. package/src/tool/tinderPhotoOptimizer/index.ts +34 -0
  64. package/src/tool/tinderPhotoOptimizer/logic.ts +199 -0
  65. package/src/tool/tinderPhotoOptimizer/seo.astro +14 -0
  66. package/src/tool/tinderPhotoOptimizer/ui.ts +37 -0
  67. package/src/tool/youtubeThumbnail/bibliography.astro +14 -0
  68. package/src/tool/youtubeThumbnail/component.astro +419 -0
  69. package/src/tool/youtubeThumbnail/i18n/en.ts +207 -0
  70. package/src/tool/youtubeThumbnail/i18n/es.ts +207 -0
  71. package/src/tool/youtubeThumbnail/i18n/fr.ts +207 -0
  72. package/src/tool/youtubeThumbnail/index.ts +34 -0
  73. package/src/tool/youtubeThumbnail/logic.ts +7 -0
  74. package/src/tool/youtubeThumbnail/seo.astro +14 -0
  75. package/src/tool/youtubeThumbnail/ui.ts +13 -0
  76. package/src/tool/youtubeThumbnailPreviewer/bibliography.astro +14 -0
  77. package/src/tool/youtubeThumbnailPreviewer/component.astro +791 -0
  78. package/src/tool/youtubeThumbnailPreviewer/i18n/en.ts +321 -0
  79. package/src/tool/youtubeThumbnailPreviewer/i18n/es.ts +321 -0
  80. package/src/tool/youtubeThumbnailPreviewer/i18n/fr.ts +321 -0
  81. package/src/tool/youtubeThumbnailPreviewer/index.ts +34 -0
  82. package/src/tool/youtubeThumbnailPreviewer/seo.astro +14 -0
  83. package/src/tool/youtubeThumbnailPreviewer/ui.ts +19 -0
  84. package/src/tools.ts +10 -0
  85. package/src/types.ts +72 -0
@@ -0,0 +1,321 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { YoutubeThumbnailPreviewerUI } from '../ui';
4
+
5
+ const slug = 'apercu-miniatures-youtube';
6
+ const title = 'Aperçu des Miniatures YouTube en Ligne - Améliorez votre CTR Gratuitement';
7
+ const description =
8
+ 'Téléchargez votre miniature et visualisez comment elle apparaît dans le vrai feed YouTube mobile et desktop. Simulateur mode sombre et clair pour optimiser les clics instantanément.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Pourquoi est-il important de tester les miniatures YouTube ?',
13
+ answer:
14
+ "La plupart des utilisateurs regardent YouTube sur des appareils mobiles. Une miniature qui s'affiche bien sur votre moniteur peut être illisible sur un petit écran. La tester dans un simulateur garantit que le texte est clair et que le sujet principal ressort à n'importe quelle taille.",
15
+ },
16
+ {
17
+ question: 'Dois-je m\'inscrire pour utiliser cet outil ?',
18
+ answer:
19
+ "Non. Notre outil est 100% gratuit et fonctionne directement dans votre navigateur. Vous n'avez pas besoin de créer un compte ni de laisser votre adresse e-mail pour optimiser vos miniatures.",
20
+ },
21
+ {
22
+ question: 'Mes designs sont-ils téléchargés sur votre serveur ?',
23
+ answer:
24
+ "Absolument pas. La confidentialité est notre priorité absolue. Lorsque vous sélectionnez un fichier, il est chargé localement dans la mémoire de votre navigateur via une URL temporaire. Personne sauf vous ne peut voir le design que vous testez.",
25
+ },
26
+ {
27
+ question: 'Comment cet outil aide-t-il à améliorer mon CTR ?',
28
+ answer:
29
+ "Le CTR (taux de clics) est le pourcentage de personnes qui cliquent en voyant votre miniature. En simulant l'environnement réel (fond noir vs blanc, mobile vs PC), vous pouvez corriger les erreurs de contraste et de composition avant de publier, augmentant ainsi vos clics.",
30
+ },
31
+ {
32
+ question: 'Fonctionne-t-il avec le mode sombre officiel de YouTube ?',
33
+ answer:
34
+ "Oui. Nous avons inclus un sélecteur de thèmes (Clair et Sombre) qui imite exactement les couleurs hexadécimales utilisées par l'application officielle YouTube dans les deux modes.",
35
+ },
36
+ ];
37
+
38
+ const howToData = [
39
+ {
40
+ name: 'Téléchargez votre design',
41
+ text: "Cliquez sur la zone de dépôt ou faites glisser votre fichier image (PNG, JPG ou WebP) directement dans l'outil.",
42
+ },
43
+ {
44
+ name: 'Définissez le contexte',
45
+ text: 'Tapez le titre de votre vidéo et le nom de votre chaîne pour que la simulation soit aussi réaliste que possible.',
46
+ },
47
+ {
48
+ name: "Changez d'appareil",
49
+ text: "Alternez entre la vue 'Desktop' et 'Mobile' pour vérifier la lisibilité sur des écrans de différentes tailles.",
50
+ },
51
+ {
52
+ name: 'Testez le contraste',
53
+ text: "Activez le thème 'Sombre' pour vérifier si les couleurs ressortent correctement sur le fond noir de YouTube.",
54
+ },
55
+ ];
56
+
57
+ const faqSchema: WithContext<FAQPage> = {
58
+ '@context': 'https://schema.org',
59
+ '@type': 'FAQPage',
60
+ mainEntity: faqData.map((item) => ({
61
+ '@type': 'Question',
62
+ name: item.question,
63
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
64
+ })),
65
+ };
66
+
67
+ const howToSchema: WithContext<HowToThing> = {
68
+ '@context': 'https://schema.org',
69
+ '@type': 'HowTo',
70
+ name: title,
71
+ description,
72
+ step: howToData.map((step, i) => ({
73
+ '@type': 'HowToStep',
74
+ position: i + 1,
75
+ name: step.name,
76
+ text: step.text,
77
+ })),
78
+ };
79
+
80
+ const appSchema: WithContext<SoftwareApplication> = {
81
+ '@context': 'https://schema.org',
82
+ '@type': 'SoftwareApplication',
83
+ name: title,
84
+ description,
85
+ applicationCategory: 'UtilityApplication',
86
+ operatingSystem: 'All',
87
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
88
+ inLanguage: 'fr',
89
+ };
90
+
91
+ export const content: ToolLocaleContent<YoutubeThumbnailPreviewerUI> = {
92
+ slug,
93
+ title,
94
+ description,
95
+ faqTitle: 'Questions Fréquentes',
96
+ faq: faqData,
97
+ bibliographyTitle: 'Références',
98
+ bibliography: [
99
+ {
100
+ name: 'YouTube Help: Create custom video thumbnails',
101
+ url: 'https://support.google.com/youtube/answer/141805',
102
+ },
103
+ {
104
+ name: 'Nielsen Norman Group: Visual Processing and UX Design',
105
+ url: 'https://www.nngroup.com/articles/visual-processing/',
106
+ },
107
+ {
108
+ name: 'Derral Eves: The YouTube Formula (Thumbnail Strategy)',
109
+ url: 'https://derraleves.com/the-youtube-formula/',
110
+ },
111
+ ],
112
+ howTo: howToData,
113
+ schemas: [faqSchema, howToSchema, appSchema],
114
+ seo: [
115
+ {
116
+ type: 'title',
117
+ text: 'Aperçu des Miniatures YouTube : Maîtrisez le CTR de votre Chaîne',
118
+ level: 2,
119
+ },
120
+ {
121
+ type: 'paragraph',
122
+ html: "Dans l'écosystème YouTube, la miniature (ou thumbnail) est la porte d'entrée de votre contenu. Vous pouvez avoir la meilleure vidéo du monde, avec un montage Hollywood et un scénario digne d'un Oscar, mais si personne ne clique, votre travail sera invisible pour l'algorithme. C'est là qu'intervient le <strong>CTR (taux de clics)</strong>, et la miniature est le facteur déterminant.",
123
+ },
124
+ {
125
+ type: 'title',
126
+ text: 'Pourquoi tester vos miniatures avant de les publier',
127
+ level: 3,
128
+ },
129
+ {
130
+ type: 'list',
131
+ items: [
132
+ '<strong>Aperçu Réel :</strong> Voyez votre miniature telle qu\'elle apparaîtra dans le feed YouTube.',
133
+ '<strong>Mode Sombre et Clair :</strong> Assurez-vous que les couleurs ressortent dans n\'importe quelle configuration utilisateur.',
134
+ '<strong>Simulateur d\'Appareils :</strong> Vérifiez la lisibilité du texte sur les moniteurs et les petits mobiles.',
135
+ '<strong>Optimisation du CTR :</strong> Comparez votre design avec l\'interface native pour maximiser les clics.',
136
+ '<strong>Sans Inscription :</strong> Téléchargez votre image et testez-la instantanément sans créer de compte.',
137
+ '<strong>Confidentialité Garantie :</strong> Vos designs sont traités localement et ne sont jamais envoyés vers des serveurs.',
138
+ ],
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'Beaucoup de créateurs font l\'erreur de concevoir leurs miniatures sur de grands moniteurs, en les voyant en plein écran dans leurs éditeurs favoris. Le problème est que l\'utilisateur final les voit rarement ainsi. La plupart les consomment sur un appareil mobile en faisant défiler infiniment, ou dans un coin du moniteur en mode sombre. Notre <strong>Aperçu de Miniatures YouTube</strong> vous permet de briser cette "illusion du designer" et de voir la réalité chirurgicale du feed.',
143
+ },
144
+ {
145
+ type: 'title',
146
+ text: 'Métriques Techniques et Performance',
147
+ level: 3,
148
+ },
149
+ {
150
+ type: 'grid',
151
+ columns: [
152
+ { title: '0,2 s', body: 'Temps de Réponse' },
153
+ { title: '4K', body: 'Résolution Maximale' },
154
+ { title: '100%', body: 'Confidentialité Locale' },
155
+ { title: 'HD', body: 'Qualité Native' },
156
+ ],
157
+ },
158
+ {
159
+ type: 'title',
160
+ text: 'La Psychologie du Clic : Pourquoi les miniatures échouent-elles ?',
161
+ level: 3,
162
+ },
163
+ {
164
+ type: 'paragraph',
165
+ html: 'Le cerveau humain traite les images des milliers de fois plus vite que le texte. Pourtant, sur YouTube, la concurrence est brutale. Votre miniature ne doit pas seulement être "jolie", elle doit être <strong>lisible</strong> et avoir du <strong>contraste</strong>.',
166
+ },
167
+ {
168
+ type: 'paragraph',
169
+ html: "Une erreur courante est d'utiliser des couleurs qui se fondent dans le fond de YouTube. Si vous utilisez des gris foncés et que votre spectateur est en mode sombre, votre vidéo disparaîtra simplement de sa vision périphérique. En utilisant ce testeur, vous pouvez alterner entre les thèmes et vous assurer que votre design \"pop\" (ressort) dans n'importe quel scénario.",
170
+ },
171
+ {
172
+ type: 'title',
173
+ text: 'Comparaison Directe : Design vs. Réalité',
174
+ level: 3,
175
+ },
176
+ {
177
+ type: 'paragraph',
178
+ html: "Vaut-il la peine de passer 30 secondes à tester la miniature ? La réponse est un OUI catégorique. Une miniature optimisée peut doubler vos vues dans les premières 24 heures, ce qui indique à l'IA de YouTube que votre contenu a de l'\"accroche\".",
179
+ },
180
+ {
181
+ type: 'grid',
182
+ columns: [
183
+ {
184
+ title: 'Conception dans Photoshop / Canva',
185
+ body: "Fausse impression de taille réelle · Ignore le contraste avec le fond de l'App · Le texte semble lisible mais peut ne pas l'être · Vous ne voyez pas les éléments de l'UI (durée, avatars)",
186
+ },
187
+ {
188
+ title: 'Aperçu de Miniatures YouTube',
189
+ body: 'Vue réelle dans le feed principal (Home) · Contraste vérifié en mode sombre vs clair · Lisibilité du texte garantie sur mobile · Simulation des titres et noms de chaîne',
190
+ },
191
+ ],
192
+ },
193
+ {
194
+ type: 'title',
195
+ text: 'Checklist pour une Miniature avec un CTR Supérieur à 10%',
196
+ level: 3,
197
+ },
198
+ {
199
+ type: 'paragraph',
200
+ html: 'Avant d\'exporter votre design final, assurez-vous de parcourir cette liste de contrôle avec notre simulateur professionnel :',
201
+ },
202
+ {
203
+ type: 'list',
204
+ items: [
205
+ 'Le texte est-il lisible sur un petit écran de mobile ?',
206
+ "Y a-t-il suffisamment de contraste entre le fond et le sujet principal ?",
207
+ 'La miniature est-elle belle sur le fond noir du Mode Sombre ?',
208
+ 'Le titre de la vidéo cache-t-il des informations vitales de l\'image ?',
209
+ 'La durée de la vidéo (le petit carré noir) cache-t-elle quelque chose d\'important ?',
210
+ 'Le visage ou l\'objet principal transmet-il l\'émotion souhaitée à taille réduite ?',
211
+ ],
212
+ },
213
+ {
214
+ type: 'title',
215
+ text: "Anatomie d'une Miniature à Fort Impact",
216
+ level: 3,
217
+ },
218
+ {
219
+ type: 'paragraph',
220
+ html: "D'après l'analyse des plus grandes chaînes du monde, une miniature gagnante suit généralement ce schéma structurel :",
221
+ },
222
+ {
223
+ type: 'grid',
224
+ columns: [
225
+ {
226
+ title: 'Sujet Principal',
227
+ body: "Foyer d'attention primaire · Utilisez des découpes nettes avec un léger bord ou une saturation supplémentaire.",
228
+ },
229
+ {
230
+ title: 'Texte (Max 3 mots)',
231
+ body: 'Contexte instantané · Utilisez des polices Sans Serif grasses et des couleurs complémentaires.',
232
+ },
233
+ {
234
+ title: 'Arrière-plan Flou',
235
+ body: 'Séparation des plans · Ajoute de la profondeur pour que le sujet principal "saute" de l\'écran.',
236
+ },
237
+ {
238
+ title: 'Espace de Durée',
239
+ body: "Éviter les erreurs · Ne placez pas de visages ou de texte dans le coin inférieur droit.",
240
+ },
241
+ ],
242
+ },
243
+ {
244
+ type: 'tip',
245
+ title: 'L\'Astuce de la Zone Morte',
246
+ html: "<p>YouTube place toujours un encadré noir avec la durée de la vidéo dans le coin inférieur droit de la miniature. Des milliers de créateurs mettent des éléments vitaux dans cette zone, pour découvrir ensuite que l'App les couvre. Notre outil simule cet encadré pour que vous ne couvriez jamais votre meilleur plan.</p>",
247
+ },
248
+ {
249
+ type: 'title',
250
+ text: "Avantages et Limites de l'Outil",
251
+ level: 3,
252
+ },
253
+ {
254
+ type: 'grid',
255
+ columns: [
256
+ {
257
+ title: 'Interface ultra rapide et réactive',
258
+ body: "Limitation : Ne permet pas l'édition d'image (utiliser Canva/PS)",
259
+ },
260
+ {
261
+ title: 'Maquettes exactes de l\'App et du Web',
262
+ body: 'Limitation : Ne simule pas les publicités Pre-roll',
263
+ },
264
+ {
265
+ title: 'Gratuit et sans publicité intrusive',
266
+ body: 'Limitation : Prend uniquement en charge les fichiers locaux',
267
+ },
268
+ ],
269
+ },
270
+ {
271
+ type: 'title',
272
+ text: "Utilisation du Mode 'Split' (Comparaison Directe)",
273
+ level: 3,
274
+ },
275
+ {
276
+ type: 'paragraph',
277
+ html: "C'est la fonction phare. En activant le mode Split, vous verrez votre miniature sous le prisme du Mode Clair et du Mode Sombre simultanément. C'est la façon définitive de vérifier si votre palette de couleurs est universelle ou si elle nécessite des ajustements de luminosité et de contraste.",
278
+ },
279
+ {
280
+ type: 'title',
281
+ text: 'Confidentialité : Vos Designs ne sont pas Téléchargés dans le Cloud',
282
+ level: 3,
283
+ },
284
+ {
285
+ type: 'paragraph',
286
+ html: "Nous savons que vos miniatures font partie de votre stratégie secrète avant un lancement. C'est pourquoi nous avons conçu cet outil pour qu'il fonctionne exclusivement dans le moteur de votre navigateur. <strong>Rien n'est envoyé sur internet</strong>. Le fichier que vous sélectionnez est chargé via une URL locale temporaire qui disparaît lorsque vous fermez l'onglet. Votre propriété intellectuelle est 100% sous votre contrôle.",
287
+ },
288
+ {
289
+ type: 'title',
290
+ text: 'Conclusion : Le Pixel Parfait Garanti',
291
+ level: 3,
292
+ },
293
+ {
294
+ type: 'paragraph',
295
+ html: "Arrêtez de deviner et commencez à valider. L'<strong>Aperçu de Miniatures YouTube</strong> de JJLMoya est l'outil gratuit qui sépare les créateurs amateurs des professionnels du contenu. Un petit ajustement dans la taille d'une police ou dans la position du sujet peut faire la différence entre une vidéo qui passe inaperçue et un succès viral.",
296
+ },
297
+ {
298
+ type: 'paragraph',
299
+ html: 'Commencez à optimiser votre chaîne maintenant et donnez à vos vidéos le taux de clics qu\'elles méritent !',
300
+ },
301
+ ],
302
+ ui: {
303
+ dropFeedTitle: 'Déposez votre Miniature',
304
+ dropFeedSub: 'PNG, JPG ou WebP · Images multiples',
305
+ dropAvatarTitle: 'Déposez votre Avatar',
306
+ dropAvatarSub: 'Photo de profil de la chaîne',
307
+ labelTitle: 'Titre de la vidéo',
308
+ labelChannel: 'Nom de la chaîne',
309
+ defaultTitle: 'Votre Titre de Vidéo Ici',
310
+ defaultChannel: 'Nom de la Chaîne',
311
+ btnDesktop: 'Ordinateur',
312
+ btnMobile: 'Mobile',
313
+ btnClear: 'Effacer',
314
+ labelLight: 'Clair',
315
+ labelDark: 'Sombre',
316
+ views0: '1,2 M de vues · il y a 1 heure',
317
+ views1: 'Il y a 45 minutes',
318
+ views2: '250 000 vues · il y a 1 jour',
319
+ views3: '3,1 M de vues · il y a 1 semaine',
320
+ },
321
+ };
@@ -0,0 +1,34 @@
1
+ import type { SocialToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
+ import YoutubeThumbnailPreviewerComponent from './component.astro';
3
+ import YoutubeThumbnailPreviewerSEO from './seo.astro';
4
+ import YoutubeThumbnailPreviewerBibliography from './bibliography.astro';
5
+
6
+ import type { YoutubeThumbnailPreviewerUI } from './ui';
7
+
8
+ export type YoutubeThumbnailPreviewerLocaleContent = ToolLocaleContent<YoutubeThumbnailPreviewerUI>;
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 youtubeThumbnailPreviewer: SocialToolEntry<YoutubeThumbnailPreviewerUI> = {
15
+ id: 'youtube-thumbnail-previewer',
16
+ icons: {
17
+ bg: 'mdi:youtube',
18
+ fg: 'mdi:image-search-outline',
19
+ },
20
+ i18n: {
21
+ es: async () => es,
22
+ en: async () => en,
23
+ fr: async () => fr,
24
+ },
25
+ };
26
+
27
+ export { YoutubeThumbnailPreviewerComponent, YoutubeThumbnailPreviewerSEO, YoutubeThumbnailPreviewerBibliography };
28
+
29
+ export const YOUTUBE_THUMBNAIL_PREVIEWER_TOOL: ToolDefinition = {
30
+ entry: youtubeThumbnailPreviewer,
31
+ Component: YoutubeThumbnailPreviewerComponent,
32
+ SEOComponent: YoutubeThumbnailPreviewerSEO,
33
+ BibliographyComponent: YoutubeThumbnailPreviewerBibliography,
34
+ };
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { youtubeThumbnailPreviewer } 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 youtubeThumbnailPreviewer.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+ <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
@@ -0,0 +1,19 @@
1
+ export interface YoutubeThumbnailPreviewerUI extends Record<string, string> {
2
+ dropFeedTitle: string;
3
+ dropFeedSub: string;
4
+ dropAvatarTitle: string;
5
+ dropAvatarSub: string;
6
+ labelTitle: string;
7
+ labelChannel: string;
8
+ defaultTitle: string;
9
+ defaultChannel: string;
10
+ btnDesktop: string;
11
+ btnMobile: string;
12
+ btnClear: string;
13
+ labelLight: string;
14
+ labelDark: string;
15
+ views0: string;
16
+ views1: string;
17
+ views2: string;
18
+ views3: string;
19
+ }
package/src/tools.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { ToolDefinition } from './types';
2
+ import { SAFE_ZONES_TOOL } from './tool/safeZones/index';
3
+ import { YOUTUBE_THUMBNAIL_TOOL } from './tool/youtubeThumbnail/index';
4
+ import { SOCIAL_VALUE_CALCULATOR_TOOL } from './tool/socialValueCalculator/index';
5
+ import { REDDIT_FORMATTER_TOOL } from './tool/redditFormatter/index';
6
+ import { SOCIAL_IMAGE_RESIZER_TOOL } from './tool/socialImageResizer/index';
7
+ import { TINDER_PHOTO_OPTIMIZER_TOOL } from './tool/tinderPhotoOptimizer/index';
8
+ import { YOUTUBE_THUMBNAIL_PREVIEWER_TOOL } from './tool/youtubeThumbnailPreviewer/index';
9
+
10
+ export const ALL_TOOLS: ToolDefinition[] = [SAFE_ZONES_TOOL, YOUTUBE_THUMBNAIL_TOOL, SOCIAL_VALUE_CALCULATOR_TOOL, REDDIT_FORMATTER_TOOL, SOCIAL_IMAGE_RESIZER_TOOL, TINDER_PHOTO_OPTIMIZER_TOOL, YOUTUBE_THUMBNAIL_PREVIEWER_TOOL];
package/src/types.ts ADDED
@@ -0,0 +1,72 @@
1
+ import type { SEOSection } from '@jjlmoya/utils-shared';
2
+ import type { WithContext, Thing } from 'schema-dts';
3
+
4
+ export type { SEOSection };
5
+
6
+ export type KnownLocale =
7
+ | 'ar' | 'da' | 'de' | 'en' | 'es' | 'fi'
8
+ | 'fr' | 'it' | 'ja' | 'ko' | 'nb' | 'nl'
9
+ | 'pl' | 'pt' | 'ru' | 'sv' | 'tr' | 'zh';
10
+
11
+ export interface FAQItem {
12
+ question: string;
13
+ answer: string;
14
+ }
15
+
16
+ export interface BibliographyEntry {
17
+ name: string;
18
+ url: string;
19
+ }
20
+
21
+ export interface HowToStep {
22
+ name: string;
23
+ text: string;
24
+ }
25
+
26
+ export interface ToolLocaleContent<TUI extends Record<string, string> = Record<string, string>> {
27
+ slug: string;
28
+ title: string;
29
+ description: string;
30
+ ui: TUI;
31
+ seo: SEOSection[];
32
+ faqTitle?: string;
33
+ faq: FAQItem[];
34
+ bibliographyTitle?: string;
35
+ bibliography: BibliographyEntry[];
36
+ howTo: HowToStep[];
37
+ schemas: WithContext<Thing>[];
38
+ }
39
+
40
+ export interface CategoryLocaleContent {
41
+ slug: string;
42
+ title: string;
43
+ description: string;
44
+ seo: SEOSection[];
45
+ }
46
+
47
+ export type LocaleLoader<T> = () => Promise<T>;
48
+
49
+ export type LocaleMap<T> = Partial<Record<KnownLocale, LocaleLoader<T>>>;
50
+
51
+ export interface SocialToolEntry<TUI extends Record<string, string> = Record<string, string>> {
52
+ id: string;
53
+ icons: {
54
+ bg: string;
55
+ fg: string;
56
+ };
57
+ i18n: LocaleMap<ToolLocaleContent<TUI>>;
58
+ }
59
+
60
+ export interface SocialCategoryEntry {
61
+ icon: string;
62
+ tools: SocialToolEntry[];
63
+ i18n: LocaleMap<CategoryLocaleContent>;
64
+ }
65
+
66
+ export interface ToolDefinition {
67
+ entry: SocialToolEntry;
68
+ Component: unknown;
69
+ SEOComponent: unknown;
70
+ BibliographyComponent: unknown;
71
+ }
72
+