sqlite-hub 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/.npmingnore +4 -0
  2. package/README.md +46 -0
  3. package/assets/images/logo.webp +0 -0
  4. package/assets/images/logo_extrasmall.webp +0 -0
  5. package/assets/images/logo_raw.png +0 -0
  6. package/assets/images/logo_small.webp +0 -0
  7. package/assets/mockups/connections.png +0 -0
  8. package/assets/mockups/data.png +0 -0
  9. package/assets/mockups/data_edit.png +0 -0
  10. package/assets/mockups/home.png +0 -0
  11. package/assets/mockups/overview.png +0 -0
  12. package/assets/mockups/sql_editor.png +0 -0
  13. package/assets/mockups/structure.png +0 -0
  14. package/bin/sqlite-hub.js +116 -0
  15. package/changelog.md +3 -0
  16. package/data/.gitkeep +0 -0
  17. package/index.html +100 -0
  18. package/js/api.js +193 -0
  19. package/js/app.js +520 -0
  20. package/js/components/actionBar.js +8 -0
  21. package/js/components/appShell.js +17 -0
  22. package/js/components/badges.js +5 -0
  23. package/js/components/bottomTabs.js +37 -0
  24. package/js/components/connectionCard.js +106 -0
  25. package/js/components/dataGrid.js +47 -0
  26. package/js/components/emptyState.js +159 -0
  27. package/js/components/metricCard.js +32 -0
  28. package/js/components/modal.js +317 -0
  29. package/js/components/pageHeader.js +33 -0
  30. package/js/components/queryEditor.js +121 -0
  31. package/js/components/queryResults.js +107 -0
  32. package/js/components/rowEditorPanel.js +164 -0
  33. package/js/components/sidebar.js +57 -0
  34. package/js/components/statusBar.js +39 -0
  35. package/js/components/toast.js +39 -0
  36. package/js/components/topNav.js +27 -0
  37. package/js/router.js +66 -0
  38. package/js/store.js +1092 -0
  39. package/js/utils/format.js +179 -0
  40. package/js/views/connections.js +133 -0
  41. package/js/views/data.js +400 -0
  42. package/js/views/editor.js +259 -0
  43. package/js/views/landing.js +11 -0
  44. package/js/views/overview.js +220 -0
  45. package/js/views/settings.js +109 -0
  46. package/js/views/structure.js +242 -0
  47. package/package.json +18 -0
  48. package/publish_brew.sh +444 -0
  49. package/publish_npm.sh +241 -0
  50. package/server/routes/connections.js +146 -0
  51. package/server/routes/data.js +59 -0
  52. package/server/routes/export.js +25 -0
  53. package/server/routes/overview.js +39 -0
  54. package/server/routes/settings.js +50 -0
  55. package/server/routes/sql.js +50 -0
  56. package/server/routes/structure.js +38 -0
  57. package/server/server.js +136 -0
  58. package/server/services/sqlite/connectionManager.js +306 -0
  59. package/server/services/sqlite/dataBrowserService.js +255 -0
  60. package/server/services/sqlite/exportService.js +34 -0
  61. package/server/services/sqlite/importService.js +111 -0
  62. package/server/services/sqlite/introspection.js +302 -0
  63. package/server/services/sqlite/overviewService.js +109 -0
  64. package/server/services/sqlite/sqlExecutor.js +434 -0
  65. package/server/services/sqlite/structureService.js +60 -0
  66. package/server/services/storage/appStateStore.js +530 -0
  67. package/server/utils/csv.js +34 -0
  68. package/server/utils/errors.js +175 -0
  69. package/server/utils/fileValidation.js +135 -0
  70. package/server/utils/identifier.js +38 -0
  71. package/server/utils/sqliteTypes.js +112 -0
  72. package/styles/base.css +176 -0
  73. package/styles/components.css +323 -0
  74. package/styles/layout.css +101 -0
  75. package/styles/tokens.css +49 -0
  76. package/styles/views.css +84 -0
@@ -0,0 +1,323 @@
1
+ .top-nav-shell {
2
+ align-items: center;
3
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0.05), transparent);
4
+ display: flex;
5
+ height: 100%;
6
+ justify-content: space-between;
7
+ padding: 0 var(--spacing-6);
8
+ }
9
+
10
+ .top-nav-brand {
11
+ color: var(--color-primary-container);
12
+ font-family: var(--font-family-headline);
13
+ font-size: 1.25rem;
14
+ font-weight: 900;
15
+ letter-spacing: 0.2em;
16
+ text-transform: uppercase;
17
+ }
18
+
19
+ .top-nav-links {
20
+ align-items: center;
21
+ display: none;
22
+ gap: var(--spacing-4);
23
+ height: 100%;
24
+ }
25
+
26
+ .top-nav-link {
27
+ align-items: center;
28
+ color: rgba(229, 226, 225, 0.6);
29
+ display: flex;
30
+ font-family: var(--font-family-headline);
31
+ height: 100%;
32
+ letter-spacing: -0.04em;
33
+ padding: 0 var(--spacing-2);
34
+ text-transform: uppercase;
35
+ transition: background-color var(--transition-fast), color var(--transition-fast);
36
+ }
37
+
38
+ .top-nav-link:hover {
39
+ background: var(--color-surface-highest);
40
+ }
41
+
42
+ .top-nav-link.is-active {
43
+ border-bottom: 2px solid var(--color-primary-container);
44
+ color: var(--color-primary-container);
45
+ padding-bottom: 1px;
46
+ }
47
+
48
+ .top-nav-actions {
49
+ align-items: center;
50
+ display: flex;
51
+ gap: var(--spacing-2);
52
+ }
53
+
54
+ .top-nav-icon {
55
+ align-items: center;
56
+ color: var(--color-primary-container);
57
+ display: inline-flex;
58
+ height: 2rem;
59
+ justify-content: center;
60
+ transition: background-color var(--transition-fast);
61
+ width: 2rem;
62
+ }
63
+
64
+ .top-nav-icon:hover {
65
+ background: var(--color-surface-highest);
66
+ }
67
+
68
+ .sidebar-shell {
69
+ background: var(--color-surface-low);
70
+ box-shadow: var(--shadow-sidebar);
71
+ flex-direction: column;
72
+ min-height: 0;
73
+ padding: var(--spacing-4) 0;
74
+ }
75
+
76
+ .sidebar-links {
77
+ display: flex;
78
+ flex: 1;
79
+ flex-direction: column;
80
+ gap: var(--spacing-1);
81
+ min-height: 0;
82
+ }
83
+
84
+ .sidebar-link {
85
+ align-items: center;
86
+ color: rgba(229, 226, 225, 0.4);
87
+ display: flex;
88
+ font-family: var(--font-family-headline);
89
+ font-size: 0.75rem;
90
+ font-weight: 700;
91
+ gap: var(--spacing-4);
92
+ letter-spacing: 0.15em;
93
+ padding: 0.75rem var(--spacing-6);
94
+ text-transform: uppercase;
95
+ transition: background-color var(--transition-fast), color var(--transition-fast),
96
+ border-color var(--transition-fast);
97
+ }
98
+
99
+ .sidebar-link:hover {
100
+ background: var(--color-surface-container);
101
+ color: var(--color-primary-container);
102
+ }
103
+
104
+ .sidebar-link.is-active {
105
+ background: var(--color-surface-high);
106
+ border-left: 2px solid var(--color-primary-container);
107
+ color: var(--color-primary-container);
108
+ }
109
+
110
+ .sidebar-footer {
111
+ margin-top: auto;
112
+ padding: 0 var(--spacing-6);
113
+ }
114
+
115
+ .sidebar-footer-card {
116
+ align-items: center;
117
+ background: var(--color-surface-lowest);
118
+ display: flex;
119
+ gap: var(--spacing-3);
120
+ padding: var(--spacing-2);
121
+ }
122
+
123
+ .sidebar-footer-mark {
124
+ align-items: center;
125
+ background: var(--color-primary-container);
126
+ color: var(--color-on-primary);
127
+ display: flex;
128
+ font-size: 0.75rem;
129
+ font-weight: 900;
130
+ height: 2rem;
131
+ justify-content: center;
132
+ width: 2rem;
133
+ }
134
+
135
+ .status-bar-shell {
136
+ align-items: center;
137
+ background: var(--color-surface-lowest);
138
+ border-top: 1px solid rgba(75, 71, 50, 0.15);
139
+ display: flex;
140
+ height: 100%;
141
+ justify-content: space-between;
142
+ padding: 0 var(--spacing-4);
143
+ }
144
+
145
+ .status-bar-primary,
146
+ .status-bar-secondary {
147
+ align-items: center;
148
+ display: flex;
149
+ gap: var(--spacing-4);
150
+ }
151
+
152
+ .status-bar-text {
153
+ color: var(--color-primary-container);
154
+ font-family: var(--font-family-mono);
155
+ font-size: var(--font-size-status);
156
+ letter-spacing: -0.02em;
157
+ }
158
+
159
+ .status-bar-link {
160
+ color: rgba(229, 226, 225, 0.3);
161
+ cursor: default;
162
+ font-family: var(--font-family-mono);
163
+ font-size: var(--font-size-status);
164
+ letter-spacing: -0.02em;
165
+ text-transform: uppercase;
166
+ transition: color var(--transition-fast);
167
+ }
168
+
169
+ .status-bar-link:hover {
170
+ color: var(--color-primary-container);
171
+ }
172
+
173
+ .status-bar-dot {
174
+ background: var(--color-success);
175
+ border-radius: 9999px;
176
+ box-shadow: 0 0 8px rgba(34, 197, 94, 0.6);
177
+ height: 6px;
178
+ width: 6px;
179
+ }
180
+
181
+ .shell-section {
182
+ background: var(--color-surface-container);
183
+ border: 1px solid rgba(75, 71, 50, 0.12);
184
+ }
185
+
186
+ .toolbar-button {
187
+ align-items: center;
188
+ display: inline-flex;
189
+ gap: var(--spacing-2);
190
+ justify-content: center;
191
+ text-transform: uppercase;
192
+ transition: background-color var(--transition-fast), box-shadow var(--transition-standard),
193
+ color var(--transition-fast);
194
+ }
195
+
196
+ .toolbar-button--primary:hover {
197
+ box-shadow: var(--shadow-subtle-glow);
198
+ }
199
+
200
+ .metric-card {
201
+ background: var(--color-surface-low);
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: var(--spacing-2);
205
+ padding: var(--spacing-6);
206
+ }
207
+
208
+ .metric-card--accent {
209
+ border-left: 2px solid var(--color-primary-container);
210
+ }
211
+
212
+ .status-badge {
213
+ border: 1px solid transparent;
214
+ display: inline-flex;
215
+ font-size: var(--font-size-micro);
216
+ font-weight: 700;
217
+ letter-spacing: 0.12em;
218
+ padding: 0.125rem 0.5rem;
219
+ text-transform: uppercase;
220
+ }
221
+
222
+ .status-badge--primary {
223
+ background: rgba(252, 227, 0, 0.1);
224
+ border-color: rgba(252, 227, 0, 0.2);
225
+ color: var(--color-primary-container);
226
+ }
227
+
228
+ .status-badge--muted {
229
+ background: var(--color-surface-highest);
230
+ border-color: rgba(75, 71, 50, 0.2);
231
+ color: var(--color-on-surface-variant);
232
+ }
233
+
234
+ .status-badge--alert {
235
+ background: rgba(147, 0, 10, 0.2);
236
+ border-color: rgba(255, 180, 171, 0.2);
237
+ color: var(--color-error);
238
+ }
239
+
240
+ .status-badge--success {
241
+ background: rgba(0, 220, 225, 0.1);
242
+ color: var(--color-tertiary-dim);
243
+ }
244
+
245
+ .connection-card {
246
+ background: var(--color-surface-container);
247
+ border-left: 2px solid transparent;
248
+ cursor: pointer;
249
+ display: flex;
250
+ flex-direction: column;
251
+ min-height: 100%;
252
+ text-align: left;
253
+ transition: background-color var(--transition-fast), border-color var(--transition-fast),
254
+ box-shadow var(--transition-standard);
255
+ }
256
+
257
+ .connection-card:hover {
258
+ background: var(--color-surface-high);
259
+ border-color: var(--color-outline-variant);
260
+ }
261
+
262
+ .connection-card.is-active {
263
+ border-color: var(--color-primary-container);
264
+ box-shadow: 0 0 20px rgba(252, 227, 0, 0.05);
265
+ }
266
+
267
+ .connection-card-footer {
268
+ background: var(--color-surface-highest);
269
+ height: 4px;
270
+ width: 100%;
271
+ }
272
+
273
+ .bottom-tab {
274
+ border-bottom: 1px solid transparent;
275
+ color: rgba(205, 199, 171, 0.4);
276
+ font-size: var(--font-size-status);
277
+ font-weight: 700;
278
+ height: 100%;
279
+ letter-spacing: 0.15em;
280
+ text-transform: uppercase;
281
+ }
282
+
283
+ .bottom-tab.is-active {
284
+ border-color: var(--color-primary-container);
285
+ color: var(--color-primary-container);
286
+ }
287
+
288
+ .page-eyebrow {
289
+ align-items: center;
290
+ display: flex;
291
+ gap: var(--spacing-2);
292
+ margin-bottom: var(--spacing-2);
293
+ }
294
+
295
+ .page-eyebrow-line {
296
+ background: rgba(252, 227, 0, 0.3);
297
+ height: 1px;
298
+ width: 48px;
299
+ }
300
+
301
+ .empty-state-shell {
302
+ max-width: 42rem;
303
+ width: 100%;
304
+ }
305
+
306
+ .view-card {
307
+ background: var(--color-surface-low);
308
+ border: 1px solid rgba(75, 71, 50, 0.1);
309
+ }
310
+
311
+ .view-card-header {
312
+ align-items: center;
313
+ background: var(--color-surface-highest);
314
+ display: flex;
315
+ justify-content: space-between;
316
+ padding: var(--spacing-3) var(--spacing-4);
317
+ }
318
+
319
+ @media (min-width: 768px) {
320
+ .top-nav-links {
321
+ display: flex;
322
+ }
323
+ }
@@ -0,0 +1,101 @@
1
+ #app {
2
+ height: 100%;
3
+ }
4
+
5
+ .app-shell {
6
+ display: flex;
7
+ flex-direction: column;
8
+ height: 100%;
9
+ overflow: hidden;
10
+ position: relative;
11
+ }
12
+
13
+ .app-top-nav {
14
+ flex: 0 0 var(--top-nav-height);
15
+ height: var(--top-nav-height);
16
+ }
17
+
18
+ .app-body {
19
+ display: flex;
20
+ flex: 1;
21
+ min-height: 0;
22
+ overflow: hidden;
23
+ position: relative;
24
+ }
25
+
26
+ .app-sidebar {
27
+ display: none;
28
+ flex: 0 0 var(--sidebar-width);
29
+ min-height: 0;
30
+ width: var(--sidebar-width);
31
+ }
32
+
33
+ .app-main {
34
+ display: flex;
35
+ flex: 1;
36
+ flex-direction: column;
37
+ min-height: 0;
38
+ min-width: 0;
39
+ overflow: hidden;
40
+ }
41
+
42
+ .app-main-scroll {
43
+ flex: 1;
44
+ min-height: 0;
45
+ min-width: 0;
46
+ overflow: auto;
47
+ }
48
+
49
+ .app-main-scroll--locked {
50
+ overflow: hidden;
51
+ }
52
+
53
+ .app-view {
54
+ height: 100%;
55
+ min-height: 0;
56
+ }
57
+
58
+ .app-right-panel {
59
+ background: var(--color-surface-low);
60
+ border-left: 1px solid rgba(75, 71, 50, 0.2);
61
+ box-shadow: var(--shadow-panel);
62
+ display: flex;
63
+ flex-direction: column;
64
+ min-height: 0;
65
+ opacity: 0;
66
+ overflow: hidden;
67
+ pointer-events: none;
68
+ position: absolute;
69
+ bottom: 0;
70
+ right: 0;
71
+ top: 0;
72
+ transform: translateX(100%);
73
+ transition: transform var(--transition-standard), opacity var(--transition-fast);
74
+ width: min(var(--panel-width), 100%);
75
+ z-index: 30;
76
+ }
77
+
78
+ .app-shell.panel-open .app-right-panel {
79
+ opacity: 1;
80
+ pointer-events: auto;
81
+ transform: translateX(0);
82
+ }
83
+
84
+ .app-status-bar {
85
+ flex: 0 0 var(--status-bar-height);
86
+ height: var(--status-bar-height);
87
+ }
88
+
89
+ @media (min-width: 768px) {
90
+ .app-sidebar {
91
+ display: flex;
92
+ }
93
+ }
94
+
95
+ @media (max-width: 767px) {
96
+ .app-right-panel {
97
+ bottom: 0;
98
+ left: 0;
99
+ width: 100%;
100
+ }
101
+ }
@@ -0,0 +1,49 @@
1
+ :root {
2
+ --color-background: #131313;
3
+ --color-surface: #131313;
4
+ --color-surface-lowest: #0e0e0e;
5
+ --color-surface-low: #1c1b1b;
6
+ --color-surface-container: #201f1f;
7
+ --color-surface-high: #2a2a2a;
8
+ --color-surface-highest: #353534;
9
+ --color-surface-bright: #3a3939;
10
+ --color-primary-container: #fce300;
11
+ --color-primary-fixed: #fde403;
12
+ --color-on-primary: #373100;
13
+ --color-on-surface: #e5e2e1;
14
+ --color-on-surface-variant: #cdc7ab;
15
+ --color-outline-variant: #4b4732;
16
+ --color-error: #ffb4ab;
17
+ --color-error-container: #93000a;
18
+ --color-tertiary-dim: #00dce1;
19
+ --color-grid-dot: rgba(252, 227, 0, 0.03);
20
+ --color-success: #22c55e;
21
+ --font-family-headline: "Space Grotesk", sans-serif;
22
+ --font-family-body: "Inter", sans-serif;
23
+ --font-family-mono: "Roboto Mono", monospace;
24
+ --font-size-status: 10px;
25
+ --font-size-micro: 9px;
26
+ --font-size-label: 11px;
27
+ --font-size-icon: 18px;
28
+ --spacing-1: 4px;
29
+ --spacing-2: 8px;
30
+ --spacing-3: 12px;
31
+ --spacing-4: 16px;
32
+ --spacing-5: 20px;
33
+ --spacing-6: 24px;
34
+ --spacing-8: 32px;
35
+ --spacing-10: 40px;
36
+ --radius-none: 0;
37
+ --top-nav-height: 56px;
38
+ --status-bar-height: 24px;
39
+ --sidebar-width: 256px;
40
+ --panel-width: 480px;
41
+ --shadow-sidebar: 4px 0 0 0 #131313;
42
+ --shadow-panel: -20px 0 60px rgba(0, 0, 0, 0.8);
43
+ --shadow-subtle-glow: 0 0 15px rgba(252, 227, 0, 0.3);
44
+ --shadow-strong-glow: 0 0 20px rgba(252, 227, 0, 0.3);
45
+ --transition-fast: 150ms ease;
46
+ --transition-standard: 300ms ease;
47
+ --duration-cursor-blink: 1s;
48
+ --scrollbar-size: 4px;
49
+ }
@@ -0,0 +1,84 @@
1
+ .machined-grid {
2
+ background-image: radial-gradient(var(--color-grid-dot) 1px, transparent 1px);
3
+ background-size: 32px 32px;
4
+ }
5
+
6
+ .data-grid-texture {
7
+ background-image: radial-gradient(var(--color-primary-container) 1px, transparent 1px);
8
+ background-size: 24px 24px;
9
+ opacity: 0.03;
10
+ }
11
+
12
+ .view-surface {
13
+ background: var(--color-surface);
14
+ min-height: 100%;
15
+ }
16
+
17
+ .view-frame {
18
+ min-height: 100%;
19
+ padding: var(--spacing-8);
20
+ }
21
+
22
+ .view-stack {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: var(--spacing-8);
26
+ }
27
+
28
+ .landing-view {
29
+ align-items: center;
30
+ display: flex;
31
+ justify-content: center;
32
+ min-height: 100%;
33
+ overflow: hidden;
34
+ position: relative;
35
+ }
36
+
37
+ .landing-accent {
38
+ background: rgba(75, 71, 50, 0.2);
39
+ height: 1px;
40
+ position: absolute;
41
+ }
42
+
43
+ .landing-accent--a {
44
+ left: 3rem;
45
+ top: 2.5rem;
46
+ transform: rotate(45deg);
47
+ width: 8rem;
48
+ }
49
+
50
+ .landing-accent--b {
51
+ bottom: 2.5rem;
52
+ right: 3rem;
53
+ transform: rotate(-12deg);
54
+ width: 16rem;
55
+ }
56
+
57
+ .landing-accent--c {
58
+ border-bottom: 1px solid rgba(75, 71, 50, 0.12);
59
+ border-right: 1px solid rgba(75, 71, 50, 0.12);
60
+ height: 4rem;
61
+ left: 0;
62
+ top: 50%;
63
+ width: 4rem;
64
+ }
65
+
66
+ .system-placeholder-grid {
67
+ display: grid;
68
+ gap: var(--spacing-4);
69
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
70
+ }
71
+
72
+ .system-placeholder-card {
73
+ background: var(--color-surface-low);
74
+ border-bottom: 2px solid rgba(49, 48, 48, 1);
75
+ display: flex;
76
+ flex-direction: column;
77
+ gap: var(--spacing-2);
78
+ min-height: 160px;
79
+ padding: var(--spacing-6);
80
+ }
81
+
82
+ .system-placeholder-card.is-primary {
83
+ border-bottom-color: var(--color-primary-container);
84
+ }