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
2 changes: 2 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"highlight.js": "^11.11.1",
"html-to-image": "^1.11.13",
"isomorphic-dompurify": "^2.31.0",
"jszip": "^3.10.1",
"juice": "^11.0.3",
"lucide-vue-next": "^0.552.0",
"marked": "^16.4.1",
Expand Down Expand Up @@ -83,6 +84,7 @@
"@tailwindcss/vite": "^4.1.16",
"@types/buffer-from": "^1.1.3",
"@types/crypto-js": "^4.2.2",
"@types/jszip": "^3.4.1",
"@types/mdast": "^4.0.4",
"@types/unist": "^3.0.3",
"@vitejs/plugin-vue": "^6.0.1",
Expand Down
66 changes: 37 additions & 29 deletions apps/web/src/components/editor/post-slider/PostItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ const props = defineProps<{
handleDragEnd: () => void
// 以添加子文章的方式打开对话框
openAddPostDialog: (parentId: string) => void
// 打开多选导出对话框
isOpenMultipleMode: boolean
// 选中的文章 ID 集合
selectedPosts: Set<string>
// 切换文章选中状态
togglePostSelection: (postId: string) => void
// 如果多选模式未开启,则开启它
openMultipleModeIfClosed: () => void
// 如果没有选中任何文章,则关闭多选模式
closeMultipleModeIfNoSelection: () => void
}>()

const postStore = usePostStore()
Expand Down Expand Up @@ -85,11 +95,13 @@ function isHasChild(postId: string) {
</script>

<template>
<div v-for="post in props.sortedPosts.filter(p => (props.parentId == null && p.parentId == null) || p.parentId === props.parentId)" :key="post.id">
<div
v-for="post in props.sortedPosts.filter(p => (props.parentId == null && p.parentId == null) || p.parentId === props.parentId)"
:key="post.id"
>
<!-- 根文章外层容器 -->
<a
class="w-full inline-flex cursor-pointer items-center gap-1 rounded p-2 text-sm transition-colors"
:class="[
class="w-full inline-flex cursor-pointer items-center gap-1 rounded p-2 text-sm transition-colors" :class="[
// eslint-disable-next-line vue/prefer-separate-static-class
'hover:text-primary-foreground hover:bg-primary',
{
Expand All @@ -105,32 +117,31 @@ function isHasChild(postId: string) {
@drop.prevent="props.handleDrop(post.id)"
@dragover.stop.prevent="props.setDropTargetId(post.id)"
@dragleave.prevent="props.setDropTargetId(null)"
@mouseenter="props.openMultipleModeIfClosed"
@mouseleave="props.closeMultipleModeIfNoSelection"
@click="currentPostId = post.id"
>
<!-- 折叠展开图标 -->
<Button
size="xs"
variant="ghost"
class="h-max p-0.5"
:class="isHasChild(post.id) ? 'opacity-100' : 'opacity-0'"
size="xs" variant="ghost" class="h-max p-0.5" :class="isHasChild(post.id) ? 'opacity-100' : 'opacity-0'"
@click.stop="isHasChild(post.id) && togglePostExpanded(post.id)"
>
<ChevronRight
class="size-4 transition-transform"
:class="{ 'rotate-90': !post.collapsed }"
/>
<ChevronRight class="size-4 transition-transform" :class="{ 'rotate-90': !post.collapsed }" />
</Button>
<CheckBox
v-if="props.isOpenMultipleMode" :checked="props.selectedPosts.has(post.id)"
@update:checked="props.togglePostSelection(post.id)"
>
<span class="line-clamp-1">{{ post.title }}</span>
</CheckBox>

<span class="line-clamp-1">{{ post.title }}</span>
<!-- 如果没有开启多选模式,直接显示标题 -->
<span v-if="!props.isOpenMultipleMode" class="line-clamp-1">{{ post.title }}</span>

<!-- 每条文章操作 -->
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button
size="xs"
variant="ghost"
class="ml-auto h-max p-0.5"
>
<Button size="xs" variant="ghost" class="ml-auto h-max p-0.5">
<Ellipsis class="size-4" />
</Button>
</DropdownMenuTrigger>
Expand Down Expand Up @@ -159,18 +170,15 @@ function isHasChild(postId: string) {
class="space-y-1 ml-4 mt-1 border-l-2 border-gray-300 pl-1 dark:border-gray-700"
>
<PostItem
:parent-id="post.id"
:sorted-posts="props.sortedPosts"
:start-rename-post="props.startRenamePost"
:open-history-dialog="props.openHistoryDialog"
:start-del-post="props.startDelPost"
:drag-source-id="props.dragSourceId"
:set-drag-source-id="props.setDragSourceId"
:drop-target-id="props.dropTargetId"
:set-drop-target-id="props.setDropTargetId"
:handle-drag-end="props.handleDragEnd"
:handle-drop="props.handleDrop"
:open-add-post-dialog="props.openAddPostDialog"
:parent-id="post.id" :sorted-posts="props.sortedPosts" :start-rename-post="props.startRenamePost"
:open-history-dialog="props.openHistoryDialog" :start-del-post="props.startDelPost"
:drag-source-id="props.dragSourceId" :set-drag-source-id="props.setDragSourceId"
:drop-target-id="props.dropTargetId" :set-drop-target-id="props.setDropTargetId"
:handle-drag-end="props.handleDragEnd" :handle-drop="props.handleDrop"
:open-add-post-dialog="props.openAddPostDialog" :is-open-multiple-mode="props.isOpenMultipleMode"
:selected-posts="props.selectedPosts" :toggle-post-selection="props.togglePostSelection"
:open-multiple-mode-if-closed="props.openMultipleModeIfClosed"
:close-multiple-mode-if-no-selection="props.closeMultipleModeIfNoSelection"
/>
</div>
</div>
Expand Down
Loading
Loading