Compare commits

..

6 Commits

Author SHA1 Message Date
dependabot[bot]
75e199d169
Merge c2bea72991 into e8b2c18c6d 2024-09-18 01:44:54 +00:00
Libin YANG
e8b2c18c6d
chore: add type check and upgrade packages (#418)
All checks were successful
Build and Deploy / build-and-deploy (push) Has been skipped
2024-09-18 09:44:51 +08:00
Libin YANG
8e93889ae4
fix: type check (#416)
All checks were successful
Build and Deploy / build-and-deploy (push) Has been skipped
2024-09-17 16:13:24 +08:00
YangFong
d8a3d06330
feat: add more style option (#414) 2024-09-17 15:58:39 +08:00
YangFong
ecb51c10f1
refactor: split store (#413) 2024-09-17 12:21:48 +08:00
YangFong
21d5259f35
chore: convert js to ts (#410)
All checks were successful
Build and Deploy / build-and-deploy (push) Has been skipped
2024-09-17 08:26:52 +08:00
77 changed files with 2146 additions and 1609 deletions

View File

@ -93,7 +93,7 @@
} }
</script> </script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script> <script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.ts"></script>
</body> </body>
<script src="https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/wechatsync/article-syncjs@latest/dist/main.js"></script> <script src="https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/wechatsync/article-syncjs@latest/dist/main.js"></script>
</html> </html>

2810
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,8 @@
"dev": "vite --host", "dev": "vite --host",
"build": "run-p type-check \"build:only {@}\" --", "build": "run-p type-check \"build:only {@}\" --",
"build:only": "vite build", "build:only": "vite build",
"build:h5-netlify": "cross-env SERVER_ENV=NETLIFY vite build", "build:h5-netlify": "run-p type-check \"build:h5-netlify:only {@}\" --",
"build:h5-netlify:only": "cross-env SERVER_ENV=NETLIFY vite build",
"build:cli": "npm run build && npm run shx rm -rf md-cli/dist && npm run shx rm -rf dist/**/*.map && npm run shx cp -r dist md-cli/ && cd md-cli && npm run pack", "build:cli": "npm run build && npm run shx rm -rf md-cli/dist && npm run shx rm -rf dist/**/*.map && npm run shx cp -r dist md-cli/ && cd md-cli && npm run pack",
"build:analyze": "cross-env ANALYZE=true vite build", "build:analyze": "cross-env ANALYZE=true vite build",
"preview": "npm run build && vite preview", "preview": "npm run build && vite preview",
@ -19,8 +20,8 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^11.0.1", "@vueuse/core": "^11.1.0",
"axios": "^1.7.4", "axios": "^1.7.7",
"buffer-from": "^1.1.2", "buffer-from": "^1.1.2",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -29,54 +30,54 @@
"cos-js-sdk-v5": "^1.8.4", "cos-js-sdk-v5": "^1.8.4",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"csstype": "^3.1.3", "csstype": "^3.1.3",
"element-plus": "^2.8.0", "element-plus": "^2.8.3",
"es-toolkit": "^1.16.0", "es-toolkit": "^1.19.0",
"form-data": "4.0.0", "form-data": "4.0.0",
"highlight.js": "^11.10.0", "highlight.js": "^11.10.0",
"juice": "^8.0.0", "juice": "^11.0.0",
"lucide-vue-next": "^0.428.0", "lucide-vue-next": "^0.441.0",
"marked": "^14.1.1", "marked": "^14.1.2",
"mermaid": "^11.1.0", "mermaid": "^11.2.1",
"minio": "7.1.3", "minio": "7.1.3",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"pinia": "^2.2.2", "pinia": "^2.2.2",
"qiniu-js": "^3.4.2", "qiniu-js": "^3.4.2",
"radix-vue": "^1.9.4", "radix-vue": "^1.9.5",
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"tiny-oss": "^0.5.1", "tiny-oss": "^0.5.1",
"uuid": "^10.0.0", "uuid": "^10.0.0",
"vue": "^3.4.38" "vue": "^3.5.6"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "2.26.0", "@antfu/eslint-config": "3.6.2",
"@types/buffer-from": "^1.1.3", "@types/buffer-from": "^1.1.3",
"@types/codemirror": "^5.60.15", "@types/codemirror": "^5.60.15",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@types/node": "^22.4.1", "@types/node": "^22.5.5",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
"@unocss/eslint-plugin": "^0.62.2", "@unocss/eslint-plugin": "^0.62.4",
"@vitejs/plugin-vue": "^5.1.2", "@vitejs/plugin-vue": "^5.1.3",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^9.9.0", "eslint": "^9.10.0",
"eslint-plugin-format": "^0.1.2", "eslint-plugin-format": "^0.1.2",
"less": "^4.2.0", "less": "^4.2.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"postcss": "^8.4.41", "postcss": "^8.4.47",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"shx": "^0.3.4", "shx": "^0.3.4",
"simple-git-hooks": "^2.11.1", "simple-git-hooks": "^2.11.1",
"tailwindcss": "^3.4.10", "tailwindcss": "^3.4.12",
"typescript": "^5.5.4", "typescript": "^5.6.2",
"unocss": "^0.62.2", "unocss": "^0.62.4",
"unplugin-auto-import": "^0.18.2", "unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.2", "vite": "^5.4.6",
"vite-plugin-node-polyfills": "^0.22.0", "vite-plugin-node-polyfills": "^0.22.0",
"vite-plugin-vue-devtools": "^7.3.9", "vite-plugin-vue-devtools": "^7.4.5",
"vue-tsc": "^2.0.29" "vue-tsc": "^2.1.6"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"pre-commit": "npx lint-staged" "pre-commit": "npx lint-staged"

View File

@ -1,4 +1,4 @@
<script setup> <script setup lang="ts">
import CodemirrorEditor from '@/views/CodemirrorEditor.vue' import CodemirrorEditor from '@/views/CodemirrorEditor.vue'
</script> </script>

View File

@ -94,12 +94,3 @@ section {
display: table; display: table;
width: 100% !important; width: 100% !important;
} }
/* ele ui */
.el-form-item {
margin-bottom: 0 !important;
}
.el-tooltip {
cursor: pointer;
}

View File

@ -1,9 +1,10 @@
<script setup> <script setup lang="ts">
import { useDisplayStore, useStore } from '@/stores'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { useStore } from '@/stores'
const store = useStore() const store = useStore()
const displayStore = useDisplayStore()
function editTabName() { function editTabName() {
ElMessageBox.prompt(`请输入新的方案名称`, `编辑方案名称`, { ElMessageBox.prompt(`请输入新的方案名称`, `编辑方案名称`, {
@ -23,7 +24,7 @@ function editTabName() {
}) })
} }
function handleTabsEdit(targetName, action) { function handleTabsEdit(targetName: string, action: string) {
if (action === `add`) { if (action === `add`) {
ElMessageBox.prompt(`请输入方案名称`, `新建自定义 CSS`, { ElMessageBox.prompt(`请输入方案名称`, `新建自定义 CSS`, {
confirmButtonText: `确认`, confirmButtonText: `确认`,
@ -67,7 +68,7 @@ function handleTabsEdit(targetName, action) {
<template> <template>
<transition enter-active-class="bounceInRight"> <transition enter-active-class="bounceInRight">
<el-col v-show="store.isShowCssEditor" :span="8" class="cssEditor-wrapper order-1 h-full flex flex-col border-l-1"> <el-col v-show="displayStore.isShowCssEditor" :span="8" class="cssEditor-wrapper order-1 h-full flex flex-col border-l-1">
<el-tabs <el-tabs
v-model="store.cssContentConfig.active" v-model="store.cssContentConfig.active"
type="border-card" type="border-card"
@ -86,7 +87,7 @@ function handleTabsEdit(targetName, action) {
<el-icon <el-icon
v-if="store.cssContentConfig.active === item.name" v-if="store.cssContentConfig.active === item.name"
class="ml-1" class="ml-1"
@click="editTabName(item.name)" @click="editTabName()"
> >
<ElIconEditPen /> <ElIconEditPen />
</el-icon> </el-icon>
@ -142,7 +143,7 @@ function handleTabsEdit(targetName, action) {
} }
:deep(.el-tabs__content) { :deep(.el-tabs__content) {
padding: 0; padding: 0 !important;
} }
// tab // tab

View File

@ -1,4 +1,4 @@
<script setup> <script setup lang="ts">
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -16,7 +16,7 @@ const props = defineProps({
const emit = defineEmits([`close`]) const emit = defineEmits([`close`])
function onUpdate(val) { function onUpdate(val: boolean) {
if (!val) { if (!val) {
emit(`close`) emit(`close`)
} }
@ -28,7 +28,7 @@ const links = [
{ label: `GitCode 仓库`, url: `https://gitcode.com/doocs/md` }, { label: `GitCode 仓库`, url: `https://gitcode.com/doocs/md` },
] ]
function onRedirect(url) { function onRedirect(url: string) {
window.open(url, `_blank`) window.open(url, `_blank`)
} }
</script> </script>

View File

@ -1,25 +1,28 @@
<script setup> <script setup lang="ts">
import { useStore } from '@/stores' import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarTrigger,
} from '@/components/ui/menubar'
import { useDisplayStore } from '@/stores'
import { TableIcon, UploadCloudIcon } from 'lucide-vue-next'
const store = useStore() const { toggleShowInsertFormDialog, toggleShowUploadImgDialog } = useDisplayStore()
const { toggleShowInsertFormDialog, toggleShowUploadImgDialog } = store
</script> </script>
<template> <template>
<MenubarMenu> <MenubarMenu>
<MenubarTrigger> 编辑 </MenubarTrigger> <MenubarTrigger>
编辑
</MenubarTrigger>
<MenubarContent align="start"> <MenubarContent align="start">
<MenubarItem @click="toggleShowUploadImgDialog()"> <MenubarItem @click="toggleShowUploadImgDialog()">
<el-icon class="mr-2 h-4 w-4"> <UploadCloudIcon class="mr-2 h-4 w-4" />
<ElIconUpload />
</el-icon>
上传图片 上传图片
</MenubarItem> </MenubarItem>
<MenubarItem @click="toggleShowInsertFormDialog()"> <MenubarItem @click="toggleShowInsertFormDialog()">
<el-icon class="mr-2 h-4 w-4"> <TableIcon class="mr-2 h-4 w-4" />
<ElIconGrid />
</el-icon>
插入表格 插入表格
</MenubarItem> </MenubarItem>
</MenubarContent> </MenubarContent>

View File

@ -1,8 +1,8 @@
<script setup> <script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useStore } from '@/stores' import { useStore } from '@/stores'
import { storeToRefs } from 'pinia'
const store = useStore() const store = useStore()
const { const {

View File

@ -1,4 +1,4 @@
<script setup> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import AboutDialog from './AboutDialog.vue' import AboutDialog from './AboutDialog.vue'

View File

@ -1,6 +1,4 @@
<script setup> <script setup lang="ts">
import { ref } from 'vue'
import { storeToRefs } from 'pinia'
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -8,30 +6,34 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import { useStore } from '@/stores' import { useStore } from '@/stores'
import { storeToRefs } from 'pinia'
import { ref } from 'vue'
const store = useStore() const store = useStore()
const { output } = storeToRefs(store) const { output } = storeToRefs(store)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const form = ref({ const form = ref<any>({
title: ``, title: ``,
desc: ``, desc: ``,
thumb: ``, thumb: ``,
content: ``, content: ``,
auto: {},
}) })
function prePost() { function prePost() {
let auto = {} let auto = {}
try { try {
auto = { auto = {
thumb: document.querySelector(`#output img`)?.src, thumb: document.querySelector<HTMLImageElement>(`#output img`)?.src,
title: [1, 2, 3, 4, 5, 6] title: [1, 2, 3, 4, 5, 6]
.map(h => document.querySelector(`#output h${h}`)) .map(h => document.querySelector(`#output h${h}`)!)
.filter(h => h)[0].textContent, .filter(h => h)[0]
desc: document.querySelector(`#output p`).textContent, .textContent,
desc: document.querySelector(`#output p`)!.textContent,
content: output.value, content: output.value,
} }
} }
@ -45,10 +47,16 @@ function prePost() {
dialogVisible.value = true dialogVisible.value = true
} }
declare global {
interface Window {
syncPost: (data: { thumb: string, title: string, desc: string, content: string }) => void
}
}
function post() { function post() {
dialogVisible.value = false dialogVisible.value = false;
// 使 window.$syncer // 使 window.$syncer
window.syncPost({ (window.syncPost)({
thumb: form.value.thumb || form.value.auto.thumb, thumb: form.value.thumb || form.value.auto.thumb,
title: form.value.title || form.value.auto.title, title: form.value.title || form.value.auto.title,
desc: form.value.desc || form.value.auto.desc, desc: form.value.desc || form.value.auto.desc,
@ -56,7 +64,7 @@ function post() {
}) })
} }
function onUpdate(val) { function onUpdate(val: boolean) {
if (!val) { if (!val) {
dialogVisible.value = false dialogVisible.value = false
} }

View File

@ -1,15 +1,9 @@
<script setup> <script setup lang="ts">
import { nextTick, ref } from 'vue'
import { storeToRefs } from 'pinia'
import StyleOptionMenu from './StyleOptionMenu.vue'
import { import {
HoverCard, HoverCard,
HoverCardContent, HoverCardContent,
HoverCardTrigger, HoverCardTrigger,
} from '@/components/ui/hover-card' } from '@/components/ui/hover-card'
import { import {
codeBlockThemeOptions, codeBlockThemeOptions,
colorOptions, colorOptions,
@ -18,9 +12,14 @@ import {
legendOptions, legendOptions,
themeOptions, themeOptions,
} from '@/config' } from '@/config'
import { useStore } from '@/stores'
import { useDisplayStore, useStore } from '@/stores'
import { storeToRefs } from 'pinia'
import { ref } from 'vue'
import StyleOptionMenu from './StyleOptionMenu.vue'
const store = useStore() const store = useStore()
const { toggleShowCssEditor } = useDisplayStore()
const { const {
theme, theme,
@ -42,25 +41,19 @@ const {
codeBlockThemeChanged, codeBlockThemeChanged,
legendChanged, legendChanged,
macCodeBlockChanged, macCodeBlockChanged,
toggleShowCssEditor,
} = store } = store
const colorPicker = ref(null) const colorPicker = ref<HTMLElement & { show: () => void } | null>(null)
function showPicker() { function showPicker() {
colorPicker.value.show() colorPicker.value?.show()
} }
// CSS // CSS
function customStyle() { function customStyle() {
toggleShowCssEditor() toggleShowCssEditor()
nextTick(() => {
if (!cssEditor.value) {
cssEditor.value.refresh()
}
})
setTimeout(() => { setTimeout(() => {
cssEditor.value.refresh() cssEditor.value!.refresh()
}, 50) }, 50)
} }
</script> </script>
@ -114,7 +107,7 @@ function customStyle() {
自定义主题色 自定义主题色
</HoverCardTrigger> </HoverCardTrigger>
<HoverCardContent side="right" class="w-min"> <HoverCardContent side="right" class="w-min">
<el-color-picker <ElColorPicker
ref="colorPicker" ref="colorPicker"
v-model="primaryColor" v-model="primaryColor"
:teleported="false" :teleported="false"

View File

@ -1,4 +1,5 @@
<script setup> <script setup lang="ts">
import type { IConfigOption } from '@/types'
import { import {
MenubarItem, MenubarItem,
MenubarSub, MenubarSub,
@ -6,26 +7,14 @@ import {
MenubarSubTrigger, MenubarSubTrigger,
} from '@/components/ui/menubar' } from '@/components/ui/menubar'
const props = defineProps({ const props = defineProps<{
title: { title: string
type: String, options: IConfigOption[]
required: true, current: string
}, change: <T>(val: T) => void
options: { }>()
type: Array,
required: true,
},
current: {
type: String,
required: true,
},
change: {
type: Function,
required: true,
},
})
function setStyle(title, value) { function setStyle(title: string, value: string) {
switch (title) { switch (title) {
case `字体`: case `字体`:
return { fontFamily: value } return { fontFamily: value }

View File

@ -1,14 +1,23 @@
<script setup> <script setup lang="ts">
import { nextTick } from 'vue' import { Button } from '@/components/ui/button'
import { storeToRefs } from 'pinia' import {
import { ElNotification } from 'element-plus' Menubar,
import { Moon, Paintbrush, Sun } from 'lucide-vue-next' MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarTrigger,
} from '@/components/ui/menubar'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import PostInfo from './PostInfo.vue'
import FileDropdown from './FileDropdown.vue'
import HelpDropdown from './HelpDropdown.vue'
import StyleDropdown from './StyleDropdown.vue'
import EditDropdown from './EditDropdown.vue'
import { import {
altSign, altSign,
codeBlockThemeOptions, codeBlockThemeOptions,
@ -21,29 +30,20 @@ import {
shiftSign, shiftSign,
themeOptions, themeOptions,
} from '@/config' } from '@/config'
import { useDisplayStore, useStore } from '@/stores'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import {
Menubar,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarTrigger,
} from '@/components/ui/menubar'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Button } from '@/components/ui/button'
import { mergeCss, solveWeChatImage } from '@/utils' import { mergeCss, solveWeChatImage } from '@/utils'
import { useStore } from '@/stores' import { ElNotification } from 'element-plus'
import { Moon, Paintbrush, Sun } from 'lucide-vue-next'
import { storeToRefs } from 'pinia'
import { nextTick } from 'vue'
import EditDropdown from './EditDropdown.vue'
import FileDropdown from './FileDropdown.vue'
import HelpDropdown from './HelpDropdown.vue'
import PostInfo from './PostInfo.vue'
import StyleDropdown from './StyleDropdown.vue'
const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`]) const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`])
@ -78,9 +78,10 @@ const formatItems = [
kbd: [altSign, shiftSign, `F`], kbd: [altSign, shiftSign, `F`],
emitArgs: [`formatContent`], emitArgs: [`formatContent`],
}, },
] ] as const
const store = useStore() const store = useStore()
const displayStore = useDisplayStore()
const { isDark, isCiteStatus, output, primaryColor } = storeToRefs(store) const { isDark, isCiteStatus, output, primaryColor } = storeToRefs(store)
@ -90,7 +91,7 @@ const { toggleDark, editorRefresh, citeStatusChanged } = store
function copy() { function copy() {
emit(`startCopy`) emit(`startCopy`)
setTimeout(() => { setTimeout(() => {
function modifyHtmlStructure(htmlString) { function modifyHtmlStructure(htmlString: string) {
// div HTML // div HTML
const tempDiv = document.createElement(`div`) const tempDiv = document.createElement(`div`)
tempDiv.innerHTML = htmlString tempDiv.innerHTML = htmlString
@ -98,7 +99,7 @@ function copy() {
const originalItems = tempDiv.querySelectorAll(`li > ul, li > ol`) const originalItems = tempDiv.querySelectorAll(`li > ul, li > ol`)
originalItems.forEach((originalItem) => { originalItems.forEach((originalItem) => {
originalItem.parentElement.insertAdjacentElement(`afterend`, originalItem) originalItem.parentElement!.insertAdjacentElement(`afterend`, originalItem)
}) })
// HTML // HTML
@ -114,7 +115,7 @@ function copy() {
nextTick(() => { nextTick(() => {
solveWeChatImage() solveWeChatImage()
const clipboardDiv = document.getElementById(`output`) const clipboardDiv = document.getElementById(`output`)!
clipboardDiv.innerHTML = mergeCss(clipboardDiv.innerHTML) clipboardDiv.innerHTML = mergeCss(clipboardDiv.innerHTML)
clipboardDiv.innerHTML = modifyHtmlStructure(clipboardDiv.innerHTML) clipboardDiv.innerHTML = modifyHtmlStructure(clipboardDiv.innerHTML)
clipboardDiv.innerHTML = clipboardDiv.innerHTML clipboardDiv.innerHTML = clipboardDiv.innerHTML
@ -125,14 +126,14 @@ function copy() {
.replaceAll(`var(--md-primary-color)`, primaryColor.value) .replaceAll(`var(--md-primary-color)`, primaryColor.value)
.replaceAll(/--md-primary-color:.+?;/g, ``) .replaceAll(/--md-primary-color:.+?;/g, ``)
clipboardDiv.focus() clipboardDiv.focus()
window.getSelection().removeAllRanges() window.getSelection()!.removeAllRanges()
const range = document.createRange() const range = document.createRange()
range.setStartBefore(clipboardDiv.firstChild) range.setStartBefore(clipboardDiv.firstChild!)
range.setEndAfter(clipboardDiv.lastChild) range.setEndAfter(clipboardDiv.lastChild!)
window.getSelection().addRange(range) window.getSelection()!.addRange(range)
document.execCommand(`copy`) document.execCommand(`copy`)
window.getSelection().removeAllRanges() window.getSelection()!.removeAllRanges()
clipboardDiv.innerHTML = output.value clipboardDiv.innerHTML = output.value
if (isBeforeDark) { if (isBeforeDark) {
@ -153,6 +154,13 @@ function copy() {
}) })
}, 350) }, 350)
} }
function customStyle() {
displayStore.toggleShowCssEditor()
setTimeout(() => {
store.cssEditor!.refresh()
}, 50)
}
</script> </script>
<template> <template>
@ -165,8 +173,8 @@ function copy() {
<MenubarContent class="w-60" align="start"> <MenubarContent class="w-60" align="start">
<MenubarItem <MenubarItem
v-for="{ label, kbd, emitArgs } in formatItems" v-for="{ label, kbd, emitArgs } in formatItems"
:key="kbd" :key="label"
@click="$emit(...emitArgs)" @click="emitArgs[0] === 'addFormat' ? $emit(emitArgs[0], emitArgs[1]) : $emit(emitArgs[0])"
> >
<el-icon class="mr-2 h-4 w-4" /> <el-icon class="mr-2 h-4 w-4" />
{{ label }} {{ label }}
@ -371,6 +379,31 @@ function copy() {
</Button> </Button>
</div> </div>
</div> </div>
<div class="space-y-2">
<h2>自定义 CSS 面板</h2>
<div class="grid grid-cols-5 justify-items-center gap-2">
<Button
class="w-full"
variant="outline"
:class="{
'border-black dark:border-white': displayStore.isShowCssEditor,
}"
@click="!displayStore.isShowCssEditor && customStyle()"
>
开启
</Button>
<Button
class="w-full"
variant="outline"
:class="{
'border-black dark:border-white': !displayStore.isShowCssEditor,
}"
@click="displayStore.isShowCssEditor && customStyle()"
>
关闭
</Button>
</div>
</div>
<div class="space-y-2"> <div class="space-y-2">
<h2>编辑区位置</h2> <h2>编辑区位置</h2>
<div class="grid grid-cols-5 justify-items-center gap-2"> <div class="grid grid-cols-5 justify-items-center gap-2">
@ -421,6 +454,17 @@ function copy() {
</Button> </Button>
</div> </div>
</div> </div>
<div class="space-y-2">
<h2>样式配置</h2>
<div>
<Button
class="w-full"
@click="store.resetStyleConfirm()"
>
重置
</Button>
</div>
</div>
</div> </div>
</PopoverContent> </PopoverContent>
</Popover> </Popover>

View File

@ -1,5 +1,4 @@
<script setup> <script setup lang="ts">
import { ref, toRaw } from 'vue'
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -7,17 +6,19 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import { useDisplayStore, useStore } from '@/stores'
import { useStore } from '@/stores'
import { createTable } from '@/utils' import { createTable } from '@/utils'
import { ref, toRaw } from 'vue'
const store = useStore() const store = useStore()
const displayStore = useDisplayStore()
const { toggleShowInsertFormDialog } = store const { toggleShowInsertFormDialog } = displayStore
const rowNum = ref(3) const rowNum = ref(3)
const colNum = ref(3) const colNum = ref(3)
const tableData = ref({}) const tableData = ref<Record<string, string>>({})
function resetVal() { function resetVal() {
rowNum.value = 3 rowNum.value = 3
@ -32,12 +33,12 @@ function insertTable() {
cols: colNum.value, cols: colNum.value,
data: tableData.value, data: tableData.value,
}) })
toRaw(store.editor).replaceSelection(`\n${table}\n`, `end`) toRaw(store.editor!).replaceSelection(`\n${table}\n`, `end`)
resetVal() resetVal()
toggleShowInsertFormDialog() toggleShowInsertFormDialog()
} }
function onUpdate(val) { function onUpdate(val: boolean) {
if (!val) { if (!val) {
toggleShowInsertFormDialog(false) toggleShowInsertFormDialog(false)
} }
@ -45,7 +46,7 @@ function onUpdate(val) {
</script> </script>
<template> <template>
<Dialog :open="store.isShowInsertFormDialog" @update:open="onUpdate"> <Dialog :open="displayStore.isShowInsertFormDialog" @update:open="onUpdate">
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>插入表格</DialogTitle> <DialogTitle>插入表格</DialogTitle>

View File

@ -1,17 +1,17 @@
<script setup> <script setup lang="ts">
import { nextTick, onBeforeMount, ref, watch } from 'vue'
import CodeMirror from 'codemirror/lib/codemirror'
import { ElMessage } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { useDisplayStore } from '@/stores'
import { checkImage, removeLeft } from '@/utils' import { checkImage, removeLeft } from '@/utils'
import { useStore } from '@/stores'
import { UploadFilled } from '@element-plus/icons-vue'
import CodeMirror from 'codemirror'
import { ElMessage } from 'element-plus'
import { nextTick, onBeforeMount, ref, watch } from 'vue'
const emit = defineEmits([`uploadImage`]) const emit = defineEmits([`uploadImage`])
const store = useStore() const displayStore = useDisplayStore()
const formGitHub = ref({ const formGitHub = ref({
repo: ``, repo: ``,
@ -50,6 +50,7 @@ const formQiniu = ref({
bucket: ``, bucket: ``,
domain: ``, domain: ``,
region: ``, region: ``,
path: ``,
}) })
const minioOSS = ref({ const minioOSS = ref({
@ -61,7 +62,7 @@ const minioOSS = ref({
secretKey: ``, secretKey: ``,
}) })
const formCustom = ref({ const formCustom = ref<{ code: string, editor: CodeMirror.EditorFromTextArea | null }>({
code: code:
localStorage.getItem(`formCustomConfig`) localStorage.getItem(`formCustomConfig`)
|| removeLeft(` || removeLeft(`
@ -76,7 +77,7 @@ const formCustom = ref({
errCb(err) errCb(err)
}) })
`).trim(), `).trim(),
editor: undefined, editor: null,
}) })
const options = [ const options = [
@ -116,7 +117,7 @@ const options = [
const imgHost = ref(`default`) const imgHost = ref(`default`)
const formCustomElInput = ref(null) const formCustomElInput = ref<(HTMLInputElement & { $el: HTMLElement }) | null>(null)
const activeName = ref(`upload`) const activeName = ref(`upload`)
watch( watch(
@ -124,10 +125,8 @@ watch(
async (val) => { async (val) => {
if (val === `formCustom`) { if (val === `formCustom`) {
nextTick(() => { nextTick(() => {
const textarea = formCustomElInput.value.$el.querySelector(`textarea`) const textarea = formCustomElInput.value!.$el.querySelector(`textarea`)!
formCustom.value.editor formCustom.value.editor ||= CodeMirror.fromTextArea(textarea, {
= formCustom.value.editor
|| CodeMirror.fromTextArea(textarea, {
mode: `javascript`, mode: `javascript`,
}) })
// formCustom.value.editor.setValue(formCustom.value.code) // formCustom.value.editor.setValue(formCustom.value.code)
@ -141,25 +140,25 @@ watch(
onBeforeMount(() => { onBeforeMount(() => {
if (localStorage.getItem(`githubConfig`)) { if (localStorage.getItem(`githubConfig`)) {
formGitHub.value = JSON.parse(localStorage.getItem(`githubConfig`)) formGitHub.value = JSON.parse(localStorage.getItem(`githubConfig`)!)
} }
// if (localStorage.getItem(`giteeConfig`)) { // if (localStorage.getItem(`giteeConfig`)) {
// formGitee.value = JSON.parse(localStorage.getItem(`giteeConfig`)) // formGitee.value = JSON.parse(localStorage.getItem(`giteeConfig`)!)
// } // }
if (localStorage.getItem(`aliOSSConfig`)) { if (localStorage.getItem(`aliOSSConfig`)) {
formAliOSS.value = JSON.parse(localStorage.getItem(`aliOSSConfig`)) formAliOSS.value = JSON.parse(localStorage.getItem(`aliOSSConfig`)!)
} }
if (localStorage.getItem(`txCOSConfig`)) { if (localStorage.getItem(`txCOSConfig`)) {
formTxCOS.value = JSON.parse(localStorage.getItem(`txCOSConfig`)) formTxCOS.value = JSON.parse(localStorage.getItem(`txCOSConfig`)!)
} }
if (localStorage.getItem(`qiniuConfig`)) { if (localStorage.getItem(`qiniuConfig`)) {
formQiniu.value = JSON.parse(localStorage.getItem(`qiniuConfig`)) formQiniu.value = JSON.parse(localStorage.getItem(`qiniuConfig`)!)
} }
if (localStorage.getItem(`minioConfig`)) { if (localStorage.getItem(`minioConfig`)) {
minioOSS.value = JSON.parse(localStorage.getItem(`minioConfig`)) minioOSS.value = JSON.parse(localStorage.getItem(`minioConfig`)!)
} }
if (localStorage.getItem(`imgHost`)) { if (localStorage.getItem(`imgHost`)) {
imgHost.value = localStorage.getItem(`imgHost`) imgHost.value = localStorage.getItem(`imgHost`)!
} }
}) })
@ -251,12 +250,12 @@ function saveQiniuConfiguration() {
} }
function formCustomSave() { function formCustomSave() {
const str = formCustom.value.editor.getValue() const str = formCustom.value.editor!.getValue()
localStorage.setItem(`formCustomConfig`, str) localStorage.setItem(`formCustomConfig`, str)
ElMessage.success(`保存成功`) ElMessage.success(`保存成功`)
} }
function beforeImageUpload(file) { function beforeImageUpload(file: File) {
// check image // check image
const checkResult = checkImage(file) const checkResult = checkImage(file)
if (!checkResult.ok) { if (!checkResult.ok) {
@ -277,13 +276,13 @@ function beforeImageUpload(file) {
return true return true
} }
function uploadImage(params) { function uploadImage(params: { file: any }) {
emit(`uploadImage`, params.file) emit(`uploadImage`, params.file)
} }
</script> </script>
<template> <template>
<Dialog v-model:open="store.isShowUploadImgDialog"> <Dialog v-model:open="displayStore.isShowUploadImgDialog">
<DialogContent class="max-w-max"> <DialogContent class="max-w-max">
<DialogHeader> <DialogHeader>
<DialogTitle>本地上传</DialogTitle> <DialogTitle>本地上传</DialogTitle>

View File

@ -1,4 +1,4 @@
<script setup> <script setup lang="ts">
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
const loading = ref(true) const loading = ref(true)

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { Primitive, type PrimitiveProps } from 'radix-vue' import { Primitive, type PrimitiveProps } from 'radix-vue'
import { type ButtonVariants, buttonVariants } from '.' import { type ButtonVariants, buttonVariants } from '.'
import { cn } from '@/lib/utils'
interface Props extends PrimitiveProps { interface Props extends PrimitiveProps {
variant?: ButtonVariants[`variant`] variant?: ButtonVariants[`variant`]

View File

@ -1,4 +1,4 @@
import { type VariantProps, cva } from 'class-variance-authority' import { cva, type VariantProps } from 'class-variance-authority'
export { default as Button } from './Button.vue' export { default as Button } from './Button.vue'

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ContextMenuRoot, useForwardPropsEmits } from 'radix-vue'
import type { ContextMenuRootEmits, ContextMenuRootProps } from 'radix-vue' import type { ContextMenuRootEmits, ContextMenuRootProps } from 'radix-vue'
import { ContextMenuRoot, useForwardPropsEmits } from 'radix-vue'
const props = defineProps<ContextMenuRootProps>() const props = defineProps<ContextMenuRootProps>()
const emits = defineEmits<ContextMenuRootEmits>() const emits = defineEmits<ContextMenuRootEmits>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Check } from 'lucide-vue-next'
import { import {
ContextMenuCheckboxItem, ContextMenuCheckboxItem,
type ContextMenuCheckboxItemEmits, type ContextMenuCheckboxItemEmits,
@ -7,8 +8,7 @@ import {
ContextMenuItemIndicator, ContextMenuItemIndicator,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Check } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<ContextMenuCheckboxItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<ContextMenuCheckboxItemProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<ContextMenuCheckboxItemEmits>() const emits = defineEmits<ContextMenuCheckboxItemEmits>()

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
ContextMenuContent, ContextMenuContent,
type ContextMenuContentEmits, type ContextMenuContentEmits,
@ -7,7 +7,7 @@ import {
ContextMenuPortal, ContextMenuPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<ContextMenuContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<ContextMenuContentProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<ContextMenuContentEmits>() const emits = defineEmits<ContextMenuContentEmits>()

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
ContextMenuItem, ContextMenuItem,
type ContextMenuItemEmits, type ContextMenuItemEmits,
type ContextMenuItemProps, type ContextMenuItemProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<ContextMenuItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<ContextMenuItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()
const emits = defineEmits<ContextMenuItemEmits>() const emits = defineEmits<ContextMenuItemEmits>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { ContextMenuLabel, type ContextMenuLabelProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ContextMenuLabel, type ContextMenuLabelProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<ContextMenuLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<ContextMenuLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Circle } from 'lucide-vue-next'
import { import {
ContextMenuItemIndicator, ContextMenuItemIndicator,
ContextMenuRadioItem, ContextMenuRadioItem,
@ -7,8 +8,7 @@ import {
type ContextMenuRadioItemProps, type ContextMenuRadioItemProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Circle } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<ContextMenuRadioItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<ContextMenuRadioItemProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<ContextMenuRadioItemEmits>() const emits = defineEmits<ContextMenuRadioItemEmits>()

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
ContextMenuSeparator, ContextMenuSeparator,
type ContextMenuSeparatorProps, type ContextMenuSeparatorProps,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<ContextMenuSeparatorProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<ContextMenuSeparatorProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
ContextMenuSubContent, ContextMenuSubContent,
type DropdownMenuSubContentEmits, type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps, type DropdownMenuSubContentProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<DropdownMenuSubContentEmits>() const emits = defineEmits<DropdownMenuSubContentEmits>()

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { ChevronRight } from 'lucide-vue-next'
import { import {
ContextMenuSubTrigger, ContextMenuSubTrigger,
type ContextMenuSubTriggerProps, type ContextMenuSubTriggerProps,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'radix-vue'
import { ChevronRight } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<ContextMenuSubTriggerProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<ContextMenuSubTriggerProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,14 +1,14 @@
export { default as ContextMenu } from './ContextMenu.vue' export { default as ContextMenu } from './ContextMenu.vue'
export { default as ContextMenuTrigger } from './ContextMenuTrigger.vue' export { default as ContextMenuCheckboxItem } from './ContextMenuCheckboxItem.vue'
export { default as ContextMenuContent } from './ContextMenuContent.vue' export { default as ContextMenuContent } from './ContextMenuContent.vue'
export { default as ContextMenuGroup } from './ContextMenuGroup.vue' export { default as ContextMenuGroup } from './ContextMenuGroup.vue'
export { default as ContextMenuRadioGroup } from './ContextMenuRadioGroup.vue'
export { default as ContextMenuItem } from './ContextMenuItem.vue' export { default as ContextMenuItem } from './ContextMenuItem.vue'
export { default as ContextMenuCheckboxItem } from './ContextMenuCheckboxItem.vue'
export { default as ContextMenuRadioItem } from './ContextMenuRadioItem.vue'
export { default as ContextMenuShortcut } from './ContextMenuShortcut.vue'
export { default as ContextMenuSeparator } from './ContextMenuSeparator.vue'
export { default as ContextMenuLabel } from './ContextMenuLabel.vue' export { default as ContextMenuLabel } from './ContextMenuLabel.vue'
export { default as ContextMenuRadioGroup } from './ContextMenuRadioGroup.vue'
export { default as ContextMenuRadioItem } from './ContextMenuRadioItem.vue'
export { default as ContextMenuSeparator } from './ContextMenuSeparator.vue'
export { default as ContextMenuShortcut } from './ContextMenuShortcut.vue'
export { default as ContextMenuSub } from './ContextMenuSub.vue' export { default as ContextMenuSub } from './ContextMenuSub.vue'
export { default as ContextMenuSubTrigger } from './ContextMenuSubTrigger.vue'
export { default as ContextMenuSubContent } from './ContextMenuSubContent.vue' export { default as ContextMenuSubContent } from './ContextMenuSubContent.vue'
export { default as ContextMenuSubTrigger } from './ContextMenuSubTrigger.vue'
export { default as ContextMenuTrigger } from './ContextMenuTrigger.vue'

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { X } from 'lucide-vue-next'
import { import {
DialogClose, DialogClose,
DialogContent, DialogContent,
@ -9,8 +10,7 @@ import {
DialogPortal, DialogPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { X } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<DialogContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DialogContentProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<DialogContentEmits>() const emits = defineEmits<DialogContentEmits>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { X } from 'lucide-vue-next'
import { import {
DialogClose, DialogClose,
DialogContent, DialogContent,
@ -9,8 +10,7 @@ import {
DialogPortal, DialogPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { X } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<DialogContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DialogContentProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<DialogContentEmits>() const emits = defineEmits<DialogContentEmits>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DialogTitleProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,9 +1,9 @@
export { default as Dialog } from './Dialog.vue' export { default as Dialog } from './Dialog.vue'
export { default as DialogClose } from './DialogClose.vue' export { default as DialogClose } from './DialogClose.vue'
export { default as DialogTrigger } from './DialogTrigger.vue'
export { default as DialogHeader } from './DialogHeader.vue'
export { default as DialogTitle } from './DialogTitle.vue'
export { default as DialogDescription } from './DialogDescription.vue'
export { default as DialogContent } from './DialogContent.vue' export { default as DialogContent } from './DialogContent.vue'
export { default as DialogScrollContent } from './DialogScrollContent.vue' export { default as DialogDescription } from './DialogDescription.vue'
export { default as DialogFooter } from './DialogFooter.vue' export { default as DialogFooter } from './DialogFooter.vue'
export { default as DialogHeader } from './DialogHeader.vue'
export { default as DialogScrollContent } from './DialogScrollContent.vue'
export { default as DialogTitle } from './DialogTitle.vue'
export { default as DialogTrigger } from './DialogTrigger.vue'

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Check } from 'lucide-vue-next'
import { import {
DropdownMenuCheckboxItem, DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits, type DropdownMenuCheckboxItemEmits,
@ -7,8 +8,7 @@ import {
DropdownMenuItemIndicator, DropdownMenuItemIndicator,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Check } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<DropdownMenuCheckboxItemEmits>() const emits = defineEmits<DropdownMenuCheckboxItemEmits>()

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
DropdownMenuContent, DropdownMenuContent,
type DropdownMenuContentEmits, type DropdownMenuContentEmits,
@ -7,7 +7,7 @@ import {
DropdownMenuPortal, DropdownMenuPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = withDefaults( const props = withDefaults(
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes[`class`] }>(), defineProps<DropdownMenuContentProps & { class?: HTMLAttributes[`class`] }>(),

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<DropdownMenuItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Circle } from 'lucide-vue-next'
import { import {
DropdownMenuItemIndicator, DropdownMenuItemIndicator,
DropdownMenuRadioItem, DropdownMenuRadioItem,
@ -7,8 +8,7 @@ import {
type DropdownMenuRadioItemProps, type DropdownMenuRadioItemProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Circle } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
DropdownMenuSeparator, DropdownMenuSeparator,
type DropdownMenuSeparatorProps, type DropdownMenuSeparatorProps,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSeparatorProps & { const props = defineProps<DropdownMenuSeparatorProps & {
class?: HTMLAttributes[`class`] class?: HTMLAttributes[`class`]

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
DropdownMenuSubContent, DropdownMenuSubContent,
type DropdownMenuSubContentEmits, type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps, type DropdownMenuSubContentProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<DropdownMenuSubContentEmits>() const emits = defineEmits<DropdownMenuSubContentEmits>()

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { ChevronRight } from 'lucide-vue-next'
import { import {
DropdownMenuSubTrigger, DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps, type DropdownMenuSubTriggerProps,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'radix-vue'
import { ChevronRight } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,16 +1,16 @@
export { DropdownMenuPortal } from 'radix-vue'
export { default as DropdownMenu } from './DropdownMenu.vue' export { default as DropdownMenu } from './DropdownMenu.vue'
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
export { default as DropdownMenuContent } from './DropdownMenuContent.vue' export { default as DropdownMenuContent } from './DropdownMenuContent.vue'
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue' export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue'
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
export { default as DropdownMenuItem } from './DropdownMenuItem.vue' export { default as DropdownMenuItem } from './DropdownMenuItem.vue'
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue' export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue'
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
export { default as DropdownMenuSub } from './DropdownMenuSub.vue' export { default as DropdownMenuSub } from './DropdownMenuSub.vue'
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue' export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue'
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
export { DropdownMenuPortal } from 'radix-vue'

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
HoverCardContent, HoverCardContent,
type HoverCardContentProps, type HoverCardContentProps,
HoverCardPortal, HoverCardPortal,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = withDefaults( const props = withDefaults(
defineProps<HoverCardContentProps & { class?: HTMLAttributes[`class`] }>(), defineProps<HoverCardContentProps & { class?: HTMLAttributes[`class`] }>(),

View File

@ -1,3 +1,3 @@
export { default as HoverCard } from './HoverCard.vue' export { default as HoverCard } from './HoverCard.vue'
export { default as HoverCardTrigger } from './HoverCardTrigger.vue'
export { default as HoverCardContent } from './HoverCardContent.vue' export { default as HoverCardContent } from './HoverCardContent.vue'
export { default as HoverCardTrigger } from './HoverCardTrigger.vue'

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
MenubarRoot, MenubarRoot,
type MenubarRootEmits, type MenubarRootEmits,
type MenubarRootProps, type MenubarRootProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarRootProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarRootProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<MenubarRootEmits>() const emits = defineEmits<MenubarRootEmits>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Check } from 'lucide-vue-next'
import { import {
MenubarCheckboxItem, MenubarCheckboxItem,
type MenubarCheckboxItemEmits, type MenubarCheckboxItemEmits,
@ -7,8 +8,7 @@ import {
MenubarItemIndicator, MenubarItemIndicator,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Check } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<MenubarCheckboxItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarCheckboxItemProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<MenubarCheckboxItemEmits>() const emits = defineEmits<MenubarCheckboxItemEmits>()

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
MenubarContent, MenubarContent,
type MenubarContentProps, type MenubarContentProps,
MenubarPortal, MenubarPortal,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = withDefaults( const props = withDefaults(
defineProps<MenubarContentProps & { class?: HTMLAttributes[`class`] }>(), defineProps<MenubarContentProps & { class?: HTMLAttributes[`class`] }>(),

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
MenubarItem, MenubarItem,
type MenubarItemEmits, type MenubarItemEmits,
type MenubarItemProps, type MenubarItemProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<MenubarItemProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { MenubarLabel, type MenubarLabelProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { MenubarLabel, type MenubarLabelProps } from 'radix-vue'
const props = defineProps<MenubarLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<MenubarLabelProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()
</script> </script>

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Circle } from 'lucide-vue-next'
import { import {
MenubarItemIndicator, MenubarItemIndicator,
MenubarRadioItem, MenubarRadioItem,
@ -7,8 +8,7 @@ import {
type MenubarRadioItemProps, type MenubarRadioItemProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { Circle } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<MenubarRadioItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarRadioItemProps & { class?: HTMLAttributes[`class`] }>()
const emits = defineEmits<MenubarRadioItemEmits>() const emits = defineEmits<MenubarRadioItemEmits>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { MenubarSeparator, type MenubarSeparatorProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { MenubarSeparator, type MenubarSeparatorProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarSeparatorProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarSeparatorProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
MenubarPortal, MenubarPortal,
MenubarSubContent, MenubarSubContent,
@ -7,7 +7,7 @@ import {
type MenubarSubContentProps, type MenubarSubContentProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarSubContentProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarSubContentProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { MenubarSubTrigger, type MenubarSubTriggerProps, useForwardProps } from 'radix-vue'
import { ChevronRight } from 'lucide-vue-next'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronRight } from 'lucide-vue-next'
import { MenubarSubTrigger, type MenubarSubTriggerProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarSubTriggerProps & { class?: HTMLAttributes[`class`], inset?: boolean }>() const props = defineProps<MenubarSubTriggerProps & { class?: HTMLAttributes[`class`], inset?: boolean }>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { MenubarTrigger, type MenubarTriggerProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { MenubarTrigger, type MenubarTriggerProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<MenubarTriggerProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<MenubarTriggerProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,15 +1,15 @@
export { default as Menubar } from './Menubar.vue' export { default as Menubar } from './Menubar.vue'
export { default as MenubarItem } from './MenubarItem.vue' export { default as MenubarCheckboxItem } from './MenubarCheckboxItem.vue'
export { default as MenubarContent } from './MenubarContent.vue' export { default as MenubarContent } from './MenubarContent.vue'
export { default as MenubarGroup } from './MenubarGroup.vue' export { default as MenubarGroup } from './MenubarGroup.vue'
export { default as MenubarItem } from './MenubarItem.vue'
export { default as MenubarLabel } from './MenubarLabel.vue'
export { default as MenubarMenu } from './MenubarMenu.vue' export { default as MenubarMenu } from './MenubarMenu.vue'
export { default as MenubarRadioGroup } from './MenubarRadioGroup.vue' export { default as MenubarRadioGroup } from './MenubarRadioGroup.vue'
export { default as MenubarRadioItem } from './MenubarRadioItem.vue' export { default as MenubarRadioItem } from './MenubarRadioItem.vue'
export { default as MenubarCheckboxItem } from './MenubarCheckboxItem.vue'
export { default as MenubarSeparator } from './MenubarSeparator.vue' export { default as MenubarSeparator } from './MenubarSeparator.vue'
export { default as MenubarShortcut } from './MenubarShortcut.vue'
export { default as MenubarSub } from './MenubarSub.vue' export { default as MenubarSub } from './MenubarSub.vue'
export { default as MenubarSubContent } from './MenubarSubContent.vue' export { default as MenubarSubContent } from './MenubarSubContent.vue'
export { default as MenubarSubTrigger } from './MenubarSubTrigger.vue' export { default as MenubarSubTrigger } from './MenubarSubTrigger.vue'
export { default as MenubarTrigger } from './MenubarTrigger.vue' export { default as MenubarTrigger } from './MenubarTrigger.vue'
export { default as MenubarShortcut } from './MenubarShortcut.vue'
export { default as MenubarLabel } from './MenubarLabel.vue'

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { PopoverRoot, useForwardPropsEmits } from 'radix-vue'
import type { PopoverRootEmits, PopoverRootProps } from 'radix-vue' import type { PopoverRootEmits, PopoverRootProps } from 'radix-vue'
import { PopoverRoot, useForwardPropsEmits } from 'radix-vue'
const props = defineProps<PopoverRootProps>() const props = defineProps<PopoverRootProps>()
const emits = defineEmits<PopoverRootEmits>() const emits = defineEmits<PopoverRootEmits>()

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
PopoverContent, PopoverContent,
type PopoverContentEmits, type PopoverContentEmits,
@ -7,7 +7,7 @@ import {
PopoverPortal, PopoverPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/lib/utils' import { computed, type HTMLAttributes } from 'vue'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,

View File

@ -1,3 +1,3 @@
export { default as Popover } from './Popover.vue' export { default as Popover } from './Popover.vue'
export { default as PopoverTrigger } from './PopoverTrigger.vue'
export { default as PopoverContent } from './PopoverContent.vue' export { default as PopoverContent } from './PopoverContent.vue'
export { default as PopoverTrigger } from './PopoverTrigger.vue'

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { import {
SelectContent, SelectContent,
type SelectContentEmits, type SelectContentEmits,
@ -8,8 +8,8 @@ import {
SelectViewport, SelectViewport,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { SelectScrollDownButton, SelectScrollUpButton } from '.' import { SelectScrollDownButton, SelectScrollUpButton } from '.'
import { cn } from '@/lib/utils'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { SelectGroup, type SelectGroupProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectGroup, type SelectGroupProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectGroupProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectGroupProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { cn } from '@/lib/utils'
import { Check } from 'lucide-vue-next'
import { import {
SelectItem, SelectItem,
SelectItemIndicator, SelectItemIndicator,
@ -7,8 +8,7 @@ import {
SelectItemText, SelectItemText,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'radix-vue'
import { Check } from 'lucide-vue-next' import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<SelectItemProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectItemProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { SelectLabel, type SelectLabelProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectLabel, type SelectLabelProps } from 'radix-vue'
const props = defineProps<SelectLabelProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectLabelProps & { class?: HTMLAttributes[`class`] }>()
</script> </script>

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { SelectScrollDownButton, type SelectScrollDownButtonProps, useForwardProps } from 'radix-vue'
import { ChevronDown } from 'lucide-vue-next'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronDown } from 'lucide-vue-next'
import { SelectScrollDownButton, type SelectScrollDownButtonProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { SelectScrollUpButton, type SelectScrollUpButtonProps, useForwardProps } from 'radix-vue'
import { ChevronUp } from 'lucide-vue-next'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronUp } from 'lucide-vue-next'
import { SelectScrollUpButton, type SelectScrollUpButtonProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { SelectSeparator, type SelectSeparatorProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectSeparator, type SelectSeparatorProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'
import { ChevronDown } from 'lucide-vue-next'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronDown } from 'lucide-vue-next'
import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes[`class`] }>() const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes[`class`] }>()

View File

@ -1,11 +1,11 @@
export { default as Select } from './Select.vue' export { default as Select } from './Select.vue'
export { default as SelectValue } from './SelectValue.vue'
export { default as SelectTrigger } from './SelectTrigger.vue'
export { default as SelectContent } from './SelectContent.vue' export { default as SelectContent } from './SelectContent.vue'
export { default as SelectGroup } from './SelectGroup.vue' export { default as SelectGroup } from './SelectGroup.vue'
export { default as SelectItem } from './SelectItem.vue' export { default as SelectItem } from './SelectItem.vue'
export { default as SelectItemText } from './SelectItemText.vue' export { default as SelectItemText } from './SelectItemText.vue'
export { default as SelectLabel } from './SelectLabel.vue' export { default as SelectLabel } from './SelectLabel.vue'
export { default as SelectSeparator } from './SelectSeparator.vue'
export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue'
export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue' export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue'
export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue'
export { default as SelectSeparator } from './SelectSeparator.vue'
export { default as SelectTrigger } from './SelectTrigger.vue'
export { default as SelectValue } from './SelectValue.vue'

View File

@ -1,7 +1,7 @@
import { toMerged } from 'es-toolkit'
import type { IConfigOption, Theme } from '@/types' import type { IConfigOption, Theme } from '@/types'
import { toMerged } from 'es-toolkit'
const defaultTheme: Theme = { const defaultTheme: Theme = {
base: { base: {
'--md-primary-color': `#000000`, '--md-primary-color': `#000000`,

View File

@ -1,10 +1,11 @@
import { ElLoading, ElMessage } from 'element-plus' import type { App } from 'vue'
import * as ElementPlusIconsVue from '@element-plus/icons-vue' import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { ElLoading, ElMessage } from 'element-plus'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css' import 'element-plus/theme-chalk/dark/css-vars.css'
export default { export default {
install(app) { install(app: App<Element>) {
// app.use(ElementPlus, { size: `default` }) // app.use(ElementPlus, { size: `default` })
app.config.globalProperties.$loading = ElLoading.service app.config.globalProperties.$loading = ElLoading.service

View File

@ -1,7 +1,7 @@
import { createPinia } from 'pinia'
import { createApp } from 'vue' import { createApp } from 'vue'
import Store from './stores'
import ElementPlus from './element'
import App from './App.vue' import App from './App.vue'
import ElementPlus from './element'
import 'virtual:uno.css' import 'virtual:uno.css'
import 'codemirror/lib/codemirror.css' import 'codemirror/lib/codemirror.css'
@ -22,7 +22,7 @@ import 'codemirror/addon/hint/css-hint'
const app = createApp(App) const app = createApp(App)
app.use(Store) app.use(createPinia())
app.use(ElementPlus) app.use(ElementPlus)
app.mount(`#app`) app.mount(`#app`)

View File

@ -1,15 +1,15 @@
import { computed, markRaw, onMounted, ref, toRaw, watch } from 'vue'
import { createPinia, defineStore } from 'pinia'
import { marked } from 'marked'
import CodeMirror from 'codemirror'
import { useDark, useStorage, useToggle } from '@vueuse/core'
import { ElMessage, ElMessageBox } from 'element-plus'
import { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
import { initRenderer } from '@/utils/renderer'
import DEFAULT_CONTENT from '@/assets/example/markdown.md?raw' import DEFAULT_CONTENT from '@/assets/example/markdown.md?raw'
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt?raw' import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt?raw'
import { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
import { addPrefix, css2json, customCssWithTemplate, customizeTheme, downloadMD, exportHTML, formatDoc } from '@/utils' import { addPrefix, css2json, customCssWithTemplate, customizeTheme, downloadMD, exportHTML, formatDoc } from '@/utils'
import { initRenderer } from '@/utils/renderer'
import { useDark, useStorage, useToggle } from '@vueuse/core'
import CodeMirror from 'codemirror'
import { ElMessage, ElMessageBox } from 'element-plus'
import { marked } from 'marked'
import { defineStore } from 'pinia'
import { computed, markRaw, onMounted, ref, toRaw, watch } from 'vue'
export const useStore = defineStore(`store`, () => { export const useStore = defineStore(`store`, () => {
// 是否开启深色模式 // 是否开启深色模式
@ -379,23 +379,7 @@ export const useStore = defineStore(`store`, () => {
}) })
} }
const isShowCssEditor = ref(false)
const toggleShowCssEditor = useToggle(isShowCssEditor)
const isShowInsertFormDialog = ref(false)
const toggleShowInsertFormDialog = useToggle(isShowInsertFormDialog)
const isShowUploadImgDialog = ref(false)
const toggleShowUploadImgDialog = useToggle(isShowUploadImgDialog)
return { return {
isShowCssEditor,
toggleShowCssEditor,
isShowInsertFormDialog,
toggleShowInsertFormDialog,
isShowUploadImgDialog,
toggleShowUploadImgDialog,
isDark, isDark,
toggleDark, toggleDark,
@ -444,4 +428,25 @@ export const useStore = defineStore(`store`, () => {
} }
}) })
export default createPinia() export const useDisplayStore = defineStore(`display`, () => {
// 是否展示 CSS 编辑器
const isShowCssEditor = ref(false)
const toggleShowCssEditor = useToggle(isShowCssEditor)
// 是否展示插入表格对话框
const isShowInsertFormDialog = ref(false)
const toggleShowInsertFormDialog = useToggle(isShowInsertFormDialog)
// 是否展示上传图片对话框
const isShowUploadImgDialog = ref(false)
const toggleShowUploadImgDialog = useToggle(isShowUploadImgDialog)
return {
isShowCssEditor,
toggleShowCssEditor,
isShowInsertFormDialog,
toggleShowInsertFormDialog,
isShowUploadImgDialog,
toggleShowUploadImgDialog,
}
})

View File

@ -1,15 +1,15 @@
import CryptoJS from 'crypto-js' import { giteeConfig, githubConfig } from '@/config'
import OSS from 'tiny-oss'
import * as Minio from 'minio'
import COS from 'cos-js-sdk-v5'
import Buffer from 'buffer-from'
import { v4 as uuidv4 } from 'uuid'
import * as qiniu from 'qiniu-js'
import fetch from '@/utils/fetch' import fetch from '@/utils/fetch'
import { base64encode, safe64, utf16to8 } from '@/utils/tokenTools' import { base64encode, safe64, utf16to8 } from '@/utils/tokenTools'
import * as tokenTools from '@/utils/tokenTools' import * as tokenTools from '@/utils/tokenTools'
import { giteeConfig, githubConfig } from '@/config' import Buffer from 'buffer-from'
import COS from 'cos-js-sdk-v5'
import CryptoJS from 'crypto-js'
import * as Minio from 'minio'
import * as qiniu from 'qiniu-js'
import OSS from 'tiny-oss'
import { v4 as uuidv4 } from 'uuid'
function getConfig(useDefault: boolean, platform: string) { function getConfig(useDefault: boolean, platform: string) {
if (useDefault) { if (useDefault) {
@ -173,7 +173,7 @@ async function qiniuUpload(file: File) {
const dir = path ? `${path}/` : `` const dir = path ? `${path}/` : ``
const dateFilename = dir + getDateFilename(file.name) const dateFilename = dir + getDateFilename(file.name)
const observable = qiniu.upload(file, dateFilename, token, {}, { region }) const observable = qiniu.upload(file, dateFilename, token, {}, { region })
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
observable.subscribe({ observable.subscribe({
next: (result) => { next: (result) => {
console.log(result) console.log(result)
@ -229,7 +229,7 @@ async function txCOSFileUpload(file: File) {
SecretId: secretId, SecretId: secretId,
SecretKey: secretKey, SecretKey: secretKey,
}) })
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
cos.putObject( cos.putObject(
{ {
Bucket: bucket, Bucket: bucket,
@ -277,7 +277,7 @@ async function minioFileUpload(content: string, filename: string) {
if (isCustomPort) { if (isCustomPort) {
conf.port = p conf.port = p
} }
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
const minioClient = new Minio.Client(conf) const minioClient = new Minio.Client(conf)
try { try {
minioClient.putObject(bucket, dateFilename, buffer, (e) => { minioClient.putObject(bucket, dateFilename, buffer, (e) => {
@ -309,7 +309,7 @@ async function formCustomUpload(content: string, file: File) {
${localStorage.getItem(`formCustomConfig`)} ${localStorage.getItem(`formCustomConfig`)}
} }
` `
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
const exportObj = { const exportObj = {
content, // 待上传图片的 base64 content, // 待上传图片的 base64
file, // 待上传图片的 file 对象 file, // 待上传图片的 file 对象

View File

@ -1,13 +1,13 @@
import juice from 'juice' import type { Block, Inline, Theme } from '@/types'
import { format } from 'prettier/standalone'
import * as prettierPluginMarkdown from 'prettier/plugins/markdown'
import * as prettierPluginBabel from 'prettier/plugins/babel'
import * as prettierPluginEstree from 'prettier/plugins/estree'
import * as prettierPluginCss from 'prettier/plugins/postcss'
import type { PropertiesHyphen } from 'csstype' import type { PropertiesHyphen } from 'csstype'
import { prefix } from '@/config' import { prefix } from '@/config'
import type { Block, Inline, Theme } from '@/types' import juice from 'juice'
import * as prettierPluginBabel from 'prettier/plugins/babel'
import * as prettierPluginEstree from 'prettier/plugins/estree'
import * as prettierPluginMarkdown from 'prettier/plugins/markdown'
import * as prettierPluginCss from 'prettier/plugins/postcss'
import { format } from 'prettier/standalone'
export function addPrefix(str: string) { export function addPrefix(str: string) {
return `${prefix}__${str}` return `${prefix}__${str}`
@ -111,8 +111,6 @@ export function css2json(css: string): Partial<Record<Block | Inline, Properties
css = css.slice(rbracket + 1).trim() css = css.slice(rbracket + 1).trim()
} }
console.log(`json`, json)
return json return json
} }
@ -253,10 +251,10 @@ export function createTable({ data, rows, cols }: { data: { [k: string]: string
} }
export function toBase64(file: Blob) { export function toBase64(file: Blob) {
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
const reader = new FileReader() const reader = new FileReader()
reader.readAsDataURL(file) reader.readAsDataURL(file)
reader.onload = () => resolve((reader.result as string).split(`,`).pop()) reader.onload = () => resolve((reader.result as string).split(`,`).pop()!)
reader.onerror = error => reject(error) reader.onerror = error => reject(error)
}) })
} }

View File

@ -1,12 +1,12 @@
import type { Renderer, RendererObject, Tokens } from 'marked'
import { marked } from 'marked'
import hljs from 'highlight.js'
import mermaid from 'mermaid'
import { toMerged } from 'es-toolkit'
import type { PropertiesHyphen } from 'csstype'
import { MDKatex } from './MDKatex'
import type { ExtendedProperties, IOpts, ThemeStyles } from '@/types' import type { ExtendedProperties, IOpts, ThemeStyles } from '@/types'
import type { PropertiesHyphen } from 'csstype'
import type { Renderer, RendererObject, Tokens } from 'marked'
import { toMerged } from 'es-toolkit'
import hljs from 'highlight.js'
import { marked } from 'marked'
import mermaid from 'mermaid'
import { MDKatex } from './MDKatex'
marked.use(MDKatex({ nonStandard: true })) marked.use(MDKatex({ nonStandard: true }))

View File

@ -1,18 +1,11 @@
<script setup> <script setup lang="ts">
import { onMounted, ref, toRaw, watch } from 'vue' import type { ComponentPublicInstance } from 'vue'
import { storeToRefs } from 'pinia' import CssEditor from '@/components/CodemirrorEditor/CssEditor.vue'
import { ElMessage } from 'element-plus'
import CodeMirror from 'codemirror'
import fileApi from '@/utils/file'
import { useStore } from '@/stores'
import EditorHeader from '@/components/CodemirrorEditor/EditorHeader/index.vue' import EditorHeader from '@/components/CodemirrorEditor/EditorHeader/index.vue'
import InsertFormDialog from '@/components/CodemirrorEditor/InsertFormDialog.vue' import InsertFormDialog from '@/components/CodemirrorEditor/InsertFormDialog.vue'
import UploadImgDialog from '@/components/CodemirrorEditor/UploadImgDialog.vue' import UploadImgDialog from '@/components/CodemirrorEditor/UploadImgDialog.vue'
import CssEditor from '@/components/CodemirrorEditor/CssEditor.vue'
import RunLoading from '@/components/RunLoading.vue'
import RunLoading from '@/components/RunLoading.vue'
import { import {
ContextMenu, ContextMenu,
ContextMenuContent, ContextMenuContent,
@ -23,15 +16,25 @@ import {
} from '@/components/ui/context-menu' } from '@/components/ui/context-menu'
import { altKey, altSign, ctrlKey, shiftKey, shiftSign } from '@/config' import { altKey, altSign, ctrlKey, shiftKey, shiftSign } from '@/config'
import { useDisplayStore, useStore } from '@/stores'
import { import {
checkImage, checkImage,
formatDoc, formatDoc,
toBase64, toBase64,
} from '@/utils' } from '@/utils'
import fileApi from '@/utils/file'
import CodeMirror from 'codemirror'
import { ElCol, ElMessage } from 'element-plus'
import { storeToRefs } from 'pinia'
import { onMounted, ref, toRaw, watch } from 'vue'
const store = useStore() const store = useStore()
const { isDark, output, editor, editorContent, isShowCssEditor } = storeToRefs(store) const displayStore = useDisplayStore()
const { isDark, output, editor, editorContent } = storeToRefs(store)
const { isShowCssEditor } = storeToRefs(displayStore)
const { const {
editorRefresh, editorRefresh,
@ -40,33 +43,37 @@ const {
formatContent, formatContent,
importMarkdownContent, importMarkdownContent,
resetStyleConfirm, resetStyleConfirm,
toggleShowInsertFormDialog,
toggleShowUploadImgDialog,
} = store } = store
const isImgLoading = ref(false) const {
const timeout = ref(0) toggleShowInsertFormDialog,
toggleShowUploadImgDialog,
} = displayStore
const preview = ref(null) const isImgLoading = ref(false)
const timeout = ref<NodeJS.Timeout>()
const preview = ref<typeof ElCol | null>(null)
// 使 // 使
function leftAndRightScroll() { function leftAndRightScroll() {
const scrollCB = (text) => { const scrollCB = (text: string) => {
let source, target let source: HTMLElement
let target: HTMLElement
clearTimeout(timeout.value) clearTimeout(timeout.value)
if (text === `preview`) { if (text === `preview`) {
source = preview.value.$el source = preview.value!.$el
target = document.querySelector(`.CodeMirror-scroll`) target = document.querySelector<HTMLElement>(`.CodeMirror-scroll`)!
editor.value.off(`scroll`, editorScrollCB) editor.value!.off(`scroll`, editorScrollCB)
timeout.value = setTimeout(() => { timeout.value = setTimeout(() => {
editor.value.on(`scroll`, editorScrollCB) editor.value!.on(`scroll`, editorScrollCB)
}, 300) }, 300)
} }
else if (text === `editor`) { else {
source = document.querySelector(`.CodeMirror-scroll`) source = document.querySelector<HTMLElement>(`.CodeMirror-scroll`)!
target = preview.value.$el target = preview.value!.$el
target.removeEventListener(`scroll`, previewScrollCB, false) target.removeEventListener(`scroll`, previewScrollCB, false)
timeout.value = setTimeout(() => { timeout.value = setTimeout(() => {
@ -89,8 +96,8 @@ function leftAndRightScroll() {
scrollCB(`preview`) scrollCB(`preview`)
} }
preview.value.$el.addEventListener(`scroll`, previewScrollCB, false) (preview.value!.$el).addEventListener(`scroll`, previewScrollCB, false)
editor.value.on(`scroll`, editorScrollCB) editor.value!.on(`scroll`, editorScrollCB)
} }
onMounted(() => { onMounted(() => {
@ -120,7 +127,7 @@ function endCopy() {
}, 800) }, 800)
} }
function beforeUpload(file) { function beforeUpload(file: File) {
// validate image // validate image
const checkResult = checkImage(file) const checkResult = checkImage(file)
if (!checkResult.ok) { if (!checkResult.ok) {
@ -142,20 +149,20 @@ function beforeUpload(file) {
} }
// //
function uploaded(imageUrl) { function uploaded(imageUrl: string) {
if (!imageUrl) { if (!imageUrl) {
ElMessage.error(`上传图片未知异常`) ElMessage.error(`上传图片未知异常`)
return return
} }
toggleShowUploadImgDialog(false) toggleShowUploadImgDialog(false)
// //
const cursor = editor.value.getCursor() const cursor = editor.value!.getCursor()
const markdownImage = `![](${imageUrl})` const markdownImage = `![](${imageUrl})`
// Markdown URL // Markdown URL
toRaw(store.editor).replaceSelection(`\n${markdownImage}\n`, cursor) toRaw(store.editor!).replaceSelection(`\n${markdownImage}\n`, cursor as any)
ElMessage.success(`图片上传成功`) ElMessage.success(`图片上传成功`)
} }
function uploadImage(file, cb) { function uploadImage(file: File, cb?: { (url: any): void, (arg0: unknown): void } | undefined) {
isImgLoading.value = true isImgLoading.value = true
toBase64(file) toBase64(file)
@ -176,7 +183,7 @@ function uploadImage(file, cb) {
}) })
} }
const changeTimer = ref(0) const changeTimer = ref<NodeJS.Timeout>()
// //
watch(isDark, () => { watch(isDark, () => {
@ -186,7 +193,7 @@ watch(isDark, () => {
// //
function initEditor() { function initEditor() {
const editorDom = document.querySelector(`#editor`) const editorDom = document.querySelector<HTMLTextAreaElement>(`#editor`)!
if (!editorDom.value) { if (!editorDom.value) {
editorDom.value = editorContent.value editorDom.value = editorContent.value
@ -200,7 +207,7 @@ function initEditor() {
autoCloseBrackets: true, autoCloseBrackets: true,
extraKeys: { extraKeys: {
[`${shiftKey}-${altKey}-F`]: function autoFormat(editor) { [`${shiftKey}-${altKey}-F`]: function autoFormat(editor) {
formatDoc(editor.getValue(0)).then((doc) => { formatDoc(editor.getValue()).then((doc) => {
editor.setValue(doc) editor.setValue(doc)
}) })
}, },
@ -241,7 +248,7 @@ function initEditor() {
}) })
// //
editor.value.on(`paste`, (cm, e) => { editor.value.on(`paste`, (_cm, e) => {
if (!(e.clipboardData && e.clipboardData.items) || isImgLoading.value) { if (!(e.clipboardData && e.clipboardData.items) || isImgLoading.value) {
return return
} }
@ -249,7 +256,7 @@ function initEditor() {
const item = e.clipboardData.items[i] const item = e.clipboardData.items[i]
if (item.kind === `file`) { if (item.kind === `file`) {
// //
const pasteFile = item.getAsFile() const pasteFile = item.getAsFile()!
const isValid = beforeUpload(pasteFile) const isValid = beforeUpload(pasteFile)
if (!isValid) { if (!isValid) {
continue continue
@ -263,33 +270,33 @@ function initEditor() {
const container = ref(null) const container = ref(null)
// //
function addFormat(cmd) { function addFormat(cmd: string | number) {
editor.value.options.extraKeys[cmd](editor.value) (editor.value as any).options.extraKeys[cmd](editor.value)
} }
const codeMirrorWrapper = ref(null) const codeMirrorWrapper = ref<ComponentPublicInstance<typeof ElCol> | null>(null)
// markdown 线 // markdown 线
// todo // todo
function mdLocalToRemote() { function mdLocalToRemote() {
const dom = codeMirrorWrapper.value.$el const dom = codeMirrorWrapper.value!.$el as HTMLElement
// md // md
const uploadMdImg = async ({ md, list }) => { const uploadMdImg = async ({ md, list }: { md: { str: string, path: string, file: File }, list: { path: string, file: File }[] }) => {
const mdImgList = [ const mdImgList = [
...(md.str.matchAll(/!\[(.*?)\]\((.*?)\)/g) || []), ...(md.str.matchAll(/!\[(.*?)\]\((.*?)\)/g) || []),
].filter((item) => { ].filter((item) => {
return item // return item //
}) })
const root = md.path.match(/.+?\//)[0] const root = md.path.match(/.+?\//)![0]
const resList = await Promise.all( const resList = await Promise.all<{ matchStr: string, url: string }>(
mdImgList.map((item) => { mdImgList.map((item) => {
return new Promise((resolve) => { return new Promise((resolve) => {
let [, , matchStr] = item let [, , matchStr] = item
matchStr = matchStr.replace(/^.\//, ``) // 处理 ./img/ img/ 统一相对路径风格 matchStr = matchStr.replace(/^.\//, ``) // 处理 ./img/ img/ 统一相对路径风格
const { file } const { file }
= list.find(f => f.path === `${root}${matchStr}`) || {} = list.find(f => f.path === `${root}${matchStr}`) || {}
uploadImage(file, (url) => { uploadImage(file!, (url) => {
resolve({ matchStr, url }) resolve({ matchStr, url })
}) })
}) })
@ -300,16 +307,16 @@ function mdLocalToRemote() {
.replace(`](./${item.matchStr})`, `](${item.url})`) .replace(`](./${item.matchStr})`, `](${item.url})`)
.replace(`](${item.matchStr})`, `](${item.url})`) .replace(`](${item.matchStr})`, `](${item.url})`)
}) })
editor.value.setValue(md.str) editor.value!.setValue(md.str)
} }
dom.ondragover = evt => evt.preventDefault() dom.ondragover = evt => evt.preventDefault()
dom.ondrop = async (evt) => { dom.ondrop = async (evt: any) => {
evt.preventDefault() evt.preventDefault()
for (const item of evt.dataTransfer.items) { for (const item of evt.dataTransfer.items) {
item.getAsFileSystemHandle().then(async (handle) => { item.getAsFileSystemHandle().then(async (handle: { kind: string, getFile: () => any }) => {
if (handle.kind === `directory`) { if (handle.kind === `directory`) {
const list = await showFileStructure(handle) const list = await showFileStructure(handle) as { path: string, file: File }[]
const md = await getMd({ list }) const md = await getMd({ list })
uploadMdImg({ md, list }) uploadMdImg({ md, list })
} }
@ -322,14 +329,14 @@ function mdLocalToRemote() {
} }
// md // md
async function getMd({ list }) { async function getMd({ list }: { list: { path: string, file: File }[] }) {
return new Promise((resolve) => { return new Promise<{ str: string, file: File, path: string }>((resolve) => {
const { path, file } = list.find(item => item.path.match(/\.md$/)) const { path, file } = list.find(item => item.path.match(/\.md$/))!
const reader = new FileReader() const reader = new FileReader()
reader.readAsText(file, `UTF-8`) reader.readAsText(file!, `UTF-8`)
reader.onload = (evt) => { reader.onload = (evt) => {
resolve({ resolve({
str: evt.target.result, str: evt.target!.result as string,
file, file,
path, path,
}) })
@ -338,7 +345,7 @@ function mdLocalToRemote() {
} }
// //
async function showFileStructure(root) { async function showFileStructure(root: any) {
const result = [] const result = []
let cwd = `` let cwd = ``
try { try {
@ -385,7 +392,7 @@ onMounted(() => {
/> />
<main class="container-main flex-1"> <main class="container-main flex-1">
<el-row class="container-main-section h-full border-1"> <el-row class="container-main-section h-full border-1">
<el-col <ElCol
ref="codeMirrorWrapper" ref="codeMirrorWrapper"
:span="isShowCssEditor ? 8 : 12" :span="isShowCssEditor ? 8 : 12"
class="codeMirror-wrapper border-r-1" class="codeMirror-wrapper border-r-1"
@ -427,8 +434,8 @@ onMounted(() => {
</ContextMenuItem> </ContextMenuItem>
</ContextMenuContent> </ContextMenuContent>
</ContextMenu> </ContextMenu>
</el-col> </ElCol>
<el-col <ElCol
id="preview" id="preview"
ref="preview" ref="preview"
:span="isShowCssEditor ? 8 : 12" :span="isShowCssEditor ? 8 : 12"
@ -445,7 +452,7 @@ onMounted(() => {
</div> </div>
</div> </div>
</div> </div>
</el-col> </ElCol>
<CssEditor /> <CssEditor />
</el-row> </el-row>
</main> </main>

View File

@ -1,15 +1,15 @@
import path from 'node:path' import path from 'node:path'
import process from 'node:process' import process from 'node:process'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'
import vueDevTools from 'vite-plugin-vue-devtools'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import { visualizer } from 'rollup-plugin-visualizer' import { visualizer } from 'rollup-plugin-visualizer'
import UnoCSS from 'unocss/vite'
import AutoImport from 'unplugin-auto-import/vite' import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vite'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({