Settings-Dialog neu: drei Gruppen, festes Zeilen-Grid, Sofort-Schreiber abgesetzt
Darstellung (Titel/Theme/Dock-Icon), Ordner (Projekt/Arbeitsordner/Archiv) und Session (Todoliste) als Gruppen mit Eyebrow-Überschriften; jede Zeile im Grid Label | Wert | Aktionen. Pfade ~-kontrahiert mit vollem Pfad im Hover-Pop. Die Ordner-Gruppe schreibt sofort und ist als eigene Fläche abgesetzt (eigener Hinweis); „gilt ab nächstem Start" hängt an der Darstellungs-Gruppe statt global. Nur ProjectList.vue + i18n-Schlüssel.
This commit is contained in:
+168
-31
@@ -152,6 +152,11 @@ const THEME_NAMES: [string, string][] = [
|
|||||||
["one-light", "One Light"],
|
["one-light", "One Light"],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Anzeige: Home-Anteil ~-kontrahiert; der volle Pfad steht im Hover-Pop.
|
||||||
|
function contractHome(p: string): string {
|
||||||
|
return p.replace(/^\/(?:home|Users)\/[^/]+/, "~");
|
||||||
|
}
|
||||||
|
|
||||||
interface TerminalSettings {
|
interface TerminalSettings {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -644,66 +649,114 @@ onUnmounted(() => window.clearInterval(timer));
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="settings" class="overlay">
|
<div v-if="settings" class="overlay">
|
||||||
<div class="dialog">
|
<div class="dialog settings-dialog">
|
||||||
<h3>{{ $t("projects.terminal", { name: settings.name }) }}</h3>
|
<h3>{{ $t("projects.terminal", { name: settings.name }) }}</h3>
|
||||||
<label class="field">
|
|
||||||
{{ $t("projects.title") }}
|
<section class="sgroup">
|
||||||
|
<h4 class="eyebrow">{{ $t("projects.groupAppearance") }}</h4>
|
||||||
|
<label class="srow">
|
||||||
|
<span class="slbl">{{ $t("projects.title") }}</span>
|
||||||
|
<span class="sval">
|
||||||
<input v-model="settings.title" :placeholder="settings.name" />
|
<input v-model="settings.title" :placeholder="settings.name" />
|
||||||
|
</span>
|
||||||
|
<span class="sacts"></span>
|
||||||
</label>
|
</label>
|
||||||
<label class="field">
|
<label class="srow">
|
||||||
{{ $t("projects.theme") }}
|
<span class="slbl">{{ $t("projects.theme") }}</span>
|
||||||
|
<span class="sval">
|
||||||
<select v-model="settings.theme">
|
<select v-model="settings.theme">
|
||||||
<option v-for="[value, label] in THEME_NAMES" :key="value" :value="value">
|
<option v-for="[value, label] in THEME_NAMES" :key="value" :value="value">
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
</span>
|
||||||
|
<span class="sacts"></span>
|
||||||
</label>
|
</label>
|
||||||
<label class="field">
|
<div class="srow">
|
||||||
{{ $t("projects.dockIcon") }}
|
<span class="slbl">{{ $t("projects.dockIcon") }}</span>
|
||||||
<span class="icon-row">
|
<span class="sval">
|
||||||
|
<span v-if="settings.icon" class="spath hover-pop">
|
||||||
|
{{ settings.icon.split("/").pop() }}
|
||||||
|
<span class="pop pop-path">{{ settings.icon }}</span>
|
||||||
|
</span>
|
||||||
|
<span v-else class="spath muted">{{ $t("projects.defaultIcon") }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="sacts">
|
||||||
<button @click="pickIcon">{{ $t("projects.chooseFile") }}</button>
|
<button @click="pickIcon">{{ $t("projects.chooseFile") }}</button>
|
||||||
<button v-if="settings.icon" @click="settings.icon = null">
|
<button v-if="settings.icon" @click="settings.icon = null">
|
||||||
{{ $t("projects.remove") }}
|
{{ $t("projects.remove") }}
|
||||||
</button>
|
</button>
|
||||||
<span v-if="settings.icon" class="icon-path hover-pop">
|
|
||||||
{{ settings.icon.split("/").pop() }}
|
|
||||||
<span class="pop pop-path">{{ settings.icon }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="icon-path">{{ $t("projects.defaultIcon") }}</span>
|
</div>
|
||||||
|
<p class="ghint">{{ $t("projects.appliesNextStart") }}</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="sgroup instant">
|
||||||
|
<h4 class="eyebrow">{{ $t("projects.groupFolders") }}</h4>
|
||||||
|
<div class="srow">
|
||||||
|
<span class="slbl">{{ $t("projects.projectDir") }}</span>
|
||||||
|
<span class="sval">
|
||||||
|
<span class="spath hover-pop">
|
||||||
|
{{ contractHome(settings.path) }}
|
||||||
|
<span class="pop pop-path">{{ settings.path }}</span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</span>
|
||||||
<label class="field field-top">
|
<span class="sacts">
|
||||||
{{ $t("projects.workDir") }}
|
|
||||||
<span class="workdirs">
|
|
||||||
<span class="icon-row">
|
|
||||||
<span class="icon-path">{{ settings.path }}</span>
|
|
||||||
<button @click="changeProjectDir">{{ $t("projects.changeDir") }}</button>
|
<button @click="changeProjectDir">{{ $t("projects.changeDir") }}</button>
|
||||||
</span>
|
</span>
|
||||||
<span v-for="wd in settings.workDirs" :key="wd" class="icon-row">
|
</div>
|
||||||
<span class="icon-path">{{ wd }}</span>
|
<div v-for="(wd, i) in settings.workDirs" :key="wd" class="srow">
|
||||||
|
<span class="slbl">{{ i === 0 ? $t("projects.workDir") : "" }}</span>
|
||||||
|
<span class="sval">
|
||||||
|
<span class="spath hover-pop">
|
||||||
|
{{ contractHome(wd) }}
|
||||||
|
<span class="pop pop-path">{{ wd }}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="sacts">
|
||||||
<button @click="removeWorkDir(wd)">{{ $t("projects.remove") }}</button>
|
<button @click="removeWorkDir(wd)">{{ $t("projects.remove") }}</button>
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="srow">
|
||||||
|
<span class="slbl">{{ settings.workDirs.length ? "" : $t("projects.workDir") }}</span>
|
||||||
|
<span class="sval"></span>
|
||||||
|
<span class="sacts">
|
||||||
<button @click="addWorkDir">{{ $t("projects.addWorkDir") }}</button>
|
<button @click="addWorkDir">{{ $t("projects.addWorkDir") }}</button>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</div>
|
||||||
<label class="field">
|
<div class="srow">
|
||||||
{{ $t("projects.archive") }}
|
<span class="slbl">{{ $t("projects.archive") }}</span>
|
||||||
<span class="icon-row">
|
<span class="sval">
|
||||||
<span class="icon-path">{{ settings.archiveHome ?? $t("projects.archiveNone") }}</span>
|
<span v-if="settings.archiveHome" class="spath hover-pop">
|
||||||
|
{{ contractHome(settings.archiveHome) }}
|
||||||
|
<span class="pop pop-path">{{ settings.archiveHome }}</span>
|
||||||
|
</span>
|
||||||
|
<span v-else class="spath muted">{{ $t("projects.archiveNone") }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="sacts">
|
||||||
<button @click="chooseArchive">{{ $t("projects.changeDir") }}</button>
|
<button @click="chooseArchive">{{ $t("projects.changeDir") }}</button>
|
||||||
<button v-if="settings.archiveHome" @click="clearArchive">
|
<button v-if="settings.archiveHome" @click="clearArchive">
|
||||||
{{ $t("projects.remove") }}
|
{{ $t("projects.remove") }}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</div>
|
||||||
<label class="field">
|
<p class="ghint">{{ $t("projects.writesImmediately") }}</p>
|
||||||
{{ $t("projects.todo") }}
|
</section>
|
||||||
<span class="checkline">
|
|
||||||
|
<section class="sgroup">
|
||||||
|
<h4 class="eyebrow">{{ $t("projects.groupSession") }}</h4>
|
||||||
|
<div class="srow">
|
||||||
|
<span class="slbl">{{ $t("projects.todo") }}</span>
|
||||||
|
<span class="sval">
|
||||||
|
<label class="checkline">
|
||||||
<input v-model="settings.todo" type="checkbox" />
|
<input v-model="settings.todo" type="checkbox" />
|
||||||
{{ $t("projects.todoDesc") }}
|
{{ $t("projects.todoDesc") }}
|
||||||
</span>
|
|
||||||
</label>
|
</label>
|
||||||
<p class="hint">{{ $t("projects.appliesNextStart") }}</p>
|
</span>
|
||||||
|
<span class="sacts"></span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button @click="settings = null">{{ $t("projects.cancel") }}</button>
|
<button @click="settings = null">{{ $t("projects.cancel") }}</button>
|
||||||
<button class="primary" @click="saveSettings">
|
<button class="primary" @click="saveSettings">
|
||||||
@@ -732,3 +785,87 @@ onUnmounted(() => window.clearInterval(timer));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Settings-Dialog: festes Grid Label | Wert | Aktionen in drei Gruppen. */
|
||||||
|
.settings-dialog {
|
||||||
|
width: 36rem;
|
||||||
|
max-width: 36rem;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sgroup {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.7rem 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sofort-Schreiber (Ordner/Archiv) als abgesetzte Fläche — hier gibt es
|
||||||
|
keinen Speichern-Schritt, der Rest des Dialogs speichert erst am Ende. */
|
||||||
|
.sgroup.instant {
|
||||||
|
background: var(--crust);
|
||||||
|
border: 1px solid var(--surface0);
|
||||||
|
border-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
margin: 0 0 0.15rem;
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.09em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.srow {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 7.5rem 1fr auto;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
min-height: 1.9rem;
|
||||||
|
color: var(--subtext);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sval {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sval input,
|
||||||
|
.sval select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sacts {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.4rem;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spath {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--subtext);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spath.muted {
|
||||||
|
color: var(--overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghint {
|
||||||
|
margin: 0.1rem 0 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-dialog .actions {
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ const de = {
|
|||||||
"Nur aus Liste nehmen entfernt den Eintrag; der Ordner bleibt unangetastet.",
|
"Nur aus Liste nehmen entfernt den Eintrag; der Ordner bleibt unangetastet.",
|
||||||
todo: "Todoliste",
|
todo: "Todoliste",
|
||||||
todoDesc: "OFFENE-PUNKTE.md bei jedem Sessionstart einspielen",
|
todoDesc: "OFFENE-PUNKTE.md bei jedem Sessionstart einspielen",
|
||||||
|
groupAppearance: "Darstellung",
|
||||||
|
groupFolders: "Ordner",
|
||||||
|
groupSession: "Session",
|
||||||
|
writesImmediately: "Änderungen hier schreiben sofort — ohne Speichern.",
|
||||||
},
|
},
|
||||||
pools: {
|
pools: {
|
||||||
pool: "Pool",
|
pool: "Pool",
|
||||||
@@ -206,6 +210,10 @@ const en: typeof de = {
|
|||||||
"Remove from list only drops the entry; the folder stays untouched.",
|
"Remove from list only drops the entry; the folder stays untouched.",
|
||||||
todo: "Todo list",
|
todo: "Todo list",
|
||||||
todoDesc: "Inject OFFENE-PUNKTE.md at every session start",
|
todoDesc: "Inject OFFENE-PUNKTE.md at every session start",
|
||||||
|
groupAppearance: "Appearance",
|
||||||
|
groupFolders: "Folders",
|
||||||
|
groupSession: "Session",
|
||||||
|
writesImmediately: "Changes here are written immediately — no save step.",
|
||||||
},
|
},
|
||||||
pools: {
|
pools: {
|
||||||
pool: "Pool",
|
pool: "Pool",
|
||||||
|
|||||||
Reference in New Issue
Block a user