snice 3.7.0 → 3.9.0
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 +2 -2
- package/bin/snice.js +11 -5
- package/bin/templates/CLAUDE.md +5 -5
- package/bin/templates/pwa/README.md +31 -16
- package/bin/templates/pwa/index.html +0 -1
- package/bin/templates/pwa/package.json +9 -2
- package/bin/templates/pwa/src/fetcher.ts +15 -0
- package/bin/templates/pwa/src/guards/auth.ts +6 -4
- package/bin/templates/pwa/src/middleware/auth.ts +7 -6
- package/bin/templates/pwa/src/middleware/error.ts +16 -5
- package/bin/templates/pwa/src/middleware/retry.ts +7 -3
- package/bin/templates/pwa/src/pages/dashboard.ts +4 -3
- package/bin/templates/pwa/src/pages/login.ts +7 -7
- package/bin/templates/pwa/src/pages/notifications.ts +2 -2
- package/bin/templates/pwa/src/pages/profile.ts +9 -8
- package/bin/templates/pwa/src/router.ts +8 -4
- package/bin/templates/pwa/src/types/auth.ts +1 -1
- package/bin/templates/pwa/tests/helpers/test-utils.ts +84 -0
- package/bin/templates/pwa/tests/middleware/auth.test.ts +67 -0
- package/bin/templates/pwa/tests/middleware/error.test.ts +105 -0
- package/bin/templates/pwa/tests/middleware/retry.test.ts +103 -0
- package/bin/templates/pwa/tests/services/auth.test.ts +89 -0
- package/bin/templates/pwa/tests/services/jwt.test.ts +76 -0
- package/bin/templates/pwa/tests/services/storage.test.ts +69 -0
- package/bin/templates/{social/vite.config.ts → pwa/vitest.config.ts} +12 -17
- package/dist/components/file-gallery/snice-file-gallery.d.ts +87 -0
- package/dist/components/file-gallery/snice-file-gallery.js +892 -0
- package/dist/components/file-gallery/snice-file-gallery.js.map +1 -0
- package/dist/components/file-gallery/snice-file-gallery.types.d.ts +72 -0
- package/dist/components/qr-reader/qr-decoder.d.ts +20 -0
- package/dist/components/qr-reader/qr-decoder.js +49 -0
- package/dist/components/qr-reader/qr-decoder.js.map +1 -0
- package/dist/components/qr-reader/qr-worker.d.ts +6 -0
- package/dist/components/qr-reader/qr-worker.js +64 -0
- package/dist/components/qr-reader/qr-worker.js.map +1 -0
- package/dist/components/qr-reader/snice-qr-reader.d.ts +39 -0
- package/dist/components/qr-reader/snice-qr-reader.js +436 -0
- package/dist/components/qr-reader/snice-qr-reader.js.map +1 -0
- package/dist/components/qr-reader/snice-qr-reader.types.d.ts +17 -0
- package/dist/components/qr-reader/zxing-reader.mjs +1582 -0
- package/dist/components/qr-reader/zxing-share.mjs +305 -0
- package/dist/components/qr-reader/zxing_reader.wasm +0 -0
- package/dist/components/zxing-reader-B3Rfebg9.js +1771 -0
- package/dist/components/zxing-reader-B3Rfebg9.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/docs/ai/README.md +1 -1
- package/docs/ai/components/file-gallery.md +206 -0
- package/docs/ai/components/qr-reader.md +80 -0
- package/docs/ai/patterns.md +1 -1
- package/docs/components/file-gallery.md +692 -0
- package/docs/components/qr-reader.md +327 -0
- package/docs/routing.md +9 -8
- package/package.json +1 -1
- package/bin/templates/pwa/public/manifest.json +0 -24
- package/bin/templates/pwa/src/utils/fetch.ts +0 -39
- package/bin/templates/social/README.md +0 -42
- package/bin/templates/social/global.d.ts +0 -14
- package/bin/templates/social/index.html +0 -13
- package/bin/templates/social/package.json +0 -21
- package/bin/templates/social/public/vite.svg +0 -1
- package/bin/templates/social/src/main.ts +0 -33
- package/bin/templates/social/src/pages/feed-page.ts +0 -111
- package/bin/templates/social/src/pages/messages-page.ts +0 -102
- package/bin/templates/social/src/pages/not-found-page.ts +0 -46
- package/bin/templates/social/src/pages/profile-page.ts +0 -99
- package/bin/templates/social/src/pages/settings-page.ts +0 -119
- package/bin/templates/social/src/router.ts +0 -9
- package/bin/templates/social/src/styles/global.css +0 -156
- package/bin/templates/social/tsconfig.json +0 -22
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# QR Reader Component
|
|
2
|
+
|
|
3
|
+
`<snice-qr-reader>` provides QR code scanning functionality using device cameras with WebAssembly-based QR detection.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Camera Access**: Use front or back camera for QR code scanning
|
|
8
|
+
- **Real-time Detection**: Continuous scanning with ZXing WASM decoder
|
|
9
|
+
- **Auto-start**: Optional automatic camera activation on mount
|
|
10
|
+
- **Event-based**: Emits events for successful scans, errors, and camera status
|
|
11
|
+
- **Responsive**: Adapts to container size with proper aspect ratio
|
|
12
|
+
- **Configurable Speed**: Adjust scan speed for performance vs detection speed trade-off
|
|
13
|
+
|
|
14
|
+
## Basic Usage
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<snice-qr-reader auto-start></snice-qr-reader>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
const reader = document.querySelector('snice-qr-reader');
|
|
21
|
+
|
|
22
|
+
reader.addEventListener('@snice/qr-scan', (event) => {
|
|
23
|
+
console.log('QR Code:', event.detail.data);
|
|
24
|
+
});
|
|
25
|
+
</script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Properties
|
|
29
|
+
|
|
30
|
+
### `auto-start`
|
|
31
|
+
- **Type**: `boolean`
|
|
32
|
+
- **Default**: `false`
|
|
33
|
+
- **Description**: Automatically start scanning when component is mounted
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<snice-qr-reader auto-start></snice-qr-reader>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### `camera`
|
|
40
|
+
- **Type**: `'front' | 'back'`
|
|
41
|
+
- **Default**: `'back'`
|
|
42
|
+
- **Description**: Which camera to use for scanning
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<snice-qr-reader camera="front"></snice-qr-reader>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `pick-first`
|
|
49
|
+
- **Type**: `boolean`
|
|
50
|
+
- **Default**: `false`
|
|
51
|
+
- **Description**: Scan continuously at maximum speed until first successful QR code detection, then stop and shut down camera. Ignores `scan-speed` setting.
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<!-- Scan at max speed until first QR hit, then stop -->
|
|
55
|
+
<snice-qr-reader pick-first></snice-qr-reader>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### `manual-snap`
|
|
59
|
+
- **Type**: `boolean`
|
|
60
|
+
- **Default**: `false`
|
|
61
|
+
- **Description**: Photo snapshot mode. Opens camera as a live viewfinder, and you manually trigger snapshot attempts by clicking the snap button.
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<!-- Manual photo snapshot mode -->
|
|
65
|
+
<snice-qr-reader manual-snap></snice-qr-reader>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `scan-speed`
|
|
69
|
+
- **Type**: `number`
|
|
70
|
+
- **Default**: `3`
|
|
71
|
+
- **Description**: Scan speed from 1-10. Higher values = faster QR detection but more CPU usage. Lower values = slower detection but better performance. **Note**: Ignored when `pick-first` is enabled (always scans at max speed).
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<!-- Slow scan (better performance) -->
|
|
75
|
+
<snice-qr-reader scan-speed="1"></snice-qr-reader>
|
|
76
|
+
|
|
77
|
+
<!-- Medium scan (balanced, default) -->
|
|
78
|
+
<snice-qr-reader scan-speed="3"></snice-qr-reader>
|
|
79
|
+
|
|
80
|
+
<!-- Fast scan (faster detection) -->
|
|
81
|
+
<snice-qr-reader scan-speed="10"></snice-qr-reader>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Methods
|
|
85
|
+
|
|
86
|
+
### `start()`
|
|
87
|
+
Start the camera and begin scanning for QR codes (or open camera for manual-snap mode).
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
const reader = document.querySelector('snice-qr-reader');
|
|
91
|
+
reader.start();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `stop()`
|
|
95
|
+
Stop scanning and release the camera.
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
reader.stop();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `snap()`
|
|
102
|
+
Take a snapshot and check for QR codes (manual-snap mode only).
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
const result = await reader.snap(); // Returns QR data or null
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Events
|
|
109
|
+
|
|
110
|
+
### `@snice/qr-scan`
|
|
111
|
+
Fired when a QR code is successfully detected.
|
|
112
|
+
|
|
113
|
+
**Detail Properties:**
|
|
114
|
+
- `data` (string): The decoded QR code content
|
|
115
|
+
- `timestamp` (number): Unix timestamp of the scan
|
|
116
|
+
- `reader` (SniceQRReader): Reference to the component
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
reader.addEventListener('@snice/qr-scan', (event) => {
|
|
120
|
+
console.log('Data:', event.detail.data);
|
|
121
|
+
console.log('Time:', new Date(event.detail.timestamp));
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `@snice/qr-error`
|
|
126
|
+
Fired when an error occurs during scanning.
|
|
127
|
+
|
|
128
|
+
**Detail Properties:**
|
|
129
|
+
- `error` (any): Error object or message
|
|
130
|
+
- `reader` (SniceQRReader): Reference to the component
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
reader.addEventListener('@snice/qr-error', (event) => {
|
|
134
|
+
console.error('Error:', event.detail.error);
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `@snice/camera-ready`
|
|
139
|
+
Fired when the camera has been successfully initialized and is ready to scan.
|
|
140
|
+
|
|
141
|
+
**Detail Properties:**
|
|
142
|
+
- `reader` (SniceQRReader): Reference to the component
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
reader.addEventListener('@snice/camera-ready', (event) => {
|
|
146
|
+
console.log('Camera is ready');
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `@snice/camera-error`
|
|
151
|
+
Fired when camera initialization fails.
|
|
152
|
+
|
|
153
|
+
**Detail Properties:**
|
|
154
|
+
- `error` (any): Error object or message
|
|
155
|
+
- `reader` (SniceQRReader): Reference to the component
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
reader.addEventListener('@snice/camera-error', (event) => {
|
|
159
|
+
console.error('Camera error:', event.detail.error);
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Examples
|
|
164
|
+
|
|
165
|
+
### Manual Control
|
|
166
|
+
|
|
167
|
+
```html
|
|
168
|
+
<snice-qr-reader id="reader"></snice-qr-reader>
|
|
169
|
+
<button onclick="startReading()">Start</button>
|
|
170
|
+
<button onclick="stopReading()">Stop</button>
|
|
171
|
+
<div id="result"></div>
|
|
172
|
+
|
|
173
|
+
<script>
|
|
174
|
+
const reader = document.getElementById('reader');
|
|
175
|
+
const result = document.getElementById('result');
|
|
176
|
+
|
|
177
|
+
function startReading() {
|
|
178
|
+
reader.start();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function stopReading() {
|
|
182
|
+
reader.stop();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
reader.addEventListener('@snice/qr-scan', (e) => {
|
|
186
|
+
result.textContent = `Scanned: ${e.detail.data}`;
|
|
187
|
+
});
|
|
188
|
+
</script>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Pick-First (One-Shot)
|
|
192
|
+
|
|
193
|
+
```html
|
|
194
|
+
<snice-qr-reader id="scanner" pick-first></snice-qr-reader>
|
|
195
|
+
|
|
196
|
+
<script>
|
|
197
|
+
const scanner = document.getElementById('scanner');
|
|
198
|
+
|
|
199
|
+
scanner.addEventListener('@snice/qr-scan', (e) => {
|
|
200
|
+
// Process the scan
|
|
201
|
+
processQRCode(e.detail.data);
|
|
202
|
+
|
|
203
|
+
// Scanner automatically stops and shuts down camera
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Start scanning at max speed
|
|
207
|
+
scanner.start();
|
|
208
|
+
</script>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Manual Snapshot
|
|
212
|
+
|
|
213
|
+
```html
|
|
214
|
+
<snice-qr-reader id="snapReader" manual-snap></snice-qr-reader>
|
|
215
|
+
<button id="snapBtn">Take Photo</button>
|
|
216
|
+
|
|
217
|
+
<script>
|
|
218
|
+
const reader = document.getElementById('snapReader');
|
|
219
|
+
const btn = document.getElementById('snapBtn');
|
|
220
|
+
|
|
221
|
+
// Open camera
|
|
222
|
+
reader.start();
|
|
223
|
+
|
|
224
|
+
// Manually trigger snapshot
|
|
225
|
+
btn.addEventListener('click', async () => {
|
|
226
|
+
const result = await reader.snap();
|
|
227
|
+
if (result) {
|
|
228
|
+
console.log('QR Code:', result);
|
|
229
|
+
} else {
|
|
230
|
+
console.log('No QR code found');
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
</script>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Front Camera
|
|
237
|
+
|
|
238
|
+
```html
|
|
239
|
+
<snice-qr-reader camera="front" auto-start></snice-qr-reader>
|
|
240
|
+
|
|
241
|
+
<script>
|
|
242
|
+
// Useful for self-scanning scenarios
|
|
243
|
+
document.querySelector('snice-qr-reader')
|
|
244
|
+
.addEventListener('@snice/qr-scan', (e) => {
|
|
245
|
+
validateTicket(e.detail.data);
|
|
246
|
+
});
|
|
247
|
+
</script>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Error Handling
|
|
251
|
+
|
|
252
|
+
```html
|
|
253
|
+
<snice-qr-reader id="reader" auto-start></snice-qr-reader>
|
|
254
|
+
<div id="status"></div>
|
|
255
|
+
|
|
256
|
+
<script>
|
|
257
|
+
const reader = document.getElementById('reader');
|
|
258
|
+
const status = document.getElementById('status');
|
|
259
|
+
|
|
260
|
+
reader.addEventListener('@snice/qr-scan', (e) => {
|
|
261
|
+
status.textContent = `✓ Scanned: ${e.detail.data}`;
|
|
262
|
+
status.style.color = 'green';
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
reader.addEventListener('@snice/qr-error', (e) => {
|
|
266
|
+
status.textContent = `✗ Error: ${e.detail.error}`;
|
|
267
|
+
status.style.color = 'red';
|
|
268
|
+
|
|
269
|
+
// Retry after error
|
|
270
|
+
setTimeout(() => reader.start(), 2000);
|
|
271
|
+
});
|
|
272
|
+
</script>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Styling
|
|
276
|
+
|
|
277
|
+
The component uses CSS custom properties for theming:
|
|
278
|
+
|
|
279
|
+
```css
|
|
280
|
+
snice-qr-reader {
|
|
281
|
+
--qr-reader-border: var(--snice-color-border, #e5e7eb);
|
|
282
|
+
--qr-reader-bg: var(--snice-color-bg, #ffffff);
|
|
283
|
+
--qr-reader-text: var(--snice-color-text, #1f2937);
|
|
284
|
+
|
|
285
|
+
/* Size */
|
|
286
|
+
width: 100%;
|
|
287
|
+
max-width: 600px;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Browser Support
|
|
292
|
+
|
|
293
|
+
- Requires `getUserMedia` API support
|
|
294
|
+
- Uses WebAssembly for QR detection (ZXing)
|
|
295
|
+
- Works on modern browsers (Chrome, Firefox, Safari, Edge)
|
|
296
|
+
- Mobile browser camera access requires HTTPS
|
|
297
|
+
|
|
298
|
+
## Implementation Details
|
|
299
|
+
|
|
300
|
+
### QR Detection
|
|
301
|
+
Uses ZXing-C++ WebAssembly build for fast, accurate QR code detection:
|
|
302
|
+
- **License**: Apache 2.0 (ZXing-C++) + MIT (zxing-wasm)
|
|
303
|
+
- **Format Support**: QR Code, Micro QR Code
|
|
304
|
+
- **Performance**: ~60fps scanning on modern devices
|
|
305
|
+
|
|
306
|
+
### Camera Management
|
|
307
|
+
- Requests user permission for camera access
|
|
308
|
+
- Automatically releases camera when component is destroyed
|
|
309
|
+
- Handles camera errors gracefully with fallback messages
|
|
310
|
+
|
|
311
|
+
### Privacy
|
|
312
|
+
- Camera feed stays in the browser (no uploads)
|
|
313
|
+
- QR data is only emitted via events
|
|
314
|
+
- Camera is released when scanning stops
|
|
315
|
+
|
|
316
|
+
## Related Components
|
|
317
|
+
|
|
318
|
+
- `<snice-qr-code>` - Generate QR codes
|
|
319
|
+
- `<snice-camera>` - General camera capture component
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
QR detection powered by:
|
|
324
|
+
- **ZXing-C++**: Apache License 2.0
|
|
325
|
+
- **zxing-wasm**: MIT License
|
|
326
|
+
|
|
327
|
+
See `components/qr-reader/ZXING-LICENSE` for full license text.
|
package/docs/routing.md
CHANGED
|
@@ -207,13 +207,14 @@ class DashboardPage extends HTMLElement {
|
|
|
207
207
|
The Context object passed to `@context()` methods has the following structure:
|
|
208
208
|
|
|
209
209
|
```typescript
|
|
210
|
-
interface Context
|
|
211
|
-
application:
|
|
210
|
+
interface Context {
|
|
211
|
+
application: AppContext; // Your router context (e.g., { user, theme, config })
|
|
212
212
|
navigation: {
|
|
213
213
|
placards: Placard[]; // All page placards
|
|
214
214
|
route: string; // Current route name
|
|
215
215
|
params: Record<string, string>; // Route parameters
|
|
216
216
|
};
|
|
217
|
+
fetch: typeof globalThis.fetch; // Fetch function with middleware support
|
|
217
218
|
update(): void; // Notify all subscribers of changes
|
|
218
219
|
}
|
|
219
220
|
```
|
|
@@ -223,10 +224,10 @@ interface Context<T = any> {
|
|
|
223
224
|
```typescript
|
|
224
225
|
@page({ tag: 'user-page', routes: ['/users/:userId'] })
|
|
225
226
|
class UserPage extends HTMLElement {
|
|
226
|
-
private ctx?: Context
|
|
227
|
+
private ctx?: Context;
|
|
227
228
|
|
|
228
229
|
@context()
|
|
229
|
-
handleContext(ctx: Context
|
|
230
|
+
handleContext(ctx: Context) {
|
|
230
231
|
this.ctx = ctx;
|
|
231
232
|
|
|
232
233
|
// Access application state
|
|
@@ -250,10 +251,10 @@ When you modify the application context, call `update()` to notify all subscribe
|
|
|
250
251
|
```typescript
|
|
251
252
|
@page({ tag: 'settings-page', routes: ['/settings'] })
|
|
252
253
|
class SettingsPage extends HTMLElement {
|
|
253
|
-
private ctx?: Context
|
|
254
|
+
private ctx?: Context;
|
|
254
255
|
|
|
255
256
|
@context()
|
|
256
|
-
handleContext(ctx: Context
|
|
257
|
+
handleContext(ctx: Context) {
|
|
257
258
|
this.ctx = ctx;
|
|
258
259
|
this.requestRender();
|
|
259
260
|
}
|
|
@@ -1066,7 +1067,7 @@ class DashboardPage extends HTMLElement {
|
|
|
1066
1067
|
private appContext?: AppContext;
|
|
1067
1068
|
|
|
1068
1069
|
@context()
|
|
1069
|
-
handleContext(ctx: Context
|
|
1070
|
+
handleContext(ctx: Context) {
|
|
1070
1071
|
this.appContext = ctx.application;
|
|
1071
1072
|
this.requestRender();
|
|
1072
1073
|
}
|
|
@@ -1093,7 +1094,7 @@ class LoginPage extends HTMLElement {
|
|
|
1093
1094
|
private appContext?: AppContext;
|
|
1094
1095
|
|
|
1095
1096
|
@context()
|
|
1096
|
-
handleContext(ctx: Context
|
|
1097
|
+
handleContext(ctx: Context) {
|
|
1097
1098
|
this.appContext = ctx.application;
|
|
1098
1099
|
}
|
|
1099
1100
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snice",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{projectName}}",
|
|
3
|
-
"short_name": "{{projectName}}",
|
|
4
|
-
"description": "PWA built with Snice",
|
|
5
|
-
"start_url": "/",
|
|
6
|
-
"display": "standalone",
|
|
7
|
-
"background_color": "#ffffff",
|
|
8
|
-
"theme_color": "#6366f1",
|
|
9
|
-
"orientation": "portrait-primary",
|
|
10
|
-
"icons": [
|
|
11
|
-
{
|
|
12
|
-
"src": "/icons/icon-192.png",
|
|
13
|
-
"sizes": "192x192",
|
|
14
|
-
"type": "image/png",
|
|
15
|
-
"purpose": "any maskable"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"src": "/icons/icon-512.png",
|
|
19
|
-
"sizes": "512x512",
|
|
20
|
-
"type": "image/png",
|
|
21
|
-
"purpose": "any maskable"
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export type Middleware = (
|
|
2
|
-
url: string,
|
|
3
|
-
options: RequestInit,
|
|
4
|
-
next: () => Promise<Response>
|
|
5
|
-
) => Promise<Response>;
|
|
6
|
-
|
|
7
|
-
export type FetchConfig = {
|
|
8
|
-
baseURL?: string;
|
|
9
|
-
middleware?: Middleware[];
|
|
10
|
-
headers?: Record<string, string>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function createFetch(config: FetchConfig = {}) {
|
|
14
|
-
return async (url: string, options: RequestInit = {}): Promise<Response> => {
|
|
15
|
-
const fullURL = config.baseURL ? `${config.baseURL}${url}` : url;
|
|
16
|
-
|
|
17
|
-
const execute = async (): Promise<Response> => {
|
|
18
|
-
return fetch(fullURL, {
|
|
19
|
-
...options,
|
|
20
|
-
headers: {
|
|
21
|
-
...config.headers,
|
|
22
|
-
...options.headers,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Chain middleware (reverse order so first middleware wraps execution)
|
|
28
|
-
let chain = execute;
|
|
29
|
-
if (config.middleware) {
|
|
30
|
-
for (let i = config.middleware.length - 1; i >= 0; i--) {
|
|
31
|
-
const middleware = config.middleware[i];
|
|
32
|
-
const next = chain;
|
|
33
|
-
chain = () => middleware(fullURL, options, next);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return chain();
|
|
38
|
-
};
|
|
39
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Social Media Sample App
|
|
2
|
-
|
|
3
|
-
A sample social media application built with Snice showcasing various components.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
This template demonstrates:
|
|
8
|
-
|
|
9
|
-
### Components Used
|
|
10
|
-
- **snice-card** - Post containers and content cards
|
|
11
|
-
- **snice-avatar** - User profile pictures
|
|
12
|
-
- **snice-button** - Action buttons throughout
|
|
13
|
-
- **snice-badge** - Status indicators and labels
|
|
14
|
-
- **snice-input** - Form inputs in settings
|
|
15
|
-
- **snice-textarea** - Multi-line text input
|
|
16
|
-
- **snice-switch** - Toggle settings
|
|
17
|
-
- **snice-tabs** - Tabbed content on profile
|
|
18
|
-
- **snice-stat** - Statistics display
|
|
19
|
-
- **snice-layout-sidebar** - Sidebar navigation layout
|
|
20
|
-
|
|
21
|
-
### Pages
|
|
22
|
-
- **Feed** (`/`) - Social feed with posts showing cards, avatars, and badges
|
|
23
|
-
- **Profile** (`/profile`) - User profile with stats and tabs
|
|
24
|
-
- **Messages** (`/messages`) - Message list with avatars
|
|
25
|
-
- **Settings** (`/settings`) - Settings page with forms and switches
|
|
26
|
-
|
|
27
|
-
## Getting Started
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npm install
|
|
31
|
-
npm run dev
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Build for Production
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npm run build
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Customize
|
|
41
|
-
|
|
42
|
-
Feel free to modify the pages, add new components, or change the styling to fit your needs.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
declare module '*.css' {
|
|
2
|
-
const content: string;
|
|
3
|
-
export default content;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
declare module '*.css?inline' {
|
|
7
|
-
const content: string;
|
|
8
|
-
export default content;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
declare module '*.html' {
|
|
12
|
-
const content: string;
|
|
13
|
-
export default content;
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{{projectName}}</title>
|
|
7
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div id="app"></div>
|
|
11
|
-
<script type="module" src="/src/main.ts"></script>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{projectName}}",
|
|
3
|
-
"private": true,
|
|
4
|
-
"version": "0.0.0",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "vite",
|
|
8
|
-
"build": "tsc && vite build",
|
|
9
|
-
"type-check": "tsc --noEmit"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"snice": "^3.0.0"
|
|
13
|
-
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@types/node": "^20.0.0",
|
|
16
|
-
"terser": "^5.24.0",
|
|
17
|
-
"typescript": "^5.3.3",
|
|
18
|
-
"unplugin-swc": "^1.5.7",
|
|
19
|
-
"vite": "^5.0.10"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { initialize } from './router';
|
|
2
|
-
import './styles/global.css';
|
|
3
|
-
|
|
4
|
-
// Import theme
|
|
5
|
-
import 'snice/components/theme/theme.css';
|
|
6
|
-
|
|
7
|
-
// Import layout
|
|
8
|
-
import 'snice/components/layout/snice-layout-sidebar';
|
|
9
|
-
|
|
10
|
-
// Import snice components
|
|
11
|
-
import 'snice/components/card/snice-card';
|
|
12
|
-
import 'snice/components/avatar/snice-avatar';
|
|
13
|
-
import 'snice/components/button/snice-button';
|
|
14
|
-
import 'snice/components/badge/snice-badge';
|
|
15
|
-
import 'snice/components/input/snice-input';
|
|
16
|
-
import 'snice/components/textarea/snice-textarea';
|
|
17
|
-
import 'snice/components/switch/snice-switch';
|
|
18
|
-
import 'snice/components/tabs/snice-tabs';
|
|
19
|
-
import 'snice/components/tabs/snice-tab';
|
|
20
|
-
import 'snice/components/tabs/snice-tab-panel';
|
|
21
|
-
import 'snice/components/stat/snice-stat';
|
|
22
|
-
import 'snice/components/list/snice-list';
|
|
23
|
-
import 'snice/components/nav/snice-nav';
|
|
24
|
-
|
|
25
|
-
// Import pages
|
|
26
|
-
import './pages/feed-page';
|
|
27
|
-
import './pages/profile-page';
|
|
28
|
-
import './pages/messages-page';
|
|
29
|
-
import './pages/settings-page';
|
|
30
|
-
import './pages/not-found-page';
|
|
31
|
-
|
|
32
|
-
// Initialize router
|
|
33
|
-
initialize();
|