feat(v0.6): add Home (⌂) button to reach Sessions/Projects from a session
Once a project/session tab was open, the home chooser (Sessions/Projects segmented control) was hidden and only reachable by closing every tab — no way back to the Projects view to open another project. Add a ⌂ Home button to the tab bar that overlays the chooser on top of the open tabs (homeForced flag; updateHomeView shows home when no tab OR forced, hiding the terminal panes). Clicking ⌂ again, clicking a tab (activate resets homeForced), or opening another session/project dismisses the overlay. Closing the last tab resets the flag. The button highlights while active. Tests: +3 (tabs.test.ts). Full suite 415 green; both typechecks clean; verified in-browser (open tab → ⌂ → Projects panel reachable → ⌂ → terminal).
This commit is contained in:
@@ -207,6 +207,26 @@ body {
|
||||
background: var(--surface-2);
|
||||
}
|
||||
|
||||
/* v0.6: Home (⌂) button — opens the Sessions/Projects chooser over open tabs. */
|
||||
.tab-home {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-dim);
|
||||
cursor: pointer;
|
||||
font-size: 17px;
|
||||
padding: 0 10px;
|
||||
flex: none;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.tab-home:hover {
|
||||
color: #fff;
|
||||
background: var(--surface-2);
|
||||
}
|
||||
.tab-home.active {
|
||||
color: var(--on-accent, #1a1408);
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
/* toolbar */
|
||||
#toolbar {
|
||||
flex: 0 0 auto;
|
||||
|
||||
@@ -59,6 +59,11 @@ export class TabApp {
|
||||
private readonly projects: ProjectsPanel
|
||||
private homeView: HomeView = 'sessions'
|
||||
private readonly segControl: HTMLElement
|
||||
// When true, the home chooser is overlaid on top of the open tabs (so you can
|
||||
// jump back to Sessions/Projects without closing anything). Reset whenever a
|
||||
// tab is activated. Irrelevant while no tab is open (home shows regardless).
|
||||
private homeForced = false
|
||||
private homeBtn: HTMLButtonElement | null = null
|
||||
|
||||
constructor(paneHost: HTMLElement, tabBar: HTMLElement) {
|
||||
this.paneHost = paneHost
|
||||
@@ -104,7 +109,9 @@ export class TabApp {
|
||||
* When no tab is open: show the seg control and the selected sub-panel.
|
||||
*/
|
||||
private updateHomeView(): void {
|
||||
const empty = this.tabs.length === 0
|
||||
// Home shows when there is no tab OR the user explicitly forced it (the ⌂
|
||||
// button), letting you reach Sessions/Projects without closing a session.
|
||||
const showHome = this.tabs.length === 0 || this.homeForced
|
||||
|
||||
// Sync active-class on segmented control buttons.
|
||||
const btns = this.segControl.querySelectorAll<HTMLButtonElement>('.home-seg-btn')
|
||||
@@ -112,8 +119,12 @@ export class TabApp {
|
||||
const view: HomeView = i === 0 ? 'sessions' : 'projects'
|
||||
btn.classList.toggle('active', view === this.homeView)
|
||||
})
|
||||
// The ⌂ button is "pressed" only while overlaying home on top of open tabs.
|
||||
this.homeBtn?.classList.toggle('active', this.homeForced && this.tabs.length > 0)
|
||||
|
||||
if (empty) {
|
||||
if (showHome) {
|
||||
// Overlay home: hide every terminal pane so the chooser is on top.
|
||||
for (const t of this.tabs) t.session.hide()
|
||||
this.segControl.style.display = 'flex'
|
||||
this.launcher.setVisible(this.homeView === 'sessions')
|
||||
this.projects.setVisible(this.homeView === 'projects')
|
||||
@@ -124,6 +135,19 @@ export class TabApp {
|
||||
}
|
||||
}
|
||||
|
||||
/** Toggle the home chooser overlay over the open tabs (the ⌂ button). No-op
|
||||
* when no tab is open (home is already showing). */
|
||||
private toggleHome(): void {
|
||||
if (this.tabs.length === 0) return
|
||||
this.homeForced = !this.homeForced
|
||||
if (this.homeForced) {
|
||||
this.updateHomeView()
|
||||
} else {
|
||||
// Return to the active terminal (activate re-shows its pane + hides home).
|
||||
this.activate(this.activeIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private saveHomeView(): void {
|
||||
try {
|
||||
localStorage.setItem(HOME_VIEW_KEY, this.homeView)
|
||||
@@ -310,11 +334,13 @@ export class TabApp {
|
||||
activate(i: number): void {
|
||||
if (i < 0 || i >= this.tabs.length) return
|
||||
this.maybeAskNotify() // first switch is a user gesture — request notif permission
|
||||
this.homeForced = false // showing a terminal dismisses any home overlay
|
||||
this.activeIndex = i
|
||||
const entry = this.tabs[i]
|
||||
if (entry) entry.hasActivity = false // viewing clears the unread dot
|
||||
this.tabs.forEach((t, idx) => (idx === i ? t.session.show() : t.session.hide()))
|
||||
this.tabs.forEach((t) => this.refreshTab(t)) // in-place class/text update, no rebuild
|
||||
this.updateHomeView() // hide the seg control + home panels now a tab is active
|
||||
this.updateApprovalBar()
|
||||
this.persist()
|
||||
}
|
||||
@@ -327,6 +353,7 @@ export class TabApp {
|
||||
if (this.tabs.length === 0) {
|
||||
// v0.5: closing the last tab returns to the home screen — no auto-blank tab.
|
||||
this.activeIndex = -1
|
||||
this.homeForced = false // back to the natural "no tabs → home" state
|
||||
this.persist()
|
||||
this.rebuild() // updateHomeView() (in rebuild) shows the chooser
|
||||
this.updateApprovalBar()
|
||||
@@ -459,6 +486,17 @@ export class TabApp {
|
||||
private rebuild(): void {
|
||||
this.tabBar.replaceChildren()
|
||||
|
||||
// Home (⌂): overlay the Sessions/Projects chooser over the open tabs so you
|
||||
// can start another session/project without closing the current one.
|
||||
const home = document.createElement('button')
|
||||
home.className = 'tab-home'
|
||||
home.textContent = '⌂'
|
||||
home.title = 'Home — Sessions & Projects'
|
||||
home.setAttribute('aria-label', 'Home — Sessions & Projects')
|
||||
home.addEventListener('click', () => this.toggleHome())
|
||||
this.tabBar.appendChild(home)
|
||||
this.homeBtn = home
|
||||
|
||||
this.tabs.forEach((entry, idx) => {
|
||||
const tabEl = document.createElement('div')
|
||||
entry.el = tabEl
|
||||
|
||||
Reference in New Issue
Block a user