mirror of
https://github.com/blossom-editor/blossom
synced 2024-11-17 14:39:21 +08:00
feat: 文档列表左右拖动
This commit is contained in:
parent
af75ad9972
commit
b4e001e3e9
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="index-article-root">
|
||||
<!-- folder menu -->
|
||||
<div class="doc-container" :style="{ width: docEditorStyle.docs }" v-show="docsExpand">
|
||||
<div class="doc-container" ref="DocsRef" v-show="docsExpand">
|
||||
<div class="doc-tree-menu-container" :style="tempTextareaStyle.docTree">
|
||||
<ArticleTreeDocs @click-doc="clickCurDoc" ref="ArticleTreeDocsRef"></ArticleTreeDocs>
|
||||
</div>
|
||||
@ -16,9 +16,9 @@
|
||||
</bl-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resize-docs-divider" ref="ResizeDocsDividerRef"></div>
|
||||
<!-- editor -->
|
||||
<div class="editor-container" :style="{ width: docEditorStyle.editor }" v-loading="editorLoading" element-loading-text="正在读取文章内容...">
|
||||
<div class="editor-container" ref="EditorContainerRef" v-loading="editorLoading" element-loading-text="正在读取文章内容...">
|
||||
<div class="editor-tools">
|
||||
<EditorTools
|
||||
@save="saveCurArticleContent()"
|
||||
@ -93,7 +93,7 @@
|
||||
</div>
|
||||
<div class="gutter-holder" ref="GutterHolderRef"></div>
|
||||
<div class="editor-codemirror" ref="EditorRef" @click.right="handleEditorClickRight"></div>
|
||||
<div class="resize-divider" ref="ResizeDividerRef"></div>
|
||||
<div class="resize-divider" ref="ResizeEditorDividerRef"></div>
|
||||
<div class="preview-marked bl-preview" ref="PreviewRef" v-html="articleHtml"></div>
|
||||
</div>
|
||||
|
||||
@ -204,7 +204,7 @@ import Notify from '@renderer/scripts/notify'
|
||||
import { useDraggable } from '@renderer/scripts/draggable'
|
||||
import type { shortcutFunc } from '@renderer/scripts/shortcut-register'
|
||||
import { treeToInfo, provideKeyDocInfo, provideKeyCurArticleInfo, isArticle } from '@renderer/views/doc/doc'
|
||||
import { TempTextareaKey, ArticleReference, DocEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import { TempTextareaKey, ArticleReference, DocsEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import type { Toc } from './scripts/article'
|
||||
import { beforeUpload, onError, picCacheWrapper, picCacheRefresh, uploadForm, uploadDate } from '@renderer/views/picture/scripts/picture'
|
||||
import { useResize } from './scripts/editor-preview-resize'
|
||||
@ -268,9 +268,12 @@ watch(
|
||||
//#endregion
|
||||
|
||||
//#region ----------------------------------------< 公共参数和页面动态样式 >--------------------------------------
|
||||
const DocsRef = ref()
|
||||
const EditorContainerRef = ref()
|
||||
const ResizeDocsDividerRef = ref()
|
||||
const GutterHolderRef = ref() // editor gutter holder
|
||||
const EditorRef = ref() // editor
|
||||
const ResizeDividerRef = ref() // editor&preview resize dom
|
||||
const ResizeEditorDividerRef = ref() // editor&preview resize dom
|
||||
const EditorOperatorRef = ref()
|
||||
const PreviewRef = ref() // html 预览
|
||||
const editorOperator = ref({
|
||||
@ -282,12 +285,6 @@ const editorOperator = ref({
|
||||
*/
|
||||
const docsExpand = ref<boolean>(true)
|
||||
const tocsExpand = ref<boolean>(true)
|
||||
const docEditorStyle = computed<DocEditorStyle>(() => {
|
||||
if (!docsExpand.value) {
|
||||
return { docs: '0px', editor: '100%' }
|
||||
}
|
||||
return { docs: '250px', editor: 'calc(100% - 250px)' }
|
||||
})
|
||||
|
||||
/**
|
||||
* 编辑器和预览的展开收起
|
||||
@ -357,7 +354,16 @@ const exitView = () => {
|
||||
autoSave()
|
||||
}
|
||||
|
||||
useResize(EditorRef, PreviewRef, ResizeDividerRef, EditorOperatorRef)
|
||||
const { hideOne, resotreOne } = useResize(DocsRef, EditorContainerRef, ResizeDocsDividerRef, undefined, {
|
||||
persistent: true,
|
||||
keyOne: 't1',
|
||||
keyTwo: 't2',
|
||||
defaultOne: '250px',
|
||||
defaultTwo: 'calc(100% - 250px)',
|
||||
maxOne: 700,
|
||||
minOne: 250
|
||||
})
|
||||
useResize(EditorRef, PreviewRef, ResizeEditorDividerRef, EditorOperatorRef)
|
||||
//#endregion
|
||||
|
||||
//#region ----------------------------------------< 图片管理 >--------------------------------------
|
||||
@ -865,6 +871,11 @@ const formatTable = () => {
|
||||
//#region ----------------------------------------< 快捷键注册 >-------------------------------------
|
||||
const alt_1: shortcutFunc = (): void => {
|
||||
docsExpand.value = !docsExpand.value
|
||||
if (!docsExpand.value) {
|
||||
hideOne()
|
||||
} else {
|
||||
resotreOne()
|
||||
}
|
||||
}
|
||||
const alt_2: shortcutFunc = (): void => {
|
||||
tocsExpand.value = !tocsExpand.value
|
||||
|
@ -246,7 +246,7 @@ import Notify from '@renderer/scripts/notify'
|
||||
import { useDraggable } from '@renderer/scripts/draggable'
|
||||
import type { shortcutFunc } from '@renderer/scripts/shortcut-register'
|
||||
import { treeToInfo, provideKeyDocInfo, provideKeyCurArticleInfo, isArticle } from '@renderer/views/doc/doc'
|
||||
import { TempTextareaKey, ArticleReference, DocEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import { TempTextareaKey, ArticleReference, DocsEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import type { Toc } from './scripts/article'
|
||||
import { beforeUpload, onError, picCacheWrapper, picCacheRefresh, uploadForm, uploadDate } from '@renderer/views/picture/scripts/picture'
|
||||
import { useResize } from './scripts/editor-preview-resize'
|
||||
@ -327,7 +327,7 @@ const editorOperator = ref({
|
||||
*/
|
||||
const docsExpand = ref<boolean>(true)
|
||||
const tocsExpand = ref<boolean>(true)
|
||||
const docEditorStyle = computed<DocEditorStyle>(() => {
|
||||
const docEditorStyle = computed<DocsEditorStyle>(() => {
|
||||
if (!docsExpand.value) {
|
||||
return { docs: '0px', editor: '100%' }
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ import Notify from '@renderer/scripts/notify'
|
||||
import { useDraggable } from '@renderer/scripts/draggable'
|
||||
import type { shortcutFunc } from '@renderer/scripts/shortcut-register'
|
||||
import { treeToInfo, provideKeyDocInfo, provideKeyCurArticleInfo, isArticle } from '@renderer/views/doc/doc'
|
||||
import { TempTextareaKey, ArticleReference, DocEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import { TempTextareaKey, ArticleReference, DocsEditorStyle, parseTocAsync } from './scripts/article'
|
||||
import type { Toc } from './scripts/article'
|
||||
import { beforeUpload, onError, picCacheWrapper, picCacheRefresh, uploadForm, uploadDate } from '@renderer/views/picture/scripts/picture'
|
||||
import { useResize } from './scripts/editor-preview-resize'
|
||||
@ -293,7 +293,7 @@ const editorOperator = ref({
|
||||
*/
|
||||
const docsExpand = ref<boolean>(true)
|
||||
const tocsExpand = ref<boolean>(true)
|
||||
const docEditorStyle = computed<DocEditorStyle>(() => {
|
||||
const docEditorStyle = computed<DocsEditorStyle>(() => {
|
||||
if (!docsExpand.value) {
|
||||
return { docs: '0px', editor: '100%' }
|
||||
}
|
||||
|
@ -4,82 +4,135 @@
|
||||
<span>《{{ curArticle?.name }}》</span>
|
||||
<span style="font-size: 9px; padding-right: 5px">{{ curArticle?.id }}</span>
|
||||
</bl-col>
|
||||
|
||||
<bl-row class="wb-page-container">
|
||||
<Transition name="wbpage-one">
|
||||
<bl-row class="wb-page-item" just="flex-end" align="flex-end" v-if="workbenchPage == 1">
|
||||
<el-tooltip effect="light" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div class="iconbl bl-a-leftdirection-line" @click="emits('show-sort')"></div>
|
||||
<template #content>
|
||||
显示排序<br />
|
||||
<bl-row>
|
||||
<bl-tag :bgColor="SortLevelColor.ONE">一级</bl-tag>
|
||||
<bl-tag :bgColor="SortLevelColor.TWO">二级</bl-tag>
|
||||
</bl-row>
|
||||
<bl-row>
|
||||
<bl-tag :bgColor="SortLevelColor.THREE">三级</bl-tag>
|
||||
<bl-tag :bgColor="SortLevelColor.FOUR">四级</bl-tag>
|
||||
</bl-row>
|
||||
</template>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<template #content>
|
||||
<div>全文搜索</div>
|
||||
<div class="keyboard small">Ctrl+Shift+F</div>
|
||||
</template>
|
||||
<div class="iconbl bl-search-line" @click="showSearch()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="刷新" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div class="iconbl bl-a-cloudrefresh-line" @click="refreshDocTree()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<template #content>
|
||||
<div>新增文件夹或文章</div>
|
||||
<div class="keyboard small">{{ keymaps.newDoc }}</div>
|
||||
</template>
|
||||
<div class="iconbl bl-a-fileadd-line" @click="handleShowAddDocInfoDialog()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="文章引用网络" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div class="iconbl bl-correlation-line" @click="openArticleReferenceWindow()"></div>
|
||||
</el-tooltip>
|
||||
</bl-row>
|
||||
</Transition>
|
||||
<bl-row class="wb-page-item" just="flex-start" align="flex-end" width="calc(100% - 16px)" height="44px">
|
||||
<el-tooltip
|
||||
content="文章引用网络"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="-5"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-correlation-line" @click="openArticleReferenceWindow()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="新增文件夹或文章"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-a-fileadd-line" @click="handleShowAddDocInfoDialog()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="刷新"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-a-cloudrefresh-line" @click="refreshDocTree()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="全文搜索"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="9"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-search-line" @click="showSearch()"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" popper-class="is-small" transition="none" placement="top" :show-arrow="false" :offset="5" :hide-after="0">
|
||||
<div class="iconbl bl-a-leftdirection-line" @click="emits('show-sort')"></div>
|
||||
<template #content>
|
||||
显示排序<br />
|
||||
<bl-row>
|
||||
<bl-tag :bgColor="SortLevelColor.ONE">一级</bl-tag>
|
||||
<bl-tag :bgColor="SortLevelColor.TWO">二级</bl-tag>
|
||||
</bl-row>
|
||||
<bl-row style="padding-bottom: 5px">
|
||||
<bl-tag :bgColor="SortLevelColor.THREE">三级</bl-tag>
|
||||
<bl-tag :bgColor="SortLevelColor.FOUR">四级</bl-tag>
|
||||
</bl-row>
|
||||
</template>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="备份记录"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-a-cloudstorage-line" @click="handleShowBackupDialog"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="文章回收站"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div class="iconbl bl-delete-line" @click="handleShowRecycleDialog"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="查看收藏"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div v-if="props.showStar">
|
||||
<div v-if="onlyStars" class="iconbl bl-star-fill" @click="changeOnlyStar()"></div>
|
||||
<div v-else class="iconbl bl-star-line" @click="changeOnlyStar()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="查看专题"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div v-if="props.showSubject">
|
||||
<div v-if="onlySubject" class="iconbl bl-a-lowerrightpage-fill" @click="changeOnlySubject()"></div>
|
||||
<div v-else class="iconbl bl-a-lowerrightpage-line" @click="changeOnlySubject()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="查看公开"
|
||||
effect="light"
|
||||
popper-class="is-small"
|
||||
transition="none"
|
||||
placement="top"
|
||||
:show-arrow="false"
|
||||
:offset="8"
|
||||
:hide-after="0">
|
||||
<div v-if="props.showOpen">
|
||||
<div v-if="onlyOpen" class="iconbl bl-cloud-fill" @click="changeOnlyOpen()"></div>
|
||||
<div v-else class="iconbl bl-cloud-line" @click="changeOnlyOpen()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</bl-row>
|
||||
|
||||
<Transition name="wbpage-two">
|
||||
<bl-row class="wb-page-item" just="flex-end" align="flex-end" v-if="workbenchPage == 2">
|
||||
<el-tooltip content="只显示公开" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div v-if="props.showOpen">
|
||||
<div v-if="onlyOpen" class="iconbl bl-cloud-fill" @click="changeOnlyOpen()"></div>
|
||||
<div v-else class="iconbl bl-cloud-line" @click="changeOnlyOpen()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="只显示专题" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div v-if="props.showSubject">
|
||||
<div v-if="onlySubject" class="iconbl bl-a-lowerrightpage-fill" @click="changeOnlySubject()"></div>
|
||||
<div v-else class="iconbl bl-a-lowerrightpage-line" @click="changeOnlySubject()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="只显示 Star 文章" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div v-if="props.showStar">
|
||||
<div v-if="onlyStars" class="iconbl bl-star-fill" @click="changeOnlyStar()"></div>
|
||||
<div v-else class="iconbl bl-star-line" @click="changeOnlyStar()"></div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="查看回收站" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div class="iconbl bl-delete-line" @click="handleShowRecycleDialog"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="查看备份记录" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
<div class="iconbl bl-a-cloudstorage-line" @click="handleShowBackupDialog"></div>
|
||||
</el-tooltip>
|
||||
</bl-row>
|
||||
</Transition>
|
||||
|
||||
<bl-col width="25px" just="end" class="workbench-page" style="position: absolute; right: 0">
|
||||
<el-icon size="13px" :class="['up', viewStyle.isGlobalShadow ? 'icon-shadow' : '']" @click="toWorkbenchPage(1)">
|
||||
<ArrowUp />
|
||||
</el-icon>
|
||||
<el-icon size="13px" :class="['down', viewStyle.isGlobalShadow ? 'icon-shadow' : '']" @click="toWorkbenchPage(2)">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
<bl-col width="12px" height="30px" just="end" class="workbench-more" style="position: absolute; top: 10px; right: 4px">
|
||||
<div class="iconbl bl-a-morevertical-line" @click="showMoreMenu"></div>
|
||||
</bl-col>
|
||||
</bl-row>
|
||||
</div>
|
||||
@ -121,23 +174,28 @@
|
||||
draggable>
|
||||
<ArticleRecycle ref="ArticleRecycleRef"></ArticleRecycle>
|
||||
</el-dialog>
|
||||
|
||||
<Teleport to="body">
|
||||
<div v-show="moreMenu.show" class="doc-tree-right-menu" :style="{ left: moreMenu.clientX + 'px', top: moreMenu.clientY + 'px', width: '120px' }">
|
||||
<div class="menu-content">
|
||||
<div @click="changeOnlyOpen"><span class="iconbl bl-cloud-line"></span>查看公开</div>
|
||||
<div @click="changeOnlySubject"><span class="iconbl bl-a-lowerrightpage-line"></span>查看专题</div>
|
||||
<div @click="changeOnlyStar"><span class="iconbl bl-star-line"></span>查看收藏</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, inject, onDeactivated } from 'vue'
|
||||
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
|
||||
import { provideKeyCurArticleInfo, SortLevelColor } from '@renderer/views/doc/doc'
|
||||
import { openNewArticleReferenceWindow } from '@renderer/assets/utils/electron'
|
||||
import { useConfigStore } from '@renderer/stores/config'
|
||||
import { keymaps } from './scripts/editor-tools'
|
||||
import { useLifecycle } from '@renderer/scripts/lifecycle'
|
||||
import hotkeys from 'hotkeys-js'
|
||||
import ArticleInfo from './ArticleInfo.vue'
|
||||
import ArticleBackup from './ArticleBackup.vue'
|
||||
import ArticleRecycle from './ArticleRecycle.vue'
|
||||
import { useLifecycle } from '@renderer/scripts/lifecycle'
|
||||
import hotkeys from 'hotkeys-js'
|
||||
import { keymaps } from './scripts/editor-tools'
|
||||
|
||||
const configStore = useConfigStore()
|
||||
const { viewStyle } = configStore
|
||||
|
||||
useLifecycle(
|
||||
() => bindKeys(),
|
||||
@ -163,12 +221,39 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
//#region --------------------------------------------------< 控制台翻页 >--------------------------------------------------
|
||||
//#region --------------------------------------------------< 控制台更多选项 >--------------------------------------------------
|
||||
const moreMenu = ref<RightMenu>({ show: false, clientX: 0, clientY: 0 })
|
||||
|
||||
const workbenchPage = ref(1)
|
||||
/**
|
||||
* 显示右键菜单
|
||||
* @param doc 文档
|
||||
* @param event 事件
|
||||
*/
|
||||
const showMoreMenu = (event: MouseEvent) => {
|
||||
moreMenu.value.show = true
|
||||
nextTick(() => {
|
||||
let y = event.clientY
|
||||
if (document.body.clientHeight - event.clientY < 50) {
|
||||
y = event.clientY - 50
|
||||
}
|
||||
moreMenu.value = { show: true, clientX: event.clientX, clientY: y }
|
||||
setTimeout(() => {
|
||||
document.body.addEventListener('click', closeMoreMenu)
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
const toWorkbenchPage = (page: number) => {
|
||||
workbenchPage.value = page
|
||||
const closeMoreMenu = (event: MouseEvent) => {
|
||||
if (event.target) {
|
||||
let isPrevent = (event.target as HTMLElement).getAttribute('data-bl-prevet')
|
||||
if (isPrevent === 'true') {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
document.body.removeEventListener('click', closeMoreMenu)
|
||||
moreMenu.value.show = false
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@ -285,16 +370,60 @@ defineExpose({ handleShowBackupDialog })
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../doc/tree-workbench.scss';
|
||||
@import '../doc/tree-docs-right-menu.scss';
|
||||
|
||||
.wb-page-container {
|
||||
position: relative;
|
||||
height: 44px;
|
||||
|
||||
.wb-page-item {
|
||||
width: 225px !important;
|
||||
height: 44px;
|
||||
flex-direction: row-reverse !important;
|
||||
align-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
// 排序
|
||||
.bl-a-leftdirection-line {
|
||||
font-size: 27px;
|
||||
padding-bottom: 3px;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
// 搜索
|
||||
.bl-search-line {
|
||||
font-size: 23px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
// 收藏
|
||||
.bl-star-line,
|
||||
.bl-star-fill {
|
||||
font-size: 23px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
// 刷新图标
|
||||
.bl-a-cloudrefresh-line,
|
||||
.bl-a-fileadd-line {
|
||||
&:active {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.bl-correlation-line {
|
||||
@include themeText(2px 3px 4px rgba(107, 104, 104, 0.5), 2px 3px 5px rgb(0, 0, 0));
|
||||
color: var(--el-color-primary) !important;
|
||||
font-size: 40px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ export const TempTextareaKey = 'editor_temp_textarea_value'
|
||||
/**
|
||||
* doc tree and editor width
|
||||
*/
|
||||
export interface DocEditorStyle {
|
||||
export interface DocsEditorStyle {
|
||||
docs: string
|
||||
editor: string
|
||||
}
|
||||
|
@ -1,36 +1,106 @@
|
||||
import { onBeforeUnmount, onMounted, watchEffect } from 'vue'
|
||||
import { onBeforeUnmount, onMounted, ref, watchEffect } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { Local } from '@renderer/assets/utils/storage'
|
||||
|
||||
type Option = {
|
||||
persistent: boolean
|
||||
keyOne: string
|
||||
keyTwo: string
|
||||
defaultOne: string
|
||||
defaultTwo: string
|
||||
maxOne?: number
|
||||
minOne?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 用与拖拽调整调整编辑器和预览部分的宽度
|
||||
* @param editorRef 编辑器
|
||||
* @param previewRef 预览
|
||||
* 拖转改变布局的功能
|
||||
*
|
||||
* @param oneRef 拖转影响到的一个组件
|
||||
* @param twoRef 拓展影响到的另一个组件
|
||||
* @param resizeDividerRef 拖动条
|
||||
* @param twoPendantRef 另一个组件可能存在的挂件
|
||||
* @param options 拖转是否持久化 {
|
||||
* persistent: 是否持久化
|
||||
*
|
||||
* }
|
||||
*/
|
||||
export const useResize = (
|
||||
editorRef: Ref<HTMLElement | undefined>,
|
||||
previewRef: Ref<HTMLElement | undefined>,
|
||||
oneRef: Ref<HTMLElement | undefined>,
|
||||
twoRef: Ref<HTMLElement | undefined>,
|
||||
resizeDividerRef: Ref<HTMLElement | undefined>,
|
||||
operatorRef: Ref<HTMLElement | undefined>
|
||||
twoPendantRef?: Ref<HTMLElement | undefined>,
|
||||
options: Option = {
|
||||
persistent: false,
|
||||
keyOne: '',
|
||||
keyTwo: '',
|
||||
defaultOne: '',
|
||||
defaultTwo: '',
|
||||
maxOne: -1,
|
||||
minOne: -1
|
||||
}
|
||||
) => {
|
||||
let last = {
|
||||
persistent: options.persistent,
|
||||
defaultOne: options.defaultOne,
|
||||
defaultTwo: options.defaultTwo,
|
||||
lastOne: '',
|
||||
lastTwo: ''
|
||||
}
|
||||
|
||||
let timer: NodeJS.Timeout | undefined
|
||||
const debounce = (fn: () => void, time = 200) => {
|
||||
if (timer != undefined) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
timer = setTimeout(fn, time)
|
||||
}
|
||||
|
||||
const hideOne = () => {
|
||||
oneRef.value!.style.width = `0px`
|
||||
twoRef.value!.style.width = `calc(100% - 2px)`
|
||||
}
|
||||
|
||||
const resotreOne = () => {
|
||||
oneRef.value!.style.width = last.lastOne
|
||||
twoRef.value!.style.width = last.lastTwo
|
||||
}
|
||||
|
||||
const persistent = () => {
|
||||
if (options.persistent) {
|
||||
debounce(() => {
|
||||
last.lastOne = oneRef.value!.style.width
|
||||
last.lastTwo = twoRef.value!.style.width
|
||||
Local.set(options.keyOne, last.lastOne)
|
||||
Local.set(options.keyTwo, last.lastTwo)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onMousedown = (_e: MouseEvent) => {
|
||||
const targetRect = editorRef.value!.getBoundingClientRect()
|
||||
const targetRect = oneRef.value!.getBoundingClientRect()
|
||||
// editor 距离应用左侧的距离
|
||||
const targetLeft = targetRect.left
|
||||
|
||||
resizeDividerRef.value!.style.borderLeft = '2px dashed var(--el-color-primary)'
|
||||
document.body.style.cursor = 'ew-resize'
|
||||
|
||||
const onMousemove = (e: MouseEvent) => {
|
||||
const x = Math.max(0, e.clientX - targetLeft)
|
||||
editorRef.value!.style.width = `${x}px`
|
||||
operatorRef.value!.style.left = `${x + 1}px`
|
||||
previewRef.value!.style.width = `calc(100% - ${x}px - 3px)`
|
||||
let oneWidth = Math.max(0, e.clientX - targetLeft)
|
||||
if (options.maxOne && options.maxOne > 0) {
|
||||
oneWidth = Math.min(options.maxOne, oneWidth)
|
||||
}
|
||||
if (options.minOne && options.minOne > 0) {
|
||||
oneWidth = Math.max(options.minOne, oneWidth)
|
||||
}
|
||||
oneRef.value!.style.width = `${oneWidth}px`
|
||||
twoRef.value!.style.width = `calc(100% - ${oneWidth}px - 2px)`
|
||||
if (twoPendantRef) {
|
||||
twoPendantRef.value!.style.left = `${oneWidth}px`
|
||||
}
|
||||
persistent()
|
||||
}
|
||||
|
||||
const onMouseup = () => {
|
||||
document.body.style.cursor = 'auto'
|
||||
resizeDividerRef.value!.style.borderLeft = '2px solid var(--el-border-color)'
|
||||
document.removeEventListener('mousemove', onMousemove)
|
||||
document.removeEventListener('mouseup', onMouseup)
|
||||
}
|
||||
@ -40,18 +110,24 @@ export const useResize = (
|
||||
}
|
||||
|
||||
const onResize = () => {
|
||||
if (previewRef.value && editorRef.value && resizeDividerRef.value) {
|
||||
if (twoRef.value && oneRef.value && resizeDividerRef.value) {
|
||||
resizeDividerRef.value.addEventListener('mousedown', onMousedown)
|
||||
}
|
||||
}
|
||||
|
||||
const offResize = () => {
|
||||
if (previewRef.value && editorRef.value && resizeDividerRef.value) {
|
||||
if (twoRef.value && oneRef.value && resizeDividerRef.value) {
|
||||
resizeDividerRef.value.removeEventListener('mousedown', onMousedown)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (options.persistent) {
|
||||
oneRef.value!.style.width = Local.get(options.keyOne) || options.defaultOne
|
||||
twoRef.value!.style.width = Local.get(options.keyTwo) || options.defaultTwo
|
||||
last.lastOne = oneRef.value!.style.width
|
||||
last.lastTwo = twoRef.value!.style.width
|
||||
}
|
||||
watchEffect(() => {
|
||||
onResize()
|
||||
})
|
||||
@ -60,4 +136,6 @@ export const useResize = (
|
||||
onBeforeUnmount(() => {
|
||||
offResize()
|
||||
})
|
||||
|
||||
return { last, hideOne, resotreOne }
|
||||
}
|
||||
|
@ -2,10 +2,45 @@
|
||||
@include box(100%, 100%);
|
||||
@include flex(row, flex-start, center);
|
||||
|
||||
.resize-divider,
|
||||
.resize-docs-divider {
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
z-index: 4;
|
||||
background-color: var(--el-border-color);
|
||||
z-index: 1001;
|
||||
position: relative;
|
||||
cursor: ew-resize;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 3px;
|
||||
display: block;
|
||||
height: 100%;
|
||||
transition: 0.3s;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
left: -1px;
|
||||
z-index: 1002;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::before {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.resize-docs-divider {
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
// 文档
|
||||
.doc-container {
|
||||
@include flex(column, flex-start, center);
|
||||
height: 100%;
|
||||
min-width: 250px;
|
||||
font-weight: 200;
|
||||
|
||||
.doc-tree-menu-container {
|
||||
@ -54,9 +89,8 @@
|
||||
|
||||
// 编辑器内容
|
||||
.editor-container {
|
||||
@include box(100%, 100%);
|
||||
@include box(calc(100% - 2px), 100%);
|
||||
position: relative;
|
||||
border-left: 1px solid var(--el-border-color);
|
||||
background-color: #ffffff00;
|
||||
|
||||
$heightTools: 45px;
|
||||
@ -79,8 +113,10 @@
|
||||
position: absolute;
|
||||
z-index: 1999;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
width: calc(100% - 1px);
|
||||
background-color: var(--bl-html-color);
|
||||
overflow: hidden;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.gutter-holder {
|
||||
@ -188,19 +224,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.resize-divider {
|
||||
height: 100%;
|
||||
border-left: 2px solid var(--el-border-color);
|
||||
margin-left: 1px;
|
||||
z-index: 4;
|
||||
position: relative;
|
||||
cursor: ew-resize;
|
||||
|
||||
&:hover {
|
||||
border-left: 2px dashed var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-marked {
|
||||
@include box(50%, 100%);
|
||||
overflow-y: scroll;
|
||||
|
@ -11,32 +11,17 @@
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.workbench-page {
|
||||
@include themeColor(#909399, #535353);
|
||||
padding: 5px;
|
||||
.workbench-more {
|
||||
@include themeBg(#f5f5f5);
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
.up {
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
.down {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
@include box(15px, 15px);
|
||||
@include themeBg(#f1f1f1, #333434);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
@include themeBg(#eaeaea, #000);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-shadow {
|
||||
@include themeShadow(0 0 3px #aeaeae, 0 0 3px rgb(0, 0, 0));
|
||||
.iconbl {
|
||||
@include themeColor(#a9a9a9, #969696);
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: -6px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,77 +40,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.bl-a-leftdirection-line {
|
||||
padding-bottom: 5px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.bl-search-line {
|
||||
font-size: 22px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
// 公开图标
|
||||
// .bl-cloud-fill {
|
||||
// color: #7ac20c;
|
||||
// @include themeText(0px 5px 5px #79c20ca4, 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
|
||||
// .bl-cloud-fill,
|
||||
// .bl-cloud-line {
|
||||
// &:hover {
|
||||
// color: #7ac20c;
|
||||
// @include themeText(5px 5px 5px #79c20ca4, 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
// }
|
||||
|
||||
// 专题图标
|
||||
// .bl-a-lowerrightpage-fill {
|
||||
// color: salmon;
|
||||
// @include themeText(0px 5px 5px rgba(250, 128, 114, 0.546), 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
|
||||
// 专题图标
|
||||
// .bl-a-lowerrightpage-fill,
|
||||
// .bl-a-lowerrightpage-line {
|
||||
// &:hover {
|
||||
// color: salmon;
|
||||
// @include themeText(5px 5px 5px rgba(250, 128, 114, 0.546), 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
// }
|
||||
|
||||
// star 图标
|
||||
// .bl-star-fill {
|
||||
// color: rgb(237, 204, 11);
|
||||
// @include themeText(0px 5px 5px rgba(237, 204, 11, 0.546), 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
|
||||
.bl-star-line,
|
||||
.bl-star-fill {
|
||||
font-size: 23px;
|
||||
padding-bottom: 5px;
|
||||
|
||||
// &:hover {
|
||||
// color: rgb(237, 204, 11);
|
||||
// @include themeText(5px 5px 5px rgba(237, 203, 11, 0.756), 2px 3px 5px rgba(183, 183, 183, 0.8));
|
||||
// }
|
||||
}
|
||||
|
||||
// 刷新图标
|
||||
.bl-a-cloudrefresh-line,
|
||||
.bl-a-fileadd-line {
|
||||
&:active {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.bl-a-fileadd-line {
|
||||
}
|
||||
|
||||
.bl-correlation-line {
|
||||
@include themeText(2px 3px 4px rgba(107, 104, 104, 0.5), 2px 3px 5px rgb(0, 0, 0));
|
||||
color: var(--el-color-primary) !important;
|
||||
font-size: 40px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user