glad-web 1.0.44 → 1.0.46
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/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/lib/claude/structured-session.js +10 -5
- package/lib/codex/image-store.js +1 -2
- package/lib/codex/structured-session.js +39 -76
- package/lib/commands/web.js +64 -9
- package/lib/config/manager.js +19 -0
- package/lib/server/routes/providers.js +0 -12
- package/lib/server/routes/skillhub.js +104 -0
- package/lib/session/file-attachment-store.js +168 -0
- package/lib/session/session-manager.js +143 -60
- package/lib/skillhub/client.js +121 -0
- package/lib/skillhub/settings-store.js +168 -0
- package/lib/skillhub/skill-installer.js +320 -0
- package/lib/web/bootstrap.js +34 -0
- package/lib/web/claude.js +44 -16
- package/lib/web/codex.js +51 -22
- package/lib/web/composer.js +293 -28
- package/lib/web/core.js +56 -38
- package/lib/web/git.js +53 -51
- package/lib/web/gitgraph.js +8 -8
- package/lib/web/index.html +61 -26
- package/lib/web/layout.js +4 -7
- package/lib/web/notifications.js +1 -0
- package/lib/web/session.js +7 -21
- package/lib/web/shell.js +17 -2
- package/lib/web/skillhub.js +197 -0
- package/lib/web/styles.css +138 -16
- package/lib/web/timed-inputs.js +6 -6
- package/package.json +6 -3
package/lib/web/shell.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
async function deleteSession(id, e) {
|
|
2
|
-
e
|
|
3
|
-
|
|
2
|
+
e?.stopPropagation();
|
|
3
|
+
if (!confirm('Terminate session?')) return;
|
|
4
|
+
const button = e?.currentTarget;
|
|
5
|
+
if (button) button.disabled = true;
|
|
6
|
+
try {
|
|
7
|
+
const response = await fetchWithTimeout('/api/sessions/' + encodeURIComponent(id), { method: 'DELETE' }, 10000);
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
const data = await response.json().catch(() => ({}));
|
|
10
|
+
throw new Error(data.error || `HTTP ${response.status}`);
|
|
11
|
+
}
|
|
12
|
+
if (id === activeSessionId) showLobby();
|
|
13
|
+
else await refreshSessionsNow();
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (button?.isConnected) button.disabled = false;
|
|
16
|
+
alert(`Failed to delete session: ${error.message}`);
|
|
17
|
+
}
|
|
4
18
|
}
|
|
5
19
|
|
|
6
20
|
function showLobby() {
|
|
@@ -10,6 +24,7 @@
|
|
|
10
24
|
activeSessionId = null;
|
|
11
25
|
window.activeSessionId = null;
|
|
12
26
|
activeToolKey = null;
|
|
27
|
+
if (typeof resetComposerSendState === 'function') resetComposerSendState();
|
|
13
28
|
document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
|
|
14
29
|
document.getElementById('lobby-view').classList.add('active');
|
|
15
30
|
refreshSessionsNow();
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
let skillHubSettings = null;
|
|
2
|
+
let skillHallSkills = [];
|
|
3
|
+
let skillHallQuery = '';
|
|
4
|
+
|
|
5
|
+
function applySkillHubAvailability(available) {
|
|
6
|
+
const button = document.getElementById('skill-hall-button');
|
|
7
|
+
if (!button) return;
|
|
8
|
+
button.disabled = !available;
|
|
9
|
+
button.title = available ? 'Skill Hall' : 'Skill暂不可用';
|
|
10
|
+
button.setAttribute('aria-label', button.title);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function refreshSkillHubAvailability() {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetchWithTimeout('/api/skillhub/status', {}, 5000);
|
|
16
|
+
const data = await response.json();
|
|
17
|
+
applySkillHubAvailability(Boolean(response.ok && data.available));
|
|
18
|
+
} catch (_) {
|
|
19
|
+
applySkillHubAvailability(false);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function setSkillHubStatus(message, type = '') {
|
|
24
|
+
const target = document.getElementById('skillhub-settings-status');
|
|
25
|
+
if (!target) return;
|
|
26
|
+
target.textContent = message;
|
|
27
|
+
target.className = `serverchan-settings-status${type ? ` ${type}` : ''}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function setSkillHubBusy(busy) {
|
|
31
|
+
for (const id of ['skillhub-save-btn', 'skillhub-test-btn', 'skillhub-remove-btn']) {
|
|
32
|
+
const button = document.getElementById(id);
|
|
33
|
+
if (button) button.disabled = busy;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function currentSkillHubForm() {
|
|
38
|
+
return {
|
|
39
|
+
baseUrl: document.getElementById('skillhub-base-url').value.trim(),
|
|
40
|
+
token: document.getElementById('skillhub-token').value.trim()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function loadSkillHubSettings() {
|
|
45
|
+
setSkillHubStatus('Loading configuration…');
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetchWithTimeout('/api/skillhub/settings', {}, 10000);
|
|
48
|
+
const data = await response.json();
|
|
49
|
+
if (!response.ok) throw new Error(data.error || 'Could not load SkillHub configuration');
|
|
50
|
+
skillHubSettings = data;
|
|
51
|
+
document.getElementById('skillhub-base-url').value = data.baseUrl || '';
|
|
52
|
+
const token = document.getElementById('skillhub-token');
|
|
53
|
+
token.value = '';
|
|
54
|
+
token.placeholder = data.configured ? data.maskedToken : 'clh_...';
|
|
55
|
+
document.getElementById('skillhub-token-hint').textContent = data.configured
|
|
56
|
+
? `Saved: ${data.maskedToken}. Leave blank to keep the current Token.`
|
|
57
|
+
: 'The Token is encrypted on this Glad host.';
|
|
58
|
+
document.getElementById('skillhub-remove-btn').style.display = data.configured ? 'inline-flex' : 'none';
|
|
59
|
+
setSkillHubStatus(data.configured ? 'Configuration saved.' : 'SkillHub is not configured.');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
setSkillHubStatus(error.message || 'Could not load SkillHub configuration', 'error');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function saveSkillHubSettings() {
|
|
66
|
+
setSkillHubBusy(true);
|
|
67
|
+
setSkillHubStatus('Testing and saving…');
|
|
68
|
+
try {
|
|
69
|
+
const response = await fetchWithTimeout('/api/skillhub/settings', {
|
|
70
|
+
method: 'PUT',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify(currentSkillHubForm())
|
|
73
|
+
}, 20000);
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
if (!response.ok) throw new Error(data.error || 'Could not save SkillHub configuration');
|
|
76
|
+
skillHubSettings = data.settings;
|
|
77
|
+
const token = document.getElementById('skillhub-token');
|
|
78
|
+
token.value = '';
|
|
79
|
+
token.placeholder = data.settings.maskedToken;
|
|
80
|
+
document.getElementById('skillhub-token-hint').textContent =
|
|
81
|
+
`Saved: ${data.settings.maskedToken}. Leave blank to keep the current Token.`;
|
|
82
|
+
document.getElementById('skillhub-remove-btn').style.display = 'inline-flex';
|
|
83
|
+
const handle = data.user?.handle || data.user?.data?.handle || '';
|
|
84
|
+
setSkillHubStatus(`Connected${handle ? ` as ${handle}` : ''}.`, 'success');
|
|
85
|
+
} catch (error) {
|
|
86
|
+
setSkillHubStatus(error.message || 'Could not save SkillHub configuration', 'error');
|
|
87
|
+
} finally {
|
|
88
|
+
setSkillHubBusy(false);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function testSkillHubSettings() {
|
|
93
|
+
setSkillHubBusy(true);
|
|
94
|
+
setSkillHubStatus('Testing connection…');
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetchWithTimeout('/api/skillhub/settings/test', {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: { 'Content-Type': 'application/json' },
|
|
99
|
+
body: JSON.stringify(currentSkillHubForm())
|
|
100
|
+
}, 20000);
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
if (!response.ok) throw new Error(data.error || 'SkillHub connection failed');
|
|
103
|
+
const handle = data.user?.handle || data.user?.data?.handle || '';
|
|
104
|
+
setSkillHubStatus(`Connection successful${handle ? ` · ${handle}` : ''}.`, 'success');
|
|
105
|
+
} catch (error) {
|
|
106
|
+
setSkillHubStatus(error.message || 'SkillHub connection failed', 'error');
|
|
107
|
+
} finally {
|
|
108
|
+
setSkillHubBusy(false);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function removeSkillHubSettings() {
|
|
113
|
+
if (!confirm('Remove the SkillHub connection?')) return;
|
|
114
|
+
setSkillHubBusy(true);
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetchWithTimeout('/api/skillhub/settings', { method: 'DELETE' }, 10000);
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
if (!response.ok) throw new Error(data.error || 'Could not remove SkillHub configuration');
|
|
119
|
+
skillHubSettings = data.settings;
|
|
120
|
+
document.getElementById('skillhub-base-url').value = '';
|
|
121
|
+
document.getElementById('skillhub-token').value = '';
|
|
122
|
+
document.getElementById('skillhub-token').placeholder = 'clh_...';
|
|
123
|
+
document.getElementById('skillhub-token-hint').textContent = 'The Token is encrypted on this Glad host.';
|
|
124
|
+
document.getElementById('skillhub-remove-btn').style.display = 'none';
|
|
125
|
+
setSkillHubStatus('SkillHub configuration removed.', 'success');
|
|
126
|
+
} catch (error) {
|
|
127
|
+
setSkillHubStatus(error.message || 'Could not remove SkillHub configuration', 'error');
|
|
128
|
+
} finally {
|
|
129
|
+
setSkillHubBusy(false);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function skillHallCard(skill, index) {
|
|
134
|
+
const name = String(skill.displayName || skill.name || skill.slug || 'Unnamed Skill');
|
|
135
|
+
const description = String(skill.description || '');
|
|
136
|
+
const meta = [skill.kind, skill.version].filter(Boolean).join(' · ');
|
|
137
|
+
return `<button type="button" class="skill-hall-card" onclick="selectSkillHallSkill(${index})"><span class="skill-hall-card-name">${escapeHtml(name)}</span>${description ? `<span class="skill-hall-card-description">${escapeHtml(description)}</span>` : ''}<span class="skill-hall-card-meta">${escapeHtml(meta)}</span></button>`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function renderSkillHall() {
|
|
141
|
+
const grid = document.getElementById('skill-hall-grid');
|
|
142
|
+
const status = document.getElementById('skill-hall-status');
|
|
143
|
+
if (!grid || !status) return;
|
|
144
|
+
const query = skillHallQuery.trim().toLocaleLowerCase();
|
|
145
|
+
const matches = skillHallSkills.map((skill, index) => ({ skill, index })).filter(({ skill }) => {
|
|
146
|
+
if (!query) return true;
|
|
147
|
+
return [skill.displayName, skill.name, skill.slug, skill.description, skill.kind, skill.version]
|
|
148
|
+
.some(value => String(value || '').toLocaleLowerCase().includes(query));
|
|
149
|
+
});
|
|
150
|
+
status.textContent = matches.length ? `${matches.length} Skill${matches.length === 1 ? '' : 's'}`
|
|
151
|
+
: (query ? 'No matching Skills.' : 'No Skills are available for this account.');
|
|
152
|
+
grid.innerHTML = matches.map(({ skill, index }) => skillHallCard(skill, index)).join('');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function openSkillHall(event = null) {
|
|
156
|
+
event?.stopPropagation();
|
|
157
|
+
if (document.getElementById('skill-hall-button')?.disabled) {
|
|
158
|
+
showAppToast('Skill暂不可用');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
document.getElementById('skill-hall-overlay').style.display = 'flex';
|
|
162
|
+
document.getElementById('skill-hall-search').value = '';
|
|
163
|
+
document.getElementById('skill-hall-status').textContent = 'Loading Skills…';
|
|
164
|
+
document.getElementById('skill-hall-grid').innerHTML = '';
|
|
165
|
+
skillHallQuery = '';
|
|
166
|
+
try {
|
|
167
|
+
const response = await fetchWithTimeout('/api/skillhub/skills', {}, 30000);
|
|
168
|
+
const data = await response.json();
|
|
169
|
+
if (!response.ok || !data.success) throw new Error(data.error || 'Could not load Skills');
|
|
170
|
+
skillHallSkills = Array.isArray(data.skills) ? data.skills : [];
|
|
171
|
+
renderSkillHall();
|
|
172
|
+
requestAnimationFrame(() => document.getElementById('skill-hall-search')?.focus());
|
|
173
|
+
} catch (error) {
|
|
174
|
+
skillHallSkills = [];
|
|
175
|
+
document.getElementById('skill-hall-status').textContent = error.message || 'Could not load Skills';
|
|
176
|
+
if (error.message === 'Skill暂不可用') applySkillHubAvailability(false);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function closeSkillHall(event = null) {
|
|
181
|
+
if (event && event.target.id !== 'skill-hall-overlay') return;
|
|
182
|
+
document.getElementById('skill-hall-overlay').style.display = 'none';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function filterSkillHall(value) {
|
|
186
|
+
skillHallQuery = String(value || '');
|
|
187
|
+
renderSkillHall();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function selectSkillHallSkill(index) {
|
|
191
|
+
const skill = skillHallSkills[index];
|
|
192
|
+
if (!skill) return;
|
|
193
|
+
closeSkillHall();
|
|
194
|
+
showToolModal(skill);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void refreshSkillHubAvailability();
|
package/lib/web/styles.css
CHANGED
|
@@ -4,17 +4,20 @@
|
|
|
4
4
|
.view.active { display: flex; }
|
|
5
5
|
#lobby { overflow-y: auto; padding: 20px; padding-top: env(safe-area-inset-top); box-sizing: border-box; }
|
|
6
6
|
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
|
|
7
|
-
.header
|
|
8
|
-
.
|
|
9
|
-
.
|
|
7
|
+
.header-actions { display: flex; align-items: center; gap: 5px; margin-left: auto; }
|
|
8
|
+
.skill-hall-entry-btn { height: 36px; padding: 0 11px; border: 1px solid rgba(0,122,255,.38); border-radius: 10px; background: rgba(0,122,255,.12); color: var(--primary); display: inline-flex; align-items: center; justify-content: center; gap: 5px; font-size: 13px; font-weight: 800; cursor: pointer; flex-shrink: 0; }
|
|
9
|
+
.skill-hall-entry-btn:active { background: rgba(0,122,255,.22); transform: scale(.97); }
|
|
10
|
+
.skill-hall-entry-btn:disabled { border-color: rgba(142,142,147,.25); background: rgba(142,142,147,.1); color: var(--text-dim); cursor: not-allowed; transform: none; }
|
|
10
11
|
.header-action-btn { height: 36px; min-width: 36px; padding: 0 10px; border: 0; border-radius: 10px; background: var(--primary); color: #fff; display: inline-flex; align-items: center; justify-content: center; gap: 3px; font-size: 13px; font-weight: 750; line-height: 1; white-space: nowrap; cursor: pointer; flex-shrink: 0; }
|
|
11
12
|
.header-action-btn.icon-only { width: 36px; padding: 0; }
|
|
12
13
|
.header-action-btn:active { background: #0062cc; transform: scale(.97); }
|
|
13
14
|
.btn-retry { background: #333; color: #fff; border: none; padding: 8px 16px; border-radius: 20px; margin-top: 10px; cursor: pointer; }
|
|
14
15
|
.session-card { background: var(--card-bg); border-radius: 12px; padding: 12px 16px 8px; margin-bottom: 12px; display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; row-gap: 0; align-items: center; position: relative; }
|
|
16
|
+
.active-session-dot { display: none; }
|
|
15
17
|
.completion-dot { width: 9px; height: 9px; border-radius: 50%; background: #ff3b30; flex-shrink: 0; }
|
|
16
18
|
.session-info { flex: 1; min-width: 0; }
|
|
17
|
-
.session-info h3 { margin: 0 0 4px 0; font-size: 17px; display: flex; align-items: center; gap: 8px; }
|
|
19
|
+
.session-info h3 { min-width: 0; margin: 0 0 4px 0; font-size: 17px; display: flex; align-items: center; gap: 8px; }
|
|
20
|
+
.session-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
18
21
|
.session-info p { margin: 0; font-size: 13px; color: var(--text-dim); }
|
|
19
22
|
.timer-count-badge { display: inline-flex; align-items: center; gap: 3px; color: #fff; background: rgba(0,122,255,0.22); border: 1px solid rgba(0,122,255,0.34); border-radius: 999px; padding: 2px 7px; font-size: 11px; font-weight: 800; flex-shrink: 0; }
|
|
20
23
|
.session-dir-row { grid-column: 1 / -1; display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0; }
|
|
@@ -37,7 +40,7 @@
|
|
|
37
40
|
#modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.8); z-index: 10000; display: none; align-items: center; justify-content: center; padding: 20px; }
|
|
38
41
|
#tool-modal { background: var(--card-bg); width: 100%; max-width: 400px; border-radius: 16px; padding: 20px; box-shadow: 0 20px 40px rgba(0,0,0,0.4); }
|
|
39
42
|
#settings-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.8); z-index: 10020; display: none; align-items: center; justify-content: center; padding: 20px; box-sizing: border-box; }
|
|
40
|
-
#settings-modal { background: var(--card-bg); width: 100%; max-width: 450px; border-radius: 16px; padding: 20px; box-shadow: 0 20px 40px rgba(0,0,0,0.4); box-sizing: border-box; }
|
|
43
|
+
#settings-modal { background: var(--card-bg); width: 100%; max-width: 450px; max-height: calc(100vh - 40px); overflow-y: auto; border-radius: 16px; padding: 20px; box-shadow: 0 20px 40px rgba(0,0,0,0.4); box-sizing: border-box; }
|
|
41
44
|
.settings-modal-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 20px; }
|
|
42
45
|
.settings-modal-header h2 { margin: 0; font-size: 20px; }
|
|
43
46
|
.settings-modal-header p { margin: 5px 0 0; color: var(--text-dim); font-size: 12px; line-height: 1.45; }
|
|
@@ -58,6 +61,22 @@
|
|
|
58
61
|
.serverchan-modal-actions { display: flex; align-items: center; gap: 8px; }
|
|
59
62
|
.serverchan-action-spacer { flex: 1; }
|
|
60
63
|
#serverchan-remove-btn { display: none; }
|
|
64
|
+
#skillhub-remove-btn { display: none; }
|
|
65
|
+
.tool-modal-skill { min-height: 16px; margin: 4px 0 0; color: var(--text-dim); font-size: 12px; }
|
|
66
|
+
#skill-hall-overlay { position: fixed; inset: 0; z-index: 10010; display: none; align-items: center; justify-content: center; padding: 18px; box-sizing: border-box; background: rgba(0,0,0,0.8); }
|
|
67
|
+
#skill-hall-modal { display: flex; flex-direction: column; width: min(820px, 100%); max-height: min(760px, calc(100vh - 36px)); padding: 20px; box-sizing: border-box; border-radius: 16px; background: var(--card-bg); box-shadow: 0 20px 50px rgba(0,0,0,0.45); }
|
|
68
|
+
.skill-hall-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
69
|
+
.skill-hall-header h2 { margin: 0; font-size: 21px; }
|
|
70
|
+
.skill-hall-header p { margin: 5px 0 0; color: var(--text-dim); font-size: 12px; }
|
|
71
|
+
.skill-hall-search { width: 100%; min-height: 42px; margin-top: 16px; padding: 9px 11px; box-sizing: border-box; border: 1px solid rgba(255,255,255,0.12); border-radius: 9px; background: rgba(255,255,255,0.08); color: var(--text); font-size: 14px; outline: none; }
|
|
72
|
+
.skill-hall-search:focus { border-color: rgba(0,122,255,0.65); }
|
|
73
|
+
.skill-hall-status { min-height: 20px; padding: 10px 1px 7px; color: var(--text-dim); font-size: 12px; }
|
|
74
|
+
.skill-hall-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; overflow-y: auto; padding: 1px; }
|
|
75
|
+
.skill-hall-card { display: flex; min-height: 126px; flex-direction: column; align-items: stretch; gap: 8px; padding: 14px; border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; background: rgba(255,255,255,0.045); color: var(--text); text-align: left; cursor: pointer; }
|
|
76
|
+
.skill-hall-card:hover { border-color: rgba(0,122,255,0.55); background: rgba(0,122,255,0.09); }
|
|
77
|
+
.skill-hall-card-name { font-size: 15px; font-weight: 700; overflow-wrap: anywhere; }
|
|
78
|
+
.skill-hall-card-description { display: -webkit-box; overflow: hidden; color: var(--text-dim); font-size: 12px; line-height: 1.45; -webkit-box-orient: vertical; -webkit-line-clamp: 3; }
|
|
79
|
+
.skill-hall-card-meta { margin-top: auto; color: var(--primary); font-size: 11px; }
|
|
61
80
|
#app-toast { position: fixed; left: 50%; bottom: max(24px, env(safe-area-inset-bottom)); z-index: 10100; max-width: calc(100vw - 32px); transform: translate(-50%, 18px); opacity: 0; pointer-events: none; padding: 9px 14px; border-radius: 999px; background: rgba(44,44,46,0.96); border: 1px solid rgba(255,255,255,0.12); color: #fff; font-size: 13px; box-shadow: 0 10px 28px rgba(0,0,0,0.35); transition: opacity .18s ease, transform .18s ease; }
|
|
62
81
|
#app-toast.visible { opacity: 1; transform: translate(-50%, 0); }
|
|
63
82
|
.tool-item { padding: 12px; border-bottom: 1px solid #333; cursor: pointer; display: flex; align-items: center; border-radius: 8px; margin-top: 4px; }
|
|
@@ -143,13 +162,16 @@
|
|
|
143
162
|
#cmd-input::placeholder { color: rgba(255,255,255,0.45); }
|
|
144
163
|
#cmd-input:focus { background: rgba(255,255,255,0.1); border-color: rgba(0,122,255,0.42); color: #fff; }
|
|
145
164
|
#send-btn { width: 44px; height: 38px; margin-left: 10px; background: #007aff; border: none; border-radius: 19px; color: #fff; display: flex; align-items: center; justify-content: center; flex-shrink: 0; cursor: pointer; }
|
|
165
|
+
#send-btn:disabled { background: color-mix(in srgb, var(--text-dim) 34%, var(--surface)); color: var(--text-dim); opacity: .72; cursor: not-allowed; }
|
|
146
166
|
#attachment-strip { display: none; width: min(calc(100% - 28px), var(--control-content-max)); margin: -3px auto 2px auto; gap: 7px; overflow-x: auto; padding: 0 0 4px 0; box-sizing: border-box; scrollbar-width: none; }
|
|
147
167
|
#attachment-strip.active { display: flex; }
|
|
148
168
|
#attachment-strip::-webkit-scrollbar { display: none; }
|
|
149
169
|
.attachment-chip { min-width: 0; max-width: 210px; display: flex; align-items: center; gap: 7px; padding: 7px 9px; border: 1px solid rgba(0,122,255,0.45); border-radius: 10px; background: rgba(0,122,255,0.14); color: #e9f2ff; font-size: 12px; }
|
|
150
170
|
.attachment-chip.uploading { border-color: rgba(255,159,10,0.55); background: rgba(255,159,10,0.12); }
|
|
171
|
+
.attachment-chip.file { border-color: var(--line); background: var(--surface-soft); color: var(--text); }
|
|
151
172
|
.attachment-chip-content { min-width: 0; flex: 1; }
|
|
152
173
|
.attachment-chip-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
174
|
+
.attachment-chip-icon { width: 17px; height: 17px; flex: 0 0 17px; }
|
|
153
175
|
.attachment-progress { display: block; height: 5px; margin-top: 5px; overflow: hidden; border-radius: 999px; background: rgba(255,255,255,0.16); }
|
|
154
176
|
.attachment-progress > span { display: block; height: 100%; border-radius: inherit; background: #ff9f0a; transition: width .15s ease; }
|
|
155
177
|
.attachment-progress.estimated > span { background: repeating-linear-gradient(90deg, #ff9f0a 0 12px, #ffd37b 12px 24px); background-size: 48px 100%; animation: attachment-upload-pulse .75s linear infinite; }
|
|
@@ -185,7 +207,7 @@
|
|
|
185
207
|
.codex-conversation { width: min(100%, var(--chat-content-max)); margin: 0 auto; }
|
|
186
208
|
.codex-working-indicator, .claude-working-indicator { position: sticky; top: 0; z-index: 4; width: 28px; height: 28px; margin: 0 0 -28px auto; border: 1px solid rgba(255,255,255,.1); border-radius: 50%; background: rgba(28,28,30,.68); box-shadow: 0 5px 16px rgba(0,0,0,.24); backdrop-filter: blur(8px); pointer-events: none; }
|
|
187
209
|
.codex-working-indicator::after, .claude-working-indicator::after { content: ''; position: absolute; inset: 8px; border: 1.5px solid rgba(255,255,255,.7); border-top-color: transparent; border-radius: 50%; animation: codex-spin .8s linear infinite; }
|
|
188
|
-
.codex-skill-bubble { position:
|
|
210
|
+
.codex-skill-bubble { position: relative; z-index: 5; display: flex; width: max-content; max-width: min(280px, 72vw); min-height: 28px; padding: 0 4px 0 10px; align-items: center; gap: 7px; border: 1px solid rgba(0,122,255,.42); border-bottom: 0; border-radius: 12px 12px 0 0; background: rgba(21,47,78,.96); color: #eaf3ff; box-shadow: 0 -3px 12px rgba(0,0,0,.12); font-size: 11px; font-weight: 750; }
|
|
189
211
|
.codex-skill-bubble-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
190
212
|
.codex-skill-bubble-close { width: 23px; height: 23px; padding: 0; border: 0; border-radius: 50%; background: rgba(255,255,255,.1); color: #fff; cursor: pointer; font-size: 16px; line-height: 1; }
|
|
191
213
|
.codex-message-block { max-width: 100%; margin: 0 0 12px; }
|
|
@@ -323,9 +345,12 @@
|
|
|
323
345
|
.claude-message-block.user > .claude-message { max-width: 100%; }
|
|
324
346
|
.claude-message-time { display: block; width: max-content; margin-top: 4px; padding: 0 2px; color: #8e8e93; font-size: 10px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; }
|
|
325
347
|
.claude-message-block.user .claude-message-time { margin-left: auto; }
|
|
326
|
-
.codex-message-
|
|
348
|
+
.codex-message-skills { position: relative; z-index: 1; display: flex; justify-content: flex-start; gap: 5px; margin-bottom: -1px; }
|
|
349
|
+
.codex-message-skill { display: inline-flex; max-width: min(220px, 58vw); min-height: 18px; align-items: center; padding: 2px 8px; border: 1px solid rgba(0,122,255,.32); border-bottom: 0; border-radius: 9px 9px 0 0; background: rgba(0,122,255,.16); color: #8fc5ff; font-size: 9px; font-weight: 750; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
350
|
+
.codex-message-skills + .codex-message.user { border-top-left-radius: 4px; }
|
|
327
351
|
.claude-message-attachments { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
|
|
328
352
|
.claude-message-attachment { max-width: 100%; border: 1px solid rgba(255,255,255,.14); border-radius: 999px; padding: 3px 7px; color: #d1d5db; background: rgba(255,255,255,.07); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
353
|
+
.message-attachment-icon { width: 13px; height: 13px; flex: 0 0 13px; margin-right: 4px; vertical-align: -2px; }
|
|
329
354
|
.claude-message.user { margin-left: auto; background: rgba(0,122,255,0.24); border: 1px solid rgba(0,122,255,0.32); color: #fff; border-radius: 12px; padding-top: 7px; padding-bottom: 7px; }
|
|
330
355
|
.claude-message.assistant { max-width: 100%; background: transparent; border: 0; color: #f5f5f7; padding: 0 4px; margin: 0 0 12px 0; }
|
|
331
356
|
.claude-message.event { max-width: 100%; background: transparent; border: 0; color: var(--text-dim); font-size: 12px; padding: 3px 2px; text-align: center; }
|
|
@@ -449,6 +474,9 @@
|
|
|
449
474
|
.history-meta { color: var(--text-dim); font-size: 11px; padding: 8px 14px; border-bottom: 1px solid rgba(255,255,255,0.06); background: #0d0d0d; }
|
|
450
475
|
|
|
451
476
|
.tab-bar { display: flex; border-bottom: 1px solid rgba(255,255,255,0.1); background: var(--bg); }
|
|
477
|
+
.subview-nav { flex: 0 0 auto; padding-top: env(safe-area-inset-top); border-bottom: 1px solid var(--line); background: var(--surface); }
|
|
478
|
+
.subview-nav-row { display: flex; align-items: center; padding: 8px 14px; }
|
|
479
|
+
.subview-nav-title { flex: 1; min-width: 0; color: var(--text); text-align: center; font-size: 16px; font-weight: 600; }
|
|
452
480
|
.tab-btn { flex: 1; text-align: center; padding: 12px 0; font-size: 14px; font-weight: 600; color: var(--text-dim); background: none; border: none; cursor: pointer; position: relative; }
|
|
453
481
|
.tab-btn.active { color: var(--text); }
|
|
454
482
|
.tab-btn.active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); height: 2px; width: 40px; background: var(--primary); border-radius: 2px; }
|
|
@@ -520,9 +548,8 @@
|
|
|
520
548
|
.usage-summary-card .value { font-size: 21px; }
|
|
521
549
|
}
|
|
522
550
|
@media (max-width: 430px) {
|
|
523
|
-
#nav-bar > div:last-child .icon-btn
|
|
524
|
-
#nav-bar > div:last-child .icon-btn
|
|
525
|
-
#codex-terminal-switch { padding-left: 8px !important; padding-right: 8px !important; }
|
|
551
|
+
#nav-bar > div:last-child .icon-btn { width: 34px; font-size: 0 !important; gap: 0 !important; }
|
|
552
|
+
#nav-bar > div:last-child .icon-btn svg { width: 16px; height: 16px; }
|
|
526
553
|
}
|
|
527
554
|
@media (min-width: 768px) and (max-width: 1199px) {
|
|
528
555
|
:root { --chat-content-max: 780px; --control-content-max: 920px; }
|
|
@@ -546,6 +573,15 @@
|
|
|
546
573
|
--input-fg: #ffffff;
|
|
547
574
|
--input-placeholder: rgba(255,255,255,.45);
|
|
548
575
|
--overlay-bg: rgba(0,0,0,.80);
|
|
576
|
+
--git-diff-bg: #0d0d0d;
|
|
577
|
+
--git-diff-text: #d1d5db;
|
|
578
|
+
--git-add-text: #4ade80;
|
|
579
|
+
--git-add-bg: rgba(74,222,128,.1);
|
|
580
|
+
--git-del-text: #f87171;
|
|
581
|
+
--git-del-bg: rgba(248,113,113,.1);
|
|
582
|
+
--git-hunk-text: #60a5fa;
|
|
583
|
+
--git-hunk-bg: rgba(96,165,250,.1);
|
|
584
|
+
--git-modified-text: #fbbf24;
|
|
549
585
|
color-scheme: dark;
|
|
550
586
|
}
|
|
551
587
|
|
|
@@ -563,6 +599,15 @@ html[data-theme="light"] {
|
|
|
563
599
|
--input-fg: #172033;
|
|
564
600
|
--input-placeholder: #8a94a6;
|
|
565
601
|
--overlay-bg: rgba(15,23,42,.45);
|
|
602
|
+
--git-diff-bg: #f7f8fa;
|
|
603
|
+
--git-diff-text: #344054;
|
|
604
|
+
--git-add-text: #176b3a;
|
|
605
|
+
--git-add-bg: #dff4e7;
|
|
606
|
+
--git-del-text: #a12b24;
|
|
607
|
+
--git-del-bg: #fde5e3;
|
|
608
|
+
--git-hunk-text: #075fae;
|
|
609
|
+
--git-hunk-bg: #e6f2ff;
|
|
610
|
+
--git-modified-text: #9a6700;
|
|
566
611
|
color-scheme: light;
|
|
567
612
|
}
|
|
568
613
|
|
|
@@ -581,13 +626,31 @@ html[data-theme="dark"] { color-scheme: dark; }
|
|
|
581
626
|
#detail-empty p { max-width: 360px; margin: 8px 0 0; font-size: 13px; line-height: 1.5; }
|
|
582
627
|
#sidebar-resizer { display: none; }
|
|
583
628
|
|
|
584
|
-
#terminal-view.active { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
|
|
629
|
+
#terminal-view.active { display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto; }
|
|
585
630
|
#top-ui { display: contents; }
|
|
586
631
|
#nav-bar { grid-row: 1; z-index: 20; padding-top: max(8px, env(safe-area-inset-top)); background: var(--surface); border-color: var(--line); }
|
|
587
|
-
#
|
|
632
|
+
#session-status-strip { display: none; grid-row: 2; z-index: 19; padding: 6px 12px; border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--surface) 97%, transparent); }
|
|
633
|
+
#session-attention-rail { display: flex; width: min(100%, var(--chat-content-max)); min-width: 0; margin: 0 auto; gap: 7px; overflow-x: auto; scrollbar-width: none; white-space: nowrap; }
|
|
634
|
+
#session-attention-rail::-webkit-scrollbar { display: none; }
|
|
635
|
+
.session-attention-pill { display: inline-flex; min-height: 28px; flex: 0 0 auto; align-items: center; gap: 5px; padding: 0 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface-soft); color: var(--text-dim); font-size: 11px; font-weight: 750; cursor: pointer; }
|
|
636
|
+
.session-attention-pill.approval { border-color: rgba(255,204,0,.42); background: rgba(255,204,0,.10); color: #ffd60a; }
|
|
637
|
+
.session-attention-pill.subagent { border-color: rgba(100,210,255,.35); background: rgba(100,210,255,.10); color: #64d2ff; }
|
|
638
|
+
.session-attention-pill:active { transform: translateY(1px); }
|
|
639
|
+
html[data-theme="light"] .session-attention-pill.approval { border-color: #e5bd36; background: #fff7d6; color: #795500; }
|
|
640
|
+
html[data-theme="light"] .session-attention-pill.subagent { border-color: #99c8f7; background: #e8f3ff; color: #075fae; }
|
|
641
|
+
#terminal-controls { position: relative; inset: auto; grid-row: 4; z-index: 30; max-height: min(62dvh, 620px); overflow-y: auto; padding-bottom: env(safe-area-inset-bottom); border-top: 1px solid var(--line); border-bottom: 0; background: color-mix(in srgb, var(--surface) 96%, transparent); box-shadow: 0 -10px 28px rgba(0,0,0,.12); }
|
|
588
642
|
#terminal-controls-spacer { display: none; }
|
|
589
|
-
#terminal-container, #claude-chat-container, #codex-chat-container { grid-row:
|
|
643
|
+
#terminal-container, #claude-chat-container, #codex-chat-container { grid-row: 3; min-width: 0; min-height: 0; background: var(--chat-bg); }
|
|
644
|
+
#composer-skill-prefix { display: none; width: min(100%, var(--control-content-max)); margin: 0 auto; padding: 8px 14px 0; box-sizing: border-box; }
|
|
645
|
+
#composer-skill-prefix.active { display: flex; justify-content: flex-start; }
|
|
646
|
+
#composer-skill-prefix.active + #input-row { padding-top: 0; }
|
|
590
647
|
#input-row { padding-top: 10px; padding-bottom: 7px; }
|
|
648
|
+
@media (max-width: 480px) {
|
|
649
|
+
#composer-skill-prefix { padding-left: 10px; padding-right: 10px; }
|
|
650
|
+
}
|
|
651
|
+
@media (min-width: 768px) and (max-width: 1199px) {
|
|
652
|
+
#composer-skill-prefix { padding-left: 18px; padding-right: 18px; }
|
|
653
|
+
}
|
|
591
654
|
#cmd-input { width: 100%; min-height: 42px; border-color: var(--line); background: var(--input-bg); color: var(--input-fg); }
|
|
592
655
|
#cmd-input::placeholder { color: var(--input-placeholder); }
|
|
593
656
|
#cmd-input:focus { color: var(--input-fg); }
|
|
@@ -595,6 +658,8 @@ html[data-theme="dark"] { color-scheme: dark; }
|
|
|
595
658
|
.composer-action-btn { position: relative; width: 40px; min-width: 40px; height: 40px; flex: 0 0 40px; padding: 0; margin: 0; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); color: var(--text-dim); display: flex; align-items: center; justify-content: center; cursor: pointer; }
|
|
596
659
|
.composer-action-btn:hover { color: var(--text); }
|
|
597
660
|
.composer-action-btn.active { color: var(--primary); border-color: color-mix(in srgb, var(--primary) 48%, transparent); background: color-mix(in srgb, var(--primary) 14%, var(--surface)); }
|
|
661
|
+
#composer-action-tooltip { position: fixed; z-index: 11000; display: none; max-width: min(220px, calc(100vw - 24px)); padding: 6px 9px; border: 1px solid var(--line); border-radius: 7px; background: color-mix(in srgb, var(--surface-raised) 96%, transparent); color: var(--text); box-shadow: 0 6px 18px rgba(0,0,0,.18); font-size: 11px; font-weight: 700; line-height: 1.2; text-align: center; white-space: nowrap; pointer-events: none; }
|
|
662
|
+
#composer-action-tooltip.visible { display: block; }
|
|
598
663
|
#send-btn { right: max(12px, calc((100% - var(--control-content-max)) / 2 + 14px)); width: 44px; height: 40px; }
|
|
599
664
|
#claude-control-panel, #codex-control-panel { position: relative; flex-direction: column; width: min(100%, var(--control-content-max)); padding: 0 14px 10px; border: 0; background: transparent; }
|
|
600
665
|
.claude-control-rail, .codex-control-rail { order: 100; min-height: 40px; gap: 7px; margin: 0 58px 0 0; padding: 0; overflow-x: auto; overflow-y: hidden; scroll-snap-type: none; scroll-padding: 0; }
|
|
@@ -626,14 +691,16 @@ html[data-theme="dark"] { color-scheme: dark; }
|
|
|
626
691
|
#lobby-view { display: flex !important; width: min(var(--sidebar-w), calc(100vw - 484px)); flex: 0 0 min(var(--sidebar-w), calc(100vw - 484px)); border-right: 1px solid var(--line); background: var(--bg); }
|
|
627
692
|
#lobby { width: 100%; padding: 18px 14px; }
|
|
628
693
|
#lobby-view .header { margin-bottom: 18px; }
|
|
629
|
-
#lobby-view .header
|
|
630
|
-
#lobby-view .header-action-btn
|
|
631
|
-
#lobby-view .header-action-btn:not(.icon-only)
|
|
694
|
+
#lobby-view .header-actions { gap: 3px; }
|
|
695
|
+
#lobby-view .header-action-btn.icon-only { width: 34px; min-width: 34px; }
|
|
696
|
+
#lobby-view .header-action-btn:not(.icon-only) { width: auto; min-width: 0; padding: 0 8px; font-size: 13px; }
|
|
697
|
+
#lobby-view .header-action-btn:not(.icon-only) span:first-child { font-size: 18px; }
|
|
632
698
|
#sidebar-resizer { display: block; width: 4px; flex: 0 0 4px; cursor: col-resize; background: var(--line); touch-action: none; transition: background .15s; }
|
|
633
699
|
#sidebar-resizer:hover, #sidebar-resizer.dragging { background: var(--primary); }
|
|
634
700
|
#detail-pane:not(:has(.view.active)) #detail-empty { display: flex; }
|
|
635
701
|
#back-btn, .usage-nav-button { visibility: hidden; pointer-events: none; }
|
|
636
702
|
.session-card.selected { border: 1px solid color-mix(in srgb, var(--primary) 48%, transparent); background: color-mix(in srgb, var(--primary) 10%, var(--card-bg)); }
|
|
703
|
+
.session-card.selected .active-session-dot { position: absolute; top: 7px; right: 7px; display: block; width: 9px; height: 9px; border: 2px solid var(--card-bg); border-radius: 50%; background: #34c759; box-shadow: 0 0 0 1px rgba(52,199,89,.25); pointer-events: none; }
|
|
637
704
|
}
|
|
638
705
|
|
|
639
706
|
@media (max-width: 919px) {
|
|
@@ -658,6 +725,7 @@ html[data-theme="light"] .usage-panel,
|
|
|
658
725
|
html[data-theme="light"] .usage-summary-card,
|
|
659
726
|
html[data-theme="light"] #tool-modal,
|
|
660
727
|
html[data-theme="light"] #settings-modal,
|
|
728
|
+
html[data-theme="light"] #skill-hall-modal,
|
|
661
729
|
html[data-theme="light"] #usage-source-modal,
|
|
662
730
|
html[data-theme="light"] #schedule-modal,
|
|
663
731
|
html[data-theme="light"] #claude-picker-panel,
|
|
@@ -670,6 +738,7 @@ html[data-theme="light"] #codex-prompt-panel,
|
|
|
670
738
|
html[data-theme="light"] #codex-skill-panel { background: var(--card-bg) !important; border-color: var(--line) !important; color: var(--text) !important; }
|
|
671
739
|
html[data-theme="light"] #modal-overlay,
|
|
672
740
|
html[data-theme="light"] #settings-modal-overlay,
|
|
741
|
+
html[data-theme="light"] #skill-hall-overlay,
|
|
673
742
|
html[data-theme="light"] #usage-source-overlay { background: var(--overlay-bg); }
|
|
674
743
|
html[data-theme="light"] #claude-chat-container,
|
|
675
744
|
html[data-theme="light"] #codex-chat-container,
|
|
@@ -696,11 +765,14 @@ html[data-theme="light"] .composer-action-btn,
|
|
|
696
765
|
html[data-theme="light"] .key-btn,
|
|
697
766
|
html[data-theme="light"] .command-key,
|
|
698
767
|
html[data-theme="light"] .small-btn { border-color: var(--line); background: var(--surface-soft); color: var(--text); }
|
|
768
|
+
html[data-theme="light"] .skill-hall-card { border-color: var(--line); background: var(--surface-soft); color: var(--text); }
|
|
769
|
+
html[data-theme="light"] .skill-hall-entry-btn { border-color: rgba(0,122,255,.28); background: rgba(0,122,255,.08); }
|
|
699
770
|
html[data-theme="light"] .claude-ctrl-btn.primary { color: #065fbd; background: rgba(0,122,255,.11); }
|
|
700
771
|
html[data-theme="light"] .claude-ctrl-btn.danger,
|
|
701
772
|
html[data-theme="light"] .small-btn.danger { color: #d92d20; background: rgba(217,45,32,.09); }
|
|
702
773
|
html[data-theme="light"] #settings-modal input,
|
|
703
774
|
html[data-theme="light"] #settings-modal select,
|
|
775
|
+
html[data-theme="light"] .skill-hall-search,
|
|
704
776
|
html[data-theme="light"] .form-field input,
|
|
705
777
|
html[data-theme="light"] .form-field select,
|
|
706
778
|
html[data-theme="light"] .form-field textarea,
|
|
@@ -748,6 +820,9 @@ html[data-theme="light"] .codex-warning-title { color: #7a5200; }
|
|
|
748
820
|
html[data-theme="light"] .codex-warning-text { color: #725d28; }
|
|
749
821
|
html[data-theme="light"] .codex-compaction-card { border-color: #d9c4ef; background: #f7f0ff; color: #3f2a56; }
|
|
750
822
|
html[data-theme="light"] .codex-compaction-meta { color: #725d86; }
|
|
823
|
+
html[data-theme="light"] .codex-skill-bubble,
|
|
824
|
+
html[data-theme="light"] .codex-message-skill { border-color: #99c8f7; background: #e8f3ff; color: #075fae; }
|
|
825
|
+
html[data-theme="light"] .codex-skill-bubble-close { background: rgba(7,95,174,.10); color: #075fae; }
|
|
751
826
|
html[data-theme="light"] .codex-context-meter { --context-color: #168447; border-color: #69c98a; background: #effaf3; color: #125f34; }
|
|
752
827
|
html[data-theme="light"] .codex-context-meter::before { background: #bcebc9; }
|
|
753
828
|
html[data-theme="light"] .codex-context-meter.warn { --context-color: #a66f00; border-color: #e0b53e; background: #fff9df; color: #715000; }
|
|
@@ -808,3 +883,50 @@ html[data-theme="light"] .usage-pricing-note { color: #667085; }
|
|
|
808
883
|
html[data-theme="light"] .usage-chart-track { background: #e9edf2; }
|
|
809
884
|
html[data-theme="light"] .usage-table th { border-color: #dfe4eb; color: #667085; }
|
|
810
885
|
html[data-theme="light"] .usage-table td { border-color: #edf0f3; color: #344054; }
|
|
886
|
+
html[data-theme="light"] .tool-modal-header { border-color: #e0e5ec; }
|
|
887
|
+
html[data-theme="light"] .tool-item { border: 1px solid #e0e5ec; background: #f7f9fb; color: #172033; }
|
|
888
|
+
html[data-theme="light"] .tool-item:hover,
|
|
889
|
+
html[data-theme="light"] .tool-item:active { border-color: #99c8f7; background: #eaf4ff; }
|
|
890
|
+
html[data-theme="light"] .tool-icon { background: #dceeff; color: #006acb; }
|
|
891
|
+
html[data-theme="light"] #default-cwd { color: #526174 !important; }
|
|
892
|
+
html[data-theme="light"] .usage-source-item { border: 1px solid #e1e6ed; background: #f7f9fb; color: #172033; }
|
|
893
|
+
html[data-theme="light"] .usage-source-item:hover,
|
|
894
|
+
html[data-theme="light"] .usage-source-item:active { border-color: #99c8f7; background: #eaf4ff; }
|
|
895
|
+
html[data-theme="light"] .usage-source-copy strong { color: #172033; }
|
|
896
|
+
html[data-theme="light"] .usage-source-badge { background: #dceeff; color: #006acb; }
|
|
897
|
+
html[data-theme="light"] .usage-source-arrow { color: #667085; }
|
|
898
|
+
html[data-theme="light"] .attachment-chip { border-color: #99c8f7; background: #e8f3ff; color: #173b61; }
|
|
899
|
+
html[data-theme="light"] .attachment-chip.file { border-color: #c8d0dc; background: #f2f4f7; color: #344054; }
|
|
900
|
+
html[data-theme="light"] .attachment-chip.uploading { border-color: #e6b94c; background: #fff6df; color: #715000; }
|
|
901
|
+
html[data-theme="light"] .attachment-status { color: #725d28; }
|
|
902
|
+
html[data-theme="light"] .attachment-remove { background: rgba(23,59,97,.1); color: #344054; }
|
|
903
|
+
html[data-theme="light"] .attachment-progress { background: rgba(23,59,97,.12); }
|
|
904
|
+
html[data-theme="light"] .claude-message-attachment { border-color: #b9c9dc; background: rgba(255,255,255,.72); color: #344054; }
|
|
905
|
+
html[data-theme="light"] .claude-md a { color: #006acb; }
|
|
906
|
+
|
|
907
|
+
.tool-modal-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
|
|
908
|
+
.tool-modal-header h2 { margin: 0; }
|
|
909
|
+
.tool-modal-header .icon-btn { width: 32px; height: 32px; border-radius: 50%; color: var(--text-dim); font-size: 24px; }
|
|
910
|
+
#add-step-type { border-color: var(--line) !important; background: var(--surface-soft) !important; color: var(--text) !important; }
|
|
911
|
+
|
|
912
|
+
.git-change-card { margin-bottom: 8px; overflow: hidden; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-raised); }
|
|
913
|
+
.git-change-header { display: flex; align-items: center; min-height: 42px; padding: 8px 10px; color: var(--text); cursor: pointer; font-size: 13px; font-weight: 600; outline: none; user-select: none; }
|
|
914
|
+
.git-change-header:hover { background: var(--surface-soft); }
|
|
915
|
+
.git-change-path { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
916
|
+
.git-status-badge { flex: 0 0 auto; margin-left: 8px; padding: 1px 5px; border: 1px solid currentColor; border-radius: 4px; font-size: 10px; font-weight: 800; }
|
|
917
|
+
.git-status-badge.modified { color: var(--git-modified-text); }
|
|
918
|
+
.git-status-badge.added { color: var(--git-staged-color, #34c759); }
|
|
919
|
+
.git-status-badge.deleted { color: var(--git-deleted-color, #ff3b30); }
|
|
920
|
+
.git-inline-diff { border-top: 1px solid var(--line); background: var(--git-diff-bg); }
|
|
921
|
+
.git-inline-diff-body { max-height: 400px; overflow: auto; padding: 4px 0; font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
922
|
+
.git-inline-diff-footer { padding: 8px; border-top: 1px solid var(--line); background: var(--surface); text-align: center; }
|
|
923
|
+
.git-diff-panel { margin-bottom: 8px; overflow: hidden; border: 1px solid var(--line); border-radius: 6px; }
|
|
924
|
+
.git-diff-summary { padding: 7px 10px; background: var(--surface-raised); color: var(--text); cursor: pointer; font-size: 13px; font-weight: 600; outline: none; user-select: none; }
|
|
925
|
+
.git-diff-body { overflow-x: auto; padding: 4px 0; background: var(--git-diff-bg); font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
926
|
+
.git-file-code { overflow-x: auto; margin: 0; padding: 12px 0; border-radius: 8px; background: var(--git-diff-bg); color: var(--git-diff-text); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
927
|
+
.git-file-toolbar-group { display: flex; gap: 2px; margin-right: 8px; padding: 2px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface-soft); }
|
|
928
|
+
.git-file-toolbar-button { padding: 4px 8px; border: 0; border-radius: 3px; background: transparent; color: var(--text-dim); cursor: pointer; font-size: 12px; }
|
|
929
|
+
.git-file-toolbar-button:hover { background: var(--surface-raised); color: var(--text); }
|
|
930
|
+
.git-file-mode-button { padding: 4px 8px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface-soft); color: var(--text); cursor: pointer; font-size: 12px; }
|
|
931
|
+
.git-file-mode-button.active { border-color: var(--primary); background: var(--primary); color: #fff; }
|
|
932
|
+
.git-line-number { width: 36px; flex: 0 0 36px; margin-right: 16px; color: var(--text-dim); text-align: right; user-select: none; }
|
package/lib/web/timed-inputs.js
CHANGED
|
@@ -172,17 +172,17 @@
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
document.getElementById('send-btn').addEventListener('click', performSend);
|
|
175
|
-
document.getElementById('
|
|
176
|
-
|
|
175
|
+
document.getElementById('attachment-btn').addEventListener('click', () => {
|
|
176
|
+
attachmentFileInput.click();
|
|
177
177
|
});
|
|
178
178
|
document.getElementById('schedule-send-btn').addEventListener('click', () => {
|
|
179
179
|
if (document.getElementById('timed-send-panel').classList.contains('active')) closeTimedSendPanel();
|
|
180
180
|
else openTimedSendPanel();
|
|
181
181
|
});
|
|
182
|
-
|
|
183
|
-
const files =
|
|
184
|
-
if (files?.length) void
|
|
185
|
-
|
|
182
|
+
attachmentFileInput.addEventListener('change', () => {
|
|
183
|
+
const files = attachmentFileInput.files;
|
|
184
|
+
if (files?.length) void uploadSelectedAttachments(files);
|
|
185
|
+
attachmentFileInput.value = '';
|
|
186
186
|
});
|
|
187
187
|
inputEl.addEventListener('keydown', (e) => {
|
|
188
188
|
if (e.key === 'Enter' && e.shiftKey) { e.preventDefault(); performSend(); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glad-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.46",
|
|
4
4
|
"description": "Glad transforms terminal-based AI coding tools into a polished, mobile-friendly local Web interface.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"glad": "bin/cli.js"
|
|
@@ -59,10 +59,13 @@
|
|
|
59
59
|
"express": "^5.2.1",
|
|
60
60
|
"node-pty": "npm:@lydell/node-pty@^1.1.0",
|
|
61
61
|
"uuid": "^11.1.1",
|
|
62
|
-
"ws": "^8.19.0"
|
|
62
|
+
"ws": "^8.19.0",
|
|
63
|
+
"yaml": "^2.8.1",
|
|
64
|
+
"yauzl": "^3.2.0"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
67
|
"@playwright/test": "^1.61.1",
|
|
66
|
-
"caxa": "^3.0.1"
|
|
68
|
+
"caxa": "^3.0.1",
|
|
69
|
+
"yazl": "^3.3.1"
|
|
67
70
|
}
|
|
68
71
|
}
|