优化: UI 去 AI 味——SVG 图标体系替代 emoji/字符图标,首页产品化重设计(文档网格+右侧新建栏),主色统一 #5b5bd6,补键盘焦点可见性
This commit is contained in:
@@ -2,11 +2,12 @@
|
||||
LibraryModal.vue — 演示文库弹窗
|
||||
===================================================================== -->
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
|
||||
import type { LibItem, Slide } from '../../core/types'
|
||||
import { store, resolveBg } from '../../core/store'
|
||||
import { appPrompt, appConfirm } from '../../core/dialog'
|
||||
import ElementView from '../editor/ElementView.vue'
|
||||
import Icon from '../common/Icon.vue'
|
||||
|
||||
const props = defineProps<{ visible: boolean }>()
|
||||
const emit = defineEmits<{
|
||||
@@ -18,6 +19,18 @@ const emit = defineEmits<{
|
||||
|
||||
const libVersion = ref(0)
|
||||
const nameInput = ref('')
|
||||
const opsOpenId = ref<string | null>(null)
|
||||
|
||||
function toggleOps(id: string) {
|
||||
opsOpenId.value = opsOpenId.value === id ? null : id
|
||||
}
|
||||
|
||||
function onDocClick(e: MouseEvent) {
|
||||
const t = e.target as HTMLElement
|
||||
if (!t.closest('.lib-ops')) opsOpenId.value = null
|
||||
}
|
||||
onMounted(() => document.addEventListener('mousedown', onDocClick))
|
||||
onUnmounted(() => document.removeEventListener('mousedown', onDocClick))
|
||||
|
||||
/** 读文库列表(非响应式,靠 libVersion 触发重算) */
|
||||
const library = computed<LibItem[]>(() => {
|
||||
@@ -86,6 +99,7 @@ function onNewBlank() {
|
||||
|
||||
function onOpen(id: string) {
|
||||
if (store.loadFromLibrary(id)) {
|
||||
opsOpenId.value = null
|
||||
toast('已打开')
|
||||
emit('open-deck')
|
||||
emit('close')
|
||||
@@ -95,6 +109,7 @@ function onOpen(id: string) {
|
||||
async function onRename(id: string) {
|
||||
const cur = store.getLibrary().find(x => x.id === id)
|
||||
const name = await appPrompt('重命名', { defaultValue: cur ? cur.name : '' })
|
||||
opsOpenId.value = null
|
||||
if (name != null && name.trim()) {
|
||||
store.renameInLibrary(id, name.trim())
|
||||
bump()
|
||||
@@ -102,12 +117,14 @@ async function onRename(id: string) {
|
||||
}
|
||||
|
||||
function onDuplicate(id: string) {
|
||||
opsOpenId.value = null
|
||||
store.duplicateInLibrary(id)
|
||||
toast('已复制')
|
||||
bump()
|
||||
}
|
||||
|
||||
async function onDelete(id: string) {
|
||||
opsOpenId.value = null
|
||||
if (await appConfirm('删除这份演示?', '此操作不可撤销', { danger: true, okText: '删除' })) {
|
||||
store.deleteFromLibrary(id)
|
||||
toast('已删除')
|
||||
@@ -119,13 +136,21 @@ async function onDelete(id: string) {
|
||||
<template>
|
||||
<div class="modal-mask lib-modal-mask" :class="{ hidden: !visible }" @click.self="emit('close')">
|
||||
<div class="modal lib-modal">
|
||||
<h3>演示文库</h3>
|
||||
<div class="lib-head">
|
||||
<h3>演示文库</h3>
|
||||
<button class="btn ghost" @click="onNewBlank">+ 新建空白</button>
|
||||
</div>
|
||||
<p class="modal-tip">保存多套演示文稿到本地,随时切换。</p>
|
||||
|
||||
<div class="lib-save-row">
|
||||
<input type="text" v-model="nameInput" :placeholder="placeholder" @keydown="onNameKeydown" />
|
||||
<button class="btn primary" @click="onSave">存入文库</button>
|
||||
<button class="btn" @click="onNewBlank">新建空白</button>
|
||||
<div class="lib-save-card">
|
||||
<div class="lib-save-title">
|
||||
<span><Icon name="save" :size="14" /> 保存当前演示</span>
|
||||
<span v-if="activeId" class="lib-autosave-flag">改动已自动同步到文库</span>
|
||||
</div>
|
||||
<div class="lib-save-row">
|
||||
<input type="text" v-model="nameInput" :placeholder="placeholder" @keydown="onNameKeydown" />
|
||||
<button class="btn primary" @click="onSave">存入文库</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lib-hint">共 {{ libCount }} 份</div>
|
||||
@@ -142,10 +167,13 @@ async function onDelete(id: string) {
|
||||
<div class="lib-meta">{{ (it.deck && it.deck.slides ? it.deck.slides.length : 0) + ' 页 · ' + formatTime(it.updatedAt || it.createdAt) }}</div>
|
||||
</div>
|
||||
<div class="lib-ops">
|
||||
<button class="btn" @click="onOpen(it.id)">打开</button>
|
||||
<button class="btn" @click="onRename(it.id)">重命名</button>
|
||||
<button class="btn" @click="onDuplicate(it.id)">复制</button>
|
||||
<button class="btn danger" @click="onDelete(it.id)">删除</button>
|
||||
<button class="btn primary small" @click="onOpen(it.id)">打开</button>
|
||||
<button class="btn" @click="toggleOps(it.id)">⋯</button>
|
||||
<div v-if="opsOpenId === it.id" class="ops-menu">
|
||||
<button @click="onRename(it.id)">重命名</button>
|
||||
<button @click="onDuplicate(it.id)">复制</button>
|
||||
<button class="danger" @click="onDelete(it.id)">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -156,3 +184,29 @@ async function onDelete(id: string) {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.lib-head { display: flex; align-items: center; justify-content: space-between; }
|
||||
.lib-head h3 { margin: 0; }
|
||||
.lib-save-card {
|
||||
border: 1px solid color-mix(in srgb, var(--ui-primary, #5b5bd6) 22%, transparent);
|
||||
background: color-mix(in srgb, var(--ui-primary, #5b5bd6) 5%, #fff);
|
||||
border-radius: 10px;
|
||||
padding: 12px 14px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.lib-save-title { font-size: 13px; font-weight: 600; color: var(--ui-text, #1e293b); margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between; }
|
||||
.lib-autosave-flag { font-size: 11px; font-weight: 400; color: var(--ui-muted, #64748b); }
|
||||
.lib-save-row { display: flex; gap: 8px; }
|
||||
.lib-save-row input { flex: 1; }
|
||||
.lib-ops { position: relative; }
|
||||
.ops-menu {
|
||||
position: absolute; right: 0; top: calc(100% + 4px);
|
||||
background: #fff; border: 1px solid var(--ui-border, #e2e8f0);
|
||||
border-radius: 8px; box-shadow: 0 4px 16px rgba(15,23,42,.12);
|
||||
min-width: 96px; z-index: 10; overflow: hidden; padding: 4px 0;
|
||||
}
|
||||
.ops-menu button { display: block; width: 100%; text-align: left; padding: 6px 12px; border: none; background: none; font-size: 12px; cursor: pointer; }
|
||||
.ops-menu button:hover { background: var(--ui-hover, #f1f5f9); }
|
||||
.ops-menu button.danger { color: var(--ui-danger, #dc2626); }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user