@proveanything/smartlinks 1.2.3 → 1.3.1

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.
@@ -0,0 +1,100 @@
1
+ # SmartLinks Theme Default Colors
2
+
3
+ Default color values for the SmartLinks theme system. Use these when no theme is provided via URL parameter.
4
+
5
+ ---
6
+
7
+ ## Light Mode (Default)
8
+
9
+ | Theme Key | CSS Variable | HSL Value | RGB | Hex |
10
+ |-----------|--------------------------|---------------------|---------------|-----------|
11
+ | `bg` | `--background` | 0 0% 100% | 255, 255, 255 | #FFFFFF |
12
+ | `fg` | `--foreground` | 222.2 84% 4.9% | 2, 8, 23 | #020817 |
13
+ | `p` | `--primary` | 222.2 47.4% 11.2% | 15, 23, 42 | #0F172A |
14
+ | `pf` | `--primary-foreground` | 210 40% 98% | 248, 250, 252 | #F8FAFC |
15
+ | `s` | `--secondary` | 210 40% 96.1% | 241, 245, 249 | #F1F5F9 |
16
+ | `sf` | `--secondary-foreground` | 222.2 47.4% 11.2% | 15, 23, 42 | #0F172A |
17
+ | `a` | `--accent` | 210 40% 96.1% | 241, 245, 249 | #F1F5F9 |
18
+ | `af` | `--accent-foreground` | 222.2 47.4% 11.2% | 15, 23, 42 | #0F172A |
19
+ | `mt` | `--muted` | 210 40% 96.1% | 241, 245, 249 | #F1F5F9 |
20
+ | `mf` | `--muted-foreground` | 215.4 16.3% 46.9% | 100, 116, 139 | #64748B |
21
+ | `bd` | `--border` | 214.3 31.8% 91.4% | 226, 232, 240 | #E2E8F0 |
22
+ | `inp` | `--input` | 214.3 31.8% 91.4% | 226, 232, 240 | #E2E8F0 |
23
+ | `ring` | `--ring` | 222.2 84% 4.9% | 2, 8, 23 | #020817 |
24
+
25
+ ---
26
+
27
+ ## Dark Mode
28
+
29
+ | Theme Key | CSS Variable | HSL Value | RGB | Hex |
30
+ |-----------|--------------------------|---------------------|---------------|-----------|
31
+ | `bg` | `--background` | 222.2 84% 4.9% | 2, 8, 23 | #020817 |
32
+ | `fg` | `--foreground` | 210 40% 98% | 248, 250, 252 | #F8FAFC |
33
+ | `p` | `--primary` | 210 40% 98% | 248, 250, 252 | #F8FAFC |
34
+ | `pf` | `--primary-foreground` | 222.2 47.4% 11.2% | 15, 23, 42 | #0F172A |
35
+ | `s` | `--secondary` | 217.2 32.6% 17.5% | 30, 41, 59 | #1E293B |
36
+ | `sf` | `--secondary-foreground` | 210 40% 98% | 248, 250, 252 | #F8FAFC |
37
+ | `a` | `--accent` | 217.2 32.6% 17.5% | 30, 41, 59 | #1E293B |
38
+ | `af` | `--accent-foreground` | 210 40% 98% | 248, 250, 252 | #F8FAFC |
39
+ | `mt` | `--muted` | 217.2 32.6% 17.5% | 30, 41, 59 | #1E293B |
40
+ | `mf` | `--muted-foreground` | 215 20.2% 65.1% | 148, 163, 184 | #94A3B8 |
41
+ | `bd` | `--border` | 217.2 32.6% 17.5% | 30, 41, 59 | #1E293B |
42
+ | `inp` | `--input` | 217.2 32.6% 17.5% | 30, 41, 59 | #1E293B |
43
+ | `ring` | `--ring` | 212.7 26.8% 83.9% | 203, 213, 225 | #CBD5E1 |
44
+
45
+ ---
46
+
47
+ ## Non-Color Defaults
48
+
49
+ | Theme Key | CSS Variable | Default Value |
50
+ |-----------|-----------------|----------------------------------------|
51
+ | `r` | `--radius` | 0.5rem |
52
+ | `fn` | `--font-family` | system-ui, -apple-system, sans-serif |
53
+
54
+ ---
55
+
56
+ ## Quick Copy (JSON)
57
+
58
+ ### Light Mode Defaults
59
+
60
+ ```json
61
+ {
62
+ "m": "l",
63
+ "bg": "0 0% 100%",
64
+ "fg": "222.2 84% 4.9%",
65
+ "p": "222.2 47.4% 11.2%",
66
+ "pf": "210 40% 98%",
67
+ "s": "210 40% 96.1%",
68
+ "sf": "222.2 47.4% 11.2%",
69
+ "a": "210 40% 96.1%",
70
+ "af": "222.2 47.4% 11.2%",
71
+ "mt": "210 40% 96.1%",
72
+ "mf": "215.4 16.3% 46.9%",
73
+ "bd": "214.3 31.8% 91.4%",
74
+ "inp": "214.3 31.8% 91.4%",
75
+ "ring": "222.2 84% 4.9%",
76
+ "r": "0.5rem"
77
+ }
78
+ ```
79
+
80
+ ### Dark Mode Defaults
81
+
82
+ ```json
83
+ {
84
+ "m": "d",
85
+ "bg": "222.2 84% 4.9%",
86
+ "fg": "210 40% 98%",
87
+ "p": "210 40% 98%",
88
+ "pf": "222.2 47.4% 11.2%",
89
+ "s": "217.2 32.6% 17.5%",
90
+ "sf": "210 40% 98%",
91
+ "a": "217.2 32.6% 17.5%",
92
+ "af": "210 40% 98%",
93
+ "mt": "217.2 32.6% 17.5%",
94
+ "mf": "215 20.2% 65.1%",
95
+ "bd": "217.2 32.6% 17.5%",
96
+ "inp": "217.2 32.6% 17.5%",
97
+ "ring": "212.7 26.8% 83.9%",
98
+ "r": "0.5rem"
99
+ }
100
+ ```
@@ -0,0 +1,338 @@
1
+ # SmartLinks Theme System
2
+
3
+ Dynamic theming for SmartLinks iframe apps. Allows parent frames to pass branding configuration via URL parameters or postMessage.
4
+
5
+ ## Quick Start
6
+
7
+ ### URL Parameter (Recommended)
8
+
9
+ Pass a base64-encoded JSON theme in the `theme` parameter:
10
+
11
+ ```
12
+ https://your-app.com/#/?collectionId=xyz&theme=eyJtIjoiZCIsInAiOiIyMTcgOTElIDYwJSJ9
13
+ ```
14
+
15
+ ### PostMessage (Live Updates)
16
+
17
+ ```javascript
18
+ iframe.contentWindow.postMessage({
19
+ type: 'smartlinks-theme',
20
+ theme: {
21
+ m: 'd',
22
+ p: '217 91% 60%',
23
+ fn: 'Inter',
24
+ fu: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'
25
+ }
26
+ }, '*');
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Theme Schema
32
+
33
+ ### Property Reference
34
+
35
+ | Key | CSS Variable | Description | Example |
36
+ | ------ | ------------------------ | ----------------------------------- | --------------- |
37
+ | `m` | - | Mode: `'d'` (dark) or `'l'` (light) | `"d"` |
38
+ | `bg` | `--background` | Background color | `"222 84% 5%"` |
39
+ | `fg` | `--foreground` | Foreground/text color | `"210 40% 98%"` |
40
+ | `p` | `--primary` | Primary brand color | `"217 91% 60%"` |
41
+ | `pf` | `--primary-foreground` | Text on primary | `"210 40% 98%"` |
42
+ | `s` | `--secondary` | Secondary color | `"217 33% 18%"` |
43
+ | `sf` | `--secondary-foreground` | Text on secondary | `"210 40% 98%"` |
44
+ | `a` | `--accent` | Accent color | `"217 33% 18%"` |
45
+ | `af` | `--accent-foreground` | Text on accent | `"210 40% 98%"` |
46
+ | `mt` | `--muted` | Muted backgrounds | `"217 33% 18%"` |
47
+ | `mf` | `--muted-foreground` | Muted text | `"215 20% 65%"` |
48
+ | `bd` | `--border` | Border color | `"217 33% 18%"` |
49
+ | `inp` | `--input` | Input border color | `"217 33% 18%"` |
50
+ | `ring` | `--ring` | Focus ring color | `"213 27% 84%"` |
51
+ | `r` | `--radius` | Border radius | `"0.5rem"` |
52
+ | `fn` | `--font-family` | Font family name | `"Inter"` |
53
+ | `fu` | - | Font URL (CSS or woff2) | See below |
54
+
55
+ ### Color Format
56
+
57
+ **All colors must be raw HSL values** (no `hsl()` wrapper):
58
+
59
+ ```
60
+ "217 91% 60%" ✅ Correct
61
+ "hsl(217, 91%, 60%)" ❌ Wrong
62
+ "#3b82f6" ⚠️ Works (auto-converted) but HSL preferred
63
+ ```
64
+
65
+ ### Font Loading
66
+
67
+ The `fu` property supports:
68
+
69
+ 1. **Google Fonts CSS URL**:
70
+
71
+ ```
72
+ https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap
73
+ ```
74
+
75
+ 2. **Direct font file URL**:
76
+ ```
77
+ https://example.com/fonts/custom-font.woff2
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Example Themes
83
+
84
+ ### Dark Theme with Custom Font
85
+
86
+ ```json
87
+ {
88
+ "m": "d",
89
+ "bg": "222 84% 5%",
90
+ "fg": "210 40% 98%",
91
+ "p": "217 91% 60%",
92
+ "pf": "210 40% 98%",
93
+ "s": "217 33% 18%",
94
+ "sf": "210 40% 98%",
95
+ "bd": "217 33% 18%",
96
+ "r": "0.75rem",
97
+ "fn": "Inter",
98
+ "fu": "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
99
+ }
100
+ ```
101
+
102
+ Base64 encoded:
103
+
104
+ ```
105
+ eyJtIjoiZCIsImJnIjoiMjIyIDg0JSA1JSIsImZnIjoiMjEwIDQwJSA5OCUiLCJwIjoiMjE3IDkxJSA2MCUiLCJwZiI6IjIxMCA0MCUgOTglIiwicyI6IjIxNyAzMyUgMTglIiwic2YiOiIyMTAgNDAlIDk4JSIsImJkIjoiMjE3IDMzJSAxOCUiLCJyIjoiMC43NXJlbSIsImZuIjoiSW50ZXIiLCJmdSI6Imh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9SW50ZXI6d2dodEA0MDA7NTAwOzYwMDs3MDAmZGlzcGxheT1zd2FwIn0=
106
+ ```
107
+
108
+ ### Light Theme (Minimal)
109
+
110
+ ```json
111
+ {
112
+ "m": "l",
113
+ "p": "221 83% 53%",
114
+ "r": "0.5rem"
115
+ }
116
+ ```
117
+
118
+ Base64 encoded:
119
+
120
+ ```
121
+ eyJtIjoibCIsInAiOiIyMjEgODMlIDUzJSIsInIiOiIwLjVyZW0ifQ==
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Integration
127
+
128
+ ### Files Required
129
+
130
+ Copy these files to your SmartLinks app:
131
+
132
+ 1. **`src/utils/theme.ts`** - Core theme utilities
133
+ 2. **`src/hooks/useSmartLinksTheme.ts`** - React hook for state management
134
+
135
+ ### Setup Steps
136
+
137
+ #### 1. Update `index.html`
138
+
139
+ Add this inline script in `<body>` before your app script. **CRITICAL**: This handles both CSS font URLs (Google Fonts) AND direct font files (.otf, .ttf, .woff, .woff2):
140
+
141
+ ```html
142
+ <script>
143
+ // Early theme application to prevent flash
144
+ (function() {
145
+ try {
146
+ function getThemeParam() {
147
+ var search = window.location.search;
148
+ var hash = window.location.hash;
149
+
150
+ var searchParams = new URLSearchParams(search);
151
+ if (searchParams.get('theme')) return searchParams.get('theme');
152
+
153
+ if (hash && hash.indexOf('?') !== -1) {
154
+ var hashParams = new URLSearchParams(hash.substring(hash.indexOf('?')));
155
+ if (hashParams.get('theme')) return hashParams.get('theme');
156
+ }
157
+ return null;
158
+ }
159
+
160
+ function applyEarlyTheme(theme) {
161
+ var root = document.documentElement;
162
+
163
+ // Apply dark/light mode
164
+ if (theme.m === 'd') root.classList.add('dark');
165
+ else if (theme.m === 'l') root.classList.remove('dark');
166
+
167
+ // CSS variable mapping
168
+ var props = {
169
+ bg: '--background', fg: '--foreground',
170
+ p: '--primary', pf: '--primary-foreground',
171
+ s: '--secondary', sf: '--secondary-foreground',
172
+ a: '--accent', af: '--accent-foreground',
173
+ mt: '--muted', mf: '--muted-foreground',
174
+ bd: '--border', inp: '--input', ring: '--ring', r: '--radius'
175
+ };
176
+
177
+ // Apply CSS variables
178
+ for (var key in props) {
179
+ if (theme[key]) root.style.setProperty(props[key], theme[key]);
180
+ }
181
+
182
+ // Load custom font - IMPORTANT: handle both CSS and direct font files
183
+ if (theme.fn) {
184
+ root.style.setProperty('--font-family', "'" + theme.fn + "', system-ui, sans-serif");
185
+ if (theme.fu) {
186
+ var fontUrl = theme.fu;
187
+
188
+ // Check if it's a CSS file (Google Fonts, etc.)
189
+ if (fontUrl.indexOf('fonts.googleapis.com') !== -1 || fontUrl.indexOf('.css') !== -1) {
190
+ // CSS file - inject as stylesheet link
191
+ var link = document.createElement('link');
192
+ link.id = 'smartlinks-custom-font';
193
+ link.rel = 'stylesheet';
194
+ link.href = fontUrl;
195
+ document.head.appendChild(link);
196
+ } else {
197
+ // Direct font file (.otf, .ttf, .woff, .woff2) - inject @font-face
198
+ var format = 'opentype'; // default for .otf
199
+ var lowerUrl = fontUrl.toLowerCase();
200
+ if (lowerUrl.indexOf('.woff2') !== -1) format = 'woff2';
201
+ else if (lowerUrl.indexOf('.woff') !== -1) format = 'woff';
202
+ else if (lowerUrl.indexOf('.ttf') !== -1) format = 'truetype';
203
+ else if (lowerUrl.indexOf('.otf') !== -1) format = 'opentype';
204
+
205
+ var style = document.createElement('style');
206
+ style.id = 'smartlinks-custom-font';
207
+ style.textContent = "@font-face { font-family: '" + theme.fn + "'; src: url('" + fontUrl + "') format('" + format + "'); font-weight: 100 900; font-display: swap; }";
208
+ document.head.appendChild(style);
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ var themeParam = getThemeParam();
215
+ if (themeParam) {
216
+ var theme = JSON.parse(atob(themeParam));
217
+ applyEarlyTheme(theme);
218
+ }
219
+ } catch(e) {
220
+ console.warn('Early theme application failed:', e);
221
+ }
222
+ })();
223
+ </script>
224
+ ```
225
+
226
+ #### Key Font Loading Logic
227
+
228
+ The script must handle two types of font URLs differently:
229
+
230
+ | Font URL Type | Example | Loading Method |
231
+ | ------------------ | ---------------------------------------- | ----------------------------------- |
232
+ | Google Fonts / CSS | `fonts.googleapis.com/css2?family=Inter` | `<link rel="stylesheet">` |
233
+ | Direct font file | `cdn.example.com/font.otf` | `<style>@font-face { ... }</style>` |
234
+
235
+ **Font Format Mapping** (for `@font-face`):
236
+
237
+ | Extension | Format Value |
238
+ | --------- | ------------ |
239
+ | `.otf` | `opentype` |
240
+ | `.ttf` | `truetype` |
241
+ | `.woff` | `woff` |
242
+ | `.woff2` | `woff2` |
243
+
244
+ #### 2. Update `src/index.css`
245
+
246
+ Add the font-family variable:
247
+
248
+ ```css
249
+ :root {
250
+ --font-family: system-ui, -apple-system, sans-serif;
251
+ /* ... other variables ... */
252
+ }
253
+
254
+ body {
255
+ font-family: var(--font-family);
256
+ }
257
+ ```
258
+
259
+ #### 3. Use the Hook in App.tsx
260
+
261
+ ```tsx
262
+ import { useSmartLinksTheme } from '@/hooks/useSmartLinksTheme';
263
+
264
+ const AppContent = () => {
265
+ // Initialize theme system (handles URL params and postMessage)
266
+ useSmartLinksTheme();
267
+
268
+ // ... rest of your app
269
+ };
270
+ ```
271
+
272
+ ---
273
+
274
+ ## PostMessage Protocol
275
+
276
+ ### Theme Push (Parent → Iframe)
277
+
278
+ ```javascript
279
+ iframe.contentWindow.postMessage({
280
+ type: 'smartlinks-theme',
281
+ theme: { m: 'd', p: '217 91% 60%' }
282
+ }, '*');
283
+ ```
284
+
285
+ ### Acknowledgment (Iframe → Parent)
286
+
287
+ The app automatically sends acknowledgment when theme is applied:
288
+
289
+ ```javascript
290
+ // Listen in parent
291
+ window.addEventListener('message', (event) => {
292
+ if (event.data.type === 'smartlinks-theme-applied') {
293
+ console.log('Theme applied:', event.data.success);
294
+ }
295
+ });
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Utilities
301
+
302
+ ### Encode Theme (for testing)
303
+
304
+ ```typescript
305
+ import { encodeTheme } from '@/utils/theme';
306
+
307
+ const theme = { m: 'd', p: '217 91% 60%' };
308
+ const encoded = encodeTheme(theme);
309
+ // Use: ?theme=encoded
310
+ ```
311
+
312
+ ### Manual Theme Application
313
+
314
+ ```typescript
315
+ import { applyTheme } from '@/utils/theme';
316
+
317
+ applyTheme({
318
+ m: 'd',
319
+ p: '217 91% 60%',
320
+ fn: 'Inter',
321
+ fu: 'https://fonts.googleapis.com/css2?family=Inter'
322
+ });
323
+ ```
324
+
325
+ ---
326
+
327
+ ## URL Length Considerations
328
+
329
+ - Safe URL limit: ~2,000 characters
330
+ - Typical theme JSON: 300-500 characters
331
+ - Base64 overhead: ~33% increase
332
+ - **Result**: Standard themes safely fit within limits
333
+
334
+ To minimize size:
335
+
336
+ - Only include properties that differ from defaults
337
+ - Use short HSL values where possible
338
+ - Omit font URL if using system fonts