This commit is contained in:
th committed 2026-04-19 22:32:06 +02:00
1 parent fcefd258eb
commit 6b6157d786
23 files changed
+1140 -237

No files matched your search

+30 -20
View File
@@ -24,7 +24,8 @@ import PropertiesPanel from './components/PropertiesPanel.vue'
import Timeline from './components/Timeline.vue'
import WelcomeDialog from './components/WelcomeDialog.vue'
import TestOverlay from './devtools/TestOverlay.vue'
import { IconButton, Toast } from './components/ui'
import { confirmDialog, DialogsHost, IconButton, promptDialog, Toast } from './components/ui'
import { t } from './i18n'
import { useHistory } from './composables/useHistory'
import { usePlaybackLoop } from './composables/usePlaybackLoop'
import {
@@ -140,8 +141,13 @@ async function saveProject() {
const scene = JSON.parse(JSON.stringify(store.scene))
let name = currentProjectName.value
if (!name) {
const suggested = `Projekt ${new Date().toLocaleDateString()}`
const entered = prompt('Projektname?', suggested)
const suggested = t('app.saveDialog.defaultName', { date: new Date().toLocaleDateString() })
const entered = await promptDialog({
title: t('app.saveDialog.title'),
message: t('app.saveDialog.message'),
defaultValue: suggested,
confirmLabel: t('app.saveDialog.confirm'),
})
if (entered === null) return
name = entered.trim() || suggested
}
@@ -152,7 +158,7 @@ async function saveProject() {
currentProjectId.value = rec.id
currentProjectName.value = rec.name
setLastOpenedId(rec.id)
showSavedToast(`"${rec.name}" gespeichert`)
showSavedToast(t('app.savedToast', { name: rec.name }))
}
function exportProjectFile() {
@@ -167,9 +173,12 @@ async function importFromFile() {
if (!file) return
const hasContent = store.scene.layers.length > 0 || store.scene.assets.length > 0
if (hasContent) {
const ok = confirm(
'Aktuelles Projekt wird durch die geladene Datei ersetzt. Ungespeicherte Änderungen gehen verloren. Fortfahren?',
)
const ok = await confirmDialog({
title: t('app.replaceDialog.title'),
message: t('app.replaceDialog.message'),
confirmLabel: t('app.replaceDialog.confirm'),
variant: 'danger',
})
if (!ok) return
}
try {
@@ -285,7 +294,7 @@ onBeforeUnmount(() => {
icon-weight="bold"
size="md"
:disabled="!history.canUndo.value"
title="Rückgängig (Ctrl+Z)"
:title="t('app.undo')"
@click="history.undo"
/>
<IconButton
@@ -293,7 +302,7 @@ onBeforeUnmount(() => {
icon-weight="bold"
size="md"
:disabled="!history.canRedo.value"
title="Wiederholen (Ctrl+Shift+Z)"
:title="t('app.redo')"
@click="history.redo"
/>
<div class="tsep"></div>
@@ -301,7 +310,7 @@ onBeforeUnmount(() => {
:icon="PhSkipBack"
icon-weight="fill"
size="md"
title="Zum Anfang"
:title="t('app.jumpToStart')"
@click="rewind"
/>
<IconButton
@@ -309,14 +318,14 @@ onBeforeUnmount(() => {
icon-weight="fill"
size="md"
variant="primary"
:title="store.playing ? 'Pause (Space)' : 'Play (Space)'"
:title="store.playing ? t('app.pause') : t('app.play')"
@click="store.togglePlay()"
/>
<IconButton
:icon="PhStop"
icon-weight="fill"
size="md"
title="Stop"
:title="t('app.stop')"
@click="stop"
/>
<span class="time">{{ store.playhead.toFixed(2) }}s / {{ store.scene.duration }}s</span>
@@ -325,18 +334,18 @@ onBeforeUnmount(() => {
<span v-if="currentProjectName" class="project-name" :title="currentProjectName">
{{ currentProjectName }}
</span>
<button class="icon-btn" title="Zuletzt verwendete Projekte" @click="welcomeOpen = true">
<button class="icon-btn" :title="t('app.recentProjects')" @click="welcomeOpen = true">
<PhFolderOpen :size="16" />
</button>
<button class="icon-btn" title="Projekt speichern (in Browser-Speicher)" @click="saveProject">
<button class="icon-btn" :title="t('app.saveProject')" @click="saveProject">
<PhFloppyDisk :size="16" />
</button>
<button class="icon-btn" title="Document Settings" @click="settingsOpen = true">
<button class="icon-btn" :title="t('app.documentSettings')" @click="settingsOpen = true">
<PhGearSix :size="16" />
</button>
<button class="export-btn" title="Exportieren" @click="exportOpen = true">
<button class="export-btn" :title="t('app.export')" @click="exportOpen = true">
<PhExport :size="14" weight="bold" />
Export
{{ t('app.export') }}
</button>
</div>
</header>
@@ -345,7 +354,7 @@ onBeforeUnmount(() => {
<div v-if="store.activeClipId" class="scope-footer">
<button class="scope-back" @click="store.exitClip">
<PhArrowLeft :size="12" weight="bold" />
Haupt-Timeline
{{ t('app.mainTimeline') }}
</button>
<span class="scope-current" :title="store.activeClip?.name ?? ''">
<PhFilmStrip :size="12" />
@@ -359,7 +368,7 @@ onBeforeUnmount(() => {
<div
class="tl-resize"
:class="{ resizing }"
title="Timeline-Höhe ziehen"
:title="t('app.dragResize')"
@pointerdown="onTimelineResizeStart"
@pointermove="onTimelineResizeMove"
@pointerup="onTimelineResizeEnd"
@@ -371,6 +380,7 @@ onBeforeUnmount(() => {
<ExportDialog v-model="exportOpen" />
<TestOverlay v-model="testsOpen" />
<FullscreenPreview v-model="fullscreenOpen" />
<DialogsHost />
<WelcomeDialog
v-model="welcomeOpen"
@open="openFromRecent"
@@ -379,7 +389,7 @@ onBeforeUnmount(() => {
@export="exportProjectFile"
/>
<Toast :visible="!!loadError" variant="error">
<strong>Projekt konnte nicht geladen werden.</strong>
<strong>{{ t('app.loadFailed') }}</strong>
<span>{{ loadError }}</span>
</Toast>
<Toast :visible="!!savedToast" variant="info" :message="savedToast ?? ''" />