@smartos-lib/components 1.7.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +12 -0
- package/.eslintrc-auto-import.json +332 -0
- package/Components.code-workspace +143 -0
- package/LICENSE +21 -0
- package/dist/smart-docx-editor/index.d.ts +2 -0
- package/dist/smart-docx-editor/index.js +68 -0
- package/dist/smart-file-preview/index.d.ts +18 -0
- package/dist/smart-file-preview/index.js +37 -0
- package/dist/smart-upload/index.d.ts +2 -0
- package/dist/smart-upload/index.js +800 -0
- package/index.html +16 -0
- package/package.json +23 -0
- package/public/favicon.svg +6 -0
- package/scripts/components.vite.config.ts +96 -0
- package/scripts/shared.ts +9 -0
- package/src/App.vue +28 -0
- package/src/components/Logo/index.vue +15 -0
- package/src/components-private/.gitkeep +0 -0
- package/src/composables/useElementStyle.ts +23 -0
- package/src/composables/useNaiveStyle.ts +43 -0
- package/src/composables/useNaiveTheme.ts +71 -0
- package/src/composables/useSmart.ts +36 -0
- package/src/layouts/default.vue +3 -0
- package/src/main.ts +33 -0
- package/src/modules/pinia/index.ts +8 -0
- package/src/modules/progress/index.ts +12 -0
- package/src/modules/router/install.ts +9 -0
- package/src/modules/router/routes.ts +40 -0
- package/src/pages/[...all].vue +21 -0
- package/src/pages/frame/component/[name].vue +14 -0
- package/src/pages/frame/index.vue +81 -0
- package/src/pages/index/composables/useTabsManage.ts +46 -0
- package/src/pages/index/index.vue +111 -0
- package/src/pages/index/type.ts +13 -0
- package/src/pages/index/utils/index.ts +41 -0
- package/src/settings.ts +9 -0
- package/src/shared/components.ts +52 -0
- package/src/shared/env.ts +11 -0
- package/src/shared/unocss.theme.ts +1600 -0
- package/src/stores/theme.ts +29 -0
- package/src/styles/element.scss +3 -0
- package/src/styles/styles.scss +21 -0
- package/src/types.ts +20 -0
- package/src/utils/callCustomElementExposed.ts +6 -0
- package/src/utils/deepCloneESModule.ts +10 -0
- package/src/utils/defineCustomElements.ts +18 -0
- package/src/utils/formatComponentsGlob.ts +16 -0
- package/src/utils/getFileMD5.ts +31 -0
- package/src/utils/getFileNameAndExt.ts +11 -0
- package/src/utils/isFileEqual.ts +13 -0
- package/src/utils/jsonToFormData.ts +8 -0
- package/src/web-components/smart-docx-drive-page/App.vue +37 -0
- package/src/web-components/smart-docx-drive-page/apis/doc.ts +85 -0
- package/src/web-components/smart-docx-drive-page/apis/file.ts +278 -0
- package/src/web-components/smart-docx-drive-page/apis/folder.ts +72 -0
- package/src/web-components/smart-docx-drive-page/children/Home.vue +8 -0
- package/src/web-components/smart-docx-drive-page/children/Me.vue +47 -0
- package/src/web-components/smart-docx-drive-page/components/CustomImage.vue +26 -0
- package/src/web-components/smart-docx-drive-page/components/CustomPopover.vue +62 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDir.vue +99 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDoc.vue +132 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDownloadPopoverItem.vue +41 -0
- package/src/web-components/smart-docx-drive-page/components/DocxFileList.vue +156 -0
- package/src/web-components/smart-docx-drive-page/components/DocxPreview.vue +33 -0
- package/src/web-components/smart-docx-drive-page/components/DocxUpload.vue +164 -0
- package/src/web-components/smart-docx-drive-page/components/FileIcon.vue +62 -0
- package/src/web-components/smart-docx-drive-page/components-private/Header.vue +65 -0
- package/src/web-components/smart-docx-drive-page/components-private/Logo.vue +15 -0
- package/src/web-components/smart-docx-drive-page/components-private/Menu.vue +34 -0
- package/src/web-components/smart-docx-drive-page/components-private/Navbar.vue +36 -0
- package/src/web-components/smart-docx-drive-page/composables/useFullscreenElDialog.ts +41 -0
- package/src/web-components/smart-docx-drive-page/composables/usePrompt.ts +73 -0
- package/src/web-components/smart-docx-drive-page/data.ts +10 -0
- package/src/web-components/smart-docx-drive-page/external-style/custom-popover.sass +8 -0
- package/src/web-components/smart-docx-drive-page/external-style/index.sass +1 -0
- package/src/web-components/smart-docx-drive-page/index.ts +20 -0
- package/src/web-components/smart-docx-drive-page/index.vue +39 -0
- package/src/web-components/smart-docx-drive-page/info.ts +2 -0
- package/src/web-components/smart-docx-drive-page/stores/menu.ts +60 -0
- package/src/web-components/smart-docx-drive-page/types.ts +51 -0
- package/src/web-components/smart-docx-drive-page/utils/file-actions.ts +63 -0
- package/src/web-components/smart-docx-drive-page/utils/file.ts +31 -0
- package/src/web-components/smart-docx-editor/App.vue +32 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Markdown.vue +202 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Menu.vue +100 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/types.ts +6 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/Markdown.tsx +71 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/MarkdownElement.tsx +81 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.sass +6 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.tsx +12 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.sass +14 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.tsx +17 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.scss +16 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.tsx +39 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/types/custom-types.d.ts +69 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/composables/useTextSelection.ts +50 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.sass +19 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.vue +21 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/shared/const.ts +23 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/utils/slateHelpers.ts +23 -0
- package/src/web-components/smart-docx-editor/data.ts +38 -0
- package/src/web-components/smart-docx-editor/demo.vue +11 -0
- package/src/web-components/smart-docx-editor/index.md +3 -0
- package/src/web-components/smart-docx-editor/index.ts +5 -0
- package/src/web-components/smart-docx-editor/index.vue +12 -0
- package/src/web-components/smart-docx-editor/info.ts +2 -0
- package/src/web-components/smart-file-preview/category/Code.vue +171 -0
- package/src/web-components/smart-file-preview/category/Image.vue +49 -0
- package/src/web-components/smart-file-preview/category/Pdf.vue +14 -0
- package/src/web-components/smart-file-preview/category/Video.vue +27 -0
- package/src/web-components/smart-file-preview/demo.vue +34 -0
- package/src/web-components/smart-file-preview/index.md +5 -0
- package/src/web-components/smart-file-preview/index.ts +29 -0
- package/src/web-components/smart-file-preview/index.vue +56 -0
- package/src/web-components/smart-file-preview/info.ts +2 -0
- package/src/web-components/smart-file-preview/shared/const.ts +4 -0
- package/src/web-components/smart-file-preview/types.ts +38 -0
- package/src/web-components/smart-upload/index.ts +5 -0
- package/src/web-components/smart-upload/index.vue +101 -0
- package/src/web-components/smart-upload/info.ts +2 -0
- package/src/web-components/smart-upload/types.ts +28 -0
- package/tsconfig.json +15 -0
- package/types/auto-imports.d.ts +975 -0
- package/types/components.d.ts +14 -0
- package/types/env.d.ts +8 -0
- package/types/shims.d.ts +6 -0
- package/unocss.config.ts +23 -0
- package/vite.config.ts +60 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RenderElementProps } from 'slate-react';
|
|
2
|
+
import type { HeadingElement } from '../../types/custom-types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 标题
|
|
6
|
+
*/
|
|
7
|
+
export function Heading(props: RenderElementProps) {
|
|
8
|
+
const element = props.element as HeadingElement;
|
|
9
|
+
|
|
10
|
+
const Tag = `docx-h${element.level}`;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Tag {...props.attributes}>
|
|
14
|
+
{props.children}
|
|
15
|
+
</Tag>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
docx-ul, docx-ol, docx-li {
|
|
2
|
+
@apply block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
docx-li {
|
|
6
|
+
@apply list-none;
|
|
7
|
+
|
|
8
|
+
&:not(.ordered) {
|
|
9
|
+
@apply relative lh-6 pl-6;
|
|
10
|
+
@apply before-(
|
|
11
|
+
content-[''] size-6 i-ci-dot-01-xs pointer-events-none
|
|
12
|
+
flex justify-left items-center
|
|
13
|
+
absolute top-0 left-0 -translate-x-1/4
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { RenderElementProps } from 'slate-react';
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
import type { ListElement } from '../../types/custom-types';
|
|
4
|
+
|
|
5
|
+
const { Provider, Consumer } = createContext(false);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 列表
|
|
9
|
+
*/
|
|
10
|
+
export function List(props: RenderElementProps) {
|
|
11
|
+
const element = props.element as ListElement;
|
|
12
|
+
|
|
13
|
+
const Tag = `docx-${element.ordered ? 'o' : 'u'}l`;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Provider value={!!element.ordered}>
|
|
17
|
+
<Tag {...props.attributes}>
|
|
18
|
+
{props.children}
|
|
19
|
+
</Tag>
|
|
20
|
+
</Provider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 列表项
|
|
26
|
+
*/
|
|
27
|
+
export function ListItem(props: RenderElementProps) {
|
|
28
|
+
return (
|
|
29
|
+
<Consumer>
|
|
30
|
+
{(ordered) => {
|
|
31
|
+
return (
|
|
32
|
+
<docx-li className={ordered ? 'ordered' : ''}>
|
|
33
|
+
{props.children}
|
|
34
|
+
</docx-li>
|
|
35
|
+
);
|
|
36
|
+
}}
|
|
37
|
+
</Consumer>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BaseEditor, BaseRange, Descendant } from "slate"
|
|
2
|
+
import { ReactEditor } from "slate-react"
|
|
3
|
+
import { HistoryEditor } from 'slate-history'
|
|
4
|
+
|
|
5
|
+
/** 段落节点 */
|
|
6
|
+
export type ParagraphElement = {
|
|
7
|
+
type: 'paragraph'
|
|
8
|
+
align?: string
|
|
9
|
+
children: Descendant[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** 标题节点 - H1 ~ H6 */
|
|
13
|
+
export type HeadingElement = {
|
|
14
|
+
type: 'heading'
|
|
15
|
+
level: string
|
|
16
|
+
children: Descendant[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 引用节点 */
|
|
20
|
+
export type BlockquoteElement = {
|
|
21
|
+
type: 'blockquote'
|
|
22
|
+
children: Descendant[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 列表节点 */
|
|
26
|
+
export type ListElement = {
|
|
27
|
+
type: 'list'
|
|
28
|
+
/** 是否为有序列表 */
|
|
29
|
+
ordered?: boolean
|
|
30
|
+
children: Descendant[]
|
|
31
|
+
}
|
|
32
|
+
/** 列表项节点 */
|
|
33
|
+
export type ListItemElement = {
|
|
34
|
+
type: 'list-item'
|
|
35
|
+
children: Descendant[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 所有自定义节点 */
|
|
39
|
+
type CustomElement = ParagraphElement |
|
|
40
|
+
HeadingElement |
|
|
41
|
+
BlockquoteElement |
|
|
42
|
+
ListElement |
|
|
43
|
+
ListItemElement;
|
|
44
|
+
|
|
45
|
+
/** 文本节点 */
|
|
46
|
+
type CustomText = {
|
|
47
|
+
bold?: boolean
|
|
48
|
+
italic?: boolean
|
|
49
|
+
del?: boolean
|
|
50
|
+
underline?: boolean
|
|
51
|
+
code?: boolean
|
|
52
|
+
text: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 扩展的编辑器类型 */
|
|
56
|
+
type CustomEditor = BaseEditor & ReactEditor & HistoryEditor & {
|
|
57
|
+
nodeToDecorations?: Map<Element, Range[]>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
declare module 'slate' {
|
|
61
|
+
interface CustomTypes {
|
|
62
|
+
Editor: CustomEditor
|
|
63
|
+
Element: CustomElement
|
|
64
|
+
Text: CustomText
|
|
65
|
+
Range: BaseRange & {
|
|
66
|
+
[key: string]: unknown
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/web-components/smart-docx-editor/MarkdownShortcuts/composables/useTextSelection.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { shadowRoot } from '../shared/const';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取文档选区
|
|
5
|
+
*/
|
|
6
|
+
export const useTextSelection = createSharedComposable(() => {
|
|
7
|
+
const selection = ref<Selection | null>(null);
|
|
8
|
+
const text = computed(() => selection.value?.toString() ?? '');
|
|
9
|
+
|
|
10
|
+
const isValidSelection = computed(() => text.value && selection.value!.rangeCount > 0);
|
|
11
|
+
|
|
12
|
+
const range = computed(() => {
|
|
13
|
+
if (isValidSelection.value) {
|
|
14
|
+
const range = selection.value!.getRangeAt(0).cloneRange();
|
|
15
|
+
|
|
16
|
+
// 使选区在鼠标终点处折叠
|
|
17
|
+
range.collapse(range.startContainer === selection.value!.focusNode);
|
|
18
|
+
|
|
19
|
+
// 修复选区在文本开头时,无法获取到正确的位置的问题
|
|
20
|
+
if (range.startOffset === 0) {
|
|
21
|
+
const newRange = document.createRange();
|
|
22
|
+
newRange.setStart(range.startContainer, 0);
|
|
23
|
+
newRange.setEnd(range.startContainer, 1);
|
|
24
|
+
return newRange;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return range;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const onValidSelectionUpdate = createEventHook<Selection>();
|
|
32
|
+
|
|
33
|
+
wheneverEffectScopeImmediate(shadowRoot, () => {
|
|
34
|
+
useEventListener(window.document, 'selectionchange', () => {
|
|
35
|
+
selection.value = null;
|
|
36
|
+
selection.value = shadowRoot.value.getSelection();
|
|
37
|
+
|
|
38
|
+
if (isValidSelection.value)
|
|
39
|
+
onValidSelectionUpdate.trigger(selection.value!);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
text,
|
|
45
|
+
isValidSelection,
|
|
46
|
+
range,
|
|
47
|
+
selection,
|
|
48
|
+
onValidSelectionUpdate: onValidSelectionUpdate.on,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* Markdown 样式 */
|
|
2
|
+
|
|
3
|
+
// 代码转换层
|
|
4
|
+
[data-use-vue-component-wrap], [__use_react_component_wrap]
|
|
5
|
+
@apply contents
|
|
6
|
+
|
|
7
|
+
// 根元素
|
|
8
|
+
.smart-docx-editor
|
|
9
|
+
@apply root size-full outline-none
|
|
10
|
+
|
|
11
|
+
> :first-child
|
|
12
|
+
@apply important:mt-0
|
|
13
|
+
|
|
14
|
+
// 标题
|
|
15
|
+
@import "./components-react/elements/Heading/index.sass"
|
|
16
|
+
// 引用
|
|
17
|
+
@import "./components-react/elements/Blockquote/index.sass"
|
|
18
|
+
// 列表 | 列表项
|
|
19
|
+
@import "./components-react/elements/List/index.scss"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- Markdown 功能组装层 / 样式层 -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<!-- Markdown -->
|
|
5
|
+
<Markdown v-bind="props" />
|
|
6
|
+
|
|
7
|
+
<!-- 菜单栏 -->
|
|
8
|
+
<Menu />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import Menu from './components/Menu.vue';
|
|
13
|
+
import Markdown from './components/Markdown.vue';
|
|
14
|
+
import type { MarkdownProps } from './components/types';
|
|
15
|
+
|
|
16
|
+
const props = defineProps<Pick<MarkdownProps, 'initialValue'>>();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<style lang="sass">
|
|
20
|
+
@import url("./index.sass")
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BaseSelection, Descendant, Editor } from 'slate';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 编辑器实例
|
|
5
|
+
*/
|
|
6
|
+
export const editor = ref() as Ref<Editor>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 编辑器 ShadowRoot
|
|
10
|
+
*/
|
|
11
|
+
export const shadowRoot = ref() as Ref<ShadowRoot & {
|
|
12
|
+
getSelection: Window['getSelection']
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 选区变化的事件回调
|
|
17
|
+
*/
|
|
18
|
+
export const selectionChange = createEventHook<BaseSelection>();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 值变化的事件回调
|
|
22
|
+
*/
|
|
23
|
+
export const valueChange = createEventHook<Descendant[]>();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Editor } from 'slate';
|
|
2
|
+
import { editor } from '../shared/const';
|
|
3
|
+
import type { CustomText } from '../components-react/types/custom-types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 判断当前选区是否是某个格式
|
|
7
|
+
*/
|
|
8
|
+
export function isMarkActive(format: keyof Omit<CustomText, 'text'>) {
|
|
9
|
+
const marks = Editor.marks(editor.value);
|
|
10
|
+
return marks ? marks[format] === true : false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 切换选区的格式
|
|
15
|
+
*/
|
|
16
|
+
export function toggleMark(format: keyof Omit<CustomText, 'text'>) {
|
|
17
|
+
const isActive = isMarkActive(format);
|
|
18
|
+
|
|
19
|
+
if (isActive)
|
|
20
|
+
Editor.removeMark(editor.value, format);
|
|
21
|
+
else
|
|
22
|
+
Editor.addMark(editor.value, format, true);
|
|
23
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const 所有支持的节点 = {
|
|
2
|
+
initialValue: [
|
|
3
|
+
{
|
|
4
|
+
type: 'paragraph',
|
|
5
|
+
children: [
|
|
6
|
+
{ text: '段落, 可以是' },
|
|
7
|
+
{ text: '粗体, ', bold: true },
|
|
8
|
+
{ text: '也可以' },
|
|
9
|
+
{ text: '是斜体', italic: true },
|
|
10
|
+
{ text: '和包含' },
|
|
11
|
+
{ text: '删除线', del: true },
|
|
12
|
+
{ text: '及' },
|
|
13
|
+
{ text: '下划线', underline: true },
|
|
14
|
+
{ text: '的文本' },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{ type: 'heading', level: '1', children: [{ text: 'H1 标题' }] },
|
|
18
|
+
{ type: 'heading', level: '2', children: [{ text: 'H2 标题' }] },
|
|
19
|
+
{ type: 'heading', level: '3', children: [{ text: 'H3 标题' }] },
|
|
20
|
+
{ type: 'heading', level: '4', children: [{ text: 'H4 标题' }] },
|
|
21
|
+
{ type: 'heading', level: '5', children: [{ text: 'H5 标题' }] },
|
|
22
|
+
{ type: 'heading', level: '6', children: [{ text: 'H6 标题' }] },
|
|
23
|
+
{
|
|
24
|
+
type: 'blockquote',
|
|
25
|
+
children: [
|
|
26
|
+
{ type: 'paragraph', children: [{ text: '引用' }] },
|
|
27
|
+
{ type: 'paragraph', children: [{ text: '节点' }] },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'list',
|
|
32
|
+
children: [
|
|
33
|
+
{ type: 'list-item', children: [{ text: '无序' }] },
|
|
34
|
+
{ type: 'list-item', children: [{ text: '列表' }] },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<smart-docx-editor
|
|
3
|
+
:initialValue.prop="所有支持的节点.initialValue"
|
|
4
|
+
/>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import '@smartos-lib/core/dist/componentsProvider';
|
|
9
|
+
import '@@/dist/smart-docx-editor/index';
|
|
10
|
+
import { 所有支持的节点 } from './data';
|
|
11
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!-- Markdown 预留层 -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<MarkdownShortcuts v-bind="props" />
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import type { MarkdownProps } from './MarkdownShortcuts/components/types';
|
|
9
|
+
import MarkdownShortcuts from './MarkdownShortcuts/index.vue';
|
|
10
|
+
|
|
11
|
+
const props = defineProps<Pick<MarkdownProps, 'initialValue'>>();
|
|
12
|
+
</script>
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
<!-- 代码 / 文件预览 -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<div size-full flex="~ justify-center items-center" pos="absolute top-0 left-0" c-neutral bg-dark>
|
|
5
|
+
<!-- 加载中 -->
|
|
6
|
+
<div v-if="isFileReading || isEditorLoading" flex="~ col gap-2 items-center">
|
|
7
|
+
<i-svg-spinners-blocks-shuffle-3 />
|
|
8
|
+
<div v-if="isFileReading" text-sm>文件读取中, 当前进度 {{ fileReadPercent }}%</div>
|
|
9
|
+
</div>
|
|
10
|
+
<!-- 不支持的文件 -->
|
|
11
|
+
<div v-else-if="isUnsupportedLanguage" flex="~ col justify-center items-center gap-3" c-gray>
|
|
12
|
+
<i-codicon-warning class="text-(5xl yellow)" />
|
|
13
|
+
此文件类型暂不支持预览
|
|
14
|
+
<el-button class="rounded-sm" color="#3177d3" @click="initEditor()">仍然打开</el-button>
|
|
15
|
+
</div>
|
|
16
|
+
<!-- 编辑器 -->
|
|
17
|
+
<div v-else ref="editorRef" size-full />
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts" setup>
|
|
22
|
+
import type * as Monaco from 'monaco-editor';
|
|
23
|
+
import loader from '@monaco-editor/loader';
|
|
24
|
+
import { getFastestCDN } from '@mixte/snippets/getFastestCDN';
|
|
25
|
+
import { shadowRoot } from '../shared/const';
|
|
26
|
+
import { devDependencies } from '../../../../../../package.json';
|
|
27
|
+
|
|
28
|
+
const props = defineProps<{ file: Blob; fileExt: string }>();
|
|
29
|
+
|
|
30
|
+
const editorRef = ref();
|
|
31
|
+
const { width, height } = useElementSize(editorRef);
|
|
32
|
+
|
|
33
|
+
const isFileReading = ref(false);
|
|
34
|
+
const isEditorLoading = ref(false);
|
|
35
|
+
const isUnsupportedLanguage = ref(false);
|
|
36
|
+
|
|
37
|
+
const monaco = shallowRef<typeof Monaco>();
|
|
38
|
+
const editor = shallowRef<Monaco.editor.IStandaloneCodeEditor>();
|
|
39
|
+
const languages = shallowRef<Monaco.languages.ILanguageExtensionPoint[]>();
|
|
40
|
+
const language = ref<string>();
|
|
41
|
+
const value = ref<string>();
|
|
42
|
+
const fileReadPercent = ref(0);
|
|
43
|
+
|
|
44
|
+
const fastestCDN = useRequestReactive(
|
|
45
|
+
() => getFastestCDN('monaco-editor', {
|
|
46
|
+
version: devDependencies['monaco-editor'].replace(/^\^/g, ''),
|
|
47
|
+
file: `/min/vs/basic-languages/css/css.js`,
|
|
48
|
+
}),
|
|
49
|
+
{ immediate: true },
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 创建 monaco 编辑器
|
|
54
|
+
*/
|
|
55
|
+
async function createEditor() {
|
|
56
|
+
editor.value?.dispose();
|
|
57
|
+
isEditorLoading.value = true;
|
|
58
|
+
isUnsupportedLanguage.value = false;
|
|
59
|
+
|
|
60
|
+
await until(() => fastestCDN.isSuccess).toBeTruthy();
|
|
61
|
+
|
|
62
|
+
loader.config({
|
|
63
|
+
"vs/nls": {
|
|
64
|
+
availableLanguages: {
|
|
65
|
+
'*': 'zh-cn',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
"paths": {
|
|
69
|
+
vs: `${fastestCDN.response}/min/vs`,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
monaco.value = await loader.init();
|
|
75
|
+
languages.value ??= monaco.value.languages.getLanguages();
|
|
76
|
+
language.value = languages.value.find(lang => lang.extensions?.includes(`.${props.fileExt}`))?.id;
|
|
77
|
+
isEditorLoading.value = false;
|
|
78
|
+
|
|
79
|
+
if (!(isUnsupportedLanguage.value = !language.value))
|
|
80
|
+
initEditor();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
isEditorLoading.value = false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 初始化 monaco 编辑器
|
|
89
|
+
*/
|
|
90
|
+
async function initEditor() {
|
|
91
|
+
isUnsupportedLanguage.value = false;
|
|
92
|
+
await nextTick();
|
|
93
|
+
|
|
94
|
+
editor.value = monaco.value!.editor.create(editorRef.value!, {
|
|
95
|
+
// 值
|
|
96
|
+
value: value.value,
|
|
97
|
+
// 编辑器语言
|
|
98
|
+
language: language.value || 'plaintext',
|
|
99
|
+
// 一个制表符等于的空格数
|
|
100
|
+
tabSize: 2,
|
|
101
|
+
// 在通过鼠标添加多个光标时使用的修改键
|
|
102
|
+
multiCursorModifier: 'ctrlCmd',
|
|
103
|
+
// 代码缩略地图
|
|
104
|
+
minimap: {
|
|
105
|
+
showSlider: 'always',
|
|
106
|
+
},
|
|
107
|
+
// 代码编辑器边距
|
|
108
|
+
padding: {
|
|
109
|
+
top: 10,
|
|
110
|
+
},
|
|
111
|
+
// 自动换行
|
|
112
|
+
wordWrap: 'on',
|
|
113
|
+
// 主题
|
|
114
|
+
theme: 'vs-dark',
|
|
115
|
+
// 只读
|
|
116
|
+
readOnly: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 读取文件内容
|
|
121
|
+
wheneverEffectScopeImmediate(() => props.file, (file, _, onCleanup) => {
|
|
122
|
+
isFileReading.value = true;
|
|
123
|
+
|
|
124
|
+
const reader = new FileReader();
|
|
125
|
+
|
|
126
|
+
reader.onprogress = (event) => {
|
|
127
|
+
fileReadPercent.value = Math.round((event.loaded / event.total) * 100);
|
|
128
|
+
};
|
|
129
|
+
reader.onload = async (event) => {
|
|
130
|
+
isFileReading.value = false;
|
|
131
|
+
value.value = event.target?.result as string;
|
|
132
|
+
createEditor();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
reader.readAsText(file);
|
|
136
|
+
|
|
137
|
+
onCleanup(() => {
|
|
138
|
+
reader.abort();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// 挂载 monaco 编辑器样式至 web components 组件中
|
|
143
|
+
wheneverEffectScopeImmediate(shadowRoot, (shadowRoot) => {
|
|
144
|
+
const selectors = `[data-name^="vs/editor"]`;
|
|
145
|
+
|
|
146
|
+
function insertStyle() {
|
|
147
|
+
shadowRoot!.querySelectorAll(selectors).forEach((link) => {
|
|
148
|
+
shadowRoot!.removeChild(link);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
Array.from(document.querySelectorAll(selectors)).forEach((link) => {
|
|
152
|
+
shadowRoot.appendChild(link.cloneNode(true));
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
useMutationObserver(document.head, insertStyle, {
|
|
157
|
+
childList: true,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
insertStyle();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// 动态调整编辑器大小
|
|
164
|
+
watchDeep(() => ({ width: width.value, height: height.value }), (size) => {
|
|
165
|
+
editor.value?.layout(size);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
onUnmounted(() => {
|
|
169
|
+
editor.value?.dispose();
|
|
170
|
+
});
|
|
171
|
+
</script>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!-- 图片预览 -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<div size-full>
|
|
5
|
+
<div ref="rootRef" size-full>
|
|
6
|
+
<img v-if="url" :src="url" hidden>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import Viewer from 'viewerjs';
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{ file: Blob }>();
|
|
15
|
+
|
|
16
|
+
const rootRef = ref();
|
|
17
|
+
|
|
18
|
+
const url = useObjectUrl(() => props.file);
|
|
19
|
+
|
|
20
|
+
wheneverEffectScopeImmediate(() => rootRef.value && url.value, (_, __, onCleanup) => {
|
|
21
|
+
const viewer = new Viewer(rootRef.value, {
|
|
22
|
+
inline: true,
|
|
23
|
+
navbar: false,
|
|
24
|
+
title: false,
|
|
25
|
+
transition: false,
|
|
26
|
+
toolbar: {
|
|
27
|
+
reset: true,
|
|
28
|
+
rotateLeft: true,
|
|
29
|
+
rotateRight: true,
|
|
30
|
+
zoomIn: true,
|
|
31
|
+
zoomOut: true,
|
|
32
|
+
flipHorizontal: true,
|
|
33
|
+
flipVertical: true,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
onCleanup(() => {
|
|
38
|
+
viewer.destroy();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<style lang="scss">
|
|
44
|
+
@import "viewerjs/dist/viewer.css";
|
|
45
|
+
|
|
46
|
+
.viewer-button.viewer-fullscreen {
|
|
47
|
+
display: none;
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- 视频预览 -->
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<video
|
|
5
|
+
ref="videoRef"
|
|
6
|
+
class="size-full absolute top-0 left-0"
|
|
7
|
+
controls
|
|
8
|
+
/>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
const props = defineProps<{ file: Blob }>();
|
|
13
|
+
|
|
14
|
+
const videoRef = ref();
|
|
15
|
+
|
|
16
|
+
const url = useObjectUrl(() => props.file);
|
|
17
|
+
|
|
18
|
+
wheneverEffectScopeImmediate(url, () => {
|
|
19
|
+
const { playing } = useMediaControls(videoRef, {
|
|
20
|
+
src: () => url.value!,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
nextTick(() => {
|
|
24
|
+
playing.value = true;
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div mb2>
|
|
3
|
+
<el-button @click="open()">点击选择文件进行预览</el-button>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div flex="~ justify-center items-center gap2" text="xs teal-5">
|
|
7
|
+
<i-ic-twotone-keyboard-arrow-down class="size-6" />
|
|
8
|
+
文件预览组件
|
|
9
|
+
<i-ic-twotone-keyboard-arrow-down class="size-6" />
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div b="1 solid neutral-2 dark:neutral-6" aspect-ratio-video>
|
|
13
|
+
<smart-file-preview ref="smartFilePreviewRef" v-bind="attrs" />
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script lang="ts" setup>
|
|
18
|
+
import type { SmartFilePreviewElement } from '@@/dist/smart-file-preview/index';
|
|
19
|
+
import '@smartos-lib/core/dist/componentsProvider';
|
|
20
|
+
import '@@/dist/smart-file-preview/index';
|
|
21
|
+
|
|
22
|
+
const attrs = useAttrs();
|
|
23
|
+
|
|
24
|
+
const smartFilePreviewRef = ref<SmartFilePreviewElement>();
|
|
25
|
+
|
|
26
|
+
const { files, open } = useFileDialog({
|
|
27
|
+
multiple: false,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
watch(() => files.value?.[0], (file) => {
|
|
31
|
+
if (file)
|
|
32
|
+
smartFilePreviewRef.value!.previewFile(file.name, file);
|
|
33
|
+
});
|
|
34
|
+
</script>
|