feat(settings): add project max aspect ratio setting with CSS constraint

This commit is contained in:
Hibryda 2026-03-09 17:27:09 +01:00
parent c6fda19170
commit 92b513dd9d
3 changed files with 49 additions and 1 deletions

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { initTheme } from './lib/stores/theme.svelte'; import { initTheme } from './lib/stores/theme.svelte';
import { getSetting } from './lib/adapters/settings-bridge';
import { isDetachedMode, getDetachedConfig } from './lib/utils/detach'; import { isDetachedMode, getDetachedConfig } from './lib/utils/detach';
import { startAgentDispatcher, stopAgentDispatcher } from './lib/agent-dispatcher'; import { startAgentDispatcher, stopAgentDispatcher } from './lib/agent-dispatcher';
import { loadWorkspace, getActiveTab, setActiveTab, setActiveProject, getEnabledProjects } from './lib/stores/workspace.svelte'; import { loadWorkspace, getActiveTab, setActiveTab, setActiveProject, getEnabledProjects } from './lib/stores/workspace.svelte';
@ -60,6 +61,9 @@
onMount(() => { onMount(() => {
initTheme(); initTheme();
getSetting('project_max_aspect').then(v => {
if (v) document.documentElement.style.setProperty('--project-max-aspect', v);
});
startAgentDispatcher(); startAgentDispatcher();
if (!detached) { if (!detached) {

View file

@ -67,6 +67,7 @@
.project-slot { .project-slot {
flex: 0 0 calc((100% - (var(--visible-count) - 1) * 0.25rem) / var(--visible-count)); flex: 0 0 calc((100% - (var(--visible-count) - 1) * 0.25rem) / var(--visible-count));
min-width: 30rem; min-width: 30rem;
max-width: calc(100vh * var(--project-max-aspect, 1));
display: flex; display: flex;
} }

View file

@ -44,6 +44,7 @@
let uiFontSize = $state(''); let uiFontSize = $state('');
let termFont = $state(''); let termFont = $state('');
let termFontSize = $state(''); let termFontSize = $state('');
let projectMaxAspect = $state('1.0');
let selectedTheme = $state<ThemeId>(getCurrentTheme()); let selectedTheme = $state<ThemeId>(getCurrentTheme());
// Dropdown open states // Dropdown open states
@ -103,13 +104,14 @@
); );
onMount(async () => { onMount(async () => {
const [shell, cwd, font, size, tfont, tsize] = await Promise.all([ const [shell, cwd, font, size, tfont, tsize, aspect] = await Promise.all([
getSetting('default_shell'), getSetting('default_shell'),
getSetting('default_cwd'), getSetting('default_cwd'),
getSetting('ui_font_family'), getSetting('ui_font_family'),
getSetting('ui_font_size'), getSetting('ui_font_size'),
getSetting('term_font_family'), getSetting('term_font_family'),
getSetting('term_font_size'), getSetting('term_font_size'),
getSetting('project_max_aspect'),
]); ]);
defaultShell = shell ?? ''; defaultShell = shell ?? '';
defaultCwd = cwd ?? ''; defaultCwd = cwd ?? '';
@ -117,6 +119,8 @@
uiFontSize = size ?? ''; uiFontSize = size ?? '';
termFont = tfont ?? ''; termFont = tfont ?? '';
termFontSize = tsize ?? ''; termFontSize = tsize ?? '';
projectMaxAspect = aspect ?? '1.0';
applyAspectRatio(projectMaxAspect);
selectedTheme = getCurrentTheme(); selectedTheme = getCurrentTheme();
try { try {
@ -174,6 +178,20 @@
await saveGlobalSetting('term_font_size', size); await saveGlobalSetting('term_font_size', size);
} }
function applyAspectRatio(value: string) {
const num = parseFloat(value);
if (isNaN(num) || num <= 0) return;
document.documentElement.style.setProperty('--project-max-aspect', value);
}
async function handleAspectChange(value: string) {
const num = parseFloat(value);
if (isNaN(num) || num < 0.3 || num > 3.0) return;
projectMaxAspect = value;
applyAspectRatio(value);
await saveGlobalSetting('project_max_aspect', value);
}
async function handleThemeChange(themeId: ThemeId) { async function handleThemeChange(themeId: ThemeId) {
selectedTheme = themeId; selectedTheme = themeId;
themeDropdownOpen = false; themeDropdownOpen = false;
@ -407,6 +425,31 @@
</div> </div>
</div> </div>
</div> </div>
<div class="setting-field">
<span class="setting-label">Project max aspect ratio</span>
<div class="size-control">
<button
class="size-btn"
onclick={() => handleAspectChange((Math.max(0.3, parseFloat(projectMaxAspect) - 0.1)).toFixed(1))}
disabled={parseFloat(projectMaxAspect) <= 0.3}
>&minus;</button>
<input
type="number"
min="0.3"
max="3.0"
step="0.1"
value={projectMaxAspect}
class="size-input"
onchange={e => handleAspectChange((e.target as HTMLInputElement).value)}
/>
<span class="size-unit">w:h</span>
<button
class="size-btn"
onclick={() => handleAspectChange((Math.min(3.0, parseFloat(projectMaxAspect) + 0.1)).toFixed(1))}
disabled={parseFloat(projectMaxAspect) >= 3.0}
>+</button>
</div>
</div>
</div> </div>
</section> </section>