mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
new linter
This commit is contained in:
parent
60d4556a58
commit
f59df3c645
18 changed files with 406 additions and 292 deletions
|
|
@ -1,34 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<!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">
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no"
|
||||
/>
|
||||
<title>VibeTunnel - Terminal Multiplexer</title>
|
||||
<meta name="description" content="Interactive terminal sessions in your browser with real-time streaming and mobile support">
|
||||
<meta
|
||||
name="description"
|
||||
content="Interactive terminal sessions in your browser with real-time streaming and mobile support"
|
||||
/>
|
||||
|
||||
<!-- PWA and 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">
|
||||
<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">
|
||||
<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" />
|
||||
|
||||
<!-- Single high-res Apple/Android/Web App icon -->
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
|
||||
<!-- Web App Manifest (important for iOS/Android home screen apps) -->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<!-- Styles -->
|
||||
<link href="bundle/styles.css" rel="stylesheet">
|
||||
<link href="bundle/styles.css" rel="stylesheet" />
|
||||
|
||||
<!-- Mobile viewport and address bar handling -->
|
||||
<style>
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
|
|
@ -67,7 +74,7 @@
|
|||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="m-0 p-0" style="background: black;">
|
||||
<body class="m-0 p-0" style="background: black">
|
||||
<vibetunnel-app></vibetunnel-app>
|
||||
|
||||
<!-- Mobile viewport height fix -->
|
||||
|
|
@ -98,6 +105,5 @@
|
|||
</script>
|
||||
|
||||
<script type="module" src="bundle/client-bundle.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<!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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<link href="bundle/styles.css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
|
|
@ -36,7 +40,7 @@
|
|||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="m-0 p-0" style="background: black;">
|
||||
<body class="m-0 p-0" style="background: black">
|
||||
<log-viewer></log-viewer>
|
||||
|
||||
<script type="module" src="bundle/client-bundle.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Monaco Diff Test</title>
|
||||
<style>
|
||||
body {
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
<script src="/monaco-editor/vs/loader.js"></script>
|
||||
<script>
|
||||
require.config({ paths: { 'vs': '/monaco-editor/vs' } });
|
||||
require.config({ paths: { vs: '/monaco-editor/vs' } });
|
||||
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
// Create original content
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
ignoreTrimWhitespace: false,
|
||||
renderIndicators: true,
|
||||
originalEditable: false,
|
||||
diffAlgorithm: 'advanced'
|
||||
diffAlgorithm: 'advanced',
|
||||
});
|
||||
|
||||
// Set the models
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
diffEditor.setModel({
|
||||
original: originalModel,
|
||||
modified: modifiedModel
|
||||
modified: modifiedModel,
|
||||
});
|
||||
|
||||
// Log some debug info
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Monaco Editor Test</title>
|
||||
<link href="../../bundle/styles.css" rel="stylesheet">
|
||||
<link href="../../bundle/styles.css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: #0a0b0d;
|
||||
color: #e0e0e0;
|
||||
min-height: 100vh;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Terminal Test</title>
|
||||
<link href="../../bundle/styles.css" rel="stylesheet">
|
||||
<link href="../../bundle/styles.css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
|
|
|
|||
|
|
@ -110,10 +110,7 @@ describe('AuthLogin', () => {
|
|||
|
||||
const authHandler = vi.fn();
|
||||
const noAuthElement = await fixture<AuthLogin>(html`
|
||||
<auth-login
|
||||
.authClient=${mockAuthClient}
|
||||
@auth-success=${authHandler}>
|
||||
</auth-login>
|
||||
<auth-login .authClient=${mockAuthClient} @auth-success=${authHandler}> </auth-login>
|
||||
`);
|
||||
|
||||
// Wait for auto-login
|
||||
|
|
|
|||
|
|
@ -168,7 +168,10 @@ export class AuthLogin extends LitElement {
|
|||
${
|
||||
this.error
|
||||
? html`
|
||||
<div class="bg-status-error text-dark-bg px-3 py-1.5 rounded mb-3 font-mono text-xs sm:text-sm" data-testid="error-message">
|
||||
<div
|
||||
class="bg-status-error text-dark-bg px-3 py-1.5 rounded mb-3 font-mono text-xs sm:text-sm"
|
||||
data-testid="error-message"
|
||||
>
|
||||
${this.error}
|
||||
<button
|
||||
@click=${() => {
|
||||
|
|
@ -210,7 +213,10 @@ export class AuthLogin extends LitElement {
|
|||
<!-- Password Login Section (Primary) -->
|
||||
<div class="p-5 sm:p-8">
|
||||
<div class="flex flex-col items-center mb-4 sm:mb-6">
|
||||
<div class="w-24 h-24 sm:w-28 sm:h-28 rounded-full mb-3 sm:mb-4 overflow-hidden" style="box-shadow: 0 0 25px rgba(124, 230, 161, 0.3);">
|
||||
<div
|
||||
class="w-24 h-24 sm:w-28 sm:h-28 rounded-full mb-3 sm:mb-4 overflow-hidden"
|
||||
style="box-shadow: 0 0 25px rgba(124, 230, 161, 0.3);"
|
||||
>
|
||||
${
|
||||
this.userAvatar
|
||||
? html`
|
||||
|
|
@ -223,8 +229,14 @@ export class AuthLogin extends LitElement {
|
|||
/>
|
||||
`
|
||||
: html`
|
||||
<div class="w-full h-full bg-dark-bg-secondary flex items-center justify-center">
|
||||
<svg class="w-12 h-12 sm:w-14 sm:h-14 text-dark-text-muted" fill="currentColor" viewBox="0 0 20 20">
|
||||
<div
|
||||
class="w-full h-full bg-dark-bg-secondary flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="w-12 h-12 sm:w-14 sm:h-14 text-dark-text-muted"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
|
@ -269,7 +281,9 @@ export class AuthLogin extends LitElement {
|
|||
<!-- Avatar for SSH-only mode -->
|
||||
<div class="ssh-key-item p-6 sm:p-8">
|
||||
<div class="flex flex-col items-center mb-4 sm:mb-6">
|
||||
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-full mb-2 sm:mb-3 overflow-hidden border-2 border-dark-border">
|
||||
<div
|
||||
class="w-16 h-16 sm:w-20 sm:h-20 rounded-full mb-2 sm:mb-3 overflow-hidden border-2 border-dark-border"
|
||||
>
|
||||
${
|
||||
this.userAvatar
|
||||
? html`
|
||||
|
|
@ -282,8 +296,14 @@ export class AuthLogin extends LitElement {
|
|||
/>
|
||||
`
|
||||
: html`
|
||||
<div class="w-full h-full bg-dark-bg-secondary flex items-center justify-center">
|
||||
<svg class="w-8 h-8 sm:w-10 sm:h-10 text-dark-text-muted" fill="currentColor" viewBox="0 0 20 20">
|
||||
<div
|
||||
class="w-full h-full bg-dark-bg-secondary flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8 sm:w-10 sm:h-10 text-dark-text-muted"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
|
@ -326,7 +346,11 @@ export class AuthLogin extends LitElement {
|
|||
<div class="w-2 h-2 rounded-full bg-accent-green"></div>
|
||||
<span class="font-mono text-xs sm:text-sm">SSH Key Management</span>
|
||||
</div>
|
||||
<button class="btn-ghost text-xs" data-testid="manage-keys" @click=${this.handleShowSSHKeyManager}>
|
||||
<button
|
||||
class="btn-ghost text-xs"
|
||||
data-testid="manage-keys"
|
||||
@click=${this.handleShowSSHKeyManager}
|
||||
>
|
||||
Manage Keys
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -667,8 +667,16 @@ export class FileBrowser extends LitElement {
|
|||
${
|
||||
file.isSymlink
|
||||
? html`
|
||||
<svg class="w-3 h-3 text-dark-text-muted absolute -bottom-1 -right-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z" clip-rule="evenodd"/>
|
||||
<svg
|
||||
class="w-3 h-3 text-dark-text-muted absolute -bottom-1 -right-1"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
`
|
||||
: ''
|
||||
|
|
@ -739,8 +747,16 @@ export class FileBrowser extends LitElement {
|
|||
${
|
||||
this.selectedFile.isSymlink
|
||||
? html`
|
||||
<svg class="w-3 h-3 text-dark-text-muted absolute -bottom-1 -right-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z" clip-rule="evenodd"/>
|
||||
<svg
|
||||
class="w-3 h-3 text-dark-text-muted absolute -bottom-1 -right-1"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
`
|
||||
: ''
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ export class FullHeader extends HeaderBase {
|
|||
</button>
|
||||
${this.renderUserMenu()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -101,9 +100,7 @@ export class FullHeader extends HeaderBase {
|
|||
<div
|
||||
class="absolute right-0 top-full mt-1 bg-dark-surface border border-dark-border rounded-lg shadow-lg py-1 z-50 min-w-36"
|
||||
>
|
||||
<div
|
||||
class="px-3 py-2 text-sm text-dark-text-muted border-b border-dark-border"
|
||||
>
|
||||
<div class="px-3 py-2 text-sm text-dark-text-muted border-b border-dark-border">
|
||||
${this.authMethod || 'authenticated'}
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -46,10 +46,7 @@ describe('SessionCard', () => {
|
|||
|
||||
// Create component
|
||||
element = await fixture<SessionCard>(html`
|
||||
<session-card
|
||||
.session=${mockSession}
|
||||
.authClient=${mockAuthClient}
|
||||
></session-card>
|
||||
<session-card .session=${mockSession} .authClient=${mockAuthClient}></session-card>
|
||||
`);
|
||||
|
||||
await element.updateComplete;
|
||||
|
|
|
|||
|
|
@ -227,7 +227,9 @@ export class SessionCard extends LitElement {
|
|||
? 'shadow-[0_0_0_2px_#00ff88] shadow-glow-green-sm'
|
||||
: ''
|
||||
}"
|
||||
style="view-transition-name: session-${this.session.id}; --session-id: session-${this.session.id}"
|
||||
style="view-transition-name: session-${this.session.id}; --session-id: session-${
|
||||
this.session.id
|
||||
}"
|
||||
data-session-id="${this.session.id}"
|
||||
@click=${this.handleCardClick}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -48,10 +48,7 @@ describe('SessionCreateForm', () => {
|
|||
|
||||
// Create component
|
||||
element = await fixture<SessionCreateForm>(html`
|
||||
<session-create-form
|
||||
.authClient=${mockAuthClient}
|
||||
.visible=${true}
|
||||
></session-create-form>
|
||||
<session-create-form .authClient=${mockAuthClient} .visible=${true}></session-create-form>
|
||||
`);
|
||||
|
||||
await element.updateComplete;
|
||||
|
|
@ -81,10 +78,7 @@ describe('SessionCreateForm', () => {
|
|||
});
|
||||
|
||||
const newElement = await fixture<SessionCreateForm>(html`
|
||||
<session-create-form
|
||||
.authClient=${mockAuthClient}
|
||||
.visible=${true}
|
||||
></session-create-form>
|
||||
<session-create-form .authClient=${mockAuthClient} .visible=${true}></session-create-form>
|
||||
`);
|
||||
|
||||
expect(newElement.workingDir).toBe('/home/user/projects');
|
||||
|
|
|
|||
|
|
@ -408,9 +408,7 @@ export class SessionCreateForm extends LitElement {
|
|||
<div class="mb-4 flex items-center justify-between">
|
||||
<div class="flex-1 pr-4">
|
||||
<span class="text-dark-text text-sm">Spawn window</span>
|
||||
<p class="text-xs text-dark-text-muted mt-1">
|
||||
Opens native terminal window
|
||||
</p>
|
||||
<p class="text-xs text-dark-text-muted mt-1">Opens native terminal window</p>
|
||||
</div>
|
||||
<button
|
||||
role="switch"
|
||||
|
|
|
|||
|
|
@ -281,9 +281,19 @@ export class SessionList extends LitElement {
|
|||
<div class="flex-1 min-w-0">
|
||||
<div
|
||||
class="text-sm font-mono text-accent-green truncate"
|
||||
title="${session.name || (Array.isArray(session.command) ? session.command.join(' ') : session.command)}"
|
||||
title="${
|
||||
session.name ||
|
||||
(Array.isArray(session.command)
|
||||
? session.command.join(' ')
|
||||
: session.command)
|
||||
}"
|
||||
>
|
||||
${session.name || (Array.isArray(session.command) ? session.command.join(' ') : session.command)}
|
||||
${
|
||||
session.name ||
|
||||
(Array.isArray(session.command)
|
||||
? session.command.join(' ')
|
||||
: session.command)
|
||||
}
|
||||
</div>
|
||||
<div class="text-xs text-dark-text-muted truncate">
|
||||
${formatPathForDisplay(session.workingDir)}
|
||||
|
|
@ -401,11 +411,18 @@ export class SessionList extends LitElement {
|
|||
? 'border-dark-border bg-dark-bg-secondary text-dark-text-muted hover:bg-dark-bg-tertiary hover:text-dark-text'
|
||||
: 'border-dark-border bg-dark-bg-tertiary text-dark-text hover:bg-dark-bg-secondary'
|
||||
}"
|
||||
@click=${() => this.dispatchEvent(new CustomEvent('hide-exited-change', { detail: !this.hideExited }))}
|
||||
@click=${() =>
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('hide-exited-change', { detail: !this.hideExited })
|
||||
)}
|
||||
>
|
||||
<div class="flex items-center gap-2 sm:gap-3">
|
||||
<span class="hidden sm:inline">${this.hideExited ? 'Show' : 'Hide'} Exited (${exitedSessions.length})</span>
|
||||
<span class="sm:hidden">${this.hideExited ? 'Show' : 'Hide'} (${exitedSessions.length})</span>
|
||||
<span class="hidden sm:inline"
|
||||
>${this.hideExited ? 'Show' : 'Hide'} Exited (${exitedSessions.length})</span
|
||||
>
|
||||
<span class="sm:hidden"
|
||||
>${this.hideExited ? 'Show' : 'Hide'} (${exitedSessions.length})</span
|
||||
>
|
||||
<div
|
||||
class="w-8 h-4 rounded-full transition-colors duration-200 ${
|
||||
this.hideExited ? 'bg-dark-surface' : 'bg-dark-bg'
|
||||
|
|
@ -444,7 +461,11 @@ export class SessionList extends LitElement {
|
|||
@click=${this.handleCleanupExited}
|
||||
?disabled=${this.cleaningExited}
|
||||
>
|
||||
<span class="hidden sm:inline">${this.cleaningExited ? 'Cleaning...' : `Clean Exited (${exitedSessions.length})`}</span>
|
||||
<span class="hidden sm:inline"
|
||||
>${
|
||||
this.cleaningExited ? 'Cleaning...' : `Clean Exited (${exitedSessions.length})`
|
||||
}</span
|
||||
>
|
||||
<span class="sm:hidden">${this.cleaningExited ? 'Cleaning...' : 'Clean'}</span>
|
||||
</button>
|
||||
`
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ describe('SessionView', () => {
|
|||
fetchMock = setupFetchMock();
|
||||
|
||||
// Create component
|
||||
element = await fixture<SessionView>(html`
|
||||
<session-view></session-view>
|
||||
`);
|
||||
element = await fixture<SessionView>(html` <session-view></session-view> `);
|
||||
|
||||
await element.updateComplete;
|
||||
});
|
||||
|
|
@ -69,9 +67,7 @@ describe('SessionView', () => {
|
|||
configurable: true,
|
||||
});
|
||||
|
||||
const mobileElement = await fixture<SessionView>(html`
|
||||
<session-view></session-view>
|
||||
`);
|
||||
const mobileElement = await fixture<SessionView>(html` <session-view></session-view> `);
|
||||
|
||||
await mobileElement.updateComplete;
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,9 @@ export class SidebarHeader extends HeaderBase {
|
|||
this.killingAll
|
||||
? html`
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<div class="w-3 h-3 border-2 border-dark-bg border-t-transparent rounded-full animate-spin"></div>
|
||||
<div
|
||||
class="w-3 h-3 border-2 border-dark-bg border-t-transparent rounded-full animate-spin"
|
||||
></div>
|
||||
<span>Killing...</span>
|
||||
</div>
|
||||
`
|
||||
|
|
@ -165,7 +167,9 @@ export class SidebarHeader extends HeaderBase {
|
|||
title="User menu"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
|
||||
<path
|
||||
d="M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
${
|
||||
|
|
|
|||
|
|
@ -82,12 +82,7 @@ describe('Terminal', () => {
|
|||
|
||||
it('should handle custom dimensions', async () => {
|
||||
const customElement = await fixture<Terminal>(html`
|
||||
<vibe-terminal
|
||||
session-id="test-789"
|
||||
cols="120"
|
||||
rows="40"
|
||||
font-size="16">
|
||||
</vibe-terminal>
|
||||
<vibe-terminal session-id="test-789" cols="120" rows="40" font-size="16"> </vibe-terminal>
|
||||
`);
|
||||
|
||||
await customElement.updateComplete;
|
||||
|
|
|
|||
|
|
@ -341,30 +341,66 @@ body.sessions-showing .session-flex-responsive > session-card {
|
|||
}
|
||||
|
||||
/* Stagger animation when showing exited sessions */
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(1) { animation-delay: 0s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(2) { animation-delay: 0.05s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(3) { animation-delay: 0.1s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(4) { animation-delay: 0.15s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(5) { animation-delay: 0.2s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(6) { animation-delay: 0.25s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(7) { animation-delay: 0.3s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(8) { animation-delay: 0.35s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(n+9) { animation-delay: 0.4s; }
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(2) {
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(3) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(4) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(5) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(6) {
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(7) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(8) {
|
||||
animation-delay: 0.35s;
|
||||
}
|
||||
body.sessions-showing .session-flex-responsive > session-card:nth-child(n + 9) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
/* Compact mode animations */
|
||||
body.sessions-showing .space-y-2 > div {
|
||||
animation: sessionFlow 0.4s ease-out backwards;
|
||||
}
|
||||
|
||||
body.sessions-showing .space-y-2 > div:nth-child(1) { animation-delay: 0s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(2) { animation-delay: 0.05s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(3) { animation-delay: 0.1s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(4) { animation-delay: 0.15s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(5) { animation-delay: 0.2s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(6) { animation-delay: 0.25s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(7) { animation-delay: 0.3s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(8) { animation-delay: 0.35s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(n+9) { animation-delay: 0.4s; }
|
||||
body.sessions-showing .space-y-2 > div:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(2) {
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(3) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(4) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(5) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(6) {
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(7) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(8) {
|
||||
animation-delay: 0.35s;
|
||||
}
|
||||
body.sessions-showing .space-y-2 > div:nth-child(n + 9) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes sessionFlow {
|
||||
from {
|
||||
|
|
@ -393,15 +429,33 @@ body.initial-session-load .session-flex-responsive > session-card {
|
|||
}
|
||||
|
||||
/* Stagger animation for initial load */
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(1) { animation-delay: 0s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(2) { animation-delay: 0.05s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(3) { animation-delay: 0.1s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(4) { animation-delay: 0.15s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(5) { animation-delay: 0.2s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(6) { animation-delay: 0.25s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(7) { animation-delay: 0.3s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(8) { animation-delay: 0.35s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(n+9) { animation-delay: 0.4s; }
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(2) {
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(3) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(4) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(5) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(6) {
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(7) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(8) {
|
||||
animation-delay: 0.35s;
|
||||
}
|
||||
body.initial-session-load .session-flex-responsive > session-card:nth-child(n + 9) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
/* View transition specific styles for initial load */
|
||||
::view-transition-old(root) {
|
||||
|
|
@ -417,13 +471,21 @@ body.initial-session-load ::view-transition-new(root) {
|
|||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* View transition names for smoother morphing */
|
||||
|
|
|
|||
Loading…
Reference in a new issue