面板布局更新

This commit is contained in:
tianmo committed 2026-10-24 19:30:32 +08:00
1 parent a417c9119d
commit 7069b168de
18 files changed
+220 -145

No files matched your search

+21 -4
View File
@@ -1,6 +1,7 @@
<template>
<div class="timeline">
<!-- 控制按钮 -->
<Teleport defer to="#timeline-controls-host">
<div class="tl-controls">
<button class="tl-btn" :class="{ on: store.timeline.playing }" @click="store.togglePlay()" :title="store.timeline.playing ? $t('timeline.pause') : $t('timeline.play')">
{{ store.timeline.playing ? '❚❚' : '▶' }}
@@ -65,6 +66,7 @@
</label>
<span class="tl-zoom">{{ zoomLabel }}</span>
</div>
</Teleport>
<!-- 时间轴视口 -->
<div
@@ -145,6 +147,8 @@ type SysLike = { id: number; config: any }
const store = useParticleStore()
const { t } = useI18n()
const vpRef = ref<HTMLElement | null>(null)
const viewportWidth = ref(0)
let viewportResizeObserver: ResizeObserver | null = null
const animationMenuRef = ref<HTMLElement | null>(null)
const animationMenuOpen = ref(false)
const animationNameDraft = ref('animation')
@@ -203,8 +207,21 @@ function onDocumentPointerDown(event: PointerEvent) {
if (!animationMenuRef.value?.contains(event.target as Node)) animationMenuOpen.value = false
}
onMounted(() => document.addEventListener('pointerdown', onDocumentPointerDown))
onBeforeUnmount(() => document.removeEventListener('pointerdown', onDocumentPointerDown))
onMounted(() => {
document.addEventListener('pointerdown', onDocumentPointerDown)
const viewport = vpRef.value
if (!viewport) return
viewportWidth.value = viewport.clientWidth
viewportResizeObserver = new ResizeObserver(([entry]) => {
viewportWidth.value = Math.max(1, entry.contentRect.width)
})
viewportResizeObserver.observe(viewport)
})
onBeforeUnmount(() => {
document.removeEventListener('pointerdown', onDocumentPointerDown)
viewportResizeObserver?.disconnect()
viewportResizeObserver = null
})
// 时间轴与固定步长模拟统一读取 Store;默认 1 秒 = 30 帧,与 Spine 对齐。
const fps = computed(() => Math.max(1, store.timeline.fps || 30))
@@ -258,7 +275,7 @@ function commitPlaybackEnd() {
// 每像素代表的帧数(视口宽度内放下 viewFrames 帧)
function pxPerF() {
const vw = vpRef.value?.clientWidth || 600
const vw = viewportWidth.value || vpRef.value?.clientWidth || 600
return viewFrames.value / vw
}
@@ -494,7 +511,7 @@ function onSpineBarDown(e: PointerEvent, spine: SpineSceneObject) {
<style scoped>
.timeline { height: 100%; background: #12121c; border-top: 1px solid #2a2a3c; display: flex; flex-direction: column; padding: 6px 10px; gap: 4px; }
.tl-controls { display: flex; align-items: center; gap: 8px; }
.tl-controls { display: flex; width: 100%; align-items: center; gap: 8px; flex-wrap: wrap; }
.tl-btn { width: 30px; height: 26px; background: #1e1e2e; border: 1px solid #2e2e44; border-radius: 6px; color: #aab; font-size: 12px; cursor: pointer; }
.tl-btn.on { background: #3a5a8c; color: #fff; border-color: #5a7ab8; }
.tl-ab-loop { position: relative; }