desktop: components/apps/settings — settings panel with display/audio/network/about sections
This commit is contained in:
parent
0048eabb60
commit
6beb93b16f
@ -0,0 +1,62 @@
|
||||
<div class="settings">
|
||||
<!-- Sidebar -->
|
||||
<div class="settings-sidebar">
|
||||
<div class="settings-title">Settings</div>
|
||||
@for (section of sections; track section.id) {
|
||||
<button
|
||||
class="settings-nav-item"
|
||||
[class.active]="activeSection() === section.id"
|
||||
(click)="activeSection.set(section.id)"
|
||||
>
|
||||
<span class="nav-icon">{{ section.icon }}</span>
|
||||
<span class="nav-label">{{ section.title }}</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="settings-content">
|
||||
@switch (activeSection()) {
|
||||
@case ('display') {
|
||||
<div class="settings-section">
|
||||
<h3>Display Settings</h3>
|
||||
<div class="setting-row">
|
||||
<label>Frame Buffer Size</label>
|
||||
<input type="number" [ngModel]="frameBufferSize()" min="10" max="300" />
|
||||
</div>
|
||||
<div class="setting-desc">Number of frames to buffer for late-joining viewers (default: 60).</div>
|
||||
</div>
|
||||
}
|
||||
@case ('audio') {
|
||||
<div class="settings-section">
|
||||
<h3>Audio Settings</h3>
|
||||
<div class="setting-desc">Audio settings will be available once the VM agent is connected.</div>
|
||||
</div>
|
||||
}
|
||||
@case ('network') {
|
||||
<div class="settings-section">
|
||||
<h3>Network Settings</h3>
|
||||
<div class="setting-row">
|
||||
<label>Server URL</label>
|
||||
<input type="text" [ngModel]="serverUrl()" />
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label>Idle Timeout (sec)</label>
|
||||
<input type="number" [ngModel]="idleTimeout()" min="30" max="3600" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@case ('about') {
|
||||
<div class="settings-section">
|
||||
<h3>About Butterfly</h3>
|
||||
<div class="about-info">
|
||||
<div class="about-row"><span>Version</span><span>0.1.0</span></div>
|
||||
<div class="about-row"><span>Backend</span><span>Rust / Actix-Web 4</span></div>
|
||||
<div class="about-row"><span>Frontend</span><span>Angular 21</span></div>
|
||||
<div class="about-row"><span>Protocol</span><span>WebSocket + REST</span></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
127
desktop/src/app/components/apps/settings/settings.component.scss
Normal file
127
desktop/src/app/components/apps/settings/settings.component.scss
Normal file
@ -0,0 +1,127 @@
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.settings {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
.settings-sidebar {
|
||||
width: 200px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #404040;
|
||||
padding: 12px 0;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.settings-title {
|
||||
padding: 0 16px 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.settings-nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #ccc;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(0, 120, 212, 0.15);
|
||||
color: #fff;
|
||||
border-left: 2px solid #0078d4;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
flex: 1;
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
max-width: 500px;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 16px;
|
||||
color: #e0e0e0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
label {
|
||||
color: #ccc;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid #555;
|
||||
border-radius: 4px;
|
||||
background: #383838;
|
||||
color: #e0e0e0;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-color: #0078d4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.setting-desc {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.about-info {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.about-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #333;
|
||||
font-size: 13px;
|
||||
|
||||
span:first-child {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
span:last-child {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
interface SettingSection {
|
||||
id: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrl: './settings.component.scss',
|
||||
})
|
||||
export class SettingsComponent {
|
||||
readonly activeSection = signal('display');
|
||||
|
||||
sections: SettingSection[] = [
|
||||
{ id: 'display', title: 'Display', icon: '🖥️' },
|
||||
{ id: 'audio', title: 'Audio', icon: '🔊' },
|
||||
{ id: 'network', title: 'Network', icon: '🌐' },
|
||||
{ id: 'about', title: 'About', icon: 'ℹ️' },
|
||||
];
|
||||
|
||||
readonly serverUrl = signal(window.location.origin);
|
||||
readonly maxSessions = signal('100');
|
||||
readonly frameBufferSize = signal('60');
|
||||
readonly idleTimeout = signal('300');
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user