@jjlmoya/utils-alcohol 1.22.0 → 1.24.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,15 +1,17 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-alcohol",
3
- "version": "1.22.0",
3
+ "version": "1.24.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
- "./data": "./src/data.ts"
9
+ "./data": "./src/data.ts",
10
+ "./entries": "./src/entries.ts"
10
11
  },
11
12
  "files": [
12
- "src"
13
+ "src",
14
+ "scripts"
13
15
  ],
14
16
  "publishConfig": {
15
17
  "access": "public"
@@ -28,7 +30,8 @@
28
30
  "postversion": "git push && git push --tags",
29
31
  "patch": "npm version patch",
30
32
  "minor": "npm version minor",
31
- "major": "npm version major"
33
+ "major": "npm version major",
34
+ "postinstall": "node scripts/postinstall.mjs"
32
35
  },
33
36
  "lint-staged": {
34
37
  "*.{ts,tsx,astro}": [
@@ -0,0 +1,27 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const libDir = dirname(fileURLToPath(import.meta.url));
6
+ const toolsDir = join(libDir, '../src/tool');
7
+
8
+ const inNodeModules = libDir.includes('node_modules');
9
+ if (!inNodeModules) process.exit(0);
10
+
11
+ const projectRoot = join(libDir, '../../../..');
12
+ const categoryKey = JSON.parse(readFileSync(join(libDir, '../package.json'), 'utf8')).name.replace('@jjlmoya/utils-', '');
13
+ const destDir = join(projectRoot, `public/styles/lib/${categoryKey}`);
14
+
15
+ mkdirSync(destDir, { recursive: true });
16
+
17
+ const tools = readdirSync(toolsDir, { withFileTypes: true }).filter(d => d.isDirectory());
18
+ for (const tool of tools) {
19
+ const toolDir = join(toolsDir, tool.name);
20
+ let files;
21
+ try { files = readdirSync(toolDir).filter(f => f.endsWith('.css')); }
22
+ catch { continue; }
23
+ for (const file of files) {
24
+ writeFileSync(join(destDir, file), readFileSync(join(toolDir, file)));
25
+ console.log(`[@jjlmoya/utils-${categoryKey}] copied ${file}`);
26
+ }
27
+ }
package/src/entries.ts ADDED
@@ -0,0 +1,17 @@
1
+ export { alcoholClearance } from './tool/alcoholClearance/entry';
2
+ export type { AlcoholClearanceUI, AlcoholClearanceLocaleContent } from './tool/alcoholClearance/entry';
3
+ export { beerCooler } from './tool/beerCooler/entry';
4
+ export type { BeerCoolerUI, BeerCoolerLocaleContent } from './tool/beerCooler/entry';
5
+ export { carbonationCalculator } from './tool/carbonationCalculator/entry';
6
+ export type { CarbonationUI, CarbonationLocaleContent } from './tool/carbonationCalculator/entry';
7
+ export { cocktailBalancer } from './tool/cocktailBalancer/entry';
8
+ export type { CocktailBalancerUI, CocktailBalancerLocaleContent } from './tool/cocktailBalancer/entry';
9
+ export { partyKeg } from './tool/partyKeg/entry';
10
+ export type { PartyKegUI, PartyKegLocaleContent } from './tool/partyKeg/entry';
11
+ export { alcoholCategory, toolsCategory } from './category';
12
+ import { alcoholClearance } from './tool/alcoholClearance/entry';
13
+ import { beerCooler } from './tool/beerCooler/entry';
14
+ import { carbonationCalculator } from './tool/carbonationCalculator/entry';
15
+ import { cocktailBalancer } from './tool/cocktailBalancer/entry';
16
+ import { partyKeg } from './tool/partyKeg/entry';
17
+ export const ALL_ENTRIES = [alcoholClearance, beerCooler, carbonationCalculator, cocktailBalancer, partyKeg];
@@ -0,0 +1,431 @@
1
+ .alc-app {
2
+ width: 100%;
3
+ max-width: 56rem;
4
+ margin: 0 auto;
5
+ padding: 0.5rem;
6
+ }
7
+
8
+ .alc-card {
9
+ background: #fff;
10
+ border: 1px solid #e2e8f0;
11
+ border-radius: 1.25rem;
12
+ overflow: clip;
13
+ box-shadow: 0 4px 20px rgba(0,0,0,0.06);
14
+ color: #1e293b;
15
+ }
16
+ :global(.theme-dark) .alc-card {
17
+ background: #0f172a;
18
+ border-color: #1e293b;
19
+ color: #f1f5f9;
20
+ }
21
+
22
+ .alc-grid { display: grid; }
23
+
24
+ @media (min-width: 768px) {
25
+ .alc-grid {
26
+ grid-template-columns: 1fr 1fr;
27
+ align-items: stretch;
28
+ }
29
+ }
30
+
31
+ .alc-inputs-panel {
32
+ display: flex;
33
+ flex-direction: column;
34
+ }
35
+
36
+ @media (min-width: 768px) { .alc-inputs-panel { border-right: 1px solid #e2e8f0; } }
37
+ :global(.theme-dark) .alc-inputs-panel { border-color: #1e293b; }
38
+
39
+ .alc-sec {
40
+ padding: 1.25rem 1.5rem;
41
+ border-bottom: 1px solid #e2e8f0;
42
+ }
43
+ :global(.theme-dark) .alc-sec { border-color: #1e293b; }
44
+ .alc-sec:last-child { border-bottom: none; }
45
+
46
+ .alc-sex-weight {
47
+ display: grid;
48
+ grid-template-columns: 1fr 1fr;
49
+ gap: 1.25rem;
50
+ }
51
+ .alc-field {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 0.75rem;
55
+ }
56
+
57
+ .field-label {
58
+ font-size: 0.75rem;
59
+ font-weight: 700;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.1em;
62
+ color: #94a3b8;
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 0.5rem;
66
+ }
67
+ .field-label-icon {
68
+ width: 1rem;
69
+ height: 1rem;
70
+ }
71
+
72
+ .sex-toggle {
73
+ display: flex;
74
+ gap: 0.5rem;
75
+ padding: 0.25rem;
76
+ background: #f1f5f9;
77
+ border-radius: 0.75rem;
78
+ }
79
+ :global(.theme-dark) .sex-toggle { background: #1e293b; }
80
+
81
+ .sex-btn {
82
+ flex: 1;
83
+ padding: 0.75rem;
84
+ border-radius: 0.5rem;
85
+ border: none;
86
+ cursor: pointer;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ color: #94a3b8;
91
+ background: transparent;
92
+ transition: all 0.2s;
93
+ }
94
+ .sex-btn:hover { color: #64748b; }
95
+ .sex-btn.selected {
96
+ background: #fff;
97
+ color: #4f46e5;
98
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
99
+ }
100
+ :global(.theme-dark) .sex-btn.selected {
101
+ background: #334155;
102
+ color: #818cf8;
103
+ }
104
+ .sex-icon {
105
+ width: 1.5rem;
106
+ height: 1.5rem;
107
+ }
108
+
109
+ .weight-input-wrap { position: relative; }
110
+ .weight-input {
111
+ width: 100%;
112
+ background: #f8fafc;
113
+ border: 2px solid #e2e8f0;
114
+ border-radius: 0.75rem;
115
+ padding: 0.75rem 3rem 0.75rem 1rem;
116
+ font-weight: 700;
117
+ font-size: 1.125rem;
118
+ outline: none;
119
+ transition: border-color 0.2s;
120
+ box-sizing: border-box;
121
+ }
122
+ :global(.theme-dark) .weight-input {
123
+ background: rgba(0,0,0,0.2);
124
+ border-color: #334155;
125
+ color: #f1f5f9;
126
+ }
127
+ .weight-input:focus { border-color: #6366f1; }
128
+ .weight-unit {
129
+ position: absolute;
130
+ right: 1rem;
131
+ top: 50%;
132
+ transform: translateY(-50%);
133
+ color: #94a3b8;
134
+ font-weight: 700;
135
+ font-size: 0.75rem;
136
+ text-transform: uppercase;
137
+ }
138
+
139
+ .drink-btns {
140
+ display: grid;
141
+ grid-template-columns: repeat(4, 1fr);
142
+ gap: 0.75rem;
143
+ margin-top: 0.75rem;
144
+ }
145
+ .drink-add-btn {
146
+ display: flex;
147
+ flex-direction: column;
148
+ align-items: center;
149
+ gap: 0.5rem;
150
+ padding: 1rem;
151
+ border-radius: 0.75rem;
152
+ border: none;
153
+ cursor: pointer;
154
+ background: #f1f5f9;
155
+ color: #475569;
156
+ transition: all 0.15s;
157
+ }
158
+ :global(.theme-dark) .drink-add-btn {
159
+ background: #1e293b;
160
+ color: #94a3b8;
161
+ }
162
+ .drink-add-btn:hover {
163
+ background: #e0e7ff;
164
+ color: #6366f1;
165
+ transform: scale(1.05);
166
+ }
167
+ .drink-add-btn:active { transform: scale(0.95); }
168
+ .drink-icon {
169
+ width: 2rem;
170
+ height: 2rem;
171
+ }
172
+
173
+ .list-header {
174
+ display: flex;
175
+ justify-content: space-between;
176
+ align-items: center;
177
+ margin-bottom: 0.75rem;
178
+ }
179
+ .items-count {
180
+ font-size: 0.75rem;
181
+ font-weight: 900;
182
+ color: #6366f1;
183
+ text-transform: uppercase;
184
+ }
185
+
186
+ .drinks-list {
187
+ max-height: 250px;
188
+ overflow-y: auto;
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: 0.5rem;
192
+ padding-right: 0.5rem;
193
+ }
194
+ .list-empty {
195
+ text-align: center;
196
+ padding: 2rem 0;
197
+ color: #cbd5e1;
198
+ display: flex;
199
+ flex-direction: column;
200
+ align-items: center;
201
+ gap: 0.75rem;
202
+ }
203
+ :global(.theme-dark) .list-empty { color: #334155; }
204
+ .list-empty-icon {
205
+ width: 2.5rem;
206
+ height: 2.5rem;
207
+ opacity: 0.2;
208
+ }
209
+ .list-empty-text {
210
+ font-size: 0.875rem;
211
+ font-weight: 500;
212
+ }
213
+
214
+ .custom-scroll::-webkit-scrollbar { width: 4px; }
215
+ .custom-scroll::-webkit-scrollbar-track { background: transparent; }
216
+ .custom-scroll::-webkit-scrollbar-thumb {
217
+ background: #e2e8f0;
218
+ border-radius: 10px;
219
+ }
220
+
221
+ :global(.drink-list-row) {
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: space-between;
225
+ padding: 0.75rem;
226
+ background: #f8fafc;
227
+ border-radius: 0.75rem;
228
+ border: 1px solid #e2e8f0;
229
+ }
230
+ :global(.theme-dark) :global(.drink-list-row) {
231
+ background: #1e293b;
232
+ border-color: #334155;
233
+ }
234
+
235
+ :global(.drink-row-info) {
236
+ display: flex;
237
+ align-items: center;
238
+ gap: 0.75rem;
239
+ }
240
+
241
+ :global(.drink-row-name) {
242
+ font-weight: 700;
243
+ color: #334155;
244
+ }
245
+ :global(.theme-dark) :global(.drink-row-name) {
246
+ color: #e2e8f0;
247
+ }
248
+
249
+ :global(.drink-row-qty) {
250
+ font-size: 0.75rem;
251
+ background: #e0e7ff;
252
+ color: #4f46e5;
253
+ padding: 0.125rem 0.5rem;
254
+ border-radius: 0.25rem;
255
+ font-weight: 700;
256
+ }
257
+ :global(.theme-dark) :global(.drink-row-qty) {
258
+ background: #312e81;
259
+ color: #a5b4fc;
260
+ }
261
+
262
+ :global(.drink-row-del) {
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: center;
266
+ width: 2rem;
267
+ height: 2rem;
268
+ padding: 0;
269
+ background: none;
270
+ border: none;
271
+ color: #ef4444;
272
+ cursor: pointer;
273
+ transition: background 0.2s;
274
+ }
275
+ :global(.drink-row-del:hover) {
276
+ background: #fef2f2;
277
+ border-radius: 0.5rem;
278
+ }
279
+ :global(.theme-dark) :global(.drink-row-del:hover) {
280
+ background: rgba(239,68,68,0.1);
281
+ }
282
+
283
+ .alc-results-panel {
284
+ display: flex;
285
+ flex-direction: column;
286
+ background: #f8fafc;
287
+ }
288
+ :global(.theme-dark) .alc-results-panel { background: rgba(0,0,0,0.2); }
289
+
290
+ .bac-section {
291
+ background: #4f46e5;
292
+ color: #fff;
293
+ padding: 1.5rem;
294
+ position: relative;
295
+ overflow: hidden;
296
+ flex-shrink: 0;
297
+ }
298
+ :global(.theme-dark) .bac-section { background: #4338ca; }
299
+ .bac-bg-icon {
300
+ position: absolute;
301
+ top: 0;
302
+ right: 0;
303
+ padding: 1.5rem;
304
+ opacity: 0.1;
305
+ }
306
+ .bac-bg-icon-svg {
307
+ width: 5rem;
308
+ height: 5rem;
309
+ transform: rotate(12deg);
310
+ }
311
+ .bac-content {
312
+ position: relative;
313
+ z-index: 1;
314
+ display: flex;
315
+ flex-direction: column;
316
+ gap: 1rem;
317
+ }
318
+ .bac-label {
319
+ font-size: 0.75rem;
320
+ font-weight: 700;
321
+ text-transform: uppercase;
322
+ letter-spacing: 0.2em;
323
+ opacity: 0.6;
324
+ }
325
+ .bac-value-row {
326
+ display: flex;
327
+ align-items: baseline;
328
+ gap: 0.5rem;
329
+ }
330
+ .bac-number {
331
+ font-size: 3.5rem;
332
+ font-weight: 900;
333
+ letter-spacing: -0.05em;
334
+ line-height: 1;
335
+ font-variant-numeric: tabular-nums;
336
+ }
337
+ .bac-unit {
338
+ font-size: 1rem;
339
+ font-weight: 700;
340
+ opacity: 0.6;
341
+ }
342
+
343
+ .time-box {
344
+ display: flex;
345
+ align-items: center;
346
+ gap: 0.75rem;
347
+ background: rgba(255,255,255,0.1);
348
+ border-radius: 0.75rem;
349
+ padding: 0.75rem;
350
+ border: 1px solid rgba(255,255,255,0.1);
351
+ }
352
+ .time-icon {
353
+ width: 1.25rem;
354
+ height: 1.25rem;
355
+ flex-shrink: 0;
356
+ }
357
+ .time-text {
358
+ font-weight: 700;
359
+ font-size: 0.875rem;
360
+ }
361
+
362
+ .alc-advice-sec {
363
+ display: flex;
364
+ flex-direction: column;
365
+ gap: 1rem;
366
+ }
367
+ .advice-row {
368
+ display: flex;
369
+ align-items: center;
370
+ gap: 1rem;
371
+ }
372
+ .advice-icon {
373
+ width: 2.25rem;
374
+ height: 2.25rem;
375
+ border-radius: 0.6rem;
376
+ display: flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ flex-shrink: 0;
380
+ }
381
+ .advice-icon-blue {
382
+ background: #dbeafe;
383
+ color: #3b82f6;
384
+ }
385
+ :global(.theme-dark) .advice-icon-blue { background: rgba(59,130,246,0.2); }
386
+ .advice-icon-amber {
387
+ background: #fef3c7;
388
+ color: #f59e0b;
389
+ }
390
+ :global(.theme-dark) .advice-icon-amber { background: rgba(245,158,11,0.2); }
391
+ .advice-icon-svg {
392
+ width: 1.25rem;
393
+ height: 1.25rem;
394
+ }
395
+ .advice-label {
396
+ font-size: 0.75rem;
397
+ font-weight: 700;
398
+ color: #94a3b8;
399
+ text-transform: uppercase;
400
+ margin: 0 0 0.2rem;
401
+ }
402
+ .advice-value {
403
+ font-size: 1.125rem;
404
+ font-weight: 900;
405
+ margin: 0;
406
+ }
407
+ .advice-value-sm { font-size: 0.875rem; }
408
+
409
+ .alc-disclaimer-sec { margin-top: auto; }
410
+ .disclaimer {
411
+ background: #fffbeb;
412
+ border-radius: 0.75rem;
413
+ padding: 0.875rem;
414
+ display: flex;
415
+ gap: 0.75rem;
416
+ color: #92400e;
417
+ font-size: 0.75rem;
418
+ line-height: 1.6;
419
+ border: 1px solid #fde68a;
420
+ }
421
+ :global(.theme-dark) .disclaimer {
422
+ background: rgba(120,53,15,0.2);
423
+ border-color: rgba(120,53,15,0.5);
424
+ color: #f59e0b;
425
+ }
426
+ .disclaimer-icon {
427
+ width: 1.5rem;
428
+ height: 1.5rem;
429
+ flex-shrink: 0;
430
+ }
431
+ .disclaimer-text { margin: 0; }