tangled
alpha
login
or
join now
tylur.dev
/
prototypey
1
fork
atom
prototypey.org - atproto lexicon typescript toolkit - mirror https://github.com/tylersayshi/prototypey
1
fork
atom
overview
issues
pulls
pipelines
use tailwind for site
Tyler
4 months ago
c58c71b3
f59841f4
+236
-351
9 changed files
expand all
collapse all
unified
split
packages
site
package.json
src
App.tsx
components
Editor.tsx
Header.tsx
OutputPanel.tsx
Playground.tsx
index.css
vite.config.ts
pnpm-lock.yaml
+2
packages/site/package.json
···
20
20
"react-dom": "^19.2.0"
21
21
},
22
22
"devDependencies": {
23
23
+
"@tailwindcss/vite": "^4.1.17",
23
24
"@testing-library/jest-dom": "^6.9.1",
24
25
"@testing-library/react": "^16.3.0",
25
26
"@testing-library/user-event": "^14.6.1",
···
29
30
"babel-plugin-react-compiler": "^1.0.0",
30
31
"eslint-plugin-react-compiler": "19.1.0-rc.2",
31
32
"jsdom": "^25.0.1",
33
33
+
"tailwindcss": "^4.1.17",
32
34
"typescript": "5.8.3",
33
35
"vite": "^6.4.1",
34
36
"vitest": "^3.2.4"
+2
-2
packages/site/src/App.tsx
···
3
3
4
4
export function App() {
5
5
return (
6
6
-
<>
6
6
+
<div className="flex flex-col min-h-screen w-full bg-white dark:bg-gray-900 text-gray-700 dark:text-gray-200">
7
7
<Header />
8
8
<Playground />
9
9
-
</>
9
9
+
</div>
10
10
);
11
11
}
+6
-31
packages/site/src/components/Editor.tsx
···
83
83
84
84
if (!isReady) {
85
85
return (
86
86
-
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
87
87
-
<div
88
88
-
style={{
89
89
-
padding: "0.75rem 1rem",
90
90
-
backgroundColor: "var(--color-bg-secondary)",
91
91
-
borderBottom: "1px solid var(--color-border)",
92
92
-
fontSize: "0.875rem",
93
93
-
fontWeight: "600",
94
94
-
color: "var(--color-text-secondary)",
95
95
-
}}
96
96
-
>
86
86
+
<div className="flex-1 flex flex-col">
87
87
+
<div className="py-3 px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-500 dark:text-gray-400">
97
88
Input
98
89
</div>
99
99
-
<div
100
100
-
style={{
101
101
-
flex: 1,
102
102
-
display: "flex",
103
103
-
alignItems: "center",
104
104
-
justifyContent: "center",
105
105
-
}}
106
106
-
>
90
90
+
<div className="flex-1 flex items-center justify-center">
107
91
Loading...
108
92
</div>
109
93
</div>
···
111
95
}
112
96
113
97
return (
114
114
-
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
115
115
-
<div
116
116
-
style={{
117
117
-
padding: "0.75rem 1rem",
118
118
-
backgroundColor: "var(--color-bg-secondary)",
119
119
-
borderBottom: "1px solid var(--color-border)",
120
120
-
fontSize: "0.875rem",
121
121
-
fontWeight: "600",
122
122
-
color: "var(--color-text-secondary)",
123
123
-
}}
124
124
-
>
98
98
+
<div className="flex-1 flex flex-col">
99
99
+
<div className="py-3 px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-500 dark:text-gray-400">
125
100
Input
126
101
</div>
127
127
-
<div style={{ flex: 1 }}>
102
102
+
<div className="flex-1">
128
103
<MonacoEditor
129
104
height="100%"
130
105
defaultLanguage="typescript"
+15
-88
packages/site/src/components/Header.tsx
···
12
12
href={href}
13
13
target="_blank"
14
14
rel="noopener noreferrer"
15
15
-
style={{
16
16
-
color: "var(--color-text-heading)",
17
17
-
textDecoration: "none",
18
18
-
fontSize: "1rem",
19
19
-
fontWeight: "600",
20
20
-
display: "flex",
21
21
-
alignItems: "center",
22
22
-
gap: "0.5rem",
23
23
-
transition: "opacity 0.2s",
24
24
-
willChange: "opacity",
25
25
-
}}
26
26
-
onMouseEnter={(e) => (e.currentTarget.style.opacity = "0.6")}
27
27
-
onMouseLeave={(e) => (e.currentTarget.style.opacity = "1")}
15
15
+
className="text-gray-900 dark:text-gray-100 no-underline text-base font-semibold flex items-center gap-2 transition-opacity duration-200 hover:opacity-60"
28
16
>
29
17
{icon}
30
18
{label}
···
48
36
};
49
37
50
38
return (
51
51
-
<header
52
52
-
style={{
53
53
-
padding: "2rem 2rem 1rem 2rem",
54
54
-
borderBottom: "1px solid var(--color-border)",
55
55
-
}}
56
56
-
>
57
57
-
<div style={{ maxWidth: "1400px", margin: "0 auto" }}>
58
58
-
<div className="header-content">
39
39
+
<header className="py-8 px-8 pb-4 border-b border-gray-200 dark:border-gray-700">
40
40
+
<div className="max-w-[1400px] mx-auto">
41
41
+
<div className="flex justify-between items-start flex-col md:flex-row gap-4 md:gap-0">
59
42
<div>
60
60
-
<h1
61
61
-
style={{
62
62
-
fontSize: "2.5rem",
63
63
-
fontWeight: "700",
64
64
-
marginBottom: "0.5rem",
65
65
-
}}
66
66
-
>
67
67
-
<span style={{ color: "var(--color-text-secondary)" }}>
68
68
-
at://
69
69
-
</span>
43
43
+
<h1 className="text-4xl font-bold mb-2">
44
44
+
<span className="text-gray-500 dark:text-gray-400">at://</span>
70
45
prototypey
71
46
</h1>
72
72
-
<p
73
73
-
style={{
74
74
-
fontSize: "1.125rem",
75
75
-
color: "var(--color-text-secondary)",
76
76
-
marginTop: "0.5rem",
77
77
-
}}
78
78
-
>
47
47
+
<p className="text-lg text-gray-500 dark:text-gray-400 mt-2">
79
48
ATProto lexicon typescript toolkit
80
49
</p>
81
50
</div>
82
82
-
<div
83
83
-
className="link-container"
84
84
-
style={{
85
85
-
display: "flex",
86
86
-
flexDirection: "column",
87
87
-
alignItems: "flex-end",
88
88
-
gap: "1rem",
89
89
-
}}
90
90
-
>
91
91
-
<div className="header-links">
51
51
+
<div className="flex flex-col items-end gap-4 w-full md:w-auto">
52
52
+
<div className="flex gap-5 pt-2 md:pt-0 w-full md:w-auto justify-start">
92
53
<HeaderLink
93
54
href="https://github.com/tylersayshi/prototypey?tab=readme-ov-file#prototypey"
94
55
icon={
···
98
59
viewBox="0 0 24 24"
99
60
fill="currentColor"
100
61
aria-hidden="true"
101
101
-
style={{ flexShrink: 0 }}
62
62
+
className="shrink-0"
102
63
>
103
64
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
104
65
</svg>
···
118
79
strokeLinecap="round"
119
80
strokeLinejoin="round"
120
81
aria-hidden="true"
121
121
-
style={{ flexShrink: 0 }}
82
82
+
className="shrink-0"
122
83
>
123
84
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
124
85
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
···
140
101
strokeLinecap="round"
141
102
strokeLinejoin="round"
142
103
aria-hidden="true"
143
143
-
style={{ flexShrink: 0 }}
104
104
+
className="shrink-0"
144
105
>
145
106
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
146
107
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
···
151
112
</div>
152
113
<button
153
114
onClick={handleShare}
154
154
-
style={{
155
155
-
color: "var(--color-text-heading)",
156
156
-
fontSize: "0.875rem",
157
157
-
fontWeight: "600",
158
158
-
display: "flex",
159
159
-
alignItems: "center",
160
160
-
gap: "0.5rem",
161
161
-
transition: "background-color 0.2s, border-color 0.2s",
162
162
-
backgroundColor: "transparent",
163
163
-
border: "1px solid var(--color-border)",
164
164
-
borderRadius: "0.5rem",
165
165
-
cursor: "pointer",
166
166
-
padding: "0.5rem 1rem",
167
167
-
boxShadow: "none",
168
168
-
outline: "none",
169
169
-
flexShrink: 0,
170
170
-
whiteSpace: "nowrap",
171
171
-
}}
172
172
-
onMouseEnter={(e) => {
173
173
-
const bgColor = getComputedStyle(document.documentElement)
174
174
-
.getPropertyValue("--color-bg-secondary")
175
175
-
.trim();
176
176
-
const borderColor = getComputedStyle(document.documentElement)
177
177
-
.getPropertyValue("--color-text-heading")
178
178
-
.trim();
179
179
-
e.currentTarget.style.backgroundColor = bgColor;
180
180
-
e.currentTarget.style.borderColor = borderColor;
181
181
-
}}
182
182
-
onMouseLeave={(e) => {
183
183
-
e.currentTarget.style.backgroundColor = "transparent";
184
184
-
const borderColor = getComputedStyle(document.documentElement)
185
185
-
.getPropertyValue("--color-border")
186
186
-
.trim();
187
187
-
e.currentTarget.style.borderColor = borderColor;
188
188
-
}}
115
115
+
className="text-gray-900 dark:text-gray-100 text-sm font-semibold flex items-center gap-2 transition-all duration-200 bg-transparent border border-gray-200 dark:border-gray-700 rounded-lg cursor-pointer py-2 px-4 shadow-none outline-none shrink-0 whitespace-nowrap hover:bg-gray-50 dark:hover:bg-gray-800 hover:border-gray-900 dark:hover:border-gray-100"
189
116
aria-label="share playground"
190
117
>
191
118
{copied ? (
···
200
127
strokeLinecap="round"
201
128
strokeLinejoin="round"
202
129
aria-hidden="true"
203
203
-
style={{ flexShrink: 0 }}
130
130
+
className="shrink-0"
204
131
>
205
132
<polyline points="20 6 9 17 4 12" />
206
133
</svg>
···
218
145
strokeLinecap="round"
219
146
strokeLinejoin="round"
220
147
aria-hidden="true"
221
221
-
style={{ flexShrink: 0 }}
148
148
+
className="shrink-0"
222
149
>
223
150
<circle cx="18" cy="5" r="3" />
224
151
<circle cx="6" cy="12" r="3" />
+4
-21
packages/site/src/components/OutputPanel.tsx
···
27
27
}, []);
28
28
29
29
return (
30
30
-
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
31
31
-
<div
32
32
-
style={{
33
33
-
padding: "0.75rem 1rem",
34
34
-
backgroundColor: "var(--color-bg-secondary)",
35
35
-
borderBottom: "1px solid var(--color-border)",
36
36
-
fontSize: "0.875rem",
37
37
-
fontWeight: "600",
38
38
-
color: "var(--color-text-secondary)",
39
39
-
}}
40
40
-
>
30
30
+
<div className="flex-1 flex flex-col">
31
31
+
<div className="py-3 px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-500 dark:text-gray-400">
41
32
Output
42
33
</div>
43
43
-
<div style={{ flex: 1 }}>
34
34
+
<div className="flex-1">
44
35
{output.error ? (
45
45
-
<div
46
46
-
style={{
47
47
-
padding: "1rem",
48
48
-
color: "var(--color-error)",
49
49
-
backgroundColor: "var(--color-error-bg)",
50
50
-
height: "100%",
51
51
-
overflow: "auto",
52
52
-
}}
53
53
-
>
36
36
+
<div className="p-4 text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950 h-full overflow-auto">
54
37
<strong>Error:</strong> {output.error}
55
38
</div>
56
39
) : (
+12
-80
packages/site/src/components/Playground.tsx
···
112
112
return (
113
113
<>
114
114
{/* Desktop playground */}
115
115
-
<div
116
116
-
className="desktop-only"
117
117
-
style={{
118
118
-
flex: 1,
119
119
-
overflow: "hidden",
120
120
-
}}
121
121
-
>
122
122
-
<div
123
123
-
style={{
124
124
-
flex: 1,
125
125
-
display: "flex",
126
126
-
borderRight: "1px solid var(--color-border)",
127
127
-
}}
128
128
-
>
115
115
+
<div className="hidden md:flex flex-1 overflow-hidden">
116
116
+
<div className="flex-1 flex border-r border-gray-200 dark:border-gray-700">
129
117
<Editor
130
118
value={code}
131
119
onChange={handleCodeChange}
132
120
onReady={handleEditorReady}
133
121
/>
134
122
</div>
135
135
-
<div style={{ flex: 1, display: "flex" }}>
123
123
+
<div className="flex-1 flex">
136
124
<OutputPanel output={output} />
137
125
</div>
138
126
</div>
139
127
140
128
{/* Mobile static demo */}
141
141
-
<div
142
142
-
className="mobile-only"
143
143
-
style={{
144
144
-
flex: 1,
145
145
-
flexDirection: "column",
146
146
-
overflow: "auto",
147
147
-
padding: "1rem",
148
148
-
}}
149
149
-
>
150
150
-
<div
151
151
-
style={{
152
152
-
backgroundColor: "var(--color-bg-secondary)",
153
153
-
padding: "1rem",
154
154
-
borderRadius: "0.5rem",
155
155
-
marginBottom: "1rem",
156
156
-
textAlign: "center",
157
157
-
color: "var(--color-text-secondary)",
158
158
-
fontSize: "0.875rem",
159
159
-
}}
160
160
-
>
129
129
+
<div className="flex md:hidden flex-1 flex-col overflow-auto p-4">
130
130
+
<div className="bg-gray-50 dark:bg-gray-800 p-4 rounded-lg mb-4 text-center text-gray-500 dark:text-gray-400 text-sm">
161
131
Playground available on desktop
162
132
</div>
163
133
···
190
160
const jsonWrappedLines = estimateWrappedLines(json, 50);
191
161
192
162
return (
193
193
-
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
163
163
+
<div className="flex flex-col gap-4">
194
164
{/* You write section */}
195
195
-
<div style={{ display: "flex", flexDirection: "column" }}>
196
196
-
<div
197
197
-
style={{
198
198
-
padding: "0.75rem 1rem",
199
199
-
backgroundColor: "var(--color-bg-secondary)",
200
200
-
borderBottom: "1px solid var(--color-border)",
201
201
-
fontSize: "0.875rem",
202
202
-
fontWeight: "600",
203
203
-
color: "var(--color-text-secondary)",
204
204
-
borderTopLeftRadius: "0.5rem",
205
205
-
borderTopRightRadius: "0.5rem",
206
206
-
}}
207
207
-
>
165
165
+
<div className="flex flex-col">
166
166
+
<div className="py-3 px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-500 dark:text-gray-400 rounded-t-lg">
208
167
You write
209
168
</div>
210
210
-
<div
211
211
-
style={{
212
212
-
border: "1px solid var(--color-border)",
213
213
-
borderTop: "none",
214
214
-
borderBottomLeftRadius: "0.5rem",
215
215
-
borderBottomRightRadius: "0.5rem",
216
216
-
overflow: "hidden",
217
217
-
}}
218
218
-
>
169
169
+
<div className="border border-gray-200 dark:border-gray-700 border-t-0 rounded-b-lg overflow-hidden">
219
170
<MonacoEditor
220
171
height={`${String(codeWrappedLines * 18 + 32)}px`}
221
172
defaultLanguage="typescript"
···
244
195
</div>
245
196
246
197
{/* JSON generated section */}
247
247
-
<div style={{ display: "flex", flexDirection: "column" }}>
248
248
-
<div
249
249
-
style={{
250
250
-
padding: "0.75rem 1rem",
251
251
-
backgroundColor: "var(--color-bg-secondary)",
252
252
-
borderBottom: "1px solid var(--color-border)",
253
253
-
fontSize: "0.875rem",
254
254
-
fontWeight: "600",
255
255
-
color: "var(--color-text-secondary)",
256
256
-
borderTopLeftRadius: "0.5rem",
257
257
-
borderTopRightRadius: "0.5rem",
258
258
-
}}
259
259
-
>
198
198
+
<div className="flex flex-col">
199
199
+
<div className="py-3 px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-500 dark:text-gray-400 rounded-t-lg">
260
200
JSON generated
261
201
</div>
262
262
-
<div
263
263
-
style={{
264
264
-
border: "1px solid var(--color-border)",
265
265
-
borderTop: "none",
266
266
-
borderBottomLeftRadius: "0.5rem",
267
267
-
borderBottomRightRadius: "0.5rem",
268
268
-
overflow: "hidden",
269
269
-
}}
270
270
-
>
202
202
+
<div className="border border-gray-200 dark:border-gray-700 border-t-0 rounded-b-lg overflow-hidden">
271
203
<MonacoEditor
272
204
height={`${String(jsonWrappedLines * 18 + 32)}px`}
273
205
defaultLanguage="json"
+2
-129
packages/site/src/index.css
···
1
1
-
/*
2
2
-
Josh's Custom CSS Reset
3
3
-
https://www.joshwcomeau.com/css/custom-css-reset/
4
4
-
*/
5
5
-
*,
6
6
-
*::before,
7
7
-
*::after {
8
8
-
box-sizing: border-box;
9
9
-
}
10
10
-
11
11
-
* {
12
12
-
margin: 0;
13
13
-
}
14
14
-
15
15
-
body {
16
16
-
line-height: 1.5;
17
17
-
-webkit-font-smoothing: antialiased;
18
18
-
}
19
19
-
20
20
-
img,
21
21
-
picture,
22
22
-
video,
23
23
-
canvas,
24
24
-
svg {
25
25
-
display: block;
26
26
-
max-width: 100%;
27
27
-
}
28
28
-
29
29
-
input,
30
30
-
button,
31
31
-
textarea,
32
32
-
select {
33
33
-
font: inherit;
34
34
-
}
35
35
-
36
36
-
p,
37
37
-
h1,
38
38
-
h2,
39
39
-
h3,
40
40
-
h4,
41
41
-
h5,
42
42
-
h6 {
43
43
-
overflow-wrap: break-word;
44
44
-
}
45
45
-
46
46
-
#root {
47
47
-
isolation: isolate;
48
48
-
}
1
1
+
@import "tailwindcss";
49
2
50
3
:root {
51
4
font-family:
52
5
-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
53
6
"Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
54
54
-
line-height: 1.5;
55
55
-
font-weight: 400;
56
7
font-synthesis: none;
57
8
text-rendering: optimizeLegibility;
58
9
-webkit-font-smoothing: antialiased;
59
10
-moz-osx-font-smoothing: grayscale;
60
60
-
61
61
-
--color-text: #213547;
62
62
-
--color-text-secondary: #6b7280;
63
63
-
--color-text-heading: #111827;
64
64
-
--color-bg: #ffffff;
65
65
-
--color-bg-secondary: #f9fafb;
66
66
-
--color-border: #e5e7eb;
67
67
-
--color-error: #dc2626;
68
68
-
--color-error-bg: #fef2f2;
69
69
-
70
70
-
color: var(--color-text);
71
71
-
background-color: var(--color-bg);
72
72
-
}
73
73
-
74
74
-
@media (prefers-color-scheme: dark) {
75
75
-
:root {
76
76
-
--color-text: #e5e7eb;
77
77
-
--color-text-secondary: #9ca3af;
78
78
-
--color-text-heading: #f9fafb;
79
79
-
--color-bg: #111827;
80
80
-
--color-bg-secondary: #1f2937;
81
81
-
--color-border: #374151;
82
82
-
--color-error: #f87171;
83
83
-
--color-error-bg: #3f1f1f;
84
84
-
}
85
11
}
86
12
87
13
body {
88
88
-
display: flex;
89
14
min-width: 320px;
90
15
min-height: 100vh;
91
16
}
92
17
93
18
#root {
94
94
-
width: 100%;
95
95
-
display: flex;
96
96
-
flex-direction: column;
97
97
-
}
98
98
-
99
99
-
/* Desktop layout - default */
100
100
-
.header-content {
101
101
-
display: flex;
102
102
-
justify-content: space-between;
103
103
-
align-items: flex-start;
104
104
-
}
105
105
-
106
106
-
.header-links {
107
107
-
display: flex;
108
108
-
gap: 1.25rem;
109
109
-
padding-top: 0.5rem;
110
110
-
}
111
111
-
112
112
-
.mobile-only {
113
113
-
display: none;
114
114
-
}
115
115
-
116
116
-
.desktop-only {
117
117
-
display: flex;
118
118
-
}
119
119
-
120
120
-
/* Mobile layout */
121
121
-
@media (max-width: 768px) {
122
122
-
.header-content {
123
123
-
flex-direction: column;
124
124
-
gap: 1rem;
125
125
-
}
126
126
-
127
127
-
.header-links {
128
128
-
padding-top: 0;
129
129
-
width: 100%;
130
130
-
justify-content: flex-start;
131
131
-
}
132
132
-
133
133
-
.mobile-only {
134
134
-
display: flex !important;
135
135
-
flex-direction: column;
136
136
-
}
137
137
-
138
138
-
.desktop-only {
139
139
-
display: none !important;
140
140
-
}
141
141
-
142
142
-
.link-container {
143
143
-
width: 100%;
144
144
-
flex-direction: row !important;
145
145
-
justify-content: space-between;
146
146
-
}
19
19
+
isolation: isolate;
147
20
}
+2
packages/site/vite.config.ts
···
1
1
import { defineConfig } from "vite";
2
2
import react from "@vitejs/plugin-react";
3
3
+
import tailwindcss from "@tailwindcss/vite";
3
4
4
5
export default defineConfig({
5
6
plugins: [
7
7
+
tailwindcss(),
6
8
react({
7
9
babel: {
8
10
plugins: [["babel-plugin-react-compiler", {}]],
+191
pnpm-lock.yaml
···
82
82
specifier: ^19.2.0
83
83
version: 19.2.0(react@19.2.0)
84
84
devDependencies:
85
85
+
'@tailwindcss/vite':
86
86
+
specifier: ^4.1.17
87
87
+
version: 4.1.17(rolldown-vite@7.0.6(@types/node@24.0.4)(esbuild@0.25.10)(jiti@2.6.1))
85
88
'@testing-library/jest-dom':
86
89
specifier: ^6.9.1
87
90
version: 6.9.1
···
109
112
jsdom:
110
113
specifier: ^25.0.1
111
114
version: 25.0.1
115
115
+
tailwindcss:
116
116
+
specifier: ^4.1.17
117
117
+
version: 4.1.17
112
118
typescript:
113
119
specifier: 5.8.3
114
120
version: 5.8.3
···
890
896
891
897
'@standard-schema/spec@1.0.0':
892
898
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
899
899
+
900
900
+
'@tailwindcss/node@4.1.17':
901
901
+
resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==}
902
902
+
903
903
+
'@tailwindcss/oxide-android-arm64@4.1.17':
904
904
+
resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==}
905
905
+
engines: {node: '>= 10'}
906
906
+
cpu: [arm64]
907
907
+
os: [android]
908
908
+
909
909
+
'@tailwindcss/oxide-darwin-arm64@4.1.17':
910
910
+
resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==}
911
911
+
engines: {node: '>= 10'}
912
912
+
cpu: [arm64]
913
913
+
os: [darwin]
914
914
+
915
915
+
'@tailwindcss/oxide-darwin-x64@4.1.17':
916
916
+
resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==}
917
917
+
engines: {node: '>= 10'}
918
918
+
cpu: [x64]
919
919
+
os: [darwin]
920
920
+
921
921
+
'@tailwindcss/oxide-freebsd-x64@4.1.17':
922
922
+
resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==}
923
923
+
engines: {node: '>= 10'}
924
924
+
cpu: [x64]
925
925
+
os: [freebsd]
926
926
+
927
927
+
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17':
928
928
+
resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==}
929
929
+
engines: {node: '>= 10'}
930
930
+
cpu: [arm]
931
931
+
os: [linux]
932
932
+
933
933
+
'@tailwindcss/oxide-linux-arm64-gnu@4.1.17':
934
934
+
resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==}
935
935
+
engines: {node: '>= 10'}
936
936
+
cpu: [arm64]
937
937
+
os: [linux]
938
938
+
939
939
+
'@tailwindcss/oxide-linux-arm64-musl@4.1.17':
940
940
+
resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==}
941
941
+
engines: {node: '>= 10'}
942
942
+
cpu: [arm64]
943
943
+
os: [linux]
944
944
+
945
945
+
'@tailwindcss/oxide-linux-x64-gnu@4.1.17':
946
946
+
resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==}
947
947
+
engines: {node: '>= 10'}
948
948
+
cpu: [x64]
949
949
+
os: [linux]
950
950
+
951
951
+
'@tailwindcss/oxide-linux-x64-musl@4.1.17':
952
952
+
resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==}
953
953
+
engines: {node: '>= 10'}
954
954
+
cpu: [x64]
955
955
+
os: [linux]
956
956
+
957
957
+
'@tailwindcss/oxide-wasm32-wasi@4.1.17':
958
958
+
resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==}
959
959
+
engines: {node: '>=14.0.0'}
960
960
+
cpu: [wasm32]
961
961
+
bundledDependencies:
962
962
+
- '@napi-rs/wasm-runtime'
963
963
+
- '@emnapi/core'
964
964
+
- '@emnapi/runtime'
965
965
+
- '@tybys/wasm-util'
966
966
+
- '@emnapi/wasi-threads'
967
967
+
- tslib
968
968
+
969
969
+
'@tailwindcss/oxide-win32-arm64-msvc@4.1.17':
970
970
+
resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==}
971
971
+
engines: {node: '>= 10'}
972
972
+
cpu: [arm64]
973
973
+
os: [win32]
974
974
+
975
975
+
'@tailwindcss/oxide-win32-x64-msvc@4.1.17':
976
976
+
resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==}
977
977
+
engines: {node: '>= 10'}
978
978
+
cpu: [x64]
979
979
+
os: [win32]
980
980
+
981
981
+
'@tailwindcss/oxide@4.1.17':
982
982
+
resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==}
983
983
+
engines: {node: '>= 10'}
984
984
+
985
985
+
'@tailwindcss/vite@4.1.17':
986
986
+
resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==}
987
987
+
peerDependencies:
988
988
+
vite: ^5.2.0 || ^6 || ^7
893
989
894
990
'@testing-library/dom@10.4.1':
895
991
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
···
1314
1410
resolution: {integrity: sha512-rsPft6CK3eHtrlp9Y5ALBb+hfK+DWnA4WFebbazxjWyx8vSm3rZeoM3z9irsjcqO3PYRzlfv27XIB4tz2DV7RA==}
1315
1411
engines: {node: '>=14'}
1316
1412
1413
1413
+
enhanced-resolve@5.18.3:
1414
1414
+
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
1415
1415
+
engines: {node: '>=10.13.0'}
1416
1416
+
1317
1417
enquirer@2.4.1:
1318
1418
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
1319
1419
engines: {node: '>=8.6'}
···
1820
1920
magic-string@0.30.19:
1821
1921
resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
1822
1922
1923
1923
+
magic-string@0.30.21:
1924
1924
+
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
1925
1925
+
1823
1926
make-synchronized@0.4.2:
1824
1927
resolution: {integrity: sha512-EwEJSg8gSGLicKXp/VzNi1tvzhdmNBxOzslkkJSoNUCQFZKH/NIUIp7xlfN+noaHrz4BJDN73gne8IHnjl/F/A==}
1825
1928
···
2255
2358
2256
2359
symbol-tree@3.2.4:
2257
2360
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
2361
2361
+
2362
2362
+
tailwindcss@4.1.17:
2363
2363
+
resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==}
2364
2364
+
2365
2365
+
tapable@2.3.0:
2366
2366
+
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
2367
2367
+
engines: {node: '>=6'}
2258
2368
2259
2369
term-size@2.2.1:
2260
2370
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
···
3282
3392
3283
3393
'@standard-schema/spec@1.0.0': {}
3284
3394
3395
3395
+
'@tailwindcss/node@4.1.17':
3396
3396
+
dependencies:
3397
3397
+
'@jridgewell/remapping': 2.3.5
3398
3398
+
enhanced-resolve: 5.18.3
3399
3399
+
jiti: 2.6.1
3400
3400
+
lightningcss: 1.30.2
3401
3401
+
magic-string: 0.30.21
3402
3402
+
source-map-js: 1.2.1
3403
3403
+
tailwindcss: 4.1.17
3404
3404
+
3405
3405
+
'@tailwindcss/oxide-android-arm64@4.1.17':
3406
3406
+
optional: true
3407
3407
+
3408
3408
+
'@tailwindcss/oxide-darwin-arm64@4.1.17':
3409
3409
+
optional: true
3410
3410
+
3411
3411
+
'@tailwindcss/oxide-darwin-x64@4.1.17':
3412
3412
+
optional: true
3413
3413
+
3414
3414
+
'@tailwindcss/oxide-freebsd-x64@4.1.17':
3415
3415
+
optional: true
3416
3416
+
3417
3417
+
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17':
3418
3418
+
optional: true
3419
3419
+
3420
3420
+
'@tailwindcss/oxide-linux-arm64-gnu@4.1.17':
3421
3421
+
optional: true
3422
3422
+
3423
3423
+
'@tailwindcss/oxide-linux-arm64-musl@4.1.17':
3424
3424
+
optional: true
3425
3425
+
3426
3426
+
'@tailwindcss/oxide-linux-x64-gnu@4.1.17':
3427
3427
+
optional: true
3428
3428
+
3429
3429
+
'@tailwindcss/oxide-linux-x64-musl@4.1.17':
3430
3430
+
optional: true
3431
3431
+
3432
3432
+
'@tailwindcss/oxide-wasm32-wasi@4.1.17':
3433
3433
+
optional: true
3434
3434
+
3435
3435
+
'@tailwindcss/oxide-win32-arm64-msvc@4.1.17':
3436
3436
+
optional: true
3437
3437
+
3438
3438
+
'@tailwindcss/oxide-win32-x64-msvc@4.1.17':
3439
3439
+
optional: true
3440
3440
+
3441
3441
+
'@tailwindcss/oxide@4.1.17':
3442
3442
+
optionalDependencies:
3443
3443
+
'@tailwindcss/oxide-android-arm64': 4.1.17
3444
3444
+
'@tailwindcss/oxide-darwin-arm64': 4.1.17
3445
3445
+
'@tailwindcss/oxide-darwin-x64': 4.1.17
3446
3446
+
'@tailwindcss/oxide-freebsd-x64': 4.1.17
3447
3447
+
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17
3448
3448
+
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.17
3449
3449
+
'@tailwindcss/oxide-linux-arm64-musl': 4.1.17
3450
3450
+
'@tailwindcss/oxide-linux-x64-gnu': 4.1.17
3451
3451
+
'@tailwindcss/oxide-linux-x64-musl': 4.1.17
3452
3452
+
'@tailwindcss/oxide-wasm32-wasi': 4.1.17
3453
3453
+
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.17
3454
3454
+
'@tailwindcss/oxide-win32-x64-msvc': 4.1.17
3455
3455
+
3456
3456
+
'@tailwindcss/vite@4.1.17(rolldown-vite@7.0.6(@types/node@24.0.4)(esbuild@0.25.10)(jiti@2.6.1))':
3457
3457
+
dependencies:
3458
3458
+
'@tailwindcss/node': 4.1.17
3459
3459
+
'@tailwindcss/oxide': 4.1.17
3460
3460
+
tailwindcss: 4.1.17
3461
3461
+
vite: rolldown-vite@7.0.6(@types/node@24.0.4)(esbuild@0.25.10)(jiti@2.6.1)
3462
3462
+
3285
3463
'@testing-library/dom@10.4.1':
3286
3464
dependencies:
3287
3465
'@babel/code-frame': 7.27.1
···
3740
3918
3741
3919
empathic@1.1.0: {}
3742
3920
3921
3921
+
enhanced-resolve@5.18.3:
3922
3922
+
dependencies:
3923
3923
+
graceful-fs: 4.2.11
3924
3924
+
tapable: 2.3.0
3925
3925
+
3743
3926
enquirer@2.4.1:
3744
3927
dependencies:
3745
3928
ansi-colors: 4.1.3
···
4272
4455
dependencies:
4273
4456
'@jridgewell/sourcemap-codec': 1.5.5
4274
4457
4458
4458
+
magic-string@0.30.21:
4459
4459
+
dependencies:
4460
4460
+
'@jridgewell/sourcemap-codec': 1.5.5
4461
4461
+
4275
4462
make-synchronized@0.4.2: {}
4276
4463
4277
4464
math-intrinsics@1.1.0: {}
···
4640
4827
has-flag: 4.0.0
4641
4828
4642
4829
symbol-tree@3.2.4: {}
4830
4830
+
4831
4831
+
tailwindcss@4.1.17: {}
4832
4832
+
4833
4833
+
tapable@2.3.0: {}
4643
4834
4644
4835
term-size@2.2.1: {}
4645
4836