@linktr.ee/linkapp 0.0.22 → 0.0.24

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 (76) hide show
  1. package/dev-server/README.md +5 -5
  2. package/dev-server/{vite-env.d.ts → env.d.ts} +1 -1
  3. package/dev-server/featured/main.tsx +32 -311
  4. package/dev-server/package.json +5 -6
  5. package/dev-server/postcss/tailwind-source-fallback.js +94 -0
  6. package/dev-server/postcss.config.mjs +28 -3
  7. package/dev-server/preview/Preview.tsx +114 -339
  8. package/dev-server/preview/preview.css +3 -0
  9. package/dev-server/rsbuild.config.ts +45 -0
  10. package/dev-server/shared/theme-presets.ts +315 -0
  11. package/dev-server/shared/theme-utils.ts +38 -0
  12. package/dev-server/sheet/main.tsx +44 -0
  13. package/dev-server/{classic.html → sheet.html} +2 -2
  14. package/dist/commands/add.d.ts.map +1 -1
  15. package/dist/commands/add.js +20 -12
  16. package/dist/commands/add.js.map +1 -1
  17. package/dist/commands/build.d.ts.map +1 -1
  18. package/dist/commands/build.js +55 -36
  19. package/dist/commands/build.js.map +1 -1
  20. package/dist/commands/deploy.d.ts.map +1 -1
  21. package/dist/commands/deploy.js +58 -45
  22. package/dist/commands/deploy.js.map +1 -1
  23. package/dist/commands/dev.d.ts.map +1 -1
  24. package/dist/commands/dev.js +541 -128
  25. package/dist/commands/dev.js.map +1 -1
  26. package/dist/commands/login.d.ts.map +1 -1
  27. package/dist/commands/login.js +19 -9
  28. package/dist/commands/login.js.map +1 -1
  29. package/dist/commands/logout.d.ts.map +1 -1
  30. package/dist/commands/logout.js +9 -4
  31. package/dist/commands/logout.js.map +1 -1
  32. package/dist/commands/test-url-match-rules.d.ts.map +1 -1
  33. package/dist/commands/test-url-match-rules.js +24 -13
  34. package/dist/commands/test-url-match-rules.js.map +1 -1
  35. package/dist/lib/build/detect-layouts.d.ts +1 -1
  36. package/dist/lib/build/detect-layouts.d.ts.map +1 -1
  37. package/dist/lib/build/detect-layouts.js +8 -7
  38. package/dist/lib/build/detect-layouts.js.map +1 -1
  39. package/dist/lib/deploy/pack-project.js +1 -1
  40. package/dist/lib/deploy/pack-project.js.map +1 -1
  41. package/dist/lib/deploy/validation.d.ts.map +1 -1
  42. package/dist/lib/deploy/validation.js +8 -5
  43. package/dist/lib/deploy/validation.js.map +1 -1
  44. package/dist/lib/rsbuild/config-factory.d.ts +24 -0
  45. package/dist/lib/rsbuild/config-factory.d.ts.map +1 -0
  46. package/dist/lib/rsbuild/config-factory.js +135 -0
  47. package/dist/lib/rsbuild/config-factory.js.map +1 -0
  48. package/dist/lib/rsbuild/plugins/asset-versioning.d.ts +11 -0
  49. package/dist/lib/rsbuild/plugins/asset-versioning.d.ts.map +1 -0
  50. package/dist/lib/rsbuild/plugins/asset-versioning.js +62 -0
  51. package/dist/lib/rsbuild/plugins/asset-versioning.js.map +1 -0
  52. package/dist/lib/rsbuild/plugins/copy-public.d.ts +11 -0
  53. package/dist/lib/rsbuild/plugins/copy-public.d.ts.map +1 -0
  54. package/dist/lib/rsbuild/plugins/copy-public.js +32 -0
  55. package/dist/lib/rsbuild/plugins/copy-public.js.map +1 -0
  56. package/dist/lib/rsbuild/postcss/tailwind-source-fallback.d.ts +12 -0
  57. package/dist/lib/rsbuild/postcss/tailwind-source-fallback.d.ts.map +1 -0
  58. package/dist/lib/rsbuild/postcss/tailwind-source-fallback.js +60 -0
  59. package/dist/lib/rsbuild/postcss/tailwind-source-fallback.js.map +1 -0
  60. package/dist/lib/utils/setup-runtime.d.ts.map +1 -1
  61. package/dist/lib/utils/setup-runtime.js +60 -26
  62. package/dist/lib/utils/setup-runtime.js.map +1 -1
  63. package/dist/lib/vite/config-factory.d.ts.map +1 -1
  64. package/dist/lib/vite/config-factory.js +5 -1
  65. package/dist/lib/vite/config-factory.js.map +1 -1
  66. package/dist/lib/vite/plugins/copy-public.d.ts +12 -0
  67. package/dist/lib/vite/plugins/copy-public.d.ts.map +1 -0
  68. package/dist/lib/vite/plugins/copy-public.js +31 -0
  69. package/dist/lib/vite/plugins/copy-public.js.map +1 -0
  70. package/dist/schema/config.schema.d.ts +18 -1
  71. package/dist/schema/config.schema.d.ts.map +1 -1
  72. package/dist/schema/config.schema.js +1 -0
  73. package/dist/schema/config.schema.js.map +1 -1
  74. package/package.json +7 -3
  75. package/dev-server/classic/main.tsx +0 -346
  76. package/dev-server/vite.config.ts +0 -34
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Theme presets for testing LinkApps in dev mode
3
+ * Based on actual CSS variables from live Linktree profiles
4
+ */
5
+ export const THEME_PRESETS = {
6
+ default: {
7
+ name: "Default (Light)",
8
+ variables: {
9
+ "--button-style-text": "#000000",
10
+ "--button-style-background": "#ffffff",
11
+ "--button-style-background-hover":
12
+ "color-mix(in srgb, #ffffff 93%, #000000 7%)",
13
+ "--button-style-border": "none",
14
+ "--button-style-border-color": "transparent",
15
+ "--button-style-shadow": "none",
16
+ "--button-style-shadow-color": "#000000",
17
+ "--button-style-contrast-color": "#000000",
18
+ "--button-style-radius": "8px",
19
+ "--button-style-inner-radius": "min(8px, max(4px, calc(8px - 8px)))",
20
+ "--button-style-skeleton-color": "rgba(0, 0, 0, 0.05)",
21
+ "--link-gap": "14px",
22
+ "--link-inner-padding": "7px",
23
+ "--link-preview-thumbnail-width": "160px",
24
+ "--linkRadius": "8px",
25
+ "--profile-container-desktop-width": "580px",
26
+ "--profileBackground": "#eceef1",
27
+ "--background-contrast-color": "#000000",
28
+ "--bodyText": "#000000",
29
+ "--profileTitleText": "#000000",
30
+ "--profileDescriptionText": "#000000",
31
+ "--defaultAvatarBackground": "#000000",
32
+ "--defaultAvatarText": "#ffffff",
33
+ "--socialLinkFill": "#000000",
34
+ "--linkBackground": "#ffffff",
35
+ "--linkText": "#000000",
36
+ "--linkHoverBackground": "color-mix(in srgb, #ffffff 93%, #000000 7%)",
37
+ "--linkHoverText": "#000000",
38
+ "--linkShadow": "#000000",
39
+ "--bannerBackground": "#ffffff",
40
+ "--bannerText": "#000000",
41
+ "--desktop-frame-color": "color-mix(in srgb, #eceef1 88%, black 12%)",
42
+ "--profileFontFamilyPrimary":
43
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
44
+ "--profileFontFamilySecondary":
45
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
46
+ "--header-font-family":
47
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
48
+ "--profileFontWeightNormal": "500",
49
+ "--profileFontWeightBold": "700",
50
+ "--profileDescriptionFontWeight": "500",
51
+ "--linkTextFontWeight": "500",
52
+ "--headerFontWeight": "700",
53
+ "--header-font-weight": "600",
54
+ "--embedLinkTextFontWeight": "500",
55
+ "--signupSubmitTextFontWeight": "700",
56
+ "--bannerFontWeight": "700",
57
+ "--headerFontSize": "normal",
58
+ "--header-bio-font-size": "16px",
59
+ "--embedLinkTextFontSize": "14px",
60
+ "--signupSubmitTextFontSize": "14px",
61
+ "--linkHeaderFontSize": "14px",
62
+ "--bannerFontSize": "14px",
63
+ "--profileDescriptionLineHeight": "1.5",
64
+ "--headerLineHeight": "1.5",
65
+ "--header-text-color": "#000000",
66
+ },
67
+ },
68
+ dark: {
69
+ name: "Dark",
70
+ variables: {
71
+ "--button-style-text": "#ffffff",
72
+ "--button-style-background": "#1f2937",
73
+ "--button-style-background-hover":
74
+ "color-mix(in srgb, #1f2937 93%, #ffffff 7%)",
75
+ "--button-style-border": "none",
76
+ "--button-style-border-color": "transparent",
77
+ "--button-style-shadow": "none",
78
+ "--button-style-shadow-color": "#000000",
79
+ "--button-style-contrast-color": "#ffffff",
80
+ "--button-style-radius": "8px",
81
+ "--button-style-inner-radius": "min(8px, max(4px, calc(8px - 8px)))",
82
+ "--button-style-skeleton-color": "rgba(255, 255, 255, 0.1)",
83
+ "--link-gap": "14px",
84
+ "--link-inner-padding": "7px",
85
+ "--link-preview-thumbnail-width": "160px",
86
+ "--linkRadius": "8px",
87
+ "--profile-container-desktop-width": "580px",
88
+ "--profileBackground": "#111827",
89
+ "--background-contrast-color": "#ffffff",
90
+ "--bodyText": "#ffffff",
91
+ "--profileTitleText": "#ffffff",
92
+ "--profileDescriptionText": "#ffffff",
93
+ "--defaultAvatarBackground": "#ffffff",
94
+ "--defaultAvatarText": "#000000",
95
+ "--socialLinkFill": "#ffffff",
96
+ "--linkBackground": "#1f2937",
97
+ "--linkText": "#ffffff",
98
+ "--linkHoverBackground": "color-mix(in srgb, #1f2937 93%, #ffffff 7%)",
99
+ "--linkHoverText": "#ffffff",
100
+ "--linkShadow": "#000000",
101
+ "--bannerBackground": "#1f2937",
102
+ "--bannerText": "#ffffff",
103
+ "--desktop-frame-color": "color-mix(in srgb, #111827 88%, white 12%)",
104
+ "--profileFontFamilyPrimary":
105
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
106
+ "--profileFontFamilySecondary":
107
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
108
+ "--header-font-family":
109
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
110
+ "--profileFontWeightNormal": "500",
111
+ "--profileFontWeightBold": "700",
112
+ "--profileDescriptionFontWeight": "500",
113
+ "--linkTextFontWeight": "500",
114
+ "--headerFontWeight": "700",
115
+ "--header-font-weight": "600",
116
+ "--embedLinkTextFontWeight": "500",
117
+ "--signupSubmitTextFontWeight": "700",
118
+ "--bannerFontWeight": "700",
119
+ "--headerFontSize": "normal",
120
+ "--header-bio-font-size": "16px",
121
+ "--embedLinkTextFontSize": "14px",
122
+ "--signupSubmitTextFontSize": "14px",
123
+ "--linkHeaderFontSize": "14px",
124
+ "--bannerFontSize": "14px",
125
+ "--profileDescriptionLineHeight": "1.5",
126
+ "--headerLineHeight": "1.5",
127
+ "--header-text-color": "#ffffff",
128
+ },
129
+ },
130
+ purple: {
131
+ name: "Purple",
132
+ variables: {
133
+ "--button-style-text": "#ffffff",
134
+ "--button-style-background": "#7c3aed",
135
+ "--button-style-background-hover":
136
+ "color-mix(in srgb, #7c3aed 93%, #ffffff 7%)",
137
+ "--button-style-border": "none",
138
+ "--button-style-border-color": "transparent",
139
+ "--button-style-shadow": "none",
140
+ "--button-style-shadow-color": "#000000",
141
+ "--button-style-contrast-color": "#ede9fe",
142
+ "--button-style-radius": "16px",
143
+ "--button-style-inner-radius": "min(16px, max(4px, calc(16px - 8px)))",
144
+ "--button-style-skeleton-color": "rgba(124, 58, 237, 0.1)",
145
+ "--link-gap": "14px",
146
+ "--link-inner-padding": "7px",
147
+ "--link-preview-thumbnail-width": "160px",
148
+ "--linkRadius": "16px",
149
+ "--profile-container-desktop-width": "580px",
150
+ "--profileBackground": "#faf5ff",
151
+ "--background-contrast-color": "#1f2937",
152
+ "--bodyText": "#1f2937",
153
+ "--profileTitleText": "#1f2937",
154
+ "--profileDescriptionText": "#1f2937",
155
+ "--defaultAvatarBackground": "#7c3aed",
156
+ "--defaultAvatarText": "#ffffff",
157
+ "--socialLinkFill": "#1f2937",
158
+ "--linkBackground": "#7c3aed",
159
+ "--linkText": "#ffffff",
160
+ "--linkHoverBackground": "color-mix(in srgb, #7c3aed 93%, #ffffff 7%)",
161
+ "--linkHoverText": "#ffffff",
162
+ "--linkShadow": "#7c3aed",
163
+ "--bannerBackground": "#7c3aed",
164
+ "--bannerText": "#ffffff",
165
+ "--desktop-frame-color": "color-mix(in srgb, #faf5ff 88%, black 12%)",
166
+ "--profileFontFamilyPrimary":
167
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
168
+ "--profileFontFamilySecondary":
169
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
170
+ "--header-font-family":
171
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
172
+ "--profileFontWeightNormal": "500",
173
+ "--profileFontWeightBold": "700",
174
+ "--profileDescriptionFontWeight": "500",
175
+ "--linkTextFontWeight": "500",
176
+ "--headerFontWeight": "700",
177
+ "--header-font-weight": "600",
178
+ "--embedLinkTextFontWeight": "500",
179
+ "--signupSubmitTextFontWeight": "700",
180
+ "--bannerFontWeight": "700",
181
+ "--headerFontSize": "normal",
182
+ "--header-bio-font-size": "16px",
183
+ "--embedLinkTextFontSize": "14px",
184
+ "--signupSubmitTextFontSize": "14px",
185
+ "--linkHeaderFontSize": "14px",
186
+ "--bannerFontSize": "14px",
187
+ "--profileDescriptionLineHeight": "1.5",
188
+ "--headerLineHeight": "1.5",
189
+ "--header-text-color": "#1f2937",
190
+ },
191
+ },
192
+ outline: {
193
+ name: "Outline Style",
194
+ variables: {
195
+ "--button-style-text": "#000000",
196
+ "--button-style-background": "transparent",
197
+ "--button-style-background-hover": "rgba(0, 0, 0, 0.05)",
198
+ "--button-style-border": "2px solid currentColor",
199
+ "--button-style-border-color": "#000000",
200
+ "--button-style-shadow": "none",
201
+ "--button-style-shadow-color": "#000000",
202
+ "--button-style-contrast-color": "#ffffff",
203
+ "--button-style-radius": "24px",
204
+ "--button-style-inner-radius": "min(24px, max(4px, calc(24px - 8px)))",
205
+ "--button-style-skeleton-color": "rgba(0, 0, 0, 0.05)",
206
+ "--link-gap": "14px",
207
+ "--link-inner-padding": "7px",
208
+ "--link-preview-thumbnail-width": "160px",
209
+ "--linkRadius": "24px",
210
+ "--profile-container-desktop-width": "580px",
211
+ "--profileBackground": "#ffffff",
212
+ "--background-contrast-color": "#000000",
213
+ "--bodyText": "#000000",
214
+ "--profileTitleText": "#000000",
215
+ "--profileDescriptionText": "#000000",
216
+ "--defaultAvatarBackground": "#000000",
217
+ "--defaultAvatarText": "#ffffff",
218
+ "--socialLinkFill": "#000000",
219
+ "--linkBackground": "transparent",
220
+ "--linkText": "#000000",
221
+ "--linkHoverBackground": "rgba(0, 0, 0, 0.05)",
222
+ "--linkHoverText": "#000000",
223
+ "--linkShadow": "#000000",
224
+ "--bannerBackground": "#ffffff",
225
+ "--bannerText": "#000000",
226
+ "--desktop-frame-color": "color-mix(in srgb, #ffffff 88%, black 12%)",
227
+ "--profileFontFamilyPrimary":
228
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
229
+ "--profileFontFamilySecondary":
230
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
231
+ "--header-font-family":
232
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
233
+ "--profileFontWeightNormal": "500",
234
+ "--profileFontWeightBold": "700",
235
+ "--profileDescriptionFontWeight": "500",
236
+ "--linkTextFontWeight": "500",
237
+ "--headerFontWeight": "700",
238
+ "--header-font-weight": "600",
239
+ "--embedLinkTextFontWeight": "500",
240
+ "--signupSubmitTextFontWeight": "700",
241
+ "--bannerFontWeight": "700",
242
+ "--headerFontSize": "normal",
243
+ "--header-bio-font-size": "16px",
244
+ "--embedLinkTextFontSize": "14px",
245
+ "--signupSubmitTextFontSize": "14px",
246
+ "--linkHeaderFontSize": "14px",
247
+ "--bannerFontSize": "14px",
248
+ "--profileDescriptionLineHeight": "1.5",
249
+ "--headerLineHeight": "1.5",
250
+ "--header-text-color": "#000000",
251
+ },
252
+ },
253
+ rounded: {
254
+ name: "Fully Rounded",
255
+ variables: {
256
+ "--button-style-text": "#ffffff",
257
+ "--button-style-background": "#059669",
258
+ "--button-style-background-hover":
259
+ "color-mix(in srgb, #059669 93%, #ffffff 7%)",
260
+ "--button-style-border": "none",
261
+ "--button-style-border-color": "transparent",
262
+ "--button-style-shadow": "none",
263
+ "--button-style-shadow-color": "#000000",
264
+ "--button-style-contrast-color": "#d1fae5",
265
+ "--button-style-radius": "28px",
266
+ "--button-style-inner-radius": "28px",
267
+ "--button-style-skeleton-color": "rgba(5, 150, 105, 0.1)",
268
+ "--link-gap": "14px",
269
+ "--link-inner-padding": "7px",
270
+ "--link-preview-thumbnail-width": "160px",
271
+ "--linkRadius": "28px",
272
+ "--profile-container-desktop-width": "580px",
273
+ "--profileBackground": "#ecfdf5",
274
+ "--background-contrast-color": "#1f2937",
275
+ "--bodyText": "#1f2937",
276
+ "--profileTitleText": "#1f2937",
277
+ "--profileDescriptionText": "#1f2937",
278
+ "--defaultAvatarBackground": "#059669",
279
+ "--defaultAvatarText": "#ffffff",
280
+ "--socialLinkFill": "#1f2937",
281
+ "--linkBackground": "#059669",
282
+ "--linkText": "#ffffff",
283
+ "--linkHoverBackground": "color-mix(in srgb, #059669 93%, #ffffff 7%)",
284
+ "--linkHoverText": "#ffffff",
285
+ "--linkShadow": "#059669",
286
+ "--bannerBackground": "#059669",
287
+ "--bannerText": "#ffffff",
288
+ "--desktop-frame-color": "color-mix(in srgb, #ecfdf5 88%, black 12%)",
289
+ "--profileFontFamilyPrimary":
290
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
291
+ "--profileFontFamilySecondary":
292
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
293
+ "--header-font-family":
294
+ 'Link Sans Product, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
295
+ "--profileFontWeightNormal": "500",
296
+ "--profileFontWeightBold": "700",
297
+ "--profileDescriptionFontWeight": "500",
298
+ "--linkTextFontWeight": "500",
299
+ "--headerFontWeight": "700",
300
+ "--header-font-weight": "600",
301
+ "--embedLinkTextFontWeight": "500",
302
+ "--signupSubmitTextFontWeight": "700",
303
+ "--bannerFontWeight": "700",
304
+ "--headerFontSize": "normal",
305
+ "--header-bio-font-size": "16px",
306
+ "--embedLinkTextFontSize": "14px",
307
+ "--signupSubmitTextFontSize": "14px",
308
+ "--linkHeaderFontSize": "14px",
309
+ "--bannerFontSize": "14px",
310
+ "--profileDescriptionLineHeight": "1.5",
311
+ "--headerLineHeight": "1.5",
312
+ "--header-text-color": "#1f2937",
313
+ },
314
+ },
315
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Utility functions for theme handling in dev mode
3
+ */
4
+
5
+ /**
6
+ * Merges theme CSS variables with preview props and creates a theme object
7
+ * compatible with the LinkApp runtime
8
+ */
9
+ export function mergeThemeProps(
10
+ themeVariables: Record<string, string>,
11
+ previewProps: Record<string, unknown> = {},
12
+ additionalProps: Record<string, unknown> = {}
13
+ ) {
14
+ return {
15
+ ...previewProps,
16
+ ...additionalProps,
17
+ theme: {
18
+ cssVariables: themeVariables,
19
+ // Legacy properties (deprecated) - derived from cssVariables
20
+ textColor: themeVariables["--button-style-text"] || "#000000",
21
+ backgroundColor: themeVariables["--button-style-background"] || "#ffffff",
22
+ borderRadius: themeVariables["--button-style-inner-radius"] || "12px",
23
+ borderColor: themeVariables["--button-style-border-color"] || "#e5e7eb",
24
+ backgroundHover: themeVariables["--button-style-background-hover"] || "#f3f4f6",
25
+ contrastColor: themeVariables["--button-style-contrast-color"] || "#ffffff",
26
+ textHoverColor: themeVariables["--linkHoverText"] || "#111827",
27
+ },
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Gets theme variables from URL parameters
33
+ */
34
+ export function getThemeFromUrl(presets: Record<string, Record<string, string>>): Record<string, string> {
35
+ const params = new URLSearchParams(window.location.search);
36
+ const themeParam = params.get('theme') || 'default';
37
+ return presets[themeParam] || presets.default;
38
+ }
@@ -0,0 +1,44 @@
1
+ import Sheet from "@/app/sheet";
2
+ import { StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import "@/app/globals.css";
5
+ import { THEME_PRESETS } from "../shared/theme-presets";
6
+ import { getThemeFromUrl, mergeThemeProps } from "../shared/theme-utils";
7
+
8
+ // Declare global window property for theme application
9
+ declare global {
10
+ interface Window {
11
+ __linkapp_applyTheme?: (variables: Record<string, string>) => void
12
+ }
13
+ }
14
+
15
+ // Preview props injected by dev server via Vite define
16
+ declare const __PREVIEW_PROPS__: Record<string, unknown>;
17
+
18
+ // Extract just the variables from THEME_PRESETS for theme lookups
19
+ const THEME_VARS = Object.fromEntries(
20
+ Object.entries(THEME_PRESETS).map(([key, { variables }]) => [key, variables])
21
+ );
22
+
23
+ // Get theme variables from URL
24
+ const themeVariables = getThemeFromUrl(THEME_VARS);
25
+
26
+ // Merge with preview props
27
+ const previewProps = __PREVIEW_PROPS__ || {};
28
+ const mergedProps = mergeThemeProps(themeVariables, previewProps);
29
+
30
+ // Apply theme CSS variables on mount
31
+ if (themeVariables && window.__linkapp_applyTheme) {
32
+ window.__linkapp_applyTheme(themeVariables);
33
+ }
34
+
35
+ const rootElement = document.getElementById("root");
36
+ if (!rootElement) {
37
+ throw new Error("Root element not found");
38
+ }
39
+
40
+ createRoot(rootElement).render(
41
+ <StrictMode>
42
+ <Sheet {...mergedProps} />
43
+ </StrictMode>,
44
+ );
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Classic - LinkApp</title>
6
+ <title>Sheet - LinkApp</title>
7
7
 
8
8
  <!-- iframe-resizer: Required for iframe height auto-adjustment -->
9
9
  <script crossorigin src="https://unpkg.com/iframe-resizer@4.3.2/js/iframeResizer.contentWindow.js"></script>
@@ -51,6 +51,6 @@
51
51
  </head>
52
52
  <body>
53
53
  <div id="root"></div>
54
- <script type="module" src="/classic/main.tsx"></script>
54
+ <script type="module" src="/sheet/main.tsx"></script>
55
55
  </body>
56
56
  </html>
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAMA,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAKD,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,iBA+D5E"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAUA,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAKD,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,iBAoE5E"}
@@ -3,17 +3,21 @@ import * as p from '@clack/prompts';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { spawn } from 'node:child_process';
6
+ const writeLine = (message = '') => {
7
+ process.stdout.write(`${message}\n`);
8
+ };
6
9
  // Default registry URL - can be overridden with --registry flag or LINKAPP_REGISTRY_URL env var
7
10
  const DEFAULT_REGISTRY = process.env.LINKAPP_REGISTRY_URL || 'https://create-linkapp-registry.vercel.app/r';
8
11
  export async function addCommand(component, options = {}) {
9
- console.log(pc.cyan('📦 Adding components from LinkApp registry...\n'));
12
+ writeLine(pc.cyan('📦 Adding components from LinkApp registry...'));
13
+ writeLine();
10
14
  try {
11
15
  // Check if components.json exists
12
16
  const projectPath = process.cwd();
13
17
  const componentsJsonPath = join(projectPath, 'components.json');
14
18
  if (!existsSync(componentsJsonPath)) {
15
- console.log(pc.red('✗ components.json not found'));
16
- console.log(pc.dim('Please run this command from a LinkApp project root'));
19
+ writeLine(pc.red('✗ components.json not found'));
20
+ writeLine(pc.dim('Please run this command from a LinkApp project root'));
17
21
  process.exit(1);
18
22
  }
19
23
  // Determine the registry URL (priority: CLI flag > env var > default)
@@ -21,11 +25,13 @@ export async function addCommand(component, options = {}) {
21
25
  // Build the component URL
22
26
  let componentUrl;
23
27
  if (!component) {
24
- console.log(pc.red('✗ Please specify a component name'));
25
- console.log(pc.dim('\\nAvailable components:'));
26
- console.log(pc.dim(' button'));
27
- console.log(pc.dim(' • switch'));
28
- console.log(pc.dim('\\nExample: linkapp add button'));
28
+ writeLine(pc.red('✗ Please specify a component name'));
29
+ writeLine();
30
+ writeLine(pc.dim('Available components:'));
31
+ writeLine(pc.dim(' • button'));
32
+ writeLine(pc.dim(' switch'));
33
+ writeLine();
34
+ writeLine(pc.dim('Example: linkapp add button'));
29
35
  process.exit(1);
30
36
  }
31
37
  // Check if it's a full URL or just a component name
@@ -35,7 +41,8 @@ export async function addCommand(component, options = {}) {
35
41
  else {
36
42
  componentUrl = `${registryUrl}/${component}.json`;
37
43
  }
38
- console.log(pc.dim(`Installing from: ${componentUrl}\n`));
44
+ writeLine(pc.dim(`Installing from: ${componentUrl}`));
45
+ writeLine();
39
46
  // Use shadcn CLI to install the component
40
47
  const args = ['add', componentUrl];
41
48
  if (options.yes) {
@@ -48,9 +55,10 @@ export async function addCommand(component, options = {}) {
48
55
  s.start(`Installing ${component}`);
49
56
  await runShadcnCommand(args);
50
57
  s.stop(pc.green(`✓ Successfully installed ${component}`));
51
- console.log(pc.dim('\\nYou can now import and use the component:'));
52
- console.log(pc.dim(` import { ${capitalize(component)} } from '@/components/ui/${component}'`));
53
- console.log();
58
+ writeLine();
59
+ writeLine(pc.dim('You can now import and use the component:'));
60
+ writeLine(pc.dim(` import { ${capitalize(component)} } from '@/components/ui/${component}'`));
61
+ writeLine();
54
62
  }
55
63
  catch (error) {
56
64
  console.error(pc.red('\\n✗ Failed to add component:'), error);
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAMA,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,iBAqDvD"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAUA,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,iBAyDvD"}
@@ -1,70 +1,89 @@
1
1
  import pc from 'picocolors';
2
- import { build as viteBuild } from 'vite';
3
- import { createViteConfig } from '../lib/vite/config-factory.js';
2
+ import { createRsbuild } from '@rsbuild/core';
3
+ import { createRsbuildConfig } from '../lib/rsbuild/config-factory.js';
4
4
  import { existsSync, statSync, readdirSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
+ const writeLine = (message = '') => {
7
+ process.stdout.write(`${message}\n`);
8
+ };
6
9
  export async function buildCommand(options) {
7
- console.log(pc.cyan('🏗️ Building for production...\n'));
10
+ writeLine(pc.cyan('🏗️ Building for production...'));
11
+ writeLine();
8
12
  const startTime = Date.now();
9
13
  try {
10
14
  // Use profile flag, fall back to analyze for backward compatibility
11
15
  const enableProfiling = options.profile || options.analyze || false;
12
- const config = createViteConfig({
16
+ const config = createRsbuildConfig({
13
17
  mode: 'production',
14
18
  sourcemap: options.sourcemap || false,
15
19
  profile: enableProfiling,
16
20
  });
17
- // Run Vite build
18
- const result = await viteBuild(config);
21
+ // Run Rsbuild build
22
+ const rsbuild = await createRsbuild({ rsbuildConfig: config });
23
+ const buildResult = await rsbuild.build();
19
24
  const endTime = Date.now();
20
25
  const duration = ((endTime - startTime) / 1000).toFixed(2);
21
- console.log(pc.green(`\n✓ Build completed in ${duration}s\n`));
22
- // Show bundle info
23
- if (Array.isArray(result)) {
24
- // Multiple builds
25
- for (const output of result) {
26
- if ('output' in output) {
27
- showBundleInfo(output.output);
28
- }
26
+ writeLine();
27
+ writeLine(pc.green(`✓ Build completed in ${duration}s`));
28
+ writeLine();
29
+ const assetDetails = collectAssetDetails(buildResult?.stats);
30
+ if (assetDetails.length > 0) {
31
+ writeLine(pc.bold('Build output:'));
32
+ for (const asset of assetDetails) {
33
+ const sizeKB = (asset.size / 1024).toFixed(1);
34
+ writeLine(pc.dim(` ${asset.name} ${sizeKB} KB`));
29
35
  }
30
- }
31
- else if (result && 'output' in result) {
32
- showBundleInfo(result.output);
36
+ writeLine();
33
37
  }
34
38
  // Show dist directory size
35
39
  const distPath = join(process.cwd(), 'dist');
36
40
  if (existsSync(distPath)) {
37
41
  const totalSize = getDirSize(distPath);
38
42
  const sizeKB = (totalSize / 1024).toFixed(1);
39
- console.log(pc.dim(`Total dist size: ${sizeKB} KB\n`));
43
+ writeLine(pc.dim(`Total dist size: ${sizeKB} KB`));
44
+ writeLine();
40
45
  }
41
46
  if (enableProfiling) {
42
- console.log(pc.cyan('\n📊 Bundle analysis files generated:'));
43
- console.log(pc.cyan(' 📄 Bundle report: dist/stats.html'));
44
- console.log(pc.cyan(' 💡 Open stats.html in your browser to analyze bundle size'));
45
- console.log(pc.cyan('\n🔍 Detailed profiling enabled - check build output above for timing breakdown\n'));
47
+ writeLine(pc.cyan('\n📊 Bundle analysis:'));
48
+ writeLine(pc.cyan(' 💡 Use --sourcemap flag and analyze with external tools'));
49
+ writeLine();
46
50
  }
51
+ await buildResult?.close();
47
52
  }
48
53
  catch (error) {
49
54
  console.error(pc.red('Build failed:'), error);
50
55
  process.exit(1);
51
56
  }
52
57
  }
53
- function showBundleInfo(output) {
54
- if (!Array.isArray(output))
55
- return;
56
- console.log(pc.bold('Build output:'));
57
- for (const chunk of output) {
58
- if (chunk.type === 'chunk') {
59
- const sizeKB = (chunk.code.length / 1024).toFixed(1);
60
- console.log(pc.dim(` ${chunk.fileName} ${sizeKB} KB`));
61
- }
62
- else if (chunk.type === 'asset') {
63
- const size = typeof chunk.source === 'string' ? chunk.source.length : chunk.source.byteLength;
64
- const sizeKB = (size / 1024).toFixed(1);
65
- console.log(pc.dim(` ${chunk.fileName} ${sizeKB} KB`));
66
- }
58
+ function collectAssetDetails(stats) {
59
+ if (!stats) {
60
+ return [];
67
61
  }
62
+ const collectFromStats = (single) => {
63
+ const json = single.toJson({
64
+ assets: true,
65
+ modules: false,
66
+ chunks: false,
67
+ chunkModules: false,
68
+ entrypoints: false,
69
+ children: false,
70
+ });
71
+ const assets = Array.isArray(json.assets) ? json.assets : [];
72
+ return assets
73
+ .filter((asset) => asset.emitted && asset.name && asset.size !== undefined)
74
+ .map((asset) => ({
75
+ name: asset.name,
76
+ size: asset.size,
77
+ }))
78
+ .sort((a, b) => a.name.localeCompare(b.name));
79
+ };
80
+ if (isMultiStats(stats)) {
81
+ return stats.stats.flatMap(collectFromStats).sort((a, b) => a.name.localeCompare(b.name));
82
+ }
83
+ return collectFromStats(stats);
84
+ }
85
+ function isMultiStats(stats) {
86
+ return 'stats' in stats && Array.isArray(stats.stats);
68
87
  }
69
88
  function getDirSize(dirPath) {
70
89
  let totalSize = 0;