11import { DatabaseStudio } from "./components/DatabaseStudio.tsx" ;
2+ import { DatabaseSelector , type DiscoveredDatabase } from "./components/DatabaseSelector.tsx" ;
23import { TableDetail , type TableRow } from "./components/TableDetail.tsx" ;
34
45export type AppProps = {
@@ -25,7 +26,8 @@ export function App({ title, children }: AppProps) {
2526 background: var(--bg-main); min-height: 100vh; color: var(--text-primary);
2627 line-height: 1.6; overflow: hidden;
2728 }
28- .app-layout { display: flex; height: 100vh; }
29+ .app-container { display: flex; flex-direction: column; height: 100vh; }
30+ .app-layout { display: flex; flex: 1; overflow: hidden; }
2931 .sidebar {
3032 width: 280px; background: var(--bg-sidebar); border-right: 1px solid var(--border-color);
3133 display: flex; flex-direction: column; overflow: hidden;
@@ -38,7 +40,34 @@ export function App({ title, children }: AppProps) {
3840 width: 20px; height: 20px; flex-shrink: 0;
3941 }
4042 .sidebar-title { font-size: 1.1rem; font-weight: 700; color: var(--text-primary); }
41- .sidebar-section { padding: 1rem 0.5rem; flex: 1; overflow-y: auto; }
43+ .top-toolbar {
44+ background: var(--bg-sidebar); border-bottom: 1px solid var(--border-color);
45+ padding: 1rem 1.5rem; display: flex; align-items: center; justify-content: space-between;
46+ height: 60px; flex-shrink: 0;
47+ }
48+ .top-toolbar-left {
49+ display: flex; align-items: center; gap: 0.75rem;
50+ }
51+ .top-toolbar-left svg {
52+ width: 20px; height: 20px; flex-shrink: 0;
53+ }
54+ .top-toolbar-title { font-size: 1.1rem; font-weight: 700; color: var(--text-primary); }
55+ .top-toolbar-right { display: flex; align-items: center; }
56+ .back-button {
57+ display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem;
58+ background: var(--bg-hover); border: 1px solid var(--border-color);
59+ border-radius: 6px; color: var(--text-primary); text-decoration: none;
60+ font-size: 0.9rem; transition: all 0.15s ease;
61+ cursor: pointer;
62+ }
63+ .back-button:hover {
64+ background: var(--accent); border-color: var(--text-muted);
65+ }
66+ .back-icon {
67+ width: 18px; height: 18px; color: var(--text-muted); flex-shrink: 0;
68+ }
69+ .back-button:hover .back-icon { color: var(--text-primary); }
70+ .sidebar-section { padding: 1.5rem 0.5rem 1rem; flex: 1; overflow-y: auto; }
4271 .section-label {
4372 padding: 0.5rem 0.75rem; font-size: 0.75rem; font-weight: 600;
4473 color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;
@@ -49,6 +78,7 @@ export function App({ title, children }: AppProps) {
4978 display: flex; align-items: center; gap: 0.75rem; padding: 0.65rem 0.75rem;
5079 color: var(--text-primary); text-decoration: none; border-radius: 6px;
5180 transition: all 0.15s ease; font-size: 0.9rem;
81+ cursor: pointer;
5282 }
5383 .table-link:hover { background: var(--bg-hover); color: white; }
5484 .table-link.active { background: var(--accent); color: white; }
@@ -114,6 +144,82 @@ export function App({ title, children }: AppProps) {
114144 .data-table td.null { color: var(--text-muted); font-style: italic; }
115145 .empty-state { text-align: center; padding: 4rem 2rem; color: var(--text-muted); }
116146 .empty-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.5; }
147+
148+ /* Database Selector Styles */
149+ .selector-container {
150+ min-height: 100vh; display: flex; align-items: center; justify-content: center;
151+ background: var(--bg-main); padding: 2rem;
152+ }
153+ .selector-content { max-width: 1200px; width: 100%; }
154+ .selector-header { text-align: center; margin-bottom: 3rem; }
155+ .selector-logo {
156+ display: flex; justify-content: center; margin-bottom: 1.5rem;
157+ }
158+ .selector-logo svg {
159+ width: 64px; height: 64px;
160+ }
161+ .selector-header h1 {
162+ font-size: 2.5rem; font-weight: 700; color: var(--text-primary);
163+ margin-bottom: 0.75rem;
164+ }
165+ .selector-subtitle {
166+ font-size: 1.1rem; color: var(--text-primary);
167+ margin-bottom: 0.5rem;
168+ }
169+ .selector-count {
170+ font-size: 0.9rem; color: var(--text-muted);
171+ }
172+ .database-grid {
173+ display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
174+ gap: 1rem; margin-top: 2rem;
175+ }
176+ .database-card {
177+ background: var(--bg-sidebar); border: 1px solid var(--border-color);
178+ border-radius: 12px; padding: 1.5rem; display: flex; align-items: center;
179+ gap: 1rem; cursor: pointer; transition: all 0.2s ease;
180+ text-align: left; width: 100%; text-decoration: none;
181+ cursor: pointer;
182+ }
183+ .database-card:hover {
184+ background: var(--bg-hover); border-color: var(--text-muted);
185+ transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
186+ }
187+ .database-icon {
188+ width: 48px; height: 48px; flex-shrink: 0;
189+ background: var(--accent); border-radius: 8px;
190+ display: flex; align-items: center; justify-content: center;
191+ }
192+ .database-icon svg { width: 28px; height: 28px; color: var(--text-primary); }
193+ .database-info { flex: 1; min-width: 0; }
194+ .database-name {
195+ font-size: 1.1rem; font-weight: 600; color: var(--text-primary);
196+ margin-bottom: 0.25rem; font-family: Monaco, monospace;
197+ display: flex; align-items: center; gap: 0.5rem;
198+ }
199+ .local-badge {
200+ font-size: 0.7rem; font-weight: 600; color: #10b981;
201+ background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.3);
202+ padding: 0.15rem 0.5rem; border-radius: 4px;
203+ text-transform: uppercase; letter-spacing: 0.05em;
204+ }
205+ .database-path {
206+ font-size: 0.85rem; color: var(--text-muted);
207+ font-family: Monaco, monospace; white-space: nowrap;
208+ overflow: hidden; text-overflow: ellipsis;
209+ }
210+ .database-meta {
211+ display: flex; align-items: center; gap: 0.5rem;
212+ margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-muted);
213+ }
214+ .meta-divider { opacity: 0.5; }
215+ .database-arrow {
216+ width: 24px; height: 24px; flex-shrink: 0;
217+ color: var(--text-muted); transition: transform 0.2s ease;
218+ }
219+ .database-card:hover .database-arrow {
220+ transform: translateX(4px); color: var(--text-primary);
221+ }
222+ .database-arrow svg { width: 100%; height: 100%; }
117223 ` } </ style >
118224 </ head >
119225 < body >
@@ -126,12 +232,25 @@ export function App({ title, children }: AppProps) {
126232export type HomeViewProps = {
127233 dbPath : string ;
128234 tables : string [ ] ;
235+ dbIndex ?: number ;
129236}
130237
131- export function HomeView ( { dbPath, tables } : HomeViewProps ) {
238+ export function HomeView ( { dbPath, tables, dbIndex } : HomeViewProps ) {
132239 return (
133240 < App title = "Database Studio · Elide" >
134- < DatabaseStudio dbPath = { dbPath } tables = { tables } />
241+ < DatabaseStudio dbPath = { dbPath } tables = { tables } dbIndex = { dbIndex } />
242+ </ App >
243+ ) ;
244+ }
245+
246+ export type SelectionViewProps = {
247+ databases : DiscoveredDatabase [ ] ;
248+ }
249+
250+ export function SelectionView ( { databases } : SelectionViewProps ) {
251+ return (
252+ < App title = "Select Database · Database Studio · Elide" >
253+ < DatabaseSelector databases = { databases } />
135254 </ App >
136255 ) ;
137256}
@@ -143,9 +262,10 @@ export type TableViewProps = {
143262 rows : TableRow [ ] ;
144263 totalRows : number ;
145264 allTables : string [ ] ;
265+ dbIndex ?: number ;
146266}
147267
148- export function TableView ( { dbPath, tableName, columns, rows, totalRows, allTables } : TableViewProps ) {
268+ export function TableView ( { dbPath, tableName, columns, rows, totalRows, allTables, dbIndex } : TableViewProps ) {
149269 return (
150270 < App title = { `${ tableName } · Database Studio · Elide` } >
151271 < TableDetail
@@ -155,6 +275,7 @@ export function TableView({ dbPath, tableName, columns, rows, totalRows, allTabl
155275 rows = { rows }
156276 totalRows = { totalRows }
157277 allTables = { allTables }
278+ dbIndex = { dbIndex }
158279 />
159280 </ App >
160281 ) ;
0 commit comments