99
1010import { useState , useEffect } from 'react' ;
1111import { ObjectStackClient } from '@objectstack/client' ;
12+ import { Database } from 'lucide-react' ;
1213import { MetadataExplorer } from './components/MetadataExplorer' ;
1314import { ObjectDataTable } from './components/ObjectDataTable' ;
1415import { ObjectDataForm } from './components/ObjectDataForm' ;
@@ -23,6 +24,7 @@ export function App() {
2324 const [ selectedObject , setSelectedObject ] = useState < string | null > ( 'todo_task' ) ;
2425 const [ view , setView ] = useState < 'list' | 'form' > ( 'list' ) ;
2526 const [ editingRecord , setEditingRecord ] = useState < any > ( null ) ; // null = create new
27+ const [ refreshKey , setRefreshKey ] = useState ( 0 ) ;
2628
2729 useEffect ( ( ) => {
2830 initializeClient ( ) ;
@@ -60,108 +62,94 @@ export function App() {
6062 const handleFormSuccess = ( ) => {
6163 setView ( 'list' ) ;
6264 setEditingRecord ( null ) ;
63- // Table will reload when switching back to list implicitly if we force refresh?
64- // Actually ObjectDataTable mounts again or we can trigger refresh.
65- // For simplicity, remounting works or we can add a refresh trigger key.
65+ setRefreshKey ( k => k + 1 ) ;
6666 } ;
6767
6868 if ( ! connected || ! client ) {
6969 return (
70- < div className = "min-h-screen flex items-center justify-center bg-gray-100 " >
71- < div className = "text-center" >
72- < h2 className = "text-xl font-bold text-gray-700 " > Connecting to Platform...</ h2 >
73- { error && < p className = "text-red-500 mt-2 " > { error } </ p > }
70+ < div className = "min-h-screen flex items-center justify-center bg-background " >
71+ < div className = "text-center space-y-4 " >
72+ < h2 className = "text-xl font-bold text-foreground " > Connecting to Platform...</ h2 >
73+ { error && < p className = "text-destructive font-medium " > { error } </ p > }
7474 </ div >
7575 </ div >
7676 ) ;
7777 }
7878
7979 return (
80- < div className = "min-h-screen bg-gray-100 font-sans flex flex-col" >
80+ < div className = "min-h-screen bg-background font-sans flex flex-col text-foreground " >
8181 { /* Top Header */ }
82- < header className = "bg-foreground text- background shadow-md z-10 " >
83- < div className = "mx-auto px-6 h-16 flex items-center justify-between " >
84- < div className = "flex items-center space-x-3 " >
85- < div className = "font-extrabold text-2xl tracking-tighter " >
86- Object< span className = "text-gray-400 " > Stack</ span >
82+ < header className = "sticky top-0 z-50 w-full border-b bg- background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 " >
83+ < div className = "container flex h-14 items-center px-4 md:px-6 " >
84+ < div className = "mr-4 hidden md: flex items-center space-x-2 " >
85+ < div className = "font-bold text-xl tracking-tight " >
86+ Object< span className = "text-muted-foreground " > Stack</ span >
8787 </ div >
88- < span className = "px-2 py-0.5 rounded text-xs bg-gray-700 text-gray-300 border border-gray-600 " >
88+ < div className = "hidden sm:inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80 " >
8989 Console
90- </ span >
90+ </ div >
9191 </ div >
92- < div className = "text-sm opacity-80 flex items-center gap-2" >
93- < div className = "w-2 h-2 rounded-full bg-green-400" > </ div >
94- v1.0.0 (Memory Kernel)
92+ < div className = "flex flex-1 items-center justify-between space-x-2 md:justify-end" >
93+ < div className = "text-sm text-muted-foreground flex items-center gap-2" >
94+ < span className = "relative flex h-2 w-2" >
95+ < span className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" > </ span >
96+ < span className = "relative inline-flex rounded-full h-2 w-2 bg-green-500" > </ span >
97+ </ span >
98+ v1.0.0 (Memory Kernel)
99+ </ div >
95100 </ div >
96101 </ div >
97102 </ header >
98103
99104 { /* Main Layout */ }
100105 < div className = "flex flex-1 overflow-hidden" >
101- { /* Sidebar: Metadata Explorer */ }
102- < aside className = "w-64 bg-white border-r border-gray-200 overflow-y-auto hidden md:block" >
103- < div className = "p-4" >
104- < MetadataExplorer
105- client = { client }
106- selectedObject = { selectedObject }
107- onSelectObject = { ( obj ) => {
108- setSelectedObject ( obj ) ;
109- setView ( 'list' ) ; // Reset to list when changing objects
110- } }
111- />
112- </ div >
113- </ aside >
114-
115- { /* Main Content Area */ }
116- < main className = "flex-1 overflow-y-auto p-6 relative" >
117- { selectedObject ? (
118- < div className = "space-y-6 max-w-7xl mx-auto" >
119- { /* Toolbar */ }
120- < div className = "flex justify-between items-end pb-4 border-b border-gray-200" >
121- < div >
122- < h1 className = "text-2xl font-bold text-gray-900" >
123- { selectedObject }
124- </ h1 >
125- < p className = "text-sm text-gray-500 mt-1" >
126- Manage records and view schema definition.
127- </ p >
128- </ div >
129- < button
130- onClick = { handleCreate }
131- className = "px-4 py-2 bg-foreground text-white rounded hover:bg-black transition-colors shadow-sm font-medium flex items-center gap-2"
132- >
133- < span > +</ span > New Record
134- </ button >
135- </ div >
106+ { /* Sidebar */ }
107+ < aside className = "hidden w-64 flex-col border-r bg-muted/10 md:flex" >
108+ < div className = "p-4 font-medium text-sm text-muted-foreground uppercase tracking-wider" >
109+ Explorer
110+ </ div >
111+ < div className = "flex-1 overflow-hidden px-2 pb-4" >
112+ < MetadataExplorer
113+ client = { client }
114+ selectedObject = { selectedObject }
115+ onSelectObject = { ( obj ) => {
116+ setSelectedObject ( obj ) ;
117+ setView ( 'list' ) ;
118+ setEditingRecord ( null ) ;
119+ } }
120+ />
121+ </ div >
122+ </ aside >
136123
137- { /* Data Table */ }
138- < ObjectDataTable
139- key = { selectedObject + view } // Force refresh when switching back
140- client = { client }
141- objectApiName = { selectedObject }
142- onEdit = { handleEdit }
143- />
144-
145- </ div >
146- ) : (
147- < div className = "flex flex-col items-center justify-center h-full text-gray-400" >
148- < div className = "text-6xl mb-4" > Select an Object</ div >
149- < p > Choose an object from the sidebar to manage data.</ p >
150- </ div >
151- ) }
152- </ main >
124+ { /* Content Area */ }
125+ < main className = "flex-1 overflow-hidden p-4 md:p-6 flex flex-col bg-muted/5 relative" >
126+ { selectedObject ? (
127+ < >
128+ < ObjectDataTable
129+ key = { `${ selectedObject } -${ refreshKey } ` }
130+ client = { client }
131+ objectApiName = { selectedObject }
132+ onEdit = { handleEdit }
133+ />
134+ { view === 'form' && (
135+ < ObjectDataForm
136+ client = { client }
137+ objectApiName = { selectedObject }
138+ record = { editingRecord }
139+ onSuccess = { handleFormSuccess }
140+ onCancel = { ( ) => setView ( 'list' ) }
141+ />
142+ ) }
143+ </ >
144+ ) : (
145+ < div className = "flex flex-col items-center justify-center h-full text-muted-foreground" >
146+ < Database className = "h-12 w-12 mb-4 opacity-20" />
147+ < div className = "text-xl font-medium" > Select an Object</ div >
148+ < p className = "opacity-60" > Choose an object from the sidebar to manage data.</ p >
149+ </ div >
150+ ) }
151+ </ main >
153152 </ div >
154-
155- { /* Modal Form */ }
156- { view === 'form' && selectedObject && (
157- < ObjectDataForm
158- client = { client }
159- objectApiName = { selectedObject }
160- record = { editingRecord }
161- onSuccess = { handleFormSuccess }
162- onCancel = { ( ) => setView ( 'list' ) }
163- />
164- ) }
165153 </ div >
166154 ) ;
167155}
0 commit comments