// SPDX-License-Identifier: AGPL-3.0-or-later import { LitElement, html, css, } from "//shared.localhost:8888/third_party/lit/lit-all.min.js"; export class MobileOverview extends LitElement { static properties = { open: { type: Boolean, reflect: true }, tabs: { type: Array }, activeTabId: { type: String }, }; static styles = css` @import url(//system.localhost:8888/mobile_overview.css); `; constructor() { super(); this.open = false; this.tabs = []; this.activeTabId = null; // Touch state for swipe-to-close this.swipeState = null; } handleOverlayClick(e) { if (e.target.classList.contains("overlay")) { this.close(); } } close() { this.open = false; this.dispatchEvent(new CustomEvent("overview-close", { bubbles: true })); } handleTabClick(tab) { this.dispatchEvent( new CustomEvent("tab-select", { bubbles: true, detail: { tabId: tab.id }, }), ); this.close(); } handleCloseTab(e, tab) { e.stopPropagation(); // Animate the card closing const card = e.currentTarget.closest(".tab-card"); card.classList.add("closing"); setTimeout(() => { this.dispatchEvent( new CustomEvent("tab-close", { bubbles: true, detail: { tabId: tab.id }, }), ); }, 300); } handleNewTab() { this.dispatchEvent(new CustomEvent("tab-new", { bubbles: true })); this.close(); } handleHome() { this.dispatchEvent(new CustomEvent("tab-home", { bubbles: true })); this.close(); } // Touch handlers for swipe-up-to-close on cards handleTouchStart(e, tab) { const touch = e.touches[0]; this.swipeState = { tab, startY: touch.clientY, currentY: touch.clientY, element: e.currentTarget, }; } handleTouchMove(e) { if (!this.swipeState) { return; } const touch = e.touches[0]; this.swipeState.currentY = touch.clientY; const deltaY = this.swipeState.currentY - this.swipeState.startY; // Only allow upward swipe (close) if (deltaY < 0) { this.swipeState.element.style.transform = `translateY(${deltaY}px)`; this.swipeState.element.style.opacity = Math.max(0, 1 + deltaY / 150); } } handleTouchEnd(e) { if (!this.swipeState) { return; } const deltaY = this.swipeState.currentY - this.swipeState.startY; const element = this.swipeState.element; const tab = this.swipeState.tab; if (deltaY < -80) { // Close threshold reached element.classList.add("closing"); setTimeout(() => { this.dispatchEvent( new CustomEvent("tab-close", { bubbles: true, detail: { tabId: tab.id }, }), ); }, 300); } else { // Snap back element.style.transform = ""; element.style.opacity = ""; } this.swipeState = null; } render() { let tabText = this.tabs.length > 1 ? `${this.tabs.length} Views` : `1 View`; return html`