@jjlmoya/utils-cooking 1.2.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 (130) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +24 -0
  3. package/src/category/i18n/es.ts +208 -0
  4. package/src/category/i18n/fr.ts +24 -0
  5. package/src/category/index.ts +37 -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 +32 -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/i18n-titles.test.ts +66 -0
  18. package/src/tests/locale_completeness.test.ts +42 -0
  19. package/src/tests/mocks/astro_mock.js +2 -0
  20. package/src/tests/no_h1_in_components.test.ts +48 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/tool_validation.test.ts +17 -0
  23. package/src/tool/american-kitchen-converter/AmericanKitchenEngine.ts +259 -0
  24. package/src/tool/american-kitchen-converter/bibliography.astro +6 -0
  25. package/src/tool/american-kitchen-converter/component.astro +838 -0
  26. package/src/tool/american-kitchen-converter/i18n/en.ts +282 -0
  27. package/src/tool/american-kitchen-converter/i18n/es.ts +281 -0
  28. package/src/tool/american-kitchen-converter/i18n/fr.ts +292 -0
  29. package/src/tool/american-kitchen-converter/index.ts +24 -0
  30. package/src/tool/american-kitchen-converter/seo.astro +8 -0
  31. package/src/tool/banana-ripeness/BananaCare.css +587 -0
  32. package/src/tool/banana-ripeness/BananaEngine.ts +79 -0
  33. package/src/tool/banana-ripeness/bibliography.astro +6 -0
  34. package/src/tool/banana-ripeness/component.astro +285 -0
  35. package/src/tool/banana-ripeness/i18n/en.ts +177 -0
  36. package/src/tool/banana-ripeness/i18n/es.ts +177 -0
  37. package/src/tool/banana-ripeness/i18n/fr.ts +177 -0
  38. package/src/tool/banana-ripeness/index.ts +24 -0
  39. package/src/tool/banana-ripeness/seo.astro +8 -0
  40. package/src/tool/brine/bibliography.astro +6 -0
  41. package/src/tool/brine/component.astro +884 -0
  42. package/src/tool/brine/i18n/en.ts +221 -0
  43. package/src/tool/brine/i18n/es.ts +222 -0
  44. package/src/tool/brine/i18n/fr.ts +221 -0
  45. package/src/tool/brine/index.ts +26 -0
  46. package/src/tool/brine/seo.astro +8 -0
  47. package/src/tool/cookware-guide/CookwareGuide.css +487 -0
  48. package/src/tool/cookware-guide/bibliography.astro +6 -0
  49. package/src/tool/cookware-guide/component.astro +164 -0
  50. package/src/tool/cookware-guide/i18n/en.ts +163 -0
  51. package/src/tool/cookware-guide/i18n/es.ts +163 -0
  52. package/src/tool/cookware-guide/i18n/fr.ts +164 -0
  53. package/src/tool/cookware-guide/index.ts +24 -0
  54. package/src/tool/cookware-guide/init.ts +174 -0
  55. package/src/tool/cookware-guide/seo.astro +8 -0
  56. package/src/tool/egg-timer/EggTimer.css +503 -0
  57. package/src/tool/egg-timer/bibliography.astro +14 -0
  58. package/src/tool/egg-timer/component.astro +281 -0
  59. package/src/tool/egg-timer/i18n/en.ts +230 -0
  60. package/src/tool/egg-timer/i18n/es.ts +222 -0
  61. package/src/tool/egg-timer/i18n/fr.ts +121 -0
  62. package/src/tool/egg-timer/index.ts +27 -0
  63. package/src/tool/egg-timer/seo.astro +39 -0
  64. package/src/tool/ingredient-rescaler/IngredientRescaler.css +308 -0
  65. package/src/tool/ingredient-rescaler/bibliography.astro +6 -0
  66. package/src/tool/ingredient-rescaler/component.astro +107 -0
  67. package/src/tool/ingredient-rescaler/i18n/en.ts +265 -0
  68. package/src/tool/ingredient-rescaler/i18n/es.ts +268 -0
  69. package/src/tool/ingredient-rescaler/i18n/fr.ts +207 -0
  70. package/src/tool/ingredient-rescaler/index.ts +24 -0
  71. package/src/tool/ingredient-rescaler/init.ts +200 -0
  72. package/src/tool/ingredient-rescaler/seo.astro +8 -0
  73. package/src/tool/kitchen-timer/KitchenTimer.css +325 -0
  74. package/src/tool/kitchen-timer/bibliography.astro +6 -0
  75. package/src/tool/kitchen-timer/component.astro +341 -0
  76. package/src/tool/kitchen-timer/i18n/en.ts +154 -0
  77. package/src/tool/kitchen-timer/i18n/es.ts +154 -0
  78. package/src/tool/kitchen-timer/i18n/fr.ts +154 -0
  79. package/src/tool/kitchen-timer/index.ts +26 -0
  80. package/src/tool/kitchen-timer/init.ts +55 -0
  81. package/src/tool/kitchen-timer/lib/AudioHelper.ts +27 -0
  82. package/src/tool/kitchen-timer/lib/DockManager.ts +97 -0
  83. package/src/tool/kitchen-timer/lib/KitchenTimer.ts +264 -0
  84. package/src/tool/kitchen-timer/seo.astro +8 -0
  85. package/src/tool/meringue-peak/MeringueCalculator.css +298 -0
  86. package/src/tool/meringue-peak/bibliography.astro +6 -0
  87. package/src/tool/meringue-peak/component.astro +169 -0
  88. package/src/tool/meringue-peak/i18n/en.ts +257 -0
  89. package/src/tool/meringue-peak/i18n/es.ts +234 -0
  90. package/src/tool/meringue-peak/i18n/fr.ts +234 -0
  91. package/src/tool/meringue-peak/index.ts +24 -0
  92. package/src/tool/meringue-peak/seo.astro +8 -0
  93. package/src/tool/mold-scaler/MoldScaler.css +406 -0
  94. package/src/tool/mold-scaler/bibliography.astro +6 -0
  95. package/src/tool/mold-scaler/component.astro +126 -0
  96. package/src/tool/mold-scaler/i18n/en.ts +268 -0
  97. package/src/tool/mold-scaler/i18n/es.ts +269 -0
  98. package/src/tool/mold-scaler/i18n/fr.ts +276 -0
  99. package/src/tool/mold-scaler/index.ts +26 -0
  100. package/src/tool/mold-scaler/init.ts +264 -0
  101. package/src/tool/mold-scaler/seo.astro +8 -0
  102. package/src/tool/pizza/Pizza.css +569 -0
  103. package/src/tool/pizza/bibliography.astro +6 -0
  104. package/src/tool/pizza/calculator.ts +143 -0
  105. package/src/tool/pizza/component.astro +237 -0
  106. package/src/tool/pizza/i18n/en.ts +288 -0
  107. package/src/tool/pizza/i18n/es.ts +289 -0
  108. package/src/tool/pizza/i18n/fr.ts +288 -0
  109. package/src/tool/pizza/index.ts +27 -0
  110. package/src/tool/pizza/seo.astro +8 -0
  111. package/src/tool/roux-guide/RouxGuide.css +483 -0
  112. package/src/tool/roux-guide/bibliography.astro +6 -0
  113. package/src/tool/roux-guide/component.astro +194 -0
  114. package/src/tool/roux-guide/i18n/en.ts +233 -0
  115. package/src/tool/roux-guide/i18n/es.ts +225 -0
  116. package/src/tool/roux-guide/i18n/fr.ts +225 -0
  117. package/src/tool/roux-guide/index.ts +24 -0
  118. package/src/tool/roux-guide/init.ts +187 -0
  119. package/src/tool/roux-guide/seo.astro +8 -0
  120. package/src/tool/sourdough-calculator/SourdoughCalculator.css +369 -0
  121. package/src/tool/sourdough-calculator/bibliography.astro +6 -0
  122. package/src/tool/sourdough-calculator/component.astro +198 -0
  123. package/src/tool/sourdough-calculator/i18n/en.ts +242 -0
  124. package/src/tool/sourdough-calculator/i18n/es.ts +243 -0
  125. package/src/tool/sourdough-calculator/i18n/fr.ts +248 -0
  126. package/src/tool/sourdough-calculator/index.ts +24 -0
  127. package/src/tool/sourdough-calculator/init.ts +131 -0
  128. package/src/tool/sourdough-calculator/seo.astro +8 -0
  129. package/src/tools.ts +29 -0
  130. package/src/types.ts +73 -0
@@ -0,0 +1,174 @@
1
+ type CookingStyle = 'sear' | 'delicate' | 'stew' | 'fast';
2
+ type MaintenanceLevel = 'lazy' | 'care' | 'ritual';
3
+
4
+ interface State {
5
+ style: CookingStyle | null;
6
+ maint: MaintenanceLevel | null;
7
+ }
8
+
9
+ interface MaterialData {
10
+ name: string;
11
+ tag: string;
12
+ grad: string;
13
+ icon: string;
14
+ pros: string;
15
+ cons: string;
16
+ tip: string;
17
+ }
18
+
19
+ interface MaterialGrads {
20
+ stainless: string;
21
+ nonstick: string;
22
+ castiron: string;
23
+ carbon: string;
24
+ enameled: string;
25
+ }
26
+
27
+ const GRADS: MaterialGrads = {
28
+ stainless: 'linear-gradient(135deg, hsl(217, 33%, 37%), hsl(217, 33%, 17%))',
29
+ nonstick: 'linear-gradient(135deg, hsl(280, 8%, 43%), hsl(217, 33%, 7%))',
30
+ castiron: 'linear-gradient(135deg, hsl(24, 77%, 25%), hsl(217, 33%, 7%))',
31
+ carbon: 'linear-gradient(135deg, hsl(217, 60%, 27%), hsl(217, 33%, 7%))',
32
+ enameled: 'linear-gradient(135deg, hsl(0, 74%, 42%), hsl(0, 74%, 17%))',
33
+ };
34
+
35
+ function createMaterial(ui: Record<string, string>, prefix: string, grad: string, icon: string): MaterialData {
36
+ return {
37
+ name: ui[`${prefix}Name`],
38
+ tag: ui[`${prefix}Tag`],
39
+ grad,
40
+ icon,
41
+ pros: ui[`${prefix}Pro`],
42
+ cons: ui[`${prefix}Con`],
43
+ tip: ui[`${prefix}Tip`],
44
+ };
45
+ }
46
+
47
+ function buildMaterialDB(ui: Record<string, string>): Record<string, MaterialData> {
48
+ return {
49
+ stainless: createMaterial(ui, 'stainless', GRADS.stainless, 'stainless'),
50
+ nonstick: createMaterial(ui, 'nonstick', GRADS.nonstick, 'nonstick'),
51
+ castiron: createMaterial(ui, 'castiron', GRADS.castiron, 'castiron'),
52
+ carbon: createMaterial(ui, 'carbon', GRADS.carbon, 'carbon'),
53
+ enameled: createMaterial(ui, 'enamel', GRADS.enameled, 'enameled'),
54
+ };
55
+ }
56
+
57
+ const LOGIC: Record<CookingStyle, Record<MaintenanceLevel, string>> = {
58
+ sear: { lazy: 'stainless', care: 'stainless', ritual: 'castiron' },
59
+ delicate: { lazy: 'nonstick', care: 'nonstick', ritual: 'carbon' },
60
+ stew: { lazy: 'stainless', care: 'enameled', ritual: 'enameled' },
61
+ fast: { lazy: 'stainless', care: 'stainless', ritual: 'carbon' },
62
+ };
63
+
64
+ interface CookwareElements {
65
+ styleButtons: NodeListOf<Element>;
66
+ maintButtons: NodeListOf<Element>;
67
+ progressBar: HTMLElement;
68
+ cardGrad: HTMLElement;
69
+ resName: HTMLElement;
70
+ resTag: HTMLElement;
71
+ resPros: HTMLElement;
72
+ resCons: HTMLElement;
73
+ resTip: HTMLElement;
74
+ resDetails: HTMLElement;
75
+ iconPlaceholder: HTMLElement | null;
76
+ resultIcons: NodeListOf<Element>;
77
+ }
78
+
79
+ function getRequiredElement(id: string): HTMLElement | null {
80
+ return document.getElementById(id);
81
+ }
82
+
83
+ function setupElements(): CookwareElements | null {
84
+ const progressBar = getRequiredElement('progress-bar');
85
+ const cardGrad = getRequiredElement('card-grad');
86
+ const resName = getRequiredElement('res-name');
87
+ const resTag = getRequiredElement('res-tag');
88
+ const resPros = getRequiredElement('res-pros');
89
+ const resCons = getRequiredElement('res-cons');
90
+ const resTip = getRequiredElement('res-tip');
91
+ const resDetails = getRequiredElement('res-details');
92
+
93
+ const required = [progressBar, cardGrad, resName, resTag, resPros, resCons, resTip, resDetails];
94
+ if (required.some((el) => !el)) return null;
95
+
96
+ return {
97
+ styleButtons: document.querySelectorAll('.style-btn'),
98
+ maintButtons: document.querySelectorAll('.maint-btn'),
99
+ progressBar: progressBar as HTMLElement,
100
+ cardGrad: cardGrad as HTMLElement,
101
+ resName: resName as HTMLElement,
102
+ resTag: resTag as HTMLElement,
103
+ resPros: resPros as HTMLElement,
104
+ resCons: resCons as HTMLElement,
105
+ resTip: resTip as HTMLElement,
106
+ resDetails: resDetails as HTMLElement,
107
+ iconPlaceholder: getRequiredElement('icon-placeholder'),
108
+ resultIcons: document.querySelectorAll('.cw-result-icon'),
109
+ };
110
+ }
111
+
112
+ function updateDisplay(state: State, els: CookwareElements, db: Record<string, MaterialData>): void {
113
+ const progress = (state.style ? 50 : 0) + (state.maint ? 50 : 0);
114
+ els.progressBar.style.width = `${progress}%`;
115
+
116
+ if (!state.style || !state.maint) return;
117
+
118
+ const key = LOGIC[state.style][state.maint];
119
+ const data = db[key];
120
+
121
+ els.cardGrad.style.background = data.grad;
122
+ els.resName.textContent = data.name;
123
+ els.resTag.textContent = data.tag;
124
+ els.resPros.textContent = data.pros;
125
+ els.resCons.textContent = data.cons;
126
+ els.resTip.textContent = `"${data.tip}"`;
127
+ els.resDetails.classList.remove('cw-hidden');
128
+
129
+ if (els.iconPlaceholder) {
130
+ els.iconPlaceholder.classList.add('cw-hidden');
131
+ }
132
+ els.resultIcons.forEach((icon) => icon.classList.add('cw-hidden'));
133
+ const targetIcon = document.getElementById(`icon-${key}`);
134
+ if (targetIcon) {
135
+ targetIcon.classList.remove('cw-hidden');
136
+ }
137
+ }
138
+
139
+ function setupStyleButtons(styleButtons: NodeListOf<Element>, state: State, els: CookwareElements, db: Record<string, MaterialData>): void {
140
+ styleButtons.forEach((btn) => {
141
+ btn.addEventListener('click', () => {
142
+ styleButtons.forEach((b) => b.classList.remove('active'));
143
+ btn.classList.add('active');
144
+ state.style = (btn as HTMLElement).dataset.value as CookingStyle;
145
+ updateDisplay(state, els, db);
146
+ });
147
+ });
148
+ }
149
+
150
+ function setupMaintenanceButtons(maintButtons: NodeListOf<Element>, state: State, els: CookwareElements, db: Record<string, MaterialData>): void {
151
+ maintButtons.forEach((btn) => {
152
+ btn.addEventListener('click', () => {
153
+ maintButtons.forEach((b) => b.classList.remove('active'));
154
+ btn.classList.add('active');
155
+ state.maint = (btn as HTMLElement).dataset.value as MaintenanceLevel;
156
+ updateDisplay(state, els, db);
157
+ });
158
+ });
159
+ }
160
+
161
+ export function initCookwareGuide(ui: Record<string, string>): void {
162
+ const els = setupElements();
163
+ if (!els) return;
164
+
165
+ const state: State = { style: null, maint: null };
166
+ const db = buildMaterialDB(ui);
167
+
168
+ if (ui.defaultTip) {
169
+ els.resTip.textContent = `"${ui.defaultTip}"`;
170
+ }
171
+
172
+ setupStyleButtons(els.styleButtons, state, els, db);
173
+ setupMaintenanceButtons(els.maintButtons, state, els, db);
174
+ }
@@ -0,0 +1,8 @@
1
+ ---
2
+ import { SEORenderer } from "@jjlmoya/utils-shared";
3
+ import { content } from "./i18n/es";
4
+
5
+ const locale = "es";
6
+ ---
7
+
8
+ <SEORenderer content={{ sections: content.seo, locale }} />
@@ -0,0 +1,503 @@
1
+ .egg-timer-wrapper {
2
+ --color-primary: #eab308;
3
+ --color-secondary: #f59e0b;
4
+ --color-tertiary: #ea580c;
5
+ --color-bg: #fff;
6
+ --color-bg-secondary: #f9fafb;
7
+ --color-border: #e5e7eb;
8
+ --color-text-primary: #111827;
9
+ --color-text-secondary: #4b5563;
10
+ --color-text-tertiary: #6b7280;
11
+ --color-soft: #fef08a;
12
+ --color-soft-bg: #fef08a;
13
+ --color-soft-text: #713f12;
14
+ --color-mollet: #fbbf24;
15
+ --color-mollet-bg: #fbbf24;
16
+ --color-mollet-text: #92400e;
17
+ --color-hard: #b45309;
18
+ --color-hard-text: #78350f;
19
+ --color-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
20
+ --color-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
21
+ --color-ring: rgba(234, 179, 8, 0.5);
22
+ }
23
+
24
+ .theme-dark .egg-timer-wrapper {
25
+ --color-bg: #1f2937;
26
+ --color-bg-secondary: #111827;
27
+ --color-border: #374151;
28
+ --color-text-primary: #f3f4f6;
29
+ --color-text-secondary: #d1d5db;
30
+ --color-text-tertiary: #9ca3af;
31
+ --color-soft-bg: #78350f;
32
+ --color-soft-text: #fef08a;
33
+ --color-mollet-bg: #92400e;
34
+ --color-mollet-text: #fbbf24;
35
+ --color-hard-text: #fbbf24;
36
+ --color-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3);
37
+ --color-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
38
+ --color-ring: rgba(234, 179, 8, 0.3);
39
+ }
40
+
41
+ .egg-timer-container {
42
+ width: 100%;
43
+ max-width: 1200px;
44
+ margin: 0 auto;
45
+ padding: 2rem 1rem;
46
+ }
47
+
48
+ .egg-timer-grid {
49
+ display: grid;
50
+ grid-template-columns: 1fr 2fr;
51
+ gap: 2rem;
52
+ margin-bottom: 2rem;
53
+ }
54
+
55
+ @media (max-width: 1024px) {
56
+ .egg-timer-grid {
57
+ grid-template-columns: 1fr;
58
+ }
59
+ }
60
+
61
+ .egg-timer-card {
62
+ background-color: var(--color-bg);
63
+ border: 1px solid var(--color-border);
64
+ border-radius: 1.5rem;
65
+ padding: 1.5rem;
66
+ box-shadow: var(--color-shadow);
67
+ transition: all 0.3s ease;
68
+ }
69
+
70
+ .egg-timer-card:hover {
71
+ box-shadow: var(--color-shadow-lg);
72
+ }
73
+
74
+ .egg-timer-title {
75
+ font-size: 1.125rem;
76
+ font-weight: 700;
77
+ color: var(--color-text-primary);
78
+ margin-bottom: 1rem;
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 0.5rem;
82
+ }
83
+
84
+ .egg-timer-title svg {
85
+ width: 1.25rem;
86
+ height: 1.25rem;
87
+ color: var(--color-primary);
88
+ }
89
+
90
+ .egg-timer-controls-space {
91
+ display: flex;
92
+ flex-direction: column;
93
+ gap: 1.5rem;
94
+ }
95
+
96
+ .egg-timer-control-group {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: 0.75rem;
100
+ }
101
+
102
+ .egg-timer-label-row {
103
+ display: flex;
104
+ justify-content: space-between;
105
+ align-items: center;
106
+ margin-bottom: 0.5rem;
107
+ }
108
+
109
+ .egg-timer-label {
110
+ font-size: 0.875rem;
111
+ font-weight: 600;
112
+ color: var(--color-text-secondary);
113
+ text-transform: uppercase;
114
+ letter-spacing: 0.05em;
115
+ }
116
+
117
+ .egg-timer-buttons-group {
118
+ display: grid;
119
+ grid-template-columns: 1fr 1fr;
120
+ gap: 0.5rem;
121
+ }
122
+
123
+ .egg-timer-btn {
124
+ padding: 0.75rem;
125
+ border-radius: 0.75rem;
126
+ border: 1px solid var(--color-border);
127
+ background-color: var(--color-bg-secondary);
128
+ color: var(--color-text-secondary);
129
+ font-size: 0.875rem;
130
+ font-weight: 600;
131
+ cursor: pointer;
132
+ transition: all 0.2s ease;
133
+ display: flex;
134
+ flex-direction: column;
135
+ align-items: center;
136
+ justify-content: center;
137
+ gap: 0.25rem;
138
+ }
139
+
140
+ .egg-timer-btn:hover {
141
+ background-color: var(--color-bg);
142
+ border-color: var(--color-primary);
143
+ }
144
+
145
+ .egg-timer-btn.active {
146
+ border-color: var(--color-primary);
147
+ background-color: var(--color-soft);
148
+ color: var(--color-text-primary);
149
+ box-shadow: 0 0 0 1px var(--color-primary);
150
+ }
151
+
152
+ .theme-dark .egg-timer-btn.active {
153
+ background-color: rgba(234, 179, 8, 0.1);
154
+ color: var(--color-primary);
155
+ }
156
+
157
+ .egg-timer-btn svg {
158
+ width: 1.25rem;
159
+ height: 1.25rem;
160
+ }
161
+
162
+ .egg-timer-size-buttons {
163
+ display: grid;
164
+ grid-template-columns: repeat(4, 1fr);
165
+ gap: 0.5rem;
166
+ }
167
+
168
+ .egg-timer-size-btn {
169
+ padding: 0.5rem;
170
+ border-radius: 0.75rem;
171
+ border: 1px solid var(--color-border);
172
+ background-color: var(--color-bg-secondary);
173
+ color: var(--color-text-secondary);
174
+ font-size: 0.875rem;
175
+ font-weight: 600;
176
+ cursor: pointer;
177
+ transition: all 0.2s ease;
178
+ }
179
+
180
+ .egg-timer-size-btn:hover {
181
+ border-color: var(--color-primary);
182
+ background-color: var(--color-bg);
183
+ }
184
+
185
+ .egg-timer-size-btn.active {
186
+ border-color: var(--color-primary);
187
+ background-color: var(--color-soft);
188
+ color: var(--color-text-primary);
189
+ box-shadow: 0 0 0 1px var(--color-primary);
190
+ }
191
+
192
+ .theme-dark .egg-timer-size-btn.active {
193
+ background-color: rgba(234, 179, 8, 0.1);
194
+ color: var(--color-primary);
195
+ }
196
+
197
+ .egg-timer-input-wrapper {
198
+ position: relative;
199
+ display: flex;
200
+ }
201
+
202
+ .egg-timer-input {
203
+ width: 100%;
204
+ padding: 0.75rem 3rem 0.75rem 1rem;
205
+ border-radius: 0.75rem;
206
+ border: 1px solid var(--color-border);
207
+ background-color: var(--color-bg-secondary);
208
+ color: var(--color-text-primary);
209
+ font-size: 1rem;
210
+ transition: all 0.2s ease;
211
+ }
212
+
213
+ .egg-timer-input:focus {
214
+ outline: none;
215
+ border-color: var(--color-primary);
216
+ box-shadow: 0 0 0 2px var(--color-ring);
217
+ }
218
+
219
+ .egg-timer-input-buttons {
220
+ position: absolute;
221
+ right: 0.5rem;
222
+ top: 50%;
223
+ transform: translateY(-50%);
224
+ display: flex;
225
+ gap: 0.25rem;
226
+ }
227
+
228
+ .egg-timer-quick-btn {
229
+ padding: 0.25rem 0.5rem;
230
+ border-radius: 0.5rem;
231
+ border: 1px solid var(--color-border);
232
+ background-color: var(--color-bg-secondary);
233
+ color: var(--color-text-secondary);
234
+ font-size: 0.625rem;
235
+ font-weight: 600;
236
+ cursor: pointer;
237
+ transition: all 0.2s ease;
238
+ }
239
+
240
+ .egg-timer-quick-btn:hover {
241
+ background-color: var(--color-bg);
242
+ border-color: var(--color-primary);
243
+ color: var(--color-primary);
244
+ }
245
+
246
+ .egg-timer-help-text {
247
+ font-size: 0.75rem;
248
+ color: var(--color-text-tertiary);
249
+ margin-top: 0.5rem;
250
+ }
251
+
252
+ .egg-timer-results {
253
+ display: flex;
254
+ flex-direction: column;
255
+ gap: 1rem;
256
+ }
257
+
258
+ .egg-timer-result-card {
259
+ background-color: var(--color-bg);
260
+ border: 1px solid var(--color-border);
261
+ border-radius: 1.5rem;
262
+ padding: 1.5rem;
263
+ transition: all 0.3s ease;
264
+ cursor: default;
265
+ }
266
+
267
+ .egg-timer-result-card:hover {
268
+ box-shadow: var(--color-shadow-lg);
269
+ border-color: var(--color-primary);
270
+ }
271
+
272
+ .egg-timer-result-card.soft {
273
+ background-color: var(--color-bg);
274
+ }
275
+
276
+ .egg-timer-result-card.mollet {
277
+ background-color: var(--color-bg);
278
+ border: 2px solid var(--color-mollet);
279
+ box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.1);
280
+ }
281
+
282
+ .theme-dark .egg-timer-result-card.mollet {
283
+ box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.15);
284
+ }
285
+
286
+ .egg-timer-result-card.hard {
287
+ background-color: var(--color-bg);
288
+ }
289
+
290
+ .egg-timer-result-header {
291
+ display: flex;
292
+ justify-content: space-between;
293
+ align-items: flex-start;
294
+ margin-bottom: 1rem;
295
+ }
296
+
297
+ .egg-timer-result-title {
298
+ font-size: 1.25rem;
299
+ font-weight: 700;
300
+ color: var(--color-text-primary);
301
+ }
302
+
303
+ .egg-timer-result-subtitle {
304
+ font-size: 0.875rem;
305
+ color: var(--color-text-secondary);
306
+ margin-top: 0.25rem;
307
+ }
308
+
309
+ .egg-timer-result-icon {
310
+ width: 2rem;
311
+ height: 2rem;
312
+ color: var(--color-primary);
313
+ }
314
+
315
+ .egg-timer-result-card.mollet .egg-timer-result-icon {
316
+ color: var(--color-mollet);
317
+ }
318
+
319
+ .egg-timer-result-card.hard .egg-timer-result-icon {
320
+ color: var(--color-hard);
321
+ }
322
+
323
+ .egg-timer-result-time {
324
+ font-size: 2.25rem;
325
+ font-weight: 900;
326
+ color: var(--color-text-primary);
327
+ letter-spacing: -0.05em;
328
+ }
329
+
330
+ .egg-timer-result-card.mollet .egg-timer-result-time {
331
+ color: var(--color-mollet);
332
+ }
333
+
334
+ .egg-timer-result-card.hard .egg-timer-result-time {
335
+ color: var(--color-hard);
336
+ }
337
+
338
+ .egg-timer-seo-section {
339
+ background-color: var(--color-bg);
340
+ border: 1px solid var(--color-border);
341
+ border-radius: 1.5rem;
342
+ padding: 2rem;
343
+ margin-top: 2rem;
344
+ }
345
+
346
+ .egg-timer-seo-title {
347
+ font-size: 1.875rem;
348
+ font-weight: 700;
349
+ color: var(--color-text-primary);
350
+ margin-bottom: 1.5rem;
351
+ }
352
+
353
+ .egg-timer-seo-subtitle {
354
+ font-size: 1.25rem;
355
+ font-weight: 700;
356
+ color: var(--color-text-primary);
357
+ margin-bottom: 1rem;
358
+ display: flex;
359
+ align-items: center;
360
+ gap: 0.5rem;
361
+ margin-top: 1.5rem;
362
+ }
363
+
364
+ .egg-timer-seo-subtitle:not(:first-of-type) {
365
+ margin-top: 2rem;
366
+ }
367
+
368
+ .egg-timer-seo-subtitle svg {
369
+ width: 1.5rem;
370
+ height: 1.5rem;
371
+ color: var(--color-primary);
372
+ }
373
+
374
+ .egg-timer-seo-text {
375
+ font-size: 1rem;
376
+ line-height: 1.625;
377
+ color: var(--color-text-secondary);
378
+ margin-bottom: 1rem;
379
+ }
380
+
381
+ .egg-timer-seo-grid {
382
+ display: grid;
383
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
384
+ gap: 1.5rem;
385
+ margin-bottom: 1.5rem;
386
+ }
387
+
388
+ .egg-timer-seo-card {
389
+ background-color: var(--color-bg-secondary);
390
+ border-radius: 1rem;
391
+ padding: 1.5rem;
392
+ transition: all 0.2s ease;
393
+ }
394
+
395
+ .egg-timer-seo-card:hover {
396
+ background-color: var(--color-soft);
397
+ }
398
+
399
+ .theme-dark .egg-timer-seo-card:hover {
400
+ background-color: rgba(234, 179, 8, 0.1);
401
+ }
402
+
403
+ .egg-timer-seo-card-title {
404
+ font-weight: 700;
405
+ color: var(--color-primary);
406
+ margin-bottom: 0.75rem;
407
+ font-size: 0.875rem;
408
+ }
409
+
410
+ .egg-timer-seo-card-heading {
411
+ font-weight: 700;
412
+ color: var(--color-text-primary);
413
+ margin-bottom: 0.5rem;
414
+ }
415
+
416
+ .egg-timer-seo-card-text {
417
+ font-size: 0.875rem;
418
+ color: var(--color-text-secondary);
419
+ line-height: 1.5;
420
+ }
421
+
422
+ .egg-timer-formula-box {
423
+ background-color: var(--color-bg-secondary);
424
+ border-radius: 0.75rem;
425
+ padding: 1rem;
426
+ font-size: 0.875rem;
427
+ color: var(--color-text-secondary);
428
+ margin-bottom: 1rem;
429
+ overflow-x: auto;
430
+ }
431
+
432
+ .egg-timer-formula-list {
433
+ list-style: none;
434
+ padding: 0;
435
+ margin: 0;
436
+ display: flex;
437
+ flex-direction: column;
438
+ gap: 0.5rem;
439
+ }
440
+
441
+ .egg-timer-formula-list li {
442
+ font-size: 0.875rem;
443
+ color: var(--color-text-secondary);
444
+ }
445
+
446
+ .egg-timer-formula-list strong {
447
+ color: var(--color-text-primary);
448
+ }
449
+
450
+ .egg-timer-tips-list {
451
+ list-style-position: inside;
452
+ color: var(--color-text-secondary);
453
+ font-size: 0.95rem;
454
+ line-height: 1.75;
455
+ margin-bottom: 1rem;
456
+ }
457
+
458
+ .egg-timer-tips-list li {
459
+ margin-bottom: 0.75rem;
460
+ }
461
+
462
+ .egg-timer-tips-list strong {
463
+ color: var(--color-text-primary);
464
+ }
465
+
466
+ .egg-timer-links {
467
+ font-size: 0.75rem;
468
+ color: var(--color-text-tertiary);
469
+ border-top: 1px solid var(--color-border);
470
+ padding-top: 1.5rem;
471
+ margin-top: 1.5rem;
472
+ }
473
+
474
+ .egg-timer-links-title {
475
+ font-weight: 700;
476
+ margin-bottom: 0.5rem;
477
+ color: var(--color-text-secondary);
478
+ }
479
+
480
+ .egg-timer-links-list {
481
+ list-style: none;
482
+ padding: 0;
483
+ margin: 0;
484
+ display: flex;
485
+ flex-direction: column;
486
+ gap: 0.25rem;
487
+ }
488
+
489
+ .egg-timer-links-list a {
490
+ color: inherit;
491
+ text-decoration: none;
492
+ transition: color 0.2s ease;
493
+ }
494
+
495
+ .egg-timer-links-list a:hover {
496
+ color: var(--color-primary);
497
+ }
498
+
499
+ .egg-timer-hr {
500
+ border: none;
501
+ border-top: 1px solid var(--color-border);
502
+ margin: 2rem 0;
503
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography } from "@jjlmoya/utils-shared";
3
+ import { eggTimer } 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 eggTimer.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <Bibliography links={content.bibliography} />}