Merge remote-tracking branch 'origin/frontend-redesign-2'

This commit is contained in:
Peter Steinberger 2025-06-20 06:03:48 +02:00
commit 12cb1e5c8e
10 changed files with 359 additions and 575 deletions

View file

@ -265,9 +265,11 @@ export class VibeTunnelApp extends LitElement {
${this.errorMessage
? html`
<div class="fixed top-4 right-4 z-50">
<div class="bg-vs-warning text-vs-bg px-4 py-2 rounded shadow-lg font-mono text-sm">
<div
class="bg-status-error text-dark-bg px-4 py-2 rounded shadow-lg font-mono text-sm"
>
${this.errorMessage}
<button @click=${this.clearError} class="ml-2 text-vs-bg hover:text-vs-muted">
<button @click=${this.clearError} class="ml-2 text-dark-bg hover:text-dark-text">
</button>
</div>
@ -277,9 +279,11 @@ export class VibeTunnelApp extends LitElement {
${this.successMessage
? html`
<div class="fixed top-4 right-4 z-50">
<div class="bg-vs-link text-vs-bg px-4 py-2 rounded shadow-lg font-mono text-sm">
<div
class="bg-status-success text-dark-bg px-4 py-2 rounded shadow-lg font-mono text-sm"
>
${this.successMessage}
<button @click=${this.clearSuccess} class="ml-2 text-vs-bg hover:text-vs-muted">
<button @click=${this.clearSuccess} class="ml-2 text-dark-bg hover:text-dark-text">
</button>
</div>
@ -298,7 +302,7 @@ export class VibeTunnelApp extends LitElement {
`
)
: html`
<div class="max-w-4xl mx-auto" style="background: black;">
<div class="max-w-4xl mx-auto">
<app-header
.sessions=${this.sessions}
.hideExited=${this.hideExited}

View file

@ -1,7 +1,7 @@
import { LitElement, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import type { Session } from './session-list.js';
import './vibe-logo.js';
import './terminal-icon.js';
@customElement('app-header')
export class AppHeader extends LitElement {
@ -46,109 +46,71 @@ export class AppHeader extends LitElement {
}
return html`
<div class="app-header p-4" style="background: black;">
<div class="app-header bg-dark-bg-secondary border-b border-dark-border p-6">
<!-- Mobile layout -->
<div class="flex flex-col gap-3 sm:hidden">
<!-- Centered VibeTunnel title -->
<div class="text-center">
<vibe-logo></vibe-logo>
<div class="flex flex-col gap-4 sm:hidden">
<!-- Centered Sessions title with stats -->
<div class="text-center flex flex-col items-center gap-2">
<h1 class="text-2xl font-bold text-accent-green flex items-center gap-3">
<terminal-icon size="28"></terminal-icon>
<span>Sessions</span>
</h1>
<p class="text-dark-text-muted text-sm">
${runningSessions.length} ${runningSessions.length === 1 ? 'Session' : 'Sessions'}
${exitedSessions.length > 0 ? `${exitedSessions.length} Exited` : ''}
</p>
</div>
<!-- Controls row: left buttons and right buttons -->
<div class="flex items-center justify-between">
<div class="flex gap-1">
<div class="flex gap-2">
${exitedSessions.length > 0
? html`
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid ${this.hideExited
? '#23d18b'
: '#888'};"
class="btn-ghost font-mono text-xs ${this.hideExited
? 'text-accent-green border border-accent-green'
: ''}"
@click=${() =>
this.dispatchEvent(
new CustomEvent('hide-exited-change', {
detail: !this.hideExited,
})
)}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
const borderColor = this.hideExited ? '#23d18b' : '#888';
btn.style.background = borderColor;
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
${this.hideExited
? `SHOW EXITED (${exitedSessions.length})`
: `HIDE EXITED (${exitedSessions.length})`}
? `Show Exited (${exitedSessions.length})`
: `Hide Exited (${exitedSessions.length})`}
</button>
`
: ''}
${!this.hideExited && exitedSessions.length > 0
? html`
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
class="btn-ghost font-mono text-xs text-status-warning"
@click=${this.handleCleanExited}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#d19a66';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CLEAN EXITED
Clean Exited
</button>
`
: ''}
${runningSessions.length > 0 && !this.killingAll
? html`
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
class="btn-ghost font-mono text-xs text-status-error"
@click=${this.handleKillAll}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#d19a66';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
KILL (${runningSessions.length})
Kill (${runningSessions.length})
</button>
`
: ''}
</div>
<div class="flex gap-1">
<div class="flex gap-2">
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
class="btn-primary font-mono text-xs px-4 py-2"
@click=${this.handleCreateSession}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CREATE
Create
</button>
</div>
</div>
@ -156,7 +118,16 @@ export class AppHeader extends LitElement {
<!-- Desktop layout: single row -->
<div class="hidden sm:flex sm:items-center sm:justify-between">
<vibe-logo></vibe-logo>
<div class="flex items-center gap-3">
<terminal-icon size="32"></terminal-icon>
<div>
<h1 class="text-xl font-bold text-accent-green">VibeTunnel</h1>
<p class="text-dark-text-muted text-sm">
${runningSessions.length} ${runningSessions.length === 1 ? 'Session' : 'Sessions'}
${exitedSessions.length > 0 ? `${exitedSessions.length} Exited` : ''}
</p>
</div>
</div>
<div class="flex items-center gap-3">
${exitedSessions.length > 0
? html`
@ -193,61 +164,28 @@ export class AppHeader extends LitElement {
${!this.hideExited && this.sessions.filter((s) => s.status === 'exited').length > 0
? html`
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
class="btn-ghost font-mono text-xs text-status-warning"
@click=${this.handleCleanExited}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#d19a66';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CLEAN EXITED
Clean Exited
</button>
`
: ''}
${runningSessions.length > 0 && !this.killingAll
? html`
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
class="btn-ghost font-mono text-xs text-status-error"
@click=${this.handleKillAll}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#d19a66';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
KILL ALL (${runningSessions.length})
Kill All (${runningSessions.length})
</button>
`
: ''}
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
class="btn-primary font-mono text-xs px-4 py-2"
@click=${this.handleCreateSession}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CREATE SESSION
Create Session
</button>
</div>
</div>

View file

@ -145,48 +145,31 @@ export class FileBrowser extends LitElement {
}
return html`
<div
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
style="z-index: 9999;"
>
<div
class="font-mono text-sm w-96 h-96 flex flex-col"
style="background: black; border: 1px solid #569cd6; border-radius: 4px;"
>
<div class="p-4 flex-shrink-0" style="border-bottom: 1px solid #444;">
<div class="modal-backdrop flex items-center justify-center">
<div class="modal-content font-mono text-sm w-96 h-96 flex flex-col overflow-hidden">
<div class="pb-4 mb-4 border-b border-dark-border flex-shrink-0">
<div class="flex justify-between items-center mb-2">
<div class="text-vs-user text-sm">Select Directory</div>
<h2 class="text-accent-green text-lg font-bold">Select Directory</h2>
<button
class="font-mono px-2 py-1 text-xs rounded transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
class="btn-secondary font-mono text-xs px-3 py-1"
@click=${this.handleCreateFolder}
?disabled=${this.loading}
title="Create new folder"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
+ folder
+ Folder
</button>
</div>
<div class="text-vs-muted text-sm break-all">${this.currentPath}</div>
<div class="text-dark-text-muted text-sm break-all">${this.currentPath}</div>
</div>
<div class="p-4 flex-1 overflow-y-auto">
<div class="px-4 pb-4 flex-1 overflow-y-auto">
${this.loading
? html` <div class="text-vs-muted">Loading...</div> `
? html` <div class="text-dark-text-muted">Loading...</div> `
: html`
${this.currentPath !== '/'
? html`
<div
class="flex items-center gap-2 p-2 hover:bg-vs-nav-hover cursor-pointer text-vs-accent"
class="flex items-center gap-2 p-2 hover:bg-dark-bg-tertiary rounded cursor-pointer text-accent-green transition-colors"
@click=${this.handleParentClick}
>
<span>📁</span>
@ -199,7 +182,7 @@ export class FileBrowser extends LitElement {
.map(
(file) => html`
<div
class="flex items-center gap-2 p-2 hover:bg-vs-nav-hover cursor-pointer text-vs-accent"
class="flex items-center gap-2 p-2 hover:bg-dark-bg-tertiary rounded cursor-pointer text-accent-green transition-colors"
@click=${() => this.handleDirectoryClick(file.name)}
>
<span>📁</span>
@ -211,7 +194,7 @@ export class FileBrowser extends LitElement {
.filter((f) => !f.isDir)
.map(
(file) => html`
<div class="flex items-center gap-2 p-2 text-vs-muted">
<div class="flex items-center gap-2 p-2 text-dark-text-muted">
<span>📄</span>
<span>${file.name}</span>
</div>
@ -223,13 +206,12 @@ export class FileBrowser extends LitElement {
<!-- Create folder dialog -->
${this.showCreateFolder
? html`
<div class="p-4 border-t border-vs-border flex-shrink-0">
<div class="text-vs-assistant text-sm mb-2">Create New Folder</div>
<div class="p-4 border-t border-dark-border flex-shrink-0">
<label class="form-label">Create New Folder</label>
<div class="flex gap-2">
<input
type="text"
class="flex-1 outline-none font-mono px-2 py-1 text-sm"
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
class="input-field text-sm"
placeholder="Folder name"
.value=${this.newFolderName}
@input=${this.handleFolderNameInput}
@ -237,89 +219,27 @@ export class FileBrowser extends LitElement {
?disabled=${this.creating}
/>
<button
class="font-mono px-2 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
class="btn-primary font-mono text-xs px-3 py-1 disabled:opacity-50 disabled:cursor-not-allowed"
@click=${this.createFolder}
?disabled=${this.creating || !this.newFolderName.trim()}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = '#569cd6';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
${this.creating ? '...' : 'create'}
${this.creating ? '...' : 'Create'}
</button>
<button
class="font-mono px-2 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
class="btn-ghost font-mono text-xs disabled:opacity-50 disabled:cursor-not-allowed"
@click=${this.handleCancelCreateFolder}
?disabled=${this.creating}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = '#888';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
cancel
Cancel
</button>
</div>
</div>
`
: ''}
<div class="p-4 border-t border-vs-border flex gap-4 justify-end flex-shrink-0">
<button
class="font-mono px-4 py-2 transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
@click=${this.handleCancel}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#888';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
cancel
</button>
<button
class="font-mono px-4 py-2 transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
@click=${this.handleSelect}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
select
</button>
<div class="p-4 border-t border-dark-border flex gap-4 justify-end flex-shrink-0">
<button class="btn-ghost font-mono" @click=${this.handleCancel}>Cancel</button>
<button class="btn-primary font-mono" @click=${this.handleSelect}>Select</button>
</div>
</div>
</div>

View file

@ -156,17 +156,17 @@ export class SessionCard extends LitElement {
render() {
return html`
<div
class="bg-vs-bg rounded shadow cursor-pointer overflow-hidden ${this.killing
? 'opacity-60'
: ''} ${this.hasEscPrompt ? 'border-2 border-orange-500' : 'border border-vs-border'}"
class="card cursor-pointer overflow-hidden ${this.killing ? 'opacity-60' : ''} ${this
.hasEscPrompt
? 'border-2 border-status-warning'
: ''}"
@click=${this.handleCardClick}
>
<!-- Compact Header -->
<div
class="flex justify-between items-center px-3 py-2 border-b border-vs-border"
style="background: black;"
class="flex justify-between items-center px-3 py-2 border-b border-dark-border bg-dark-bg-tertiary"
>
<div class="text-xs font-mono pr-2 flex-1 min-w-0" style="color: #569cd6;">
<div class="text-xs font-mono pr-2 flex-1 min-w-0 text-accent-green">
<div class="truncate" title="${this.session.name || this.session.command}">
${this.session.name || this.session.command}
</div>
@ -174,24 +174,9 @@ export class SessionCard extends LitElement {
${this.session.status === 'running'
? html`
<button
class="font-mono px-2 py-0.5 text-xs disabled:opacity-50 flex-shrink-0 rounded transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
class="btn-ghost font-mono text-xs py-1 text-status-error disabled:opacity-50 flex-shrink-0"
@click=${this.handleKillClick}
?disabled=${this.killing}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!this.killing) {
btn.style.background = '#d19a66';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!this.killing) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
${this.killing ? 'killing...' : 'kill'}
</button>
@ -200,10 +185,10 @@ export class SessionCard extends LitElement {
</div>
<!-- Terminal display (main content) -->
<div class="session-preview bg-black overflow-hidden" style="aspect-ratio: 640/480;">
<div class="session-preview bg-dark-bg overflow-hidden" style="aspect-ratio: 640/480;">
${this.killing
? html`
<div class="w-full h-full flex items-center justify-center text-vs-warning">
<div class="w-full h-full flex items-center justify-center text-status-error">
<div class="text-center font-mono">
<div class="text-4xl mb-2">${this.getKillingText()}</div>
<div class="text-sm">Killing session...</div>
@ -222,8 +207,7 @@ export class SessionCard extends LitElement {
<!-- Compact Footer -->
<div
class="px-3 py-2 text-vs-muted text-xs border-t border-vs-border"
style="background: black;"
class="px-3 py-2 text-dark-text-muted text-xs border-t border-dark-border bg-dark-bg-tertiary"
>
<div class="flex justify-between items-center min-w-0">
<span class="${this.getStatusColor()} text-xs flex items-center gap-1 flex-shrink-0">
@ -233,7 +217,7 @@ export class SessionCard extends LitElement {
${this.session.pid
? html`
<span
class="cursor-pointer hover:text-vs-accent transition-colors text-xs flex-shrink-0 ml-2"
class="cursor-pointer hover:text-accent-green transition-colors text-xs flex-shrink-0 ml-2"
@click=${this.handlePidClick}
title="Click to copy PID"
>
@ -261,15 +245,15 @@ export class SessionCard extends LitElement {
private getStatusColor(): string {
if (this.session.waiting) {
return 'text-vs-muted';
return 'text-dark-text-muted';
}
return this.session.status === 'running' ? 'text-vs-user' : 'text-vs-warning';
return this.session.status === 'running' ? 'text-status-success' : 'text-status-warning';
}
private getStatusDotColor(): string {
if (this.session.waiting) {
return 'bg-gray-500';
return 'bg-dark-text-muted';
}
return this.session.status === 'running' ? 'bg-green-500' : 'bg-orange-500';
return this.session.status === 'running' ? 'bg-status-success' : 'bg-status-warning';
}
}

View file

@ -231,25 +231,18 @@ export class SessionCreateForm extends LitElement {
}
return html`
<div
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
style="z-index: 9999;"
>
<div
class="font-mono text-sm w-96 max-w-full mx-4"
style="background: black; border: 1px solid #569cd6; border-radius: 4px;"
>
<div class="p-4" style="border-bottom: 1px solid #444;">
<div class="text-vs-user text-sm">Create New Session</div>
<div class="modal-backdrop flex items-center justify-center">
<div class="modal-content font-mono text-sm w-96 max-w-full mx-4">
<div class="pb-6 mb-6 border-b border-dark-border">
<h2 class="text-accent-green text-lg font-bold">Create New Session</h2>
</div>
<div class="p-4">
<div class="mb-4">
<div class="text-vs-text mb-2">Session Name (optional):</div>
<label class="form-label">Session Name (optional):</label>
<input
type="text"
class="w-full outline-none font-mono px-4 py-2"
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
class="input-field"
.value=${this.sessionName}
@input=${this.handleSessionNameChange}
placeholder="My Session"
@ -258,44 +251,31 @@ export class SessionCreateForm extends LitElement {
</div>
<div class="mb-4">
<div class="text-vs-text mb-2">Working Directory:</div>
<label class="form-label">Working Directory:</label>
<div class="flex gap-4">
<input
type="text"
class="flex-1 outline-none font-mono px-4 py-2"
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
class="input-field"
.value=${this.workingDir}
@input=${this.handleWorkingDirChange}
placeholder="~/"
?disabled=${this.disabled || this.isCreating}
/>
<button
class="font-mono px-4 py-2 transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
class="btn-secondary font-mono px-4"
@click=${this.handleBrowse}
?disabled=${this.disabled || this.isCreating}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
browse
Browse
</button>
</div>
</div>
<div class="mb-4">
<div class="text-vs-text mb-2">Command:</div>
<label class="form-label">Command:</label>
<input
type="text"
class="w-full outline-none font-mono px-4 py-2"
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
class="input-field"
.value=${this.command}
@input=${this.handleCommandChange}
@keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.handleCreate()}
@ -306,47 +286,21 @@ export class SessionCreateForm extends LitElement {
<div class="flex gap-4 justify-end">
<button
class="font-mono px-4 py-2 transition-colors"
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
class="btn-ghost font-mono"
@click=${this.handleCancel}
?disabled=${this.isCreating}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#888';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
cancel
Cancel
</button>
<button
class="font-mono px-4 py-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
class="btn-primary font-mono disabled:opacity-50 disabled:cursor-not-allowed"
@click=${this.handleCreate}
?disabled=${this.disabled ||
this.isCreating ||
!this.workingDir.trim() ||
!this.command.trim()}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = '#569cd6';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
${this.isCreating ? 'creating...' : 'create'}
${this.isCreating ? 'Creating...' : 'Create'}
</button>
</div>
</div>

View file

@ -99,10 +99,10 @@ export class SessionList extends LitElement {
: this.sessions;
return html`
<div class="font-mono text-sm p-4" style="background: black;">
<div class="font-mono text-sm p-4 bg-dark-bg">
${filteredSessions.length === 0
? html`
<div class="text-vs-muted text-center py-8">
<div class="text-dark-text-muted text-center py-8">
${this.loading
? 'Loading sessions...'
: this.hideExited && this.sessions.length > 0

View file

@ -821,28 +821,28 @@ export class SessionView extends LitElement {
}
private getStatusColor(): string {
if (!this.session) return 'text-vs-muted';
if (!this.session) return 'text-dark-text-muted';
if ('waiting' in this.session && this.session.waiting) {
return 'text-vs-muted';
return 'text-dark-text-muted';
}
return this.session.status === 'running' ? 'text-vs-user' : 'text-vs-warning';
return this.session.status === 'running' ? 'text-status-success' : 'text-status-warning';
}
private getStatusDotColor(): string {
if (!this.session) return 'bg-gray-500';
if (!this.session) return 'bg-dark-text-muted';
if ('waiting' in this.session && this.session.waiting) {
return 'bg-gray-500';
return 'bg-dark-text-muted';
}
return this.session.status === 'running' ? 'bg-green-500' : 'bg-orange-500';
return this.session.status === 'running' ? 'bg-status-success' : 'bg-status-warning';
}
render() {
if (!this.session) {
return html`
<div class="fixed inset-0 bg-black flex items-center justify-center">
<div class="text-vs-text font-mono text-center">
<div class="fixed inset-0 bg-dark-bg flex items-center justify-center">
<div class="text-dark-text font-mono text-center">
<div class="text-2xl mb-2">${this.getLoadingText()}</div>
<div class="text-sm text-vs-muted">Waiting for session...</div>
<div class="text-sm text-dark-text-muted">Waiting for session...</div>
</div>
</div>
`;
@ -857,40 +857,28 @@ export class SessionView extends LitElement {
box-shadow: none !important;
}
session-view:focus {
outline: 2px solid #007acc !important;
outline: 2px solid #00ff88 !important;
outline-offset: -2px;
}
</style>
<div
class="flex flex-col bg-vs-bg font-mono"
class="flex flex-col bg-dark-bg font-mono"
style="height: 100vh; height: 100dvh; outline: none !important; box-shadow: none !important;"
>
<!-- Compact Header -->
<div
class="flex items-center justify-between px-3 py-2 border-b border-vs-border text-sm min-w-0"
style="background: black;"
class="flex items-center justify-between px-3 py-2 border-b border-dark-border text-sm min-w-0 bg-dark-bg-secondary"
>
<div class="flex items-center gap-3 min-w-0 flex-1">
<button
class="font-mono px-2 py-1 rounded transition-colors text-xs flex-shrink-0"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
class="btn-secondary font-mono text-xs px-3 py-1 flex-shrink-0"
@click=${this.handleBack}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
BACK
Back
</button>
<div class="text-vs-text min-w-0 flex-1 overflow-hidden">
<div class="text-dark-text min-w-0 flex-1 overflow-hidden">
<div
class="text-vs-accent text-xs sm:text-sm overflow-hidden text-ellipsis whitespace-nowrap"
class="text-accent-green text-xs sm:text-sm overflow-hidden text-ellipsis whitespace-nowrap"
title="${this.session.name || this.session.command}"
>
${this.session.name || this.session.command}
@ -906,7 +894,7 @@ export class SessionView extends LitElement {
${this.terminalCols > 0 && this.terminalRows > 0
? html`
<span
class="text-vs-muted text-xs opacity-60"
class="text-dark-text-muted text-xs opacity-60"
style="font-size: 10px; line-height: 1;"
>
${this.terminalCols}×${this.terminalRows}
@ -919,7 +907,7 @@ export class SessionView extends LitElement {
<!-- Terminal Container -->
<div
class="flex-1 bg-black overflow-hidden min-h-0 relative"
class="flex-1 bg-dark-bg overflow-hidden min-h-0 relative"
id="terminal-container"
style="max-width: 100vw; height: 100%;"
>
@ -927,11 +915,11 @@ export class SessionView extends LitElement {
? html`
<!-- Loading overlay -->
<div
class="absolute inset-0 bg-black bg-opacity-80 flex items-center justify-center z-10"
class="absolute inset-0 bg-dark-bg bg-opacity-80 flex items-center justify-center z-10"
>
<div class="text-vs-text font-mono text-center">
<div class="text-dark-text font-mono text-center">
<div class="text-2xl mb-2">${this.getLoadingText()}</div>
<div class="text-sm text-vs-muted">Connecting to session...</div>
<div class="text-sm text-dark-text-muted">Connecting to session...</div>
</div>
</div>
`
@ -954,70 +942,26 @@ export class SessionView extends LitElement {
<!-- First row: Arrow keys -->
<div class="flex gap-2 mb-2">
<button
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer"
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer quick-start-btn"
@click=${() => this.handleSpecialKey('arrow_up')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
<button
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer"
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer quick-start-btn"
@click=${() => this.handleSpecialKey('arrow_down')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
<button
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer"
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer quick-start-btn"
@click=${() => this.handleSpecialKey('arrow_left')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
<button
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer"
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer quick-start-btn"
@click=${() => this.handleSpecialKey('arrow_right')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
@ -1026,87 +970,32 @@ export class SessionView extends LitElement {
<!-- Second row: Special keys -->
<div class="flex gap-2">
<button
class="font-mono text-sm transition-all cursor-pointer w-16"
class="font-mono text-sm transition-all cursor-pointer w-16 quick-start-btn"
@click=${() => this.handleSpecialKey('escape')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px; padding: 8px 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
ESC
</button>
<button
class="font-mono text-sm transition-all cursor-pointer w-16"
class="font-mono text-sm transition-all cursor-pointer w-16 quick-start-btn"
@click=${() => this.handleSpecialKey('\t')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px; padding: 8px 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
<button
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer"
class="flex-1 font-mono px-3 py-2 text-sm transition-all cursor-pointer quick-start-btn"
@click=${this.handleMobileInputToggle}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
ABC123
</button>
<button
class="font-mono text-sm transition-all cursor-pointer w-16"
class="font-mono text-sm transition-all cursor-pointer w-16 quick-start-btn"
@click=${this.handleCtrlAlphaToggle}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px; padding: 8px 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
CTRL
</button>
<button
class="font-mono text-sm transition-all cursor-pointer w-16"
class="font-mono text-sm transition-all cursor-pointer w-16 quick-start-btn"
@click=${() => this.handleSpecialKey('enter')}
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px; padding: 8px 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.9)';
btn.style.borderColor = '#666';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.borderColor = '#444';
}}
>
<span class="text-xl"></span>
</button>
@ -1167,63 +1056,22 @@ export class SessionView extends LitElement {
<!-- Controls -->
<div class="p-4 flex gap-2" style="border-top: 1px solid #444;">
<button
class="font-mono px-3 py-2 text-xs transition-colors"
class="font-mono px-3 py-2 text-xs transition-colors btn-ghost"
@click=${() => (this.showMobileInput = false)}
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#888';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CANCEL
</button>
<button
class="flex-1 font-mono px-3 py-2 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
class="flex-1 font-mono px-3 py-2 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed btn-ghost"
@click=${this.handleMobileInputSendOnly}
?disabled=${!this.mobileInputText.trim()}
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = '#888';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
SEND
</button>
<button
class="flex-1 font-mono px-3 py-2 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
class="flex-1 font-mono px-3 py-2 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed btn-secondary"
@click=${this.handleMobileInputSend}
?disabled=${!this.mobileInputText.trim()}
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = '#569cd6';
btn.style.color = 'black';
}
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
if (!btn.hasAttribute('disabled')) {
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}
}}
>
SEND +
</button>
@ -1297,19 +1145,8 @@ export class SessionView extends LitElement {
].map(
(letter) => html`
<button
class="font-mono text-xs transition-all cursor-pointer aspect-square flex items-center justify-center"
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
class="font-mono text-xs transition-all cursor-pointer aspect-square flex items-center justify-center quick-start-btn"
@click=${() => this.handleCtrlKey(letter)}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'rgba(0, 0, 0, 0.8)';
btn.style.color = '#d4d4d4';
}}
>
${letter}
</button>
@ -1325,55 +1162,22 @@ export class SessionView extends LitElement {
<!-- Action buttons -->
<div class="flex gap-2 justify-center">
<button
class="font-mono px-4 py-2 text-sm transition-all cursor-pointer"
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
class="font-mono px-4 py-2 text-sm transition-all cursor-pointer btn-ghost"
@click=${() => (this.showCtrlAlpha = false)}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#888';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CANCEL
</button>
${this.ctrlSequence.length > 0
? html`
<button
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer"
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer btn-ghost"
@click=${this.handleClearCtrlSequence}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#888';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
CLEAR
</button>
<button
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer"
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer btn-secondary"
@click=${this.handleSendCtrlSequence}
@mouseover=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = '#569cd6';
btn.style.color = 'black';
}}
@mouseout=${(e: Event) => {
const btn = e.target as HTMLElement;
btn.style.background = 'black';
btn.style.color = '#d4d4d4';
}}
>
SEND
</button>

View file

@ -0,0 +1,39 @@
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('terminal-icon')
export class TerminalIcon extends LitElement {
@property({ type: Number }) size = 24;
static styles = css`
:host {
display: inline-flex;
align-items: center;
justify-content: center;
}
svg {
display: block;
width: var(--icon-size, 24px);
height: var(--icon-size, 24px);
}
`;
render() {
return html`
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
style="--icon-size: ${this.size}px"
class="terminal-icon"
>
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
`;
}
}

View file

@ -2,6 +2,93 @@
@tailwind components;
@tailwind utilities;
/* Global dark theme styles */
@layer base {
body {
@apply bg-dark-bg text-dark-text;
}
/* Default focus styles */
:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(0, 255, 136, 0.3);
}
}
/* Custom components */
@layer components {
/* Glowing terminal icon */
.terminal-icon {
@apply text-accent-green;
filter: drop-shadow(0 0 10px rgba(0, 255, 136, 0.6));
}
/* Input fields with glow effect */
.input-field {
@apply bg-dark-bg-secondary border border-dark-border rounded-lg px-4 py-3 text-dark-text w-full;
@apply transition-all duration-200 ease-in-out;
@apply hover:border-accent-green-darker focus:border-accent-green;
@apply focus:shadow-glow-green-sm;
}
/* Button styles */
.btn-primary {
@apply bg-accent-green text-dark-bg font-medium px-6 py-3 rounded-lg;
@apply transition-all duration-200 ease-in-out;
@apply hover:bg-accent-green-light hover:shadow-glow-green;
@apply active:scale-95;
}
.btn-secondary {
@apply border border-accent-green text-accent-green px-6 py-3 rounded-lg;
@apply transition-all duration-200 ease-in-out;
@apply hover:bg-accent-green hover:text-dark-bg hover:shadow-glow-green;
@apply active:scale-95;
}
.btn-ghost {
@apply text-dark-text-muted px-4 py-2 rounded-lg;
@apply transition-all duration-200 ease-in-out;
@apply hover:text-dark-text hover:bg-dark-bg-tertiary;
}
/* Card styles */
.card {
@apply bg-dark-bg-secondary border border-dark-border rounded-lg p-6;
@apply transition-all duration-200 ease-in-out;
@apply hover:border-accent-green-darker hover:shadow-glow-green-sm;
}
/* Quick start buttons */
.quick-start-btn {
@apply bg-dark-bg-tertiary border border-dark-border rounded-lg px-4 py-3 h-12;
@apply transition-all duration-200 ease-in-out text-dark-text-muted;
@apply hover:border-accent-green hover:text-accent-green hover:shadow-glow-green-sm;
@apply active:scale-95;
}
.quick-start-btn.active {
@apply bg-accent-green text-dark-bg border-accent-green shadow-glow-green-sm;
}
/* Modal backdrop */
.modal-backdrop {
@apply fixed inset-0 bg-black bg-opacity-80 z-40;
backdrop-filter: blur(4px);
}
/* Modal content */
.modal-content {
@apply bg-dark-bg-secondary border border-dark-border rounded-xl p-8;
@apply shadow-2xl shadow-black/50;
}
/* Labels */
.form-label {
@apply text-dark-text-muted text-sm font-medium mb-2 flex items-center gap-2;
}
}
/* Fira Code Variable Font */
@font-face {
font-family: 'Fira Code';
@ -112,9 +199,10 @@ body {
/* Terminal container styling */
.terminal-container {
color: #d4d4d4;
color: #e4e4e4;
white-space: pre;
overflow: hidden;
background-color: #0a0a0a;
}
/* Terminal line styling */
@ -196,8 +284,8 @@ body {
/* Terminal focus indicator */
.terminal-focused {
box-shadow: 0 0 0 2px #00ff00;
border-color: #00ff00 !important;
box-shadow: 0 0 0 2px #00ff88;
border-color: #00ff88 !important;
}
/* Keyboard capture indicator */
@ -205,9 +293,9 @@ body {
position: fixed;
top: 10px;
right: 10px;
background: rgba(0, 255, 0, 0.1);
border: 1px solid #00ff00;
color: #00ff00;
background: rgba(0, 255, 136, 0.1);
border: 1px solid #00ff88;
color: #00ff88;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
@ -517,14 +605,14 @@ body {
left: 12px;
width: 48px;
height: 48px;
background: rgba(0, 0, 0, 0.8);
border: 1px solid #444;
background: rgba(26, 26, 26, 0.9);
border: 1px solid #2a2a2a;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #d4d4d4;
color: #e4e4e4;
font-size: 24px;
transition: all 0.2s ease;
user-select: none;
@ -532,9 +620,11 @@ body {
}
.scroll-to-bottom:hover {
background: rgba(0, 0, 0, 0.9);
border-color: #666;
background: rgba(26, 26, 26, 1);
border-color: #00ff88;
color: #00ff88;
transform: translateY(-1px);
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
}
.scroll-to-bottom:active {
@ -546,13 +636,13 @@ body {
position: absolute;
bottom: 8px;
right: 8px;
background: rgba(0, 0, 0, 0.8);
border: 1px solid #444;
background: rgba(26, 26, 26, 0.9);
border: 1px solid #2a2a2a;
border-radius: 4px;
padding: 8px 12px;
font-family: 'Fira Code', monospace;
font-size: 11px;
color: #d4d4d4;
color: #e4e4e4;
user-select: none;
z-index: 10;
line-height: 1.4;
@ -580,14 +670,14 @@ body {
right: 12px;
width: 48px;
height: 48px;
background: rgba(0, 0, 0, 0.8);
border: 1px solid #444;
background: rgba(26, 26, 26, 0.9);
border: 1px solid #2a2a2a;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #d4d4d4;
color: #e4e4e4;
font-size: 20px;
transition: all 0.2s ease;
user-select: none;
@ -595,9 +685,11 @@ body {
}
.fit-toggle:hover {
background: rgba(0, 0, 0, 0.9);
border-color: #666;
background: rgba(26, 26, 26, 1);
border-color: #00ff88;
color: #00ff88;
transform: translateY(-1px);
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
}
.fit-toggle:active {
@ -605,6 +697,7 @@ body {
}
.fit-toggle.active {
border-color: #569cd6;
color: #569cd6;
border-color: #00ff88;
color: #00ff88;
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
}

View file

@ -4,24 +4,72 @@ module.exports = {
theme: {
extend: {
colors: {
"vs-bg": "#1e1e1e",
"vs-text": "#d4d4d4",
"vs-muted": "#8c8c8c",
"vs-accent": "#569cd6",
"vs-user": "#6a9955",
"vs-assistant": "#ce9178",
"vs-warning": "#f48771",
"vs-function": "#dcdcaa",
"vs-type": "#4ec9b0",
"vs-border": "#3e3e42",
"vs-border-light": "#5a5a5e",
"vs-bg-secondary": "#2d2d30",
"vs-nav": "#3e3e42",
"vs-nav-hover": "#4a4a4e",
"vs-nav-active": "#f48771",
// Dark theme colors
"dark-bg": "#0a0a0a",
"dark-bg-secondary": "#1a1a1a",
"dark-bg-tertiary": "#242424",
"dark-border": "#2a2a2a",
"dark-border-light": "#3a3a3a",
// Text colors
"dark-text": "#e4e4e4",
"dark-text-muted": "#7a7a7a",
"dark-text-dim": "#5a5a5a",
// Green accent colors (multiple shades)
"accent-green": "#00ff88",
"accent-green-dark": "#00cc66",
"accent-green-darker": "#009944",
"accent-green-light": "#44ffaa",
"accent-green-glow": "#00ff8866",
// Secondary accent colors
"accent-cyan": "#00ffcc",
"accent-teal": "#00ccaa",
// Status colors
"status-error": "#cc3333",
"status-warning": "#cc8833",
"status-success": "#00cc66",
// Legacy VS Code theme colors (for compatibility)
"vs-bg": "#0a0a0a",
"vs-text": "#e4e4e4",
"vs-muted": "#7a7a7a",
"vs-accent": "#00ff88",
"vs-user": "#00ff88",
"vs-assistant": "#00ccaa",
"vs-warning": "#ffaa44",
"vs-function": "#44ffaa",
"vs-type": "#00ffcc",
"vs-border": "#2a2a2a",
"vs-border-light": "#3a3a3a",
"vs-bg-secondary": "#1a1a1a",
"vs-nav": "#1a1a1a",
"vs-nav-hover": "#242424",
"vs-nav-active": "#00ff88",
"vs-highlight": "#8b6914",
},
},
boxShadow: {
'glow-green': '0 0 20px rgba(0, 255, 136, 0.4)',
'glow-green-sm': '0 0 10px rgba(0, 255, 136, 0.3)',
'glow-green-lg': '0 0 30px rgba(0, 255, 136, 0.5)',
},
animation: {
'pulse-green': 'pulseGreen 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
},
keyframes: {
pulseGreen: {
'0%, 100%': {
opacity: '1',
},
'50%': {
opacity: '.8',
},
},
},
},
},
plugins: [],
};