mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
Merge christianhaberl's session-sidebar branch, ported to current master
Brings in https://github.com/christianhaberl/Codeman/pull/4 (three commits, authorship preserved) and adapts it across the 211 commits master gained since the branch was cut: - App Settings control re-authored for the set-* surface (PR #278): a set-row in Layout -> Tabs, replacing the old settings-item markup the branch targeted. i18n description synced. - Lineage arcs (PR #291, post-branch) are SKIPPED in sidebar layout: computeLineagePath()'s U-bridge geometry hangs from the horizontal strip's bottom edge and has no meaning against a vertical list. The lineage strip-scroll listener now also redraws subagent/ultracode connectors while the sidebar scrolls vertically. - The desktop home tab rail (post-branch) defers to the sidebar: both dock the session list flush left, and the rail would render z-ordered under it. - Active-row reveal unified into _scrollActiveTabIntoView() (#257 landed on master after the branch): sidebar mode branches to scrollIntoView block:'nearest', and _fullRenderSessionTabs() restores scrollTop alongside the #257 scrollLeft restore so ambient rebuilds cannot yank a mid-scroll sidebar back to the top. - Mobile active-tab hoisting the branch guarded against no longer exists on master (removed by #257); kept master's order-stable render. Verified: typecheck, lint, format:check, check:frontend-syntax, check:public-assets, PostCSS parse of both merged stylesheets, the 26 new jsdom tests, the structural guard suites, and the headless-Chromium harness (scripts/verify-session-sidebar.mts) green across all seven layout states at 1600/1000/393px against current master. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -401,15 +401,12 @@ Object.assign(CodemanApp.prototype, {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Draw curved line from TAB bottom-center to window top-center
|
||||
const x1 = tabRect.left + tabRect.width / 2;
|
||||
const y1 = tabRect.bottom;
|
||||
const x2 = winRect.left + winRect.width / 2;
|
||||
const y2 = winRect.top;
|
||||
|
||||
// Bezier curve control points for smooth curve
|
||||
const midY = (y1 + y2) / 2;
|
||||
const path = `M ${x1} ${y1} C ${x1} ${midY}, ${x2} ${midY}, ${x2} ${y2}`;
|
||||
// Draw a curved line from the tab to the window. Header strip: tab
|
||||
// bottom-center → window top-center (vertical). Sidebar: tab right-edge →
|
||||
// window left-edge (horizontal), otherwise the curve loops backwards
|
||||
// underneath the sidebar. _tabAnchor/_tabConnectorPath live in app.js.
|
||||
const anchor = this._tabAnchor(tabRect);
|
||||
const path = this._tabConnectorPath(anchor, winRect);
|
||||
|
||||
const line = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
line.setAttribute('d', path);
|
||||
@@ -749,9 +746,11 @@ Object.assign(CodemanApp.prototype, {
|
||||
win.style.top = `${finalY}px`;
|
||||
win.style.bottom = 'auto';
|
||||
} else if (flyFromTab) {
|
||||
const tabRect = parentTab.getBoundingClientRect();
|
||||
win.style.left = `${tabRect.left}px`;
|
||||
win.style.top = `${tabRect.bottom}px`;
|
||||
// Spawn at the tab: below it in header layout, to its RIGHT in sidebar
|
||||
// layout — spawning at tabRect.left there would land on top of the sidebar.
|
||||
const anchor = this._tabAnchor(parentTab.getBoundingClientRect());
|
||||
win.style.left = `${anchor.spawnLeft}px`;
|
||||
win.style.top = `${anchor.spawnTop}px`;
|
||||
win.style.transform = 'scale(0.3)';
|
||||
win.style.opacity = '0';
|
||||
win.classList.add('spawning');
|
||||
@@ -1226,6 +1225,19 @@ Object.assign(CodemanApp.prototype, {
|
||||
dropdown.style.left = `${rect.left + rect.width / 2}px`;
|
||||
dropdown.style.transform = 'translateX(-50%)';
|
||||
dropdown.classList.add('open');
|
||||
|
||||
// Keep it on screen. A badge in the left sidebar — and above all one in the
|
||||
// 44px collapsed rail — sits so far left that a centre-anchored dropdown
|
||||
// hangs off the viewport. Measured after .open so it has a box; a no-op
|
||||
// whenever the centred position already fits, so header layout is unchanged.
|
||||
const dropRect = dropdown.getBoundingClientRect();
|
||||
const overflowLeft = 8 - dropRect.left;
|
||||
const overflowRight = dropRect.right - (window.innerWidth - 8);
|
||||
if (overflowLeft > 0) {
|
||||
dropdown.style.transform = `translateX(calc(-50% + ${Math.round(overflowLeft)}px))`;
|
||||
} else if (overflowRight > 0) {
|
||||
dropdown.style.transform = `translateX(calc(-50% - ${Math.round(overflowRight)}px))`;
|
||||
}
|
||||
},
|
||||
|
||||
// Schedule hide after delay (allows moving mouse to dropdown)
|
||||
|
||||
Reference in New Issue
Block a user