Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support html copy #489

Merged
merged 3 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 51 additions & 13 deletions src/components/CodemirrorEditor/EditorHeader/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
themeOptions,
} from '@/config'
import { useDisplayStore, useStore } from '@/stores'
import { mergeCss, solveWeChatImage } from '@/utils'
import { Moon, PanelLeftClose, PanelLeftOpen, Settings, Sun } from 'lucide-vue-next'
import { addPrefix, mergeCss, solveWeChatImage } from '@/utils'
import { ChevronDownIcon, Moon, PanelLeftClose, PanelLeftOpen, Settings, Sun } from 'lucide-vue-next'
import PickColors from 'vue-pick-colors'

const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`])
Expand Down Expand Up @@ -60,6 +60,10 @@ const { isDark, isCiteStatus, output, primaryColor } = storeToRefs(store)

const { toggleDark, editorRefresh, citeStatusChanged } = store

const copyMode = useStorage(addPrefix(`copyMode`), `txt`)
const source = ref(``)
const { copy: copyContent } = useClipboard({ source })

// 复制到微信公众号
function copy() {
emit(`startCopy`)
Expand All @@ -85,7 +89,7 @@ function copy() {
toggleDark()
}

nextTick(() => {
nextTick(async () => {
solveWeChatImage()

const clipboardDiv = document.getElementById(`output`)!
Expand Down Expand Up @@ -128,21 +132,30 @@ function copy() {
})

window.getSelection()!.removeAllRanges()
const range = document.createRange()

range.setStartBefore(clipboardDiv.firstChild!)
range.setEndAfter(clipboardDiv.lastChild!)
window.getSelection()!.addRange(range)
document.execCommand(`copy`)
window.getSelection()!.removeAllRanges()
const temp = clipboardDiv.innerHTML

if (copyMode.value === `txt`) {
const range = document.createRange()
range.setStartBefore(clipboardDiv.firstChild!)
range.setEndAfter(clipboardDiv.lastChild!)
window.getSelection()!.addRange(range)
document.execCommand(`copy`)
window.getSelection()!.removeAllRanges()
}

clipboardDiv.innerHTML = output.value

if (isBeforeDark) {
nextTick(() => toggleDark())
}

if (copyMode.value === `html`) {
await copyContent(temp)
}

// 输出提示
toast.success(`已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴`)
toast.success(copyMode.value === `html` ? `已复制 HTML 源码,请进行下一步操作。` : `已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴`)

editorRefresh()
emit(`endCopy`)
Expand Down Expand Up @@ -424,9 +437,34 @@ const formatOptions = ref<Format[]>([`rgb`, `hex`, `hsl`, `hsv`])
</div>
</PopoverContent>
</Popover>
<Button variant="outline" class="mx-2" @click="copy">
复制
</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">
复制
</Button>
<Separator orientation="vertical" class="h-5" />
<DropdownMenu v-model="copyMode">
<DropdownMenuTrigger as-child>
<Button variant="ghost" class="px-2 shadow-none">
<ChevronDownIcon class="text-secondary-foreground h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
:align-offset="-5"
class="w-[200px]"
>
<DropdownMenuRadioGroup v-model="copyMode">
<DropdownMenuRadioItem value="txt">
公众号格式
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="html">
HTML 格式
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>

<PostInfo />

Expand Down
35 changes: 35 additions & 0 deletions src/components/ui/separator/Separator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { Separator, type SeparatorProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'

const props = defineProps<
SeparatorProps & { class?: HTMLAttributes[`class`], label?: string }
>()

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props

return delegated
})
</script>

<template>
<Separator
v-bind="delegatedProps"
:class="
cn(
'shrink-0 bg-border relative',
props.orientation === 'vertical' ? 'w-px h-full' : 'h-px w-full',
props.class,
)
"
>
<span
v-if="props.label"
:class="cn('text-xs text-muted-foreground bg-background absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex justify-center items-center',
props.orientation === 'vertical' ? 'w-[1px] px-1 py-2' : 'h-[1px] py-1 px-2',
)"
>{{ props.label }}</span>
</Separator>
</template>
1 change: 1 addition & 0 deletions src/components/ui/separator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Separator } from './Separator.vue'
Loading