feat(v3): redesign project workspace layout + emoji icons
- ProjectBox: CSS grid layout (header|session|terminal zones) - AgentPane: bottom-anchored prompt, full-width form - Icons: emoji replacing Nerd Font codepoints (cross-platform) - SettingsTab: emoji picker grid (24 icons, 8-column popup) - CSS: px to rem conversions across ProjectGrid, TerminalTabs, ProjectBox
This commit is contained in:
parent
b8001dc56c
commit
5c657d0daa
6 changed files with 128 additions and 52 deletions
|
|
@ -553,18 +553,17 @@
|
||||||
|
|
||||||
.prompt-area {
|
.prompt-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 24px;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-form {
|
.prompt-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 0.5rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-input {
|
.prompt-input {
|
||||||
|
|
@ -942,8 +941,7 @@
|
||||||
/* Session toolbar */
|
/* Session toolbar */
|
||||||
.session-toolbar {
|
.session-toolbar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
margin-bottom: 0.5rem;
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-row {
|
.toolbar-row {
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,13 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.project-box {
|
.project-box {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-rows: auto 1fr auto;
|
||||||
min-width: 480px;
|
min-width: 30rem;
|
||||||
scroll-snap-align: start;
|
scroll-snap-align: start;
|
||||||
background: var(--ctp-base);
|
background: var(--ctp-base);
|
||||||
border: 1px solid var(--ctp-surface0);
|
border: 1px solid var(--ctp-surface0);
|
||||||
border-radius: 6px;
|
border-radius: 0.375rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: border-color 0.15s;
|
transition: border-color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
@ -61,17 +61,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-session-area {
|
.project-session-area {
|
||||||
flex: 1;
|
display: flex;
|
||||||
min-height: 200px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-terminal-area {
|
.project-terminal-area {
|
||||||
flex-shrink: 0;
|
height: 16rem;
|
||||||
min-height: 120px;
|
min-height: 8rem;
|
||||||
border-top: 1px solid var(--ctp-surface0);
|
border-top: 1px solid var(--ctp-surface0);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -57,16 +57,16 @@
|
||||||
<style>
|
<style>
|
||||||
.project-grid {
|
.project-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 0.25rem;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
scroll-snap-type: x mandatory;
|
scroll-snap-type: x mandatory;
|
||||||
padding: 4px;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-slot {
|
.project-slot {
|
||||||
flex: 0 0 calc((100% - (var(--visible-count) - 1) * 4px) / var(--visible-count));
|
flex: 0 0 calc((100% - (var(--visible-count) - 1) * 0.25rem) / var(--visible-count));
|
||||||
min-width: 480px;
|
min-width: 30rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
style="--accent: var({accentVar})"
|
style="--accent: var({accentVar})"
|
||||||
{onclick}
|
{onclick}
|
||||||
>
|
>
|
||||||
<span class="project-icon">{project.icon || '\uf120'}</span>
|
<span class="project-icon">{project.icon || '📁'}</span>
|
||||||
<span class="project-name">{project.name}</span>
|
<span class="project-name">{project.name}</span>
|
||||||
<span class="project-id">({project.identifier})</span>
|
<span class="project-id">({project.identifier})</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -29,9 +29,8 @@
|
||||||
.project-header {
|
.project-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 0.375rem;
|
||||||
padding: 4px 10px;
|
padding: 0.375rem 0.625rem;
|
||||||
height: 28px;
|
|
||||||
background: var(--ctp-mantle);
|
background: var(--ctp-mantle);
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
|
|
@ -54,9 +53,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-icon {
|
.project-icon {
|
||||||
font-family: 'NerdFontsSymbols Nerd Font', 'Symbols Nerd Font Mono', monospace;
|
font-size: 0.85rem;
|
||||||
font-size: 0.9rem;
|
line-height: 1;
|
||||||
color: var(--accent);
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-name {
|
.project-name {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@
|
||||||
import { THEME_LIST, getPalette, type ThemeId } from '../../styles/themes';
|
import { THEME_LIST, getPalette, type ThemeId } from '../../styles/themes';
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
|
||||||
|
const PROJECT_ICONS = [
|
||||||
|
'📁', '🚀', '🤖', '🌐', '🔧', '🎮', '📱', '💻',
|
||||||
|
'🔬', '📊', '🎨', '🔒', '💬', '📦', '⚡', '🧪',
|
||||||
|
'🏗️', '📝', '🎯', '💡', '🔥', '🛠️', '🧩', '🗄️',
|
||||||
|
];
|
||||||
|
|
||||||
let activeGroupId = $derived(getActiveGroupId());
|
let activeGroupId = $derived(getActiveGroupId());
|
||||||
let activeGroup = $derived(getActiveGroup());
|
let activeGroup = $derived(getActiveGroup());
|
||||||
let activeProjectId = $derived(getActiveProjectId());
|
let activeProjectId = $derived(getActiveProjectId());
|
||||||
|
|
@ -194,7 +200,7 @@
|
||||||
name: newName.trim(),
|
name: newName.trim(),
|
||||||
identifier: deriveIdentifier(newName.trim()),
|
identifier: deriveIdentifier(newName.trim()),
|
||||||
description: '',
|
description: '',
|
||||||
icon: '\uf120',
|
icon: '📁',
|
||||||
cwd: newCwd.trim(),
|
cwd: newCwd.trim(),
|
||||||
profile: 'default',
|
profile: 'default',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
@ -455,14 +461,29 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label class="project-field">
|
<div class="project-field icon-field">
|
||||||
<span class="field-label">Icon</span>
|
<span class="field-label">Icon</span>
|
||||||
<input
|
<button
|
||||||
value={project.icon}
|
class="icon-trigger"
|
||||||
onchange={e => updateProject(activeGroupId, project.id, { icon: (e.target as HTMLInputElement).value })}
|
onclick={(e) => {
|
||||||
style="width: 60px"
|
const btn = e.currentTarget as HTMLElement;
|
||||||
/>
|
const popup = btn.nextElementSibling as HTMLElement;
|
||||||
</label>
|
popup.classList.toggle('visible');
|
||||||
|
}}
|
||||||
|
>{project.icon || '📁'}</button>
|
||||||
|
<div class="icon-picker">
|
||||||
|
{#each PROJECT_ICONS as emoji}
|
||||||
|
<button
|
||||||
|
class="icon-option"
|
||||||
|
class:active={project.icon === emoji}
|
||||||
|
onclick={(e) => {
|
||||||
|
updateProject(activeGroupId, project.id, { icon: emoji });
|
||||||
|
((e.currentTarget as HTMLElement).closest('.icon-picker') as HTMLElement).classList.remove('visible');
|
||||||
|
}}
|
||||||
|
>{emoji}</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<label class="project-field">
|
<label class="project-field">
|
||||||
<span class="field-label">Enabled</span>
|
<span class="field-label">Enabled</span>
|
||||||
<input
|
<input
|
||||||
|
|
@ -806,6 +827,71 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-field {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-trigger {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--ctp-base);
|
||||||
|
border: 1px solid var(--ctp-surface1);
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-trigger:hover {
|
||||||
|
border-color: var(--ctp-overlay0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-picker {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 20;
|
||||||
|
background: var(--ctp-mantle);
|
||||||
|
border: 1px solid var(--ctp-surface1);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
padding: 0.375rem;
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
gap: 2px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
width: max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-picker.visible {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-option {
|
||||||
|
width: 1.75rem;
|
||||||
|
height: 1.75rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-option:hover {
|
||||||
|
background: var(--ctp-surface0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-option.active {
|
||||||
|
background: var(--ctp-surface1);
|
||||||
|
border-color: var(--ctp-blue);
|
||||||
|
}
|
||||||
|
|
||||||
.add-form {
|
.add-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1px;
|
gap: 1px;
|
||||||
height: 26px;
|
padding: 0 0.25rem;
|
||||||
padding: 0 4px;
|
|
||||||
background: var(--ctp-mantle);
|
background: var(--ctp-mantle);
|
||||||
border-bottom: 1px solid var(--ctp-surface0);
|
border-bottom: 1px solid var(--ctp-surface0);
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
|
@ -114,14 +113,14 @@
|
||||||
.tab {
|
.tab {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 0.25rem;
|
||||||
padding: 2px 8px;
|
padding: 0.25rem 0.5rem;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--ctp-overlay1);
|
color: var(--ctp-overlay1);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 3px 3px 0 0;
|
border-radius: 0.1875rem 0.1875rem 0 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: color 0.1s, background 0.1s;
|
transition: color 0.1s, background 0.1s;
|
||||||
}
|
}
|
||||||
|
|
@ -137,13 +136,8 @@
|
||||||
border-bottom: 1px solid var(--ctp-blue);
|
border-bottom: 1px solid var(--ctp-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-icon {
|
|
||||||
font-family: 'NerdFontsSymbols Nerd Font', 'Symbols Nerd Font Mono', monospace;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-title {
|
.tab-title {
|
||||||
max-width: 100px;
|
max-width: 6.25rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +148,7 @@
|
||||||
color: var(--ctp-overlay0);
|
color: var(--ctp-overlay0);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0 2px;
|
padding: 0 0.125rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,8 +162,8 @@
|
||||||
color: var(--ctp-overlay0);
|
color: var(--ctp-overlay0);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 2px 6px;
|
padding: 0.125rem 0.375rem;
|
||||||
border-radius: 3px;
|
border-radius: 0.1875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-add:hover {
|
.tab-add:hover {
|
||||||
|
|
@ -201,13 +195,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-first {
|
.add-first {
|
||||||
padding: 6px 16px;
|
padding: 0.375rem 1rem;
|
||||||
background: var(--ctp-surface0);
|
background: var(--ctp-surface0);
|
||||||
border: 1px solid var(--ctp-surface1);
|
border: 1px solid var(--ctp-surface1);
|
||||||
border-radius: 4px;
|
border-radius: 0.25rem;
|
||||||
color: var(--ctp-subtext0);
|
color: var(--ctp-subtext0);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-first:hover {
|
.add-first:hover {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue