gh-here 3.0.3 → 3.2.0

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 (47) hide show
  1. package/.env +0 -0
  2. package/lib/constants.js +21 -16
  3. package/lib/content-search.js +212 -0
  4. package/lib/error-handler.js +39 -28
  5. package/lib/file-utils.js +438 -287
  6. package/lib/git.js +11 -55
  7. package/lib/gitignore.js +70 -41
  8. package/lib/renderers.js +17 -33
  9. package/lib/server.js +73 -196
  10. package/lib/symbol-parser.js +600 -0
  11. package/package.json +1 -1
  12. package/public/app.js +135 -68
  13. package/public/css/components/buttons.css +423 -0
  14. package/public/css/components/forms.css +171 -0
  15. package/public/css/components/modals.css +286 -0
  16. package/public/css/components/notifications.css +36 -0
  17. package/public/css/file-table.css +318 -0
  18. package/public/css/file-tree.css +269 -0
  19. package/public/css/file-viewer.css +1259 -0
  20. package/public/css/layout.css +372 -0
  21. package/public/css/main.css +35 -0
  22. package/public/css/reset.css +64 -0
  23. package/public/css/search.css +694 -0
  24. package/public/css/symbol-outline.css +279 -0
  25. package/public/css/variables.css +135 -0
  26. package/public/js/constants.js +50 -34
  27. package/public/js/content-search-handler.js +551 -0
  28. package/public/js/file-viewer.js +437 -0
  29. package/public/js/focus-mode.js +280 -0
  30. package/public/js/inline-search.js +659 -0
  31. package/public/js/modal-manager.js +14 -28
  32. package/public/js/symbol-outline.js +454 -0
  33. package/public/js/utils.js +152 -94
  34. package/.claude/settings.local.json +0 -30
  35. package/SAMPLE.md +0 -287
  36. package/lib/validation.js +0 -77
  37. package/public/app.js.backup +0 -1902
  38. package/public/highlight.css +0 -121
  39. package/public/js/draft-manager.js +0 -36
  40. package/public/js/editor-manager.js +0 -159
  41. package/public/styles.css +0 -2727
  42. package/test.js +0 -138
  43. package/tests/draftManager.test.js +0 -241
  44. package/tests/fileTypeDetection.test.js +0 -111
  45. package/tests/httpService.test.js +0 -268
  46. package/tests/languageDetection.test.js +0 -145
  47. package/tests/pathUtils.test.js +0 -136
@@ -0,0 +1,318 @@
1
+ /**
2
+ * File Table Styles
3
+ * Directory listing table, file rows, and language stats
4
+ */
5
+
6
+ /* ========================================
7
+ File Table Container
8
+ ======================================== */
9
+
10
+ .file-table-container {
11
+ margin-bottom: 24px;
12
+ margin-top: 0;
13
+ }
14
+
15
+ /* ========================================
16
+ File Table
17
+ ======================================== */
18
+
19
+ .file-table {
20
+ backdrop-filter: blur(10px);
21
+ background: var(--bg-card);
22
+ border: 1px solid var(--border-subtle);
23
+ border-collapse: separate;
24
+ border-radius: var(--radius-xl);
25
+ border-spacing: 0;
26
+ box-shadow: var(--shadow-md);
27
+ margin-top: 0;
28
+ overflow: hidden;
29
+ transition: all var(--transition-base);
30
+ width: 100%;
31
+ }
32
+
33
+ .file-table:hover {
34
+ border-color: var(--border-primary);
35
+ box-shadow: var(--shadow-xl);
36
+ transform: translateY(-2px);
37
+ }
38
+
39
+ /* ========================================
40
+ Table Header
41
+ ======================================== */
42
+
43
+ .file-table thead {
44
+ backdrop-filter: blur(10px);
45
+ background: linear-gradient(180deg, rgba(19, 23, 29, 0.6) 0%, rgba(19, 23, 29, 0.4) 100%);
46
+ position: sticky;
47
+ top: 0;
48
+ z-index: 10;
49
+ }
50
+
51
+ [data-theme="light"] .file-table thead {
52
+ background: linear-gradient(180deg, rgba(248, 250, 252, 0.8) 0%, rgba(248, 250, 252, 0.6) 100%);
53
+ }
54
+
55
+ .file-table th {
56
+ border-bottom: 1px solid var(--border-subtle);
57
+ color: var(--text-secondary);
58
+ font-size: 12px;
59
+ font-weight: 600;
60
+ padding: 12px 16px;
61
+ text-align: left;
62
+ }
63
+
64
+ /* ========================================
65
+ Table Columns
66
+ ======================================== */
67
+
68
+ .file-table .col-icon {
69
+ padding-left: 16px;
70
+ padding-right: 0;
71
+ text-align: center;
72
+ width: 52px;
73
+ }
74
+
75
+ .file-table .col-name {
76
+ min-width: 200px;
77
+ padding-right: 80px;
78
+ text-align: left;
79
+ }
80
+
81
+ .file-table .col-name a {
82
+ color: var(--link-color);
83
+ display: block;
84
+ font-weight: 500;
85
+ overflow: hidden;
86
+ padding-right: 8px;
87
+ text-decoration: none;
88
+ text-overflow: ellipsis;
89
+ white-space: nowrap;
90
+ }
91
+
92
+ .file-table .col-name a:hover {
93
+ text-decoration: underline;
94
+ }
95
+
96
+ .file-table .col-size {
97
+ text-align: right;
98
+ width: 100px;
99
+ }
100
+
101
+ .file-table .col-modified {
102
+ padding-right: 16px;
103
+ text-align: right;
104
+ width: 120px;
105
+ }
106
+
107
+ /* ========================================
108
+ Table Body Rows
109
+ ======================================== */
110
+
111
+ .file-table tbody tr {
112
+ border-bottom: 1px solid var(--border-subtle);
113
+ position: relative;
114
+ transition: all var(--transition-base);
115
+ }
116
+
117
+ .file-table tbody tr::before {
118
+ background: var(--link-color);
119
+ border-radius: 0 2px 2px 0;
120
+ bottom: 0;
121
+ content: '';
122
+ left: 0;
123
+ opacity: 0;
124
+ position: absolute;
125
+ top: 0;
126
+ transition: opacity var(--transition-base);
127
+ width: 3px;
128
+ }
129
+
130
+ .file-table tbody tr:hover {
131
+ background: linear-gradient(90deg, var(--hover-bg) 0%, rgba(30, 36, 43, 0.5) 50%, transparent 100%);
132
+ box-shadow: -4px 0 12px rgba(96, 165, 250, 0.1);
133
+ transform: translateX(4px);
134
+ }
135
+
136
+ .file-table tbody tr:hover::before {
137
+ opacity: 1;
138
+ }
139
+
140
+ [data-theme="light"] .file-table tbody tr:hover {
141
+ background: linear-gradient(90deg, var(--hover-bg) 0%, rgba(241, 245, 249, 0.8) 50%, transparent 100%);
142
+ box-shadow: -4px 0 12px rgba(37, 99, 235, 0.08);
143
+ }
144
+
145
+ .file-table tbody tr:last-child {
146
+ border-bottom: none;
147
+ }
148
+
149
+ .file-table tbody tr:first-child td {
150
+ padding-top: 16px;
151
+ }
152
+
153
+ .file-table tbody tr:last-child td {
154
+ padding-bottom: 16px;
155
+ }
156
+
157
+ /* ========================================
158
+ Table Cells
159
+ ======================================== */
160
+
161
+ .file-table td {
162
+ font-size: 14px;
163
+ padding: 10px 16px;
164
+ transition: all var(--transition-base);
165
+ vertical-align: middle;
166
+ }
167
+
168
+ .file-table td.col-icon {
169
+ align-items: center;
170
+ display: flex;
171
+ gap: 8px;
172
+ }
173
+
174
+ .file-table td.col-icon svg {
175
+ flex-shrink: 0;
176
+ height: 16px;
177
+ width: 16px;
178
+ }
179
+
180
+ .file-table td.col-size,
181
+ .file-table td.col-modified {
182
+ color: var(--text-muted);
183
+ white-space: nowrap;
184
+ }
185
+
186
+ /* ========================================
187
+ File Row States
188
+ ======================================== */
189
+
190
+ .file-row {
191
+ cursor: pointer;
192
+ transition: all 0.15s ease;
193
+ }
194
+
195
+ .file-row:hover {
196
+ background-color: var(--hover-bg);
197
+ transform: translateX(2px);
198
+ }
199
+
200
+ .file-row.focused {
201
+ background-color: var(--link-color);
202
+ color: white;
203
+ }
204
+
205
+ .file-row.focused a {
206
+ color: white;
207
+ }
208
+
209
+ .file-row.focused .text-yellow,
210
+ .file-row.focused .text-blue,
211
+ .file-row.focused .text-green,
212
+ .file-row.focused .text-red,
213
+ .file-row.focused .text-orange,
214
+ .file-row.focused .text-purple,
215
+ .file-row.focused .text-gray {
216
+ color: rgba(255, 255, 255, 0.9);
217
+ }
218
+
219
+ .file-row.hidden {
220
+ display: none;
221
+ }
222
+
223
+ /* ========================================
224
+ Name Column
225
+ ======================================== */
226
+
227
+ .name {
228
+ align-items: center;
229
+ display: flex;
230
+ flex-wrap: nowrap;
231
+ gap: 4px;
232
+ position: relative;
233
+ }
234
+
235
+ /* ========================================
236
+ Language Stats
237
+ ======================================== */
238
+
239
+ .language-stats {
240
+ align-items: center;
241
+ backdrop-filter: blur(10px);
242
+ background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-elevated) 100%);
243
+ border: 1px solid var(--border-subtle);
244
+ border-radius: var(--radius-lg);
245
+ box-shadow: var(--shadow-sm);
246
+ display: flex;
247
+ flex-shrink: 1;
248
+ gap: var(--space-md);
249
+ margin-left: var(--space-lg);
250
+ max-width: 400px;
251
+ min-width: 0;
252
+ overflow: visible;
253
+ padding: var(--space-sm) var(--space-md);
254
+ position: relative;
255
+ transition: all var(--transition-base);
256
+ white-space: nowrap;
257
+ }
258
+
259
+ .language-stats:hover {
260
+ border-color: var(--border-primary);
261
+ box-shadow: var(--shadow-md);
262
+ }
263
+
264
+ .lang-stat {
265
+ align-items: center;
266
+ border-radius: var(--radius-sm);
267
+ color: var(--text-secondary);
268
+ display: inline-flex;
269
+ flex-shrink: 0;
270
+ font-size: 12px;
271
+ gap: 6px;
272
+ padding: 4px 8px;
273
+ position: relative;
274
+ transition: all var(--transition-base);
275
+ white-space: nowrap;
276
+ }
277
+
278
+ .lang-stat:hover {
279
+ background: var(--hover-bg);
280
+ color: var(--text-primary);
281
+ }
282
+
283
+ .lang-dot {
284
+ border-radius: 50%;
285
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1), 0 2px 4px rgba(0, 0, 0, 0.2);
286
+ display: inline-block;
287
+ flex-shrink: 0;
288
+ height: 10px;
289
+ transition: all var(--transition-base);
290
+ width: 10px;
291
+ }
292
+
293
+ .lang-stat:hover .lang-dot {
294
+ box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.15), 0 4px 8px rgba(0, 0, 0, 0.3);
295
+ }
296
+
297
+ .lang-name {
298
+ color: var(--text-primary);
299
+ font-weight: 600;
300
+ letter-spacing: -0.01em;
301
+ }
302
+
303
+ .lang-percent {
304
+ color: var(--text-secondary);
305
+ font-variant-numeric: tabular-nums;
306
+ font-weight: 500;
307
+ }
308
+
309
+ /* ========================================
310
+ Responsive - Mobile
311
+ ======================================== */
312
+
313
+ @media (max-width: 768px) {
314
+ .file-table .col-size,
315
+ .file-table .col-modified {
316
+ display: none;
317
+ }
318
+ }
@@ -0,0 +1,269 @@
1
+ /**
2
+ * File Tree Sidebar Styles
3
+ * Navigation sidebar, tree items, and sidebar controls
4
+ */
5
+
6
+ /* ========================================
7
+ File Tree Sidebar Container
8
+ ======================================== */
9
+
10
+ .file-tree-sidebar {
11
+ align-self: stretch;
12
+ background: linear-gradient(180deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
13
+ border-right: 1px solid var(--border-subtle);
14
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
15
+ display: flex;
16
+ flex-direction: column;
17
+ flex-shrink: 0;
18
+ height: 100vh;
19
+ max-height: 100vh;
20
+ max-width: 300px;
21
+ min-width: 300px;
22
+ overflow-x: hidden;
23
+ overflow-y: auto;
24
+ position: sticky;
25
+ scrollbar-color: var(--border-primary) transparent;
26
+ scrollbar-width: thin;
27
+ top: 0;
28
+ transition: all var(--transition-base);
29
+ width: 300px;
30
+ }
31
+
32
+ [data-theme="light"] .file-tree-sidebar {
33
+ background: linear-gradient(180deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
34
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05);
35
+ }
36
+
37
+ .file-tree-sidebar::-webkit-scrollbar {
38
+ width: 6px;
39
+ }
40
+
41
+ .file-tree-sidebar::-webkit-scrollbar-track {
42
+ background: transparent;
43
+ }
44
+
45
+ .file-tree-sidebar::-webkit-scrollbar-thumb {
46
+ background: var(--border-primary);
47
+ border-radius: 3px;
48
+ }
49
+
50
+ .file-tree-sidebar::-webkit-scrollbar-thumb:hover {
51
+ background: var(--text-secondary);
52
+ }
53
+
54
+ .file-tree-sidebar.hidden {
55
+ display: none;
56
+ }
57
+
58
+ /* ========================================
59
+ File Tree Header
60
+ ======================================== */
61
+
62
+ .file-tree-header {
63
+ align-items: center;
64
+ backdrop-filter: blur(10px);
65
+ background: linear-gradient(180deg, rgba(19, 23, 29, 0.95) 0%, rgba(19, 23, 29, 0.85) 100%);
66
+ border-bottom: 1px solid var(--border-subtle);
67
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
68
+ color: var(--text-primary);
69
+ display: flex;
70
+ font-size: 15px;
71
+ font-weight: 700;
72
+ gap: 12px;
73
+ letter-spacing: -0.01em;
74
+ padding: 18px 24px;
75
+ position: sticky;
76
+ top: 0;
77
+ z-index: 1;
78
+ }
79
+
80
+ [data-theme="light"] .file-tree-header {
81
+ background: linear-gradient(180deg, rgba(248, 250, 252, 0.95) 0%, rgba(248, 250, 252, 0.85) 100%);
82
+ }
83
+
84
+ .files-icon {
85
+ fill: var(--text-secondary);
86
+ flex-shrink: 0;
87
+ }
88
+
89
+ /* ========================================
90
+ Sidebar Controls
91
+ ======================================== */
92
+
93
+ .sidebar-controls {
94
+ backdrop-filter: blur(5px);
95
+ background: linear-gradient(180deg, rgba(19, 23, 29, 0.4) 0%, transparent 100%);
96
+ border-bottom: 1px solid var(--border-subtle);
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: var(--space-md);
100
+ padding: var(--space-lg) var(--space-lg) var(--space-md);
101
+ }
102
+
103
+ [data-theme="light"] .sidebar-controls {
104
+ background: linear-gradient(180deg, rgba(248, 250, 252, 0.6) 0%, transparent 100%);
105
+ }
106
+
107
+ .sidebar-branch {
108
+ font-size: 12px;
109
+ justify-content: flex-start;
110
+ width: 100%;
111
+ }
112
+
113
+ /* ========================================
114
+ File Tree Container
115
+ ======================================== */
116
+
117
+ .file-tree-container {
118
+ background: var(--bg-secondary);
119
+ padding: 8px 0;
120
+ }
121
+
122
+ /* ========================================
123
+ Tree Item
124
+ ======================================== */
125
+
126
+ .tree-item {
127
+ align-items: center;
128
+ border-radius: var(--radius-md);
129
+ color: var(--text-primary);
130
+ cursor: pointer;
131
+ display: flex;
132
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
133
+ font-size: 13px;
134
+ font-weight: 500;
135
+ gap: 8px;
136
+ line-height: 22px;
137
+ margin: 2px 6px;
138
+ padding: 8px 14px;
139
+ position: relative;
140
+ transition: all var(--transition-base);
141
+ user-select: none;
142
+ }
143
+
144
+ .tree-item::before {
145
+ background: linear-gradient(180deg, var(--link-color) 0%, var(--link-hover) 100%);
146
+ border-radius: 0 3px 3px 0;
147
+ box-shadow: 0 0 8px rgba(96, 165, 250, 0.4);
148
+ content: '';
149
+ height: 0;
150
+ left: 0;
151
+ position: absolute;
152
+ top: 50%;
153
+ transform: translateY(-50%);
154
+ transition: all var(--transition-base);
155
+ width: 3px;
156
+ }
157
+
158
+ .tree-item:hover {
159
+ background: rgba(96, 165, 250, 0.08);
160
+ border-left: 2px solid var(--link-color);
161
+ padding-left: 14px;
162
+ }
163
+
164
+ .tree-item:hover::before {
165
+ display: none;
166
+ }
167
+
168
+ .tree-item.active {
169
+ background: rgba(96, 165, 250, 0.12);
170
+ border-left: 2px solid var(--link-color);
171
+ font-weight: 600;
172
+ padding-left: 14px;
173
+ }
174
+
175
+ .tree-item.active::before {
176
+ box-shadow: 0 0 12px rgba(96, 165, 250, 0.6);
177
+ height: 85%;
178
+ opacity: 1;
179
+ }
180
+
181
+ [data-theme="light"] .tree-item.active {
182
+ background: linear-gradient(90deg, rgba(37, 99, 235, 0.1) 0%, rgba(37, 99, 235, 0.03) 100%);
183
+ border-color: rgba(37, 99, 235, 0.15);
184
+ }
185
+
186
+ .tree-item.hidden,
187
+ .tree-children.hidden {
188
+ display: none;
189
+ }
190
+
191
+ /* ========================================
192
+ Tree Item Components
193
+ ======================================== */
194
+
195
+ .tree-toggle {
196
+ color: var(--text-secondary);
197
+ display: inline-block;
198
+ flex-shrink: 0;
199
+ font-size: 10px;
200
+ text-align: center;
201
+ width: 12px;
202
+ }
203
+
204
+ .tree-spacer {
205
+ flex-shrink: 0;
206
+ width: 12px;
207
+ }
208
+
209
+ .tree-icon {
210
+ fill: var(--text-secondary);
211
+ flex-shrink: 0;
212
+ }
213
+
214
+ .tree-icon.file-icon {
215
+ fill: var(--text-secondary);
216
+ opacity: 0.7;
217
+ }
218
+
219
+ .tree-item .tree-icon:not(.file-icon) {
220
+ fill: #7dd3fc;
221
+ }
222
+
223
+ [data-theme="light"] .tree-item .tree-icon:not(.file-icon) {
224
+ fill: #54adf5;
225
+ }
226
+
227
+ .tree-label {
228
+ flex: 1;
229
+ font-weight: 400;
230
+ letter-spacing: normal;
231
+ overflow: hidden;
232
+ text-overflow: ellipsis;
233
+ white-space: nowrap;
234
+ }
235
+
236
+ .tree-children {
237
+ transition: none;
238
+ }
239
+
240
+ /* ========================================
241
+ Skeleton Loading
242
+ ======================================== */
243
+
244
+ .tree-skeleton {
245
+ padding: 8px;
246
+ }
247
+
248
+ .skeleton-item {
249
+ animation: skeleton-loading 1.5s ease-in-out infinite;
250
+ background: linear-gradient(90deg, var(--bg-secondary) 0%, var(--hover-bg) 50%, var(--bg-secondary) 100%);
251
+ background-size: 200% 100%;
252
+ border-radius: 4px;
253
+ height: 28px;
254
+ margin-bottom: 4px;
255
+ }
256
+
257
+ .skeleton-indent {
258
+ margin-left: 20px;
259
+ width: calc(100% - 20px);
260
+ }
261
+
262
+ @keyframes skeleton-loading {
263
+ 0% {
264
+ background-position: 200% 0;
265
+ }
266
+ 100% {
267
+ background-position: -200% 0;
268
+ }
269
+ }