@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
package/README.md ADDED
@@ -0,0 +1,420 @@
1
+ # @linktr.ee/linkapp
2
+
3
+ Development, build, and deployment tooling for LinkApps - custom interactive link experiences for Linktree profiles.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @linktr.ee/linkapp
9
+ ```
10
+
11
+ Or create a new LinkApp project:
12
+
13
+ ```bash
14
+ npm create @linktr.ee/linkapp@latest
15
+ ```
16
+
17
+ ## Commands
18
+
19
+ ### Development
20
+
21
+ Start the development server with hot reloading and theme preview UI:
22
+
23
+ ```bash
24
+ linkapp dev [--port 3000]
25
+ ```
26
+
27
+ The dev server provides:
28
+ - Live preview of all layouts (sheet, featured, carousel)
29
+ - Theme switcher with Linktree presets
30
+ - Settings editor for testing configurations
31
+ - Hot module replacement
32
+
33
+ ### Building
34
+
35
+ Build your LinkApp for production:
36
+
37
+ ```bash
38
+ linkapp build [options]
39
+ ```
40
+
41
+ **Options:**
42
+ - `--sourcemap` - Generate source maps for debugging
43
+ - `--profile` - Enable bundle profiling
44
+ - `--compress` - Generate Brotli-compressed files (30-40% smaller)
45
+
46
+ Outputs to `dist/` directory with:
47
+ - Content-hashed filenames for cache busting
48
+ - `build-manifest.json` with asset versions
49
+ - Optimized React vendor chunks for better caching
50
+
51
+ ### Deployment
52
+
53
+ Deploy your LinkApp to Linktree:
54
+
55
+ ```bash
56
+ linkapp deploy [--qa] [--skip-confirm]
57
+ ```
58
+
59
+ **Options:**
60
+ - `--qa` - Deploy to QA environment instead of production
61
+ - `--skip-confirm` - Skip confirmation prompt
62
+
63
+ The deployment process:
64
+ 1. Validates project structure and configuration
65
+ 2. Builds if needed (runs `linkapp build`)
66
+ 3. Generates manifest files from `linkapp.config.ts`
67
+ 4. Packs project into tarball
68
+ 5. Uploads to Linktree API
69
+ 6. Returns build ID and admin URL
70
+
71
+ ### Authentication
72
+
73
+ Authenticate with Linktree using OAuth device flow:
74
+
75
+ ```bash
76
+ linkapp login [--qa] # Login
77
+ linkapp logout [--qa] # Logout
78
+ ```
79
+
80
+ Tokens are stored in `~/.config/linkapp/auth-token.json`.
81
+
82
+ ### Components
83
+
84
+ Add UI components from the registry:
85
+
86
+ ```bash
87
+ linkapp add <component>
88
+ ```
89
+
90
+ Example: `linkapp add button`
91
+
92
+ ### URL Testing
93
+
94
+ Test URL matching rules from your config:
95
+
96
+ ```bash
97
+ linkapp test-url-match-rules <url>
98
+ ```
99
+
100
+ Example: `linkapp test-url-match-rules https://google.com/search`
101
+
102
+ ## Exports
103
+
104
+ ### CLI
105
+
106
+ ```json
107
+ {
108
+ "bin": {
109
+ "linkapp": "bin/cli.js"
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### Types
115
+
116
+ ```typescript
117
+ import type { AppProps, LinkAppConfig, SettingsElement } from '@linktr.ee/linkapp/types'
118
+
119
+ // Layout component props
120
+ interface MySettings {
121
+ title: string
122
+ color: string
123
+ }
124
+
125
+ export default function SheetLayout({ settings, theme }: AppProps<MySettings>) {
126
+ return <div>{settings.title}</div>
127
+ }
128
+ ```
129
+
130
+ ### SDK
131
+
132
+ ```typescript
133
+ import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'
134
+
135
+ // In featured layout, trigger popup/modal
136
+ function FeaturedLayout() {
137
+ const expandLinkApp = useExpandLinkApp()
138
+
139
+ return (
140
+ <button onClick={() => expandLinkApp({ itemId: '123' })}>
141
+ Expand
142
+ </button>
143
+ )
144
+ }
145
+ ```
146
+
147
+ ## Project Structure
148
+
149
+ A LinkApp project has this structure:
150
+
151
+ ```
152
+ my-linkapp/
153
+ ├── app/
154
+ │ ├── sheet.tsx # Required: default layout
155
+ │ ├── featured.tsx # Optional: featured layout
156
+ │ ├── featured-carousel.tsx # Optional: carousel variant
157
+ │ ├── layout.tsx # Optional: wrapper component
158
+ │ ├── globals.css # Global styles
159
+ │ └── icon.svg # LinkApp icon
160
+ ├── components/ # Your components
161
+ ├── public/ # Static assets (copied to dist/)
162
+ ├── linkapp.config.ts # Configuration
163
+ ├── postcss.config.mjs # PostCSS config (Tailwind v4)
164
+ ├── components.json # Component registry config
165
+ └── package.json
166
+ ```
167
+
168
+ ## Configuration
169
+
170
+ The `linkapp.config.ts` file defines your LinkApp:
171
+
172
+ ```typescript
173
+ import { defineConfig } from '@linktr.ee/linkapp/types'
174
+
175
+ export default defineConfig({
176
+ manifest: {
177
+ name: 'My LinkApp',
178
+ tagline: 'A custom link experience',
179
+ category: 'share',
180
+ author: {
181
+ name: 'Your Name',
182
+ website: 'https://example.com'
183
+ },
184
+ supporting_links: {
185
+ terms_of_service: 'https://example.com/terms',
186
+ privacy_policy: 'https://example.com/privacy'
187
+ }
188
+ },
189
+ settings: {
190
+ title: 'My LinkApp Settings',
191
+ uses_url: true,
192
+ featured_chin_position: 'below',
193
+ featured_head_allow_unlocked_aspect_ratio: true,
194
+ sheet_behavior: 'expandGeneric',
195
+ featured_head_click_behavior: 'expand',
196
+ elements: [
197
+ {
198
+ type: 'text',
199
+ id: 'title',
200
+ label: 'Title',
201
+ defaultValue: 'Hello World'
202
+ }
203
+ ]
204
+ },
205
+ url_match_rules: {
206
+ hostnames: ['{*.}?example.com']
207
+ },
208
+ preview_props: {
209
+ settings: {
210
+ title: 'Preview Title'
211
+ }
212
+ }
213
+ })
214
+ ```
215
+
216
+ **Important:** The `manifest.name` becomes your LinkApp ID (kebab-cased) and cannot be changed after first deployment.
217
+
218
+ ## Build System
219
+
220
+ Uses Rsbuild (Rspack) for fast, optimized builds:
221
+
222
+ - **Entry Point**: `.linkapp/main.tsx` (auto-generated)
223
+ - **Alias**: `@/` points to project root
224
+ - **PostCSS**: Supports Tailwind CSS v4
225
+ - **Asset Prefix**: `./` for S3 subdirectory deployment
226
+ - **Code Splitting**: React vendor chunks separated for caching
227
+ - **Compression**: Optional Brotli compression with `--compress` flag
228
+
229
+ ## Layout Components
230
+
231
+ ### Sheet Layout (Required)
232
+
233
+ Compact layout for profile pages:
234
+
235
+ ```typescript
236
+ import type { AppProps } from '@linktr.ee/linkapp/types'
237
+
238
+ interface Settings {
239
+ title: string
240
+ }
241
+
242
+ export default function Sheet({ settings, theme, __linkUrl }: AppProps<Settings>) {
243
+ return (
244
+ <div style={{ color: theme.textColor }}>
245
+ <h1>{settings.title}</h1>
246
+ <a href={__linkUrl}>Visit Link</a>
247
+ </div>
248
+ )
249
+ }
250
+ ```
251
+
252
+ ### Featured Layout (Optional)
253
+
254
+ Hero-style layout for featured content:
255
+
256
+ ```typescript
257
+ import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'
258
+ import type { AppProps } from '@linktr.ee/linkapp/types'
259
+
260
+ export default function Featured({ settings }: AppProps<Settings>) {
261
+ const expand = useExpandLinkApp()
262
+
263
+ return (
264
+ <div onClick={() => expand()}>
265
+ <h1>{settings.title}</h1>
266
+ </div>
267
+ )
268
+ }
269
+ ```
270
+
271
+ The featured layout can trigger a modal that displays the sheet layout.
272
+
273
+ ## Theme System
274
+
275
+ LinkApps receive theme data via props:
276
+
277
+ ```typescript
278
+ interface Theme {
279
+ // Legacy properties (maintained for compatibility)
280
+ textColor: string
281
+ backgroundColor: string
282
+ borderRadius: number
283
+
284
+ // Modern CSS variables (preferred)
285
+ cssVariables: Record<string, string>
286
+ }
287
+ ```
288
+
289
+ Apply CSS variables for theming:
290
+
291
+ ```css
292
+ /* app/globals.css */
293
+ :root {
294
+ --color-primary: var(--theme-primary, #000);
295
+ --color-background: var(--theme-background, #fff);
296
+ }
297
+ ```
298
+
299
+ ## PostMessage API
300
+
301
+ LinkApps run in iframes and communicate with the parent window:
302
+
303
+ ### From LinkApp to Parent
304
+
305
+ ```typescript
306
+ import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'
307
+
308
+ // Opens modal in parent window
309
+ const expand = useExpandLinkApp()
310
+ expand({ itemId: '123' })
311
+ ```
312
+
313
+ ### From Parent to LinkApp
314
+
315
+ ```typescript
316
+ // Parent sends theme updates
317
+ window.postMessage({
318
+ type: 'THEME_UPDATE',
319
+ payload: {
320
+ name: 'dark',
321
+ variables: { '--theme-primary': '#fff' }
322
+ }
323
+ }, '*')
324
+ ```
325
+
326
+ ## Development
327
+
328
+ ### Local Development
329
+
330
+ ```bash
331
+ npm run build # Compile TypeScript
332
+ npm run dev # Watch mode
333
+ npm run test # Run tests
334
+ npm run lint # Lint with Biome
335
+ npm run format # Format with Biome
336
+ ```
337
+
338
+ ### Testing Locally
339
+
340
+ Link the package globally to test CLI changes:
341
+
342
+ ```bash
343
+ cd packages/linkapp
344
+ npm run build
345
+ npm link
346
+
347
+ cd ../../apps/my-test-app
348
+ linkapp dev
349
+ ```
350
+
351
+ ### Package Scripts
352
+
353
+ - `build` - Compile TypeScript to `dist/`
354
+ - `dev` - Watch mode compilation
355
+ - `test` - Run Vitest tests
356
+ - `test:watch` - Watch mode for tests
357
+ - `lint` - Lint with Biome
358
+ - `format` - Format with Biome
359
+ - `clean` - Remove build artifacts
360
+
361
+ ## Key Concepts
362
+
363
+ ### LinkApp ID
364
+
365
+ The LinkApp ID is derived from `manifest.name` using kebab-case:
366
+ - `"My Cool App"` → `"my-cool-app"`
367
+ - This ID is permanent and identifies your LinkApp across deployments
368
+ - Cannot be changed after first deployment
369
+
370
+ ### Layout Detection
371
+
372
+ The `supports_featured_layout` setting is auto-detected based on the presence of `app/featured.tsx`. You don't need to manually configure it.
373
+
374
+ ### Settings Schema
375
+
376
+ Settings are defined as an array of elements:
377
+
378
+ ```typescript
379
+ elements: [
380
+ {
381
+ type: 'text',
382
+ id: 'title',
383
+ label: 'Title',
384
+ defaultValue: 'Hello'
385
+ },
386
+ {
387
+ type: 'select',
388
+ id: 'style',
389
+ label: 'Style',
390
+ options: ['minimal', 'bold'],
391
+ defaultValue: 'minimal'
392
+ },
393
+ {
394
+ type: 'array',
395
+ id: 'items',
396
+ label: 'Items',
397
+ element: {
398
+ type: 'text',
399
+ id: 'name',
400
+ label: 'Name'
401
+ }
402
+ }
403
+ ]
404
+ ```
405
+
406
+ Supported types: `text`, `select`, `file`, `switch`, `array`, `number`, `date`, `color`
407
+
408
+ ## Requirements
409
+
410
+ - Node.js >= 18.0.0
411
+ - npm >= 10.0.0
412
+
413
+ ## Related Packages
414
+
415
+ - `@linktr.ee/create-linkapp` - Scaffolding tool for new projects
416
+ - `@linktr.ee/registry` - Component registry
417
+
418
+ ## License
419
+
420
+ See LICENSE file in repository root.
@@ -1,15 +1,15 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import Preview from './Preview'
4
- import './preview.css'
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import Preview from "./preview";
4
+ import "./preview.css";
5
5
 
6
- const rootElement = document.getElementById('root')
6
+ const rootElement = document.getElementById("root");
7
7
  if (!rootElement) {
8
- throw new Error('Root element not found')
8
+ throw new Error("Root element not found");
9
9
  }
10
10
 
11
11
  createRoot(rootElement).render(
12
12
  <StrictMode>
13
13
  <Preview />
14
- </StrictMode>
15
- )
14
+ </StrictMode>,
15
+ );