@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.
- package/README.md +420 -0
- package/dev-server/preview/main.tsx +8 -8
- package/dev-server/preview/preview.tsx +417 -0
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/build.d.ts +1 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +43 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/lib/deploy/generate-manifest-files.d.ts.map +1 -1
- package/dist/lib/deploy/generate-manifest-files.js +9 -0
- package/dist/lib/deploy/generate-manifest-files.js.map +1 -1
- package/dist/lib/rsbuild/config-factory.d.ts +1 -0
- package/dist/lib/rsbuild/config-factory.d.ts.map +1 -1
- package/dist/lib/rsbuild/config-factory.js +28 -1
- package/dist/lib/rsbuild/config-factory.js.map +1 -1
- package/dist/lib/rsbuild/plugins/brotli-compression.d.ts +21 -0
- package/dist/lib/rsbuild/plugins/brotli-compression.d.ts.map +1 -0
- package/dist/lib/rsbuild/plugins/brotli-compression.js +68 -0
- package/dist/lib/rsbuild/plugins/brotli-compression.js.map +1 -0
- package/dist/lib/utils/setup-runtime.d.ts.map +1 -1
- package/dist/lib/utils/setup-runtime.js +16 -1
- package/dist/lib/utils/setup-runtime.js.map +1 -1
- package/dist/schema/config.schema.d.ts +33 -2
- package/dist/schema/config.schema.d.ts.map +1 -1
- package/dist/schema/config.schema.js +18 -1
- package/dist/schema/config.schema.js.map +1 -1
- package/dist/types.d.ts +7 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/runtime/index.html +45 -0
- package/dev-server/preview/Preview.tsx +0 -276
- /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
|
|
2
|
-
import { createRoot } from
|
|
3
|
-
import Preview from
|
|
4
|
-
import
|
|
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(
|
|
6
|
+
const rootElement = document.getElementById("root");
|
|
7
7
|
if (!rootElement) {
|
|
8
|
-
throw new Error(
|
|
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
|
+
);
|