Skip to content
Open
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
100 changes: 65 additions & 35 deletions apps/web/src/components/editor/editor-header/PostInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,21 @@ async function prePost() {
declare global {
interface Window {
syncPost: (data: { thumb: string, title: string, desc: string, content: string }) => void
$syncer: any
$cose: any
}
}

async function getAccounts(): Promise<void> {
return new Promise((resolve) => {
window.$syncer?.getAccounts((resp: PostAccount[]) => {
allAccounts.value = resp.map(a => ({ ...a, checked: true }))
if (window.$cose !== undefined) {
window.$cose.getAccounts((resp: PostAccount[]) => {
allAccounts.value = resp.map(a => ({ ...a, checked: false }))
resolve()
})
}
else {
resolve()
})
}
})
}

Expand All @@ -100,24 +105,33 @@ function onUpdate(val: boolean) {
}
}

function getPlatformUrl(type: string): string {
const urls: Record<string, string> = {
csdn: 'https://blog.csdn.net',
juejin: 'https://juejin.cn',
wechat: 'https://mp.weixin.qq.com',
}
return urls[type] || '#'
}

function checkExtension() {
if (window.$syncer !== undefined) {
if (window.$cose !== undefined) {
extensionInstalled.value = true
return
}

// 如果插件还没加载,5秒内每 500ms 检查一次
let count = 0
const timer = setInterval(async () => {
if (window.$syncer !== undefined) {
if (window.$cose !== undefined) {
extensionInstalled.value = true
await getAccounts()
clearInterval(timer)
return
}

count++
if (count > 10) { // 5秒后还是没有检测到,就停止检查
if (count > 10) {
clearInterval(timer)
}
}, 500)
Expand Down Expand Up @@ -156,14 +170,7 @@ onBeforeMount(() => {
<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>
插件
请安装 <a href="https://chromewebstore.google.com/detail/ilhikcdphhpjofhlnbojifbihhfmmhfk" target="_blank" class="underline text-primary">cose 文章同步助手</a> 浏览器扩展
</AlertDescription>
</Alert>

Expand All @@ -188,28 +195,51 @@ onBeforeMount(() => {

<div class="w-full flex items-start gap-4">
<Label class="w-10 text-end">
账号
平台
</Label>
<div class="flex flex-1 flex-col gap-2">
<div v-for="account in form.accounts" :key="account.uid + account.displayName" class="flex items-center gap-2">
<label class="flex flex-row items-center gap-4">
<CheckboxRoot
v-model:checked="account.checked"
class="bg-background hover:bg-muted h-[25px] w-[25px] flex appearance-none items-center justify-center border border-gray-200 rounded-[4px] outline-hidden"
<div class="flex-1 grid grid-cols-1 gap-y-2">
<div
v-for="account in form.accounts"
:key="account.uid"
class="flex items-center gap-2"
>
<CheckboxRoot
v-model:checked="account.checked"
:disabled="!account.loggedIn"
class="bg-background hover:bg-muted h-[18px] w-[18px] flex shrink-0 appearance-none items-center justify-center border border-gray-300 rounded-[3px] outline-hidden disabled:opacity-50 disabled:cursor-not-allowed"
>
<CheckboxIndicator>
<Check v-if="account.checked" class="h-3 w-3" />
</CheckboxIndicator>
</CheckboxRoot>
<img
:src="account.icon"
alt=""
class="inline-block h-[16px] w-[16px] shrink-0"
>
<span class="text-sm font-medium">{{ account.title }}</span>
<!-- 已登录:显示头像和用户名 -->
<template v-if="account.loggedIn">
<img
v-if="account.avatar"
:src="account.avatar"
alt=""
class="ml-1 h-4 w-4 rounded-full object-cover"
referrerpolicy="no-referrer"
@error="(e: Event) => (e.target as HTMLImageElement).style.display = 'none'"
>
<CheckboxIndicator>
<Check v-if="account.checked" class="h-4 w-4" />
</CheckboxIndicator>
</CheckboxRoot>
<span class="flex items-center gap-2 text-sm">
<img
:src="account.icon"
alt=""
class="inline-block h-[20px] w-[20px]"
>
{{ account.title }} - {{ account.displayName ?? account.home }}
</span>
</label>
<span class="text-sm text-muted-foreground">@{{ account.displayName }}</span>
</template>
<!-- 未登录:显示登录链接 -->
<Primitive
v-else
as="a"
:href="getPlatformUrl(account.type)"
target="_blank"
class="ml-1 text-sm text-muted-foreground hover:underline"
>
登录
</Primitive>
</div>
</div>
</div>
Expand Down
44 changes: 26 additions & 18 deletions apps/web/src/components/editor/editor-header/PostTaskDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
import type { Post } from '@md/shared/types'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'

declare global {
interface Window {
$cose: any
}
}

const props = defineProps<{
post: Post
open: boolean
Expand All @@ -21,25 +27,27 @@ async function startPost() {
if (!props.post)
return

const taskData = {
post: {
title: props.post.title,
content: props.post.content,
markdown: props.post.markdown,
thumb: props.post.thumb,
desc: props.post.desc,
},
accounts: props.post.accounts.filter(a => a.checked),
}

const onProgress = (newStatus: any) => {
taskStatus.value = newStatus
}

const onComplete = () => {
submitting.value = false
}

try {
window.$syncer?.addTask(
{
post: {
title: props.post.title,
content: props.post.content,
markdown: props.post.markdown,
thumb: props.post.thumb,
desc: props.post.desc,
},
accounts: props.post.accounts.filter(a => a.checked),
},
(newStatus: any) => {
taskStatus.value = newStatus
},
() => {
submitting.value = false
},
)
window.$cose?.addTask(taskData, onProgress, onComplete)
}
catch (error) {
console.error(`发布失败:`, error)
Expand Down
5 changes: 3 additions & 2 deletions packages/shared/src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ export interface Alert {
}

export interface PostAccount {
avatar: string
avatar?: string
displayName: string
home: string
icon: string
supportTypes: string[]
supportTypes?: string[]
title: string
type: string
uid: string
checked: boolean
loggedIn?: boolean
status?: string
error?: string
}
Expand Down
Loading