Skip to content

Commit 5904452

Browse files
committed
feat: improved UI
1 parent c3bcc4d commit 5904452

8 files changed

Lines changed: 775 additions & 678 deletions

File tree

examples/react-app/src/components/FunctionSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export const FunctionSelector = ({
116116
role="combobox"
117117
aria-autocomplete="list"
118118
aria-expanded={isOpen}
119-
className="h-10 body-m pr-8"
119+
className=" pr-8"
120120
/>
121121
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center space-x-1">
122122
{value && (

examples/react-app/src/components/ProgramAutocomplete.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export const ProgramAutocomplete = ({
160160
role="combobox"
161161
aria-autocomplete="list"
162162
aria-expanded={isOpen}
163-
className="h-10 body-m pr-8"
163+
className="body-m pr-8"
164164
/>
165165
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center space-x-1">
166166
{value && (

examples/react-app/src/components/functions/PrivateInputs.tsx

Lines changed: 417 additions & 389 deletions
Large diffs are not rendered by default.

examples/react-app/src/components/functions/private-inputs/PrimitiveSlotEditor.tsx

Lines changed: 151 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import { ALGORITHM_SCHEMAS, KnownAlgorithm } from '@provablehq/aleo-types';
22
import { Button } from '@/components/ui/button';
33
import { Input } from '@/components/ui/input';
44
import { Label } from '@/components/ui/label';
5+
import {
6+
Select,
7+
SelectContent,
8+
SelectItem,
9+
SelectTrigger,
10+
SelectValue,
11+
} from '@/components/ui/select';
512
import {
613
eligibleAlgorithmsForBaseType,
714
FormState,
@@ -32,133 +39,153 @@ export function PrimitiveSlotEditor({
3239
const algSchema = state.derivedAlgorithm ? ALGORITHM_SCHEMAS[state.derivedAlgorithm] : null;
3340

3441
return (
35-
<div className="space-y-2 border border-dashed border-border rounded-lg p-3">
36-
<Label className="body-s-bold">
37-
{slot.name} <span className="label-xs text-muted-foreground normal-case">({slot.raw})</span>
38-
</Label>
39-
{modes.length > 1 && (
40-
<div className="flex gap-1 flex-wrap">
41-
{modes.map(mode => (
42-
<Button
43-
key={mode}
44-
type="button"
45-
size="sm"
46-
variant={state.mode === mode ? 'default' : 'outline'}
47-
onClick={() => {
48-
const patch: Partial<SlotState> = { mode };
49-
if (mode === 'derived' && !state.derivedAlgorithm && eligibleAlgs[0]) {
50-
(patch as { derivedAlgorithm?: KnownAlgorithm }).derivedAlgorithm =
51-
eligibleAlgs[0];
52-
}
53-
updateSlot(index, patch);
54-
}}
55-
>
56-
{mode === 'literal'
57-
? 'Literal'
58-
: mode === 'address'
59-
? 'Wallet active address'
60-
: 'Derived (wallet computes)'}
61-
</Button>
62-
))}
63-
</div>
64-
)}
65-
{state.mode === 'literal' && (
66-
<Input
67-
placeholder={`aleo literal (e.g. ${slot.baseType}.${slot.visibility === 'public' ? 'public value' : 'value'})`}
68-
value={state.value}
69-
onChange={e => updateSlot(index, { value: e.target.value })}
70-
/>
71-
)}
72-
{state.mode === 'address' && (
73-
<p className="body-s text-muted-foreground">
74-
Sends <code>{`{type:"address"}`}</code>. The wallet fills the slot with the active
75-
address; the dapp never sees it.
76-
</p>
77-
)}
78-
{state.mode === 'derived' && (
79-
<div className="space-y-2">
80-
<div className="space-y-1">
81-
<Label className="body-s">Algorithm</Label>
82-
<select
83-
value={state.derivedAlgorithm}
84-
onChange={e =>
85-
updateSlot(index, {
86-
derivedAlgorithm: e.target.value as KnownAlgorithm | '',
87-
derivedArgs: {},
88-
})
89-
}
90-
className="body-s w-full font-mono rounded-xl border border-input px-3 py-2 shadow-sm bg-background"
91-
>
92-
<option value="">- pick an algorithm -</option>
93-
{eligibleAlgs.map(name => (
94-
<option key={name} value={name}>
95-
{name}
96-
</option>
97-
))}
98-
</select>
42+
<div className="border border-border rounded-lg overflow-hidden ">
43+
{/* Slot header */}
44+
<div className="flex items-center gap-2 px-3 py-2 bg-muted border-b border-border">
45+
<span className="label-xs text-muted-foreground tabular-nums shrink-0">#{index + 1}</span>
46+
<Label className="body-xs-bold">{slot.name}</Label>
47+
<code className="label-xs font-mono bg-primary/10 px-1.5 py-0.5 rounded text-primary">
48+
{slot.raw}
49+
</code>
50+
</div>
51+
52+
{/* Slot body */}
53+
<div className="p-3 space-y-2">
54+
{modes.length > 1 && (
55+
<div className="flex gap-1 flex-wrap rounded-md bg-muted/30 p-1 w-fit">
56+
{modes.map(mode => (
57+
<Button
58+
key={mode}
59+
type="button"
60+
size="sm"
61+
variant={state.mode === mode ? 'default' : 'ghost'}
62+
onClick={() => {
63+
const patch: Partial<SlotState> = { mode };
64+
if (mode === 'derived' && !state.derivedAlgorithm && eligibleAlgs[0]) {
65+
(patch as { derivedAlgorithm?: KnownAlgorithm }).derivedAlgorithm =
66+
eligibleAlgs[0];
67+
}
68+
updateSlot(index, patch);
69+
}}
70+
>
71+
{mode === 'literal'
72+
? 'Literal'
73+
: mode === 'address'
74+
? 'Wallet active address'
75+
: 'Derived (wallet computes)'}
76+
</Button>
77+
))}
9978
</div>
100-
{algSchema && (
101-
<div className="space-y-2 border-l-2 border-muted-foreground/20 pl-3">
102-
<p className="body-s text-muted-foreground">
103-
Output type: <code>{algSchema.outputType}</code>. Sends{' '}
104-
<code>{`{type:"derived", algorithm, args}`}</code>. Authorized only if a matching{' '}
105-
<code>algorithmsAllowed</code> grant exists for{' '}
106-
<code>
107-
{form.programName.trim()}/{form.functionName.trim()}@{index}
108-
</code>
109-
.
110-
</p>
111-
{Object.entries(algSchema.args).map(([argName, rawSchema]) => {
112-
const argSchema = rawSchema as {
113-
type: string;
114-
possibleValues?: readonly string[];
115-
optional?: boolean;
116-
};
117-
const current = state.derivedArgs[argName] ?? '';
118-
const setArg = (value: string) =>
79+
)}
80+
81+
{state.mode === 'literal' && (
82+
<Input
83+
placeholder={`aleo literal (e.g. ${slot.baseType}.${slot.visibility === 'public' ? 'public value' : 'value'})`}
84+
value={state.value}
85+
onChange={e => updateSlot(index, { value: e.target.value })}
86+
/>
87+
)}
88+
89+
{state.mode === 'address' && (
90+
<p className="body-s text-muted-foreground">
91+
Sends <code>{`{type:"address"}`}</code>. The wallet fills the slot with the active
92+
address; the dapp never sees it.
93+
</p>
94+
)}
95+
96+
{state.mode === 'derived' && (
97+
<div className="space-y-2">
98+
<div className="space-y-1">
99+
<Label className="body-s">Algorithm</Label>
100+
<Select
101+
value={state.derivedAlgorithm || undefined}
102+
onValueChange={value =>
119103
updateSlot(index, {
120-
derivedArgs: { ...state.derivedArgs, [argName]: value },
121-
});
122-
return (
123-
<div key={argName} className="space-y-1">
124-
<Label className="body-s">
125-
{argName}{' '}
126-
<span className="label-xs text-muted-foreground normal-case">
127-
({argSchema.type}
128-
{argSchema.optional ? ', optional' : ''})
129-
</span>
130-
</Label>
131-
{argSchema.possibleValues ? (
132-
<select
133-
value={current}
134-
onChange={e => setArg(e.target.value)}
135-
className="body-s w-full font-mono rounded-xl border border-input px-3 py-2 shadow-sm bg-background"
136-
>
137-
{argSchema.optional && <option value="">- omit -</option>}
138-
{argSchema.possibleValues.map(value => (
139-
<option key={value} value={value}>
140-
{value}
141-
</option>
142-
))}
143-
</select>
144-
) : (
145-
<Input
146-
placeholder={
147-
argSchema.type === 'string'
148-
? `value for ${argName}${argSchema.optional ? ' (optional)' : ''}`
149-
: `aleo literal of type ${argSchema.type} (e.g. "12345${argSchema.type}")`
150-
}
151-
value={current}
152-
onChange={e => setArg(e.target.value)}
153-
/>
154-
)}
155-
</div>
156-
);
157-
})}
104+
derivedAlgorithm: value as KnownAlgorithm | '',
105+
derivedArgs: {},
106+
})
107+
}
108+
>
109+
<SelectTrigger className="font-mono rounded-sm">
110+
<SelectValue placeholder="- pick an algorithm -" />
111+
</SelectTrigger>
112+
<SelectContent>
113+
{eligibleAlgs.map(name => (
114+
<SelectItem key={name} value={name} className="font-mono">
115+
{name}
116+
</SelectItem>
117+
))}
118+
</SelectContent>
119+
</Select>
158120
</div>
159-
)}
160-
</div>
161-
)}
121+
122+
{algSchema && (
123+
<div className="rounded-md border border-border overflow-hidden">
124+
<div className="px-3 py-2 bg-muted/30 border-b border-border">
125+
<p className="body-s text-muted-foreground">
126+
Output: <code>{algSchema.outputType}</code>. Sends{' '}
127+
<code>{`{type:"derived", algorithm, args}`}</code>. Needs a matching{' '}
128+
<code>algorithmsAllowed</code> grant for{' '}
129+
<code>
130+
{form.programName.trim()}/{form.functionName.trim()}@{index}
131+
</code>
132+
.
133+
</p>
134+
</div>
135+
<div className="p-3 space-y-2">
136+
{Object.entries(algSchema.args).map(([argName, rawSchema]) => {
137+
const argSchema = rawSchema as {
138+
type: string;
139+
possibleValues?: readonly string[];
140+
optional?: boolean;
141+
};
142+
const current = state.derivedArgs[argName] ?? '';
143+
const setArg = (value: string) =>
144+
updateSlot(index, {
145+
derivedArgs: { ...state.derivedArgs, [argName]: value },
146+
});
147+
return (
148+
<div key={argName} className="space-y-1">
149+
<Label className="body-s">
150+
{argName}{' '}
151+
<span className="label-xs text-muted-foreground normal-case">
152+
({argSchema.type}
153+
{argSchema.optional ? ', optional' : ''})
154+
</span>
155+
</Label>
156+
{argSchema.possibleValues ? (
157+
<Select value={current || undefined} onValueChange={setArg}>
158+
<SelectTrigger className="font-mono rounded-sm">
159+
<SelectValue placeholder="- omit -" />
160+
</SelectTrigger>
161+
<SelectContent>
162+
{argSchema.possibleValues.map(value => (
163+
<SelectItem key={value} value={value} className="font-mono">
164+
{value}
165+
</SelectItem>
166+
))}
167+
</SelectContent>
168+
</Select>
169+
) : (
170+
<Input
171+
placeholder={
172+
argSchema.type === 'string'
173+
? `value for ${argName}${argSchema.optional ? ' (optional)' : ''}`
174+
: `aleo literal of type ${argSchema.type} (e.g. "12345${argSchema.type}")`
175+
}
176+
value={current}
177+
onChange={e => setArg(e.target.value)}
178+
/>
179+
)}
180+
</div>
181+
);
182+
})}
183+
</div>
184+
</div>
185+
)}
186+
</div>
187+
)}
188+
</div>
162189
</div>
163190
);
164191
}

examples/react-app/src/components/functions/private-inputs/RecordRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function RecordRow({ record, index }: RecordRowProps) {
1515
);
1616

1717
return (
18-
<div className="border border-border rounded-lg p-3 space-y-2 transition-all">
18+
<div className="border border-border rounded-lg p-3 space-y-3 transition-all">
1919
<div className="flex items-center justify-between gap-2">
2020
<code className="label-xs truncate normal-case flex-1 min-w-0">
2121
{(record.programName as string | undefined) ?? '?'}.

0 commit comments

Comments
 (0)