@jjlmoya/utils-alcohol 1.13.0 → 1.14.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/package.json CHANGED
@@ -1,60 +1,60 @@
1
1
  {
2
- "name": "@jjlmoya/utils-alcohol",
3
- "version": "1.13.0",
4
- "type": "module",
5
- "main": "./src/index.ts",
6
- "types": "./src/index.ts",
7
- "exports": {
8
- ".": "./src/index.ts",
9
- "./data": "./src/data.ts"
10
- },
11
- "files": [
12
- "src"
13
- ],
14
- "publishConfig": {
15
- "access": "public"
16
- },
17
- "scripts": {
18
- "dev": "astro dev",
19
- "start": "astro dev",
20
- "build": "astro build",
21
- "preview": "astro preview",
22
- "astro": "astro",
23
- "lint": "eslint src/ --max-warnings 0 && stylelint \"src/**/*.{css,astro}\"",
24
- "check": "astro check",
25
- "type-check": "astro check",
26
- "test": "vitest run",
27
- "preversion": "npm run lint && npm run test",
28
- "postversion": "git push && git push --tags",
29
- "patch": "npm version patch",
30
- "minor": "npm version minor",
31
- "major": "npm version major"
32
- },
33
- "lint-staged": {
34
- "*.{ts,tsx,astro}": [
35
- "eslint --fix"
36
- ]
37
- },
38
- "dependencies": {
39
- "@iconify-json/mdi": "^1.2.3",
40
- "@jjlmoya/utils-shared": "^1.1.0",
41
- "astro": "^6.1.2",
42
- "astro-icon": "^1.1.0"
43
- },
44
- "devDependencies": {
45
- "@astrojs/check": "^0.9.8",
46
- "eslint": "^9.39.4",
47
- "eslint-plugin-astro": "^1.6.0",
48
- "eslint-plugin-no-comments": "^1.1.10",
49
- "husky": "^9.1.7",
50
- "lint-staged": "^16.4.0",
51
- "postcss-html": "^1.8.1",
52
- "schema-dts": "^1.1.2",
53
- "stylelint": "^17.6.0",
54
- "stylelint-config-standard": "^40.0.0",
55
- "stylelint-declaration-strict-value": "^1.11.1",
56
- "typescript": "^5.4.0",
57
- "typescript-eslint": "^8.58.0",
58
- "vitest": "^4.1.2"
59
- }
2
+ "name": "@jjlmoya/utils-alcohol",
3
+ "version": "1.14.0",
4
+ "type": "module",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
+ "exports": {
8
+ ".": "./src/index.ts",
9
+ "./data": "./src/data.ts"
10
+ },
11
+ "files": [
12
+ "src"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "dev": "astro dev",
19
+ "start": "astro dev",
20
+ "build": "astro build",
21
+ "preview": "astro preview",
22
+ "astro": "astro",
23
+ "lint": "eslint src/ --max-warnings 0 && stylelint \"src/**/*.{css,astro}\"",
24
+ "check": "astro check",
25
+ "type-check": "astro check",
26
+ "test": "vitest run",
27
+ "preversion": "npm run lint && npm run test",
28
+ "postversion": "git push && git push --tags",
29
+ "patch": "npm version patch",
30
+ "minor": "npm version minor",
31
+ "major": "npm version major"
32
+ },
33
+ "lint-staged": {
34
+ "*.{ts,tsx,astro}": [
35
+ "eslint --fix"
36
+ ]
37
+ },
38
+ "dependencies": {
39
+ "@iconify-json/mdi": "^1.2.3",
40
+ "@jjlmoya/utils-shared": "1.2.0",
41
+ "astro": "^6.1.2",
42
+ "astro-icon": "^1.1.0"
43
+ },
44
+ "devDependencies": {
45
+ "@astrojs/check": "^0.9.8",
46
+ "eslint": "^9.39.4",
47
+ "eslint-plugin-astro": "^1.6.0",
48
+ "eslint-plugin-no-comments": "^1.1.10",
49
+ "husky": "^9.1.7",
50
+ "lint-staged": "^16.4.0",
51
+ "postcss-html": "^1.8.1",
52
+ "schema-dts": "^1.1.2",
53
+ "stylelint": "^17.6.0",
54
+ "stylelint-config-standard": "^40.0.0",
55
+ "stylelint-declaration-strict-value": "^1.11.1",
56
+ "typescript": "^5.4.0",
57
+ "typescript-eslint": "^8.58.0",
58
+ "vitest": "^4.1.2"
59
+ }
60
60
  }
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+ import type { ToolLocaleContent } from '../types';
4
+
5
+ describe('Schemas Fulfillment Validation', () => {
6
+ ALL_TOOLS.forEach((tool) => {
7
+ describe(`Tool: ${tool.entry.id}`, () => {
8
+ Object.keys(tool.entry.i18n).forEach((locale) => {
9
+ it(`Locale: ${locale} should have faqSchema, appSchema and howToSchema`, async () => {
10
+ const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
11
+ if (!loader) return;
12
+ const content = (await loader()) as ToolLocaleContent;
13
+
14
+ const schemaTypes = content.schemas.map((s: any) => s['@type']);
15
+
16
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing FAQPage schema`).toContain('FAQPage');
17
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing SoftwareApplication schema`).toContain('SoftwareApplication');
18
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing HowTo schema`).toContain('HowTo');
19
+ });
20
+ });
21
+ });
22
+ });
23
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, it } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ function getFiles(dir: string, ext: string[]): string[] {
6
+ const results: string[] = [];
7
+ if (!fs.existsSync(dir)) return results;
8
+ const list = fs.readdirSync(dir);
9
+ for (const file of list) {
10
+ const fullPath = path.join(dir, file);
11
+ const stat = fs.statSync(fullPath);
12
+ if (stat && stat.isDirectory()) {
13
+ results.push(...getFiles(fullPath, ext));
14
+ } else if (ext.some((e) => file.endsWith(e))) {
15
+ results.push(fullPath);
16
+ }
17
+ }
18
+ return results;
19
+ }
20
+
21
+ const SRC_DIR = path.join(process.cwd(), 'src');
22
+
23
+ describe('Project Titles - Separator Validation', () => {
24
+ const files = [
25
+ ...getFiles(path.join(SRC_DIR, 'tool'), ['.ts']),
26
+ ...getFiles(path.join(SRC_DIR, 'category'), ['.ts']),
27
+ ].filter(f => f.includes('i18n'));
28
+
29
+ it.each(files)('Verify that titles in %s do not contain | or -', (filePath) => {
30
+ const content = fs.readFileSync(filePath, 'utf-8');
31
+ const relativePath = path.relative(process.cwd(), filePath);
32
+
33
+ const titlePatterns = [
34
+ /const\s+title\s*=\s*['"]([^'"]+)['"]/g,
35
+ /title\s*:\s*['"]([^'"]+)['"]/g,
36
+ ];
37
+
38
+ const findings: string[] = [];
39
+
40
+ for (const pattern of titlePatterns) {
41
+ let match;
42
+ while ((match = pattern.exec(content)) !== null) {
43
+ const title = match[1];
44
+ if (title.includes('|') || title.includes('-')) {
45
+ findings.push(title);
46
+ }
47
+ }
48
+ }
49
+
50
+ if (findings.length > 0) {
51
+ const list = findings.map((f) => ` - "${f}"`).join('\n');
52
+ throw new Error(`Forbidden separators (| or -) found in titles in ${relativePath}:\n${list}`);
53
+ }
54
+ });
55
+ });
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { AlcoholClearanceUI, AlcoholClearanceLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'alcohol-clearance-calculator';
@@ -158,6 +158,27 @@ const seo: AlcoholClearanceLocaleContent['seo'] = [
158
158
  ];
159
159
 
160
160
  const schemas: AlcoholClearanceLocaleContent['schemas'] = [
161
+ {
162
+ '@context': 'https://schema.org',
163
+ '@type': 'FAQPage',
164
+ mainEntity: faq.map((item) => ({
165
+ '@type': 'Question',
166
+ name: item.question,
167
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
168
+ })),
169
+ } as WithContext<FAQPage>,
170
+ {
171
+ '@context': 'https://schema.org',
172
+ '@type': 'HowTo',
173
+ name: title,
174
+ description: description,
175
+ step: howTo.map((step, i) => ({
176
+ '@type': 'HowToStep',
177
+ position: i + 1,
178
+ name: step.name,
179
+ text: step.text,
180
+ })),
181
+ } as WithContext<HowTo>,
161
182
  {
162
183
  '@context': 'https://schema.org',
163
184
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { AlcoholClearanceUI, AlcoholClearanceLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculadora-alcohol-resaca';
@@ -167,6 +167,27 @@ const seo: AlcoholClearanceLocaleContent['seo'] = [
167
167
  ];
168
168
 
169
169
  const schemas: AlcoholClearanceLocaleContent['schemas'] = [
170
+ {
171
+ '@context': 'https://schema.org',
172
+ '@type': 'FAQPage',
173
+ mainEntity: faq.map((item) => ({
174
+ '@type': 'Question',
175
+ name: item.question,
176
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
177
+ })),
178
+ } as WithContext<FAQPage>,
179
+ {
180
+ '@context': 'https://schema.org',
181
+ '@type': 'HowTo',
182
+ name: title,
183
+ description: description,
184
+ step: howTo.map((step, i) => ({
185
+ '@type': 'HowToStep',
186
+ position: i + 1,
187
+ name: step.name,
188
+ text: step.text,
189
+ })),
190
+ } as WithContext<HowTo>,
170
191
  {
171
192
  '@context': 'https://schema.org',
172
193
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { AlcoholClearanceUI, AlcoholClearanceLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculateur-elimination-alcohol';
@@ -149,6 +149,27 @@ const seo: AlcoholClearanceLocaleContent['seo'] = [
149
149
  ];
150
150
 
151
151
  const schemas: AlcoholClearanceLocaleContent['schemas'] = [
152
+ {
153
+ '@context': 'https://schema.org',
154
+ '@type': 'FAQPage',
155
+ mainEntity: faq.map((item) => ({
156
+ '@type': 'Question',
157
+ name: item.question,
158
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
159
+ })),
160
+ } as WithContext<FAQPage>,
161
+ {
162
+ '@context': 'https://schema.org',
163
+ '@type': 'HowTo',
164
+ name: title,
165
+ description: description,
166
+ step: howTo.map((step, i) => ({
167
+ '@type': 'HowToStep',
168
+ position: i + 1,
169
+ name: step.name,
170
+ text: step.text,
171
+ })),
172
+ } as WithContext<HowTo>,
152
173
  {
153
174
  '@context': 'https://schema.org',
154
175
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { BeerCoolerUI, BeerCoolerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'beer-cooler';
@@ -135,7 +135,7 @@ const seo: BeerCoolerLocaleContent['seo'] = [
135
135
  },
136
136
  {
137
137
  type: 'tip',
138
- title: 'Pro Tip: Pre-chill the Glass',
138
+ title: 'Pro Tip: Prechill the Glass',
139
139
  html: 'The glass you serve beer into has a significant thermal mass. A warm glass can raise the temperature of a perfectly cold beer by 2-3°C instantly on contact. Place your serving glass in the freezer for 5 minutes before pouring, or rinse it with cold water. This simple step extends the window where your beer tastes exactly as intended.'
140
140
  },
141
141
  {
@@ -150,11 +150,32 @@ const seo: BeerCoolerLocaleContent['seo'] = [
150
150
  ];
151
151
 
152
152
  const schemas: BeerCoolerLocaleContent['schemas'] = [
153
+ {
154
+ '@context': 'https://schema.org',
155
+ '@type': 'FAQPage',
156
+ mainEntity: faq.map((item) => ({
157
+ '@type': 'Question',
158
+ name: item.question,
159
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
160
+ })),
161
+ } as WithContext<FAQPage>,
162
+ {
163
+ '@context': 'https://schema.org',
164
+ '@type': 'HowTo',
165
+ name: title,
166
+ description: description,
167
+ step: howTo.map((step, i) => ({
168
+ '@type': 'HowToStep',
169
+ position: i + 1,
170
+ name: step.name,
171
+ text: step.text,
172
+ })),
173
+ } as WithContext<HowTo>,
153
174
  {
154
175
  '@context': 'https://schema.org',
155
176
  '@type': 'SoftwareApplication',
156
- name: "Beer Cooling Calculator – Newton's Law of Cooling",
157
- description: 'Applied thermodynamics tool that uses Newton\'s Law of Cooling to calculate the exact time for your beer to reach the ideal serving temperature in a fridge or freezer.',
177
+ name: title,
178
+ description: description,
158
179
  applicationCategory: 'UtilityApplication',
159
180
  operatingSystem: 'Web',
160
181
  offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { BeerCoolerUI, BeerCoolerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculadora-enfriamiento-cerveza';
@@ -135,7 +135,7 @@ const seo: BeerCoolerLocaleContent['seo'] = [
135
135
  },
136
136
  {
137
137
  type: 'tip',
138
- title: 'Consejo Pro: Pre-enfría el Vaso',
138
+ title: 'Consejo Pro: Preenfría el Vaso',
139
139
  html: 'El vaso en el que sirves la cerveza tiene una masa térmica significativa. Un vaso caliente puede subir la temperatura de una cerveza perfectamente fría en 2-3°C al instante. Mete el vaso de servicio en el congelador 5 minutos antes de servir, o enjuágalo con agua fría. Este simple paso prolonga la ventana en que tu cerveza sabe exactamente como debe.'
140
140
  },
141
141
  {
@@ -163,11 +163,32 @@ const seo: BeerCoolerLocaleContent['seo'] = [
163
163
  ];
164
164
 
165
165
  const schemas: BeerCoolerLocaleContent['schemas'] = [
166
+ {
167
+ '@context': 'https://schema.org',
168
+ '@type': 'FAQPage',
169
+ mainEntity: faq.map((item) => ({
170
+ '@type': 'Question',
171
+ name: item.question,
172
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
173
+ })),
174
+ } as WithContext<FAQPage>,
175
+ {
176
+ '@context': 'https://schema.org',
177
+ '@type': 'HowTo',
178
+ name: title,
179
+ description: description,
180
+ step: howTo.map((step, i) => ({
181
+ '@type': 'HowToStep',
182
+ position: i + 1,
183
+ name: step.name,
184
+ text: step.text,
185
+ })),
186
+ } as WithContext<HowTo>,
166
187
  {
167
188
  '@context': 'https://schema.org',
168
189
  '@type': 'SoftwareApplication',
169
- name: 'Calculadora de Enfriamiento de Cerveza – Ley de Newton',
170
- description: 'Herramienta de termodinámica aplicada que calcula con la Ley de Enfriamiento de Newton el tiempo exacto para que tu cerveza alcance la temperatura de servicio ideal en nevera o congelador.',
190
+ name: title,
191
+ description: description,
171
192
  applicationCategory: 'UtilityApplication',
172
193
  operatingSystem: 'Web',
173
194
  offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { BeerCoolerUI, BeerCoolerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'refroidisseur-biere';
@@ -135,7 +135,7 @@ const seo: BeerCoolerLocaleContent['seo'] = [
135
135
  },
136
136
  {
137
137
  type: 'tip',
138
- title: 'Conseil Pro : Pré-refroidir le Verre',
138
+ title: 'Conseil Pro : Prérefroidir le Verre',
139
139
  html: 'Le verre dans lequel vous servez la bière possède une masse thermique significative. Un verre chaud peut augmenter la température d\'une bière parfaitement froide de 2 à 3°C instantanément au contact. Placez votre verre de service au congélateur 5 minutes avant de verser, ou rincez-le à l\'eau froide. Cette simple étape prolonge la fenêtre où votre bière a exactement le goût voulu.'
140
140
  },
141
141
  {
@@ -150,11 +150,32 @@ const seo: BeerCoolerLocaleContent['seo'] = [
150
150
  ];
151
151
 
152
152
  const schemas: BeerCoolerLocaleContent['schemas'] = [
153
+ {
154
+ '@context': 'https://schema.org',
155
+ '@type': 'FAQPage',
156
+ mainEntity: faq.map((item) => ({
157
+ '@type': 'Question',
158
+ name: item.question,
159
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
160
+ })),
161
+ } as WithContext<FAQPage>,
162
+ {
163
+ '@context': 'https://schema.org',
164
+ '@type': 'HowTo',
165
+ name: title,
166
+ description: description,
167
+ step: howTo.map((step, i) => ({
168
+ '@type': 'HowToStep',
169
+ position: i + 1,
170
+ name: step.name,
171
+ text: step.text,
172
+ })),
173
+ } as WithContext<HowTo>,
153
174
  {
154
175
  '@context': 'https://schema.org',
155
176
  '@type': 'SoftwareApplication',
156
- name: 'Calculateur de Refroidissement de Bière – Loi du Refroidissement de Newton',
157
- description: 'Outil de thermodynamique appliquée qui utilise la Loi du Refroidissement de Newton pour calculer le temps exact nécessaire à votre bière pour atteindre la température de service idéale au frigo ou au congélateur.',
177
+ name: title,
178
+ description: description,
158
179
  applicationCategory: 'UtilityApplication',
159
180
  operatingSystem: 'Web',
160
181
  offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CarbonationUI, CarbonationLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'beer-carbonation-calculator';
@@ -153,6 +153,27 @@ const seo: CarbonationLocaleContent['seo'] = [
153
153
  ];
154
154
 
155
155
  const schemas: CarbonationLocaleContent['schemas'] = [
156
+ {
157
+ '@context': 'https://schema.org',
158
+ '@type': 'FAQPage',
159
+ mainEntity: faq.map((item) => ({
160
+ '@type': 'Question',
161
+ name: item.question,
162
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
163
+ })),
164
+ } as WithContext<FAQPage>,
165
+ {
166
+ '@context': 'https://schema.org',
167
+ '@type': 'HowTo',
168
+ name: title,
169
+ description: description,
170
+ step: howTo.map((step, i) => ({
171
+ '@type': 'HowToStep',
172
+ position: i + 1,
173
+ name: step.name,
174
+ text: step.text,
175
+ })),
176
+ } as WithContext<HowTo>,
156
177
  {
157
178
  '@context': 'https://schema.org',
158
179
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CarbonationUI, CarbonationLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculadora-carbonatacion';
@@ -157,6 +157,27 @@ const seo: CarbonationLocaleContent['seo'] = [
157
157
  ];
158
158
 
159
159
  const schemas: CarbonationLocaleContent['schemas'] = [
160
+ {
161
+ '@context': 'https://schema.org',
162
+ '@type': 'FAQPage',
163
+ mainEntity: faq.map((item) => ({
164
+ '@type': 'Question',
165
+ name: item.question,
166
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
167
+ })),
168
+ } as WithContext<FAQPage>,
169
+ {
170
+ '@context': 'https://schema.org',
171
+ '@type': 'HowTo',
172
+ name: title,
173
+ description: description,
174
+ step: howTo.map((step, i) => ({
175
+ '@type': 'HowToStep',
176
+ position: i + 1,
177
+ name: step.name,
178
+ text: step.text,
179
+ })),
180
+ } as WithContext<HowTo>,
160
181
  {
161
182
  '@context': 'https://schema.org',
162
183
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CarbonationUI, CarbonationLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculateur-carbonatation-biere';
@@ -153,6 +153,27 @@ const seo: CarbonationLocaleContent['seo'] = [
153
153
  ];
154
154
 
155
155
  const schemas: CarbonationLocaleContent['schemas'] = [
156
+ {
157
+ '@context': 'https://schema.org',
158
+ '@type': 'FAQPage',
159
+ mainEntity: faq.map((item) => ({
160
+ '@type': 'Question',
161
+ name: item.question,
162
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
163
+ })),
164
+ } as WithContext<FAQPage>,
165
+ {
166
+ '@context': 'https://schema.org',
167
+ '@type': 'HowTo',
168
+ name: title,
169
+ description: description,
170
+ step: howTo.map((step, i) => ({
171
+ '@type': 'HowToStep',
172
+ position: i + 1,
173
+ name: step.name,
174
+ text: step.text,
175
+ })),
176
+ } as WithContext<HowTo>,
156
177
  {
157
178
  '@context': 'https://schema.org',
158
179
  '@type': 'SoftwareApplication',
@@ -1,8 +1,8 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CocktailBalancerUI, CocktailBalancerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'cocktail-balancer';
5
- const title = 'Cocktail Balancer - The Sour Law';
5
+ const title = 'Cocktail Balancer: The Sour Law';
6
6
  const description = 'Calculate the perfect balance between sweet and sour for your cocktails. Master the golden ratio of mixology.';
7
7
 
8
8
  const ui: CocktailBalancerUI = {
@@ -175,6 +175,27 @@ const seo: CocktailBalancerLocaleContent['seo'] = [
175
175
  ];
176
176
 
177
177
  const schemas: CocktailBalancerLocaleContent['schemas'] = [
178
+ {
179
+ '@context': 'https://schema.org',
180
+ '@type': 'FAQPage',
181
+ mainEntity: faq.map((item) => ({
182
+ '@type': 'Question',
183
+ name: item.question,
184
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
185
+ })),
186
+ } as WithContext<FAQPage>,
187
+ {
188
+ '@context': 'https://schema.org',
189
+ '@type': 'HowTo',
190
+ name: title,
191
+ description: description,
192
+ step: howTo.map((step, i) => ({
193
+ '@type': 'HowToStep',
194
+ position: i + 1,
195
+ name: step.name,
196
+ text: step.text,
197
+ })),
198
+ } as WithContext<HowTo>,
178
199
  {
179
200
  '@context': 'https://schema.org',
180
201
  '@type': 'SoftwareApplication',
@@ -1,8 +1,8 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CocktailBalancerUI, CocktailBalancerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'equilibrador-cocteles';
5
- const title = 'Equilibrador de Cócteles - La Ley del Sour';
5
+ const title = 'Equilibrador de Cócteles: La Ley del Sour';
6
6
  const description = 'Calcula el equilibrio perfecto entre dulce y ácido para tus cócteles. Domina la proporción áurea de la mixología.';
7
7
 
8
8
  const ui: CocktailBalancerUI = {
@@ -175,6 +175,27 @@ const seo: CocktailBalancerLocaleContent['seo'] = [
175
175
  ];
176
176
 
177
177
  const schemas: CocktailBalancerLocaleContent['schemas'] = [
178
+ {
179
+ '@context': 'https://schema.org',
180
+ '@type': 'FAQPage',
181
+ mainEntity: faq.map((item) => ({
182
+ '@type': 'Question',
183
+ name: item.question,
184
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
185
+ })),
186
+ } as WithContext<FAQPage>,
187
+ {
188
+ '@context': 'https://schema.org',
189
+ '@type': 'HowTo',
190
+ name: title,
191
+ description: description,
192
+ step: howTo.map((step, i) => ({
193
+ '@type': 'HowToStep',
194
+ position: i + 1,
195
+ name: step.name,
196
+ text: step.text,
197
+ })),
198
+ } as WithContext<HowTo>,
178
199
  {
179
200
  '@context': 'https://schema.org',
180
201
  '@type': 'SoftwareApplication',
@@ -1,8 +1,8 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { CocktailBalancerUI, CocktailBalancerLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'equilibre-cocktail';
5
- const title = 'Équilibreur de Cocktails - La Loi du Sour';
5
+ const title = 'Équilibreur de Cocktails: La Loi du Sour';
6
6
  const description = 'Calculez l\'équilibre parfait entre le sucré et l\'acide pour vos cocktails. Maîtrisez le nombre d\'or de la mixologie.';
7
7
 
8
8
  const ui: CocktailBalancerUI = {
@@ -175,6 +175,27 @@ const seo: CocktailBalancerLocaleContent['seo'] = [
175
175
  ];
176
176
 
177
177
  const schemas: CocktailBalancerLocaleContent['schemas'] = [
178
+ {
179
+ '@context': 'https://schema.org',
180
+ '@type': 'FAQPage',
181
+ mainEntity: faq.map((item) => ({
182
+ '@type': 'Question',
183
+ name: item.question,
184
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
185
+ })),
186
+ } as WithContext<FAQPage>,
187
+ {
188
+ '@context': 'https://schema.org',
189
+ '@type': 'HowTo',
190
+ name: title,
191
+ description: description,
192
+ step: howTo.map((step, i) => ({
193
+ '@type': 'HowToStep',
194
+ position: i + 1,
195
+ name: step.name,
196
+ text: step.text,
197
+ })),
198
+ } as WithContext<HowTo>,
178
199
  {
179
200
  '@context': 'https://schema.org',
180
201
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { PartyKegUI, PartyKegLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'party-stock-calculator';
@@ -140,6 +140,27 @@ const seo: PartyKegLocaleContent['seo'] = [
140
140
  ];
141
141
 
142
142
  const schemas: PartyKegLocaleContent['schemas'] = [
143
+ {
144
+ '@context': 'https://schema.org',
145
+ '@type': 'FAQPage',
146
+ mainEntity: faq.map((item) => ({
147
+ '@type': 'Question',
148
+ name: item.question,
149
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
150
+ })),
151
+ } as WithContext<FAQPage>,
152
+ {
153
+ '@context': 'https://schema.org',
154
+ '@type': 'HowTo',
155
+ name: title,
156
+ description: description,
157
+ step: howTo.map((step, i) => ({
158
+ '@type': 'HowToStep',
159
+ position: i + 1,
160
+ name: step.name,
161
+ text: step.text,
162
+ })),
163
+ } as WithContext<HowTo>,
143
164
  {
144
165
  '@context': 'https://schema.org',
145
166
  '@type': 'SoftwareApplication',
@@ -1,4 +1,4 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { PartyKegUI, PartyKegLocaleContent } from '../index';
3
3
 
4
4
  const slug = 'calculadora-barriles-fiesta';
@@ -144,6 +144,27 @@ const seo: PartyKegLocaleContent['seo'] = [
144
144
  ];
145
145
 
146
146
  const schemas: PartyKegLocaleContent['schemas'] = [
147
+ {
148
+ '@context': 'https://schema.org',
149
+ '@type': 'FAQPage',
150
+ mainEntity: faq.map((item) => ({
151
+ '@type': 'Question',
152
+ name: item.question,
153
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
154
+ })),
155
+ } as WithContext<FAQPage>,
156
+ {
157
+ '@context': 'https://schema.org',
158
+ '@type': 'HowTo',
159
+ name: title,
160
+ description: description,
161
+ step: howTo.map((step, i) => ({
162
+ '@type': 'HowToStep',
163
+ position: i + 1,
164
+ name: step.name,
165
+ text: step.text,
166
+ })),
167
+ } as WithContext<HowTo>,
147
168
  {
148
169
  '@context': 'https://schema.org',
149
170
  '@type': 'SoftwareApplication',
@@ -1,7 +1,7 @@
1
- import type { WithContext, SoftwareApplication } from 'schema-dts';
1
+ import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
2
2
  import type { PartyKegUI, PartyKegLocaleContent } from '../index';
3
3
 
4
- const slug = 'calculateur-fete-fût';
4
+ const slug = 'calculateur-fete-fut';
5
5
  const title = 'Calculateur de Bière pour Fêtes : Quantité par Personne, Mariage ou Anniversaire';
6
6
  const description = 'Outil gratuit pour calculer la quantité de bière et de glace selon les invités, la durée et la température. Idéal pour les mariages, anniversaires et événements en plein air.';
7
7
 
@@ -140,6 +140,27 @@ const seo: PartyKegLocaleContent['seo'] = [
140
140
  ];
141
141
 
142
142
  const schemas: PartyKegLocaleContent['schemas'] = [
143
+ {
144
+ '@context': 'https://schema.org',
145
+ '@type': 'FAQPage',
146
+ mainEntity: faq.map((item) => ({
147
+ '@type': 'Question',
148
+ name: item.question,
149
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
150
+ })),
151
+ } as WithContext<FAQPage>,
152
+ {
153
+ '@context': 'https://schema.org',
154
+ '@type': 'HowTo',
155
+ name: title,
156
+ description: description,
157
+ step: howTo.map((step, i) => ({
158
+ '@type': 'HowToStep',
159
+ position: i + 1,
160
+ name: step.name,
161
+ text: step.text,
162
+ })),
163
+ } as WithContext<HowTo>,
143
164
  {
144
165
  '@context': 'https://schema.org',
145
166
  '@type': 'SoftwareApplication',