@jjlmoya/utils-nature 1.11.0 → 1.13.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-nature",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -10,7 +10,8 @@
10
10
  "./entries": "./src/entries.ts"
11
11
  },
12
12
  "files": [
13
- "src"
13
+ "src",
14
+ "scripts"
14
15
  ],
15
16
  "publishConfig": {
16
17
  "access": "public"
@@ -29,7 +30,8 @@
29
30
  "postversion": "git push && git push --tags",
30
31
  "patch": "npm version patch",
31
32
  "minor": "npm version minor",
32
- "major": "npm version major"
33
+ "major": "npm version major",
34
+ "postinstall": "node scripts/postinstall.mjs"
33
35
  },
34
36
  "lint-staged": {
35
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
+ }
@@ -71,262 +71,6 @@ const { ui } = Astro.props;
71
71
  </div>
72
72
  </div>
73
73
 
74
- <style>
75
- .ct-card {
76
- --ct-bg-card: #fff;
77
- --ct-bg-image: #f0fdf4;
78
- --ct-gradient-from: #fff;
79
- --ct-border: #d1fae5;
80
- --ct-shadow: rgba(0, 0, 0, 0.1);
81
- --ct-circle-bg: #f0fdf4;
82
- --ct-circle-border: #a7f3d0;
83
- --ct-circle-shadow: rgba(0, 0, 0, 0.08);
84
- --ct-temp-color: #064e3b;
85
- --ct-unit-color: #059669;
86
- --ct-bpm-color: #6b7280;
87
- --ct-btn-border: #d1fae5;
88
- --ct-btn-color: #374151;
89
- --ct-btn-hover-bg: #ecfdf5;
90
- --ct-btn-hover-color: #064e3b;
91
- --ct-audio-active: #059669;
92
- --ct-glow: rgba(16, 185, 129, 0.15);
93
- --ct-tap-hint: rgba(4, 47, 46, 0.65);
94
- --ct-tap-bg-from: #84cc16;
95
- --ct-tap-bg-to: #059669;
96
- --ct-tap-shadow: rgba(5, 150, 105, 0.35);
97
- --ct-tap-border: rgba(16, 185, 129, 0.3);
98
- --ct-fill-colors: #3b82f6, #10b981, #ef4444;
99
-
100
- position: relative;
101
- width: 100%;
102
- max-width: 32rem;
103
- margin: 0 auto;
104
- background: var(--ct-bg-card);
105
- border-radius: 2rem;
106
- overflow: hidden;
107
- box-shadow: 0 25px 50px -12px var(--ct-shadow);
108
- border: 1px solid var(--ct-border);
109
- transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
110
- }
111
-
112
- :global(.theme-dark) .ct-card {
113
- --ct-bg-card: #0f172a;
114
- --ct-bg-image: #1e293b;
115
- --ct-gradient-from: #0f172a;
116
- --ct-border: #1e293b;
117
- --ct-shadow: rgba(0, 0, 0, 0.5);
118
- --ct-circle-bg: #1e293b;
119
- --ct-circle-border: #334155;
120
- --ct-circle-shadow: rgba(0, 0, 0, 0.3);
121
- --ct-temp-color: #fff;
122
- --ct-unit-color: #34d399;
123
- --ct-bpm-color: #64748b;
124
- --ct-btn-border: #334155;
125
- --ct-btn-color: #94a3b8;
126
- --ct-btn-hover-bg: #1e293b;
127
- --ct-btn-hover-color: #fff;
128
- --ct-audio-active: #34d399;
129
- --ct-glow: rgba(16, 185, 129, 0.2);
130
- --ct-tap-hint: rgba(209, 250, 229, 0.8);
131
- --ct-tap-shadow: rgba(6, 78, 59, 0.5);
132
- }
133
-
134
- .ct-image-wrapper {
135
- position: relative;
136
- height: 16rem;
137
- width: 100%;
138
- background: var(--ct-bg-image);
139
- overflow: hidden;
140
- }
141
-
142
- .ct-image {
143
- display: block;
144
- object-fit: cover;
145
- width: 100%;
146
- height: 100%;
147
- }
148
-
149
- .ct-image-gradient {
150
- position: absolute;
151
- inset: 0;
152
- background: linear-gradient(to top, var(--ct-gradient-from), transparent, transparent);
153
- opacity: 0.9;
154
- }
155
-
156
- .ct-body {
157
- padding: 2rem;
158
- margin-top: -5rem;
159
- position: relative;
160
- z-index: 10;
161
- display: flex;
162
- flex-direction: column;
163
- align-items: center;
164
- }
165
-
166
- .ct-display-wrapper {
167
- position: relative;
168
- margin-bottom: 2rem;
169
- }
170
-
171
- .ct-glow {
172
- position: absolute;
173
- inset: -1rem;
174
- background: var(--ct-glow);
175
- border-radius: 50%;
176
- filter: blur(2rem);
177
- transition: opacity 1s ease;
178
- opacity: 0;
179
- pointer-events: none;
180
- }
181
-
182
- :global(.ct-display-wrapper.has-value) .ct-glow {
183
- opacity: 1;
184
- }
185
-
186
- .ct-circle {
187
- width: 12rem;
188
- height: 12rem;
189
- background: var(--ct-circle-bg);
190
- border-radius: 50%;
191
- border: 4px solid var(--ct-circle-border);
192
- display: flex;
193
- align-items: center;
194
- justify-content: center;
195
- box-shadow: 0 20px 25px -5px var(--ct-circle-shadow);
196
- overflow: hidden;
197
- position: relative;
198
- transition: background 0.3s ease, border-color 0.3s ease;
199
- }
200
-
201
- .ct-inner {
202
- position: relative;
203
- z-index: 2;
204
- text-align: center;
205
- }
206
-
207
- .ct-temp-row {
208
- display: flex;
209
- align-items: baseline;
210
- justify-content: center;
211
- gap: 0.15rem;
212
- }
213
-
214
- .ct-temp-value {
215
- font-size: 3rem;
216
- font-weight: 700;
217
- color: var(--ct-temp-color);
218
- transition: all 0.3s ease;
219
- }
220
-
221
- .ct-temp-unit {
222
- font-size: 1.5rem;
223
- color: var(--ct-unit-color);
224
- font-weight: 700;
225
- }
226
-
227
- .ct-bpm-label {
228
- font-size: 0.75rem;
229
- color: var(--ct-bpm-color);
230
- margin-top: 0.5rem;
231
- }
232
-
233
- .ct-fill {
234
- position: absolute;
235
- bottom: 0;
236
- left: 0;
237
- right: 0;
238
- background: linear-gradient(to top, var(--ct-fill-colors));
239
- transition: height 1s ease, opacity 1s ease;
240
- opacity: 0.2;
241
- height: 0;
242
- }
243
-
244
- .ct-tap-btn {
245
- width: 100%;
246
- max-width: 20rem;
247
- aspect-ratio: 1;
248
- border-radius: 50%;
249
- background: linear-gradient(135deg, var(--ct-tap-bg-from), var(--ct-tap-bg-to));
250
- box-shadow: 0 10px 15px -3px var(--ct-tap-shadow);
251
- display: flex;
252
- flex-direction: column;
253
- align-items: center;
254
- justify-content: center;
255
- gap: 0.25rem;
256
- transform: scale(1);
257
- transition: transform 0.15s ease, box-shadow 0.15s ease;
258
- border: 4px solid var(--ct-tap-border);
259
- margin-bottom: 1.5rem;
260
- cursor: pointer;
261
- }
262
-
263
- .ct-tap-btn:hover {
264
- transform: scale(1.05);
265
- box-shadow: 0 10px 20px var(--ct-glow);
266
- }
267
-
268
- .ct-tap-btn:active {
269
- transform: scale(0.95);
270
- }
271
-
272
- :global(.ct-tap-btn.ct-tap-pressed) {
273
- transform: scale(0.95);
274
- }
275
-
276
- .ct-tap-icon {
277
- font-size: 2.5rem;
278
- color: #fff;
279
- pointer-events: none;
280
- }
281
-
282
- .ct-tap-label {
283
- font-size: 1.25rem;
284
- font-weight: 700;
285
- color: #fff;
286
- text-transform: uppercase;
287
- letter-spacing: 0.2em;
288
- pointer-events: none;
289
- }
290
-
291
- .ct-tap-hint {
292
- font-size: 0.75rem;
293
- color: var(--ct-tap-hint);
294
- pointer-events: none;
295
- }
296
-
297
- .ct-controls {
298
- display: flex;
299
- gap: 1rem;
300
- }
301
-
302
- .ct-reset-btn,
303
- .ct-audio-btn {
304
- padding: 0.5rem 1.5rem;
305
- border-radius: 9999px;
306
- border: 1px solid var(--ct-btn-border);
307
- color: var(--ct-btn-color);
308
- background: transparent;
309
- cursor: pointer;
310
- font-size: 0.875rem;
311
- transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
312
- }
313
-
314
- .ct-reset-btn:hover,
315
- .ct-audio-btn:hover {
316
- background: var(--ct-btn-hover-bg);
317
- color: var(--ct-btn-hover-color);
318
- }
319
-
320
- .ct-audio-btn {
321
- display: flex;
322
- align-items: center;
323
- gap: 0.5rem;
324
- }
325
-
326
- :global(.ct-audio-btn.audio-active) {
327
- color: var(--ct-audio-active);
328
- }
329
- </style>
330
74
 
331
75
  <script>
332
76
  const card = document.querySelector<HTMLElement>(".ct-card");
@@ -0,0 +1,254 @@
1
+ .ct-card {
2
+ --ct-bg-card: #fff;
3
+ --ct-bg-image: #f0fdf4;
4
+ --ct-gradient-from: #fff;
5
+ --ct-border: #d1fae5;
6
+ --ct-shadow: rgba(0, 0, 0, 0.1);
7
+ --ct-circle-bg: #f0fdf4;
8
+ --ct-circle-border: #a7f3d0;
9
+ --ct-circle-shadow: rgba(0, 0, 0, 0.08);
10
+ --ct-temp-color: #064e3b;
11
+ --ct-unit-color: #059669;
12
+ --ct-bpm-color: #6b7280;
13
+ --ct-btn-border: #d1fae5;
14
+ --ct-btn-color: #374151;
15
+ --ct-btn-hover-bg: #ecfdf5;
16
+ --ct-btn-hover-color: #064e3b;
17
+ --ct-audio-active: #059669;
18
+ --ct-glow: rgba(16, 185, 129, 0.15);
19
+ --ct-tap-hint: rgba(4, 47, 46, 0.65);
20
+ --ct-tap-bg-from: #84cc16;
21
+ --ct-tap-bg-to: #059669;
22
+ --ct-tap-shadow: rgba(5, 150, 105, 0.35);
23
+ --ct-tap-border: rgba(16, 185, 129, 0.3);
24
+ --ct-fill-colors: #3b82f6, #10b981, #ef4444;
25
+
26
+ position: relative;
27
+ width: 100%;
28
+ max-width: 32rem;
29
+ margin: 0 auto;
30
+ background: var(--ct-bg-card);
31
+ border-radius: 2rem;
32
+ overflow: hidden;
33
+ box-shadow: 0 25px 50px -12px var(--ct-shadow);
34
+ border: 1px solid var(--ct-border);
35
+ transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
36
+ }
37
+
38
+ .theme-dark .ct-card {
39
+ --ct-bg-card: #0f172a;
40
+ --ct-bg-image: #1e293b;
41
+ --ct-gradient-from: #0f172a;
42
+ --ct-border: #1e293b;
43
+ --ct-shadow: rgba(0, 0, 0, 0.5);
44
+ --ct-circle-bg: #1e293b;
45
+ --ct-circle-border: #334155;
46
+ --ct-circle-shadow: rgba(0, 0, 0, 0.3);
47
+ --ct-temp-color: #fff;
48
+ --ct-unit-color: #34d399;
49
+ --ct-bpm-color: #64748b;
50
+ --ct-btn-border: #334155;
51
+ --ct-btn-color: #94a3b8;
52
+ --ct-btn-hover-bg: #1e293b;
53
+ --ct-btn-hover-color: #fff;
54
+ --ct-audio-active: #34d399;
55
+ --ct-glow: rgba(16, 185, 129, 0.2);
56
+ --ct-tap-hint: rgba(209, 250, 229, 0.8);
57
+ --ct-tap-shadow: rgba(6, 78, 59, 0.5);
58
+ }
59
+
60
+ .ct-image-wrapper {
61
+ position: relative;
62
+ height: 16rem;
63
+ width: 100%;
64
+ background: var(--ct-bg-image);
65
+ overflow: hidden;
66
+ }
67
+
68
+ .ct-image {
69
+ display: block;
70
+ object-fit: cover;
71
+ width: 100%;
72
+ height: 100%;
73
+ }
74
+
75
+ .ct-image-gradient {
76
+ position: absolute;
77
+ inset: 0;
78
+ background: linear-gradient(to top, var(--ct-gradient-from), transparent, transparent);
79
+ opacity: 0.9;
80
+ }
81
+
82
+ .ct-body {
83
+ padding: 2rem;
84
+ margin-top: -5rem;
85
+ position: relative;
86
+ z-index: 10;
87
+ display: flex;
88
+ flex-direction: column;
89
+ align-items: center;
90
+ }
91
+
92
+ .ct-display-wrapper {
93
+ position: relative;
94
+ margin-bottom: 2rem;
95
+ }
96
+
97
+ .ct-glow {
98
+ position: absolute;
99
+ inset: -1rem;
100
+ background: var(--ct-glow);
101
+ border-radius: 50%;
102
+ filter: blur(2rem);
103
+ transition: opacity 1s ease;
104
+ opacity: 0;
105
+ pointer-events: none;
106
+ }
107
+
108
+ .ct-display-wrapper.has-value .ct-glow {
109
+ opacity: 1;
110
+ }
111
+
112
+ .ct-circle {
113
+ width: 12rem;
114
+ height: 12rem;
115
+ background: var(--ct-circle-bg);
116
+ border-radius: 50%;
117
+ border: 4px solid var(--ct-circle-border);
118
+ display: flex;
119
+ align-items: center;
120
+ justify-content: center;
121
+ box-shadow: 0 20px 25px -5px var(--ct-circle-shadow);
122
+ overflow: hidden;
123
+ position: relative;
124
+ transition: background 0.3s ease, border-color 0.3s ease;
125
+ }
126
+
127
+ .ct-inner {
128
+ position: relative;
129
+ z-index: 2;
130
+ text-align: center;
131
+ }
132
+
133
+ .ct-temp-row {
134
+ display: flex;
135
+ align-items: baseline;
136
+ justify-content: center;
137
+ gap: 0.15rem;
138
+ }
139
+
140
+ .ct-temp-value {
141
+ font-size: 3rem;
142
+ font-weight: 700;
143
+ color: var(--ct-temp-color);
144
+ transition: all 0.3s ease;
145
+ }
146
+
147
+ .ct-temp-unit {
148
+ font-size: 1.5rem;
149
+ color: var(--ct-unit-color);
150
+ font-weight: 700;
151
+ }
152
+
153
+ .ct-bpm-label {
154
+ font-size: 0.75rem;
155
+ color: var(--ct-bpm-color);
156
+ margin-top: 0.5rem;
157
+ }
158
+
159
+ .ct-fill {
160
+ position: absolute;
161
+ bottom: 0;
162
+ left: 0;
163
+ right: 0;
164
+ background: linear-gradient(to top, var(--ct-fill-colors));
165
+ transition: height 1s ease, opacity 1s ease;
166
+ opacity: 0.2;
167
+ height: 0;
168
+ }
169
+
170
+ .ct-tap-btn {
171
+ width: 100%;
172
+ max-width: 20rem;
173
+ aspect-ratio: 1;
174
+ border-radius: 50%;
175
+ background: linear-gradient(135deg, var(--ct-tap-bg-from), var(--ct-tap-bg-to));
176
+ box-shadow: 0 10px 15px -3px var(--ct-tap-shadow);
177
+ display: flex;
178
+ flex-direction: column;
179
+ align-items: center;
180
+ justify-content: center;
181
+ gap: 0.25rem;
182
+ transform: scale(1);
183
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
184
+ border: 4px solid var(--ct-tap-border);
185
+ margin-bottom: 1.5rem;
186
+ cursor: pointer;
187
+ }
188
+
189
+ .ct-tap-btn:hover {
190
+ transform: scale(1.05);
191
+ box-shadow: 0 10px 20px var(--ct-glow);
192
+ }
193
+
194
+ .ct-tap-btn:active {
195
+ transform: scale(0.95);
196
+ }
197
+
198
+ .ct-tap-btn.ct-tap-pressed {
199
+ transform: scale(0.95);
200
+ }
201
+
202
+ .ct-tap-icon {
203
+ font-size: 2.5rem;
204
+ color: #fff;
205
+ pointer-events: none;
206
+ }
207
+
208
+ .ct-tap-label {
209
+ font-size: 1.25rem;
210
+ font-weight: 700;
211
+ color: #fff;
212
+ text-transform: uppercase;
213
+ letter-spacing: 0.2em;
214
+ pointer-events: none;
215
+ }
216
+
217
+ .ct-tap-hint {
218
+ font-size: 0.75rem;
219
+ color: var(--ct-tap-hint);
220
+ pointer-events: none;
221
+ }
222
+
223
+ .ct-controls {
224
+ display: flex;
225
+ gap: 1rem;
226
+ }
227
+
228
+ .ct-reset-btn,
229
+ .ct-audio-btn {
230
+ padding: 0.5rem 1.5rem;
231
+ border-radius: 9999px;
232
+ border: 1px solid var(--ct-btn-border);
233
+ color: var(--ct-btn-color);
234
+ background: transparent;
235
+ cursor: pointer;
236
+ font-size: 0.875rem;
237
+ transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
238
+ }
239
+
240
+ .ct-reset-btn:hover,
241
+ .ct-audio-btn:hover {
242
+ background: var(--ct-btn-hover-bg);
243
+ color: var(--ct-btn-hover-color);
244
+ }
245
+
246
+ .ct-audio-btn {
247
+ display: flex;
248
+ align-items: center;
249
+ gap: 0.5rem;
250
+ }
251
+
252
+ .ct-audio-btn.audio-active {
253
+ color: var(--ct-audio-active);
254
+ }