feat: dark-tech UI redesign + markdown patch cards

Redesign the frontend with a dark-tech theme: add Tailwind + PostCSS,
design tokens, and shadcn-style primitives (Button/Card/Input/Dialog/
DropdownMenu/Tabs/ScrollArea/etc.); restyle the app shell, navigation,
sidebar tree, content view, markdown rendering, editors, modals and
settings panels. Behavior/props unchanged; Font Awesome replaced with
lucide-react.

Add the patch cards feature UI: patch-queries hooks and a PatchCards
component rendered below the markdown body, with an Add Patch button
and create/edit dialog.

Fix tree expandability: folders with an index page now expand on name
click (and navigate), and the chevron+folder icon is one larger toggle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-05-16 17:28:13 +01:00
parent 045c7c51d6
commit 952387d50f
54 changed files with 4503 additions and 1765 deletions

View File

@@ -1,5 +1,8 @@
import React, {useEffect, useState} from "react";
import { Plus, Trash2, ChevronDown, ChevronRight } from "lucide-react";
import TypeEditor from "./TypeEditor";
import { Input, Label } from "../ui/input";
import { Button } from "../ui/button";
const ParametersManager = ({ parameters, onChange }) => {
const [_parameters, setParameters] = useState(parameters || []);
@@ -10,7 +13,7 @@ const ParametersManager = ({ parameters, onChange }) => {
..._parameters,
{
name: "",
type: {
type: {
base_type: "string",
definition: {}
}
@@ -59,56 +62,53 @@ const ParametersManager = ({ parameters, onChange }) => {
};
return (
<div className="box">
<div className="field">
<div className="control">
<button className="button is-primary" onClick={handleAdd}>
Add Parameter
</button>
</div>
</div>
<div style={{ maxHeight: "50vh", overflowY: "auto" }}>
<div className="space-y-4 rounded-lg border border-border bg-card p-5">
<Button type="button" onClick={handleAdd}>
<Plus className="h-4 w-4" /> Add Parameter
</Button>
<div className="max-h-[50vh] space-y-3 overflow-y-auto">
{_parameters.map((param, index) => (
<div key={index} className="box" style={{ marginBottom: "0.5rem" }}>
<div className="field is-grouped is-align-items-end">
<div className="control">
<label className="label">Name:</label>
</div>
<div className="control is-expanded">
<input
<div key={index} className="space-y-3 rounded-md border border-border bg-surface/40 p-4">
<div className="flex items-end gap-2">
<div className="flex-1 space-y-1.5">
<Label>Name</Label>
<Input
type="text"
className="input"
value={param.name}
onChange={(e) => handleNameChange(index, e.target.value)}
placeholder="Parameter name"
/>
</div>
<div className="control">
<button
className="button is-danger"
onClick={() => handleDelete(index)}
>
Delete
</button>
</div>
<Button
type="button"
variant="destructive"
size="icon"
onClick={() => handleDelete(index)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
<div className="field">
<div className="is-flex is-justify-content-space-between is-align-items-center mb-1">
<label className="label mb-0">Type:</label>
<button
className="button is-small"
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label>Type</Label>
<Button
type="button"
variant="ghost"
size="icon-sm"
onClick={() => toggleExpand(index)}
>
{expandedStates[index] ? "-" : "+"}
</button>
{expandedStates[index] ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
</div>
{expandedStates[index] && (
<div className="control">
<TypeEditor
type={param.type}
onChange={(newType) => handleTypeChange(index, newType)}
/>
</div>
<TypeEditor
type={param.type}
onChange={(newType) => handleTypeChange(index, newType)}
/>
)}
</div>
</div>