mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
Merge remote-tracking branch 'origin/frontend-redesign-2'
This commit is contained in:
commit
12cb1e5c8e
10 changed files with 359 additions and 575 deletions
|
|
@ -265,9 +265,11 @@ export class VibeTunnelApp extends LitElement {
|
||||||
${this.errorMessage
|
${this.errorMessage
|
||||||
? html`
|
? html`
|
||||||
<div class="fixed top-4 right-4 z-50">
|
<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}
|
${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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -277,9 +279,11 @@ export class VibeTunnelApp extends LitElement {
|
||||||
${this.successMessage
|
${this.successMessage
|
||||||
? html`
|
? html`
|
||||||
<div class="fixed top-4 right-4 z-50">
|
<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}
|
${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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -298,7 +302,7 @@ export class VibeTunnelApp extends LitElement {
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
: html`
|
: html`
|
||||||
<div class="max-w-4xl mx-auto" style="background: black;">
|
<div class="max-w-4xl mx-auto">
|
||||||
<app-header
|
<app-header
|
||||||
.sessions=${this.sessions}
|
.sessions=${this.sessions}
|
||||||
.hideExited=${this.hideExited}
|
.hideExited=${this.hideExited}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { LitElement, html } from 'lit';
|
import { LitElement, html } from 'lit';
|
||||||
import { customElement, property, state } from 'lit/decorators.js';
|
import { customElement, property, state } from 'lit/decorators.js';
|
||||||
import type { Session } from './session-list.js';
|
import type { Session } from './session-list.js';
|
||||||
import './vibe-logo.js';
|
import './terminal-icon.js';
|
||||||
|
|
||||||
@customElement('app-header')
|
@customElement('app-header')
|
||||||
export class AppHeader extends LitElement {
|
export class AppHeader extends LitElement {
|
||||||
|
|
@ -46,109 +46,71 @@ export class AppHeader extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
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 -->
|
<!-- Mobile layout -->
|
||||||
<div class="flex flex-col gap-3 sm:hidden">
|
<div class="flex flex-col gap-4 sm:hidden">
|
||||||
<!-- Centered VibeTunnel title -->
|
<!-- Centered Sessions title with stats -->
|
||||||
<div class="text-center">
|
<div class="text-center flex flex-col items-center gap-2">
|
||||||
<vibe-logo></vibe-logo>
|
<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>
|
</div>
|
||||||
|
|
||||||
<!-- Controls row: left buttons and right buttons -->
|
<!-- Controls row: left buttons and right buttons -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-2">
|
||||||
${exitedSessions.length > 0
|
${exitedSessions.length > 0
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-ghost font-mono text-xs ${this.hideExited
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid ${this.hideExited
|
? 'text-accent-green border border-accent-green'
|
||||||
? '#23d18b'
|
: ''}"
|
||||||
: '#888'};"
|
|
||||||
@click=${() =>
|
@click=${() =>
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('hide-exited-change', {
|
new CustomEvent('hide-exited-change', {
|
||||||
detail: !this.hideExited,
|
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
|
${this.hideExited
|
||||||
? `SHOW EXITED (${exitedSessions.length})`
|
? `Show Exited (${exitedSessions.length})`
|
||||||
: `HIDE EXITED (${exitedSessions.length})`}
|
: `Hide Exited (${exitedSessions.length})`}
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
${!this.hideExited && exitedSessions.length > 0
|
${!this.hideExited && exitedSessions.length > 0
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-ghost font-mono text-xs text-status-warning"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
|
|
||||||
@click=${this.handleCleanExited}
|
@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>
|
</button>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
${runningSessions.length > 0 && !this.killingAll
|
${runningSessions.length > 0 && !this.killingAll
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-ghost font-mono text-xs text-status-error"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
|
|
||||||
@click=${this.handleKillAll}
|
@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>
|
</button>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-2">
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-primary font-mono text-xs px-4 py-2"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
|
|
||||||
@click=${this.handleCreateSession}
|
@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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -156,7 +118,16 @@ export class AppHeader extends LitElement {
|
||||||
|
|
||||||
<!-- Desktop layout: single row -->
|
<!-- Desktop layout: single row -->
|
||||||
<div class="hidden sm:flex sm:items-center sm:justify-between">
|
<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">
|
<div class="flex items-center gap-3">
|
||||||
${exitedSessions.length > 0
|
${exitedSessions.length > 0
|
||||||
? html`
|
? html`
|
||||||
|
|
@ -193,61 +164,28 @@ export class AppHeader extends LitElement {
|
||||||
${!this.hideExited && this.sessions.filter((s) => s.status === 'exited').length > 0
|
${!this.hideExited && this.sessions.filter((s) => s.status === 'exited').length > 0
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-ghost font-mono text-xs text-status-warning"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
|
|
||||||
@click=${this.handleCleanExited}
|
@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>
|
</button>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
${runningSessions.length > 0 && !this.killingAll
|
${runningSessions.length > 0 && !this.killingAll
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-ghost font-mono text-xs text-status-error"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
|
|
||||||
@click=${this.handleKillAll}
|
@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>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs whitespace-nowrap"
|
class="btn-primary font-mono text-xs px-4 py-2"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
|
|
||||||
@click=${this.handleCreateSession}
|
@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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -145,48 +145,31 @@ export class FileBrowser extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div class="modal-backdrop flex items-center justify-center">
|
||||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
|
<div class="modal-content font-mono text-sm w-96 h-96 flex flex-col overflow-hidden">
|
||||||
style="z-index: 9999;"
|
<div class="pb-4 mb-4 border-b border-dark-border flex-shrink-0">
|
||||||
>
|
|
||||||
<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="flex justify-between items-center mb-2">
|
<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
|
<button
|
||||||
class="font-mono px-2 py-1 text-xs rounded transition-colors"
|
class="btn-secondary font-mono text-xs px-3 py-1"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
|
|
||||||
@click=${this.handleCreateFolder}
|
@click=${this.handleCreateFolder}
|
||||||
?disabled=${this.loading}
|
?disabled=${this.loading}
|
||||||
title="Create new folder"
|
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>
|
</button>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="p-4 flex-1 overflow-y-auto">
|
<div class="px-4 pb-4 flex-1 overflow-y-auto">
|
||||||
${this.loading
|
${this.loading
|
||||||
? html` <div class="text-vs-muted">Loading...</div> `
|
? html` <div class="text-dark-text-muted">Loading...</div> `
|
||||||
: html`
|
: html`
|
||||||
${this.currentPath !== '/'
|
${this.currentPath !== '/'
|
||||||
? html`
|
? html`
|
||||||
<div
|
<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}
|
@click=${this.handleParentClick}
|
||||||
>
|
>
|
||||||
<span>📁</span>
|
<span>📁</span>
|
||||||
|
|
@ -199,7 +182,7 @@ export class FileBrowser extends LitElement {
|
||||||
.map(
|
.map(
|
||||||
(file) => html`
|
(file) => html`
|
||||||
<div
|
<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)}
|
@click=${() => this.handleDirectoryClick(file.name)}
|
||||||
>
|
>
|
||||||
<span>📁</span>
|
<span>📁</span>
|
||||||
|
|
@ -211,7 +194,7 @@ export class FileBrowser extends LitElement {
|
||||||
.filter((f) => !f.isDir)
|
.filter((f) => !f.isDir)
|
||||||
.map(
|
.map(
|
||||||
(file) => html`
|
(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>📄</span>
|
||||||
<span>${file.name}</span>
|
<span>${file.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -223,13 +206,12 @@ export class FileBrowser extends LitElement {
|
||||||
<!-- Create folder dialog -->
|
<!-- Create folder dialog -->
|
||||||
${this.showCreateFolder
|
${this.showCreateFolder
|
||||||
? html`
|
? html`
|
||||||
<div class="p-4 border-t border-vs-border flex-shrink-0">
|
<div class="p-4 border-t border-dark-border flex-shrink-0">
|
||||||
<div class="text-vs-assistant text-sm mb-2">Create New Folder</div>
|
<label class="form-label">Create New Folder</label>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="flex-1 outline-none font-mono px-2 py-1 text-sm"
|
class="input-field text-sm"
|
||||||
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
|
|
||||||
placeholder="Folder name"
|
placeholder="Folder name"
|
||||||
.value=${this.newFolderName}
|
.value=${this.newFolderName}
|
||||||
@input=${this.handleFolderNameInput}
|
@input=${this.handleFolderNameInput}
|
||||||
|
|
@ -237,89 +219,27 @@ export class FileBrowser extends LitElement {
|
||||||
?disabled=${this.creating}
|
?disabled=${this.creating}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn-primary font-mono text-xs px-3 py-1 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
|
|
||||||
@click=${this.createFolder}
|
@click=${this.createFolder}
|
||||||
?disabled=${this.creating || !this.newFolderName.trim()}
|
?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>
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn-ghost font-mono text-xs disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
|
|
||||||
@click=${this.handleCancelCreateFolder}
|
@click=${this.handleCancelCreateFolder}
|
||||||
?disabled=${this.creating}
|
?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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
|
|
||||||
<div class="p-4 border-t border-vs-border flex gap-4 justify-end flex-shrink-0">
|
<div class="p-4 border-t border-dark-border flex gap-4 justify-end flex-shrink-0">
|
||||||
<button
|
<button class="btn-ghost font-mono" @click=${this.handleCancel}>Cancel</button>
|
||||||
class="font-mono px-4 py-2 transition-colors"
|
<button class="btn-primary font-mono" @click=${this.handleSelect}>Select</button>
|
||||||
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -156,17 +156,17 @@ export class SessionCard extends LitElement {
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
class="bg-vs-bg rounded shadow cursor-pointer overflow-hidden ${this.killing
|
class="card cursor-pointer overflow-hidden ${this.killing ? 'opacity-60' : ''} ${this
|
||||||
? 'opacity-60'
|
.hasEscPrompt
|
||||||
: ''} ${this.hasEscPrompt ? 'border-2 border-orange-500' : 'border border-vs-border'}"
|
? 'border-2 border-status-warning'
|
||||||
|
: ''}"
|
||||||
@click=${this.handleCardClick}
|
@click=${this.handleCardClick}
|
||||||
>
|
>
|
||||||
<!-- Compact Header -->
|
<!-- Compact Header -->
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-center px-3 py-2 border-b border-vs-border"
|
class="flex justify-between items-center px-3 py-2 border-b border-dark-border bg-dark-bg-tertiary"
|
||||||
style="background: black;"
|
|
||||||
>
|
>
|
||||||
<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}">
|
<div class="truncate" title="${this.session.name || this.session.command}">
|
||||||
${this.session.name || this.session.command}
|
${this.session.name || this.session.command}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -174,24 +174,9 @@ export class SessionCard extends LitElement {
|
||||||
${this.session.status === 'running'
|
${this.session.status === 'running'
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-0.5 text-xs disabled:opacity-50 flex-shrink-0 rounded transition-colors"
|
class="btn-ghost font-mono text-xs py-1 text-status-error disabled:opacity-50 flex-shrink-0"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #d19a66;"
|
|
||||||
@click=${this.handleKillClick}
|
@click=${this.handleKillClick}
|
||||||
?disabled=${this.killing}
|
?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'}
|
${this.killing ? 'killing...' : 'kill'}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -200,10 +185,10 @@ export class SessionCard extends LitElement {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Terminal display (main content) -->
|
<!-- 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
|
${this.killing
|
||||||
? html`
|
? 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-center font-mono">
|
||||||
<div class="text-4xl mb-2">${this.getKillingText()}</div>
|
<div class="text-4xl mb-2">${this.getKillingText()}</div>
|
||||||
<div class="text-sm">Killing session...</div>
|
<div class="text-sm">Killing session...</div>
|
||||||
|
|
@ -222,8 +207,7 @@ export class SessionCard extends LitElement {
|
||||||
|
|
||||||
<!-- Compact Footer -->
|
<!-- Compact Footer -->
|
||||||
<div
|
<div
|
||||||
class="px-3 py-2 text-vs-muted text-xs border-t border-vs-border"
|
class="px-3 py-2 text-dark-text-muted text-xs border-t border-dark-border bg-dark-bg-tertiary"
|
||||||
style="background: black;"
|
|
||||||
>
|
>
|
||||||
<div class="flex justify-between items-center min-w-0">
|
<div class="flex justify-between items-center min-w-0">
|
||||||
<span class="${this.getStatusColor()} text-xs flex items-center gap-1 flex-shrink-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
|
${this.session.pid
|
||||||
? html`
|
? html`
|
||||||
<span
|
<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}
|
@click=${this.handlePidClick}
|
||||||
title="Click to copy PID"
|
title="Click to copy PID"
|
||||||
>
|
>
|
||||||
|
|
@ -261,15 +245,15 @@ export class SessionCard extends LitElement {
|
||||||
|
|
||||||
private getStatusColor(): string {
|
private getStatusColor(): string {
|
||||||
if (this.session.waiting) {
|
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 {
|
private getStatusDotColor(): string {
|
||||||
if (this.session.waiting) {
|
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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,25 +231,18 @@ export class SessionCreateForm extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div class="modal-backdrop flex items-center justify-center">
|
||||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
|
<div class="modal-content font-mono text-sm w-96 max-w-full mx-4">
|
||||||
style="z-index: 9999;"
|
<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
|
|
||||||
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>
|
</div>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="mb-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
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full outline-none font-mono px-4 py-2"
|
class="input-field"
|
||||||
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
|
|
||||||
.value=${this.sessionName}
|
.value=${this.sessionName}
|
||||||
@input=${this.handleSessionNameChange}
|
@input=${this.handleSessionNameChange}
|
||||||
placeholder="My Session"
|
placeholder="My Session"
|
||||||
|
|
@ -258,44 +251,31 @@ export class SessionCreateForm extends LitElement {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<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">
|
<div class="flex gap-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="flex-1 outline-none font-mono px-4 py-2"
|
class="input-field"
|
||||||
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
|
|
||||||
.value=${this.workingDir}
|
.value=${this.workingDir}
|
||||||
@input=${this.handleWorkingDirChange}
|
@input=${this.handleWorkingDirChange}
|
||||||
placeholder="~/"
|
placeholder="~/"
|
||||||
?disabled=${this.disabled || this.isCreating}
|
?disabled=${this.disabled || this.isCreating}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="font-mono px-4 py-2 transition-colors"
|
class="btn-secondary font-mono px-4"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
|
|
||||||
@click=${this.handleBrowse}
|
@click=${this.handleBrowse}
|
||||||
?disabled=${this.disabled || this.isCreating}
|
?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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="text-vs-text mb-2">Command:</div>
|
<label class="form-label">Command:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full outline-none font-mono px-4 py-2"
|
class="input-field"
|
||||||
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
|
|
||||||
.value=${this.command}
|
.value=${this.command}
|
||||||
@input=${this.handleCommandChange}
|
@input=${this.handleCommandChange}
|
||||||
@keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.handleCreate()}
|
@keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.handleCreate()}
|
||||||
|
|
@ -306,47 +286,21 @@ export class SessionCreateForm extends LitElement {
|
||||||
|
|
||||||
<div class="flex gap-4 justify-end">
|
<div class="flex gap-4 justify-end">
|
||||||
<button
|
<button
|
||||||
class="font-mono px-4 py-2 transition-colors"
|
class="btn-ghost font-mono"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
|
|
||||||
@click=${this.handleCancel}
|
@click=${this.handleCancel}
|
||||||
?disabled=${this.isCreating}
|
?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>
|
||||||
<button
|
<button
|
||||||
class="font-mono px-4 py-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn-primary font-mono disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
|
|
||||||
@click=${this.handleCreate}
|
@click=${this.handleCreate}
|
||||||
?disabled=${this.disabled ||
|
?disabled=${this.disabled ||
|
||||||
this.isCreating ||
|
this.isCreating ||
|
||||||
!this.workingDir.trim() ||
|
!this.workingDir.trim() ||
|
||||||
!this.command.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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ export class SessionList extends LitElement {
|
||||||
: this.sessions;
|
: this.sessions;
|
||||||
|
|
||||||
return html`
|
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
|
${filteredSessions.length === 0
|
||||||
? html`
|
? html`
|
||||||
<div class="text-vs-muted text-center py-8">
|
<div class="text-dark-text-muted text-center py-8">
|
||||||
${this.loading
|
${this.loading
|
||||||
? 'Loading sessions...'
|
? 'Loading sessions...'
|
||||||
: this.hideExited && this.sessions.length > 0
|
: this.hideExited && this.sessions.length > 0
|
||||||
|
|
|
||||||
|
|
@ -821,28 +821,28 @@ export class SessionView extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStatusColor(): string {
|
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) {
|
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 {
|
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) {
|
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() {
|
render() {
|
||||||
if (!this.session) {
|
if (!this.session) {
|
||||||
return html`
|
return html`
|
||||||
<div class="fixed inset-0 bg-black flex items-center justify-center">
|
<div class="fixed inset-0 bg-dark-bg flex items-center justify-center">
|
||||||
<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-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>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
@ -857,40 +857,28 @@ export class SessionView extends LitElement {
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
session-view:focus {
|
session-view:focus {
|
||||||
outline: 2px solid #007acc !important;
|
outline: 2px solid #00ff88 !important;
|
||||||
outline-offset: -2px;
|
outline-offset: -2px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<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;"
|
style="height: 100vh; height: 100dvh; outline: none !important; box-shadow: none !important;"
|
||||||
>
|
>
|
||||||
<!-- Compact Header -->
|
<!-- Compact Header -->
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between px-3 py-2 border-b border-vs-border text-sm min-w-0"
|
class="flex items-center justify-between px-3 py-2 border-b border-dark-border text-sm min-w-0 bg-dark-bg-secondary"
|
||||||
style="background: black;"
|
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||||
<button
|
<button
|
||||||
class="font-mono px-2 py-1 rounded transition-colors text-xs flex-shrink-0"
|
class="btn-secondary font-mono text-xs px-3 py-1 flex-shrink-0"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6;"
|
|
||||||
@click=${this.handleBack}
|
@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>
|
</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
|
<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}"
|
title="${this.session.name || this.session.command}"
|
||||||
>
|
>
|
||||||
${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
|
${this.terminalCols > 0 && this.terminalRows > 0
|
||||||
? html`
|
? html`
|
||||||
<span
|
<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;"
|
style="font-size: 10px; line-height: 1;"
|
||||||
>
|
>
|
||||||
${this.terminalCols}×${this.terminalRows}
|
${this.terminalCols}×${this.terminalRows}
|
||||||
|
|
@ -919,7 +907,7 @@ export class SessionView extends LitElement {
|
||||||
|
|
||||||
<!-- Terminal Container -->
|
<!-- Terminal Container -->
|
||||||
<div
|
<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"
|
id="terminal-container"
|
||||||
style="max-width: 100vw; height: 100%;"
|
style="max-width: 100vw; height: 100%;"
|
||||||
>
|
>
|
||||||
|
|
@ -927,11 +915,11 @@ export class SessionView extends LitElement {
|
||||||
? html`
|
? html`
|
||||||
<!-- Loading overlay -->
|
<!-- Loading overlay -->
|
||||||
<div
|
<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-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>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
@ -954,70 +942,26 @@ export class SessionView extends LitElement {
|
||||||
<!-- First row: Arrow keys -->
|
<!-- First row: Arrow keys -->
|
||||||
<div class="flex gap-2 mb-2">
|
<div class="flex gap-2 mb-2">
|
||||||
<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_up')}
|
@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>
|
<span class="text-xl">↑</span>
|
||||||
</button>
|
</button>
|
||||||
<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')}
|
@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>
|
<span class="text-xl">↓</span>
|
||||||
</button>
|
</button>
|
||||||
<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')}
|
@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>
|
<span class="text-xl">←</span>
|
||||||
</button>
|
</button>
|
||||||
<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')}
|
@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>
|
<span class="text-xl">→</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1026,87 +970,32 @@ export class SessionView extends LitElement {
|
||||||
<!-- Second row: Special keys -->
|
<!-- Second row: Special keys -->
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<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('escape')}
|
@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
|
ESC
|
||||||
</button>
|
</button>
|
||||||
<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')}
|
@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>
|
<span class="text-xl">⇥</span>
|
||||||
</button>
|
</button>
|
||||||
<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}
|
@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
|
ABC123
|
||||||
</button>
|
</button>
|
||||||
<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}
|
@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
|
CTRL
|
||||||
</button>
|
</button>
|
||||||
<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')}
|
@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>
|
<span class="text-xl">⏎</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1167,63 +1056,22 @@ export class SessionView extends LitElement {
|
||||||
<!-- Controls -->
|
<!-- Controls -->
|
||||||
<div class="p-4 flex gap-2" style="border-top: 1px solid #444;">
|
<div class="p-4 flex gap-2" style="border-top: 1px solid #444;">
|
||||||
<button
|
<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)}
|
@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
|
CANCEL
|
||||||
</button>
|
</button>
|
||||||
<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}
|
@click=${this.handleMobileInputSendOnly}
|
||||||
?disabled=${!this.mobileInputText.trim()}
|
?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
|
SEND
|
||||||
</button>
|
</button>
|
||||||
<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}
|
@click=${this.handleMobileInputSend}
|
||||||
?disabled=${!this.mobileInputText.trim()}
|
?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 + ⏎
|
SEND + ⏎
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1297,19 +1145,8 @@ export class SessionView extends LitElement {
|
||||||
].map(
|
].map(
|
||||||
(letter) => html`
|
(letter) => html`
|
||||||
<button
|
<button
|
||||||
class="font-mono text-xs transition-all cursor-pointer aspect-square flex items-center justify-center"
|
class="font-mono text-xs transition-all cursor-pointer aspect-square flex items-center justify-center quick-start-btn"
|
||||||
style="background: rgba(0, 0, 0, 0.8); color: #d4d4d4; border: 1px solid #444; border-radius: 4px;"
|
|
||||||
@click=${() => this.handleCtrlKey(letter)}
|
@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}
|
${letter}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1325,55 +1162,22 @@ export class SessionView extends LitElement {
|
||||||
<!-- Action buttons -->
|
<!-- Action buttons -->
|
||||||
<div class="flex gap-2 justify-center">
|
<div class="flex gap-2 justify-center">
|
||||||
<button
|
<button
|
||||||
class="font-mono px-4 py-2 text-sm transition-all cursor-pointer"
|
class="font-mono px-4 py-2 text-sm transition-all cursor-pointer btn-ghost"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
|
|
||||||
@click=${() => (this.showCtrlAlpha = false)}
|
@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
|
CANCEL
|
||||||
</button>
|
</button>
|
||||||
${this.ctrlSequence.length > 0
|
${this.ctrlSequence.length > 0
|
||||||
? html`
|
? html`
|
||||||
<button
|
<button
|
||||||
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer"
|
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer btn-ghost"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #888; border-radius: 4px;"
|
|
||||||
@click=${this.handleClearCtrlSequence}
|
@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
|
CLEAR
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer"
|
class="font-mono px-3 py-2 text-sm transition-all cursor-pointer btn-secondary"
|
||||||
style="background: black; color: #d4d4d4; border: 1px solid #569cd6; border-radius: 4px;"
|
|
||||||
@click=${this.handleSendCtrlSequence}
|
@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
|
SEND
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
39
web/src/client/components/terminal-icon.ts
Normal file
39
web/src/client/components/terminal-icon.ts
Normal 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>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,93 @@
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@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 */
|
/* Fira Code Variable Font */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Fira Code';
|
font-family: 'Fira Code';
|
||||||
|
|
@ -112,9 +199,10 @@ body {
|
||||||
|
|
||||||
/* Terminal container styling */
|
/* Terminal container styling */
|
||||||
.terminal-container {
|
.terminal-container {
|
||||||
color: #d4d4d4;
|
color: #e4e4e4;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background-color: #0a0a0a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminal line styling */
|
/* Terminal line styling */
|
||||||
|
|
@ -196,8 +284,8 @@ body {
|
||||||
|
|
||||||
/* Terminal focus indicator */
|
/* Terminal focus indicator */
|
||||||
.terminal-focused {
|
.terminal-focused {
|
||||||
box-shadow: 0 0 0 2px #00ff00;
|
box-shadow: 0 0 0 2px #00ff88;
|
||||||
border-color: #00ff00 !important;
|
border-color: #00ff88 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keyboard capture indicator */
|
/* Keyboard capture indicator */
|
||||||
|
|
@ -205,9 +293,9 @@ body {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
background: rgba(0, 255, 0, 0.1);
|
background: rgba(0, 255, 136, 0.1);
|
||||||
border: 1px solid #00ff00;
|
border: 1px solid #00ff88;
|
||||||
color: #00ff00;
|
color: #00ff88;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -517,14 +605,14 @@ body {
|
||||||
left: 12px;
|
left: 12px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(26, 26, 26, 0.9);
|
||||||
border: 1px solid #444;
|
border: 1px solid #2a2a2a;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #d4d4d4;
|
color: #e4e4e4;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
@ -532,9 +620,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom:hover {
|
.scroll-to-bottom:hover {
|
||||||
background: rgba(0, 0, 0, 0.9);
|
background: rgba(26, 26, 26, 1);
|
||||||
border-color: #666;
|
border-color: #00ff88;
|
||||||
|
color: #00ff88;
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom:active {
|
.scroll-to-bottom:active {
|
||||||
|
|
@ -546,13 +636,13 @@ body {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 8px;
|
bottom: 8px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(26, 26, 26, 0.9);
|
||||||
border: 1px solid #444;
|
border: 1px solid #2a2a2a;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-family: 'Fira Code', monospace;
|
font-family: 'Fira Code', monospace;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #d4d4d4;
|
color: #e4e4e4;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
|
|
@ -580,14 +670,14 @@ body {
|
||||||
right: 12px;
|
right: 12px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(26, 26, 26, 0.9);
|
||||||
border: 1px solid #444;
|
border: 1px solid #2a2a2a;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #d4d4d4;
|
color: #e4e4e4;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
@ -595,9 +685,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.fit-toggle:hover {
|
.fit-toggle:hover {
|
||||||
background: rgba(0, 0, 0, 0.9);
|
background: rgba(26, 26, 26, 1);
|
||||||
border-color: #666;
|
border-color: #00ff88;
|
||||||
|
color: #00ff88;
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fit-toggle:active {
|
.fit-toggle:active {
|
||||||
|
|
@ -605,6 +697,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.fit-toggle.active {
|
.fit-toggle.active {
|
||||||
border-color: #569cd6;
|
border-color: #00ff88;
|
||||||
color: #569cd6;
|
color: #00ff88;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,72 @@ module.exports = {
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
"vs-bg": "#1e1e1e",
|
// Dark theme colors
|
||||||
"vs-text": "#d4d4d4",
|
"dark-bg": "#0a0a0a",
|
||||||
"vs-muted": "#8c8c8c",
|
"dark-bg-secondary": "#1a1a1a",
|
||||||
"vs-accent": "#569cd6",
|
"dark-bg-tertiary": "#242424",
|
||||||
"vs-user": "#6a9955",
|
"dark-border": "#2a2a2a",
|
||||||
"vs-assistant": "#ce9178",
|
"dark-border-light": "#3a3a3a",
|
||||||
"vs-warning": "#f48771",
|
|
||||||
"vs-function": "#dcdcaa",
|
// Text colors
|
||||||
"vs-type": "#4ec9b0",
|
"dark-text": "#e4e4e4",
|
||||||
"vs-border": "#3e3e42",
|
"dark-text-muted": "#7a7a7a",
|
||||||
"vs-border-light": "#5a5a5e",
|
"dark-text-dim": "#5a5a5a",
|
||||||
"vs-bg-secondary": "#2d2d30",
|
|
||||||
"vs-nav": "#3e3e42",
|
// Green accent colors (multiple shades)
|
||||||
"vs-nav-hover": "#4a4a4e",
|
"accent-green": "#00ff88",
|
||||||
"vs-nav-active": "#f48771",
|
"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",
|
"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: [],
|
plugins: [],
|
||||||
};
|
};
|
||||||
Loading…
Reference in a new issue