import { css, html, LitElement, nothing } from 'lit'; import { SignalWatcher } from '@lit-labs/signals'; import { app } from './store.ts'; import type { TileEntry } from '../types.ts'; import type { MaslSizing } from '@dasl/tile-lexicon'; import './tile-frame.ts'; import './data-console.ts'; const KIND_LABEL: Record = { car: 'CAR file', at: 'AT Protocol', watch: 'watched dir', }; export class TileCard extends SignalWatcher(LitElement) { static override properties = { tile: { attribute: false }, showing: { state: true }, showingConsole: { state: true }, }; // `declare`d so they stay Lit reactive accessors (class fields shadow them) declare tile: TileEntry; declare showing: boolean; declare showingConsole: boolean; #sizing?: MaslSizing; constructor() { super(); this.showing = false; this.showingConsole = false; } static override styles = css` :host { display: block; border: 1px solid var(--border, #d5d5d8); border-radius: 8px; background: var(--card-bg, #fff); overflow: hidden; } header { display: flex; align-items: center; gap: 0.6rem; padding: 0.7rem 0.9rem; border-bottom: 1px solid var(--border, #e5e5e8); } header .name { font-weight: 600; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .kind { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.15rem 0.5rem; border-radius: 99px; background: var(--badge-bg, #eef); color: var(--badge-fg, #446); white-space: nowrap; } .source, .published { font-size: 0.78rem; font-family: ui-monospace, monospace; color: var(--muted, #777); padding: 0.4rem 0.9rem 0; word-break: break-all; } .published { color: var(--accent, #2a6); } .actions { display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0.7rem 0.9rem; } button { font: inherit; font-size: 0.82rem; padding: 0.3rem 0.7rem; border-radius: 6px; border: 1px solid var(--border, #ccc); background: var(--btn-bg, #f7f7f9); cursor: pointer; } button:hover { background: var(--btn-hover, #ececf1); } button.danger { color: #c0392b; } .progress { font-size: 0.8rem; padding: 0 0.9rem 0.6rem; color: var(--accent, #26c); } tile-frame { border-top: 1px solid var(--border, #e5e5e8); } `; override render() { const model = app.get(); const tile = this.tile; const version = model.versions[tile.id] ?? 0; const publishing = model.publishing[tile.id]; const source = tile.path ?? tile.atUri ?? tile.dir ?? ''; return html`
${tile.name ?? source} ${KIND_LABEL[tile.kind]}
${source}
${tile.publishedUri ? html`
published: ${tile.publishedUri}
` : nothing} ${publishing ? html`
⇡ ${publishing}
` : nothing}
${tile.kind === 'watch' ? html` ` : nothing}
${this.showing ? html` ` : nothing} ${this.showingConsole ? html`` : nothing} `; } #toggleConsole = () => { this.showingConsole = !this.showingConsole; // data flows through the rendered tile, so make sure there is one if (this.showingConsole && !this.showing) this.showing = true; }; #onLoaded = (ev: CustomEvent) => { this.#sizing = ev.detail.sizing; const name = ev.detail.name as string | undefined; if (name && name !== this.tile.name) { app.send({ type: 'tile-name', id: this.tile.id, name }); } }; #openWindow = () => { app.send({ type: 'open-window', id: this.tile.id, width: this.#sizing?.width, height: this.#sizing?.height, }); }; } customElements.define('tile-card', TileCard);