mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
refactor: 替换Tabs、Modal、Message、TextArea、Drawer
This commit is contained in:
parent
a869633a30
commit
9206ef8596
@ -47,6 +47,7 @@ const handleClick = () => {
|
||||
color: $textColor;
|
||||
border-radius: $borderRadius;
|
||||
user-select: none;
|
||||
letter-spacing: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
&.default {
|
||||
|
@ -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
|
||||
}>(), {
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
},
|
||||
})
|
||||
})
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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'
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user