gh-here 1.0.4 → 1.1.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.
- package/.claude/settings.local.json +3 -1
- package/README.md +11 -44
- package/bin/gh-here.js +41 -3
- package/lib/renderers.js +69 -36
- package/lib/server.js +1 -1
- package/package.json +1 -1
- package/public/styles.css +229 -69
package/README.md
CHANGED
|
@@ -29,11 +29,12 @@ Navigate to any directory and run:
|
|
|
29
29
|
```bash
|
|
30
30
|
gh-here # Start server on available port
|
|
31
31
|
gh-here --open # Start server and open browser
|
|
32
|
+
gh-here --port=8080 # Start server on port 8080
|
|
32
33
|
gh-here --open --browser=safari # Start server and open in Safari
|
|
33
34
|
gh-here --open --browser=arc # Start server and open in Arc
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
The app will automatically find an available port starting from
|
|
37
|
+
The app will automatically find an available port starting from 5555 and serve your current directory with a GitHub-like interface.
|
|
37
38
|
|
|
38
39
|
## Features
|
|
39
40
|
|
|
@@ -46,12 +47,13 @@ The app will automatically find an available port starting from 3000 and serve y
|
|
|
46
47
|
- File and folder creation, editing, renaming, and deletion
|
|
47
48
|
|
|
48
49
|
### 🎨 Code Viewing & Editing
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
50
|
+
- VS Code-quality Monaco Editor with advanced syntax highlighting for 30+ languages
|
|
51
|
+
- GitHub-style line numbers with selection (click, shift-click, ctrl-click)
|
|
52
|
+
- Professional in-browser file editing with auto-save to localStorage
|
|
53
|
+
- Draft management with persistence across sessions
|
|
52
54
|
- Raw and rendered markdown views
|
|
53
55
|
- Shareable URLs with line selections (`#L10-L20`)
|
|
54
|
-
-
|
|
56
|
+
- Monaco Editor features: IntelliSense, bracket matching, folding
|
|
55
57
|
|
|
56
58
|
### 🔀 Git Integration
|
|
57
59
|
- Automatic git repository detection
|
|
@@ -86,44 +88,9 @@ The app will automatically find an available port starting from 3000 and serve y
|
|
|
86
88
|
- Error handling and loading states
|
|
87
89
|
- Notification system for user feedback
|
|
88
90
|
|
|
89
|
-
##
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- JavaScript (.js, .mjs, .jsx) - React, Node.js
|
|
93
|
-
- TypeScript (.ts, .tsx)
|
|
94
|
-
- Python (.py)
|
|
95
|
-
- Java (.java)
|
|
96
|
-
- Go (.go)
|
|
97
|
-
- Rust (.rs)
|
|
98
|
-
- PHP (.php)
|
|
99
|
-
- Ruby (.rb)
|
|
100
|
-
- Swift (.swift)
|
|
101
|
-
- Kotlin (.kt)
|
|
102
|
-
- Dart (.dart)
|
|
103
|
-
|
|
104
|
-
### Web Technologies
|
|
105
|
-
- HTML (.html)
|
|
106
|
-
- CSS (.css, .scss, .sass, .less)
|
|
107
|
-
- JSON (.json)
|
|
108
|
-
- XML (.xml)
|
|
109
|
-
- YAML (.yml, .yaml)
|
|
110
|
-
|
|
111
|
-
### Documentation & Config
|
|
112
|
-
- Markdown (.md) - with beautiful rendering
|
|
113
|
-
- Text files (.txt)
|
|
114
|
-
- Configuration files (ESLint, Prettier, Webpack, etc.)
|
|
115
|
-
- Docker files (Dockerfile, docker-compose.yml)
|
|
116
|
-
- Environment files (.env)
|
|
117
|
-
|
|
118
|
-
### Media & Archives
|
|
119
|
-
- Images (.png, .jpg, .gif, .svg, .webp)
|
|
120
|
-
- Videos (.mp4, .mov, .avi)
|
|
121
|
-
- Audio (.mp3, .wav, .flac)
|
|
122
|
-
- Archives (.zip, .tar, .gz, .rar)
|
|
123
|
-
|
|
124
|
-
### Shell & Database
|
|
125
|
-
- Shell scripts (.sh, .bash, .zsh)
|
|
126
|
-
- SQL (.sql)
|
|
91
|
+
## Language Support
|
|
92
|
+
|
|
93
|
+
Supports syntax highlighting for 30+ languages including JavaScript, TypeScript, Python, Go, Rust, Java, C/C++, and many more through Monaco Editor integration.
|
|
127
94
|
|
|
128
95
|
## Keyboard Shortcuts
|
|
129
96
|
|
|
@@ -161,7 +128,7 @@ npm install
|
|
|
161
128
|
npm start
|
|
162
129
|
```
|
|
163
130
|
|
|
164
|
-
Navigate to `http://localhost:
|
|
131
|
+
Navigate to `http://localhost:5555` to view the interface.
|
|
165
132
|
|
|
166
133
|
## Dependencies
|
|
167
134
|
|
package/bin/gh-here.js
CHANGED
|
@@ -12,6 +12,17 @@ const args = process.argv.slice(2);
|
|
|
12
12
|
const openBrowser = args.includes('--open') || args.includes('-o');
|
|
13
13
|
const helpRequested = args.includes('--help') || args.includes('-h');
|
|
14
14
|
|
|
15
|
+
// Check for port specification
|
|
16
|
+
let specifiedPort = null;
|
|
17
|
+
const portArg = args.find(arg => arg.startsWith('--port='));
|
|
18
|
+
if (portArg) {
|
|
19
|
+
specifiedPort = parseInt(portArg.split('=')[1]);
|
|
20
|
+
if (isNaN(specifiedPort) || specifiedPort < 1 || specifiedPort > 65535) {
|
|
21
|
+
console.error('❌ Invalid port number. Port must be between 1 and 65535.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
// Check for browser specification
|
|
16
27
|
let specificBrowser = null;
|
|
17
28
|
const browserArg = args.find(arg => arg.startsWith('--browser='));
|
|
@@ -28,11 +39,13 @@ Usage: npx gh-here [options]
|
|
|
28
39
|
Options:
|
|
29
40
|
--open, -o Open browser automatically
|
|
30
41
|
--browser=<name> Specify browser (safari, chrome, firefox, arc)
|
|
42
|
+
--port=<number> Specify port number (default: 5555)
|
|
31
43
|
--help, -h Show this help message
|
|
32
44
|
|
|
33
45
|
Examples:
|
|
34
|
-
npx gh-here Start server on available
|
|
46
|
+
npx gh-here Start server on port 5555 (or next available)
|
|
35
47
|
npx gh-here --open Start server and open browser
|
|
48
|
+
npx gh-here --port=8080 Start server on port 8080
|
|
36
49
|
npx gh-here --open --browser=safari Start server and open in Safari
|
|
37
50
|
npx gh-here --open --browser=arc Start server and open in Arc
|
|
38
51
|
`);
|
|
@@ -50,7 +63,7 @@ const isGitRepo = !!gitRepoRoot;
|
|
|
50
63
|
setupRoutes(app, workingDir, isGitRepo, gitRepoRoot);
|
|
51
64
|
|
|
52
65
|
// Function to find an available port
|
|
53
|
-
async function findAvailablePort(startPort =
|
|
66
|
+
async function findAvailablePort(startPort = 5555) {
|
|
54
67
|
const net = require('net');
|
|
55
68
|
|
|
56
69
|
return new Promise((resolve, reject) => {
|
|
@@ -133,7 +146,32 @@ function openBrowserToUrl(url) {
|
|
|
133
146
|
// Start server with automatic port selection
|
|
134
147
|
async function startServer() {
|
|
135
148
|
try {
|
|
136
|
-
|
|
149
|
+
let port;
|
|
150
|
+
if (specifiedPort) {
|
|
151
|
+
// If user specified a port, try only that port
|
|
152
|
+
const net = require('net');
|
|
153
|
+
const server = net.createServer();
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
await new Promise((resolve, reject) => {
|
|
157
|
+
server.listen(specifiedPort, () => {
|
|
158
|
+
server.close(() => resolve());
|
|
159
|
+
});
|
|
160
|
+
server.on('error', reject);
|
|
161
|
+
});
|
|
162
|
+
port = specifiedPort;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (error.code === 'EADDRINUSE') {
|
|
165
|
+
console.error(`❌ Port ${specifiedPort} is already in use. Please choose a different port.`);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
} else {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
// Find available port starting from 5555
|
|
173
|
+
port = await findAvailablePort(5555);
|
|
174
|
+
}
|
|
137
175
|
const url = `http://localhost:${port}`;
|
|
138
176
|
|
|
139
177
|
app.listen(port, () => {
|
package/lib/renderers.js
CHANGED
|
@@ -13,8 +13,9 @@ const { getGitStatusIcon, getGitStatusDescription } = require('./git');
|
|
|
13
13
|
* Handles all HTML template generation for different views
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
function renderDirectory(currentPath, items, showGitignored = false, gitBranch = null, gitStatus = {}) {
|
|
17
|
-
const
|
|
16
|
+
function renderDirectory(currentPath, items, showGitignored = false, gitBranch = null, gitStatus = {}, workingDir = null) {
|
|
17
|
+
const workingDirName = workingDir ? path.basename(workingDir) : null;
|
|
18
|
+
const breadcrumbs = generateBreadcrumbs(currentPath, gitBranch, workingDirName);
|
|
18
19
|
const readmeFile = findReadmeFile(items);
|
|
19
20
|
const readmePreview = readmeFile ? generateReadmePreview(currentPath, readmeFile) : '';
|
|
20
21
|
const languageStats = generateLanguageStats(items);
|
|
@@ -22,7 +23,7 @@ function renderDirectory(currentPath, items, showGitignored = false, gitBranch =
|
|
|
22
23
|
const itemsHtml = items.map(item => `
|
|
23
24
|
<tr class="file-row" data-name="${item.name.toLowerCase()}" data-type="${item.isDirectory ? 'dir' : 'file'}" data-path="${item.path}">
|
|
24
25
|
<td class="icon">
|
|
25
|
-
${item.isDirectory ? octicons['file-directory'].toSVG({ class: 'octicon-directory' }) : getFileIcon(item.name)}
|
|
26
|
+
${item.isDirectory ? octicons['file-directory-fill'].toSVG({ class: 'octicon-directory' }) : getFileIcon(item.name)}
|
|
26
27
|
</td>
|
|
27
28
|
<td class="git-status-col">
|
|
28
29
|
${item.gitStatus ? (item.gitStatus.status === '??' ? `<span class="git-status git-status-untracked" title="Untracked file">${require('./git').getGitStatusIcon('??')}</span>` : `<span class="git-status git-status-${item.gitStatus.status.replace(' ', '')}" title="Git Status: ${getGitStatusDescription(item.gitStatus.status)}">${getGitStatusIcon(item.gitStatus.status)}</span>`) : ''}
|
|
@@ -78,13 +79,9 @@ function renderDirectory(currentPath, items, showGitignored = false, gitBranch =
|
|
|
78
79
|
<header>
|
|
79
80
|
<div class="header-content">
|
|
80
81
|
<div class="header-left">
|
|
81
|
-
<h1
|
|
82
|
+
<h1>gh-here</h1>
|
|
82
83
|
</div>
|
|
83
84
|
<div class="header-right">
|
|
84
|
-
<div class="search-container">
|
|
85
|
-
${octicons.search.toSVG({ class: 'search-icon' })}
|
|
86
|
-
<input type="text" id="file-search" placeholder="Find files..." class="search-input">
|
|
87
|
-
</div>
|
|
88
85
|
${Object.keys(gitStatus).length > 0 ? `
|
|
89
86
|
<button id="commit-btn" class="commit-btn" title="Commit changes">
|
|
90
87
|
${octicons['git-commit'].toSVG({ class: 'commit-icon' })}
|
|
@@ -100,15 +97,42 @@ function renderDirectory(currentPath, items, showGitignored = false, gitBranch =
|
|
|
100
97
|
</div>
|
|
101
98
|
</div>
|
|
102
99
|
</header>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
|
|
101
|
+
<!-- White canvas section like GitHub -->
|
|
102
|
+
<div class="repo-canvas">
|
|
103
|
+
<div class="repo-canvas-content">
|
|
104
|
+
<div class="breadcrumb-section">${breadcrumbs}</div>
|
|
105
|
+
<hr class="repo-divider">
|
|
106
|
+
|
|
107
|
+
<div class="repo-controls">
|
|
108
|
+
<div class="repo-controls-left">
|
|
109
|
+
${gitBranch ? `
|
|
110
|
+
<button class="branch-button">
|
|
111
|
+
${octicons['git-branch'].toSVG({ class: 'octicon-branch' })}
|
|
112
|
+
<span class="branch-name">${gitBranch}</span>
|
|
113
|
+
${octicons['chevron-down'].toSVG({ class: 'octicon-chevron' })}
|
|
114
|
+
</button>
|
|
115
|
+
` : ''}
|
|
116
|
+
</div>
|
|
117
|
+
<div class="repo-controls-right">
|
|
118
|
+
<div class="search-container">
|
|
119
|
+
${octicons.search.toSVG({ class: 'search-icon' })}
|
|
120
|
+
<input type="text" id="file-search" placeholder="Go to file" class="search-input">
|
|
121
|
+
<kbd class="search-hotkey">t</kbd>
|
|
122
|
+
</div>
|
|
123
|
+
<button id="new-file-btn" class="btn btn-outline">
|
|
124
|
+
<span class="btn-text">New file</span>
|
|
125
|
+
</button>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
109
128
|
</div>
|
|
110
|
-
|
|
111
|
-
|
|
129
|
+
</div>
|
|
130
|
+
<main>
|
|
131
|
+
<div class="repo-canvas">
|
|
132
|
+
<div class="repo-canvas-content">
|
|
133
|
+
${languageStats}
|
|
134
|
+
<div class="file-table-container">
|
|
135
|
+
<table class="file-table" id="file-table">
|
|
112
136
|
<thead>
|
|
113
137
|
<tr>
|
|
114
138
|
<th></th>
|
|
@@ -133,8 +157,10 @@ function renderDirectory(currentPath, items, showGitignored = false, gitBranch =
|
|
|
133
157
|
${itemsHtml}
|
|
134
158
|
</tbody>
|
|
135
159
|
</table>
|
|
160
|
+
</div>
|
|
161
|
+
${readmePreview}
|
|
162
|
+
</div>
|
|
136
163
|
</div>
|
|
137
|
-
${readmePreview}
|
|
138
164
|
</main>
|
|
139
165
|
</body>
|
|
140
166
|
</html>
|
|
@@ -265,7 +291,7 @@ async function renderFileDiff(filePath, ext, gitInfo, gitRepoRoot) {
|
|
|
265
291
|
<header>
|
|
266
292
|
<div class="header-content">
|
|
267
293
|
<div class="header-left">
|
|
268
|
-
<h1
|
|
294
|
+
<h1>gh-here</h1>
|
|
269
295
|
</div>
|
|
270
296
|
<div class="header-right">
|
|
271
297
|
${viewToggle}
|
|
@@ -276,9 +302,12 @@ async function renderFileDiff(filePath, ext, gitInfo, gitRepoRoot) {
|
|
|
276
302
|
</div>
|
|
277
303
|
</header>
|
|
278
304
|
<main>
|
|
279
|
-
<div class="
|
|
280
|
-
<div class="
|
|
281
|
-
|
|
305
|
+
<div class="main-content">
|
|
306
|
+
<div class="breadcrumb-section">${breadcrumbs}</div>
|
|
307
|
+
<div class="diff-container">
|
|
308
|
+
<div class="diff-content">
|
|
309
|
+
${diffContent}
|
|
310
|
+
</div>
|
|
282
311
|
</div>
|
|
283
312
|
</div>
|
|
284
313
|
</main>
|
|
@@ -433,10 +462,7 @@ async function renderFile(filePath, content, ext, viewMode = 'rendered', gitStat
|
|
|
433
462
|
<header>
|
|
434
463
|
<div class="header-content">
|
|
435
464
|
<div class="header-left">
|
|
436
|
-
<h1
|
|
437
|
-
${breadcrumbs}
|
|
438
|
-
${hasGitChanges ? (hasGitChanges.status === '??' ? `<span class="git-status git-status-untracked" title="Untracked file">${getGitStatusIcon('??')}</span>` : `<span class="git-status git-status-${hasGitChanges.status.replace(' ', '')}" title="Git Status: ${getGitStatusDescription(hasGitChanges.status)}">${getGitStatusIcon(hasGitChanges.status)}</span>`) : ''}
|
|
439
|
-
</h1>
|
|
465
|
+
<h1>gh-here</h1>
|
|
440
466
|
</div>
|
|
441
467
|
<div class="header-right">
|
|
442
468
|
<div id="filename-input-container" class="filename-input-container" style="display: none;">
|
|
@@ -453,9 +479,11 @@ async function renderFile(filePath, content, ext, viewMode = 'rendered', gitStat
|
|
|
453
479
|
</div>
|
|
454
480
|
</header>
|
|
455
481
|
<main>
|
|
456
|
-
<div class="
|
|
457
|
-
|
|
458
|
-
|
|
482
|
+
<div class="main-content">
|
|
483
|
+
<div class="breadcrumb-section">${breadcrumbs}</div>
|
|
484
|
+
<div class="file-content">
|
|
485
|
+
${displayContent}
|
|
486
|
+
</div>
|
|
459
487
|
<div id="editor-container" class="editor-container" style="display: none;">
|
|
460
488
|
<div class="editor-header">
|
|
461
489
|
<div class="editor-title">Edit ${path.basename(filePath)}</div>
|
|
@@ -469,6 +497,7 @@ async function renderFile(filePath, content, ext, viewMode = 'rendered', gitStat
|
|
|
469
497
|
<div id="file-editor" class="monaco-editor"></div>
|
|
470
498
|
</div>
|
|
471
499
|
</div>
|
|
500
|
+
</div>
|
|
472
501
|
</main>
|
|
473
502
|
</body>
|
|
474
503
|
</html>
|
|
@@ -492,7 +521,7 @@ function renderNewFile(currentPath) {
|
|
|
492
521
|
<header>
|
|
493
522
|
<div class="header-content">
|
|
494
523
|
<div class="header-left">
|
|
495
|
-
<h1
|
|
524
|
+
<h1>gh-here</h1>
|
|
496
525
|
</div>
|
|
497
526
|
<div class="header-right">
|
|
498
527
|
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle theme">
|
|
@@ -502,8 +531,10 @@ function renderNewFile(currentPath) {
|
|
|
502
531
|
</div>
|
|
503
532
|
</header>
|
|
504
533
|
<main>
|
|
505
|
-
<div class="
|
|
506
|
-
<div class="
|
|
534
|
+
<div class="main-content">
|
|
535
|
+
<div class="breadcrumb-section">${breadcrumbs}</div>
|
|
536
|
+
<div class="new-file-container">
|
|
537
|
+
<div class="new-file-header">
|
|
507
538
|
<div class="filename-section">
|
|
508
539
|
<span class="filename-label">Name your file...</span>
|
|
509
540
|
<input type="text" id="new-filename-input" class="new-filename-input" placeholder="README.md" autofocus>
|
|
@@ -519,24 +550,26 @@ function renderNewFile(currentPath) {
|
|
|
519
550
|
</div>
|
|
520
551
|
</div>
|
|
521
552
|
</div>
|
|
553
|
+
</div>
|
|
522
554
|
</main>
|
|
523
555
|
</body>
|
|
524
556
|
</html>
|
|
525
557
|
`;
|
|
526
558
|
}
|
|
527
559
|
|
|
528
|
-
function generateBreadcrumbs(currentPath, gitBranch = null) {
|
|
529
|
-
|
|
560
|
+
function generateBreadcrumbs(currentPath, gitBranch = null, workingDirName = null) {
|
|
561
|
+
const rootDisplayName = workingDirName || 'repository';
|
|
562
|
+
|
|
563
|
+
// At root, show working directory name
|
|
530
564
|
if (!currentPath || currentPath === '.') {
|
|
531
|
-
|
|
532
|
-
return `${octicons.home.toSVG({ class: 'octicon-home' })} gh-here ${gitBranchDisplay}`;
|
|
565
|
+
return `${octicons.home.toSVG({ class: 'octicon-home' })} ${rootDisplayName}`;
|
|
533
566
|
}
|
|
534
567
|
|
|
535
568
|
// In subdirectories, show clickable path
|
|
536
569
|
const parts = currentPath.split('/').filter(p => p && p !== '.');
|
|
537
570
|
let breadcrumbs = `
|
|
538
571
|
<div class="breadcrumb-item">
|
|
539
|
-
<a href="/">${octicons.home.toSVG({ class: 'octicon-home' })}</a>
|
|
572
|
+
<a href="/">${octicons.home.toSVG({ class: 'octicon-home' })} ${rootDisplayName}</a>
|
|
540
573
|
</div>
|
|
541
574
|
`;
|
|
542
575
|
let buildPath = '';
|
package/lib/server.js
CHANGED
|
@@ -82,7 +82,7 @@ function setupRoutes(app, workingDir, isGitRepo, gitRepoRoot) {
|
|
|
82
82
|
return a.name.localeCompare(b.name);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
res.send(renderDirectory(currentPath, items, showGitignored, gitBranch, gitStatus));
|
|
85
|
+
res.send(renderDirectory(currentPath, items, showGitignored, gitBranch, gitStatus, workingDir));
|
|
86
86
|
} else {
|
|
87
87
|
const content = fs.readFileSync(fullPath, 'utf8');
|
|
88
88
|
const ext = path.extname(fullPath).slice(1);
|
package/package.json
CHANGED
package/public/styles.css
CHANGED
|
@@ -52,15 +52,15 @@ body {
|
|
|
52
52
|
header {
|
|
53
53
|
background-color: var(--bg-secondary);
|
|
54
54
|
border-bottom: 1px solid var(--border-primary);
|
|
55
|
-
padding: 16px 24px;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
.header-content {
|
|
59
58
|
display: flex;
|
|
60
59
|
justify-content: space-between;
|
|
61
60
|
align-items: flex-start;
|
|
62
|
-
max-width:
|
|
61
|
+
max-width: 900px;
|
|
63
62
|
margin: 0 auto;
|
|
63
|
+
padding: 16px 24px;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.header-left h1 {
|
|
@@ -82,6 +82,203 @@ header {
|
|
|
82
82
|
gap: 12px;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/* GitHub-style White Canvas Section */
|
|
86
|
+
.repo-canvas {
|
|
87
|
+
background-color: var(--bg-primary);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.repo-canvas-content {
|
|
91
|
+
max-width: 900px;
|
|
92
|
+
margin: 0 auto;
|
|
93
|
+
padding: 16px 24px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.breadcrumb-section {
|
|
97
|
+
font-size: 20px;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
color: var(--text-primary);
|
|
100
|
+
margin: 0 0 12px 0;
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
flex-wrap: wrap;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.repo-name {
|
|
107
|
+
font-size: 20px;
|
|
108
|
+
font-weight: 600;
|
|
109
|
+
color: var(--text-primary);
|
|
110
|
+
margin: 0 0 12px 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.repo-divider {
|
|
114
|
+
border: none;
|
|
115
|
+
border-top: 1px solid var(--border-primary);
|
|
116
|
+
margin: 0 0 12px 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.repo-controls {
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: space-between;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.repo-controls-left {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.repo-controls-right {
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 12px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.branch-button {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 6px;
|
|
140
|
+
padding: 5px 12px;
|
|
141
|
+
background: var(--bg-primary);
|
|
142
|
+
border: 1px solid var(--border-primary);
|
|
143
|
+
border-radius: 6px;
|
|
144
|
+
color: var(--text-primary);
|
|
145
|
+
font-size: 14px;
|
|
146
|
+
font-weight: 500;
|
|
147
|
+
cursor: pointer;
|
|
148
|
+
transition: all 0.2s ease;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.branch-button:hover {
|
|
152
|
+
background: var(--bg-secondary);
|
|
153
|
+
border-color: var(--text-secondary);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.branch-count,
|
|
157
|
+
.tag-count {
|
|
158
|
+
color: var(--text-secondary);
|
|
159
|
+
font-size: 14px;
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
gap: 6px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.octicon-branch {
|
|
166
|
+
width: 16px;
|
|
167
|
+
height: 16px;
|
|
168
|
+
fill: var(--text-secondary);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.octicon-small {
|
|
172
|
+
width: 14px;
|
|
173
|
+
height: 14px;
|
|
174
|
+
fill: var(--text-secondary);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.branch-name {
|
|
178
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.octicon-chevron {
|
|
183
|
+
width: 12px;
|
|
184
|
+
height: 12px;
|
|
185
|
+
fill: var(--text-secondary);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.search-container {
|
|
189
|
+
position: relative;
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.search-input {
|
|
195
|
+
background: var(--bg-primary);
|
|
196
|
+
border: 1px solid var(--border-primary);
|
|
197
|
+
border-radius: 6px;
|
|
198
|
+
padding: 6px 40px 6px 32px;
|
|
199
|
+
color: var(--text-primary);
|
|
200
|
+
font-size: 14px;
|
|
201
|
+
width: 300px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.search-input:focus {
|
|
205
|
+
outline: none;
|
|
206
|
+
border-color: #0969da;
|
|
207
|
+
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.3);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.search-icon {
|
|
211
|
+
position: absolute;
|
|
212
|
+
left: 8px;
|
|
213
|
+
width: 16px;
|
|
214
|
+
height: 16px;
|
|
215
|
+
fill: var(--text-secondary);
|
|
216
|
+
pointer-events: none;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.search-hotkey {
|
|
220
|
+
position: absolute;
|
|
221
|
+
right: 8px;
|
|
222
|
+
background: var(--bg-tertiary);
|
|
223
|
+
border: 1px solid var(--border-primary);
|
|
224
|
+
border-radius: 3px;
|
|
225
|
+
padding: 2px 6px;
|
|
226
|
+
font-size: 12px;
|
|
227
|
+
color: var(--text-secondary);
|
|
228
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* GitHub-style Buttons */
|
|
232
|
+
.btn {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 6px;
|
|
236
|
+
padding: 6px 12px;
|
|
237
|
+
border-radius: 6px;
|
|
238
|
+
font-size: 14px;
|
|
239
|
+
font-weight: 500;
|
|
240
|
+
cursor: pointer;
|
|
241
|
+
transition: all 0.2s ease;
|
|
242
|
+
border: 1px solid;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.btn-primary {
|
|
246
|
+
background: var(--bg-primary);
|
|
247
|
+
border-color: var(--border-primary);
|
|
248
|
+
color: var(--text-primary);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.btn-primary:hover {
|
|
252
|
+
background: var(--bg-secondary);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.btn-outline {
|
|
256
|
+
background: var(--bg-primary);
|
|
257
|
+
border-color: var(--border-primary);
|
|
258
|
+
color: var(--text-primary);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.btn-outline:hover {
|
|
262
|
+
background: var(--bg-secondary);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.btn-success {
|
|
266
|
+
background: #238636;
|
|
267
|
+
border-color: rgba(240, 246, 252, 0.1);
|
|
268
|
+
color: #ffffff;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.btn-success:hover {
|
|
272
|
+
background: #2ea043;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.btn-icon,
|
|
276
|
+
.btn-chevron {
|
|
277
|
+
width: 16px;
|
|
278
|
+
height: 16px;
|
|
279
|
+
fill: currentColor;
|
|
280
|
+
}
|
|
281
|
+
|
|
85
282
|
.theme-toggle,
|
|
86
283
|
.gitignore-toggle,
|
|
87
284
|
.edit-btn {
|
|
@@ -158,7 +355,7 @@ header {
|
|
|
158
355
|
}
|
|
159
356
|
|
|
160
357
|
.breadcrumb-item {
|
|
161
|
-
display: flex;
|
|
358
|
+
display: inline-flex;
|
|
162
359
|
align-items: center;
|
|
163
360
|
}
|
|
164
361
|
|
|
@@ -184,9 +381,13 @@ header {
|
|
|
184
381
|
}
|
|
185
382
|
|
|
186
383
|
main {
|
|
187
|
-
padding:
|
|
188
|
-
|
|
384
|
+
padding: 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.main-content {
|
|
388
|
+
max-width: 900px;
|
|
189
389
|
margin: 0 auto;
|
|
390
|
+
padding: 16px 24px;
|
|
190
391
|
}
|
|
191
392
|
|
|
192
393
|
.directory-actions {
|
|
@@ -261,13 +462,13 @@ main {
|
|
|
261
462
|
vertical-align: text-bottom;
|
|
262
463
|
}
|
|
263
464
|
|
|
264
|
-
/* GitHub-style blue folder icons */
|
|
465
|
+
/* GitHub-style baby blue folder icons */
|
|
265
466
|
.octicon-directory {
|
|
266
|
-
fill: #
|
|
467
|
+
fill: #7dd3fc;
|
|
267
468
|
}
|
|
268
469
|
|
|
269
470
|
[data-theme="light"] .octicon-directory {
|
|
270
|
-
fill: #
|
|
471
|
+
fill: #54adf5;
|
|
271
472
|
}
|
|
272
473
|
|
|
273
474
|
.octicon-home {
|
|
@@ -296,43 +497,7 @@ main {
|
|
|
296
497
|
[data-theme="light"] .text-orange { color: #bc4c00; }
|
|
297
498
|
[data-theme="light"] .text-purple { color: #6f42c1; }
|
|
298
499
|
|
|
299
|
-
/*
|
|
300
|
-
.search-container {
|
|
301
|
-
position: relative;
|
|
302
|
-
display: flex;
|
|
303
|
-
align-items: center;
|
|
304
|
-
background: var(--bg-primary);
|
|
305
|
-
border: 1px solid var(--border-primary);
|
|
306
|
-
border-radius: 6px;
|
|
307
|
-
padding: 6px 8px;
|
|
308
|
-
transition: all 0.2s ease;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.search-container:focus-within {
|
|
312
|
-
border-color: var(--link-color);
|
|
313
|
-
box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.search-icon {
|
|
317
|
-
width: 16px;
|
|
318
|
-
height: 16px;
|
|
319
|
-
fill: var(--text-secondary);
|
|
320
|
-
margin-right: 6px;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.search-input {
|
|
324
|
-
background: none;
|
|
325
|
-
border: none;
|
|
326
|
-
outline: none;
|
|
327
|
-
color: var(--text-primary);
|
|
328
|
-
font-size: 14px;
|
|
329
|
-
width: 200px;
|
|
330
|
-
transition: all 0.2s ease;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
.search-input::placeholder {
|
|
334
|
-
color: var(--text-secondary);
|
|
335
|
-
}
|
|
500
|
+
/* Old search styles removed - using new GitHub-style search */
|
|
336
501
|
|
|
337
502
|
/* Language stats */
|
|
338
503
|
.language-stats {
|
|
@@ -451,9 +616,6 @@ main {
|
|
|
451
616
|
|
|
452
617
|
|
|
453
618
|
/* Loading states */
|
|
454
|
-
.search-input:focus {
|
|
455
|
-
width: 250px;
|
|
456
|
-
}
|
|
457
619
|
|
|
458
620
|
/* Quick actions */
|
|
459
621
|
.name {
|
|
@@ -1109,8 +1271,18 @@ main {
|
|
|
1109
1271
|
|
|
1110
1272
|
|
|
1111
1273
|
@media (max-width: 768px) {
|
|
1112
|
-
main {
|
|
1113
|
-
padding: 16px;
|
|
1274
|
+
.main-content {
|
|
1275
|
+
padding: 12px 16px;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
.repo-canvas-content {
|
|
1279
|
+
padding: 12px 16px;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
.header-content {
|
|
1283
|
+
padding: 12px 16px;
|
|
1284
|
+
flex-direction: column;
|
|
1285
|
+
gap: 12px;
|
|
1114
1286
|
}
|
|
1115
1287
|
|
|
1116
1288
|
.file-table .size,
|
|
@@ -1118,13 +1290,15 @@ main {
|
|
|
1118
1290
|
display: none;
|
|
1119
1291
|
}
|
|
1120
1292
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1293
|
+
.repo-controls {
|
|
1294
|
+
flex-direction: column;
|
|
1295
|
+
gap: 12px;
|
|
1296
|
+
align-items: stretch;
|
|
1123
1297
|
}
|
|
1124
1298
|
|
|
1125
|
-
.
|
|
1299
|
+
.repo-controls-right {
|
|
1126
1300
|
flex-direction: column;
|
|
1127
|
-
gap:
|
|
1301
|
+
gap: 8px;
|
|
1128
1302
|
}
|
|
1129
1303
|
|
|
1130
1304
|
.header-right {
|
|
@@ -1331,22 +1505,8 @@ main {
|
|
|
1331
1505
|
transform: translateY(0);
|
|
1332
1506
|
}
|
|
1333
1507
|
}
|
|
1334
|
-
}
|
|
1335
|
-
/* Git Integration */
|
|
1336
|
-
.git-branch {
|
|
1337
|
-
display: inline-flex;
|
|
1338
|
-
align-items: center;
|
|
1339
|
-
margin-left: 12px;
|
|
1340
|
-
color: var(--text-secondary);
|
|
1341
|
-
font-size: 14px;
|
|
1342
|
-
font-weight: 500;
|
|
1343
|
-
gap: 6px;
|
|
1344
|
-
}
|
|
1345
1508
|
|
|
1346
|
-
|
|
1347
|
-
width: 16px;
|
|
1348
|
-
height: 16px;
|
|
1349
|
-
}
|
|
1509
|
+
/* Git Integration */
|
|
1350
1510
|
|
|
1351
1511
|
.git-status {
|
|
1352
1512
|
display: inline;
|