@haowjy/remote-workspace 0.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.
@@ -0,0 +1,185 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
+ <title>Workspace</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script>
9
+ tailwind.config = {
10
+ theme: {
11
+ extend: {
12
+ colors: {
13
+ ink: {
14
+ 50: 'var(--ink-50)', 100: 'var(--ink-100)', 200: 'var(--ink-200)',
15
+ 300: 'var(--ink-300)', 400: 'var(--ink-400)', 500: 'var(--ink-500)',
16
+ 600: 'var(--ink-600)', 700: 'var(--ink-700)', 800: 'var(--ink-800)',
17
+ 900: 'var(--ink-900)', 950: 'var(--ink-950)',
18
+ },
19
+ brand: { DEFAULT: 'var(--brand)', light: 'var(--brand-light)', dark: 'var(--brand-dark)' },
20
+ },
21
+ fontFamily: {
22
+ sans: ['"DM Sans"', 'ui-sans-serif', 'system-ui', 'sans-serif'],
23
+ mono: ['"JetBrains Mono"', 'ui-monospace', 'monospace'],
24
+ },
25
+ },
26
+ },
27
+ };
28
+ </script>
29
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
30
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
31
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
32
+ <link id="hljs-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css" />
33
+ <link rel="stylesheet" href="/styles.css" />
34
+ </head>
35
+ <body class="bg-ink-950 text-ink-100 font-sans h-[100dvh] flex flex-col overflow-hidden">
36
+
37
+ <!-- Top bar -->
38
+ <header class="shrink-0 bg-ink-900 border-b border-ink-800 px-4 py-2.5 flex items-center gap-3 z-30">
39
+ <h1 class="text-sm font-bold tracking-wide uppercase text-ink-400 shrink-0">Workspace</h1>
40
+ <div class="flex-1"></div>
41
+ <button id="theme-toggle-btn" type="button" class="p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Toggle theme">
42
+ <i data-lucide="sun" class="w-4 h-4"></i>
43
+ </button>
44
+ <div id="status" class="text-[11px] text-ink-500 font-mono truncate max-w-52"></div>
45
+ </header>
46
+
47
+ <!-- Tab panels (only one visible at a time) -->
48
+ <div class="flex-1 min-h-0 relative">
49
+
50
+ <!-- Tab: Clipboard -->
51
+ <section id="panel-clipboard" class="tab-panel absolute inset-0 flex flex-col">
52
+ <div class="shrink-0 bg-ink-900/60 border-b border-ink-800 px-4 py-3 flex flex-wrap items-center gap-2">
53
+ <label class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-brand bg-brand-light/10 border border-brand/20 rounded-lg cursor-pointer hover:bg-brand-light/20 transition-colors">
54
+ <i data-lucide="image-plus" class="w-3.5 h-3.5"></i>
55
+ Choose
56
+ <input id="upload-input" type="file" accept="image/*" hidden />
57
+ </label>
58
+ <button id="paste-clipboard-btn" type="button" class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-ink-300 bg-ink-800 border border-ink-700 rounded-lg hover:bg-ink-700 transition-colors">
59
+ <i data-lucide="clipboard-paste" class="w-3.5 h-3.5"></i>
60
+ Paste
61
+ </button>
62
+ <input
63
+ id="upload-name-input"
64
+ type="text"
65
+ placeholder="filename.png"
66
+ class="px-2.5 py-1.5 text-sm font-mono bg-ink-800 border border-ink-700 rounded-lg w-40 focus:outline-none focus:ring-2 focus:ring-brand/40 focus:border-brand placeholder:text-ink-600 text-ink-200"
67
+ />
68
+ <button id="upload-btn" type="button" class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-semibold text-white bg-brand rounded-lg hover:bg-brand-dark transition-colors">
69
+ <i data-lucide="upload" class="w-3.5 h-3.5"></i>
70
+ Upload
71
+ </button>
72
+ <button id="clipboard-refresh-btn" type="button" class="p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors ml-auto" title="Refresh">
73
+ <i data-lucide="refresh-cw" class="w-4 h-4"></i>
74
+ </button>
75
+ </div>
76
+ <div id="clipboard-status" class="shrink-0 px-4 py-1 text-[11px] text-ink-500 font-mono min-h-[1.4em]"></div>
77
+ <div id="clipboard-grid" class="flex-1 overflow-y-auto overscroll-contain p-3 grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 content-start"></div>
78
+ </section>
79
+
80
+ <!-- Tab: Files -->
81
+ <section id="panel-files" class="tab-panel absolute inset-0 flex flex-col hidden">
82
+ <!-- Search bar -->
83
+ <div class="shrink-0 bg-ink-900/60 border-b border-ink-800 px-4 py-2.5 flex items-center gap-2">
84
+ <div class="relative flex-1">
85
+ <i data-lucide="search" class="absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-ink-500 pointer-events-none"></i>
86
+ <input
87
+ id="search-input"
88
+ type="text"
89
+ placeholder="Search files..."
90
+ class="w-full pl-8 pr-3 py-1.5 text-sm font-mono bg-ink-800 border border-ink-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand/40 focus:border-brand placeholder:text-ink-600 text-ink-200 transition-colors"
91
+ />
92
+ <div id="search-results" class="hidden absolute top-full left-0 right-0 mt-1 bg-ink-800 border border-ink-700 rounded-lg shadow-xl max-h-72 overflow-y-auto z-40"></div>
93
+ </div>
94
+ <button id="tree-refresh-btn" type="button" class="p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Refresh">
95
+ <i data-lucide="refresh-cw" class="w-4 h-4"></i>
96
+ </button>
97
+ </div>
98
+ <!-- Split: tree + preview -->
99
+ <div class="flex-1 min-h-0 flex flex-col lg:flex-row">
100
+ <div id="file-tree" class="shrink-0 lg:shrink lg:w-72 lg:min-w-[220px] lg:max-w-[360px] h-48 lg:h-auto overflow-y-auto overscroll-contain border-b lg:border-b-0 lg:border-r border-ink-800 px-1 py-1"></div>
101
+ <div class="flex-1 min-h-0 flex flex-col">
102
+ <div class="shrink-0 flex items-center gap-2 px-4 py-2 border-b border-ink-800/60">
103
+ <i data-lucide="eye" class="w-3.5 h-3.5 text-ink-500"></i>
104
+ <span id="viewer-title" class="text-xs font-mono text-ink-400 truncate">Select a file</span>
105
+ <button id="viewer-refresh-btn" type="button" class="ml-auto p-1 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors hidden" title="Refresh file">
106
+ <i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i>
107
+ </button>
108
+ </div>
109
+ <div id="viewer" class="flex-1 overflow-y-auto overscroll-contain p-4">
110
+ <div class="flex flex-col items-center justify-center h-full text-ink-600">
111
+ <i data-lucide="file-search" class="w-10 h-10 mb-2 opacity-30"></i>
112
+ <p class="text-sm">Select a file to preview</p>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </section>
118
+
119
+ <!-- Tab: Screenshots -->
120
+ <section id="panel-screenshots" class="tab-panel absolute inset-0 flex flex-col hidden">
121
+ <div class="shrink-0 bg-ink-900/60 border-b border-ink-800 px-4 py-2.5 flex items-center gap-2">
122
+ <span class="text-xs text-ink-500 font-mono">.playwright-mcp/</span>
123
+ <div class="flex-1"></div>
124
+ <button id="screenshots-refresh-btn" type="button" class="p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Refresh">
125
+ <i data-lucide="refresh-cw" class="w-4 h-4"></i>
126
+ </button>
127
+ </div>
128
+ <div id="screenshots-status" class="shrink-0 px-4 py-1 text-[11px] text-ink-500 font-mono min-h-[1.4em]"></div>
129
+ <div id="screenshots-grid" class="flex-1 overflow-y-auto overscroll-contain p-3 grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-3 content-start"></div>
130
+ </section>
131
+
132
+ <!-- Lightbox overlay -->
133
+ <div id="lightbox" class="hidden absolute inset-0 z-50 bg-ink-950/90">
134
+ <!-- Modal panel -->
135
+ <div id="lightbox-panel" class="absolute inset-6 bg-ink-900 rounded-xl shadow-2xl flex flex-col overflow-hidden">
136
+ <div class="shrink-0 flex items-center justify-end px-3 pt-3">
137
+ <button id="lightbox-close-btn" type="button"
138
+ class="p-1.5 text-ink-400 hover:text-ink-200 hover:bg-ink-800 rounded-lg transition-colors">
139
+ <i data-lucide="x" class="w-5 h-5"></i>
140
+ </button>
141
+ </div>
142
+ <div id="lightbox-content" class="flex-1 min-h-0 flex items-center justify-center p-4 pt-0">
143
+ <img id="lightbox-img" class="hidden max-w-full max-h-full object-contain rounded-lg" />
144
+ <div id="lightbox-svg-container" class="hidden w-full h-full"></div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+
149
+ </div>
150
+
151
+ <!-- Bottom tab bar -->
152
+ <nav class="shrink-0 bg-ink-900 border-t border-ink-800 flex z-30 safe-bottom">
153
+ <button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="clipboard">
154
+ <i data-lucide="clipboard" class="w-5 h-5"></i>
155
+ <span class="text-[10px] font-semibold uppercase tracking-wide">Clipboard</span>
156
+ <span id="tab-badge-clipboard" class="text-[9px] font-mono text-ink-600"></span>
157
+ </button>
158
+ <button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="files">
159
+ <i data-lucide="folder-tree" class="w-5 h-5"></i>
160
+ <span class="text-[10px] font-semibold uppercase tracking-wide">Files</span>
161
+ <span id="tab-badge-files" class="text-[9px] font-mono text-ink-600"></span>
162
+ </button>
163
+ <button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="screenshots">
164
+ <i data-lucide="camera" class="w-5 h-5"></i>
165
+ <span class="text-[10px] font-semibold uppercase tracking-wide">Screenshots</span>
166
+ <span id="tab-badge-screenshots" class="text-[9px] font-mono text-ink-600"></span>
167
+ </button>
168
+ </nav>
169
+
170
+ <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
171
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
172
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
173
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/typescript.min.js"></script>
174
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
175
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/rust.min.js"></script>
176
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
177
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/yaml.min.js"></script>
178
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/sql.min.js"></script>
179
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/diff.min.js"></script>
180
+ <script src="https://cdn.jsdelivr.net/npm/markdown-it@14/dist/markdown-it.min.js"></script>
181
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
182
+ <script src="https://cdn.jsdelivr.net/npm/svg-pan-zoom@3.6.1/dist/svg-pan-zoom.min.js"></script>
183
+ <script src="/app.js"></script>
184
+ </body>
185
+ </html>
@@ -0,0 +1,140 @@
1
+ /* ---------------------------------------------------------------------------
2
+ CSS Variables — ink scale + brand
3
+ Dark theme (default): original ink scale
4
+ Light theme: flipped ink scale so existing Tailwind classes auto-adapt
5
+ --------------------------------------------------------------------------- */
6
+ :root {
7
+ --ink-50: #f8f8f7;
8
+ --ink-100: #f0efed;
9
+ --ink-200: #dddbd6;
10
+ --ink-300: #c4c1b9;
11
+ --ink-400: #a09d94;
12
+ --ink-500: #7c786e;
13
+ --ink-600: #5c5850;
14
+ --ink-700: #45423c;
15
+ --ink-800: #2d2b27;
16
+ --ink-900: #1a1917;
17
+ --ink-950: #0d0d0c;
18
+ --brand: #c45d2c;
19
+ --brand-light: #f9e5db;
20
+ --brand-dark: #9e4520;
21
+ }
22
+
23
+ [data-theme="light"] {
24
+ --ink-50: #0d0d0c;
25
+ --ink-100: #1a1917;
26
+ --ink-200: #2d2b27;
27
+ --ink-300: #45423c;
28
+ --ink-400: #5c5850;
29
+ --ink-500: #7c786e;
30
+ --ink-600: #a09d94;
31
+ --ink-700: #c4c1b9;
32
+ --ink-800: #dddbd6;
33
+ --ink-900: #f0efed;
34
+ --ink-950: #f8f8f7;
35
+ --brand: #c45d2c;
36
+ --brand-light: rgba(196, 93, 44, 0.08);
37
+ --brand-dark: #9e4520;
38
+ }
39
+
40
+ /* Tree indentation — depth set via inline style */
41
+ .tree-item {
42
+ padding-left: calc(var(--depth, 0) * 16px);
43
+ }
44
+
45
+ /* Active tab styling */
46
+ .tab-btn.active {
47
+ color: var(--brand);
48
+ }
49
+ .tab-btn.active i,
50
+ .tab-btn.active span {
51
+ color: inherit;
52
+ }
53
+
54
+ /* Safe area for bottom nav (iPhone notch) */
55
+ .safe-bottom {
56
+ padding-bottom: env(safe-area-inset-bottom, 0);
57
+ }
58
+
59
+ /* Markdown prose */
60
+ .markdown-body {
61
+ line-height: 1.65;
62
+ font-size: 0.925rem;
63
+ color: var(--ink-300);
64
+ }
65
+ .markdown-body h1, .markdown-body h2, .markdown-body h3,
66
+ .markdown-body h4, .markdown-body h5, .markdown-body h6 {
67
+ margin-top: 1.4em;
68
+ margin-bottom: 0.5em;
69
+ font-weight: 700;
70
+ line-height: 1.3;
71
+ color: var(--ink-100);
72
+ }
73
+ .markdown-body h1 { font-size: 1.5em; }
74
+ .markdown-body h2 { font-size: 1.25em; }
75
+ .markdown-body h3 { font-size: 1.1em; }
76
+ .markdown-body p { margin: 0.6em 0; }
77
+ .markdown-body ul, .markdown-body ol { padding-left: 1.5em; margin: 0.5em 0; }
78
+ .markdown-body img { max-width: 100%; border-radius: 8px; }
79
+ .markdown-body blockquote {
80
+ margin: 0.6em 0;
81
+ padding: 0.4em 1em;
82
+ border-left: 3px solid var(--ink-700);
83
+ color: var(--ink-400);
84
+ }
85
+ .markdown-body a { color: var(--brand); text-decoration: underline; }
86
+ .markdown-body table { border-collapse: collapse; margin: 0.6em 0; width: 100%; }
87
+ .markdown-body th, .markdown-body td {
88
+ border: 1px solid var(--ink-700);
89
+ padding: 0.35em 0.7em;
90
+ text-align: left;
91
+ font-size: 0.875rem;
92
+ }
93
+ .markdown-body th { background: var(--ink-800); font-weight: 600; }
94
+
95
+ /* Code blocks (highlight.js + markdown) */
96
+ pre {
97
+ white-space: pre-wrap;
98
+ overflow-wrap: anywhere;
99
+ background: var(--ink-900);
100
+ border: 1px solid var(--ink-700);
101
+ border-radius: 8px;
102
+ padding: 12px;
103
+ font-size: 0.82rem;
104
+ line-height: 1.55;
105
+ }
106
+ code {
107
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
108
+ font-size: 0.85em;
109
+ }
110
+ :not(pre) > code {
111
+ background: var(--ink-800);
112
+ padding: 0.15em 0.35em;
113
+ border-radius: 4px;
114
+ color: var(--ink-200);
115
+ }
116
+
117
+ /* Override highlight.js theme for transparent bg */
118
+ .hljs {
119
+ background: transparent !important;
120
+ color: var(--ink-300) !important;
121
+ }
122
+
123
+ /* Scrollbar styling */
124
+ .overflow-y-auto::-webkit-scrollbar { width: 5px; }
125
+ .overflow-y-auto::-webkit-scrollbar-track { background: transparent; }
126
+ .overflow-y-auto::-webkit-scrollbar-thumb {
127
+ background: var(--ink-700);
128
+ border-radius: 3px;
129
+ }
130
+ .overflow-y-auto::-webkit-scrollbar-thumb:hover { background: var(--ink-600); }
131
+
132
+ /* Lightbox transition */
133
+ #lightbox {
134
+ transition: opacity 0.15s ease;
135
+ }
136
+
137
+ /* Mermaid diagram click hint */
138
+ .mermaid svg {
139
+ cursor: pointer;
140
+ }