snice 3.3.0 → 3.4.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.
Files changed (130) hide show
  1. package/bin/snice.js +56 -11
  2. package/bin/templates/CLAUDE.md +138 -0
  3. package/bin/templates/base/src/components/counter-button.ts +2 -2
  4. package/bin/templates/base/src/components/feature-card.ts +59 -0
  5. package/bin/templates/base/src/components/feature-card.types.ts +5 -0
  6. package/bin/templates/base/src/main.ts +7 -2
  7. package/bin/templates/base/src/pages/about-page.ts +8 -5
  8. package/bin/templates/base/src/pages/home-page.ts +47 -28
  9. package/bin/templates/base/src/pages/not-found-page.ts +7 -4
  10. package/bin/templates/base/src/types/api-response.ts +5 -0
  11. package/bin/templates/base/src/types/status.ts +1 -0
  12. package/bin/templates/base/src/types/theme.ts +1 -0
  13. package/bin/templates/base/src/types/user.ts +5 -0
  14. package/bin/templates/social/README.md +42 -0
  15. package/bin/templates/social/global.d.ts +14 -0
  16. package/bin/templates/social/index.html +13 -0
  17. package/bin/templates/social/package.json +21 -0
  18. package/bin/templates/social/public/vite.svg +1 -0
  19. package/bin/templates/social/src/main.ts +33 -0
  20. package/bin/templates/social/src/pages/feed-page.ts +111 -0
  21. package/bin/templates/social/src/pages/messages-page.ts +102 -0
  22. package/bin/templates/social/src/pages/not-found-page.ts +46 -0
  23. package/bin/templates/social/src/pages/profile-page.ts +99 -0
  24. package/bin/templates/social/src/pages/settings-page.ts +119 -0
  25. package/bin/templates/social/src/router.ts +9 -0
  26. package/bin/templates/social/src/styles/global.css +147 -0
  27. package/bin/templates/social/tsconfig.json +22 -0
  28. package/bin/templates/social/vite.config.ts +38 -0
  29. package/dist/components/accordion/snice-accordion-item.js +1 -1
  30. package/dist/components/accordion/snice-accordion-item.js.map +1 -1
  31. package/dist/components/accordion/snice-accordion.js +1 -1
  32. package/dist/components/accordion/snice-accordion.js.map +1 -1
  33. package/dist/components/actions/snice-actions.js +4 -4
  34. package/dist/components/actions/snice-actions.js.map +1 -1
  35. package/dist/components/audio-recorder/snice-audio-recorder.js +6 -6
  36. package/dist/components/audio-recorder/snice-audio-recorder.js.map +1 -1
  37. package/dist/components/avatar/snice-avatar.js +1 -1
  38. package/dist/components/avatar/snice-avatar.js.map +1 -1
  39. package/dist/components/badge/snice-badge.js +1 -1
  40. package/dist/components/badge/snice-badge.js.map +1 -1
  41. package/dist/components/breadcrumbs/snice-breadcrumbs.js +3 -3
  42. package/dist/components/breadcrumbs/snice-breadcrumbs.js.map +1 -1
  43. package/dist/components/calendar/snice-calendar.js +3 -3
  44. package/dist/components/calendar/snice-calendar.js.map +1 -1
  45. package/dist/components/camera/snice-camera.js +1 -1
  46. package/dist/components/camera/snice-camera.js.map +1 -1
  47. package/dist/components/card/snice-card.js +1 -1
  48. package/dist/components/card/snice-card.js.map +1 -1
  49. package/dist/components/carousel/snice-carousel.js +2 -2
  50. package/dist/components/carousel/snice-carousel.js.map +1 -1
  51. package/dist/components/chart/snice-chart.js +23 -17
  52. package/dist/components/chart/snice-chart.js.map +1 -1
  53. package/dist/components/chat/snice-chat.js +9 -9
  54. package/dist/components/chat/snice-chat.js.map +1 -1
  55. package/dist/components/code-block/snice-code-block.js +2 -2
  56. package/dist/components/code-block/snice-code-block.js.map +1 -1
  57. package/dist/components/color-display/snice-color-display.js +1 -1
  58. package/dist/components/color-display/snice-color-display.js.map +1 -1
  59. package/dist/components/command-palette/snice-command-palette.js +3 -3
  60. package/dist/components/command-palette/snice-command-palette.js.map +1 -1
  61. package/dist/components/divider/snice-divider.js +2 -2
  62. package/dist/components/divider/snice-divider.js.map +1 -1
  63. package/dist/components/doc/snice-doc.js +4 -4
  64. package/dist/components/doc/snice-doc.js.map +1 -1
  65. package/dist/components/draw/snice-draw.js +1 -1
  66. package/dist/components/draw/snice-draw.js.map +1 -1
  67. package/dist/components/drawer/snice-drawer.js +1 -1
  68. package/dist/components/drawer/snice-drawer.js.map +1 -1
  69. package/dist/components/gantt/snice-gantt.js +2 -2
  70. package/dist/components/gantt/snice-gantt.js.map +1 -1
  71. package/dist/components/image/snice-image.js +2 -2
  72. package/dist/components/image/snice-image.js.map +1 -1
  73. package/dist/components/kanban/snice-kanban.js +2 -2
  74. package/dist/components/kanban/snice-kanban.js.map +1 -1
  75. package/dist/components/kpi/snice-kpi.js +1 -1
  76. package/dist/components/kpi/snice-kpi.js.map +1 -1
  77. package/dist/components/link/snice-link.js +1 -1
  78. package/dist/components/link/snice-link.js.map +1 -1
  79. package/dist/components/list/snice-list-item.js +1 -1
  80. package/dist/components/list/snice-list-item.js.map +1 -1
  81. package/dist/components/list/snice-list.js +18 -12
  82. package/dist/components/list/snice-list.js.map +1 -1
  83. package/dist/components/list/snice-list.types.d.ts +7 -25
  84. package/dist/components/location/snice-location.js +1 -1
  85. package/dist/components/location/snice-location.js.map +1 -1
  86. package/dist/components/menu/snice-menu-divider.js +1 -1
  87. package/dist/components/menu/snice-menu-divider.js.map +1 -1
  88. package/dist/components/menu/snice-menu-item.js +1 -1
  89. package/dist/components/menu/snice-menu-item.js.map +1 -1
  90. package/dist/components/menu/snice-menu.js +1 -1
  91. package/dist/components/menu/snice-menu.js.map +1 -1
  92. package/dist/components/progress/snice-progress.js +2 -2
  93. package/dist/components/progress/snice-progress.js.map +1 -1
  94. package/dist/components/qr-code/qrcode.js +11 -1
  95. package/dist/components/qr-code/qrcode.js.map +1 -1
  96. package/dist/components/qr-code/snice-qr-code.js +9 -2
  97. package/dist/components/qr-code/snice-qr-code.js.map +1 -1
  98. package/dist/components/select/snice-select.js +1 -1
  99. package/dist/components/select/snice-select.js.map +1 -1
  100. package/dist/components/skeleton/snice-skeleton.js +1 -1
  101. package/dist/components/skeleton/snice-skeleton.js.map +1 -1
  102. package/dist/components/sparkline/snice-sparkline.js +1 -1
  103. package/dist/components/sparkline/snice-sparkline.js.map +1 -1
  104. package/dist/components/spinner/snice-spinner.js +1 -1
  105. package/dist/components/spinner/snice-spinner.js.map +1 -1
  106. package/dist/components/split-pane/snice-split-pane.js +1 -1
  107. package/dist/components/split-pane/snice-split-pane.js.map +1 -1
  108. package/dist/components/stat/snice-stat.js +1 -1
  109. package/dist/components/stat/snice-stat.js.map +1 -1
  110. package/dist/components/stepper/snice-stepper-panel.js +1 -1
  111. package/dist/components/stepper/snice-stepper-panel.js.map +1 -1
  112. package/dist/components/stepper/snice-stepper.js +2 -2
  113. package/dist/components/stepper/snice-stepper.js.map +1 -1
  114. package/dist/components/theme/theme.css +234 -0
  115. package/dist/components/timeline/snice-timeline.js +2 -2
  116. package/dist/components/timeline/snice-timeline.js.map +1 -1
  117. package/dist/components/tree/snice-tree-item.js +1 -1
  118. package/dist/components/tree/snice-tree-item.js.map +1 -1
  119. package/dist/components/tree/snice-tree.js +1 -1
  120. package/dist/components/tree/snice-tree.js.map +1 -1
  121. package/dist/components/virtual-scroller/snice-virtual-scroller.js +3 -3
  122. package/dist/components/virtual-scroller/snice-virtual-scroller.js.map +1 -1
  123. package/dist/index.cjs +1 -1
  124. package/dist/index.esm.js +1 -1
  125. package/dist/index.iife.js +1 -1
  126. package/dist/symbols.cjs +1 -1
  127. package/dist/symbols.esm.js +1 -1
  128. package/dist/transitions.cjs +1 -1
  129. package/dist/transitions.esm.js +1 -1
  130. package/package.json +2 -1
package/bin/snice.js CHANGED
@@ -11,27 +11,57 @@ const args = process.argv.slice(2);
11
11
  const command = args[0];
12
12
 
13
13
  if (command === 'create-app') {
14
- const projectPath = args[1] || '.';
15
- createApp(projectPath);
14
+ // Parse arguments - separate flags from positional arguments
15
+ const flags = {};
16
+ const positional = [];
17
+
18
+ for (let i = 1; i < args.length; i++) {
19
+ const arg = args[i];
20
+ if (arg.startsWith('--')) {
21
+ if (arg.includes('=')) {
22
+ const [key, value] = arg.split('=');
23
+ flags[key.slice(2)] = value;
24
+ } else {
25
+ flags[arg.slice(2)] = true;
26
+ }
27
+ } else {
28
+ positional.push(arg);
29
+ }
30
+ }
31
+
32
+ const projectPath = positional[0] || '.';
33
+ const template = flags.template || 'base';
34
+
35
+ createApp(projectPath, template);
16
36
  } else {
17
37
  console.log(`
18
38
  Snice CLI
19
39
 
20
40
  Usage:
21
- snice create-app <project-name> Create a new Snice application
22
- snice create-app . Initialize in current directory
41
+ snice create-app [options] <project-name>
42
+ snice create-app [options] . Initialize in current directory
43
+
44
+ Options:
45
+ --template=<name> Template to use (default: base)
46
+
47
+ Templates:
48
+ base - Minimal starter with counter example (default)
49
+ social - Social media sample app showcasing components
23
50
 
24
51
  Examples:
25
52
  snice create-app my-app
26
- npx snice create-app my-app
53
+ snice create-app my-app --template=social
54
+ snice create-app --template=social my-app
55
+ npx snice create-app my-app --template=social
27
56
  `);
28
57
  }
29
58
 
30
- function createApp(projectPath) {
59
+ function createApp(projectPath, template = 'base') {
31
60
  const targetDir = resolve(process.cwd(), projectPath);
32
61
  const projectName = projectPath === '.' ? basename(process.cwd()) : basename(targetDir);
33
-
62
+
34
63
  console.log(`\n🚀 Creating Snice app in ${targetDir}...\n`);
64
+ console.log(`📦 Using template: ${template}\n`);
35
65
 
36
66
  // Check if directory exists and is empty
37
67
  if (projectPath !== '.') {
@@ -55,18 +85,33 @@ function createApp(projectPath) {
55
85
  }
56
86
 
57
87
  // Path to templates
58
- const templateDir = join(__dirname, 'templates', 'base');
59
-
88
+ const templateDir = join(__dirname, 'templates', template);
89
+
90
+ // Check if template exists
91
+ if (!existsSync(templateDir)) {
92
+ console.error(`❌ Template "${template}" not found!`);
93
+ console.error(`Available templates: base, social`);
94
+ process.exit(1);
95
+ }
96
+
60
97
  // Copy template files
61
98
  copyTemplateFiles(templateDir, targetDir, projectName);
62
99
 
100
+ // Copy shared CLAUDE.md
101
+ const claudeMdPath = join(__dirname, 'templates', 'CLAUDE.md');
102
+ if (existsSync(claudeMdPath)) {
103
+ console.log(` Creating CLAUDE.md...`);
104
+ const claudeMdContent = readFileSync(claudeMdPath, 'utf8');
105
+ writeFileSync(join(targetDir, 'CLAUDE.md'), claudeMdContent.replace(/\{\{projectName\}\}/g, projectName));
106
+ }
107
+
63
108
  console.log(`\n✨ Project created successfully!\n`);
64
109
  console.log('Next steps:');
65
-
110
+
66
111
  if (projectPath !== '.') {
67
112
  console.log(` cd ${projectPath}`);
68
113
  }
69
-
114
+
70
115
  console.log(' npm install');
71
116
  console.log(' npm run dev\n');
72
117
  console.log('Happy coding! 🎉\n');
@@ -0,0 +1,138 @@
1
+ # Snice Project - AI Assistant Guide
2
+
3
+ ## Documentation Location
4
+
5
+ AI-optimized docs shipped in: `node_modules/snice/docs/ai/`
6
+
7
+ **Read these files:**
8
+ - `api.md` - Complete API reference
9
+ - `patterns.md` - Usage examples
10
+ - `architecture.md` - System design
11
+ - `components/*.md` - Component docs (read only as needed)
12
+
13
+ ## Project Structure
14
+
15
+ ```
16
+ src/
17
+ pages/ # @page decorated route components
18
+ components/ # @element decorated UI components
19
+ controllers/ # @controller decorated behavior modules
20
+ styles/ # Global CSS
21
+ ```
22
+
23
+ **Separation of concerns:**
24
+ - **Pages** - Orchestrate elements, handle URLs
25
+ - **Elements** - Pure presentation, no business logic
26
+ - **Controllers** - Behavior, data fetching, swappable
27
+
28
+ ## Decorators
29
+
30
+ ```typescript
31
+ // Class decorators
32
+ @page({ tag, routes, guards?, placard? })
33
+ @element('tag-name')
34
+ @controller('name')
35
+ @layout('name')
36
+
37
+ // Property/method decorators
38
+ @property() name = 'default'
39
+ @render() fn() { return html`...` }
40
+ @styles() fn() { return css`...` }
41
+ @ready() async fn() { ... }
42
+ @dispose() fn() { ... }
43
+ @watch('name') fn(oldVal, newVal) { ... }
44
+ @query('input') input!: HTMLInputElement
45
+ @queryAll('.item') items!: NodeListOf<HTMLElement>
46
+ @on('click', 'button') fn(e: Event) { ... }
47
+ @dispatch('value-changed') fn(val: string) => Event Detail
48
+ @context() fn(ctx: Context) { ... }
49
+ @request('user') fn(): () => Request
50
+ @respond('user') fn(req) => Response
51
+ @observe(() => this.el, options) fn(mutations) { ... }
52
+ ```
53
+
54
+ ## Quick Examples
55
+
56
+ **Element:**
57
+ ```typescript
58
+ @element('my-counter')
59
+ class Counter extends HTMLElement {
60
+ @property({ type: Number }) count = 0;
61
+
62
+ @render()
63
+ renderContent() {
64
+ return html`
65
+ <div>${this.count}</div>
66
+ <button @click=${() => this.count++}>+</button>
67
+ `;
68
+ }
69
+
70
+ @styles()
71
+ componentStyles() {
72
+ return css`:host { display: block; }`;
73
+ }
74
+ }
75
+ ```
76
+
77
+ **Page:**
78
+ ```typescript
79
+ @page({ tag: 'user-page', routes: ['/users/:id'] })
80
+ class UserPage extends HTMLElement {
81
+ @property() id = '';
82
+
83
+ @ready()
84
+ async load() {
85
+ const user = await fetch(`/api/users/${this.id}`).then(r => r.json());
86
+ }
87
+ }
88
+ ```
89
+
90
+ **Controller:**
91
+ ```typescript
92
+ @controller('data-loader')
93
+ class DataLoader implements IController {
94
+ element: HTMLElement;
95
+
96
+ async attach(el: HTMLElement) {
97
+ this.element = el;
98
+ }
99
+
100
+ async detach() {}
101
+
102
+ @on('click', '.item')
103
+ handleClick(e: Event) {}
104
+ }
105
+
106
+ // Usage: <my-list controller="data-loader"></my-list>
107
+ ```
108
+
109
+ **Lists:**
110
+ ```typescript
111
+ html`
112
+ ${items.map(item => html`
113
+ <li key=${item.id}>${item.name}</li>
114
+ `)}
115
+ `
116
+ ```
117
+
118
+ **Conditionals:**
119
+ ```typescript
120
+ html`
121
+ <if ${condition}>Content</if>
122
+ `
123
+ ```
124
+
125
+ ## Communication
126
+
127
+ - **Parent → Child:** Properties (`.prop=${value}`)
128
+ - **Child → Parent:** Events (`@dispatch`)
129
+ - **Element ↔ Controller:** Request/Response (`@request`, `@respond`)
130
+ - **Global State:** Context (`@context()`)
131
+
132
+ ## Build Commands
133
+
134
+ ```bash
135
+ npm run dev # Dev server
136
+ npm run build # Production build
137
+ npm run type-check # TypeScript check
138
+ ```
@@ -8,7 +8,7 @@ export class CounterButton extends HTMLElement implements ICounterButton {
8
8
 
9
9
  @render()
10
10
  renderContent() {
11
- return html`
11
+ return html/*html*/`
12
12
  <div class="counter">
13
13
  <button class="btn minus" @click=${this.handleMinus}>-</button>
14
14
  <span class="count">${this.count}</span>
@@ -19,7 +19,7 @@ export class CounterButton extends HTMLElement implements ICounterButton {
19
19
 
20
20
  @styles()
21
21
  componentStyles() {
22
- return css`
22
+ return css/*css*/`
23
23
  .counter {
24
24
  display: inline-flex;
25
25
  align-items: center;
@@ -0,0 +1,59 @@
1
+ import { element, property, render, styles, html, css } from 'snice';
2
+
3
+ @element('feature-card')
4
+ export class FeatureCard extends HTMLElement {
5
+ @property() icon = '✨';
6
+ @property() title = '';
7
+ @property() description = '';
8
+
9
+ @render()
10
+ renderContent() {
11
+ return html/*html*/`
12
+ <div class="card">
13
+ <div class="card__icon">${this.icon}</div>
14
+ <h3 class="card__title">${this.title}</h3>
15
+ <p class="card__description">${this.description}</p>
16
+ </div>
17
+ `;
18
+ }
19
+
20
+ @styles()
21
+ componentStyles() {
22
+ return css/*css*/`
23
+ :host {
24
+ display: block;
25
+ }
26
+
27
+ .card {
28
+ padding: 2rem;
29
+ background: white;
30
+ border-radius: 12px;
31
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
32
+ transition: transform 0.2s, box-shadow 0.2s;
33
+ }
34
+
35
+ .card:hover {
36
+ transform: translateY(-4px);
37
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
38
+ }
39
+
40
+ .card__icon {
41
+ font-size: 3rem;
42
+ margin-bottom: 1rem;
43
+ }
44
+
45
+ .card__title {
46
+ font-size: 1.25rem;
47
+ font-weight: 600;
48
+ margin: 0 0 0.5rem 0;
49
+ color: var(--text-color, #333);
50
+ }
51
+
52
+ .card__description {
53
+ margin: 0;
54
+ color: var(--text-light, #666);
55
+ line-height: 1.6;
56
+ }
57
+ `;
58
+ }
59
+ }
@@ -0,0 +1,5 @@
1
+ export interface FeatureCardElement extends HTMLElement {
2
+ icon: string;
3
+ title: string;
4
+ description: string;
5
+ }
@@ -1,11 +1,16 @@
1
1
  import { initialize } from './router';
2
2
  import './styles/global.css';
3
3
 
4
- // Import a layout
4
+ // Import snice layout
5
5
  import 'snice/components/layout/snice-layout';
6
6
 
7
- // Import components
7
+ // Import snice components
8
+ import 'snice/components/button/snice-button';
9
+ import 'snice/components/card/snice-card';
10
+
11
+ // Import custom components
8
12
  import './components/counter-button';
13
+ import './components/feature-card';
9
14
 
10
15
  // Import controllers
11
16
  import './controllers/counter-controller';
@@ -1,4 +1,5 @@
1
1
  import { page } from '../router';
2
+ import { render, styles, html, css } from 'snice';
2
3
  import type { Placard } from 'snice';
3
4
 
4
5
  const placard: Placard = {
@@ -11,13 +12,14 @@ const placard: Placard = {
11
12
 
12
13
  @page({ tag: 'about-page', routes: ['/about'], placard })
13
14
  export class AboutPage extends HTMLElement {
14
- html() {
15
- return /*html*/`
15
+ @render()
16
+ renderContent() {
17
+ return html/*html*/`
16
18
  <div class="container">
17
19
  <h1>About</h1>
18
20
  <p>This app was built with Snice, a modern web components framework.</p>
19
21
  <p>Version 1.0.0</p>
20
-
22
+
21
23
  <div class="nav">
22
24
  <a href="#/" class="btn">Back to Home</a>
23
25
  </div>
@@ -25,8 +27,9 @@ export class AboutPage extends HTMLElement {
25
27
  `;
26
28
  }
27
29
 
28
- css() {
29
- return /*css*/`
30
+ @styles()
31
+ componentStyles() {
32
+ return css/*css*/`
30
33
  .container {
31
34
  padding: 3rem;
32
35
  max-width: 800px;
@@ -1,4 +1,5 @@
1
1
  import { page } from '../router';
2
+ import { render, styles, html, css } from 'snice';
2
3
  import type { Placard } from 'snice';
3
4
 
4
5
  const placard: Placard = {
@@ -11,27 +12,51 @@ const placard: Placard = {
11
12
 
12
13
  @page({ tag: 'home-page', routes: ['/'], placard })
13
14
  export class HomePage extends HTMLElement {
14
- html() {
15
- return /*html*/`
15
+ @render()
16
+ renderContent() {
17
+ return html/*html*/`
16
18
  <div class="container">
17
19
  <h1>Welcome to {{projectName}}</h1>
18
20
  <p>Built with Snice</p>
19
-
20
- <div class="demo-section">
21
+
22
+ <div class="features">
23
+ <feature-card
24
+ icon="⚡"
25
+ title="Fast & Lightweight"
26
+ description="No virtual DOM overhead. Direct DOM updates with differential rendering.">
27
+ </feature-card>
28
+
29
+ <feature-card
30
+ icon="🎨"
31
+ title="Type-Safe"
32
+ description="Full TypeScript support with decorators for clean, maintainable code.">
33
+ </feature-card>
34
+
35
+ <feature-card
36
+ icon="🔧"
37
+ title="Web Standards"
38
+ description="Built on native Web Components. Works everywhere, no framework lock-in.">
39
+ </feature-card>
40
+ </div>
41
+
42
+ <snice-card class="demo-section">
21
43
  <h2>Interactive Counter Demo</h2>
22
44
  <p>This counter persists its state using a controller:</p>
23
45
  <counter-button controller="counter"></counter-button>
24
- </div>
25
-
46
+ </snice-card>
47
+
26
48
  <div class="nav">
27
- <a href="#/about" class="btn">About</a>
49
+ <snice-button variant="primary" size="medium">
50
+ <a href="#/about" style="color: inherit; text-decoration: none;">Learn More</a>
51
+ </snice-button>
28
52
  </div>
29
53
  </div>
30
54
  `;
31
55
  }
32
56
 
33
- css() {
34
- return /*css*/`
57
+ @styles()
58
+ componentStyles() {
59
+ return css/*css*/`
35
60
  .container {
36
61
  padding: 3rem;
37
62
  text-align: center;
@@ -56,31 +81,25 @@ export class HomePage extends HTMLElement {
56
81
  margin-bottom: 2rem;
57
82
  }
58
83
 
84
+ .features {
85
+ display: grid;
86
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
87
+ gap: 2rem;
88
+ margin: 3rem 0;
89
+ }
90
+
59
91
  .demo-section {
60
92
  margin: 3rem 0;
61
- padding: 2rem;
62
- background: rgba(255, 255, 255, 0.5);
63
- border-radius: 12px;
64
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
93
+ text-align: center;
65
94
  }
66
-
95
+
96
+ .demo-section h2 {
97
+ margin-top: 0;
98
+ }
99
+
67
100
  .nav {
68
101
  margin-top: 3rem;
69
102
  }
70
-
71
- .btn {
72
- display: inline-block;
73
- padding: 0.75rem 1.5rem;
74
- background: var(--primary-color);
75
- color: white;
76
- text-decoration: none;
77
- border-radius: 6px;
78
- transition: background 0.3s ease;
79
- }
80
-
81
- .btn:hover {
82
- background: var(--secondary-color);
83
- }
84
103
  `;
85
104
  }
86
105
  }
@@ -1,9 +1,11 @@
1
1
  import { page } from '../router';
2
+ import { render, styles, html, css } from 'snice';
2
3
 
3
4
  @page({ tag: 'not-found-page', routes: ['/404'] })
4
5
  export class NotFoundPage extends HTMLElement {
5
- html() {
6
- return /*html*/`
6
+ @render()
7
+ renderContent() {
8
+ return html/*html*/`
7
9
  <div class="container">
8
10
  <h1>404</h1>
9
11
  <p>Page not found</p>
@@ -12,8 +14,9 @@ export class NotFoundPage extends HTMLElement {
12
14
  `;
13
15
  }
14
16
 
15
- css() {
16
- return /*css*/`
17
+ @styles()
18
+ componentStyles() {
19
+ return css/*css*/`
17
20
  .container {
18
21
  padding: 3rem;
19
22
  text-align: center;
@@ -0,0 +1,5 @@
1
+ export interface ApiResponse<T> {
2
+ data: T;
3
+ error?: string;
4
+ loading: boolean;
5
+ }
@@ -0,0 +1 @@
1
+ export type Status = 'idle' | 'loading' | 'success' | 'error';
@@ -0,0 +1 @@
1
+ export type Theme = 'light' | 'dark' | 'auto';
@@ -0,0 +1,5 @@
1
+ export interface User {
2
+ id: string;
3
+ name: string;
4
+ email: string;
5
+ }
@@ -0,0 +1,42 @@
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.
@@ -0,0 +1,14 @@
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
+ }
@@ -0,0 +1,13 @@
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>
@@ -0,0 +1,21 @@
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": "^2.5.1"
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
+ }
@@ -0,0 +1 @@
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>
@@ -0,0 +1,33 @@
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();