@linktr.ee/linkapp 0.0.35 → 0.0.37

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 (34) hide show
  1. package/README.md +420 -0
  2. package/dev-server/preview/main.tsx +8 -8
  3. package/dev-server/preview/preview.tsx +417 -0
  4. package/dist/cli.js +1 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/build.d.ts +1 -0
  7. package/dist/commands/build.d.ts.map +1 -1
  8. package/dist/commands/build.js +43 -2
  9. package/dist/commands/build.js.map +1 -1
  10. package/dist/lib/deploy/generate-manifest-files.d.ts.map +1 -1
  11. package/dist/lib/deploy/generate-manifest-files.js +9 -0
  12. package/dist/lib/deploy/generate-manifest-files.js.map +1 -1
  13. package/dist/lib/rsbuild/config-factory.d.ts +1 -0
  14. package/dist/lib/rsbuild/config-factory.d.ts.map +1 -1
  15. package/dist/lib/rsbuild/config-factory.js +28 -1
  16. package/dist/lib/rsbuild/config-factory.js.map +1 -1
  17. package/dist/lib/rsbuild/plugins/brotli-compression.d.ts +21 -0
  18. package/dist/lib/rsbuild/plugins/brotli-compression.d.ts.map +1 -0
  19. package/dist/lib/rsbuild/plugins/brotli-compression.js +68 -0
  20. package/dist/lib/rsbuild/plugins/brotli-compression.js.map +1 -0
  21. package/dist/lib/utils/setup-runtime.d.ts.map +1 -1
  22. package/dist/lib/utils/setup-runtime.js +16 -1
  23. package/dist/lib/utils/setup-runtime.js.map +1 -1
  24. package/dist/schema/config.schema.d.ts +33 -2
  25. package/dist/schema/config.schema.d.ts.map +1 -1
  26. package/dist/schema/config.schema.js +18 -1
  27. package/dist/schema/config.schema.js.map +1 -1
  28. package/dist/types.d.ts +7 -3
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/types.js.map +1 -1
  31. package/package.json +1 -1
  32. package/runtime/index.html +45 -0
  33. package/dev-server/preview/Preview.tsx +0 -276
  34. /package/dev-server/components/{SettingsPreview.tsx → settings-preview.tsx} +0 -0
@@ -1,276 +0,0 @@
1
- import { Portal } from "@radix-ui/react-portal";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- import IframeResizer, { IFrameComponent } from "iframe-resizer-react";
4
- import {
5
- Dialog,
6
- DialogContent,
7
- DialogHeader,
8
- DialogTitle,
9
- } from "../components/ui/dialog";
10
- import {
11
- Tabs,
12
- TabsContent,
13
- TabsList,
14
- TabsTrigger,
15
- } from "../components/ui/tabs";
16
- import { cn, renderCssVariables } from "../lib/utils";
17
- import { SettingsPreview } from "../components/SettingsPreview";
18
- import { THEME_PRESETS } from "../shared/theme-presets";
19
-
20
- export default function Preview() {
21
- // Initialize state from localStorage
22
- const [selectedTab, setSelectedTab] = useState<"sheet" | "featured" | "settings">(() => {
23
- const saved = localStorage.getItem("linkapp-preview-tab");
24
- return (saved as "sheet" | "featured" | "settings") || "sheet";
25
- });
26
- const [selectedTheme, setSelectedTheme] = useState<keyof typeof THEME_PRESETS>(() => {
27
- const saved = localStorage.getItem("linkapp-preview-theme");
28
- return (saved as keyof typeof THEME_PRESETS) || "default";
29
- });
30
- const [selectedGroupLayoutOption, setSelectedGroupLayoutOption] = useState<string | undefined>(() => {
31
- const saved = localStorage.getItem("linkapp-preview-groupLayoutOption");
32
- return saved || undefined;
33
- });
34
-
35
- // Popup dialog state
36
- const [isPopupOpen, setIsPopupOpen] = useState(false);
37
-
38
- // Generate unique IDs for iframes using timestamp
39
- const sheetIframeId = useMemo(() => `preview-iframe-sheet-${Date.now()}`, []);
40
- const featuredIframeId = useMemo(() => `preview-iframe-featured-${Date.now()}`, []);
41
- const popupIframeId = useMemo(() => `preview-iframe-popup-${Date.now()}`, []);
42
-
43
- // Save selected tab to localStorage
44
- useEffect(() => {
45
- localStorage.setItem("linkapp-preview-tab", selectedTab);
46
- }, [selectedTab]);
47
-
48
- // Save selected theme to localStorage
49
- useEffect(() => {
50
- localStorage.setItem("linkapp-preview-theme", selectedTheme);
51
- }, [selectedTheme]);
52
-
53
- // Save selected groupLayoutOption to localStorage
54
- useEffect(() => {
55
- if (selectedGroupLayoutOption) {
56
- localStorage.setItem("linkapp-preview-groupLayoutOption", selectedGroupLayoutOption);
57
- } else {
58
- localStorage.removeItem("linkapp-preview-groupLayoutOption");
59
- }
60
- }, [selectedGroupLayoutOption]);
61
-
62
- // Handle iframe resize events
63
- const handleResized = useCallback(
64
- (ev: { iframe: IFrameComponent; height: number; width: number; type: string }): void => {
65
- // IframeResizer automatically handles height adjustments
66
- // This callback is available for debugging if needed
67
- },
68
- []
69
- );
70
-
71
- // Handle postMessage from featured iframe for EXPAND_LINK_APP
72
- const handleMessage = useCallback((event: MessageEvent) => {
73
- if (
74
- event.data &&
75
- typeof event.data === 'object' &&
76
- event.data.source === 'linkapp' &&
77
- event.data.type === 'EXPAND_LINK_APP'
78
- ) {
79
- setIsPopupOpen(true);
80
- }
81
- }, []);
82
-
83
- // Add message listener
84
- useEffect(() => {
85
- window.addEventListener('message', handleMessage);
86
- return () => window.removeEventListener('message', handleMessage);
87
- }, [handleMessage]);
88
-
89
-
90
- const renderedCssVariables = useMemo(() => {
91
- const themeVariables = THEME_PRESETS[selectedTheme] || THEME_PRESETS.default
92
- return renderCssVariables(themeVariables.variables);
93
- }, [selectedTheme])
94
-
95
- return (
96
- <>
97
- <style>{`:root {
98
- ${renderedCssVariables}
99
- }`}</style>
100
-
101
- <div
102
- className={cn("min-h-screen", {
103
- "bg-black/50": selectedTab === "classic",
104
- "bg-linktree-frame": selectedTab === "featured",
105
- })}
106
- id="preview"
107
- >
108
- <Tabs
109
- value={selectedTab}
110
- onValueChange={(value) =>
111
- setSelectedTab(value as "sheet" | "featured" | "settings")
112
- }
113
- >
114
- <Portal>
115
- <div
116
- className="fixed top-0 left-0 right-0 p-4 flex justify-center gap-4 bg-background border-b"
117
- style={{ zIndex: 1000000 }}
118
- >
119
- <TabsList>
120
- <TabsTrigger value="sheet">Sheet</TabsTrigger>
121
- <TabsTrigger value="featured">Featured</TabsTrigger>
122
- <TabsTrigger value="settings">Settings</TabsTrigger>
123
- </TabsList>
124
-
125
- {/* Theme Switcher */}
126
- <div className="flex items-center gap-2">
127
- <label htmlFor="theme-select" className="text-sm font-medium">
128
- Theme:
129
- </label>
130
- <select
131
- id="theme-select"
132
- value={selectedTheme}
133
- onChange={(e) =>
134
- setSelectedTheme(e.target.value as keyof typeof THEME_PRESETS)
135
- }
136
- className="h-9 px-3 py-1 text-sm border border-input bg-background rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
137
- >
138
- {Object.entries(THEME_PRESETS).map(([key, theme]) => (
139
- <option key={key} value={key}>
140
- {theme.name}
141
- </option>
142
- ))}
143
- </select>
144
- </div>
145
-
146
- {/* Group Layout Option Switcher - Only show for Featured tab */}
147
- {selectedTab === "featured" && (
148
- <div className="flex items-center gap-2">
149
- <label htmlFor="groupLayoutOption-select" className="text-sm font-medium">
150
- Layout:
151
- </label>
152
- <select
153
- id="groupLayoutOption-select"
154
- value={selectedGroupLayoutOption || "default"}
155
- onChange={(e) =>
156
- setSelectedGroupLayoutOption(e.target.value === "default" ? undefined : e.target.value)
157
- }
158
- className="h-9 px-3 py-1 text-sm border border-input bg-background rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
159
- >
160
- <option value="default">Default</option>
161
- <option value="carousel">Carousel</option>
162
- </select>
163
- </div>
164
- )}
165
- </div>
166
- </Portal>
167
-
168
- {/* Main Content with Padding for Fixed Tabs */}
169
- <div className="pt-20">
170
- <TabsContent value="sheet" className="m-0">
171
- {/* Sheet Modal - Always Open */}
172
- <Dialog open={true} modal={false}>
173
- <DialogContent
174
- className="h-[calc(100dvh-2rem)] max-w-[608px] md:min-h-[25vh] md:h-[80%] md:max-h-[900px] overflow-auto"
175
- showCloseButton={false}
176
- >
177
- <DialogHeader className="sticky top-0 bg-white px-4">
178
- <div className="grid h-16 grid-cols-[32px_auto_32px] items-center gap-4">
179
- <button className="flex size-8 items-center justify-center rounded-sm focus-visible:outline-none">
180
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className=" " role="img" aria-hidden="true"><path fill="currentColor" d="m10.65 3.85.35.36.7-.71-.35-.35-3-3h-.7l-3 3-.36.35.71.7.35-.35L7.5 1.71V10h1V1.7l2.15 2.15ZM1 5.5l.5-.5H4v1H2v9h12V6h-2V5h2.5l.5.5v10l-.5.5h-13l-.5-.5v-10Z"></path></svg>
181
- </button>
182
-
183
- <DialogTitle className="self-center truncate py-3 text-center">
184
- Sheet
185
- </DialogTitle>
186
-
187
- <button className="flex size-8 items-center justify-center rounded-sm focus-visible:outline-none">
188
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className=" " role="img" aria-hidden="true"><path fill="currentColor" d="m13.63 3.12.37-.38-.74-.74-.38.37.75.75ZM2.37 12.89l-.37.37.74.74.38-.37-.75-.75Zm.75-10.52L2.74 2 2 2.74l.37.38.75-.75Zm9.76 11.26.38.37.74-.74-.37-.38-.75.75Zm0-11.26L2.38 12.9l.74.74 10.5-10.51-.74-.75Zm-10.5.75 10.5 10.5.75-.73L3.12 2.37l-.75.75Z"></path></svg>
189
- </button>
190
- </div>
191
- </DialogHeader>
192
-
193
- <div className="flex h-[calc(100%-64px)] flex-1 flex-col justify-between overflow-hidden">
194
- <div className="h-full overflow-y-auto overflow-x-hidden">
195
- <IframeResizer
196
- key={`sheet-${selectedTheme}`}
197
- id={sheetIframeId}
198
- src={`/sheet?theme=${selectedTheme}`}
199
- style={{ height: '0px', width: '1px', minWidth: '100%', border: 0 }}
200
- checkOrigin={false}
201
- onResized={handleResized}
202
- heightCalculationMethod="max"
203
- />
204
- </div>
205
- </div>
206
- </DialogContent>
207
- </Dialog>
208
- </TabsContent>
209
-
210
- <TabsContent value="featured" className="m-0 flex justify-center p-8">
211
- {/* Featured Iframe - Max Width 524px */}
212
- <div className="w-full max-w-[580px] flex flex-col px-[28px] py-7 items-center bg-linktree-profile-bg">
213
-
214
- <div className="w-full max-w-[524px]">
215
- <div className="bg-linktree-button-bg hover:bg-linktree-button-bg-hover border-linktree-button-border text-linktree-button-text rounded-linktree-button shadow-linktree-button overflow-hidden">
216
- <IframeResizer
217
- key={`featured-${selectedTheme}-${selectedGroupLayoutOption || 'default'}`}
218
- id={featuredIframeId}
219
- src={`/featured?theme=${selectedTheme}${selectedGroupLayoutOption ? `&groupLayoutOption=${selectedGroupLayoutOption}` : ''}`}
220
- style={{ height: '0px', width: '1px', minWidth: '100%', border: 0 }}
221
- checkOrigin={false}
222
- onResized={handleResized}
223
- heightCalculationMethod="max"
224
- />
225
- </div>
226
- </div>
227
- </div>
228
- </TabsContent>
229
-
230
- <TabsContent value="settings" className="m-0">
231
- <SettingsPreview settings={__SETTINGS_CONFIG__} />
232
- </TabsContent>
233
- </div>
234
- </Tabs>
235
-
236
- {/* Popup Dialog for EXPAND_LINK_APP message */}
237
- <Dialog open={isPopupOpen} onOpenChange={setIsPopupOpen} modal={false}>
238
- <DialogContent
239
- className="h-[calc(100dvh-2rem)] max-w-[608px] md:min-h-[25vh] md:h-[80%] md:max-h-[900px] overflow-auto"
240
- showCloseButton={false}
241
- >
242
- <DialogHeader className="sticky top-0 bg-white px-4">
243
- <div className="grid h-16 grid-cols-[32px_auto_32px] items-center gap-4">
244
- <button className="flex size-8 items-center justify-center rounded-sm focus-visible:outline-none">
245
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className=" " role="img" aria-hidden="true"><path fill="currentColor" d="m10.65 3.85.35.36.7-.71-.35-.35-3-3h-.7l-3 3-.36.35.71.7.35-.35L7.5 1.71V10h1V1.7l2.15 2.15ZM1 5.5l.5-.5H4v1H2v9h12V6h-2V5h2.5l.5.5v10l-.5.5h-13l-.5-.5v-10Z"></path></svg>
246
- </button>
247
-
248
- <DialogTitle className="self-center truncate py-3 text-center">
249
- Sheet
250
- </DialogTitle>
251
-
252
- <button className="flex size-8 items-center justify-center rounded-sm focus-visible:outline-none">
253
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className=" " role="img" aria-hidden="true"><path fill="currentColor" d="m13.63 3.12.37-.38-.74-.74-.38.37.75.75ZM2.37 12.89l-.37.37.74.74.38-.37-.75-.75Zm.75-10.52L2.74 2 2 2.74l.37.38.75-.75Zm9.76 11.26.38.37.74-.74-.37-.38-.75.75Zm0-11.26L2.38 12.9l.74.74 10.5-10.51-.74-.75Zm-10.5.75 10.5 10.5.75-.73L3.12 2.37l-.75.75Z"></path></svg>
254
- </button>
255
- </div>
256
- </DialogHeader>
257
-
258
- <div className="flex h-[calc(100%-64px)] flex-1 flex-col justify-between overflow-hidden">
259
- <div className="h-full overflow-y-auto overflow-x-hidden">
260
- <IframeResizer
261
- key={`popup-${selectedTheme}`}
262
- id={popupIframeId}
263
- src={`/sheet?theme=${selectedTheme}`}
264
- style={{ height: '0px', width: '1px', minWidth: '100%', border: 0 }}
265
- checkOrigin={false}
266
- onResized={handleResized}
267
- heightCalculationMethod="max"
268
- />
269
- </div>
270
- </div>
271
- </DialogContent>
272
- </Dialog>
273
- </div>
274
- </>
275
- );
276
- }