feat: advance toolbar

This commit is contained in:
KUN1007 2023-09-04 20:02:23 +08:00
parent 4a42f94b32
commit f346249685
9 changed files with 229 additions and 162 deletions

View file

@ -1,25 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { defineAsyncComponent, ref } from 'vue'
// //
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
//
import SwitchButton from './SwitchButton.vue' //
const EditorSettingsMenu = defineAsyncComponent(
() => import('./EditorSettingsMenu.vue')
)
// css // css
import 'animate.css' import 'animate.css'
// store //
import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia'
const { editorHeight } = storeToRefs(useKUNGalgameEditStore())
defineProps<{ defineProps<{
textCount: number textCount: number
}>() }>()
// //
const isShowSettingsMenu = ref(true) const isShowSettingsMenu = ref(false)
// //
const handelClickSettings = () => { const handelClickSettings = () => {
@ -43,37 +41,8 @@ const handelClickSettings = () => {
<!-- 文字计数 --> <!-- 文字计数 -->
<span class="count">{{ textCount + ` ${$tm('edit.word')}` }}</span> <span class="count">{{ textCount + ` ${$tm('edit.word')}` }}</span>
<Transition <!-- 设置面板 -->
enter-active-class="animate__animated animate__jackInTheBox animate__faster" <EditorSettingsMenu :isShowSettingsMenu="isShowSettingsMenu" />
leave-active-class="animate__animated animate__rollOut animate__faster"
>
<!-- 设置菜单 -->
<div v-if="isShowSettingsMenu" class="settings-menu">
<!-- 编辑器高度设置 -->
<div class="editor-height-title">
<span> 编辑器高度 </span>
<span>{{ editorHeight }} px</span>
</div>
<div class="editor-height">
<span>300 px</span>
<input
type="range"
min="300"
max="500"
step="1"
v-model="editorHeight"
/>
<span>500 px</span>
</div>
<!-- 是否显示编辑器高级选项 -->
<div class="editor-advance-title">
<span> 高级选项 </span>
<!-- 切换按钮 -->
<SwitchButton />
</div>
</div>
</Transition>
</div> </div>
</template> </template>
@ -101,37 +70,6 @@ const handelClickSettings = () => {
} }
} }
.settings-menu {
padding: 10px;
z-index: 1009;
position: absolute;
bottom: 50px;
background-color: var(--kungalgame-white);
border: 1px solid var(--kungalgame-blue-1);
box-shadow: var(--shadow);
border-radius: 5px;
display: flex;
flex-direction: column;
.editor-height-title {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-size: 17px;
}
.editor-advance-title {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-size: 17px;
}
.editor-height {
margin-bottom: 20px;
}
}
.count { .count {
color: var(--kungalgame-font-color-0); color: var(--kungalgame-font-color-0);
background-color: var(--kungalgame-trans-white-9); background-color: var(--kungalgame-trans-white-9);

View file

@ -0,0 +1,146 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
//
import { Icon } from '@iconify/vue'
//
import SwitchButton from './SwitchButton.vue'
// css
import 'animate.css'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia'
// 使 store
const settingsStore = useKUNGalgameEditStore()
const { isShowAdvance } = storeToRefs(settingsStore)
const { editorHeight } = storeToRefs(useKUNGalgameEditStore())
defineProps<{
isShowSettingsMenu: boolean
}>()
//
const isRefreshPage = ref(false)
//
watch(isShowAdvance, () => {
isRefreshPage.value = !isRefreshPage.value
})
const handleRefreshPage = () => location.reload()
</script>
<template>
<Transition
enter-active-class="animate__animated animate__jackInTheBox animate__faster"
leave-active-class="animate__animated animate__rollOut animate__faster"
>
<!-- 设置菜单 -->
<div v-if="isShowSettingsMenu" class="settings-menu">
<!-- 编辑器高度设置 -->
<div class="editor-height-title">
<span> 编辑器高度 </span>
<span>{{ editorHeight }} px</span>
</div>
<div class="editor-height">
<span>300 px</span>
<input
type="range"
min="300"
max="500"
step="1"
v-model="editorHeight"
/>
<span>500 px</span>
</div>
<!-- 是否显示编辑器高级选项 -->
<div class="editor-advance-title">
<div class="editor-advance">
<Transition mode="out-in" name="slide-up">
<span v-if="!isRefreshPage"> 高级编辑模式 </span>
<span
@click="handleRefreshPage"
class="refresh"
v-else-if="isRefreshPage"
>
<span>刷新页面生效</span>
<Icon icon="line-md:rotate-270" />
</span>
</Transition>
</div>
<!-- 切换按钮 -->
<SwitchButton />
</div>
</div>
</Transition>
</template>
<style lang="scss" scoped>
.settings-menu {
padding: 10px;
z-index: 1009;
position: absolute;
bottom: 50px;
background-color: var(--kungalgame-white);
border: 1px solid var(--kungalgame-blue-1);
box-shadow: var(--shadow);
border-radius: 5px;
display: flex;
flex-direction: column;
.editor-height-title {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-size: 17px;
}
.editor-advance-title {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-size: 17px;
}
}
.editor-height {
margin-bottom: 20px;
}
.editor-advance {
display: flex;
flex-direction: column;
.refresh {
display: flex;
align-items: center;
font-size: 23px;
cursor: pointer;
&:hover {
color: var(--kungalgame-blue-4);
}
span {
margin-right: 10px;
font-size: 17px;
}
}
}
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.25s ease-out;
}
.slide-up-enter-from {
opacity: 0;
transform: translateY(30px);
}
.slide-up-leave-to {
opacity: 0;
transform: translateY(-30px);
}
</style>

View file

@ -1,6 +1,7 @@
<!-- KUNGalgame 通用切换按钮 --> <!-- KUNGalgame 通用切换按钮 -->
<script setup lang="ts"> <script setup lang="ts">
import { watch } from 'vue'
// store // store
import { useKUNGalgameEditStore } from '@/store/modules/edit' import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
@ -9,15 +10,14 @@ import { storeToRefs } from 'pinia'
const settingsStore = useKUNGalgameEditStore() const settingsStore = useKUNGalgameEditStore()
const { isShowAdvance } = storeToRefs(settingsStore) const { isShowAdvance } = storeToRefs(settingsStore)
// toolbar // store store
const toggleEditorMode = () => { watch(isShowAdvance, (newValue) => {
isShowAdvance.value = !isShowAdvance.value isShowAdvance.value = newValue
} })
</script> </script>
<template> <template>
<input type="checkbox" id="switch" /><label <input type="checkbox" id="switch" v-model="isShowAdvance" /><label
@click="toggleEditorMode"
for="switch" for="switch"
>Toggle</label >Toggle</label
> >

View file

@ -78,7 +78,5 @@ const handelInput = () => {
/* 标题输入字体大小 */ /* 标题输入字体大小 */
font-size: 40px; font-size: 40px;
border: none; border: none;
/* 光标样式 */
caret-shape: block;
} }
</style> </style>

View file

@ -20,6 +20,7 @@ import { Editor } from '@wangeditor/editor-for-vue'
// //
import { IToolbarConfig } from '@wangeditor/editor' import { IToolbarConfig } from '@wangeditor/editor'
import { Toolbar } from '@wangeditor/editor-for-vue' import { Toolbar } from '@wangeditor/editor-for-vue'
import { keysToExclude } from './keysToExclude'
// //
const Title = defineAsyncComponent( const Title = defineAsyncComponent(
@ -38,7 +39,9 @@ import DOMPurify from 'dompurify'
// //
import { debounce } from '@/utils/debounce' import { debounce } from '@/utils/debounce'
const topicData = storeToRefs(useKUNGalgameEditStore()) const { editorHeight, isShowAdvance, isSave, content } = storeToRefs(
useKUNGalgameEditStore()
)
// //
const props = defineProps<{ const props = defineProps<{
@ -54,7 +57,7 @@ const props = defineProps<{
const editorRef = shallowRef<IDomEditor | undefined>(undefined) const editorRef = shallowRef<IDomEditor | undefined>(undefined)
// //
const editorHeight = computed(() => `height: ${topicData.editorHeight.value}px`) const editorHeightStyle = computed(() => `height: ${editorHeight.value}px`)
// //
const valueHtml = ref('') const valueHtml = ref('')
// //
@ -82,23 +85,23 @@ const editorConfig: Partial<IEditorConfig> = {
}, },
} }
const keys: string[] = []
// //
const toolbarConfig: Partial<IToolbarConfig> = { const toolbarConfig: Partial<IToolbarConfig> = {
excludeKeys: ['uploadVideo'].concat(keys), // keys
excludeKeys: isShowAdvance.value ? ['uploadVideo'] : keysToExclude,
} }
const handleCreated = (editor: IDomEditor) => { const handleCreated = (editor: IDomEditor) => {
console.log(editor.getAllMenuKeys())
editorRef.value = editor // editor editorRef.value = editor // editor
editor.on('modalOrPanelShow', (modalOrPanel) => {
console.log(modalOrPanel)
})
} }
// //
onBeforeMount(() => { onBeforeMount(() => {
if (topicData.isSave.value) { if (isSave.value) {
valueHtml.value = topicData.content.value valueHtml.value = content.value
} }
}) })
@ -115,7 +118,7 @@ const handleChange = (editor: IDomEditor) => {
// //
const debouncedUpdateContent = debounce(() => { const debouncedUpdateContent = debounce(() => {
// xss // xss
topicData.content.value = DOMPurify.sanitize(editor.getHtml()) content.value = DOMPurify.sanitize(editor.getHtml())
}, 1007) }, 1007)
// //
@ -149,7 +152,7 @@ const handleChange = (editor: IDomEditor) => {
<!-- 编辑器本体 --> <!-- 编辑器本体 -->
<Editor <Editor
class="wang-editor" class="wang-editor"
:style="editorHeight" :style="editorHeightStyle"
v-model="valueHtml" v-model="valueHtml"
:defaultConfig="editorConfig" :defaultConfig="editorConfig"
@onCreated="handleCreated" @onCreated="handleCreated"
@ -162,10 +165,7 @@ const handleChange = (editor: IDomEditor) => {
</div> </div>
<!-- 编辑器 footer --> <!-- 编辑器 footer -->
<EditorFooter <EditorFooter :textCount="textCount" :editorHeight="editorHeight" />
:textCount="textCount"
:editorHeight="topicData.editorHeight.value"
/>
</div> </div>
</template> </template>
@ -177,8 +177,7 @@ const handleChange = (editor: IDomEditor) => {
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto;
z-index: 1008; z-index: 1008;
background-color: var(--kungalgame-trans-white-5); background-color: var(--kungalgame-trans-white-2);
backdrop-filter: blur(5px);
} }
.toolbar { .toolbar {

View file

@ -1,62 +0,0 @@
;[
'bold',
'underline',
'italic',
'through',
'code',
'sub',
'sup',
'clearStyle',
'color',
'bgColor',
'fontSize',
'fontFamily',
'indent',
'delIndent',
'justifyLeft',
'justifyRight',
'justifyCenter',
'justifyJustify',
'lineHeight',
'insertImage',
'deleteImage',
'editImage',
'viewImageLink',
'imageWidth30',
'imageWidth50',
'imageWidth100',
'divider',
'emotion',
'insertLink',
'editLink',
'unLink',
'viewLink',
'codeBlock',
'blockquote',
'headerSelect',
'header1',
'header2',
'header3',
'header4',
'header5',
'todo',
'redo',
'undo',
'fullScreen',
'enter',
'bulletedList',
'numberedList',
'insertTable',
'deleteTable',
'insertTableRow',
'deleteTableRow',
'insertTableCol',
'deleteTableCol',
'tableHeader',
'tableFullWidth',
'insertVideo',
'uploadVideo',
'editVideoSize',
'uploadImage',
'codeSelectLang',
]

View file

@ -0,0 +1,34 @@
// 编辑器 toolbar 要排除的项目
export const keysToExclude: string[] = [
// 角标
'sub',
'sup',
// 文字精确大小,字体,行高
'fontSize',
'fontFamily',
'lineHeight',
// 文字背景色
'bgColor',
// todo, undo, redo
'todo',
'redo',
'undo',
// 缩进的组
'group-indent',
// 插入视频的组
'group-video',
// 表格
'insertTable',
'deleteTable',
'deleteTableRow',
'insertTableCol',
'deleteTableCol',
'tableHeader',
'tableFullWidth',
// 右键菜单已有的功能
'headerSelect',
'bold',
'bulletedList',
'insertLink',
'group-more-style',
]

View file

@ -27,14 +27,27 @@ u {
text-shadow: none; text-shadow: none;
} }
/* 不显示分割线 */
.w-e-bar-divider {
display: none;
}
a {
color: var(--kungalgame-blue-5);
border-bottom: 1.5px solid var(--kungalgame-trans-white-9);
&:hover {
border-bottom: 1.5px solid var(--kungalgame-blue-5);
}
}
:root { :root {
/* textarea - css vars */ /* textarea - css vars */
--w-e-textarea-bg-color: var(--kungalgame-white-9); --w-e-textarea-bg-color: var(--kungalgame-white-9);
--w-e-textarea-color: var(--kungalgame-font-color-3); --w-e-textarea-color: var(--kungalgame-font-color-3);
--w-e-textarea-border-color: var(--kungalgame-blue-1); --w-e-textarea-border-color: var(--kungalgame-blue-4);
--w-e-textarea-slight-border-color: var(--kungalgame-blue-4); --w-e-textarea-slight-border-color: var(--kungalgame-blue-4);
--w-e-textarea-slight-color: var(--kungalgame-font-color-0); --w-e-textarea-slight-color: var(--kungalgame-font-color-0);
--w-e-textarea-slight-bg-color: var(--kungalgame-white-9); --w-e-textarea-slight-bg-color: var(--kungalgame-trans-blue-0);
--w-e-textarea-selected-border-color: var(--kungalgame-blue-1); --w-e-textarea-selected-border-color: var(--kungalgame-blue-1);
/* 选中的元素,如选中了分割线 */ /* 选中的元素,如选中了分割线 */
--w-e-textarea-handler-bg-color: var(--kungalgame-blue-4); --w-e-textarea-handler-bg-color: var(--kungalgame-blue-4);

View file

@ -28,7 +28,8 @@ onMounted(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
/* 内容区右侧的话题展示区 */ /* 内容区右侧的话题展示区 */
.w-e-text-container { .w-e-text-container {
width: 82%; /** 100 + 20 + 20 + 1 = 141px */
width: calc(100% - 141px);
font-size: 15px; font-size: 15px;
padding: 17px; padding: 17px;
border-left: 1px solid var(--kungalgame-blue-1); border-left: 1px solid var(--kungalgame-blue-1);