Skip to content

Commit 5082d28

Browse files
committed
feat: refactor App and MetadataExplorer components for improved layout and styling; remove unused code and enhance responsiveness
1 parent 90586fe commit 5082d28

8 files changed

Lines changed: 103 additions & 121 deletions

File tree

examples/app-react-crud/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<link rel="preconnect" href="https://fonts.googleapis.com">
7+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet">
69
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
710
<title>ObjectStack MSW + React CRUD Example</title>
811
</head>

examples/app-react-crud/src/App.tsx

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { ObjectDataForm } from './components/ObjectDataForm';
1616
import { Badge } from "@/components/ui/badge";
1717
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
1818
import { ScrollArea } from "@/components/ui/scroll-area";
19-
import { Separator } from "@/components/ui/separator";
2019

2120
export function App() {
2221
const [client, setClient] = useState<ObjectStackClient | null>(null);
@@ -52,11 +51,6 @@ export function App() {
5251

5352
// --- Actions ---
5453

55-
const handleCreate = () => {
56-
setEditingRecord(null); // New record
57-
setView('form');
58-
};
59-
6054
const handleEdit = (record: any) => {
6155
setEditingRecord(record);
6256
setView('form');
@@ -80,7 +74,7 @@ export function App() {
8074
}
8175

8276
return (
83-
<div className="min-h-screen bg-background font-sans flex flex-col text-foreground">
77+
<div className="h-screen bg-background font-sans flex flex-col text-foreground overflow-hidden">
8478
{/* Top Header */}
8579
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
8680
<div className="container flex h-14 items-center px-4 md:px-6">
@@ -103,54 +97,58 @@ export function App() {
10397
</header>
10498

10599
{/* Main Layout */}
106-
<div className="flex flex-1 overflow-hidden">
107-
{/* Sidebar */}
108-
<aside className="hidden w-64 flex-col border-r bg-muted/10 md:flex">
109-
<div className="p-4 font-medium text-sm text-muted-foreground uppercase tracking-wider">
110-
Explorer
100+
<ResizablePanelGroup orientation="horizontal" className="flex-1 w-full border-t">
101+
<ResizablePanel defaultSize={20} minSize={15} maxSize={30} className="hidden md:flex flex-col bg-muted/10">
102+
<div className="flex h-[52px] items-center px-4 border-b">
103+
<h2 className="font-semibold tracking-tight text-sm">Explorer</h2>
111104
</div>
112-
<div className="flex-1 overflow-hidden px-2 pb-4">
113-
<MetadataExplorer
114-
client={client}
115-
selectedObject={selectedObject}
116-
onSelectObject={(obj) => {
117-
setSelectedObject(obj);
118-
setView('list');
119-
setEditingRecord(null);
120-
}}
121-
/>
122-
</div>
123-
</aside>
124-
125-
{/* Content Area */}
126-
<main className="flex-1 overflow-hidden p-4 md:p-6 flex flex-col bg-muted/20 relative">
127-
{selectedObject ? (
128-
<>
129-
<ObjectDataTable
130-
key={`${selectedObject}-${refreshKey}`}
131-
client={client}
132-
objectApiName={selectedObject}
133-
onEdit={handleEdit}
105+
<ScrollArea className="flex-1">
106+
<div className="p-4">
107+
<MetadataExplorer
108+
client={client}
109+
selectedObject={selectedObject}
110+
onSelectObject={(obj) => {
111+
setSelectedObject(obj);
112+
setView('list');
113+
setEditingRecord(null);
114+
}}
134115
/>
135-
{view === 'form' && (
136-
<ObjectDataForm
116+
</div>
117+
</ScrollArea>
118+
</ResizablePanel>
119+
120+
<ResizableHandle withHandle />
121+
122+
<ResizablePanel defaultSize={80}>
123+
<main className="h-full overflow-hidden p-4 md:p-6 flex flex-col bg-muted/20 relative">
124+
{selectedObject ? (
125+
<>
126+
<ObjectDataTable
127+
key={`${selectedObject}-${refreshKey}`}
137128
client={client}
138129
objectApiName={selectedObject}
139-
record={editingRecord}
140-
onSuccess={handleFormSuccess}
141-
onCancel={() => setView('list')}
130+
onEdit={handleEdit}
142131
/>
143-
)}
144-
</>
145-
) : (
146-
<div className="flex flex-col items-center justify-center h-full text-muted-foreground">
147-
<Database className="h-12 w-12 mb-4 opacity-20" />
148-
<div className="text-xl font-medium">Select an Object</div>
149-
<p className="opacity-60">Choose an object from the sidebar to manage data.</p>
150-
</div>
151-
)}
152-
</main>
153-
</div>
132+
{view === 'form' && (
133+
<ObjectDataForm
134+
client={client}
135+
objectApiName={selectedObject}
136+
record={editingRecord}
137+
onSuccess={handleFormSuccess}
138+
onCancel={() => setView('list')}
139+
/>
140+
)}
141+
</>
142+
) : (
143+
<div className="flex flex-col items-center justify-center h-full text-muted-foreground">
144+
<Database className="h-12 w-12 mb-4 opacity-20" />
145+
<div className="text-xl font-medium">Select an Object</div>
146+
<p className="opacity-60">Choose an object from the sidebar to manage data.</p>
147+
</div>
148+
)}
149+
</main>
150+
</ResizablePanel>
151+
</ResizablePanelGroup>
154152
</div>
155153
);
156154
}
Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { useState, useEffect } from 'react';
22
import { ObjectStackClient } from '@objectstack/client';
3-
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
4-
import { ScrollArea } from "@/components/ui/scroll-area";
53
import { Button } from "@/components/ui/button";
64
import { Badge } from "@/components/ui/badge";
75
import { Database, Package } from 'lucide-react';
@@ -45,52 +43,37 @@ export function MetadataExplorer({ client, selectedObject, onSelectObject }: Met
4543
}, [client]);
4644

4745
return (
48-
<Card className="h-full flex flex-col border-border/60">
49-
<CardHeader className="p-4 border-b bg-muted/30">
50-
<CardTitle className="text-sm font-bold flex items-center gap-2">
51-
<Database className="h-4 w-4" />
52-
Registered Objects
53-
</CardTitle>
54-
</CardHeader>
55-
<CardContent className="flex-1 p-0 overflow-hidden">
56-
<ScrollArea className="h-full">
57-
<div className="p-2 space-y-1">
58-
{loading && (
59-
<div className="p-4 text-center text-sm text-muted-foreground animate-pulse">
60-
Loading objects...
61-
</div>
62-
)}
63-
64-
{objects.map(obj => (
65-
<Button
66-
key={obj.name}
67-
variant={selectedObject === obj.name ? "secondary" : "ghost"}
68-
size="sm"
69-
onClick={() => onSelectObject(obj.name)}
70-
className="w-full justify-between font-normal h-9"
71-
>
72-
<div className="flex items-center gap-2 truncate">
73-
<Package className="h-3.5 w-3.5 text-muted-foreground" />
74-
<span>{obj.label}</span>
75-
</div>
76-
<Badge variant="outline" className="text-[10px] h-5 py-0 px-1.5 font-normal opacity-70">
77-
{obj.name}
78-
</Badge>
79-
</Button>
80-
))}
46+
<div className="space-y-1">
47+
{loading && (
48+
<div className="p-4 text-center text-sm text-muted-foreground animate-pulse">
49+
Loading objects...
50+
</div>
51+
)}
52+
53+
{objects.map(obj => (
54+
<Button
55+
key={obj.name}
56+
variant={selectedObject === obj.name ? "secondary" : "ghost"}
57+
size="sm"
58+
onClick={() => onSelectObject(obj.name)}
59+
className="w-full justify-between font-normal h-9"
60+
>
61+
<div className="flex items-center gap-2 truncate">
62+
<Package className="h-3.5 w-3.5 text-muted-foreground" />
63+
<span>{obj.label}</span>
64+
</div>
65+
<Badge variant="outline" className="text-[10px] h-5 py-0 px-1.5 font-normal opacity-70">
66+
{obj.name}
67+
</Badge>
68+
</Button>
69+
))}
8170

82-
{!loading && objects.length === 0 && (
83-
<div className="p-8 text-center text-muted-foreground text-sm flex flex-col items-center gap-2">
84-
<Database className="h-8 w-8 opacity-20" />
85-
<p>No objects found</p>
86-
</div>
87-
)}
71+
{!loading && objects.length === 0 && (
72+
<div className="p-8 text-center text-muted-foreground text-sm flex flex-col items-center gap-2">
73+
<Database className="h-8 w-8 opacity-20" />
74+
<p>No objects found</p>
8875
</div>
89-
</ScrollArea>
90-
</CardContent>
91-
<CardFooter className="p-2 border-t bg-muted/30 text-xs text-muted-foreground justify-center">
92-
Total: {objects.length} Objects
93-
</CardFooter>
94-
</Card>
76+
)}
77+
</div>
9578
);
9679
}
Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1+
"use client"
2+
13
import * as React from "react"
2-
import * as LabelPrimitive from "@radix-ui/react-label" // I don't have this pkg, so I will mock it or just use label
4+
import * as LabelPrimitive from "@radix-ui/react-label"
35
import { cva, type VariantProps } from "class-variance-authority"
6+
47
import { cn } from "@/lib/utils"
58

69
const labelVariants = cva(
710
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
811
)
912

10-
// Since I might not have @radix-ui/react-label, I'll use a standard label
11-
// If the user wants standard shadcn, they usually have the deps.
12-
// But context shows only slot and scroll-area.
13-
// I will just make a styled label component.
14-
1513
const Label = React.forwardRef<
16-
HTMLLabelElement,
17-
React.LabelHTMLAttributes<HTMLLabelElement> & VariantProps<typeof labelVariants>
14+
React.ElementRef<typeof LabelPrimitive.Root>,
15+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
16+
VariantProps<typeof labelVariants>
1817
>(({ className, ...props }, ref) => (
19-
<label
18+
<LabelPrimitive.Root
2019
ref={ref}
2120
className={cn(labelVariants(), className)}
2221
{...props}
2322
/>
2423
))
25-
Label.displayName = "Label" // LabelPrimitive.Root.displayName if using radix
24+
Label.displayName = LabelPrimitive.Root.displayName
2625

2726
export { Label }
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
"use client"
22

33
import * as React from "react"
4-
import { PanelResizeHandle as PanelResizeHandlePrimitive } from "react-resizable-panels"
4+
import { Panel, Group, Separator } from "react-resizable-panels"
55

66
import { cn } from "@/lib/utils"
77

88
const ResizablePanelGroup = ({
99
className,
1010
...props
11-
}: React.ComponentProps<typeof import("react-resizable-panels").PanelGroup>) => (
12-
<import("react-resizable-panels").PanelGroup
11+
}: React.ComponentProps<typeof Group>) => (
12+
<Group
1313
className={cn(
1414
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
1515
className
@@ -18,16 +18,16 @@ const ResizablePanelGroup = ({
1818
/>
1919
)
2020

21-
const ResizablePanel = import("react-resizable-panels").Panel
21+
const ResizablePanel = Panel
2222

2323
const ResizableHandle = ({
2424
withHandle,
2525
className,
2626
...props
27-
}: React.ComponentProps<typeof PanelResizeHandlePrimitive> & {
27+
}: React.ComponentProps<typeof Separator> & {
2828
withHandle?: boolean
2929
}) => (
30-
<PanelResizeHandlePrimitive
30+
<Separator
3131
className={cn(
3232
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
3333
className
@@ -39,7 +39,7 @@ const ResizableHandle = ({
3939
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" className="h-2.5 w-2.5"><path d="M5.5 4.625C5.5 4.41789 5.33211 4.25 5.125 4.25C4.91789 4.25 4.75 4.41789 4.75 4.625V10.375C4.75 10.5821 4.91789 10.75 5.125 10.75C5.33211 10.75 5.5 10.5821 5.5 10.375V4.625ZM9.5 4.625C9.5 4.41789 9.33211 4.25 9.125 4.25C8.91789 4.25 8.75 4.41789 8.75 4.625V10.375C8.75 10.5821 8.91789 10.75 9.125 10.75C9.33211 10.75 9.5 10.5821 9.5 10.375V4.625Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg>
4040
</div>
4141
)}
42-
</PanelResizeHandlePrimitive>
42+
</Separator>
4343
)
4444

4545
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }

examples/app-react-crud/src/index.css

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@
8282
}
8383

8484
body {
85-
background-color: var(--background);
86-
color: var(--foreground);
87-
-webkit-font-smoothing: antialiased;
88-
-moz-osx-font-smoothing: grayscale;
89-
font-family: 'Inter', sans-serif;
85+
@apply bg-background text-foreground;
86+
}
87+
88+
* {
89+
@apply border-border;
9090
}
9191
}

examples/app-react-crud/test/api.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('App React CRUD Integration Tests (Virtual Browser)', () => {
1515
});
1616

1717
it('should boot kernel and have seeded data available immediately', async () => {
18-
const { client, kernel } = env;
18+
const { client } = env;
1919

2020
console.log('[Test] Verifying network-to-kernel bridge...');
2121

examples/app-react-crud/test/dom-rendering.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// @vitest-environment happy-dom
22
import { describe, it, expect } from 'vitest';
3-
import React from 'react';
43
import { createRoot } from 'react-dom/client';
54
import { flushSync } from 'react-dom';
65

0 commit comments

Comments
 (0)