@solidjs/start 2.0.3 → 2.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/config/fs-router.js +24 -28
  3. package/dist/shared/dev-toolbar/error-viewer/CodeView.jsx +9 -4
  4. package/dist/shared/dev-toolbar/error-viewer/create-stack-frame.d.ts +2 -1
  5. package/dist/shared/dev-toolbar/error-viewer/create-stack-frame.js +29 -19
  6. package/dist/shared/dev-toolbar/error-viewer/get-source-map.d.ts +2 -2
  7. package/dist/shared/dev-toolbar/error-viewer/get-source-map.js +3 -2
  8. package/dist/shared/dev-toolbar/error-viewer/index.jsx +52 -35
  9. package/dist/shared/dev-toolbar/error-viewer/styles.css +91 -43
  10. package/dist/shared/dev-toolbar/functions/BlobViewer.css +50 -2
  11. package/dist/shared/dev-toolbar/functions/BlobViewer.jsx +23 -4
  12. package/dist/shared/dev-toolbar/functions/FormDataViewer.jsx +9 -6
  13. package/dist/shared/dev-toolbar/functions/HeadersViewer.css +0 -4
  14. package/dist/shared/dev-toolbar/functions/HeadersViewer.jsx +9 -7
  15. package/dist/shared/dev-toolbar/functions/HexViewer.css +36 -17
  16. package/dist/shared/dev-toolbar/functions/HexViewer.jsx +7 -6
  17. package/dist/shared/dev-toolbar/functions/SerovalValue.css +21 -0
  18. package/dist/shared/dev-toolbar/functions/SerovalValue.d.ts +1 -0
  19. package/dist/shared/dev-toolbar/functions/SerovalValue.jsx +4 -2
  20. package/dist/shared/dev-toolbar/functions/SerovalViewer.css +98 -36
  21. package/dist/shared/dev-toolbar/functions/SerovalViewer.jsx +268 -279
  22. package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.jsx +9 -6
  23. package/dist/shared/dev-toolbar/functions/index.jsx +96 -69
  24. package/dist/shared/dev-toolbar/functions/styles.css +143 -10
  25. package/dist/shared/dev-toolbar/index.css +54 -14
  26. package/dist/shared/dev-toolbar/index.jsx +8 -1
  27. package/dist/shared/ui/Badge.css +21 -10
  28. package/dist/shared/ui/Button.css +7 -6
  29. package/dist/shared/ui/IconButton.css +16 -10
  30. package/dist/shared/ui/Placeholder.css +2 -0
  31. package/dist/shared/ui/Section.css +42 -3
  32. package/dist/shared/ui/Section.d.ts +3 -1
  33. package/dist/shared/ui/Section.jsx +14 -6
  34. package/dist/shared/ui/Select.css +11 -4
  35. package/dist/shared/ui/Tabs.css +30 -16
  36. package/package.json +5 -5
  37. package/dist/shared/ui/Cascade.css +0 -29
  38. package/dist/shared/ui/Cascade.d.ts +0 -4
  39. package/dist/shared/ui/Cascade.jsx +0 -4
  40. package/dist/shared/ui/Dialog.css +0 -25
  41. package/dist/shared/ui/Dialog.d.ts +0 -5
  42. package/dist/shared/ui/Dialog.jsx +0 -5
  43. package/dist/shared/ui/Table.css +0 -22
  44. package/dist/shared/ui/Table.d.ts +0 -11
  45. package/dist/shared/ui/Table.jsx +0 -13
@@ -1,14 +1,17 @@
1
1
  import { createResource, For, Show, Suspense } from "solid-js";
2
2
  import { Section } from "../../ui/Section.jsx";
3
- import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
3
+ import { Text } from "../../ui/Text.jsx";
4
4
  function URLSearchParamsViewerInner(props) {
5
5
  return (<Section title="URLSearchParams" options={{ size: "sm" }}>
6
- <div data-start-properties>
6
+ <div data-start-properties data-start-kv-table>
7
7
  <For each={Array.from(props.source.entries())}>
8
- {([key, value]) => (<div data-start-property>
9
- <SerovalValue value={`"${key}"`}/>
10
- <PropertySeparator />
11
- <SerovalValue value={`"${JSON.stringify(value)}"`}/>
8
+ {([key, value]) => (<div data-start-property data-start-kv-row>
9
+ <Text data-start-kv-key options={{ size: "xs", weight: "semibold", font: "mono", wrap: "nowrap" }}>
10
+ {key}
11
+ </Text>
12
+ <Text data-start-kv-value options={{ size: "xs", font: "mono", wrap: "wrap" }}>
13
+ {JSON.stringify(value)}
14
+ </Text>
12
15
  </div>)}
13
16
  </For>
14
17
  </div>
@@ -7,12 +7,11 @@ import { Section } from "../../ui/Section.jsx";
7
7
  import { Select, SelectOption } from "../../ui/Select.jsx";
8
8
  import { Tab, TabGroup, TabList, TabPanel } from "../../ui/Tabs.jsx";
9
9
  import { Text } from "../../ui/Text.jsx";
10
- import { ArrowLeftIcon, FunctionIcon, TrashIcon } from "../icons.jsx";
10
+ import { FunctionIcon, TrashIcon } from "../icons.jsx";
11
11
  import { BlobViewer } from "./BlobViewer.jsx";
12
12
  import { FormDataViewer } from "./FormDataViewer.jsx";
13
13
  import { HeadersViewer } from "./HeadersViewer.jsx";
14
14
  import { HexViewer } from "./HexViewer.jsx";
15
- import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
16
15
  import { SerovalViewer } from "./SerovalViewer.jsx";
17
16
  import "./styles.css";
18
17
  import { URLSearchParamsViewer } from "./URLSearchParamsViewer.jsx";
@@ -29,37 +28,43 @@ async function getURLSearchParams(source) {
29
28
  return new URLSearchParams(text);
30
29
  }
31
30
  function ContentViewer(props) {
31
+ const body = createMemo(() => {
32
+ const original = props.source.source;
33
+ if (!original.body) {
34
+ return undefined;
35
+ }
36
+ const source = original.clone();
37
+ const startType = source.headers.get(BODY_FORMAT_KEY);
38
+ const contentType = source.headers.get("Content-Type");
39
+ switch (true) {
40
+ case startType === "true":
41
+ case startType === BodyFormat.Seroval:
42
+ return <SerovalViewer stream={source}/>;
43
+ case startType === BodyFormat.String:
44
+ return <HexViewer bytes={source.bytes()}/>;
45
+ case startType === BodyFormat.File:
46
+ return <BlobViewer source={getFile(source)}/>;
47
+ case startType === BodyFormat.FormData:
48
+ case contentType?.startsWith("multipart/form-data"):
49
+ return <FormDataViewer source={source.formData()}/>;
50
+ case startType === BodyFormat.URLSearchParams:
51
+ case contentType?.startsWith("application/x-www-form-urlencoded"):
52
+ return <URLSearchParamsViewer source={getURLSearchParams(source)}/>;
53
+ case startType === BodyFormat.Blob:
54
+ return <BlobViewer source={source.blob()}/>;
55
+ case startType === BodyFormat.ArrayBuffer:
56
+ case startType === BodyFormat.Uint8Array:
57
+ return <HexViewer bytes={source.bytes()}/>;
58
+ }
59
+ return undefined;
60
+ });
32
61
  return (<>
33
- <Section title="Headers">
62
+ <Show when={body()}>
63
+ <Section title="Body">{body()}</Section>
64
+ </Show>
65
+ <Section collapsible title="Headers">
34
66
  <HeadersViewer headers={props.source.source.headers}/>
35
67
  </Section>
36
- <Section title="Body">
37
- {(() => {
38
- const source = props.source.source.clone();
39
- const startType = source.headers.get(BODY_FORMAT_KEY);
40
- const contentType = source.headers.get("Content-Type");
41
- switch (true) {
42
- case startType === "true":
43
- case startType === BodyFormat.Seroval:
44
- return <SerovalViewer stream={source}/>;
45
- case startType === BodyFormat.String:
46
- return <HexViewer bytes={source.bytes()}/>;
47
- case startType === BodyFormat.File:
48
- return <BlobViewer source={getFile(source)}/>;
49
- case startType === BodyFormat.FormData:
50
- case contentType?.startsWith("multipart/form-data"):
51
- return <FormDataViewer source={source.formData()}/>;
52
- case startType === BodyFormat.URLSearchParams:
53
- case contentType?.startsWith("application/x-www-form-urlencoded"):
54
- return <URLSearchParamsViewer source={getURLSearchParams(source)}/>;
55
- case startType === BodyFormat.Blob:
56
- return <BlobViewer source={source.blob()}/>;
57
- case startType === BodyFormat.ArrayBuffer:
58
- case startType === BodyFormat.Uint8Array:
59
- return <HexViewer bytes={source.bytes()}/>;
60
- }
61
- })()}
62
- </Section>
63
68
  </>);
64
69
  }
65
70
  function convertRequestToEntries(request) {
@@ -78,16 +83,21 @@ function convertRequestToEntries(request) {
78
83
  }
79
84
  function RequestViewer(props) {
80
85
  return (<TabPanel value="request">
81
- <Section title="Information">
82
- <For each={convertRequestToEntries(props.request.source)}>
83
- {([key, value]) => (<div data-start-property>
84
- <Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>{key}</Text>
85
- <PropertySeparator />
86
- <SerovalValue value={value}/>
87
- </div>)}
88
- </For>
89
- </Section>
90
86
  <ContentViewer source={props.request}/>
87
+ <Section collapsible defaultOpen={false} title="Information">
88
+ <div data-start-properties data-start-kv-table>
89
+ <For each={convertRequestToEntries(props.request.source)}>
90
+ {([key, value]) => (<div data-start-property data-start-kv-row>
91
+ <Text data-start-kv-key options={{ size: "xs", weight: "semibold", font: "mono", wrap: "nowrap" }}>
92
+ {key}
93
+ </Text>
94
+ <Text data-start-kv-value options={{ size: "xs", font: "mono", wrap: "wrap" }}>
95
+ {`${value}`}
96
+ </Text>
97
+ </div>)}
98
+ </For>
99
+ </div>
100
+ </Section>
91
101
  </TabPanel>);
92
102
  }
93
103
  function convertResponseToEntries(response) {
@@ -102,23 +112,33 @@ function convertResponseToEntries(response) {
102
112
  }
103
113
  function ResponseViewer(props) {
104
114
  return (<TabPanel value="response">
105
- <Show when={props.response}>
115
+ <Show when={props.response} fallback={<Placeholder>
116
+ <Text options={{ size: "xs" }}>Waiting for response.</Text>
117
+ </Placeholder>}>
106
118
  {instance => (<>
107
- <Section title="Information">
108
- <For each={convertResponseToEntries(instance().source)}>
109
- {([key, value]) => (<div data-start-property>
110
- <Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>{key}</Text>
111
- <PropertySeparator />
112
- <SerovalValue value={value}/>
113
- </div>)}
114
- </For>
115
- <div data-start-property>
116
- <Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>Timing</Text>
117
- <PropertySeparator />
118
- <SerovalValue value={`${((instance().time - props.request.time) / 1000).toFixed(2)}s`}/>
119
+ <ContentViewer source={instance()}/>
120
+ <Section collapsible defaultOpen={false} title="Information">
121
+ <div data-start-properties data-start-kv-table>
122
+ <For each={convertResponseToEntries(instance().source)}>
123
+ {([key, value]) => (<div data-start-property data-start-kv-row>
124
+ <Text data-start-kv-key options={{ size: "xs", weight: "semibold", font: "mono", wrap: "nowrap" }}>
125
+ {key}
126
+ </Text>
127
+ <Text data-start-kv-value options={{ size: "xs", font: "mono", wrap: "wrap" }}>
128
+ {`${value}`}
129
+ </Text>
130
+ </div>)}
131
+ </For>
132
+ <div data-start-property data-start-kv-row>
133
+ <Text data-start-kv-key options={{ size: "xs", weight: "semibold", font: "mono", wrap: "nowrap" }}>
134
+ Timing
135
+ </Text>
136
+ <Text data-start-kv-value options={{ size: "xs", font: "mono", wrap: "wrap" }}>
137
+ {`${((instance().time - props.request.time) / 1000).toFixed(2)}s`}
138
+ </Text>
139
+ </div>
119
140
  </div>
120
141
  </Section>
121
- <ContentViewer source={instance()}/>
122
142
  </>)}
123
143
  </Show>
124
144
  </TabPanel>);
@@ -144,14 +164,18 @@ function ServerFunctionInstanceViewer(props) {
144
164
  return (<div data-start-function-instance-viewer>
145
165
  <div data-start-function-instance-viewer-nav>
146
166
  <div data-start-function-instance-viewer-nav-left>
147
- <IconButton onClick={props.onReturn}>
148
- <ArrowLeftIcon title="Go Back"/>
149
- </IconButton>
150
167
  <div>
151
168
  <ServerFunctionInstanceDetail id={props.id} value={props.instance}/>
152
169
  </div>
153
170
  </div>
154
171
  <div>
172
+ <Show when={props.instance.response}>
173
+ {response => (<span data-start-function-instance-timing>
174
+ <Text options={{ size: "xs", weight: "semibold", font: "mono", wrap: "nowrap" }}>
175
+ {`${((response().time - props.instance.request.time) / 1000).toFixed(2)}s`}
176
+ </Text>
177
+ </span>)}
178
+ </Show>
155
179
  <IconButton onClick={props.onDelete}>
156
180
  <TrashIcon title="Delete instance"/>
157
181
  </IconButton>
@@ -180,18 +204,8 @@ export function ServerFunctionViewer(props) {
180
204
  return (<Show when={props.show}>
181
205
  <div data-start-dev-toolbar-panel>
182
206
  <div data-start-functions-viewer>
183
- {/* request/response viewer */}
184
- <Show when={currentInstance()}>
185
- {value => (<Show when={props.instances[value()]}>
186
- {instance => (<ServerFunctionInstanceViewer id={value()} instance={instance()} onReturn={() => {
187
- setCurrentInstance(undefined);
188
- }} onDelete={() => {
189
- props.onDeleteInstance(value());
190
- }}/>)}
191
- </Show>)}
192
- </Show>
193
- <Show when={!currentInstance()}>
194
- {/* list of calls */}
207
+ {/* list of calls */}
208
+ <div data-start-functions-sidebar>
195
209
  <div data-start-functions-nav>
196
210
  <FunctionIcon title="Server functions"/>
197
211
  <Text options={{ size: "sm" }}>Server functions</Text>
@@ -209,7 +223,20 @@ export function ServerFunctionViewer(props) {
209
223
  </Select>
210
224
  </Show>
211
225
  </div>
212
- </Show>
226
+ </div>
227
+ {/* request/response viewer */}
228
+ <div data-start-functions-detail>
229
+ <Show when={currentInstance()} fallback={<Placeholder>
230
+ <Text options={{ size: "xs" }}>Select a server function call.</Text>
231
+ </Placeholder>}>
232
+ {value => (<Show when={props.instances[value()]}>
233
+ {instance => (<ServerFunctionInstanceViewer id={value()} instance={instance()} onDelete={() => {
234
+ setCurrentInstance(undefined);
235
+ props.onDeleteInstance(value());
236
+ }}/>)}
237
+ </Show>)}
238
+ </Show>
239
+ </div>
213
240
  </div>
214
241
  </div>
215
242
  </Show>);
@@ -2,21 +2,51 @@
2
2
  display: flex;
3
3
  align-items: center;
4
4
  gap: 0.5rem;
5
+
6
+ min-width: 0;
7
+ }
8
+
9
+ [data-start-functions-instance-detail] > [data-start-text-size] {
10
+ overflow: hidden;
11
+ text-overflow: ellipsis;
5
12
  }
6
13
 
7
14
  [data-start-functions-viewer] {
8
- color: rgb(249 250 251);
15
+ color: var(--start-dt-text);
16
+
17
+ display: flex;
18
+ flex-direction: row;
19
+
20
+ height: 100%;
21
+ }
9
22
 
23
+ [data-start-functions-sidebar] {
10
24
  display: flex;
11
25
  flex-direction: column;
12
26
 
13
- min-height: 100%;
27
+ width: 17rem;
28
+ flex-shrink: 0;
29
+ min-height: 0;
30
+
31
+ border-right: var(--start-dt-border-soft) 1px solid;
32
+ }
33
+
34
+ [data-start-functions-detail] {
35
+ display: flex;
36
+ flex-direction: column;
37
+
38
+ flex: 1;
39
+ min-width: 0;
40
+ min-height: 0;
41
+
42
+ overflow: auto;
14
43
  }
15
44
 
16
45
  [data-start-functions-instances-container] {
17
- color: rgb(249 250 251);
46
+ color: var(--start-dt-text);
18
47
  width: 100%;
19
- min-height: 100%;
48
+ flex: 1;
49
+ min-height: 0;
20
50
  overflow: auto;
21
51
  }
22
52
 
@@ -31,8 +61,12 @@
31
61
  display: flex;
32
62
  align-items: center;
33
63
  justify-content: space-between;
34
- padding: 0.5rem;
35
- color: rgb(249 250 251);
64
+ gap: 0.5rem;
65
+ padding: 0.5rem 0.75rem;
66
+ color: var(--start-dt-text);
67
+ font-family:
68
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
69
+ monospace;
36
70
  }
37
71
 
38
72
  [data-start-headers] {
@@ -60,16 +94,21 @@
60
94
  gap: 0.25rem;
61
95
  }
62
96
 
97
+ [data-start-property] > [data-start-text-weight="semibold"] {
98
+ color: var(--start-dt-text-muted);
99
+ }
100
+
63
101
  [data-start-function-instance-viewer] {
64
102
  display: flex;
65
103
  flex-direction: column;
66
104
 
67
105
  width: 100%;
106
+ min-height: 100%;
68
107
  }
69
108
 
70
109
  [data-start-function-instance-viewer-nav],
71
110
  [data-start-functions-nav] {
72
- padding: 0.5rem;
111
+ padding: 0.5rem 0.75rem;
73
112
  display: flex;
74
113
  align-items: center;
75
114
  gap: 0.5rem;
@@ -78,32 +117,126 @@
78
117
 
79
118
  position: sticky;
80
119
  top: 0;
120
+ z-index: 1;
121
+
122
+ border-bottom: var(--start-dt-border-soft) 1px solid;
81
123
 
82
- border-bottom: oklch(87% 0.065 274.039) 1px solid;
124
+ background: var(--start-dt-bg-glass);
125
+ backdrop-filter: blur(16px) saturate(140%);
126
+ -webkit-backdrop-filter: blur(16px) saturate(140%);
127
+ }
83
128
 
84
- background: oklch(25.7% 0.09 281.288);
129
+ [data-start-functions-nav] {
130
+ justify-content: flex-start;
131
+ flex-shrink: 0;
85
132
  }
86
133
 
87
134
  [data-start-functions-nav] svg {
88
135
  padding: 0.25rem;
136
+ color: var(--start-dt-accent);
137
+ }
138
+
139
+ [data-start-function-instance-viewer-nav] > div:last-child {
140
+ display: flex;
141
+ align-items: center;
142
+ gap: 0.5rem;
143
+
144
+ flex-shrink: 0;
145
+ }
146
+
147
+ [data-start-function-instance-timing] {
148
+ display: inline-flex;
149
+ align-items: center;
150
+
151
+ color: var(--start-dt-text-muted);
152
+ background: var(--start-dt-surface);
153
+ border-radius: 9999px;
154
+ padding: 0.125rem 0.5rem;
155
+ }
156
+
157
+ /* Body section (the only non-collapsible <div> section in a tab panel) fills the pane;
158
+ the minimum keeps it inspectable even when Headers/Information are expanded — the
159
+ tab panel scrolls instead of squeezing the body. */
160
+ [data-start-tab-panel] > div[data-start-section]:first-child {
161
+ flex: 1 1 auto;
162
+ min-height: 18rem;
163
+ }
164
+
165
+ [data-start-tab-panel] > div[data-start-section]:first-child > [data-start-section-content] {
166
+ flex: 1;
167
+ min-height: 0;
89
168
  }
90
169
 
91
170
  [data-start-function-instance-viewer-nav-left] {
92
171
  display: flex;
93
172
  align-items: center;
94
173
  gap: 0.5rem;
174
+
175
+ min-width: 0;
95
176
  }
96
177
 
97
178
  [data-start-function-instance-viewer-nav-left] > div {
98
179
  display: flex;
99
180
  align-items: center;
100
181
  gap: 0.5rem;
182
+
183
+ min-width: 0;
101
184
  }
102
185
 
103
186
  [data-start-function-instance-viewer-content] {
104
- height: 100%;
187
+ flex: 1;
188
+ min-height: 0;
105
189
  }
106
190
 
107
191
  [data-start-function-instance-viewer-content] > [tc-tab-group] {
108
192
  height: 100%;
193
+
194
+ display: flex;
195
+ flex-direction: column;
196
+ }
197
+
198
+ /* shared key-value table (headers, form data, url search params) */
199
+ [data-start-kv-table] {
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: 0;
203
+
204
+ border: 1px var(--start-dt-border-soft) solid;
205
+ border-radius: 0.5rem;
206
+ overflow: hidden;
207
+ }
208
+
209
+ [data-start-kv-row] {
210
+ display: flex;
211
+ align-items: baseline;
212
+ gap: 0.75rem;
213
+
214
+ padding: 0.375rem 0.625rem;
215
+ }
216
+
217
+ [data-start-kv-row]:nth-child(even) {
218
+ background-color: oklch(1 0 0 / 0.03);
219
+ }
220
+
221
+ [data-start-kv-row]:hover {
222
+ background-color: var(--start-dt-surface-hover);
223
+ }
224
+
225
+ [data-start-kv-key] {
226
+ flex: 0 0 11rem;
227
+ min-width: 0;
228
+
229
+ overflow: hidden;
230
+ text-overflow: ellipsis;
231
+
232
+ color: oklch(0.78 0.1 305);
233
+ }
234
+
235
+ [data-start-kv-value] {
236
+ flex: 1;
237
+ min-width: 0;
238
+
239
+ word-break: break-all;
240
+
241
+ color: var(--start-dt-text);
109
242
  }
@@ -1,4 +1,19 @@
1
1
  [data-start-dev-toolbar] {
2
+ /* design tokens — inherited by every panel and ui component inside */
3
+ --start-dt-bg: oklch(0.16 0.015 265);
4
+ --start-dt-bg-glass: oklch(0.17 0.015 265 / 0.88);
5
+ --start-dt-surface: oklch(0.22 0.02 265);
6
+ --start-dt-surface-hover: oklch(0.27 0.025 265);
7
+ --start-dt-surface-active: oklch(0.3 0.03 265);
8
+ --start-dt-border: oklch(0.34 0.02 265);
9
+ --start-dt-border-soft: oklch(0.27 0.02 265);
10
+ --start-dt-text: oklch(0.93 0.005 265);
11
+ --start-dt-text-muted: oklch(0.68 0.015 265);
12
+ --start-dt-accent: oklch(0.68 0.13 245);
13
+ --start-dt-accent-soft: oklch(0.68 0.13 245 / 0.16);
14
+ --start-dt-danger: oklch(0.63 0.21 25);
15
+ --start-dt-shadow: 0 12px 32px oklch(0 0 0 / 0.4), 0 2px 8px oklch(0 0 0 / 0.25);
16
+
2
17
  position: fixed;
3
18
 
4
19
  bottom: 0px;
@@ -8,19 +23,31 @@
8
23
  flex-direction: column-reverse;
9
24
  align-items: flex-start;
10
25
 
26
+ z-index: 2147483647;
27
+
28
+ color: var(--start-dt-text);
29
+ font-family:
30
+ system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
31
+ "Noto Color Emoji";
32
+ }
33
+
34
+ [data-start-dev-toolbar] > [tc-toolbar] {
11
35
  cursor: grab;
12
36
  }
13
37
 
14
- [data-start-dev-toolbar]:active {
38
+ [data-start-dev-toolbar] > [tc-toolbar]:active {
15
39
  cursor: grabbing;
16
40
  }
17
41
 
18
42
  [data-start-dev-toolbar] > [tc-toolbar] {
19
43
  position: relative;
20
44
 
21
- background: oklch(25.7% 0.09 281.288);
45
+ background: var(--start-dt-bg-glass);
46
+ backdrop-filter: blur(16px) saturate(140%);
47
+ -webkit-backdrop-filter: blur(16px) saturate(140%);
48
+
22
49
  margin: 1rem;
23
- padding: 0.25rem 0.5rem;
50
+ padding: 0.375rem 0.625rem;
24
51
 
25
52
  overflow: hidden;
26
53
  border-radius: 9999px;
@@ -29,9 +56,10 @@
29
56
  flex-direction: row;
30
57
  align-items: center;
31
58
 
32
- gap: 0.5rem;
59
+ gap: 0.625rem;
33
60
 
34
- border: oklch(87% 0.065 274.039) 1px solid;
61
+ border: var(--start-dt-border) 1px solid;
62
+ box-shadow: var(--start-dt-shadow);
35
63
  }
36
64
 
37
65
  [data-start-dev-toolbar] > [tc-toolbar] > div {
@@ -40,25 +68,30 @@
40
68
  flex-direction: row;
41
69
  align-items: center;
42
70
  justify-content: center;
71
+
72
+ gap: 0.125rem;
43
73
  }
44
74
 
45
75
  [data-start-dev-toolbar] > [tc-toolbar] > div:last-child {
46
- border-left: rgb(249 250 251) 1px solid;
47
- padding-left: 0.5rem;
76
+ border-left: var(--start-dt-border) 1px solid;
77
+ padding-left: 0.625rem;
48
78
 
49
79
  gap: 0.5rem;
80
+
81
+ color: var(--start-dt-text-muted);
50
82
  }
51
83
 
52
84
  [data-start-dev-toolbar-version] {
53
85
  border-radius: 9999px;
54
- color: rgb(249 250 251);
86
+ color: var(--start-dt-accent);
87
+ background: var(--start-dt-accent-soft);
55
88
  padding: 0.125rem 0.5rem;
56
89
 
57
90
  font-size: 0.875rem;
58
91
  line-height: 1.25rem;
59
92
  font-weight: 600;
60
93
 
61
- border: oklch(87% 0.065 274.039) 1px solid;
94
+ border: none;
62
95
  }
63
96
 
64
97
  [data-start-dev-toolbar-version] > div {
@@ -72,14 +105,21 @@
72
105
  }
73
106
 
74
107
  [data-start-dev-toolbar-panel] {
75
- border: oklch(87% 0.065 274.039) 1px solid;
76
- background: oklch(25.7% 0.09 281.288);
108
+ border: var(--start-dt-border) 1px solid;
109
+ background: var(--start-dt-bg-glass);
110
+ backdrop-filter: blur(16px) saturate(140%);
111
+ -webkit-backdrop-filter: blur(16px) saturate(140%);
112
+ box-shadow: var(--start-dt-shadow);
113
+
77
114
  margin: 0rem 1rem;
78
115
 
79
- overflow: auto;
116
+ overflow: hidden;
117
+
118
+ display: flex;
119
+ flex-direction: column;
80
120
 
81
- width: 50rem;
82
- height: 30rem;
121
+ width: 56rem;
122
+ height: min(40rem, calc(100vh - 4rem));
83
123
 
84
124
  max-width: calc(100vw - 10rem);
85
125
  max-height: calc(100vh - 2rem);
@@ -19,6 +19,8 @@ export function DevToolbar(props) {
19
19
  createEffect(() => {
20
20
  const current = ref();
21
21
  if (current) {
22
+ // Only the toolbar pill itself is the drag handle — panels/popovers are not draggable.
23
+ const handle = current.querySelector(":scope > [tc-toolbar]") ?? current;
22
24
  let isDown = false;
23
25
  // Offsets of the mouse relatively to the element's position
24
26
  let offsetX = 0;
@@ -35,7 +37,7 @@ export function DevToolbar(props) {
35
37
  };
36
38
  let isDirty = false;
37
39
  const ac = new AbortController();
38
- current.addEventListener("mousedown", e => {
40
+ handle.addEventListener("mousedown", e => {
39
41
  isDown = true;
40
42
  const rect = current.getBoundingClientRect();
41
43
  currentX = rect.left;
@@ -111,9 +113,14 @@ export function DevToolbar(props) {
111
113
  }
112
114
  pushError(error.error ?? error);
113
115
  };
116
+ const onRejectionEvent = (event) => {
117
+ pushError(event.reason);
118
+ };
114
119
  window.addEventListener("error", onErrorEvent);
120
+ window.addEventListener("unhandledrejection", onRejectionEvent);
115
121
  onCleanup(() => {
116
122
  window.removeEventListener("error", onErrorEvent);
123
+ window.removeEventListener("unhandledrejection", onRejectionEvent);
117
124
  });
118
125
  });
119
126
  const [store, setStore] = createStore({
@@ -5,29 +5,40 @@
5
5
  gap: 0.25rem;
6
6
 
7
7
  border-radius: 0.375rem;
8
- padding: 0.125rem 0.25rem;
8
+ padding: 0.125rem 0.375rem;
9
+
10
+ font-size: 0.75rem;
11
+ line-height: 1rem;
12
+ font-weight: 600;
13
+ font-family:
14
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
15
+ monospace;
9
16
 
10
17
  background-color: var(--background);
11
- border: 1px var(--foreground) solid;
18
+ border: 1px var(--border) solid;
12
19
  color: var(--foreground);
13
20
  }
14
21
 
15
22
  [data-start-badge="success"] {
16
- --background: oklch(98.2% 0.018 155.826);
17
- --foreground: oklch(52.7% 0.154 150.069);
23
+ --background: oklch(0.63 0.15 150 / 0.14);
24
+ --border: oklch(0.63 0.15 150 / 0.4);
25
+ --foreground: oklch(0.8 0.14 152);
18
26
  }
19
27
 
20
28
  [data-start-badge="failure"] {
21
- --background: oklch(97.1% 0.013 17.38);
22
- --foreground: oklch(50.5% 0.213 27.518);
29
+ --background: oklch(0.63 0.21 25 / 0.14);
30
+ --border: oklch(0.63 0.21 25 / 0.4);
31
+ --foreground: oklch(0.78 0.15 22);
23
32
  }
24
33
 
25
34
  [data-start-badge="warning"] {
26
- --background: oklch(98.7% 0.026 102.212);
27
- --foreground: oklch(47.6% 0.114 61.907);
35
+ --background: oklch(0.75 0.15 85 / 0.14);
36
+ --border: oklch(0.75 0.15 85 / 0.4);
37
+ --foreground: oklch(0.85 0.13 88);
28
38
  }
29
39
 
30
40
  [data-start-badge="info"] {
31
- --background: oklch(97% 0.014 254.604);
32
- --foreground: oklch(48.8% 0.243 264.376);
41
+ --background: oklch(0.68 0.13 245 / 0.14);
42
+ --border: oklch(0.68 0.13 245 / 0.4);
43
+ --foreground: oklch(0.78 0.11 245);
33
44
  }