feat: enhance article editor and detail components with improved link handling and UI updates
This commit is contained in:
@@ -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"
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user