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 name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Svelte App</title>
|
||||
<script type="module" crossorigin src="/assets/index-DyX_7OUK.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CYr5v29h.css">
|
||||
<script type="module" crossorigin src="/assets/index-Cv8GjxAz.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-6BCrvHEB.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
|
|
@ -176,9 +176,9 @@
|
|||
// ── setActiveGroup: fire-and-forget RPC ───────────────────────
|
||||
function setActiveGroup(id: string | undefined) {
|
||||
if (!id) return;
|
||||
console.log('[DEBUG] setActiveGroup:', id);
|
||||
activeGroupId = id;
|
||||
// Fire and forget — don't let RPC failures block UI
|
||||
appRpc?.request["settings.set"]?.({ key: 'active_group', value: id })?.catch?.(() => {});
|
||||
// NO RPC — pure local state change for debugging
|
||||
}
|
||||
|
||||
// ── Window controls ────────────────────────────────────────────
|
||||
|
|
@ -263,6 +263,30 @@
|
|||
function fmtTokens(n: number): string { return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n); }
|
||||
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 ───────────────────────────────────────────────────────
|
||||
onMount(() => {
|
||||
themeStore.initTheme(appRpc).catch(console.error);
|
||||
|
|
@ -309,7 +333,7 @@
|
|||
<aside class="sidebar" role="navigation" aria-label="Primary navigation">
|
||||
<!-- AGOR vertical title -->
|
||||
<!-- 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 -->
|
||||
<div class="sidebar-groups" role="list" aria-label="Project groups">
|
||||
|
|
@ -350,83 +374,38 @@
|
|||
<main class="workspace">
|
||||
<!-- Project grid -->
|
||||
<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}`)}
|
||||
{#if row.type === 'standalone'}
|
||||
<div role="listitem">
|
||||
<ProjectCard
|
||||
id={row.project.id}
|
||||
name={row.project.name}
|
||||
cwd={row.project.cwd}
|
||||
accent={row.project.accent}
|
||||
status={row.project.status}
|
||||
costUsd={row.project.costUsd}
|
||||
tokens={row.project.tokens}
|
||||
messages={row.project.messages}
|
||||
provider={row.project.provider}
|
||||
profile={row.project.profile}
|
||||
model={row.project.model}
|
||||
contextPct={row.project.contextPct}
|
||||
burnRate={row.project.burnRate}
|
||||
{blinkVisible}
|
||||
clonesAtMax={cloneCountForProject(row.project.id) >= 3}
|
||||
onClone={handleClone}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="clone-group-row" role="listitem" aria-label="Project group: {row.parent.name}">
|
||||
<ProjectCard
|
||||
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}
|
||||
<!-- ALL projects rendered always with display:none/flex toggling.
|
||||
WebKitGTK corrupts hit-test tree when DOM nodes are added/removed during click events. -->
|
||||
{#each PROJECTS as project (project.id)}
|
||||
<div role="listitem" style:display={(project.groupId ?? 'dev') === activeGroupId ? 'flex' : 'none'}>
|
||||
<ProjectCard
|
||||
id={project.id}
|
||||
name={project.name}
|
||||
cwd={project.cwd}
|
||||
accent={project.accent}
|
||||
status={project.status}
|
||||
costUsd={project.costUsd}
|
||||
tokens={project.tokens}
|
||||
messages={project.messages}
|
||||
provider={project.provider}
|
||||
profile={project.profile}
|
||||
model={project.model}
|
||||
contextPct={project.contextPct}
|
||||
burnRate={project.burnRate}
|
||||
{blinkVisible}
|
||||
clonesAtMax={cloneCountForProject(project.id) >= 3}
|
||||
onClone={handleClone}
|
||||
worktreeBranch={project.worktreeBranch}
|
||||
cloneOf={project.cloneOf}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
{#if filteredProjects.length === 0}
|
||||
<div class="empty-group" role="listitem">
|
||||
<p class="empty-group-text">No projects in {activeGroup?.name ?? 'this group'}</p>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Empty group — always in DOM, visibility toggled -->
|
||||
<div class="empty-group" role="listitem"
|
||||
style:display={filteredProjects.length === 0 ? 'flex' : 'none'}>
|
||||
<p class="empty-group-text">No projects in {activeGroup?.name ?? 'this group'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
|
@ -511,6 +490,13 @@
|
|||
<kbd class="palette-hint" title="Open command palette">Ctrl+K</kbd>
|
||||
</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>
|
||||
:global(body) { overflow: hidden; }
|
||||
:global(#app) { display: flex; flex-direction: column; height: 100vh; }
|
||||
|
|
|
|||
|
|
@ -115,18 +115,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Terminal panes: only rendered when expanded -->
|
||||
{#if expanded}
|
||||
<div class="term-panes">
|
||||
{#each tabs as tab (tab.id)}
|
||||
{#if mounted.has(tab.id)}
|
||||
<div class="term-pane" style:display={activeTabId === tab.id ? 'flex' : 'none'}>
|
||||
<Terminal sessionId={tab.id} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Terminal panes: always in DOM, display toggled.
|
||||
WebKitGTK corrupts hit-test tree on DOM add/remove during click. -->
|
||||
<div class="term-panes" style:display={expanded ? 'block' : 'none'}>
|
||||
{#each tabs as tab (tab.id)}
|
||||
{#if mounted.has(tab.id)}
|
||||
<div class="term-pane" style:display={activeTabId === tab.id ? 'flex' : 'none'}>
|
||||
<Terminal sessionId={tab.id} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue