bak
This commit is contained in:
1 parent
cc6b11e61d
commit
b977ee35a8
11 files changed
+1641
-310
No files matched your search
@@ -2,12 +2,15 @@
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import {
|
||||
PhCircle,
|
||||
PhFilmStrip,
|
||||
PhImage,
|
||||
PhImageSquare,
|
||||
PhListBullets,
|
||||
PhPencilSimple,
|
||||
PhPlus,
|
||||
PhSquare,
|
||||
PhTextT,
|
||||
PhTrash,
|
||||
PhUploadSimple,
|
||||
} from '@phosphor-icons/vue'
|
||||
import { useSceneStore } from '@/stores/scene'
|
||||
@@ -65,6 +68,32 @@ function addSampleText() {
|
||||
store.addLayer(asset.id)
|
||||
}
|
||||
|
||||
const clips = computed(() => store.scene.clips ?? [])
|
||||
|
||||
function addClip() {
|
||||
const input = prompt('Name des Clips?', 'Clip')
|
||||
if (input === null) return
|
||||
store.addClip(input)
|
||||
}
|
||||
|
||||
function renameClipPrompt(clipId: string, current: string) {
|
||||
const input = prompt('Neuer Name?', current)
|
||||
if (input === null) return
|
||||
store.renameClip(clipId, input)
|
||||
}
|
||||
|
||||
function deleteClip(clipId: string) {
|
||||
if (!confirm('Clip und alle Instanzen wirklich löschen?')) return
|
||||
store.removeClip(clipId)
|
||||
}
|
||||
|
||||
function onClipDragStart(e: DragEvent, clipId: string) {
|
||||
if (!e.dataTransfer) return
|
||||
e.dataTransfer.effectAllowed = 'copy'
|
||||
e.dataTransfer.setData('application/x-animatr-clip', clipId)
|
||||
e.dataTransfer.setData('text/plain', clipId)
|
||||
}
|
||||
|
||||
async function handleFileSelected(event: Event) {
|
||||
uploadError.value = null
|
||||
const input = event.target as HTMLInputElement
|
||||
@@ -240,6 +269,47 @@ function circlePreviewStyle(asset: Extract<Asset, { kind: 'circle' }>) {
|
||||
</li>
|
||||
<li v-if="!store.scene.assets.length" class="empty">keine Assets</li>
|
||||
</ul>
|
||||
|
||||
<div class="lib-header clips-header">
|
||||
<h4>Clips</h4>
|
||||
<button class="thumb-toggle" title="Neuen Clip anlegen" @click="addClip">
|
||||
<PhPlus :size="12" weight="bold" />
|
||||
</button>
|
||||
</div>
|
||||
<ul class="clips">
|
||||
<li
|
||||
v-for="clip in clips"
|
||||
:key="clip.id"
|
||||
class="clip"
|
||||
:class="{ editing: store.activeClipId === clip.id }"
|
||||
draggable="true"
|
||||
@dragstart="onClipDragStart($event, clip.id)"
|
||||
@dblclick="store.enterClip(clip.id)"
|
||||
>
|
||||
<div class="clip-icon">
|
||||
<PhFilmStrip :size="16" />
|
||||
</div>
|
||||
<div class="clip-meta">
|
||||
<span class="clip-name" :title="clip.name">{{ clip.name }}</span>
|
||||
<span class="clip-sub">
|
||||
{{ clip.layers.length }} Layer · {{ clip.duration.toFixed(1) }}s
|
||||
</span>
|
||||
</div>
|
||||
<div class="clip-actions">
|
||||
<button
|
||||
class="clip-btn"
|
||||
title="Umbenennen"
|
||||
@click.stop="renameClipPrompt(clip.id, clip.name)"
|
||||
>
|
||||
<PhPencilSimple :size="11" />
|
||||
</button>
|
||||
<button class="clip-btn danger" title="Löschen" @click.stop="deleteClip(clip.id)">
|
||||
<PhTrash :size="11" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="!clips.length" class="empty">keine Clips</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -439,4 +509,112 @@ h4 {
|
||||
font-style: italic;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.clips-header {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.clips {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.clip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 8px;
|
||||
background: var(--panel-alt);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: grab;
|
||||
transition: background 140ms var(--ease), border-color 140ms var(--ease);
|
||||
}
|
||||
|
||||
.clip:hover {
|
||||
background: var(--panel-hover);
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
|
||||
.clip:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.clip.editing {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
|
||||
.clip-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
background: var(--bg);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.clip-meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.clip-name {
|
||||
font-size: 12px;
|
||||
color: var(--text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.clip-sub {
|
||||
font-size: 10px;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
|
||||
.clip-actions {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
opacity: 0;
|
||||
transition: opacity 140ms var(--ease);
|
||||
}
|
||||
|
||||
.clip:hover .clip-actions,
|
||||
.clip.editing .clip-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.clip-btn {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: var(--text-dim);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.clip-btn:hover {
|
||||
background: var(--panel);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.clip-btn.danger:hover {
|
||||
background: var(--danger-soft);
|
||||
color: var(--danger);
|
||||
border-color: var(--danger);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user