create-thunderous 0.0.3 → 0.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-thunderous",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "A CLI tool to scaffold a new project using the Thunderous stack.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "eslint": "^9.38.0",
29
29
  "prettier": "^3.6.2",
30
30
  "serve": "^14.2.5",
31
- "thunderous-server": "^0.0.4",
31
+ "thunderous-server": "^0.0.5",
32
32
  "tsx": "^4.20.6",
33
33
  "typescript": "^5.9.3",
34
34
  "typescript-eslint": "^8.46.2",
@@ -1,12 +1,15 @@
1
- import { css, customElement, html } from 'thunderous';
1
+ import { createSignal, css, customElement, html } from 'thunderous';
2
+ import { theme } from '../theme';
2
3
 
3
4
  export const Crumb = customElement(({ adoptStyleSheet, attrSignals }) => {
4
- const { href } = attrSignals;
5
- const [getHref] = href ?? [() => ''];
5
+ const [getHref] = attrSignals['href'] ?? createSignal('');
6
+
7
+ adoptStyleSheet(theme);
6
8
  adoptStyleSheet(stylesheet);
9
+
7
10
  return html`
8
11
  <span class="crumb">
9
- <a href=${getHref()}>
12
+ <a href="${getHref()}">
10
13
  <slot></slot>
11
14
  </a>
12
15
  </span>
@@ -15,7 +18,7 @@ export const Crumb = customElement(({ adoptStyleSheet, attrSignals }) => {
15
18
 
16
19
  const stylesheet = css`
17
20
  a {
18
- color: var(--link);
21
+ color: var(--color-brand-1);
19
22
  text-decoration: none;
20
23
  font-weight: 600;
21
24
  transition: color 180ms ease;
@@ -23,11 +26,11 @@ const stylesheet = css`
23
26
 
24
27
  a:hover,
25
28
  a:focus-visible {
26
- color: var(--link-hover);
29
+ color: var(--color-brand-1-1);
27
30
  }
28
31
 
29
32
  a:focus-visible {
30
- outline: 2px solid color-mix(in srgb, var(--link) 50%, white 20%);
33
+ outline: 2px solid color-mix(in srgb, var(--color-brand-1) 50%, white 20%);
31
34
  outline-offset: 3px;
32
35
  border-radius: 0.25rem;
33
36
  }
@@ -1,14 +1,17 @@
1
- import { customElement, html, css } from 'thunderous';
1
+ import { customElement, html, css, createSignal } from 'thunderous';
2
+ import { theme } from '../theme';
2
3
 
3
- export const MyComponent = customElement(({ clientOnlyCallback, adoptStyleSheet }) => {
4
- clientOnlyCallback(() => {
5
- console.log('MyComponent has been mounted on the client side.');
6
- });
4
+ export const Feature = customElement(({ adoptStyleSheet, attrSignals }) => {
5
+ const [getHref] = attrSignals['href'] ?? createSignal('');
6
+ const [getButtonText] = attrSignals['buttontext'] ?? createSignal('Learn More');
7
+
8
+ adoptStyleSheet(theme);
7
9
  adoptStyleSheet(stylesheet);
10
+
8
11
  return html`
9
- <div class="my-component">
12
+ <div class="feature">
10
13
  <slot></slot>
11
- <a href="https://thunderous.dev">Learn More</a>
14
+ ${getHref() !== '' ? html`<a href=${getHref()}>${getButtonText()}</a>` : ''}
12
15
  </div>
13
16
  `;
14
17
  });
@@ -17,53 +20,33 @@ const stylesheet = css`
17
20
  :host {
18
21
  display: block;
19
22
  font-size: 2rem;
20
-
21
- --bg-1: rgba(255, 255, 255, 0.72);
22
- --bg-2: rgba(255, 255, 255, 0.5);
23
- --border: rgba(255, 255, 255, 0.35);
24
- --text: #1e293b;
25
- --muted: #b8c7e6;
26
- --link: #7dd3fc;
27
- --link-hover: #c4b5fd;
28
- --shadow: 0 18px 50px rgba(15, 23, 42, 0.35);
29
-
30
- @media (prefers-color-scheme: light) {
31
- --bg-1: rgba(255, 255, 255, 0.88);
32
- --bg-2: rgba(240, 249, 255, 0.74);
33
- --border: rgba(99, 102, 241, 0.16);
34
- --text: #1e293b;
35
- --muted: #475569;
36
- --link: #2563eb;
37
- --link-hover: #7c3aed;
38
- --shadow: 0 18px 40px rgba(51, 65, 85, 0.14);
39
- }
40
23
  }
41
24
 
42
25
  ::slotted(*) {
43
26
  margin: 0;
44
- color: var(--text);
27
+ color: var(--color-neutral-2);
45
28
  }
46
29
 
47
- .my-component {
30
+ .feature {
48
31
  text-align: center;
49
32
  position: relative;
50
33
  overflow: hidden;
51
34
  padding: 2em 3em;
52
35
  border-radius: 20px;
53
- border: 1px solid var(--border);
36
+ border: 1px solid var(--color-surface-2-2);
54
37
  background:
55
38
  linear-gradient(135deg, rgba(99, 102, 241, 0.22), rgba(14, 165, 233, 0.16)),
56
- linear-gradient(180deg, var(--bg-1), var(--bg-2));
39
+ linear-gradient(180deg, var(--color-surface-2), var(--color-surface-2-1));
57
40
  backdrop-filter: blur(18px) saturate(160%);
58
41
  -webkit-backdrop-filter: blur(18px) saturate(160%);
59
- box-shadow: var(--shadow);
42
+ box-shadow: var(--shadow-2);
60
43
  isolation: isolate;
61
44
  margin: 1em auto;
62
45
  max-width: 20em;
63
46
  }
64
47
 
65
- .my-component::before,
66
- .my-component::after {
48
+ .feature::before,
49
+ .feature::after {
67
50
  content: '';
68
51
  position: absolute;
69
52
  inset: auto;
@@ -74,7 +57,7 @@ const stylesheet = css`
74
57
  pointer-events: none;
75
58
  }
76
59
 
77
- .my-component::before {
60
+ .feature::before {
78
61
  top: -60px;
79
62
  right: -40px;
80
63
  width: 180px;
@@ -82,7 +65,7 @@ const stylesheet = css`
82
65
  background: radial-gradient(circle, rgba(125, 211, 252, 0.35), transparent 65%);
83
66
  }
84
67
 
85
- .my-component::after {
68
+ .feature::after {
86
69
  bottom: -70px;
87
70
  left: -30px;
88
71
  width: 160px;
@@ -90,16 +73,16 @@ const stylesheet = css`
90
73
  background: radial-gradient(circle, rgba(196, 181, 253, 0.28), transparent 65%);
91
74
  }
92
75
 
93
- .my-component p {
76
+ .feature p {
94
77
  margin: 0;
95
78
  font-size: 1rem;
96
79
  line-height: 1.75;
97
80
  letter-spacing: 0.01em;
98
- color: var(--text);
81
+ color: var(--color-neutral-2);
99
82
  text-wrap: pretty;
100
83
  }
101
84
 
102
- .my-component a {
85
+ .feature a {
103
86
  display: inline-flex;
104
87
  align-items: center;
105
88
  justify-content: center;
@@ -107,13 +90,14 @@ const stylesheet = css`
107
90
  margin: 1.5em 0 0.5em;
108
91
  padding: 0.85em 1.25em;
109
92
  border-radius: 999px;
110
- border: 1px solid color-mix(in srgb, var(--border) 85%, white 15%);
93
+ border: 1px solid color-mix(in srgb, var(--color-surface-2-2) 85%, white 15%);
111
94
  background:
112
- linear-gradient(135deg, var(--link), var(--link-hover)), linear-gradient(180deg, var(--bg-1), var(--bg-2));
95
+ linear-gradient(135deg, var(--color-brand-2), var(--color-brand-2-1)),
96
+ linear-gradient(180deg, var(--color-surface-2), var(--color-surface-2-1));
113
97
  box-shadow:
114
- 0 10px 30px color-mix(in srgb, var(--link-hover) 28%, transparent),
98
+ 0 10px 30px color-mix(in srgb, var(--color-brand-2-1) 28%, transparent),
115
99
  inset 0 1px 0 color-mix(in srgb, white 35%, transparent);
116
- color: var(--text);
100
+ color: var(--color-neutral-2);
117
101
  font-weight: 700;
118
102
  line-height: 1;
119
103
  letter-spacing: 0.01em;
@@ -127,37 +111,37 @@ const stylesheet = css`
127
111
  color 180ms ease;
128
112
  }
129
113
 
130
- .my-component a:hover,
131
- .my-component a:focus-visible {
114
+ .feature a:hover,
115
+ .feature a:focus-visible {
132
116
  transform: translateY(-2px);
133
117
  filter: brightness(1.05);
134
- border-color: color-mix(in srgb, var(--link) 55%, var(--border));
118
+ border-color: color-mix(in srgb, var(--color-brand-2) 55%, var(--color-surface-2-2));
135
119
  box-shadow:
136
- 0 16px 36px color-mix(in srgb, var(--link-hover) 36%, transparent),
120
+ 0 16px 36px color-mix(in srgb, var(--color-brand-2-1) 36%, transparent),
137
121
  inset 0 1px 0 color-mix(in srgb, white 45%, transparent);
138
- color: var(--text);
122
+ color: var(--color-neutral-2);
139
123
  }
140
124
 
141
- .my-component a:active {
125
+ .feature a:active {
142
126
  transform: translateY(0);
143
127
  box-shadow:
144
- 0 8px 20px color-mix(in srgb, var(--link-hover) 22%, transparent),
128
+ 0 8px 20px color-mix(in srgb, var(--color-brand-2-1) 22%, transparent),
145
129
  inset 0 1px 0 color-mix(in srgb, white 25%, transparent);
146
130
  }
147
131
 
148
- .my-component a:focus-visible {
149
- outline: 2px solid color-mix(in srgb, var(--link) 65%, white 35%);
132
+ .feature a:focus-visible {
133
+ outline: 2px solid color-mix(in srgb, var(--color-brand-2) 65%, white 35%);
150
134
  outline-offset: 4px;
151
135
  }
152
136
 
153
- .my-component a::after {
137
+ .feature a::after {
154
138
  content: '→';
155
139
  font-size: 0.95em;
156
140
  transition: transform 180ms ease;
157
141
  }
158
142
 
159
- .my-component a:hover::after,
160
- .my-component a:focus-visible::after {
143
+ .feature a:hover::after,
144
+ .feature a:focus-visible::after {
161
145
  transform: translateX(3px);
162
146
  }
163
147
  `;
@@ -1,7 +1,10 @@
1
1
  import { customElement, html, css } from 'thunderous';
2
+ import { theme } from '../theme';
2
3
 
3
4
  export const Page = customElement(({ adoptStyleSheet }) => {
5
+ adoptStyleSheet(theme);
4
6
  adoptStyleSheet(stylesheet);
7
+
5
8
  return html`
6
9
  <div class="page">
7
10
  <header>
@@ -33,15 +36,6 @@ const stylesheet = css`
33
36
  display: block;
34
37
  height: 100%;
35
38
  width: 100%;
36
-
37
- --bg-1: rgba(255, 255, 255, 0.06);
38
- --bg-2: rgba(255, 255, 255, 0.03);
39
- --border: rgba(255, 255, 255, 0.1);
40
- --text: #e5eefc;
41
- --muted: #9fb0d1;
42
- --link: #8fb4ff;
43
- --link-hover: #2a4692;
44
- --shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
45
39
  }
46
40
  .page {
47
41
  display: grid;
@@ -50,10 +44,10 @@ const stylesheet = css`
50
44
  min-width: 320px;
51
45
  min-height: 100vh;
52
46
  background:
53
- radial-gradient(circle at top left, rgba(99, 102, 241, 0.22), transparent 30%),
54
- radial-gradient(circle at bottom right, rgba(14, 165, 233, 0.18), transparent 35%),
55
- linear-gradient(180deg, #0f172a 0%, #111827 45%, #0b1120 100%);
56
- color: #eaf2ff;
47
+ radial-gradient(circle at top left, var(--color-accent-1), transparent 30%),
48
+ radial-gradient(circle at bottom right, var(--color-accent-1-1), transparent 35%),
49
+ linear-gradient(180deg, var(--color-page-1) 0%, var(--color-page-1-1) 45%, var(--color-page-1-2) 100%);
50
+ color: var(--color-page-1-c);
57
51
  font-family: 'Plus Jakarta Sans', Inter, ui-sans-serif, system-ui, sans-serif;
58
52
  font-size: 1rem;
59
53
  line-height: 1.6;
@@ -73,16 +67,16 @@ const stylesheet = css`
73
67
  gap: 0.75rem;
74
68
  align-items: center;
75
69
  padding: 0.75rem 1rem;
76
- border: 1px solid var(--border);
70
+ border: 1px solid var(--color-surface-1-2);
77
71
  border-radius: 999px;
78
72
  background: linear-gradient(
79
73
  135deg,
80
- color-mix(in srgb, var(--bg-1) 88%, transparent),
81
- color-mix(in srgb, var(--bg-2) 92%, transparent)
74
+ color-mix(in srgb, var(--color-surface-1) 88%, transparent),
75
+ color-mix(in srgb, var(--color-surface-1-1) 92%, transparent)
82
76
  );
83
77
  backdrop-filter: blur(18px) saturate(160%);
84
78
  -webkit-backdrop-filter: blur(18px) saturate(160%);
85
- box-shadow: var(--shadow);
79
+ box-shadow: var(--shadow-1);
86
80
  }
87
81
 
88
82
  .header-nav a {
@@ -92,7 +86,7 @@ const stylesheet = css`
92
86
  justify-content: center;
93
87
  padding: 0.7rem 1rem;
94
88
  border-radius: 999px;
95
- color: var(--text);
89
+ color: var(--color-neutral-1);
96
90
  font-weight: 600;
97
91
  line-height: 1;
98
92
  letter-spacing: 0.01em;
@@ -109,7 +103,7 @@ const stylesheet = css`
109
103
  position: absolute;
110
104
  inset: 0;
111
105
  border-radius: inherit;
112
- background: linear-gradient(135deg, var(--link), var(--link-hover));
106
+ background: linear-gradient(135deg, var(--color-brand-1), var(--color-brand-1-1));
113
107
  opacity: 0;
114
108
  transform: scale(0.96);
115
109
  transition:
@@ -120,10 +114,10 @@ const stylesheet = css`
120
114
 
121
115
  .header-nav a:hover,
122
116
  .header-nav a:focus-visible {
123
- color: var(--text);
117
+ color: var(--color-neutral-1);
124
118
  transform: translateY(-1px);
125
119
  box-shadow:
126
- 0 10px 24px color-mix(in srgb, var(--link-hover) 22%, transparent),
120
+ 0 10px 24px color-mix(in srgb, var(--color-brand-1-1) 22%, transparent),
127
121
  inset 0 1px 0 color-mix(in srgb, white 30%, transparent);
128
122
  }
129
123
 
@@ -138,7 +132,7 @@ const stylesheet = css`
138
132
  }
139
133
 
140
134
  .header-nav a:focus-visible {
141
- outline: 2px solid color-mix(in srgb, var(--link) 65%, white 35%);
135
+ outline: 2px solid color-mix(in srgb, var(--color-brand-1) 65%, white 35%);
142
136
  outline-offset: 4px;
143
137
  }
144
138
 
@@ -154,9 +148,9 @@ const stylesheet = css`
154
148
  place-items: center;
155
149
  gap: 1.5rem;
156
150
  padding: 2rem 1.5rem;
157
- border-top: 1px solid var(--border);
158
- background: linear-gradient(180deg, var(--bg-2), transparent);
159
- color: var(--muted);
151
+ border-top: 1px solid var(--color-surface-1-2);
152
+ background: linear-gradient(180deg, var(--color-surface-1-1), transparent);
153
+ color: var(--color-neutral-1-1);
160
154
  }
161
155
 
162
156
  .footer-nav {
@@ -179,7 +173,7 @@ const stylesheet = css`
179
173
  align-items: center;
180
174
  padding: 0.35rem 0.2rem;
181
175
  border-radius: 0.5rem;
182
- color: var(--muted);
176
+ color: var(--color-neutral-1-1);
183
177
  font-weight: 500;
184
178
  text-decoration: none;
185
179
  transition:
@@ -193,8 +187,8 @@ const stylesheet = css`
193
187
 
194
188
  .footer-nav a:hover,
195
189
  .footer-nav a:focus-visible {
196
- color: var(--text);
197
- background: color-mix(in srgb, var(--bg-1) 70%, transparent);
190
+ color: var(--color-neutral-1);
191
+ background: color-mix(in srgb, var(--color-surface-1) 70%, transparent);
198
192
  box-shadow: none;
199
193
  transform: none;
200
194
  }
@@ -204,19 +198,19 @@ const stylesheet = css`
204
198
  }
205
199
 
206
200
  .footer-nav a:focus-visible {
207
- outline: 2px solid color-mix(in srgb, var(--link) 50%, white 20%);
201
+ outline: 2px solid color-mix(in srgb, var(--color-brand-1) 50%, white 20%);
208
202
  outline-offset: 3px;
209
203
  }
210
204
 
211
205
  footer small {
212
206
  display: block;
213
- color: var(--muted);
207
+ color: var(--color-neutral-1-1);
214
208
  font-size: 0.875rem;
215
209
  line-height: 1.6;
216
210
  }
217
211
 
218
212
  footer small a {
219
- color: var(--link);
213
+ color: var(--color-brand-1);
220
214
  text-decoration: none;
221
215
  font-weight: 600;
222
216
  transition: color 180ms ease;
@@ -224,11 +218,11 @@ const stylesheet = css`
224
218
 
225
219
  footer small a:hover,
226
220
  footer small a:focus-visible {
227
- color: var(--link-hover);
221
+ color: var(--color-brand-1-1);
228
222
  }
229
223
 
230
224
  footer small a:focus-visible {
231
- outline: 2px solid color-mix(in srgb, var(--link) 50%, white 20%);
225
+ outline: 2px solid color-mix(in srgb, var(--color-brand-1) 50%, white 20%);
232
226
  outline-offset: 3px;
233
227
  border-radius: 0.25rem;
234
228
  }
@@ -1,11 +1,11 @@
1
1
  <?layout href="_layout.html">
2
2
 
3
- <my-component>
3
+ <x-feature href="https://thunderous.dev" buttontext="Read the Docs">
4
4
  <script expr>
5
5
  // These <script expr> tags are evaluated in-place as expressions and replaced by the result.
6
6
  html`<p>The ${stack} stack is dead simple and feels like there's no framework at all.</p>`;
7
7
  </script>
8
- </my-component>
8
+ </x-feature>
9
9
 
10
10
  <script>
11
11
  // This is ordinary client-only code.
@@ -23,10 +23,10 @@
23
23
  // This code runs on both the client and server.
24
24
  // Isomorphic scripts are always modules.
25
25
  // Since it runs on the client, it will also vendorize NPM dependencies.
26
- import { MyComponent } from './components/my-component';
26
+ import { Feature } from './components/feature';
27
27
 
28
28
  // Thunderous components render declarative shadow DOM when defined on the server.
29
- MyComponent.define('my-component');
29
+ Feature.define('x-feature');
30
30
  </script>
31
31
 
32
32
  <script server>
@@ -0,0 +1,57 @@
1
+ import { css } from "thunderous";
2
+
3
+ export const theme = css`
4
+ :host {
5
+ --color-page-1: #0f172a;
6
+ --color-page-1-1: #111827;
7
+ --color-page-1-2: #0b1120;
8
+ --color-page-1-c: #eaf2ff;
9
+ --color-accent-1: rgba(99, 102, 241, 0.22);
10
+ --color-accent-1-1: rgba(14, 165, 233, 0.18);
11
+
12
+ --color-surface-1: rgba(255, 255, 255, 0.06);
13
+ --color-surface-1-1: rgba(255, 255, 255, 0.03);
14
+ --color-surface-1-2: rgba(255, 255, 255, 0.1);
15
+ --color-neutral-1: #e5eefc;
16
+ --color-neutral-1-1: #9fb0d1;
17
+ --color-brand-1: #8fb4ff;
18
+ --color-brand-1-1: #2a4692;
19
+ --shadow-1: 0 10px 30px rgba(0, 0, 0, 0.18);
20
+
21
+ --color-surface-2: rgba(255, 255, 255, 0.72);
22
+ --color-surface-2-1: rgba(255, 255, 255, 0.5);
23
+ --color-surface-2-2: rgba(255, 255, 255, 0.35);
24
+ --color-neutral-2: #1e293b;
25
+ --color-neutral-2-1: #b8c7e6;
26
+ --color-brand-2: #7dd3fc;
27
+ --color-brand-2-1: #c4b5fd;
28
+ --shadow-2: 0 18px 50px rgba(15, 23, 42, 0.35);
29
+
30
+ @media (prefers-color-scheme: light) {
31
+ --color-page-1: #f0f4fa;
32
+ --color-page-1-1: #e8edf5;
33
+ --color-page-1-2: #f5f7fb;
34
+ --color-page-1-c: #1e293b;
35
+ --color-accent-1: rgba(99, 102, 241, 0.1);
36
+ --color-accent-1-1: rgba(14, 165, 233, 0.08);
37
+
38
+ --color-surface-1: rgba(255, 255, 255, 0.7);
39
+ --color-surface-1-1: rgba(255, 255, 255, 0.5);
40
+ --color-surface-1-2: rgba(99, 102, 241, 0.16);
41
+ --color-neutral-1: #1e293b;
42
+ --color-neutral-1-1: #475569;
43
+ --color-brand-1: #2563eb;
44
+ --color-brand-1-1: #7c3aed;
45
+ --shadow-1: 0 10px 30px rgba(51, 65, 85, 0.1);
46
+
47
+ --color-surface-2: rgba(255, 255, 255, 0.92);
48
+ --color-surface-2-1: rgba(245, 248, 255, 0.85);
49
+ --color-surface-2-2: rgba(99, 102, 241, 0.18);
50
+ --color-neutral-2: #1e293b;
51
+ --color-neutral-2-1: #475569;
52
+ --color-brand-2: #4f46e5;
53
+ --color-brand-2-1: #7c3aed;
54
+ --shadow-2: 0 18px 40px rgba(51, 65, 85, 0.12);
55
+ }
56
+ }
57
+ `;