feat(ui): add file explorer, TTS UI, views and routing
Add a file tree UI and corresponding composable for local file management. Introduce TTS menu and player components for voice synthesis integration. Add new EditorView and DocsView routes and update SettingsPanel view switching. Enhance Mermaid plugin with improved styling and action buttons.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<Transition name="tts-menu-fade">
|
||||
<div
|
||||
v-if="visible"
|
||||
class="tts-menu"
|
||||
:style="menuStyle"
|
||||
@mousedown.stop
|
||||
>
|
||||
<button class="tts-menu__btn" @click="$emit('speak')" :disabled="loading">
|
||||
<svg v-if="!loading" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 5L6 9H2v6h4l5 4V5z"/>
|
||||
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"/>
|
||||
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"/>
|
||||
</svg>
|
||||
<svg v-else class="tts-menu__spinner" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
|
||||
</svg>
|
||||
{{ loading ? '生成中...' : '朗读' }}
|
||||
</button>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
x: { type: Number, default: 0 },
|
||||
y: { type: Number, default: 0 },
|
||||
loading: { type: Boolean, default: false },
|
||||
})
|
||||
|
||||
defineEmits(['speak'])
|
||||
|
||||
const menuStyle = computed(() => ({
|
||||
left: `${props.x}px`,
|
||||
top: `${props.y}px`,
|
||||
transform: 'translate(-50%, -100%)',
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tts-menu {
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tts-menu__btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 14px;
|
||||
border: 1px solid var(--panel-border);
|
||||
border-radius: 20px;
|
||||
background: var(--panel-bg);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
color: var(--app-text);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--panel-shadow);
|
||||
white-space: nowrap;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.tts-menu__btn:hover:not(:disabled) {
|
||||
background: var(--btn-hover-bg);
|
||||
color: var(--btn-hover-fg);
|
||||
border-color: var(--btn-hover-bg);
|
||||
}
|
||||
|
||||
.tts-menu__btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.tts-menu__spinner {
|
||||
animation: tts-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes tts-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.tts-menu-fade-enter-active,
|
||||
.tts-menu-fade-leave-active {
|
||||
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.tts-menu-fade-enter-from,
|
||||
.tts-menu-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, calc(-100% + 4px));
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user