mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-25 14:57:37 +00:00
Logs are back, baby
This commit is contained in:
parent
ac57f77806
commit
f7e5a09d48
2 changed files with 261 additions and 84 deletions
44
web/src/client/assets/logs.html
Normal file
44
web/src/client/assets/logs.html
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no">
|
||||
<title>VibeTunnel - System Logs</title>
|
||||
<meta name="description" content="View and manage VibeTunnel system logs">
|
||||
|
||||
<!-- Mobile optimizations -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="theme-color" content="#1e1e1e">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png">
|
||||
|
||||
<!-- Styles -->
|
||||
<link href="bundle/styles.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
log-viewer {
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="m-0 p-0" style="background: black;">
|
||||
<log-viewer></log-viewer>
|
||||
|
||||
<script type="module" src="bundle/client-bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -298,105 +298,238 @@ export class LogViewer extends LitElement {
|
|||
return html`
|
||||
${scrollbarStyles}
|
||||
<div class="flex flex-col h-full bg-dark-bg text-dark-text font-mono">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center gap-3 p-4 bg-dark-bg-secondary border-b border-dark-border">
|
||||
<!-- Back button -->
|
||||
<button
|
||||
class="px-3 py-1.5 bg-dark-bg border border-dark-border rounded text-sm text-dark-text hover:border-accent-green hover:text-accent-green transition-colors flex items-center gap-2 flex-shrink-0"
|
||||
@click=${() => (window.location.href = '/')}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
Back
|
||||
</button>
|
||||
<!-- Header - single row on desktop, two rows on mobile -->
|
||||
<div class="bg-dark-bg-secondary border-b border-dark-border p-3 sm:p-4">
|
||||
<!-- Mobile layout (two rows) -->
|
||||
<div class="sm:hidden">
|
||||
<!-- Top row with back button and title -->
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<!-- Back button -->
|
||||
<button
|
||||
class="p-2 bg-dark-bg border border-dark-border rounded text-sm text-dark-text hover:border-accent-green hover:text-accent-green transition-colors flex items-center gap-1 flex-shrink-0"
|
||||
@click=${() => (window.location.href = '/')}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h1 class="text-lg font-bold text-accent-green flex items-center gap-2 flex-shrink-0">
|
||||
<terminal-icon size="24"></terminal-icon>
|
||||
<span>System Logs</span>
|
||||
</h1>
|
||||
<h1
|
||||
class="text-base font-bold text-accent-green flex items-center gap-2 flex-shrink-0"
|
||||
>
|
||||
<terminal-icon size="20"></terminal-icon>
|
||||
<span>System Logs</span>
|
||||
</h1>
|
||||
|
||||
<div class="flex-1 flex flex-wrap gap-2 items-center justify-end">
|
||||
<!-- Search input -->
|
||||
<input
|
||||
type="text"
|
||||
class="px-3 py-1.5 bg-dark-bg border border-dark-border rounded text-sm text-dark-text placeholder-dark-text-muted focus:outline-none focus:border-accent-green transition-colors flex-1 sm:flex-initial sm:w-64 md:w-80"
|
||||
placeholder="Filter logs..."
|
||||
.value=${this.filter}
|
||||
@input=${(e: Event) => {
|
||||
this.filter = (e.target as HTMLInputElement).value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Level filters -->
|
||||
<div class="flex gap-1">
|
||||
${levels.map(
|
||||
(level) => html`
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this.levelFilter.has(
|
||||
level
|
||||
)
|
||||
? level === 'error'
|
||||
? 'bg-status-error text-dark-bg'
|
||||
: level === 'warn'
|
||||
? 'bg-status-warning text-dark-bg'
|
||||
: level === 'debug'
|
||||
? 'bg-dark-text-muted text-dark-bg'
|
||||
: 'bg-dark-text text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => this.toggleLevel(level)}
|
||||
<!-- Auto-scroll toggle (mobile position) -->
|
||||
<div class="ml-auto">
|
||||
<button
|
||||
class="p-2 text-xs uppercase font-bold rounded transition-colors ${this.autoScroll
|
||||
? 'bg-accent-green text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.autoScroll = !this.autoScroll;
|
||||
}}
|
||||
title="Auto Scroll"
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
${level}
|
||||
</button>
|
||||
`
|
||||
)}
|
||||
<path d="M12 5v14M19 12l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Client/Server toggles -->
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showClient
|
||||
? 'bg-orange-500 text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showClient = !this.showClient;
|
||||
<!-- Filters row -->
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<!-- Search input -->
|
||||
<input
|
||||
type="text"
|
||||
class="px-3 py-1.5 bg-dark-bg border border-dark-border rounded text-sm text-dark-text placeholder-dark-text-muted focus:outline-none focus:border-accent-green transition-colors w-full"
|
||||
placeholder="Filter logs..."
|
||||
.value=${this.filter}
|
||||
@input=${(e: Event) => {
|
||||
this.filter = (e.target as HTMLInputElement).value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Filters container -->
|
||||
<div class="flex gap-2 items-center">
|
||||
<!-- Level filters -->
|
||||
<div class="flex gap-1">
|
||||
${levels.map(
|
||||
(level) => html`
|
||||
<button
|
||||
class="px-1.5 py-1 text-xs uppercase font-bold rounded transition-colors ${this.levelFilter.has(
|
||||
level
|
||||
)
|
||||
? level === 'error'
|
||||
? 'bg-status-error text-dark-bg'
|
||||
: level === 'warn'
|
||||
? 'bg-status-warning text-dark-bg'
|
||||
: level === 'debug'
|
||||
? 'bg-dark-text-muted text-dark-bg'
|
||||
: 'bg-dark-text text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => this.toggleLevel(level)}
|
||||
title="${level} logs"
|
||||
>
|
||||
${level === 'error'
|
||||
? 'ERR'
|
||||
: level === 'warn'
|
||||
? 'WRN'
|
||||
: level === 'debug'
|
||||
? 'DBG'
|
||||
: 'LOG'}
|
||||
</button>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
|
||||
<!-- Client/Server toggles -->
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="px-1.5 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showClient
|
||||
? 'bg-orange-500 text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showClient = !this.showClient;
|
||||
}}
|
||||
title="Client logs"
|
||||
>
|
||||
C
|
||||
</button>
|
||||
<button
|
||||
class="px-1.5 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showServer
|
||||
? 'bg-accent-green text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showServer = !this.showServer;
|
||||
}}
|
||||
title="Server logs"
|
||||
>
|
||||
S
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desktop layout (single row) -->
|
||||
<div class="hidden sm:flex items-center gap-3">
|
||||
<!-- Back button -->
|
||||
<button
|
||||
class="px-3 py-1.5 bg-dark-bg border border-dark-border rounded text-sm text-dark-text hover:border-accent-green hover:text-accent-green transition-colors flex items-center gap-2 flex-shrink-0"
|
||||
@click=${() => (window.location.href = '/')}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
CLIENT
|
||||
</button>
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<h1 class="text-lg font-bold text-accent-green flex items-center gap-2 flex-shrink-0">
|
||||
<terminal-icon size="24"></terminal-icon>
|
||||
<span>System Logs</span>
|
||||
</h1>
|
||||
|
||||
<div class="flex-1 flex flex-wrap gap-2 items-center justify-end">
|
||||
<!-- Search input -->
|
||||
<input
|
||||
type="text"
|
||||
class="px-3 py-1.5 bg-dark-bg border border-dark-border rounded text-sm text-dark-text placeholder-dark-text-muted focus:outline-none focus:border-accent-green transition-colors flex-1 sm:flex-initial sm:w-64 md:w-80"
|
||||
placeholder="Filter logs..."
|
||||
.value=${this.filter}
|
||||
@input=${(e: Event) => {
|
||||
this.filter = (e.target as HTMLInputElement).value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Level filters -->
|
||||
<div class="flex gap-1">
|
||||
${levels.map(
|
||||
(level) => html`
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this.levelFilter.has(
|
||||
level
|
||||
)
|
||||
? level === 'error'
|
||||
? 'bg-status-error text-dark-bg'
|
||||
: level === 'warn'
|
||||
? 'bg-status-warning text-dark-bg'
|
||||
: level === 'debug'
|
||||
? 'bg-dark-text-muted text-dark-bg'
|
||||
: 'bg-dark-text text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => this.toggleLevel(level)}
|
||||
>
|
||||
${level}
|
||||
</button>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
|
||||
<!-- Client/Server toggles -->
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showClient
|
||||
? 'bg-orange-500 text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showClient = !this.showClient;
|
||||
}}
|
||||
>
|
||||
CLIENT
|
||||
</button>
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showServer
|
||||
? 'bg-accent-green text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showServer = !this.showServer;
|
||||
}}
|
||||
>
|
||||
SERVER
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Auto-scroll toggle -->
|
||||
<button
|
||||
class="px-2 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.showServer
|
||||
class="px-3 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.autoScroll
|
||||
? 'bg-accent-green text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.showServer = !this.showServer;
|
||||
this.autoScroll = !this.autoScroll;
|
||||
}}
|
||||
>
|
||||
SERVER
|
||||
AUTO SCROLL
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Auto-scroll toggle -->
|
||||
<button
|
||||
class="px-3 py-1 text-xs uppercase font-bold rounded transition-colors ${this
|
||||
.autoScroll
|
||||
? 'bg-accent-green text-dark-bg'
|
||||
: 'bg-dark-bg-tertiary text-dark-text-muted border border-dark-border'}"
|
||||
@click=${() => {
|
||||
this.autoScroll = !this.autoScroll;
|
||||
}}
|
||||
>
|
||||
AUTO SCROLL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue