Skip to content

Commit 9f76ed4

Browse files
committed
Basic structural spike
1 parent fafd861 commit 9f76ed4

File tree

5 files changed

+208
-22
lines changed

5 files changed

+208
-22
lines changed

src/components/PreactTest.tsx

-13
This file was deleted.

src/components/play/playground.tsx

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import { useState } from "preact/hooks"
2+
3+
export function SearchPlayground() {
4+
const [root, setRoot] = useState<Group>([{
5+
occur: '',
6+
node:createClauseNode({specifier: 'todo specifier', value: 'todo value'})
7+
}])
8+
9+
return (
10+
<Group group={root} onChange={setRoot} />
11+
)
12+
}
13+
14+
type Group = GroupEntry[]
15+
16+
type GroupProps = {
17+
group: Group
18+
onChange: (group: Group) => void
19+
}
20+
21+
function Group({ group, onChange }: GroupProps) {
22+
return (
23+
<div style={{ border: '1px solid red', padding: 5 }}>
24+
{group.map((entry, index) => (
25+
<GroupEntry
26+
key={index}
27+
entry={entry}
28+
onChange={entry => {
29+
const newGroup = [...group]
30+
newGroup[index] = entry
31+
onChange(newGroup)
32+
}}
33+
/>
34+
))}
35+
36+
<button onClick={() => onChange([...group, { occur: '', node: createClauseNode() }])}>add clause</button>
37+
<button onClick={() => onChange([...group, { occur: '', node: createGroupNode() }])}>add group</button>
38+
</div>
39+
)
40+
}
41+
42+
type GroupEntry = {
43+
occur: Occur,
44+
node: Node
45+
}
46+
47+
48+
49+
type GroupEntryProps = {
50+
entry: GroupEntry
51+
onChange: (entry: GroupEntry) => void
52+
}
53+
54+
function GroupEntry({ entry, onChange }: GroupEntryProps) {
55+
return (
56+
<div>
57+
<Occur occur={entry.occur} onChange={occur => onChange({ ...entry, occur })} />
58+
<Node node={entry.node} onChange={node => onChange({ ...entry, node })} />
59+
</div>
60+
)
61+
}
62+
63+
type Node =
64+
| { type: 'clause', clause: Clause }
65+
| { type: 'group', group: Group }
66+
67+
function createClauseNode(clause: Partial<Clause> = {}): Node {
68+
return { type: 'clause', clause: createClause(clause) }
69+
}
70+
71+
function createGroupNode(group: Group = []): Node {
72+
return { type: 'group', group }
73+
}
74+
75+
type NodeProps = {
76+
node: Node
77+
onChange: (node: Node) => void
78+
}
79+
80+
function Node({ node, onChange }: NodeProps) {
81+
switch (node.type) {
82+
case 'clause': {
83+
return <Clause clause={node.clause} onChange={clause => onChange({ type: 'clause', clause })} />
84+
}
85+
case "group": {
86+
return <Group group={node.group} onChange={group => onChange({ type: 'group', group })} />
87+
}
88+
default: throw new UnreachableException(node)
89+
}
90+
}
91+
92+
const OCCUR = ['', '+', '-'] as const
93+
type Occur = (typeof OCCUR)[number]
94+
95+
type OccurProps = {
96+
occur: Occur,
97+
onChange: (occur: Occur) => void
98+
}
99+
100+
function Occur({ occur, onChange }: OccurProps) {
101+
// TODO: would be nice to include meaningful text with these, without it
102+
// bleeding into the idle state
103+
return (
104+
<select
105+
value={occur}
106+
onChange={event => onChange(event.currentTarget.value as Occur)}
107+
>
108+
{OCCUR.map(occur => (
109+
<option key={occur} value={occur}>{occur}</option>
110+
))}
111+
</select>
112+
)
113+
}
114+
115+
type Clause = {
116+
specifier: Specifier,
117+
operation: Operation,
118+
value: Value,
119+
}
120+
121+
function createClause(clause: Partial<Clause> = {}): Clause {
122+
return {
123+
specifier: '',
124+
operation: '=',
125+
value: '',
126+
...clause
127+
}
128+
}
129+
130+
type ClauseProps = {
131+
clause: Clause
132+
onChange: (clause: Clause) => void
133+
}
134+
135+
function Clause({ clause, onChange }: ClauseProps) {
136+
return <>
137+
<Specifier specifier={clause.specifier} onChange={specifier => onChange({ ...clause, specifier })} />
138+
<Operation operation={clause.operation} onChange={operation => onChange({ ...clause, operation })} />
139+
<Value value={clause.value} onChange={value => onChange({ ...clause, value })} />
140+
</>
141+
}
142+
143+
type Specifier = string
144+
145+
type SpecifierProps = {
146+
specifier: Specifier,
147+
onChange: (specifier: Specifier) => void
148+
}
149+
150+
function Specifier({ specifier, onChange }: SpecifierProps) {
151+
return <input
152+
value={specifier}
153+
onInput={event => onChange(event.currentTarget.value)}
154+
/>
155+
}
156+
157+
const OPERATIONS = ['=', '~', '>=', '>', '<=', '<'] as const
158+
type Operation = (typeof OPERATIONS)[number]
159+
160+
type OperationProps = {
161+
operation: Operation,
162+
onChange: (operation: Operation) => void
163+
}
164+
165+
function Operation({ operation, onChange }: OperationProps) {
166+
// TODO: would be nice to include meaningful text with these, without it
167+
// bleeding into the idle state
168+
return (
169+
<select
170+
value={operation}
171+
onChange={event => onChange(event.currentTarget.value as Operation)}
172+
>
173+
{OPERATIONS.map(operation => (
174+
<option key={operation} value={operation}>{operation}</option>
175+
))}
176+
</select>
177+
)
178+
}
179+
180+
type Value = string
181+
182+
type ValueProps = {
183+
value: Value,
184+
onChange: (value: Value) => void
185+
}
186+
187+
function Value({ value, onChange }: ValueProps) {
188+
return <input
189+
value={value}
190+
onInput={event => onChange(event.currentTarget.value)}
191+
/>
192+
}
193+
194+
class UnreachableException {
195+
constructor(_value: never) { }
196+
}

src/pages/docs/test.astro

-9
This file was deleted.

src/pages/play.astro

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
import StarlightPage, { type StarlightPageProps } from "@astrojs/starlight/components/StarlightPage.astro";
3+
import { SearchPlayground } from "components/play/playground";
4+
5+
type Frontmatter = StarlightPageProps['frontmatter']
6+
const frontmatter: Frontmatter = { title: "Playground", template: 'splash' }
7+
---
8+
9+
<StarlightPage frontmatter={frontmatter}>
10+
<SearchPlayground client:idle />
11+
</StarlightPage>

tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"include": [".astro/types.d.ts", "**/*"],
44
"exclude": ["dist"],
55
"compilerOptions": {
6+
"baseUrl": "src",
67
"jsx": "react-jsx",
78
"jsxImportSource": "preact"
89
}

0 commit comments

Comments
 (0)