feat: enhance article editor and detail components with improved link handling and UI updates
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||
import { message } from "ant-design-vue";
|
||||
import type { TableColumnsType } from "ant-design-vue";
|
||||
@@ -6,6 +7,7 @@ import type { ArticleVersion, PublishRecord } from "@geo/shared-types";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
import MarkdownPreview from "@/components/MarkdownPreview.vue";
|
||||
import {
|
||||
articlesApi,
|
||||
isGenerationStreamEnabled,
|
||||
@@ -224,23 +226,18 @@ async function refreshArticleData(): Promise<void> {
|
||||
]);
|
||||
}
|
||||
|
||||
async function copyPublishLink(record: PublishRecord): Promise<void> {
|
||||
const target = record.external_article_url || record.external_manage_url;
|
||||
if (!target) {
|
||||
message.warning(t("media.records.linkEmpty"));
|
||||
return;
|
||||
}
|
||||
await navigator.clipboard.writeText(target);
|
||||
message.success(t("media.records.copySuccess"));
|
||||
function resolvePublishLink(record: PublishRecord): string {
|
||||
return record.external_article_url || record.external_manage_url || "";
|
||||
}
|
||||
|
||||
function openPublishLink(record: PublishRecord): void {
|
||||
const target = record.external_article_url || record.external_manage_url;
|
||||
async function copyPublishLink(record: PublishRecord): Promise<void> {
|
||||
const target = resolvePublishLink(record);
|
||||
if (!target) {
|
||||
message.warning(t("media.records.linkEmpty"));
|
||||
return;
|
||||
}
|
||||
window.open(target, "_blank", "noopener,noreferrer");
|
||||
|
||||
await navigator.clipboard.writeText(target);
|
||||
message.success(t("media.records.copySuccess"));
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -292,14 +289,14 @@ function openPublishLink(record: PublishRecord): void {
|
||||
|
||||
<a-tabs v-model:activeKey="activeTab" class="article-drawer__tabs">
|
||||
<a-tab-pane key="content" :tab="t('article.preview')">
|
||||
<div v-if="displayMarkdown" class="article-drawer__content">
|
||||
<MarkdownPreview :content="displayMarkdown" />
|
||||
</div>
|
||||
<div
|
||||
v-if="detail.html_content"
|
||||
v-else-if="detail.html_content"
|
||||
class="article-drawer__content"
|
||||
v-html="detail.html_content"
|
||||
/>
|
||||
<pre v-else-if="displayMarkdown" class="article-drawer__markdown">{{
|
||||
displayMarkdown
|
||||
}}</pre>
|
||||
<a-empty v-else :description="t('article.noContent')" />
|
||||
</a-tab-pane>
|
||||
|
||||
@@ -355,26 +352,27 @@ function openPublishLink(record: PublishRecord): void {
|
||||
{{ formatDateTime(record.published_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'external_article_url'">
|
||||
<div class="article-drawer__record-actions">
|
||||
<div v-if="resolvePublishLink(record)" class="article-drawer__record-link-row">
|
||||
<a
|
||||
v-if="record.external_article_url || record.external_manage_url"
|
||||
class="article-drawer__record-link"
|
||||
:href="record.external_article_url || record.external_manage_url || '#'"
|
||||
:href="resolvePublishLink(record)"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ record.external_article_url || record.external_manage_url }}
|
||||
{{ resolvePublishLink(record) }}
|
||||
</a>
|
||||
<span v-else class="article-drawer__record-empty">--</span>
|
||||
<div class="article-drawer__record-buttons">
|
||||
<a-button size="small" type="link" @click="openPublishLink(record)">
|
||||
{{ t("media.records.open") }}
|
||||
<a-tooltip :title="t('media.records.copy')">
|
||||
<a-button
|
||||
type="text"
|
||||
size="small"
|
||||
class="article-drawer__record-copy"
|
||||
@click="copyPublishLink(record)"
|
||||
>
|
||||
<template #icon><CopyOutlined /></template>
|
||||
</a-button>
|
||||
<a-button size="small" type="link" @click="copyPublishLink(record)">
|
||||
{{ t("media.records.copy") }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<span v-else class="article-drawer__record-empty">--</span>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
@@ -433,8 +431,7 @@ function openPublishLink(record: PublishRecord): void {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.article-drawer__content,
|
||||
.article-drawer__markdown {
|
||||
.article-drawer__content {
|
||||
padding: 20px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5ecf5;
|
||||
@@ -447,13 +444,6 @@ function openPublishLink(record: PublishRecord): void {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.article-drawer__markdown {
|
||||
margin: 0;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.article-drawer__version-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -477,23 +467,30 @@ function openPublishLink(record: PublishRecord): void {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.article-drawer__record-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.article-drawer__record-link {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #1677ff;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.article-drawer__record-buttons {
|
||||
.article-drawer__record-link-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.article-drawer__record-copy.ant-btn {
|
||||
flex: none;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
.article-drawer__record-copy.ant-btn:hover:not(:disabled) {
|
||||
color: #1677ff;
|
||||
background: #e6f4ff;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
|
||||
@@ -318,6 +318,8 @@ let selectedImageLoadHandler: (() => void) | null = null;
|
||||
let aiOptimizeAbortController: AbortController | null = null;
|
||||
let aiOptimizeIgnoreNextWindowPointerDown = false;
|
||||
|
||||
const EDITOR_ACTION_MENU_DROPDOWN_SELECTOR = ".editor-action-menu__dropdown-overlay";
|
||||
|
||||
const tableContextHeaderRow = computed(() => tableContextMenu.value.rowIndex === 0);
|
||||
const aiOptimizeStreaming = computed(() => aiOptimizeStatus.value === "generating");
|
||||
const aiOptimizeHasPreview = computed(() => aiOptimizePreview.value.trim().length > 0);
|
||||
@@ -334,106 +336,135 @@ const aiOptimizeUiText = computed(() => ({
|
||||
|
||||
const tableContextMenuGroups = computed(() => [
|
||||
{
|
||||
key: "rows",
|
||||
key: "operations",
|
||||
columns: 4,
|
||||
items: [
|
||||
{
|
||||
key: "add-row-before",
|
||||
label: t("article.editor.tableMenu.addRowBefore"),
|
||||
key: "rows",
|
||||
label: "行操作",
|
||||
icon: InsertRowAboveOutlined,
|
||||
disabled: tableContextHeaderRow.value,
|
||||
children: [
|
||||
{
|
||||
key: "add-row-before",
|
||||
label: t("article.editor.tableMenu.addRowBefore"),
|
||||
icon: InsertRowAboveOutlined,
|
||||
disabled: tableContextHeaderRow.value,
|
||||
},
|
||||
{
|
||||
key: "add-row-after",
|
||||
label: t("article.editor.tableMenu.addRowAfter"),
|
||||
icon: InsertRowBelowOutlined,
|
||||
},
|
||||
{
|
||||
key: "delete-row",
|
||||
label: t("article.editor.tableMenu.deleteRow"),
|
||||
icon: DeleteOutlined,
|
||||
danger: true,
|
||||
disabled: tableContextHeaderRow.value,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "add-row-after",
|
||||
label: t("article.editor.tableMenu.addRowAfter"),
|
||||
icon: InsertRowBelowOutlined,
|
||||
key: "columns",
|
||||
label: "列操作",
|
||||
icon: InsertRowLeftOutlined,
|
||||
children: [
|
||||
{
|
||||
key: "add-col-before",
|
||||
label: t("article.editor.tableMenu.addColBefore"),
|
||||
icon: InsertRowLeftOutlined,
|
||||
},
|
||||
{
|
||||
key: "add-col-after",
|
||||
label: t("article.editor.tableMenu.addColAfter"),
|
||||
icon: InsertRowRightOutlined,
|
||||
},
|
||||
{
|
||||
key: "delete-col",
|
||||
label: t("article.editor.tableMenu.deleteCol"),
|
||||
icon: DeleteOutlined,
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "delete-row",
|
||||
label: t("article.editor.tableMenu.deleteRow"),
|
||||
icon: DeleteOutlined,
|
||||
danger: true,
|
||||
disabled: tableContextHeaderRow.value,
|
||||
key: "align",
|
||||
label: "对齐方式",
|
||||
icon: AlignCenterOutlined,
|
||||
children: [
|
||||
{
|
||||
key: "align-left",
|
||||
label: t("article.editor.tableMenu.alignLeft"),
|
||||
icon: AlignLeftOutlined,
|
||||
},
|
||||
{
|
||||
key: "align-center",
|
||||
label: t("article.editor.tableMenu.alignCenter"),
|
||||
icon: AlignCenterOutlined,
|
||||
},
|
||||
{
|
||||
key: "align-right",
|
||||
label: t("article.editor.tableMenu.alignRight"),
|
||||
icon: AlignRightOutlined,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "delete-table",
|
||||
label: t("article.editor.tableMenu.deleteTable"),
|
||||
icon: TableOutlined,
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "columns",
|
||||
columns: 6,
|
||||
items: [
|
||||
{
|
||||
key: "add-col-before",
|
||||
label: t("article.editor.tableMenu.addColBefore"),
|
||||
icon: InsertRowLeftOutlined,
|
||||
},
|
||||
{
|
||||
key: "add-col-after",
|
||||
label: t("article.editor.tableMenu.addColAfter"),
|
||||
icon: InsertRowRightOutlined,
|
||||
},
|
||||
{
|
||||
key: "delete-col",
|
||||
label: t("article.editor.tableMenu.deleteCol"),
|
||||
icon: DeleteOutlined,
|
||||
danger: true,
|
||||
},
|
||||
{
|
||||
key: "align-left",
|
||||
label: t("article.editor.tableMenu.alignLeft"),
|
||||
icon: AlignLeftOutlined,
|
||||
},
|
||||
{
|
||||
key: "align-center",
|
||||
label: t("article.editor.tableMenu.alignCenter"),
|
||||
icon: AlignCenterOutlined,
|
||||
},
|
||||
{
|
||||
key: "align-right",
|
||||
label: t("article.editor.tableMenu.alignRight"),
|
||||
icon: AlignRightOutlined,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const imageContextMenuGroups = computed(() => [
|
||||
{
|
||||
key: "image",
|
||||
columns: 3,
|
||||
key: "operations",
|
||||
columns: 4,
|
||||
items: [
|
||||
{
|
||||
key: "replace-image",
|
||||
label: t("article.editor.imageMenu.replace"),
|
||||
key: "image",
|
||||
label: "图片操作",
|
||||
icon: PictureOutlined,
|
||||
children: [
|
||||
{
|
||||
key: "replace-image",
|
||||
label: t("article.editor.imageMenu.replace"),
|
||||
icon: PictureOutlined,
|
||||
},
|
||||
{
|
||||
key: "toggle-caption",
|
||||
label: t("article.editor.imageMenu.caption"),
|
||||
icon: CodeOutlined,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "toggle-caption",
|
||||
label: t("article.editor.imageMenu.caption"),
|
||||
icon: CodeOutlined,
|
||||
},
|
||||
{
|
||||
key: "align-left",
|
||||
label: t("article.editor.imageMenu.alignLeft"),
|
||||
icon: AlignLeftOutlined,
|
||||
active: selectedImage.value.align === "left",
|
||||
},
|
||||
{
|
||||
key: "align-center",
|
||||
label: t("article.editor.imageMenu.alignCenter"),
|
||||
key: "align",
|
||||
label: "对齐方式",
|
||||
icon: AlignCenterOutlined,
|
||||
active: selectedImage.value.align === "center",
|
||||
},
|
||||
{
|
||||
key: "align-right",
|
||||
label: t("article.editor.imageMenu.alignRight"),
|
||||
icon: AlignRightOutlined,
|
||||
active: selectedImage.value.align === "right",
|
||||
children: [
|
||||
{
|
||||
key: "align-left",
|
||||
label: t("article.editor.imageMenu.alignLeft"),
|
||||
icon: AlignLeftOutlined,
|
||||
active: selectedImage.value.align === "left",
|
||||
},
|
||||
{
|
||||
key: "align-center",
|
||||
label: t("article.editor.imageMenu.alignCenter"),
|
||||
icon: AlignCenterOutlined,
|
||||
active: selectedImage.value.align === "center",
|
||||
},
|
||||
{
|
||||
key: "align-right",
|
||||
label: t("article.editor.imageMenu.alignRight"),
|
||||
icon: AlignRightOutlined,
|
||||
active: selectedImage.value.align === "right",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "reset-size",
|
||||
@@ -1224,6 +1255,10 @@ function handleWindowPointerDown(event: PointerEvent): void {
|
||||
}
|
||||
}
|
||||
|
||||
if (isEditorActionMenuDropdownTarget(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tablePickerOpen.value) {
|
||||
closeTablePicker();
|
||||
}
|
||||
@@ -1241,6 +1276,18 @@ function handleWindowPointerDown(event: PointerEvent): void {
|
||||
}
|
||||
}
|
||||
|
||||
function isEditorActionMenuDropdownTarget(target: EventTarget | null): boolean {
|
||||
if (target instanceof Element) {
|
||||
return target.closest(EDITOR_ACTION_MENU_DROPDOWN_SELECTOR) !== null;
|
||||
}
|
||||
|
||||
if (target instanceof Node) {
|
||||
return target.parentElement?.closest(EDITOR_ACTION_MENU_DROPDOWN_SELECTOR) !== null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveTableContextFromPointer(clientX: number, clientY: number): Omit<TableContextMenuState, "open" | "x" | "y"> | null {
|
||||
const editor = getEditor();
|
||||
if (!editor) {
|
||||
@@ -1870,9 +1917,7 @@ function runTableContextAction(action: TableContextMenuAction): void {
|
||||
:x="tableContextMenu.x"
|
||||
:y="tableContextMenu.y"
|
||||
:groups="tableContextMenuGroups"
|
||||
variant="tile"
|
||||
min-width="620px"
|
||||
max-width="720px"
|
||||
variant="inline"
|
||||
@select="handleTableContextMenuSelect"
|
||||
/>
|
||||
|
||||
@@ -1882,8 +1927,6 @@ function runTableContextAction(action: TableContextMenuAction): void {
|
||||
:y="imageContextMenu.y"
|
||||
:groups="imageContextMenuGroups"
|
||||
variant="inline"
|
||||
min-width="440px"
|
||||
max-width="min(520px, calc(100vw - 32px))"
|
||||
@select="handleImageContextMenuSelect"
|
||||
/>
|
||||
|
||||
|
||||
@@ -108,24 +108,36 @@ const html = computed(() => renderer.render(props.content || ""));
|
||||
|
||||
.markdown-preview :deep(table) {
|
||||
width: 100%;
|
||||
margin: 0 0 1em;
|
||||
border-collapse: collapse;
|
||||
overflow: hidden;
|
||||
margin: 1em 0;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-preview :deep(th),
|
||||
.markdown-preview :deep(td) {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
border-right: 1px solid #e5e7eb;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.markdown-preview :deep(th:last-child),
|
||||
.markdown-preview :deep(td:last-child) {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.markdown-preview :deep(tr:last-child td) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.markdown-preview :deep(th) {
|
||||
background: #f9fafb;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.markdown-preview :deep(hr) {
|
||||
|
||||
@@ -475,7 +475,11 @@ function showPublishFailures(result: PublisherPublishResponse): void {
|
||||
{{ coverRequired ? t("media.publish.messages.coverRequired") : t("media.publish.coverHint") }}
|
||||
</p>
|
||||
|
||||
<div class="publish-modal__cover-body" v-if="effectiveCoverEnabled">
|
||||
<div
|
||||
v-if="effectiveCoverEnabled"
|
||||
class="publish-modal__cover-body"
|
||||
:class="{ 'publish-modal__cover-body--single': !coverAssetUrl }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="publish-modal__cover-preview"
|
||||
@@ -490,17 +494,14 @@ function showPublishFailures(result: PublisherPublishResponse): void {
|
||||
</template>
|
||||
</button>
|
||||
|
||||
<div class="publish-modal__cover-side">
|
||||
<div v-if="coverAssetUrl" class="publish-modal__cover-side">
|
||||
<div class="publish-modal__cover-actions">
|
||||
<a-button type="primary" ghost @click="coverPickerOpen = true">
|
||||
{{ coverAssetUrl ? t("article.editor.coverReplace") : t("media.publish.coverUpload") }}
|
||||
</a-button>
|
||||
<a-button v-if="coverAssetUrl" @click="handleRemoveCover">
|
||||
<a-button @click="handleRemoveCover">
|
||||
{{ t("article.editor.coverRemove") }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div v-if="coverAssetUrl" class="publish-modal__cover-file">
|
||||
<div class="publish-modal__cover-file">
|
||||
{{ coverFileName || t("article.editor.coverSaved") }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -733,6 +734,10 @@ function showPublishFailures(result: PublisherPublishResponse): void {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.publish-modal__cover-body--single {
|
||||
grid-template-columns: 176px;
|
||||
}
|
||||
|
||||
.publish-modal__cover-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch, type Component, type CSSProperties } from "vue";
|
||||
import { DownOutlined } from "@ant-design/icons-vue";
|
||||
|
||||
type EditorActionMenuItem = {
|
||||
key: string;
|
||||
@@ -8,6 +9,7 @@ type EditorActionMenuItem = {
|
||||
danger?: boolean;
|
||||
disabled?: boolean;
|
||||
active?: boolean;
|
||||
children?: EditorActionMenuItem[];
|
||||
};
|
||||
|
||||
type EditorActionMenuGroup = {
|
||||
@@ -132,21 +134,60 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<template v-for="(group, groupIndex) in groups" :key="group.key">
|
||||
<div class="editor-action-menu__group" :style="resolveGroupStyle(group)">
|
||||
<button
|
||||
v-for="item in group.items"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="editor-action-menu__action"
|
||||
:class="{
|
||||
'editor-action-menu__action--active': item.active,
|
||||
'editor-action-menu__action--danger': item.danger,
|
||||
}"
|
||||
:disabled="item.disabled"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<component :is="item.icon" v-if="item.icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
<template v-for="item in group.items" :key="item.key">
|
||||
<a-dropdown
|
||||
v-if="item.children && item.children.length > 0"
|
||||
:trigger="['click']"
|
||||
overlay-class-name="editor-action-menu__dropdown-overlay"
|
||||
:overlay-style="{ zIndex: 2000 }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="editor-action-menu__action"
|
||||
:class="{
|
||||
'editor-action-menu__action--active': item.active,
|
||||
'editor-action-menu__action--danger': item.danger,
|
||||
}"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<component :is="item.icon" v-if="item.icon" />
|
||||
<span v-if="resolvedVariant === 'tile'">{{ item.label }}</span>
|
||||
<DownOutlined class="editor-action-menu__dropdown-icon" />
|
||||
</button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item
|
||||
v-for="child in item.children"
|
||||
:key="child.key"
|
||||
:disabled="child.disabled"
|
||||
@click="handleSelect(child)"
|
||||
>
|
||||
<span
|
||||
class="editor-action-menu__dropdown-item"
|
||||
:class="{ 'editor-action-menu__dropdown-item--danger': child.danger }"
|
||||
>
|
||||
<component :is="child.icon" v-if="child.icon" />
|
||||
<span>{{ child.label }}</span>
|
||||
</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="editor-action-menu__action"
|
||||
:class="{
|
||||
'editor-action-menu__action--active': item.active,
|
||||
'editor-action-menu__action--danger': item.danger,
|
||||
}"
|
||||
:disabled="item.disabled"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<component :is="item.icon" v-if="item.icon" />
|
||||
<span v-if="resolvedVariant === 'tile'">{{ item.label }}</span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="groupIndex < groups.length - 1" class="editor-action-menu__divider"></div>
|
||||
@@ -251,8 +292,9 @@ onBeforeUnmount(() => {
|
||||
.editor-action-menu--inline .editor-action-menu__action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
min-height: 46px;
|
||||
min-height: 36px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
background: #f7f9fc;
|
||||
@@ -296,4 +338,31 @@ onBeforeUnmount(() => {
|
||||
.editor-action-menu__action:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.editor-action-menu__dropdown-icon {
|
||||
font-size: 10px !important;
|
||||
color: #8c9eb5 !important;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.editor-action-menu__dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #3f4a5c;
|
||||
}
|
||||
|
||||
.editor-action-menu__dropdown-item--danger {
|
||||
color: #cf1322;
|
||||
}
|
||||
|
||||
.editor-action-menu__dropdown-item--danger :deep(svg) {
|
||||
color: #cf1322;
|
||||
}
|
||||
|
||||
:global(.editor-action-menu__dropdown-overlay) {
|
||||
z-index: 2000;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -284,8 +284,7 @@ onBeforeUnmount(() => {
|
||||
border-radius: 999px;
|
||||
background: #ffffff;
|
||||
box-shadow:
|
||||
0 4px 20px rgba(15, 23, 42, 0.08),
|
||||
0 0 0 1px rgba(15, 23, 42, 0.04);
|
||||
0 8px 32px rgb(17 17 17 / 28%), 0 0 0 1px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.editor-ai-assist__bar-icon {
|
||||
@@ -373,8 +372,7 @@ onBeforeUnmount(() => {
|
||||
border-radius: 16px;
|
||||
background: #ffffff;
|
||||
box-shadow:
|
||||
0 8px 32px rgba(15, 23, 42, 0.1),
|
||||
0 0 0 1px rgba(15, 23, 42, 0.05);
|
||||
0 8px 32px rgb(17 17 17 / 28%), 0 0 0 1px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.editor-ai-assist__result-box {
|
||||
|
||||
@@ -413,20 +413,6 @@ function serializePlatformSelection(platformIds: string[]): string {
|
||||
</template>
|
||||
</button>
|
||||
|
||||
<div class="article-editor-view__cover-info">
|
||||
<div class="article-editor-view__cover-actions">
|
||||
<a-button type="primary" ghost @click="coverPickerOpen = true">
|
||||
{{ coverAssetUrl ? t("article.editor.coverReplace") : t("article.editor.coverUpload") }}
|
||||
</a-button>
|
||||
<a-button v-if="coverAssetUrl" @click="handleRemoveCover">
|
||||
{{ t("article.editor.coverRemove") }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div v-if="coverAssetUrl" class="article-editor-view__cover-file">
|
||||
{{ coverFileName || t("article.editor.coverSaved") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="article-editor-view__cover-off">
|
||||
|
||||
Reference in New Issue
Block a user