mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
frontend design tweaks
This commit is contained in:
parent
08bdc5ecb4
commit
ad60da3140
2 changed files with 70 additions and 5 deletions
45
web/src/client/components/copy-icon.ts
Normal file
45
web/src/client/components/copy-icon.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { LitElement, html, css } from 'lit';
|
||||||
|
import { customElement, property } from 'lit/decorators.js';
|
||||||
|
|
||||||
|
@customElement('copy-icon')
|
||||||
|
export class CopyIcon extends LitElement {
|
||||||
|
@property({ type: Number }) size = 16;
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.4;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(:hover) {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
width: var(--icon-size, 16px);
|
||||||
|
height: var(--icon-size, 16px);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
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="copy-icon"
|
||||||
|
>
|
||||||
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||||
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +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 './vibe-terminal-buffer.js';
|
import './vibe-terminal-buffer.js';
|
||||||
|
import './copy-icon.js';
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -146,13 +147,27 @@ export class SessionCard extends LitElement {
|
||||||
textArea.select();
|
textArea.select();
|
||||||
try {
|
try {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
console.log('PID copied to clipboard (fallback):', text);
|
console.log('Text copied to clipboard (fallback):', text);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fallback copy failed:', error);
|
console.error('Fallback copy failed:', error);
|
||||||
}
|
}
|
||||||
document.body.removeChild(textArea);
|
document.body.removeChild(textArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handlePathClick(e: Event) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(this.session.workingDir);
|
||||||
|
console.log('Path copied to clipboard:', this.session.workingDir);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to copy path to clipboard:', error);
|
||||||
|
// Fallback: select text manually
|
||||||
|
this.fallbackCopyToClipboard(this.session.workingDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
|
|
@ -238,18 +253,23 @@ export class SessionCard extends LitElement {
|
||||||
${this.session.pid
|
${this.session.pid
|
||||||
? html`
|
? html`
|
||||||
<span
|
<span
|
||||||
class="cursor-pointer hover:text-accent-green 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 inline-flex items-center gap-1"
|
||||||
@click=${this.handlePidClick}
|
@click=${this.handlePidClick}
|
||||||
title="Click to copy PID"
|
title="Click to copy PID"
|
||||||
>
|
>
|
||||||
PID: ${this.session.pid} <span class="opacity-50">(click to copy)</span>
|
PID: ${this.session.pid} <copy-icon size="14"></copy-icon>
|
||||||
</span>
|
</span>
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs opacity-75 min-w-0 mt-1">
|
<div class="text-xs opacity-75 min-w-0 mt-1">
|
||||||
<div class="truncate" title="${this.session.workingDir}">
|
<div
|
||||||
${this.session.workingDir}
|
class="truncate cursor-pointer hover:text-accent-green transition-colors inline-flex items-center gap-1 max-w-full"
|
||||||
|
title="Click to copy path"
|
||||||
|
@click=${this.handlePathClick}
|
||||||
|
>
|
||||||
|
<span class="truncate">${this.session.workingDir}</span>
|
||||||
|
<copy-icon size="12" class="flex-shrink-0"></copy-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue