Refactor renamed the component groups to something less obtuse:

Elements -> Groups -> Screens -> Views
This commit is contained in:
cliffhall 2026-03-28 12:58:47 -04:00
commit dd46acba87
2 changed files with 151 additions and 144 deletions

View file

@ -0,0 +1,61 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { fn } from "storybook/test";
import { RootsTable } from "./RootsTable";
const meta: Meta<typeof RootsTable> = {
title: "Groups/RootsTable",
component: RootsTable,
args: {
onRemoveRoot: fn(),
onNewRootNameChange: fn(),
onNewRootPathChange: fn(),
onAddRoot: fn(),
onBrowse: fn(),
},
};
export default meta;
type Story = StoryObj<typeof RootsTable>;
export const WithRoots: Story = {
args: {
roots: [
{ name: "Project Source", uri: "file:///home/user/project/src" },
{ name: "Configuration", uri: "file:///home/user/project/config" },
{ name: "Documentation", uri: "file:///home/user/project/docs" },
],
newRootName: "",
newRootPath: "",
},
};
export const Empty: Story = {
args: {
roots: [],
newRootName: "",
newRootPath: "",
},
};
export const AddingNew: Story = {
args: {
roots: [{ name: "Project Source", uri: "file:///home/user/project/src" }],
newRootName: "Test Data",
newRootPath: "/home/user/project/test-data",
},
};
export const ManyRoots: Story = {
args: {
roots: [
{ name: "Source Code", uri: "file:///home/user/project/src" },
{ name: "Configuration", uri: "file:///home/user/project/config" },
{ name: "Documentation", uri: "file:///home/user/project/docs" },
{ name: "Test Fixtures", uri: "file:///home/user/project/test/fixtures" },
{ name: "Build Output", uri: "file:///home/user/project/dist" },
{ name: "Scripts", uri: "file:///home/user/project/scripts" },
],
newRootName: "",
newRootPath: "",
},
};

View file

@ -0,0 +1,113 @@
import {
ActionIcon,
Alert,
Button,
Divider,
Group,
Stack,
Table,
Text,
TextInput,
Title,
} from "@mantine/core";
export interface RootEntry {
name: string;
uri: string;
}
export interface RootsTableProps {
roots: RootEntry[];
newRootName: string;
newRootPath: string;
onRemoveRoot: (uri: string) => void;
onNewRootNameChange: (name: string) => void;
onNewRootPathChange: (path: string) => void;
onAddRoot: () => void;
onBrowse: () => void;
}
const HintText = Text.withProps({
size: "sm",
c: "dimmed",
});
const RemoveIcon = ActionIcon.withProps({
color: "red",
variant: "subtle",
});
const AddRootButton = Button.withProps({
variant: "light",
fullWidth: true,
});
export function RootsTable({
roots,
newRootName,
newRootPath,
onRemoveRoot,
onNewRootNameChange,
onNewRootPathChange,
onAddRoot,
onBrowse,
}: RootsTableProps) {
return (
<Stack gap="md">
<Title order={4}>Roots Configuration</Title>
<HintText>Filesystem roots exposed to the connected server:</HintText>
{roots.length > 0 && (
<Table>
<Table.Thead>
<Table.Tr>
<Table.Th>Name</Table.Th>
<Table.Th>URI</Table.Th>
<Table.Th>Actions</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{roots.map((root) => (
<Table.Tr key={root.uri}>
<Table.Td>{root.name}</Table.Td>
<Table.Td>{root.uri}</Table.Td>
<Table.Td>
<RemoveIcon onClick={() => onRemoveRoot(root.uri)}>
X
</RemoveIcon>
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
)}
<AddRootButton onClick={onAddRoot}>+ Add Root</AddRootButton>
<Divider />
<Title order={5}>Add New Root:</Title>
<TextInput
label="Name"
value={newRootName}
onChange={(e) => onNewRootNameChange(e.currentTarget.value)}
/>
<TextInput
label="Path"
value={newRootPath}
onChange={(e) => onNewRootPathChange(e.currentTarget.value)}
/>
<Group justify="flex-end">
<Button variant="light" onClick={onBrowse}>
Browse
</Button>
<Button onClick={onAddRoot}>Add</Button>
</Group>
<Alert color="yellow" title="Warning">
Roots give the server access to these directories. Only add directories
you trust the server to access.
</Alert>
</Stack>
);
}