mirror of
https://github.com/doocs/md.git
synced 2025-01-22 20:04:39 +08:00
feat: add dark mode toggle and enhance interaction in CodemirrorEditor (#511)
This commit is contained in:
parent
741322d69e
commit
1dc3693826
@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { useStore } from '@/stores'
|
||||
import { Info } from 'lucide-vue-next'
|
||||
import { Primitive } from 'radix-vue'
|
||||
|
||||
const store = useStore()
|
||||
const { output } = storeToRefs(store)
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
const extensionInstalled = ref(false)
|
||||
const form = ref<any>({
|
||||
title: ``,
|
||||
desc: ``,
|
||||
@ -40,12 +41,12 @@ function prePost() {
|
||||
declare global {
|
||||
interface Window {
|
||||
syncPost: (data: { thumb: string, title: string, desc: string, content: string }) => void
|
||||
$syncer: any
|
||||
}
|
||||
}
|
||||
|
||||
function post() {
|
||||
dialogVisible.value = false;
|
||||
// 使用 window.$syncer 可以检测是否安装插件
|
||||
(window.syncPost)({
|
||||
thumb: form.value.thumb || form.value.auto.thumb,
|
||||
title: form.value.title || form.value.auto.title,
|
||||
@ -59,6 +60,10 @@ function onUpdate(val: boolean) {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
extensionInstalled.value = window.$syncer !== `undefined`
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -80,6 +85,23 @@ function onUpdate(val: boolean) {
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert v-if="!extensionInstalled">
|
||||
<Info class="h-4 w-4" />
|
||||
<AlertTitle>未检测到插件</AlertTitle>
|
||||
<AlertDescription>
|
||||
请安装
|
||||
<Primitive
|
||||
as="a"
|
||||
class="text-blue-500"
|
||||
href="https://www.wechatsync.com/?utm_source=syncicon#install"
|
||||
target="_blank"
|
||||
>
|
||||
文章同步助手
|
||||
</Primitive>
|
||||
插件
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div class="w-full flex items-center gap-4">
|
||||
<Label for="thumb" class="w-10 text-end">
|
||||
封面
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
} from '@/config'
|
||||
import { useStore } from '@/stores'
|
||||
import { addPrefix, processClipboardContent } from '@/utils'
|
||||
import { ChevronDownIcon, PanelLeftClose, PanelLeftOpen, Settings } from 'lucide-vue-next'
|
||||
import { ChevronDownIcon, Moon, PanelLeftClose, PanelLeftOpen, Settings, Sun } from 'lucide-vue-next'
|
||||
|
||||
const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`])
|
||||
|
||||
@ -155,6 +155,11 @@ function copy() {
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
||||
<Button variant="outline" @click="toggleDark()">
|
||||
<Moon v-show="isDark" class="size-4" />
|
||||
<Sun v-show="!isDark" class="size-4" />
|
||||
</Button>
|
||||
|
||||
<div class="space-x-1 bg-background text-background-foreground mx-2 flex items-center border rounded-md">
|
||||
<Button variant="ghost" class="shadow-none" @click="copy">
|
||||
复制
|
||||
|
61
src/components/ui/back-top/BackTop.vue
Normal file
61
src/components/ui/back-top/BackTop.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { throttle } from 'es-toolkit'
|
||||
import { ArrowUpFromLine } from 'lucide-vue-next'
|
||||
|
||||
type Target = HTMLElement | Window | null
|
||||
|
||||
const props = defineProps<{
|
||||
left?: number
|
||||
top?: number
|
||||
right?: number
|
||||
bottom?: number
|
||||
visibilityHeight?: number
|
||||
target?: string
|
||||
onClick?: (e: MouseEvent) => void
|
||||
}>()
|
||||
|
||||
const visibilityHeight = ref(props.visibilityHeight ?? 400)
|
||||
const visible = ref(false)
|
||||
|
||||
const target = ref<Target>(null)
|
||||
|
||||
function scrollToTop(e: MouseEvent) {
|
||||
console.log(`scrollToTop`)
|
||||
target.value?.scrollTo({ top: 0, left: 0, behavior: `smooth` })
|
||||
props.onClick?.(e)
|
||||
}
|
||||
|
||||
const throttledScroll = throttle((el: Target) => {
|
||||
if (el instanceof HTMLElement) {
|
||||
visible.value = el.scrollTop > visibilityHeight.value
|
||||
}
|
||||
else {
|
||||
visible.value = window.scrollY > visibilityHeight.value
|
||||
}
|
||||
}, 200, { edges: [`leading`, `trailing`] })
|
||||
|
||||
onMounted(() => {
|
||||
if (props.target) {
|
||||
target.value = document.getElementById(props.target)
|
||||
}
|
||||
else {
|
||||
target.value = window
|
||||
}
|
||||
|
||||
target.value!.addEventListener(`scroll`, () => {
|
||||
throttledScroll(target.value)
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
target.value!.removeEventListener(`scroll`, () => {
|
||||
throttledScroll(target.value)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-if="visible" variant="outline" size="icon" class="fixed z-50 rounded-full" :style="{ left: `${left}px`, top: `${top}px`, right: `${right}px`, bottom: `${bottom}px` }" @click="scrollToTop">
|
||||
<ArrowUpFromLine />
|
||||
</Button>
|
||||
</template>
|
1
src/components/ui/back-top/index.ts
Normal file
1
src/components/ui/back-top/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as BackTop } from './BackTop.vue'
|
@ -430,6 +430,8 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BackTop target="preview" :right="40" :bottom="40" />
|
||||
</div>
|
||||
<CssEditor class="order-2 flex-1" />
|
||||
<RightSlider class="order-2" />
|
||||
|
Loading…
Reference in New Issue
Block a user