fix(electrobun): WebKitGTK click-lock — use display toggle instead of DOM add/remove
This commit is contained in:
parent
3a876329c5
commit
95f1f8208f
5 changed files with 94 additions and 109 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -4,8 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Svelte App</title>
|
<title>Svelte App</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DyX_7OUK.js"></script>
|
<script type="module" crossorigin src="/assets/index-Cv8GjxAz.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CYr5v29h.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-6BCrvHEB.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
||||||
|
|
@ -176,9 +176,9 @@
|
||||||
// ── setActiveGroup: fire-and-forget RPC ───────────────────────
|
// ── setActiveGroup: fire-and-forget RPC ───────────────────────
|
||||||
function setActiveGroup(id: string | undefined) {
|
function setActiveGroup(id: string | undefined) {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
console.log('[DEBUG] setActiveGroup:', id);
|
||||||
activeGroupId = id;
|
activeGroupId = id;
|
||||||
// Fire and forget — don't let RPC failures block UI
|
// NO RPC — pure local state change for debugging
|
||||||
appRpc?.request["settings.set"]?.({ key: 'active_group', value: id })?.catch?.(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Window controls ────────────────────────────────────────────
|
// ── Window controls ────────────────────────────────────────────
|
||||||
|
|
@ -263,6 +263,30 @@
|
||||||
function fmtTokens(n: number): string { return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n); }
|
function fmtTokens(n: number): string { return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n); }
|
||||||
function fmtCost(n: number): string { return `$${n.toFixed(3)}`; }
|
function fmtCost(n: number): string { return `$${n.toFixed(3)}`; }
|
||||||
|
|
||||||
|
// ── DEBUG: Visual click diagnostics overlay ─────────────────────
|
||||||
|
let debugLog = $state<string[]>([]);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
function debugClick(e: MouseEvent) {
|
||||||
|
const el = e.target as HTMLElement;
|
||||||
|
const tag = el?.tagName;
|
||||||
|
const cls = (el?.className?.toString?.() ?? '').slice(0, 40);
|
||||||
|
const elAtPoint = document.elementFromPoint(e.clientX, e.clientY);
|
||||||
|
let line = `CLICK ${tag}.${cls} @(${e.clientX},${e.clientY})`;
|
||||||
|
if (elAtPoint && elAtPoint !== el) {
|
||||||
|
const overTag = (elAtPoint as HTMLElement).tagName;
|
||||||
|
const overCls = ((elAtPoint as HTMLElement).className?.toString?.() ?? '').slice(0, 40);
|
||||||
|
line += ` ⚠️OVERLAY: ${overTag}.${overCls}`;
|
||||||
|
}
|
||||||
|
debugLog = [...debugLog.slice(-8), line];
|
||||||
|
}
|
||||||
|
document.addEventListener('click', debugClick, true);
|
||||||
|
document.addEventListener('mousedown', (e) => {
|
||||||
|
const el = e.target as HTMLElement;
|
||||||
|
debugLog = [...debugLog.slice(-8), `DOWN ${el?.tagName}.${(el?.className?.toString?.() ?? '').slice(0, 40)}`];
|
||||||
|
}, true);
|
||||||
|
});
|
||||||
|
|
||||||
// ── Init ───────────────────────────────────────────────────────
|
// ── Init ───────────────────────────────────────────────────────
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
themeStore.initTheme(appRpc).catch(console.error);
|
themeStore.initTheme(appRpc).catch(console.error);
|
||||||
|
|
@ -309,7 +333,7 @@
|
||||||
<aside class="sidebar" role="navigation" aria-label="Primary navigation">
|
<aside class="sidebar" role="navigation" aria-label="Primary navigation">
|
||||||
<!-- AGOR vertical title -->
|
<!-- AGOR vertical title -->
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="agor-title" aria-hidden="true" onmousedown={onDragStart}>AGOR</div>
|
<div class="agor-title" aria-hidden="true">AGOR</div>
|
||||||
|
|
||||||
<!-- Group icons — numbered circles -->
|
<!-- Group icons — numbered circles -->
|
||||||
<div class="sidebar-groups" role="list" aria-label="Project groups">
|
<div class="sidebar-groups" role="list" aria-label="Project groups">
|
||||||
|
|
@ -350,83 +374,38 @@
|
||||||
<main class="workspace">
|
<main class="workspace">
|
||||||
<!-- Project grid -->
|
<!-- Project grid -->
|
||||||
<div class="project-grid" role="list" aria-label="{activeGroup?.name ?? 'Projects'} projects">
|
<div class="project-grid" role="list" aria-label="{activeGroup?.name ?? 'Projects'} projects">
|
||||||
{#each gridRows() as row (row.type === 'standalone' ? row.project.id : `cg-${row.parent.id}`)}
|
<!-- ALL projects rendered always with display:none/flex toggling.
|
||||||
{#if row.type === 'standalone'}
|
WebKitGTK corrupts hit-test tree when DOM nodes are added/removed during click events. -->
|
||||||
<div role="listitem">
|
{#each PROJECTS as project (project.id)}
|
||||||
<ProjectCard
|
<div role="listitem" style:display={(project.groupId ?? 'dev') === activeGroupId ? 'flex' : 'none'}>
|
||||||
id={row.project.id}
|
<ProjectCard
|
||||||
name={row.project.name}
|
id={project.id}
|
||||||
cwd={row.project.cwd}
|
name={project.name}
|
||||||
accent={row.project.accent}
|
cwd={project.cwd}
|
||||||
status={row.project.status}
|
accent={project.accent}
|
||||||
costUsd={row.project.costUsd}
|
status={project.status}
|
||||||
tokens={row.project.tokens}
|
costUsd={project.costUsd}
|
||||||
messages={row.project.messages}
|
tokens={project.tokens}
|
||||||
provider={row.project.provider}
|
messages={project.messages}
|
||||||
profile={row.project.profile}
|
provider={project.provider}
|
||||||
model={row.project.model}
|
profile={project.profile}
|
||||||
contextPct={row.project.contextPct}
|
model={project.model}
|
||||||
burnRate={row.project.burnRate}
|
contextPct={project.contextPct}
|
||||||
{blinkVisible}
|
burnRate={project.burnRate}
|
||||||
clonesAtMax={cloneCountForProject(row.project.id) >= 3}
|
{blinkVisible}
|
||||||
onClone={handleClone}
|
clonesAtMax={cloneCountForProject(project.id) >= 3}
|
||||||
/>
|
onClone={handleClone}
|
||||||
</div>
|
worktreeBranch={project.worktreeBranch}
|
||||||
{:else}
|
cloneOf={project.cloneOf}
|
||||||
<div class="clone-group-row" role="listitem" aria-label="Project group: {row.parent.name}">
|
/>
|
||||||
<ProjectCard
|
</div>
|
||||||
id={row.parent.id}
|
|
||||||
name={row.parent.name}
|
|
||||||
cwd={row.parent.cwd}
|
|
||||||
accent={row.parent.accent}
|
|
||||||
status={row.parent.status}
|
|
||||||
costUsd={row.parent.costUsd}
|
|
||||||
tokens={row.parent.tokens}
|
|
||||||
messages={row.parent.messages}
|
|
||||||
provider={row.parent.provider}
|
|
||||||
profile={row.parent.profile}
|
|
||||||
model={row.parent.model}
|
|
||||||
contextPct={row.parent.contextPct}
|
|
||||||
burnRate={row.parent.burnRate}
|
|
||||||
{blinkVisible}
|
|
||||||
clonesAtMax={row.clones.length >= 3}
|
|
||||||
onClone={handleClone}
|
|
||||||
/>
|
|
||||||
{#each row.clones as clone (clone.id)}
|
|
||||||
<div class="chain-icon" aria-hidden="true">
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
|
|
||||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<ProjectCard
|
|
||||||
id={clone.id}
|
|
||||||
name={clone.name}
|
|
||||||
cwd={clone.cwd}
|
|
||||||
accent={clone.accent ?? row.parent.accent}
|
|
||||||
status={clone.status}
|
|
||||||
costUsd={clone.costUsd}
|
|
||||||
tokens={clone.tokens}
|
|
||||||
messages={clone.messages}
|
|
||||||
provider={clone.provider}
|
|
||||||
profile={clone.profile}
|
|
||||||
model={clone.model}
|
|
||||||
contextPct={clone.contextPct}
|
|
||||||
burnRate={clone.burnRate}
|
|
||||||
{blinkVisible}
|
|
||||||
worktreeBranch={clone.worktreeBranch}
|
|
||||||
cloneOf={clone.cloneOf}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if filteredProjects.length === 0}
|
<!-- Empty group — always in DOM, visibility toggled -->
|
||||||
<div class="empty-group" role="listitem">
|
<div class="empty-group" role="listitem"
|
||||||
<p class="empty-group-text">No projects in {activeGroup?.name ?? 'this group'}</p>
|
style:display={filteredProjects.length === 0 ? 'flex' : 'none'}>
|
||||||
</div>
|
<p class="empty-group-text">No projects in {activeGroup?.name ?? 'this group'}</p>
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
@ -511,6 +490,13 @@
|
||||||
<kbd class="palette-hint" title="Open command palette">Ctrl+K</kbd>
|
<kbd class="palette-hint" title="Open command palette">Ctrl+K</kbd>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- DEBUG: visible click log -->
|
||||||
|
<div style="position:fixed;bottom:0;left:0;right:0;background:#000;color:#0f0;font-family:monospace;font-size:10px;padding:4px 8px;z-index:9999;max-height:100px;overflow-y:auto;pointer-events:none;">
|
||||||
|
{#each debugLog as line}
|
||||||
|
<div>{line}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:global(body) { overflow: hidden; }
|
:global(body) { overflow: hidden; }
|
||||||
:global(#app) { display: flex; flex-direction: column; height: 100vh; }
|
:global(#app) { display: flex; flex-direction: column; height: 100vh; }
|
||||||
|
|
|
||||||
|
|
@ -115,18 +115,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Terminal panes: only rendered when expanded -->
|
<!-- Terminal panes: always in DOM, display toggled.
|
||||||
{#if expanded}
|
WebKitGTK corrupts hit-test tree on DOM add/remove during click. -->
|
||||||
<div class="term-panes">
|
<div class="term-panes" style:display={expanded ? 'block' : 'none'}>
|
||||||
{#each tabs as tab (tab.id)}
|
{#each tabs as tab (tab.id)}
|
||||||
{#if mounted.has(tab.id)}
|
{#if mounted.has(tab.id)}
|
||||||
<div class="term-pane" style:display={activeTabId === tab.id ? 'flex' : 'none'}>
|
<div class="term-pane" style:display={activeTabId === tab.id ? 'flex' : 'none'}>
|
||||||
<Terminal sessionId={tab.id} />
|
<Terminal sessionId={tab.id} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue