Skip to content

Commit 258adc5

Browse files
authored
Merge pull request #4 from TanStack/feat/settings-page
feat: add settings page
2 parents b156e6e + 01bd162 commit 258adc5

File tree

12 files changed

+6495
-244
lines changed

12 files changed

+6495
-244
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"size-limit": [
4848
{
4949
"path": "packages/devtools/dist/esm/index.js",
50-
"limit": "20 KB"
50+
"limit": "30 KB"
5151
}
5252
],
5353
"devDependencies": {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { createSignal } from 'solid-js'
2+
import { useStyles } from '../styles/use-styles'
3+
4+
interface CheckboxProps {
5+
label?: string
6+
checked?: boolean
7+
onChange?: (checked: boolean) => void
8+
description?: string
9+
}
10+
11+
export function Checkbox(props: CheckboxProps) {
12+
const styles = useStyles()
13+
const [isChecked, setIsChecked] = createSignal(props.checked || false)
14+
15+
const handleChange = (e: Event) => {
16+
const checked = (e.target as HTMLInputElement).checked
17+
setIsChecked(checked)
18+
props.onChange?.(checked)
19+
}
20+
21+
return (
22+
<div class={styles().checkboxContainer}>
23+
<label class={styles().checkboxWrapper}>
24+
<input
25+
type="checkbox"
26+
checked={isChecked()}
27+
class={styles().checkbox}
28+
onInput={handleChange}
29+
/>
30+
<div class={styles().checkboxLabelContainer}>
31+
{props.label && (
32+
<span class={styles().checkboxLabel}>{props.label}</span>
33+
)}
34+
{props.description && (
35+
<span class={styles().checkboxDescription}>
36+
{props.description}
37+
</span>
38+
)}
39+
</div>
40+
</label>
41+
</div>
42+
)
43+
}

packages/devtools/src/components/content-panel.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useDevtoolsSettings } from '../context/use-devtools-context'
12
import { useStyles } from '../styles/use-styles'
23
import type { JSX } from 'solid-js/jsx-runtime'
34

@@ -7,11 +8,12 @@ export const ContentPanel = (props: {
78
handleDragStart?: (e: any) => void
89
}) => {
910
const styles = useStyles()
11+
const { settings } = useDevtoolsSettings()
1012
return (
1113
<div ref={props.ref} class={styles().devtoolsPanel}>
1214
{props.handleDragStart ? (
1315
<div
14-
class={styles().dragHandle}
16+
class={styles().dragHandle(settings().panelLocation)}
1517
onMouseDown={props.handleDragStart}
1618
></div>
1719
) : null}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { createSignal } from 'solid-js'
2+
import { useStyles } from '../styles/use-styles'
3+
4+
interface InputProps {
5+
label?: string
6+
type?: 'text' | 'number' | 'password' | 'email'
7+
value?: string
8+
placeholder?: string
9+
onChange?: (value: string) => void
10+
description?: string
11+
}
12+
13+
export function Input(props: InputProps) {
14+
const styles = useStyles()
15+
const [val, setVal] = createSignal(props.value || '')
16+
17+
const handleChange = (e: Event) => {
18+
const value = (e.target as HTMLInputElement).value
19+
setVal((prev) => (prev !== value ? value : prev))
20+
props.onChange?.(value)
21+
}
22+
23+
return (
24+
<div class={styles().inputContainer}>
25+
<div class={styles().inputWrapper}>
26+
{props.label && (
27+
<label class={styles().inputLabel}>{props.label}</label>
28+
)}
29+
{props.description && (
30+
<p class={styles().inputDescription}>{props.description}</p>
31+
)}
32+
<input
33+
type={props.type || 'text'}
34+
class={styles().input}
35+
value={val()}
36+
placeholder={props.placeholder}
37+
onInput={handleChange}
38+
/>
39+
</div>
40+
</div>
41+
)
42+
}

packages/devtools/src/components/main-panel.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import clsx from 'clsx'
2-
import { useHeight } from '../context/use-devtools-context'
2+
import { useDevtoolsSettings, useHeight } from '../context/use-devtools-context'
33
import { useStyles } from '../styles/use-styles'
44
import { TANSTACK_DEVTOOLS } from '../utils/storage'
55
import type { JSX } from 'solid-js/jsx-runtime'
@@ -12,14 +12,15 @@ export const MainPanel = (props: {
1212
}) => {
1313
const styles = useStyles()
1414
const { height } = useHeight()
15+
const { settings } = useDevtoolsSettings()
1516
return (
1617
<div
1718
id={TANSTACK_DEVTOOLS}
1819
style={{
1920
height: height() + 'px',
2021
}}
2122
class={clsx(
22-
styles().devtoolsPanelContainer,
23+
styles().devtoolsPanelContainer(settings().panelLocation),
2324
styles().devtoolsPanelContainerAnimation(props.isOpen(), height()),
2425
styles().devtoolsPanelContainerVisibility(props.isOpen()),
2526
styles().devtoolsPanelContainerResizing(props.isResizing),
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { createSignal } from 'solid-js'
2+
import { useStyles } from '../styles/use-styles'
3+
4+
interface SelectOption<T extends string | number> {
5+
value: T
6+
label: string
7+
}
8+
9+
interface SelectProps<T extends string | number> {
10+
label?: string
11+
options: Array<SelectOption<T>>
12+
value?: T
13+
onChange?: (value: T) => void
14+
description?: string
15+
}
16+
17+
export function Select<T extends string | number>(props: SelectProps<T>) {
18+
const styles = useStyles()
19+
const [selected, setSelected] = createSignal(
20+
props.value || props.options[0]?.value,
21+
)
22+
23+
const handleChange = (e: Event) => {
24+
const value = (e.target as HTMLSelectElement).value as T
25+
setSelected((prev) => (prev !== value ? value : prev))
26+
props.onChange?.(value)
27+
}
28+
29+
return (
30+
<div class={styles().selectContainer}>
31+
<div class={styles().selectWrapper}>
32+
{props.label && (
33+
<label class={styles().selectLabel}>{props.label}</label>
34+
)}
35+
{props.description && (
36+
<p class={styles().selectDescription}>{props.description}</p>
37+
)}
38+
<select
39+
class={styles().select}
40+
value={selected()}
41+
onInput={handleChange}
42+
>
43+
{props.options.map((opt) => (
44+
<option value={opt.value}>{opt.label}</option>
45+
))}
46+
</select>
47+
</div>
48+
</div>
49+
)
50+
}

packages/devtools/src/components/trigger.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const Trigger = ({
1818
return clsx(
1919
styles().mainCloseBtn,
2020
styles().mainCloseBtnPosition(settings().position),
21-
styles().mainCloseBtnAnimation(isOpen()),
21+
styles().mainCloseBtnAnimation(isOpen(), settings().hideUntilHover),
2222
)
2323
})
2424
return (

packages/devtools/src/devtools.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createEffect, createSignal } from 'solid-js'
1+
import { Show, createEffect, createSignal } from 'solid-js'
22
import { createShortcut } from '@solid-primitives/keyboard'
33
import {
44
useDevtoolsSettings,
@@ -28,24 +28,27 @@ export default function DevTools() {
2828
setIsOpen(!open)
2929
setPersistOpen(!open)
3030
}
31-
31+
createEffect(() => {})
3232
// Used to resize the panel
3333
const handleDragStart = (
3434
panelElement: HTMLDivElement | undefined,
3535
startEvent: MouseEvent,
3636
) => {
3737
if (startEvent.button !== 0) return // Only allow left click for drag
38-
38+
if (!panelElement) return
3939
setIsResizing(true)
4040

4141
const dragInfo = {
42-
originalHeight: panelElement?.getBoundingClientRect().height ?? 0,
42+
originalHeight: panelElement.getBoundingClientRect().height,
4343
pageY: startEvent.pageY,
4444
}
4545

4646
const run = (moveEvent: MouseEvent) => {
4747
const delta = dragInfo.pageY - moveEvent.pageY
48-
const newHeight = dragInfo.originalHeight + delta
48+
const newHeight =
49+
settings().panelLocation === 'bottom'
50+
? dragInfo.originalHeight + delta
51+
: dragInfo.originalHeight - delta
4952

5053
setHeight(newHeight)
5154

@@ -72,7 +75,8 @@ export default function DevTools() {
7275
const previousValue = rootEl()?.parentElement?.style.paddingBottom
7376

7477
const run = () => {
75-
const containerHeight = panelRef!.getBoundingClientRect().height
78+
if (!panelRef) return
79+
const containerHeight = panelRef.getBoundingClientRect().height
7680
if (rootEl()?.parentElement) {
7781
setRootEl((prev) => {
7882
if (prev?.parentElement) {
@@ -126,21 +130,33 @@ export default function DevTools() {
126130
el?.style.setProperty('--tsrd-font-size', fontSize)
127131
}
128132
})
129-
createShortcut(settings().openHotkey, () => {
130-
toggleOpen()
133+
createEffect(() => {
134+
createShortcut(settings().openHotkey, () => {
135+
toggleOpen()
136+
})
131137
})
138+
139+
createEffect(() => {})
132140
return (
133141
<div ref={setRootEl} data-testid={TANSTACK_DEVTOOLS}>
134-
<Trigger isOpen={isOpen} setIsOpen={toggleOpen} />
135-
<MainPanel isResizing={isResizing} isOpen={isOpen}>
136-
<ContentPanel
137-
ref={(ref) => (panelRef = ref)}
138-
handleDragStart={(e) => handleDragStart(panelRef, e)}
139-
>
140-
<Tabs toggleOpen={toggleOpen} />
141-
<TabContent />
142-
</ContentPanel>
143-
</MainPanel>
142+
<Show
143+
when={
144+
settings().requireUrlFlag
145+
? window.location.search.includes(settings().urlFlag)
146+
: true
147+
}
148+
>
149+
<Trigger isOpen={isOpen} setIsOpen={toggleOpen} />
150+
<MainPanel isResizing={isResizing} isOpen={isOpen}>
151+
<ContentPanel
152+
ref={(ref) => (panelRef = ref)}
153+
handleDragStart={(e) => handleDragStart(panelRef, e)}
154+
>
155+
<Tabs toggleOpen={toggleOpen} />
156+
<TabContent />
157+
</ContentPanel>
158+
</MainPanel>
159+
</Show>
144160
</div>
145161
)
146162
}

0 commit comments

Comments
 (0)