feat: add catalog demo
This commit is contained in:
+12
@@ -303,9 +303,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="catalog" editor-component="catalog">
|
||||||
|
<div class="catalog__header">
|
||||||
|
<span>目录</span>
|
||||||
|
<div class="catalog__header__close">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="catalog__main"></div>
|
||||||
|
</div>
|
||||||
<div class="editor"></div>
|
<div class="editor"></div>
|
||||||
<div class="footer" editor-component="footer">
|
<div class="footer" editor-component="footer">
|
||||||
<div>
|
<div>
|
||||||
|
<div class="catalog-mode" title="目录">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
<div class="page-mode">
|
<div class="page-mode">
|
||||||
<i title="页面模式(分页、连页)"></i>
|
<i title="页面模式(分页、连页)"></i>
|
||||||
<div class="options">
|
<div class="options">
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757"><path d="M13 0c.552 0 1 .48 1 1.071V13.93c0 .59-.448 1.07-1 1.07H3c-.552 0-1-.48-1-1.071V1.07C2 .48 2.448 0 3 0h10zm0 1H3v13h10V1z"/><path d="M5 10v1H4v-1h1zm6 0v1H6v-1h5zM5 7v1H4V7h1zm6 0v1H6V7h5zM5 4v1H4V4h1zm6 0v1H6V4h5z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 337 B |
@@ -4,7 +4,8 @@ export enum EditorComponent {
|
|||||||
MAIN = 'main',
|
MAIN = 'main',
|
||||||
FOOTER = 'footer',
|
FOOTER = 'footer',
|
||||||
CONTEXTMENU = 'contextmenu',
|
CONTEXTMENU = 'contextmenu',
|
||||||
POPUP = 'popup'
|
POPUP = 'popup',
|
||||||
|
CATALOG = 'catalog'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EditorContext {
|
export enum EditorContext {
|
||||||
|
|||||||
+4
-1
@@ -42,6 +42,7 @@ import { ITitleOption } from './interface/Title'
|
|||||||
import { defaultTitleOption } from './dataset/constant/Title'
|
import { defaultTitleOption } from './dataset/constant/Title'
|
||||||
import { TitleLevel } from './dataset/enum/Title'
|
import { TitleLevel } from './dataset/enum/Title'
|
||||||
import { ListStyle, ListType } from './dataset/enum/List'
|
import { ListStyle, ListType } from './dataset/enum/List'
|
||||||
|
import { ICatalog, ICatalogItem } from './interface/Catalog'
|
||||||
|
|
||||||
export default class Editor {
|
export default class Editor {
|
||||||
|
|
||||||
@@ -216,5 +217,7 @@ export type {
|
|||||||
IWatermark,
|
IWatermark,
|
||||||
INavigateInfo,
|
INavigateInfo,
|
||||||
IBlock,
|
IBlock,
|
||||||
ILang
|
ILang,
|
||||||
|
ICatalog,
|
||||||
|
ICatalogItem
|
||||||
}
|
}
|
||||||
+57
-4
@@ -1,10 +1,11 @@
|
|||||||
import { data, options } from './mock'
|
import { data, options } from './mock'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import prism from 'prismjs'
|
import prism from 'prismjs'
|
||||||
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, IElement, KeyMap, ListStyle, ListType, PageMode, PaperDirection, RowFlex, TitleLevel } from './editor'
|
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, ICatalogItem, IElement, KeyMap, ListStyle, ListType, PageMode, PaperDirection, RowFlex, TitleLevel } from './editor'
|
||||||
import { Dialog } from './components/dialog/Dialog'
|
import { Dialog } from './components/dialog/Dialog'
|
||||||
import { formatPrismToken } from './utils/prism'
|
import { formatPrismToken } from './utils/prism'
|
||||||
import { Signature } from './components/signature/Signature'
|
import { Signature } from './components/signature/Signature'
|
||||||
|
import { debounce } from './utils'
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
const isApple = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent)
|
const isApple = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent)
|
||||||
@@ -844,7 +845,54 @@ window.onload = function () {
|
|||||||
instance.command.executePrint()
|
instance.command.executePrint()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. 页面模式 | 纸张缩放 | 纸张大小 | 纸张方向 | 页边距 | 全屏
|
// 6. 目录显隐 | 页面模式 | 纸张缩放 | 纸张大小 | 纸张方向 | 页边距 | 全屏
|
||||||
|
async function updateCatalog() {
|
||||||
|
const catalog = await instance.command.getCatalog()
|
||||||
|
const catalogMainDom = document.querySelector<HTMLDivElement>('.catalog__main')!
|
||||||
|
catalogMainDom.innerHTML = ''
|
||||||
|
if (catalog) {
|
||||||
|
const appendCatalog = (parent: HTMLDivElement, catalogItems: ICatalogItem[]) => {
|
||||||
|
for (let c = 0; c < catalogItems.length; c++) {
|
||||||
|
const catalogItem = catalogItems[c]
|
||||||
|
const catalogItemDom = document.createElement('div')
|
||||||
|
catalogItemDom.classList.add('catalog-item')
|
||||||
|
// 渲染
|
||||||
|
const catalogItemContentDom = document.createElement('div')
|
||||||
|
catalogItemContentDom.classList.add('catalog-item__content')
|
||||||
|
const catalogItemContentSpanDom = document.createElement('span')
|
||||||
|
catalogItemContentSpanDom.innerText = catalogItem.name
|
||||||
|
catalogItemContentDom.append(catalogItemContentSpanDom)
|
||||||
|
// 定位
|
||||||
|
catalogItemContentDom.onclick = () => {
|
||||||
|
instance.command.executeLocationCatalog(catalogItem.id)
|
||||||
|
}
|
||||||
|
catalogItemDom.append(catalogItemContentDom)
|
||||||
|
if (catalogItem.subCatalog && catalogItem.subCatalog.length) {
|
||||||
|
appendCatalog(catalogItemDom, catalogItem.subCatalog)
|
||||||
|
}
|
||||||
|
// 追加
|
||||||
|
parent.append(catalogItemDom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendCatalog(catalogMainDom, catalog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let isCatalogShow = true
|
||||||
|
const catalogDom = document.querySelector<HTMLElement>('.catalog')!
|
||||||
|
const catalogModeDom = document.querySelector<HTMLDivElement>('.catalog-mode')!
|
||||||
|
const catalogHeaderCloseDom = document.querySelector<HTMLDivElement>('.catalog__header__close')!
|
||||||
|
const switchCatalog = () => {
|
||||||
|
isCatalogShow = !isCatalogShow
|
||||||
|
if (isCatalogShow) {
|
||||||
|
catalogDom.style.display = 'block'
|
||||||
|
updateCatalog()
|
||||||
|
} else {
|
||||||
|
catalogDom.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catalogModeDom.onclick = switchCatalog
|
||||||
|
catalogHeaderCloseDom.onclick = switchCatalog
|
||||||
|
|
||||||
const pageModeDom = document.querySelector<HTMLDivElement>('.page-mode')!
|
const pageModeDom = document.querySelector<HTMLDivElement>('.page-mode')!
|
||||||
const pageModeOptionsDom = pageModeDom.querySelector<HTMLDivElement>('.options')!
|
const pageModeOptionsDom = pageModeDom.querySelector<HTMLDivElement>('.options')!
|
||||||
pageModeDom.onclick = function () {
|
pageModeDom.onclick = function () {
|
||||||
@@ -1158,10 +1206,15 @@ window.onload = function () {
|
|||||||
activeMode.classList.add('active')
|
activeMode.classList.add('active')
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.listener.contentChange = async function () {
|
instance.listener.contentChange = debounce(async function () {
|
||||||
|
// 字数
|
||||||
const wordCount = await instance.command.getWordCount()
|
const wordCount = await instance.command.getWordCount()
|
||||||
document.querySelector<HTMLSpanElement>('.word-count')!.innerText = `${wordCount || 0}`
|
document.querySelector<HTMLSpanElement>('.word-count')!.innerText = `${wordCount || 0}`
|
||||||
}
|
// 目录
|
||||||
|
if (isCatalogShow) {
|
||||||
|
updateCatalog()
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
|
||||||
instance.listener.saved = function (payload) {
|
instance.listener.saved = function (payload) {
|
||||||
console.log('elementList: ', payload)
|
console.log('elementList: ', payload)
|
||||||
|
|||||||
+87
-1
@@ -651,11 +651,83 @@ ul {
|
|||||||
background-image: url('./assets/images/print.svg');
|
background-image: url('./assets/images/print.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.catalog {
|
||||||
|
width: 250px;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
top: 100px;
|
||||||
|
padding: 0 20px 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog .catalog__header {
|
||||||
|
height: 48px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #e2e6ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog .catalog__header span {
|
||||||
|
color: #3d4757;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog .catalog__header i {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
background: url(./assets/images/close.svg) no-repeat;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog .catalog__header>div:hover {
|
||||||
|
background: rgba(235, 238, 241);
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main {
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
padding: 10px 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main .catalog-item {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main>.catalog-item {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main .catalog-item .catalog-item__content {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main .catalog-item .catalog-item__content:hover>span {
|
||||||
|
color: #4991f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog__main .catalog-item .catalog-item__content span {
|
||||||
|
color: #3d4757;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.editor>div {
|
.editor>div {
|
||||||
margin: 80px auto;
|
margin: 80px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.ce-page-container canvas {
|
.ce-page-container canvas {
|
||||||
box-shadow: rgb(158 161 165 / 40%) 0px 2px 12px 0px;
|
box-shadow: rgb(158 161 165 / 40%) 0px 2px 12px 0px;
|
||||||
}
|
}
|
||||||
@@ -681,6 +753,20 @@ ul {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer .catalog-mode {
|
||||||
|
padding: 1px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .catalog-mode i {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
background-image: url('./assets/images/catalog.svg');
|
||||||
|
}
|
||||||
|
|
||||||
.footer .page-mode {
|
.footer .page-mode {
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export function debounce(func: Function, delay: number) {
|
||||||
|
let timer: number
|
||||||
|
return function (...args: any) {
|
||||||
|
if (timer) {
|
||||||
|
window.clearTimeout(timer)
|
||||||
|
}
|
||||||
|
timer = window.setTimeout(() => {
|
||||||
|
// @ts-ignore
|
||||||
|
func.apply(this, args)
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user