refactor: 替换Tabs、Modal、Message、TextArea、Drawer

This commit is contained in:
pipipi-pikachu 2023-09-24 16:17:07 +08:00
parent a869633a30
commit 9206ef8596
33 changed files with 218 additions and 413 deletions

View File

@ -47,6 +47,7 @@ const handleClick = () => {
color: $textColor;
border-radius: $borderRadius;
user-select: none;
letter-spacing: 2px;
cursor: pointer;
&.default {

View File

@ -80,6 +80,7 @@ import { computed, onMounted, ref, watch } from 'vue'
import tinycolor, { type ColorFormats } from 'tinycolor2'
import { debounce } from 'lodash'
import { toCanvas } from 'html-to-image'
import message from '@/utils/message'
import Alpha from './Alpha.vue'
import Checkboard from './Checkboard.vue'
@ -87,8 +88,6 @@ import Hue from './Hue.vue'
import Saturation from './Saturation.vue'
import EditableInput from './EditableInput.vue'
import { message } from 'ant-design-vue'
const props = withDefaults(defineProps<{
modelValue?: string
}>(), {

View File

@ -1,12 +1,15 @@
<template>
<Teleport to="body">
<Transition :name="`drawer-slide-${placement}`">
<Transition :name="`drawer-slide-${placement}`"
@afterLeave="contentVisible = false"
@before-enter="contentVisible = true"
>
<div :class="['drawer', placement]" v-show="visible" :style="{ width: props.width + 'px' }">
<div class="header">
<slot name="title"></slot>
<span class="close-btn" @click="emit('update:visible', false)"><IconClose /></span>
</div>
<div class="content" v-if="visible" :style="contentStyle">
<div class="content" v-if="contentVisible" :style="contentStyle">
<slot></slot>
</div>
</div>
@ -15,7 +18,7 @@
</template>
<script lang="ts" setup>
import { computed, type CSSProperties } from 'vue'
import { computed, ref, type CSSProperties } from 'vue'
const props = withDefaults(defineProps<{
visible: boolean
@ -31,6 +34,8 @@ const emit = defineEmits<{
(event: 'update:visible', payload: boolean): void
}>()
const contentVisible = ref(false)
const contentStyle = computed(() => {
return {
width: props.width + 'px',

View File

@ -17,26 +17,19 @@
</div>
</div>
<div class="right">
<div class="tabs">
<div
class="tab"
:class="{ 'active': tab.value === toolbarState }"
v-for="tab in tabs"
:key="tab.value"
@click="toolbarState = tab.value"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="toolbarState"
card
/>
<div class="content">
<div class="symbol" v-if="toolbarState === 'symbol'">
<div class="symbol-tabs">
<div
class="symbol-tab"
:class="{ 'active': selectedSymbolKey === group.type }"
v-for="group in symbolList"
:key="group.type"
@click="selectedSymbolKey = group.type"
>{{group.label}}</div>
</div>
<Tabs
:tabs="symbolTabs"
v-model:value="selectedSymbolKey"
spaceBetween
:tabsStyle="{ margin: '10px 10px 0' }"
/>
<div class="symbol-pool">
<div class="symbol-item" v-for="item in symbolPool" :key="item.latex" @click="insertSymbol(item.latex)">
<SymbolContent :latex="item.latex" />
@ -69,25 +62,22 @@
import { computed, onMounted, ref } from 'vue'
import { hfmath } from './hfmath'
import { FORMULA_LIST, SYMBOL_LIST } from '@/configs/latex'
import message from '@/utils/message'
import FormulaContent from './FormulaContent.vue'
import SymbolContent from './SymbolContent.vue'
import Button from '../Button.vue'
import TextArea from '../TextArea.vue'
import Tabs from '../Tabs.vue'
import {
Button,
Input,
message,
} from 'ant-design-vue'
const TextArea = Input.TextArea
interface Tab {
interface TabItem {
key: 'symbol' | 'formula'
label: string
value: 'symbol' | 'formula'
}
const tabs: Tab[] = [
{ label: '常用符号', value: 'symbol' },
{ label: '预置公式', value: 'formula' },
const tabs: TabItem[] = [
{ label: '常用符号', key: 'symbol' },
{ label: '预置公式', key: 'formula' },
]
interface LatexResult {
@ -109,7 +99,11 @@ const emit = defineEmits<{
}>()
const formulaList = FORMULA_LIST
const symbolList = SYMBOL_LIST
const symbolTabs = SYMBOL_LIST.map(item => ({
label: item.label,
key: item.type,
}))
const latex = ref('')
const toolbarState = ref<'symbol' | 'formula'>('symbol')
@ -160,6 +154,7 @@ const insertSymbol = (latex: string) => {
height: 100%;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.input-area {
flex: 1;
@ -186,6 +181,7 @@ const insertSymbol = (latex: string) => {
}
.placeholder {
color: #888;
font-size: 13px;
}
.preview-content {
width: 100%;
@ -196,40 +192,15 @@ const insertSymbol = (latex: string) => {
align-items: center;
}
.right {
width: 280px;
height: 100%;
margin-left: 20px;
flex: 1;
border: solid 1px $borderColor;
background-color: #fff;
display: flex;
flex-direction: column;
user-select: none;
}
.tabs {
height: 40px;
font-size: 12px;
flex-shrink: 0;
display: flex;
user-select: none;
}
.tab {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: $lightGray;
border-bottom: 1px solid $borderColor;
cursor: pointer;
&.active {
background-color: #fff;
border-bottom-color: #fff;
}
& + .tab {
border-left: 1px solid $borderColor;
}
}
.content {
height: calc(100% - 40px);
font-size: 13px;
@ -258,22 +229,6 @@ const insertSymbol = (latex: string) => {
cursor: pointer;
}
}
.symbol-tabs {
display: flex;
justify-content: space-around;
align-items: center;
border-bottom: 1px solid $borderColor;
margin: 12px 12px 5px;
}
.symbol-tab {
padding: 6px 10px;
border-bottom: 2px solid transparent;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
}
.symbol {
height: 100%;
display: flex;

View File

@ -21,11 +21,10 @@
<div class="title" v-if="title">{{ title }}</div>
<div class="description">{{ message }}</div>
</div>
<div class="control">
<div class="control" v-if="closable">
<span
class="close-btn"
@click="close()"
v-if="closable"
>
<IconCloseSmall />
</span>
@ -100,7 +99,7 @@ defineExpose({
}
}
.message-container {
min-width: 150px;
min-width: 50px;
display: flex;
align-items: center;
padding: 10px;

View File

@ -3,10 +3,13 @@
<Transition name="modal-fade">
<div class="modal" ref="modalRef" v-show="visible" tabindex="-1" @keyup.esc="onEsc()">
<div class="mask" @click="onClickMask()"></div>
<Transition name="modal-zoom">
<Transition name="modal-zoom"
@afterLeave="contentVisible = false"
@before-enter="contentVisible = true"
>
<div class="modal-content" v-show="visible" :style="contentStyle">
<span class="close-btn" v-if="closeButton" @click="emit('update:visible', false)"><IconClose /></span>
<slot v-if="visible"></slot>
<span class="close-btn" v-if="closeButton" @click="close()"><IconClose /></span>
<slot v-if="contentVisible"></slot>
</div>
</Transition>
</div>
@ -38,8 +41,11 @@ const modalRef = ref<HTMLDivElement>()
const emit = defineEmits<{
(event: 'update:visible', payload: boolean): void
(event: 'closed'): void
}>()
const contentVisible = ref(false)
const contentStyle = computed(() => {
return {
width: props.width + 'px',
@ -53,12 +59,17 @@ watch(() => props.visible, () => {
}
})
const close = () => {
emit('update:visible', false)
emit('closed')
}
const onEsc = () => {
if (props.visible && props.closeOnEsc) emit('update:visible', false)
if (props.visible && props.closeOnEsc) close()
}
const onClickMask = () => {
if (props.closeOnClickMask) emit('update:visible', false)
if (props.closeOnClickMask) close()
}
</script>
@ -87,7 +98,7 @@ const onClickMask = () => {
.modal-content {
z-index: 5001;
padding: 15px;
padding: 20px;
background: #fff;
border-radius: $borderRadius;
box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
@ -101,8 +112,8 @@ const onClickMask = () => {
justify-content: center;
align-items: center;
position: absolute;
top: 10px;
right: 12px;
top: 16px;
right: 16px;
cursor: pointer;
}

View File

@ -1,7 +1,7 @@
<template>
<div class="popover" ref="triggerRef">
<div class="popover-content" :style="contentStyle" ref="contentRef">
<slot name="content"></slot>
<slot name="content" v-if="contentVisible"></slot>
</div>
<slot></slot>
</div>
@ -31,6 +31,7 @@ const emit = defineEmits<{
const instance = ref<Instance>()
const triggerRef = ref<HTMLElement>()
const contentRef = ref<HTMLElement>()
const contentVisible = ref(false)
const contentStyle = computed(() => {
return props.contentStyle || {}
@ -54,11 +55,15 @@ onMounted(() => {
offset: [0, 8],
duration: 200,
animation: 'scale',
onShow() {
contentVisible.value = true
},
onShown() {
if (!props.value) emit('update:value', true)
},
onHidden() {
if (props.value) emit('update:value', false)
contentVisible.value = false
},
})
})

View File

@ -1,11 +1,21 @@
<template>
<div class="tabs" :class="{ 'card': card }" :style="tabsStyle || {}">
<div class="tabs"
:class="{
'card': card,
'space-around': spaceAround,
'space-between': spaceBetween,
}"
:style="tabsStyle || {}"
>
<div
class="tab"
:class="{ 'active': tab.key === value }"
v-for="tab in tabs"
:key="tab.key"
:style="tabStyle || {}"
:style="{
...(tabStyle || {}),
'--color': tab.color,
}"
@click="emit('update:value', tab.key)"
>{{tab.label}}</div>
</div>
@ -17,6 +27,7 @@ import { type CSSProperties } from 'vue'
interface TabItem {
key: string
label: string
color?: string
}
withDefaults(defineProps<{
@ -25,8 +36,12 @@ withDefaults(defineProps<{
card?: boolean
tabsStyle?: CSSProperties
tabStyle?: CSSProperties
spaceAround?: boolean
spaceBetween?: boolean
}>(), {
card: false,
spaceAround: false,
spaceBetween: false,
})
const emit = defineEmits<{
@ -36,28 +51,40 @@ const emit = defineEmits<{
<style lang="scss" scoped>
.tabs {
font-size: 13px;
display: flex;
user-select: none;
line-height: 1;
&:not(.card) {
font-size: 13px;
align-items: center;
justify-content: flex-start;
border-bottom: 1px solid $borderColor;
&.space-around {
justify-content: space-around;
}
&.space-between {
justify-content: space-between;
}
.tab {
padding: 8px 10px;
text-align: center;
border-bottom: 2px solid transparent;
padding: 8px 10px;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
border-bottom: 2px solid var(--color, $themeColor);
}
}
}
&.card {
height: 40px;
font-size: 12px;
flex-shrink: 0;
.tab {
flex: 1;
display: flex;

View File

@ -45,6 +45,8 @@ const handleInput = (e: Event) => {
border-radius: $borderRadius;
padding: 10px;
transition: border-color .25s;
box-sizing: border-box;
line-height: 1.675;
resize: none;
font-family: -apple-system,BlinkMacSystemFont, 'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';

View File

@ -2,7 +2,7 @@ import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store'
import { copyText, readClipboard } from '@/utils/clipboard'
import { encrypt } from '@/utils/crypto'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
import useDeleteElement from './useDeleteElement'

View File

@ -12,7 +12,7 @@ import { type AST, toAST } from '@/utils/htmlParser'
import { type SvgPoints, toPoints } from '@/utils/svgPathParser'
import { encrypt } from '@/utils/crypto'
import { svg2Base64 } from '@/utils/svg2Base64'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
const INCH_PX_RATIO = 100
const PT_PX_RATIO = 0.75

View File

@ -8,8 +8,7 @@ import { decrypt } from '@/utils/crypto'
import { type ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
export default () => {
const slidesStore = useSlidesStore()

View File

@ -1,7 +1,7 @@
import { useSlidesStore } from '@/store'
import type { PPTElement, PPTElementLink } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
export default () => {
const slidesStore = useSlidesStore()

View File

@ -2,7 +2,7 @@ import { nextTick, onBeforeUnmount, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { PPTTableElement } from '@/types/slides'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
interface SearchTextResult {
elType: 'text' | 'shape'

View File

@ -7,7 +7,7 @@ import { copyText, readClipboard } from '@/utils/clipboard'
import { encrypt } from '@/utils/crypto'
import { createElementIdMap } from '@/utils/element'
import { KEYS } from '@/configs/hotkey'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useAddSlidesOrElements from '@/hooks//useAddSlidesOrElements'

View File

@ -1,14 +1,10 @@
<template>
<div class="link-dialog">
<div class="tabs">
<div
class="tab"
:class="{ 'active': type === tab.key }"
v-for="tab in tabs"
:key="tab.key"
@click="type = tab.key"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="type"
:tabsStyle="{ marginBottom: '20px' }"
/>
<Input
class="input"
@ -32,7 +28,7 @@
<div class="preview" v-if="type === 'slide' && selectedSlide">
<div>预览</div>
<ThumbnailSlide class="thumbnail" :slide="selectedSlide" :size="490" />
<ThumbnailSlide class="thumbnail" :slide="selectedSlide" :size="500" />
</div>
<div class="btns">
@ -50,6 +46,7 @@ import type { PPTElementLink } from '@/types/slides'
import useLink from '@/hooks/useLink'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
import Tabs from '@/components/Tabs.vue'
import {
Button,
Select,
@ -112,21 +109,9 @@ const save = () => {
</script>
<style lang="scss" scoped>
.tabs {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid $borderColor;
margin-bottom: 20px;
}
.tab {
padding: 0 10px 8px;
border-bottom: 2px solid transparent;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
.link-dialog {
font-size: 13px;
line-height: 1.675;
}
.input {
width: 100%;
@ -136,7 +121,7 @@ const save = () => {
margin-top: 12px;
}
.thumbnail {
outline: 1px solid rgba($color: $themeColor, $alpha: .15);
border: 1px solid rgba($color: $themeColor, $alpha: .15);
margin-top: 5px;
}
.btns {

View File

@ -23,8 +23,7 @@ import { storeToRefs } from 'pinia'
import { useKeyboardStore, useMainStore } from '@/store'
import type { CreateCustomShapeData } from '@/types/edit'
import { KEYS } from '@/configs/hotkey'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
const emit = defineEmits<{
(event: 'created', payload: CreateCustomShapeData): void

View File

@ -88,12 +88,8 @@
<Ruler :viewportStyles="viewportStyles" v-if="showRuler" />
<Modal
v-model:open="linkDialogVisible"
:footer="null"
centered
:closable="false"
v-model:visible="linkDialogVisible"
:width="540"
destroyOnClose
>
<LinkDialog @close="linkDialogVisible = false" />
</Modal>
@ -141,7 +137,7 @@ import ShapeCreateCanvas from './ShapeCreateCanvas.vue'
import MultiSelectOperate from './Operate/MultiSelectOperate.vue'
import Operate from './Operate/index.vue'
import LinkDialog from './LinkDialog.vue'
import { Modal } from 'ant-design-vue'
import Modal from '@/components/Modal.vue'
const mainStore = useMainStore()
const {

View File

@ -1,14 +1,10 @@
<template>
<div class="media-input">
<div class="tabs">
<div
class="tab"
:class="{ 'active': type === tab.key }"
v-for="tab in tabs"
:key="tab.key"
@click="type = tab.key"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="type"
:tabsStyle="{ marginBottom: '15px' }"
/>
<template v-if="type === 'video'">
<Input v-model:value="videoSrc" placeholder="请输入视频地址e.g. https://xxx.mp4"></Input>
@ -35,6 +31,7 @@ import {
Input,
message,
} from 'ant-design-vue'
import Tabs from '@/components/Tabs.vue'
type TypeKey = 'video' | 'audio'
interface TabItem {
@ -73,22 +70,6 @@ const insertAudio = () => {
.media-input {
width: 480px;
}
.tabs {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid $borderColor;
margin-bottom: 20px;
}
.tab {
padding: 0 10px 8px;
border-bottom: 2px solid transparent;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
}
.btns {
margin-top: 10px;
text-align: right;

View File

@ -109,12 +109,8 @@
</div>
<Modal
v-model:open="latexEditorVisible"
:footer="null"
centered
:closable="false"
v-model:visible="latexEditorVisible"
:width="880"
destroyOnClose
>
<LaTeXEditor
@close="latexEditorVisible = false"
@ -142,11 +138,11 @@ import TableGenerator from './TableGenerator.vue'
import MediaInput from './MediaInput.vue'
import LaTeXEditor from '@/components/LaTeXEditor/index.vue'
import FileInput from '@/components/FileInput.vue'
import Modal from '@/components/Modal.vue'
import {
Tooltip,
Popover,
Divider,
Modal,
} from 'ant-design-vue'
const mainStore = useMainStore()

View File

@ -19,14 +19,14 @@ import { HOTKEY_DOC } from '@/configs/hotkey'
height: 100%;
overflow: auto;
font-size: 12px;
margin: 0 -24px;
padding: 0 24px;
margin: 0 -15px;
padding: 0 15px 15px;
}
.title {
font-size: 14px;
font-weight: 700;
border-bottom: 1px solid #e5e5e5;
padding: 24px 0 5px 0;
padding: 25px 0 5px 0;
&:first-child {
padding-top: 0;

View File

@ -65,11 +65,9 @@
</div>
<Drawer
width="320"
:width="320"
v-model:visible="hotkeyDrawerVisible"
placement="right"
:closable="false"
:open="hotkeyDrawerVisible"
@close="hotkeyDrawerVisible = false"
>
<HotkeyDoc />
</Drawer>
@ -90,9 +88,9 @@ import type { DialogForExportTypes } from '@/types/export'
import HotkeyDoc from './HotkeyDoc.vue'
import FileInput from '@/components/FileInput.vue'
import FullscreenSpin from '@/components/FullscreenSpin.vue'
import Drawer from '@/components/Drawer.vue'
import {
Tooltip,
Drawer,
Popover,
Input,
} from 'ant-design-vue'

View File

@ -1,14 +1,11 @@
<template>
<div class="export-dialog">
<div class="tabs">
<div
class="tab"
:class="{ 'active': tab.key === dialogForExport }"
v-for="tab in tabs"
:key="tab.key"
@click="setDialogForExport(tab.key)"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
:value="dialogForExport"
card
@update:value="key => setDialogForExport(key as DialogForExportTypes)"
/>
<div class="content">
<component :is="currentDialogComponent" @close="setDialogForExport('')"></component>
</div>
@ -26,6 +23,7 @@ import ExportJSON from './ExportJSON.vue'
import ExportPDF from './ExportPDF.vue'
import ExportPPTX from './ExportPPTX.vue'
import ExportSpecificFile from './ExportSpecificFile.vue'
import Tabs from '@/components/Tabs.vue'
interface TabItem {
key: DialogForExportTypes
@ -60,35 +58,7 @@ const currentDialogComponent = computed<unknown>(() => {
<style lang="scss" scoped>
.export-dialog {
margin: -20px -24px;
}
.tabs {
height: 50px;
font-size: 12px;
flex-shrink: 0;
display: flex;
user-select: none;
border-top-left-radius: $borderRadius;
border-top-right-radius: $borderRadius;
overflow: hidden;
}
.tab {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: $lightGray;
border-bottom: 1px solid $borderColor;
cursor: pointer;
&.active {
background-color: #fff;
border-bottom-color: #fff;
}
& + .tab {
border-left: 1px solid $borderColor;
}
margin: -20px;
}
.content {
height: 460px;

View File

@ -7,16 +7,10 @@
:top="90"
>
<div class="close-btn" @click="close()" @mousedown.stop><IconClose /></div>
<div class="tabs">
<div
class="tab"
:class="{ 'active': type === tab.key }"
v-for="tab in tabs"
:key="tab.key"
@click="changeTab(tab.key)"
@mousedown.stop
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="type"
/>
<div class="content" :class="type" @mousedown.stop>
<Input class="input" v-model:value="searchWord" placeholder="输入查找内容" @keydown.enter="searchNext()" ref="searchInpRef">
@ -37,10 +31,11 @@
</template>
<script lang="ts" setup>
import { nextTick, onMounted, ref } from 'vue'
import { nextTick, onMounted, ref, watch } from 'vue'
import { useMainStore } from '@/store'
import useSearch from '@/hooks/useSearch'
import MoveablePanel from '@/components/MoveablePanel.vue'
import Tabs from '@/components/Tabs.vue'
import {
Button,
Input,
@ -81,35 +76,17 @@ onMounted(() => {
searchInpRef.value!.focus()
})
const changeTab = (key: TypeKey) => {
type.value = key
watch(type, () => {
nextTick(() => {
searchInpRef.value!.focus()
})
}
})
</script>
<style lang="scss" scoped>
.search-panel {
font-size: 13px;
}
.tabs {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid $borderColor;
line-height: 1.5;
user-select: none;
}
.tab {
padding: 0 10px 8px;
border-bottom: 2px solid transparent;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
}
.content {
display: flex;
flex-direction: column;
@ -143,10 +120,10 @@ const changeTab = (key: TypeKey) => {
margin-top: 10px;
}
.close-btn {
width: 40px;
height: 40px;
width: 32px;
height: 32px;
position: absolute;
top: 0;
top: 8px;
right: 0;
display: flex;
justify-content: center;

View File

@ -7,14 +7,13 @@
@openChange="visible => handlePopoverVisibleChange(visible)"
>
<template #content>
<div class="tabs">
<div
:class="['tab', tab.key, { 'active': activeTab === tab.key }]"
v-for="tab in tabs"
:key="tab.key"
@click="activeTab = tab.key"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="activeTab"
:tabsStyle="{ marginBottom: '20px' }"
:tabStyle="{ width: '33.333%' }"
spaceAround
/>
<template v-for="key in animationTypes">
<div :class="['animation-pool', key]" :key="key" v-if="activeTab === key">
<div class="pool-type" :key="effect.name" v-for="effect in animations[key]">
@ -130,7 +129,7 @@ import {
import { ELEMENT_TYPE_ZH } from '@/configs/element'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import Tabs from '@/components/Tabs.vue'
import Draggable from 'vuedraggable'
import {
InputNumber,
@ -163,6 +162,7 @@ type AnimationType = 'in' | 'out' | 'attention'
interface TabItem {
key: AnimationType
label: string
color: string,
}
const animationTypes: AnimationType[] = ['in', 'out', 'attention']
@ -172,9 +172,9 @@ const { handleElement, handleElementId } = storeToRefs(useMainStore())
const { currentSlide, formatedAnimations, currentSlideAnimations } = storeToRefs(slidesStore)
const tabs: TabItem[] = [
{ key: 'in', label: '入场' },
{ key: 'out', label: '退场' },
{ key: 'attention', label: '强调' },
{ key: 'in', label: '入场', color: '#68a490' },
{ key: 'out', label: '退场', color: '#d86344' },
{ key: 'attention', label: '强调', color: '#e8b76a' },
]
const activeTab = ref('in')
@ -348,33 +348,6 @@ $attentionColor: #e8b76a;
display: flex;
flex-direction: column;
}
.tabs {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid $borderColor;
margin-bottom: 20px;
}
.tab {
width: 33.33%;
padding-bottom: 8px;
border-bottom: 2px solid transparent;
text-align: center;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
&.in.active {
border-bottom-color: $inColor;
}
&.out.active {
border-bottom-color: $outColor;
}
&.attention.active {
border-bottom-color: $attentionColor;
}
}
.element-animation {
height: 32px;
display: flex;

View File

@ -135,12 +135,8 @@
<ElementOutline />
<Modal
v-model:open="chartDataEditorVisible"
:footer="null"
centered
:closable="false"
:width="648"
destroyOnClose
v-model:visible="chartDataEditorVisible"
:width="640"
>
<ChartDataEditor
:data="handleChartElement.data"
@ -163,13 +159,13 @@ import ElementOutline from '../../common/ElementOutline.vue'
import ColorButton from '../../common/ColorButton.vue'
import ChartDataEditor from './ChartDataEditor.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import Modal from '@/components/Modal.vue'
import {
Divider,
Button,
Tooltip,
Popover,
Select,
Modal,
Checkbox,
} from 'ant-design-vue'
const ButtonGroup = Button.Group

View File

@ -28,12 +28,8 @@
</div>
<Modal
v-model:open="latexEditorVisible"
:footer="null"
centered
:closable="false"
v-model:visible="latexEditorVisible"
:width="880"
destroyOnClose
>
<LaTeXEditor
:value="handleLatexElement.latex"
@ -55,12 +51,12 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ColorButton from '../common/ColorButton.vue'
import LaTeXEditor from '@/components/LaTeXEditor/index.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import Modal from '@/components/Modal.vue'
import {
InputNumber,
Divider,
Button,
Popover,
Modal,
} from 'ant-design-vue'
const slidesStore = useSlidesStore()

View File

@ -1,14 +1,11 @@
<template>
<div class="symbol-panel">
<div class="tabs">
<div
class="tab"
:class="{ 'active': selectedSymbolKey === item.key }"
v-for="item in SYMBOL_LIST"
:key="item.key"
@click="selectedSymbolKey = item.key"
>{{item.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="selectedSymbolKey"
:tabsStyle="{ marginBottom: '8px' }"
spaceBetween
/>
<div class="pool">
<div class="symbol-item" v-for="(item, index) in symbolPool" :key="index" @click="selectSymbol(item)">
<div class="symbol">{{item}}</div>
@ -21,6 +18,7 @@
import { computed, ref } from 'vue'
import { SYMBOL_LIST } from '@/configs/symbol'
import emitter, { EmitterEvents } from '@/utils/emitter'
import Tabs from '@/components/Tabs.vue'
const selectedSymbolKey = ref(SYMBOL_LIST[0].key)
const symbolPool = computed(() => {
@ -28,6 +26,11 @@ const symbolPool = computed(() => {
return selectedSymbol?.children || []
})
const tabs = SYMBOL_LIST.map(item => ({
key: item.key,
label: item.label,
}))
const selectSymbol = (value: string) => {
emitter.emit(EmitterEvents.RICH_TEXT_COMMAND, { action: { command: 'insert', value } })
}
@ -39,22 +42,6 @@ const selectSymbol = (value: string) => {
display: flex;
flex-direction: column;
.tabs {
display: flex;
justify-content: space-around;
align-items: center;
border-bottom: 1px solid $borderColor;
margin-bottom: 8px;
}
.tab {
padding: 6px 10px 8px;
border-bottom: 2px solid transparent;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
}
.pool {
padding: 5px 12px;
margin: 0 -12px;

View File

@ -1,14 +1,11 @@
<template>
<div class="toolbar">
<div class="tabs">
<div
class="tab"
:class="{ 'active': tab.value === toolbarState }"
v-for="tab in currentTabs"
:key="tab.value"
@click="setToolbarState(tab.value)"
>{{tab.label}}</div>
</div>
<Tabs
:tabs="currentTabs"
:value="toolbarState"
card
@update:value="key => setToolbarState(key as ToolbarStates)"
/>
<div class="content">
<component :is="currentPanelComponent"></component>
</div>
@ -28,10 +25,11 @@ import SlideDesignPanel from './SlideDesignPanel.vue'
import SlideAnimationPanel from './SlideAnimationPanel.vue'
import MultiPositionPanel from './MultiPositionPanel.vue'
import SymbolPanel from './SymbolPanel.vue'
import Tabs from '@/components/Tabs.vue'
interface ElementTabs {
label: string
value: ToolbarStates
key: ToolbarStates
}
const mainStore = useMainStore()
@ -40,26 +38,26 @@ const { activeElementIdList, handleElement, toolbarState } = storeToRefs(mainSto
const elementTabs = computed<ElementTabs[]>(() => {
if (handleElement.value?.type === 'text') {
return [
{ label: '样式', value: ToolbarStates.EL_STYLE },
{ label: '符号', value: ToolbarStates.SYMBOL },
{ label: '位置', value: ToolbarStates.EL_POSITION },
{ label: '动画', value: ToolbarStates.EL_ANIMATION },
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '符号', key: ToolbarStates.SYMBOL },
{ label: '位置', key: ToolbarStates.EL_POSITION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION },
]
}
return [
{ label: '样式', value: ToolbarStates.EL_STYLE },
{ label: '位置', value: ToolbarStates.EL_POSITION },
{ label: '动画', value: ToolbarStates.EL_ANIMATION },
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '位置', key: ToolbarStates.EL_POSITION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION },
]
})
const slideTabs = [
{ label: '设计', value: ToolbarStates.SLIDE_DESIGN },
{ label: '切换', value: ToolbarStates.SLIDE_ANIMATION },
{ label: '动画', value: ToolbarStates.EL_ANIMATION },
{ label: '设计', key: ToolbarStates.SLIDE_DESIGN },
{ label: '切换', key: ToolbarStates.SLIDE_ANIMATION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION },
]
const multiSelectTabs = [
{ label: '样式', value: ToolbarStates.EL_STYLE },
{ label: '位置', value: ToolbarStates.MULTI_POSITION },
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '位置', key: ToolbarStates.MULTI_POSITION },
]
const setToolbarState = (value: ToolbarStates) => {
@ -73,7 +71,7 @@ const currentTabs = computed(() => {
})
watch(currentTabs, () => {
const currentTabsValue: ToolbarStates[] = currentTabs.value.map(tab => tab.value)
const currentTabsValue: ToolbarStates[] = currentTabs.value.map(tab => tab.key)
if (!currentTabsValue.includes(toolbarState.value)) {
mainStore.setToolbarState(currentTabsValue[0])
}
@ -100,31 +98,6 @@ const currentPanelComponent = computed(() => {
display: flex;
flex-direction: column;
}
.tabs {
height: 40px;
font-size: 12px;
flex-shrink: 0;
display: flex;
user-select: none;
}
.tab {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: $lightGray;
border-bottom: 1px solid $borderColor;
cursor: pointer;
&.active {
background-color: #fff;
border-bottom-color: #fff;
}
& + .tab {
border-left: 1px solid $borderColor;
}
}
.content {
padding: 12px;
font-size: 13px;

View File

@ -20,13 +20,9 @@
<SearchPanel v-if="showSearchPanel" />
<Modal
:open="!!dialogForExport"
:footer="null"
centered
:closable="false"
:visible="!!dialogForExport"
:width="680"
destroyOnClose
@cancel="closeExportDialog()"
@closed="closeExportDialog()"
>
<ExportDialog />
</Modal>
@ -48,7 +44,7 @@ import Remark from './Remark/index.vue'
import ExportDialog from './ExportDialog/index.vue'
import SelectPanel from './SelectPanel.vue'
import SearchPanel from './SearchPanel.vue'
import { Modal } from 'ant-design-vue'
import Modal from '@/components/Modal.vue'
const mainStore = useMainStore()
const { dialogForExport, showSelectPanel, showSearchPanel } = storeToRefs(mainStore)

View File

@ -1,14 +1,14 @@
<template>
<div class="element-toolbar">
<div class="tabs">
<div
class="tab"
:class="{ 'active': activeTab === item.key }"
v-for="item in tabs"
:key="item.key"
@click="activeTab = item.key"
>{{item.label}}</div>
</div>
<Tabs
:tabs="tabs"
v-model:value="activeTab"
:tabsStyle="{ marginBottom: '8px' }"
:tabStyle="{
width: '30%',
margin: '0 10%',
}"
/>
<div class="content">
<div class="style" v-if="activeTab === 'style'">
@ -134,6 +134,7 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import CheckboxButton from '@/components/CheckboxButton.vue'
import CheckboxButtonGroup from '@/components/ButtonGroup.vue'
import Tabs from '@/components/Tabs.vue'
import {
Divider,
Button,
@ -237,27 +238,6 @@ const updateFill = (color: string) => {
flex-direction: column;
animation: slideInUp .15s;
}
.tabs {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid $borderColor;
font-size: 12px;
font-weight: 700;
margin-bottom: 10px;
}
.tab {
width: 30%;
padding: 10px 10px 12px;
margin: 0 10%;
border-bottom: 2px solid transparent;
text-align: center;
cursor: pointer;
&.active {
border-bottom: 2px solid $themeColor;
}
}
@keyframes slideInUp {
from {

View File

@ -4,8 +4,7 @@ import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store'
import { KEYS } from '@/configs/hotkey'
import { ANIMATION_CLASS_PREFIX } from '@/configs/animation'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
export default () => {
const slidesStore = useSlidesStore()

View File

@ -74,7 +74,7 @@
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { message } from 'ant-design-vue'
import message from '@/utils/message'
const props = withDefaults(defineProps<{
src: string