悬浮导航
This commit is contained in:
1 parent
cffbd49eff
commit
a417c9119d
31 files changed
+1577
-1326
No files matched your search
+59
-5
@@ -6,14 +6,38 @@
|
||||
:aria-hidden="transferProgress.visible ? 'true' : undefined"
|
||||
>
|
||||
<!-- 参数面板:可在系统设置中切换左右位置,宽度可拖。 -->
|
||||
<div class="parameter-panel" :style="{ width: panelW + 'px' }">
|
||||
<div v-show="showParameterPanel" class="parameter-panel" :style="{ width: panelW + 'px' }">
|
||||
<ParticlePanel />
|
||||
</div>
|
||||
<div class="resizer-col" @pointerdown="onPanelDrag"></div>
|
||||
<div v-show="showParameterPanel" class="resizer-col" @pointerdown="onPanelDrag"></div>
|
||||
|
||||
<!-- 右列:上=画布区,下=时间轴区(高度可拖) -->
|
||||
<div class="right">
|
||||
<div class="stage-area"><Stage /></div>
|
||||
<div class="stage-area">
|
||||
<Stage />
|
||||
<nav
|
||||
v-if="store.settings.floatingMenuEnabled"
|
||||
class="floating-section-nav"
|
||||
role="tablist"
|
||||
:aria-label="$t('settings.floatingMenu')"
|
||||
>
|
||||
<button
|
||||
v-for="(section, index) in PARTICLE_SECTIONS"
|
||||
:key="section.key"
|
||||
type="button"
|
||||
role="tab"
|
||||
class="floating-section-tab"
|
||||
:class="{ selected: activeSection === section.key && canUseSection(section.key) }"
|
||||
:disabled="!canUseSection(section.key)"
|
||||
:aria-selected="activeSection === section.key && canUseSection(section.key)"
|
||||
:title="canUseSection(section.key) ? $t(section.titleKey) : $t('settings.floatingMenuParticleOnly')"
|
||||
@click="activateSection(section.key)"
|
||||
>
|
||||
<span class="floating-section-index">{{ index + 1 }}</span>
|
||||
<span class="floating-section-label">{{ $t(section.titleKey) }}</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="resizer-row" @pointerdown="onTimelineDrag" :title="$t('app.resizeTimeline')"></div>
|
||||
<div class="timeline-area" :style="{ height: timelineH + 'px' }">
|
||||
<Timeline />
|
||||
@@ -24,7 +48,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useParticleStore } from './store/particleStore'
|
||||
import { installSystemSettingsCache } from './editor/systemSettings'
|
||||
import Stage from './views/Stage.vue'
|
||||
@@ -32,9 +56,13 @@ import ParticlePanel from './views/ParticlePanel.vue'
|
||||
import Timeline from './views/Timeline.vue'
|
||||
import TransferProgressOverlay from './views/TransferProgressOverlay.vue'
|
||||
import { transferProgress } from './editor/transferProgress'
|
||||
import { provideParticlePanel } from './views/particle-panel/particlePanelContext'
|
||||
import { PARTICLE_SECTIONS } from './views/particle-panel/particleSections'
|
||||
|
||||
const store = useParticleStore()
|
||||
installSystemSettingsCache(store)
|
||||
const { activeSection, activateSection, canUseSection } = provideParticlePanel()
|
||||
const showParameterPanel = computed(() => !store.settings.floatingMenuEnabled || activeSection.value !== null)
|
||||
const panelW = ref(360)
|
||||
const timelineH = ref(180)
|
||||
|
||||
@@ -77,7 +105,33 @@ function onTimelineDrag(e: PointerEvent) {
|
||||
.panel-right .right { order: 1; }
|
||||
.panel-right .resizer-col { order: 2; }
|
||||
.panel-right .parameter-panel { order: 3; }
|
||||
.stage-area { flex: 1; min-height: 0; overflow: clip; }
|
||||
.stage-area { position: relative; flex: 1; min-height: 0; overflow: clip; }
|
||||
.floating-section-nav {
|
||||
position: absolute; right: 12px; top: 72px; z-index: 6; display: flex;
|
||||
width: clamp(184px, 15vw, 236px); max-height: calc(100% - 92px);
|
||||
flex-direction: column; gap: 5px; overflow-y: auto; box-sizing: border-box; padding: 8px;
|
||||
border: 1px solid rgba(79, 91, 121, .72); border-radius: 10px;
|
||||
background: rgba(15, 18, 29, .9); box-shadow: 0 12px 30px rgba(0, 0, 0, .36);
|
||||
scrollbar-width: thin; scrollbar-color: #3a455e transparent;
|
||||
}
|
||||
.floating-section-tab {
|
||||
display: flex; width: 100%; min-height: 40px; flex: 0 0 auto; align-items: center; gap: 9px;
|
||||
padding: 0 10px; border: 1px solid #2d3548; border-radius: 8px;
|
||||
background: #191e2c; color: #aeb9cf; font: inherit; font-size: 12px; text-align: left; cursor: pointer;
|
||||
}
|
||||
.floating-section-tab:hover:not(:disabled) { border-color: rgba(112, 121, 167, .45); background: #242b40; color: #f0f3fb; }
|
||||
.floating-section-tab.selected {
|
||||
border-color: #6f69db; background: #37365e; color: #f5f4ff;
|
||||
box-shadow: inset 3px 0 #8580ff;
|
||||
}
|
||||
.floating-section-tab:focus-visible { outline: 2px solid #8b86ff; outline-offset: 1px; }
|
||||
.floating-section-tab:disabled { color: #596476; cursor: not-allowed; opacity: .58; }
|
||||
.floating-section-index {
|
||||
display: grid; width: 20px; height: 20px; flex: 0 0 20px; place-items: center;
|
||||
border-radius: 5px; background: #252d40; color: #8390ad; font-size: 10px; font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.floating-section-tab.selected .floating-section-index { background: #7771e8; color: #fff; }
|
||||
.floating-section-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.resizer-row { height: 4px; cursor: row-resize; background: #1c1c2a; border-top: 1px solid #2a2a3c; border-bottom: 1px solid #2a2a3c; flex-shrink: 0; }
|
||||
.resizer-row:hover { background: #3a5a8c; }
|
||||
.timeline-area { position: relative; z-index: 10; flex-shrink: 0; overflow: visible; }
|
||||
|
||||
Reference in new issue
Block a user