@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,310 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SocialValueCalculatorUI } from '../ui';
4
+
5
+ const slug = 'calculateur-valeur-compte-reseaux-sociaux';
6
+ const title = 'Calculateur de Valeur de Compte TikTok & Instagram | Tarifs';
7
+ const description =
8
+ "Découvrez combien facturer pour vos publications sponsorisées. Notre calculateur analyse les abonnés, l'engagement et le créneau pour vous donner une valeur de marché juste.";
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Le calculateur de valeur de compte est-il gratuit ?',
13
+ answer:
14
+ "Oui, notre outil est 100% gratuit et ne nécessite ni inscription ni connexion à vos réseaux sociaux. Vous n'avez qu'à saisir vos métriques publiques.",
15
+ },
16
+ {
17
+ question: "Pourquoi la valeur TikTok est-elle différente de celle d'Instagram ?",
18
+ answer:
19
+ "TikTok repose énormément sur la portée algorithmique et les vues, tandis qu'Instagram accorde encore une grande importance à la taille de la communauté et à la fidélité des abonnés.",
20
+ },
21
+ {
22
+ question: "Quel est un bon taux d'engagement pour facturer plus ?",
23
+ answer:
24
+ "En général, un engagement supérieur à 3% est considéré comme sain. Les comptes avec plus de 10% d'engagement sont considérés comme des 'profils premium' et peuvent facturer une majoration significative.",
25
+ },
26
+ {
27
+ question: 'Le créneau affecte-t-il vraiment autant le prix ?',
28
+ answer:
29
+ "Absolument. Un abonné intéressé par la finance ou les logiciels de gestion a une valeur de conversion bien plus élevée pour une marque qu'un abonné cherchant du divertissement rapide ou des mèmes.",
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Choisissez votre plateforme',
36
+ text: "Sélectionnez si vous souhaitez calculer la valeur d'un compte TikTok ou Instagram.",
37
+ },
38
+ {
39
+ name: 'Saisissez vos métriques',
40
+ text: "Entrez votre nombre d'abonnés et la moyenne de vues et de likes de vos 10 derniers posts.",
41
+ },
42
+ {
43
+ name: 'Sélectionnez votre créneau',
44
+ text: 'Choisissez la catégorie qui décrit le mieux votre contenu pour ajuster la valeur selon la demande du marché.',
45
+ },
46
+ {
47
+ name: 'Obtenez votre budget',
48
+ text: 'Recevez une fourchette estimée de ce que vous devriez facturer pour une collaboration professionnelle.',
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<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'fr',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Questions Fréquentes',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Sources et Études de Marché',
93
+ bibliography: [
94
+ {
95
+ name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
+ url: 'https://influencermarketinghub.com/influencer-rates/',
97
+ },
98
+ {
99
+ name: "HypeAuditor: Rapport d'engagement TikTok & Instagram",
100
+ url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
101
+ },
102
+ {
103
+ name: 'Social Blade: Statistiques des réseaux sociaux',
104
+ url: 'https://socialblade.com/',
105
+ },
106
+ ],
107
+ howTo: howToData,
108
+ schemas: [faqSchema, howToSchema, appSchema],
109
+ seo: [
110
+ {
111
+ type: 'tip',
112
+ title: 'Dans ce guide vous apprendrez',
113
+ html: "<ul><li>Votre <strong>valeur réelle de marché</strong> basée sur les données 2026.</li><li>À différencier l'impact de <strong>TikTok et Instagram</strong>.</li><li>Comment le <strong>créneau</strong> affecte drastiquement votre CPM.</li><li>Un modèle professionnel pour <strong>négocier avec les marques</strong>.</li></ul>",
114
+ },
115
+ {
116
+ type: 'title',
117
+ text: 'Calculateur de Valeur de Compte : Combien facturer une promotion sur TikTok ou Instagram ?',
118
+ level: 2,
119
+ },
120
+ {
121
+ type: 'paragraph',
122
+ html: 'Si vous êtes créateur de contenu, influenceur ou simplement une communauté active sur les réseaux sociaux, vous vous êtes probablement demandé à un moment : <strong>combien vaut vraiment mon compte ?</strong> ou <strong>combien devrais-je demander pour une collaboration avec une marque ?</strong>.',
123
+ },
124
+ {
125
+ type: 'title',
126
+ text: "L'essor de l'économie des créateurs",
127
+ level: 3,
128
+ },
129
+ {
130
+ type: 'paragraph',
131
+ html: "Le marketing d'influence a mûri et ne se résume plus uniquement au nombre d'abonnés. Les marques recherchent des résultats et une connexion profonde. Notre outil offre un point de départ solide basé sur des données de marché réelles.",
132
+ },
133
+ {
134
+ type: 'grid',
135
+ columns: [
136
+ {
137
+ type: 'card',
138
+ title: '+45%',
139
+ html: "<p>Croissance annuelle de l'investissement en Influencer Marketing</p>",
140
+ },
141
+ {
142
+ type: 'card',
143
+ title: '3,2%',
144
+ html: "<p>Taux d'engagement moyen considéré comme sain</p>",
145
+ },
146
+ {
147
+ type: 'card',
148
+ title: '15 €–50 €',
149
+ html: '<p>CPM moyen dans les créneaux de haute valeur (stable)</p>',
150
+ },
151
+ ],
152
+ },
153
+ {
154
+ type: 'title',
155
+ text: 'Facteurs qui déterminent la valeur de votre compte',
156
+ level: 2,
157
+ },
158
+ {
159
+ type: 'paragraph',
160
+ html: "Contrairement à ce que l'on croyait il y a quelques années, le nombre d'abonnés n'est que la partie émergée de l'iceberg. Voici les composantes fondamentales :",
161
+ },
162
+ {
163
+ type: 'title',
164
+ text: "1. Le Taux d'Engagement",
165
+ level: 3,
166
+ },
167
+ {
168
+ type: 'paragraph',
169
+ html: "C'est la métrique reine. Elle mesure quel pourcentage de votre communauté interagit activement avec votre contenu. Un petit compte avec une forte interaction est bien plus précieux qu'un grand compte \"fantôme\".",
170
+ },
171
+ {
172
+ type: 'tip',
173
+ title: "Astuce pour votre engagement",
174
+ html: "<p>Essayez de répondre aux commentaires dans les premières heures après la publication pour envoyer des signaux positifs à l'algorithme.</p>",
175
+ },
176
+ {
177
+ type: 'title',
178
+ text: '2. La Portée Moyenne',
179
+ level: 3,
180
+ },
181
+ {
182
+ type: 'paragraph',
183
+ html: "Sur TikTok, la portée est volatile en raison de son algorithme de recommandation. Sur Instagram, les Reels ont pris de l'importance par rapport aux photos statiques pour capter de nouvelles audiences.",
184
+ },
185
+ {
186
+ type: 'title',
187
+ text: '3. Le Créneau ou Catégorie',
188
+ level: 3,
189
+ },
190
+ {
191
+ type: 'paragraph',
192
+ html: "Toutes les audiences ne se valent pas. Un créateur en technologie ou finance peut facturer des tarifs bien plus élevés qu'un créateur de divertissement généraliste, en raison de la valeur plus élevée du client final.",
193
+ },
194
+ {
195
+ type: 'title',
196
+ text: 'Catégories avec le meilleur retour (CPM)',
197
+ level: 3,
198
+ },
199
+ {
200
+ type: 'list',
201
+ items: [
202
+ '<strong>Finance & Immobilier :</strong> Le créneau le mieux payé par post.',
203
+ "<strong>Technologie & Gadgets :</strong> Forte intention d'achat immédiate.",
204
+ '<strong>Santé & Fitness :</strong> Grand marché pour les équipements et applications.',
205
+ '<strong>Rénovation & Maison :</strong> Coûts de projets élevés et ROI important.',
206
+ ],
207
+ },
208
+ {
209
+ type: 'title',
210
+ text: "TikTok vs Instagram : Où est l'argent ?",
211
+ level: 2,
212
+ },
213
+ {
214
+ type: 'paragraph',
215
+ html: "Bien que les deux utilisent la vidéo verticale, leurs modèles de monétisation diffèrent. Instagram, c'est le branding ; TikTok, c'est la performance pure.",
216
+ },
217
+ {
218
+ type: 'grid',
219
+ columns: [
220
+ {
221
+ type: 'card',
222
+ title: 'Instagram',
223
+ html: "<p>Axé sur le branding, l'esthétique et la fidélité. Idéal pour les campagnes à long terme et la loyauté de marque.</p><ul><li>Valorise la taille de la communauté</li><li>Stories avec vente directe</li><li>Croissance stable</li><li>Audience plus mature</li></ul>",
224
+ },
225
+ {
226
+ type: 'card',
227
+ title: 'TikTok',
228
+ html: "<p>Le terrain de la viralité extrême. L'algorithme prime sur les abonnés. ROI explosif à court terme.</p><ul><li>Valorise la portée massive</li><li>Potentiel viral absolu</li><li>Faibles coûts de production</li><li>Audience très active</li></ul>",
229
+ },
230
+ ],
231
+ },
232
+ {
233
+ type: 'title',
234
+ text: 'Comment utiliser les résultats pour négocier',
235
+ level: 2,
236
+ },
237
+ {
238
+ type: 'paragraph',
239
+ html: "Obtenez la fourchette de prix de notre outil et utilisez-la comme guide. Présentez vos métriques avec confiance grâce à ce modèle :",
240
+ },
241
+ {
242
+ type: 'tip',
243
+ title: 'Modèle de négociation',
244
+ html: "<p>Bonjour [Nom de la Marque], merci de m'avoir contacté. En me basant sur mes métriques actuelles de portée (moyenne de [X] vues) et mon taux d'engagement de [X]%, mon tarif pour une intégration dans un [Reel/TikTok] est de [Prix €]. Cela inclut : scénarisation et production vidéo, 1 lien en bio 24h, 2 Stories d'amplification, droits d'utilisation 30 jours.</p>",
245
+ },
246
+ {
247
+ type: 'title',
248
+ text: 'Stratégies pour augmenter votre tarif',
249
+ level: 2,
250
+ },
251
+ {
252
+ type: 'list',
253
+ items: [
254
+ "<strong>Favorisez l'interaction :</strong> Répondez à chaque commentaire.",
255
+ "<strong>Améliorez la qualité :</strong> L'audio représente 50% d'une bonne vidéo.",
256
+ "<strong>Spécialisez-vous :</strong> Être 'l'expert' vous permet de demander plus.",
257
+ "<strong>Créez un Media Kit :</strong> Documentez vos succès avec des données.",
258
+ ],
259
+ },
260
+ {
261
+ type: 'title',
262
+ text: 'La valeur estimée est-elle fiable ?',
263
+ level: 3,
264
+ },
265
+ {
266
+ type: 'paragraph',
267
+ html: "Notre calculateur utilise des données agrégées d'agences internationales. Cependant, des facteurs comme la saisonnalité (Noël paie plus) peuvent faire varier le prix final.",
268
+ },
269
+ {
270
+ type: 'tip',
271
+ title: 'Note pour les Créateurs',
272
+ html: '<p>Cet outil est une estimation. Ajustez toujours le prix en fonction de la complexité du contenu demandé par la marque.</p>',
273
+ },
274
+ {
275
+ type: 'paragraph',
276
+ html: "En conclusion, connaître sa valeur est la première étape pour professionnaliser sa carrière de créateur. Effectuez des vérifications périodiques avec ce calculateur au fil de la croissance de votre compte pour maintenir vos tarifs toujours à jour.",
277
+ },
278
+ ],
279
+ ui: {
280
+ sectionTag: "Paramètres d'Audit",
281
+ labelFollowers: 'Communauté (Abonnés)',
282
+ labelAvgViewsTiktok: 'Impact (Vues par Vidéo)',
283
+ labelAvgViewsIg: 'Portée (Reach du Profil)',
284
+ tooltipViews: "Additionnez les vues de vos 10 dernières vidéos et divisez par 10 pour obtenir la moyenne réelle.",
285
+ labelEngagement: 'Fidélité (Likes + Comm)',
286
+ tooltipEngagement: 'Additionnez les likes et commentaires totaux de vos 10 derniers contenus et divisez par 10.',
287
+ labelNiche: 'Vertical de Marché',
288
+ nicheEntertainment: 'Divertissement',
289
+ nicheFinance: 'Finance & Immobilier',
290
+ nicheTech: 'Technologie & SaaS',
291
+ nicheFitness: 'Lifestyle & Santé',
292
+ nicheFashion: 'Mode & Esthétique',
293
+ nicheTravel: 'Tourisme & Voyages',
294
+ nicheFood: 'Gastronomie',
295
+ nicheGaming: 'Gaming & eSports',
296
+ nicheHome: 'Rénovation & Maison',
297
+ btnCalculate: 'Générer le Rapport de Valeur',
298
+ emptyTitle: 'Analyse de Viabilité Commerciale',
299
+ emptyDesc: 'Entrez les métriques du profil pour projeter la valeur de marché actuelle.',
300
+ roiLabel: 'Évaluation du Tarif Suggéré',
301
+ rangeLabel: 'Plage suggérée :',
302
+ audienceQuality: "Qualité d'Audience",
303
+ metricER: "Taux d'Engagement",
304
+ investmentEfficiency: "Efficacité d'Investissement",
305
+ metricCPM: 'CPM Projeté',
306
+ insightText: 'Cette valorisation est basée sur le CPM moyen du marché francophone (2026).',
307
+ currencySymbol: '€',
308
+ numberLocale: 'fr-FR',
309
+ },
310
+ };
@@ -0,0 +1,34 @@
1
+ import type { SocialToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
+
3
+ import SocialValueCalculatorComponent from './component.astro';
4
+ import SocialValueCalculatorSEO from './seo.astro';
5
+ import SocialValueCalculatorBibliography from './bibliography.astro';
6
+
7
+ import type { SocialValueCalculatorUI } from './ui';
8
+ export type SocialValueCalculatorLocaleContent = ToolLocaleContent<SocialValueCalculatorUI>;
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 socialValueCalculator: SocialToolEntry<SocialValueCalculatorUI> = {
15
+ id: 'social-value-calculator',
16
+ icons: {
17
+ bg: 'mdi:currency-usd',
18
+ fg: 'mdi:instagram',
19
+ },
20
+ i18n: {
21
+ es: async () => es,
22
+ en: async () => en,
23
+ fr: async () => fr,
24
+ },
25
+ };
26
+
27
+ export { SocialValueCalculatorComponent, SocialValueCalculatorSEO, SocialValueCalculatorBibliography };
28
+
29
+ export const SOCIAL_VALUE_CALCULATOR_TOOL: ToolDefinition = {
30
+ entry: socialValueCalculator,
31
+ Component: SocialValueCalculatorComponent,
32
+ SEOComponent: SocialValueCalculatorSEO,
33
+ BibliographyComponent: SocialValueCalculatorBibliography,
34
+ };
@@ -0,0 +1,60 @@
1
+ export interface CalcInputs {
2
+ followers: number;
3
+ avgViews: number;
4
+ avgEngagement: number;
5
+ niche: string;
6
+ platform: 'tiktok' | 'instagram';
7
+ }
8
+
9
+ export interface CalcResult {
10
+ tariff: number;
11
+ lowRange: number;
12
+ highRange: number;
13
+ er: number;
14
+ projectedCPM: number;
15
+ }
16
+
17
+ const NICHE_MULTIPLIERS: Record<string, number> = {
18
+ entertainment: 1.0,
19
+ finance: 2.3,
20
+ tech: 1.9,
21
+ fitness: 1.5,
22
+ fashion: 1.3,
23
+ travel: 1.4,
24
+ food: 1.2,
25
+ gaming: 1.25,
26
+ home: 2.1,
27
+ };
28
+
29
+ function getQualityScore(er: number): number {
30
+ if (er < 2) return 0.85;
31
+ if (er < 5) return 1.1;
32
+ if (er < 10) return 1.4;
33
+ return 1.8;
34
+ }
35
+
36
+ export function calculateValue(inputs: CalcInputs): CalcResult | null {
37
+ const { followers, avgViews, avgEngagement, niche, platform } = inputs;
38
+ if (followers === 0 && avgViews === 0) return null;
39
+
40
+ const er = followers > 0 ? (avgEngagement / followers) * 100 : 0;
41
+
42
+ let baseRate = 0;
43
+ if (platform === 'tiktok') {
44
+ baseRate = avgViews * 0.015;
45
+ } else {
46
+ baseRate = followers * 0.006 + avgViews * 0.02;
47
+ }
48
+
49
+ const nicheMult = NICHE_MULTIPLIERS[niche] ?? 1.0;
50
+ const qualityScore = getQualityScore(er);
51
+ const tariff = baseRate * nicheMult * qualityScore;
52
+
53
+ return {
54
+ tariff,
55
+ lowRange: tariff * 0.8,
56
+ highRange: tariff * 1.3,
57
+ er,
58
+ projectedCPM: avgViews > 0 ? (tariff / avgViews) * 1000 : 0,
59
+ };
60
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { socialValueCalculator } 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 socialValueCalculator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+ <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
@@ -0,0 +1,31 @@
1
+ export interface SocialValueCalculatorUI extends Record<string, string> {
2
+ sectionTag: string;
3
+ labelFollowers: string;
4
+ labelAvgViewsTiktok: string;
5
+ labelAvgViewsIg: string;
6
+ tooltipViews: string;
7
+ labelEngagement: string;
8
+ tooltipEngagement: string;
9
+ labelNiche: string;
10
+ nicheEntertainment: string;
11
+ nicheFinance: string;
12
+ nicheTech: string;
13
+ nicheFitness: string;
14
+ nicheFashion: string;
15
+ nicheTravel: string;
16
+ nicheFood: string;
17
+ nicheGaming: string;
18
+ nicheHome: string;
19
+ btnCalculate: string;
20
+ emptyTitle: string;
21
+ emptyDesc: string;
22
+ roiLabel: string;
23
+ rangeLabel: string;
24
+ audienceQuality: string;
25
+ metricER: string;
26
+ investmentEfficiency: string;
27
+ metricCPM: string;
28
+ insightText: string;
29
+ currencySymbol: string;
30
+ numberLocale: string;
31
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { tinderPhotoOptimizer } 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 tinderPhotoOptimizer.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SharedBibliography links={content.bibliography} />}