2022-09-08 08:49:42 +00:00
|
|
|
<script lang="ts" setup>
|
|
|
|
import {
|
|
|
|
VPageHeader,
|
|
|
|
IconPages,
|
2022-11-10 16:24:10 +00:00
|
|
|
IconSettings,
|
|
|
|
IconSendPlaneFill,
|
2022-09-08 08:49:42 +00:00
|
|
|
VSpace,
|
|
|
|
VButton,
|
|
|
|
IconSave,
|
2022-11-18 13:16:23 +00:00
|
|
|
Toast,
|
2022-12-22 04:14:29 +00:00
|
|
|
Dialog,
|
2023-05-25 14:54:18 +00:00
|
|
|
IconEye,
|
2022-09-08 08:49:42 +00:00
|
|
|
} from "@halo-dev/components";
|
|
|
|
import SinglePageSettingModal from "./components/SinglePageSettingModal.vue";
|
2022-11-10 16:24:10 +00:00
|
|
|
import type { SinglePage, SinglePageRequest } from "@halo-dev/api-client";
|
2022-12-22 04:14:29 +00:00
|
|
|
import {
|
|
|
|
computed,
|
|
|
|
nextTick,
|
|
|
|
onMounted,
|
|
|
|
provide,
|
|
|
|
ref,
|
|
|
|
toRef,
|
|
|
|
type ComputedRef,
|
|
|
|
} from "vue";
|
2022-09-22 08:46:32 +00:00
|
|
|
import { apiClient } from "@/utils/api-client";
|
2022-09-08 08:49:42 +00:00
|
|
|
import { useRouteQuery } from "@vueuse/router";
|
2023-12-28 09:13:38 +00:00
|
|
|
import { cloneDeep } from "lodash-es";
|
2022-11-10 16:24:10 +00:00
|
|
|
import { useRouter } from "vue-router";
|
2022-11-18 06:00:23 +00:00
|
|
|
import { randomUUID } from "@/utils/id";
|
2023-11-09 06:56:06 +00:00
|
|
|
import { useContentCache } from "@console/composables/use-content-cache";
|
2023-11-30 03:55:29 +00:00
|
|
|
import { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
|
2023-08-25 07:28:11 +00:00
|
|
|
import type { EditorProvider } from "@halo-dev/console-shared";
|
2022-12-29 13:46:34 +00:00
|
|
|
import { useLocalStorage } from "@vueuse/core";
|
|
|
|
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
|
2023-03-23 08:54:33 +00:00
|
|
|
import { useI18n } from "vue-i18n";
|
2023-05-25 14:54:18 +00:00
|
|
|
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
2023-07-18 08:16:02 +00:00
|
|
|
import { contentAnnotations } from "@/constants/annotations";
|
|
|
|
import { usePageUpdateMutate } from "./composables/use-page-update-mutate";
|
2023-11-09 06:56:06 +00:00
|
|
|
import { useAutoSaveContent } from "@console/composables/use-auto-save-content";
|
|
|
|
import { useContentSnapshot } from "@console/composables/use-content-snapshot";
|
|
|
|
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
2023-11-30 04:10:08 +00:00
|
|
|
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
2023-12-01 02:14:09 +00:00
|
|
|
import { usePermission } from "@/utils/permission";
|
2022-11-10 16:24:10 +00:00
|
|
|
|
|
|
|
const router = useRouter();
|
2023-03-23 08:54:33 +00:00
|
|
|
const { t } = useI18n();
|
2023-07-18 08:16:02 +00:00
|
|
|
const { mutateAsync: singlePageUpdateMutate } = usePageUpdateMutate();
|
2023-12-01 02:14:09 +00:00
|
|
|
const { currentUserHasPermission } = usePermission();
|
2022-09-08 08:49:42 +00:00
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// Editor providers
|
2022-12-22 04:14:29 +00:00
|
|
|
const { editorProviders } = useEditorExtensionPoints();
|
|
|
|
const currentEditorProvider = ref<EditorProvider>();
|
2022-12-29 13:46:34 +00:00
|
|
|
const storedEditorProviderName = useLocalStorage("editor-provider-name", "");
|
|
|
|
|
2023-07-18 08:16:02 +00:00
|
|
|
const handleChangeEditorProvider = async (provider: EditorProvider) => {
|
2022-12-29 13:46:34 +00:00
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
storedEditorProviderName.value = provider.name;
|
|
|
|
formState.value.page.metadata.annotations = {
|
2023-07-18 08:16:02 +00:00
|
|
|
...formState.value.page.metadata.annotations,
|
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-29 13:46:34 +00:00
|
|
|
};
|
2023-03-15 03:12:26 +00:00
|
|
|
formState.value.content.rawType = provider.rawType;
|
2023-07-18 08:16:02 +00:00
|
|
|
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
const { data } = await singlePageUpdateMutate(formState.value.page);
|
|
|
|
formState.value.page = data;
|
|
|
|
}
|
2022-12-29 13:46:34 +00:00
|
|
|
};
|
2022-12-22 04:14:29 +00:00
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// SinglePage form
|
2022-09-08 08:49:42 +00:00
|
|
|
const initialFormState: SinglePageRequest = {
|
|
|
|
page: {
|
|
|
|
spec: {
|
|
|
|
title: "",
|
|
|
|
slug: "",
|
|
|
|
template: "",
|
|
|
|
cover: "",
|
|
|
|
deleted: false,
|
2022-11-10 16:24:10 +00:00
|
|
|
publish: false,
|
2023-04-03 03:12:14 +00:00
|
|
|
publishTime: undefined,
|
2022-09-08 08:49:42 +00:00
|
|
|
pinned: false,
|
|
|
|
allowComment: true,
|
|
|
|
visible: "PUBLIC",
|
|
|
|
priority: 0,
|
|
|
|
excerpt: {
|
|
|
|
autoGenerate: true,
|
|
|
|
raw: "",
|
|
|
|
},
|
|
|
|
htmlMetas: [],
|
|
|
|
},
|
|
|
|
apiVersion: "content.halo.run/v1alpha1",
|
|
|
|
kind: "SinglePage",
|
|
|
|
metadata: {
|
2022-11-18 06:00:23 +00:00
|
|
|
name: randomUUID(),
|
2022-12-22 04:14:29 +00:00
|
|
|
annotations: {},
|
2022-09-08 08:49:42 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
content: {
|
|
|
|
raw: "",
|
|
|
|
content: "",
|
|
|
|
rawType: "HTML",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const formState = ref<SinglePageRequest>(cloneDeep(initialFormState));
|
|
|
|
const saving = ref(false);
|
2022-11-10 16:24:10 +00:00
|
|
|
const publishing = ref(false);
|
2022-09-08 08:49:42 +00:00
|
|
|
const settingModal = ref(false);
|
|
|
|
|
|
|
|
const isUpdateMode = computed(() => {
|
|
|
|
return !!formState.value.page.metadata.creationTimestamp;
|
|
|
|
});
|
|
|
|
|
2022-12-22 04:14:29 +00:00
|
|
|
// provide some data to editor
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"owner",
|
|
|
|
computed(() => formState.value.page.spec.owner)
|
|
|
|
);
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"publishTime",
|
|
|
|
computed(() => formState.value.page.spec.publishTime)
|
|
|
|
);
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"permalink",
|
|
|
|
computed(() => formState.value.page.status?.permalink)
|
|
|
|
);
|
|
|
|
|
2022-09-08 08:49:42 +00:00
|
|
|
const routeQueryName = useRouteQuery<string>("name");
|
|
|
|
|
2023-05-25 14:54:18 +00:00
|
|
|
const handleSave = async (options?: { mute?: boolean }) => {
|
2022-09-08 08:49:42 +00:00
|
|
|
try {
|
2023-05-25 14:54:18 +00:00
|
|
|
if (!options?.mute) {
|
|
|
|
saving.value = true;
|
|
|
|
}
|
2022-09-08 08:49:42 +00:00
|
|
|
|
|
|
|
//Set default title and slug
|
|
|
|
if (!formState.value.page.spec.title) {
|
2023-03-23 08:54:33 +00:00
|
|
|
formState.value.page.spec.title = t("core.page_editor.untitled");
|
2022-09-08 08:49:42 +00:00
|
|
|
}
|
|
|
|
if (!formState.value.page.spec.slug) {
|
2022-11-18 06:00:23 +00:00
|
|
|
formState.value.page.spec.slug = new Date().getTime().toString();
|
2022-09-08 08:49:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isUpdateMode.value) {
|
2022-11-18 13:16:23 +00:00
|
|
|
const { data } = await apiClient.singlePage.updateSinglePageContent({
|
2022-09-08 08:49:42 +00:00
|
|
|
name: formState.value.page.metadata.name,
|
2022-11-18 13:16:23 +00:00
|
|
|
content: formState.value.content,
|
2022-09-08 08:49:42 +00:00
|
|
|
});
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2022-09-08 08:49:42 +00:00
|
|
|
formState.value.page = data;
|
|
|
|
} else {
|
2023-08-25 16:18:16 +00:00
|
|
|
// Clear new page content cache
|
|
|
|
handleClearCache();
|
2022-09-09 03:10:20 +00:00
|
|
|
const { data } = await apiClient.singlePage.draftSinglePage({
|
2022-09-08 08:49:42 +00:00
|
|
|
singlePageRequest: formState.value,
|
|
|
|
});
|
|
|
|
formState.value.page = data;
|
|
|
|
routeQueryName.value = data.metadata.name;
|
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2023-05-25 14:54:18 +00:00
|
|
|
if (!options?.mute) {
|
|
|
|
Toast.success(t("core.common.toast.save_success"));
|
|
|
|
}
|
2022-11-18 13:16:23 +00:00
|
|
|
|
2023-08-25 16:18:16 +00:00
|
|
|
handleClearCache(formState.value.page.metadata.name as string);
|
2022-09-08 08:49:42 +00:00
|
|
|
await handleFetchContent();
|
2023-08-25 16:18:16 +00:00
|
|
|
await handleFetchSnapshot();
|
2022-09-08 08:49:42 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error("Failed to save single page", error);
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
2022-09-08 08:49:42 +00:00
|
|
|
} finally {
|
|
|
|
saving.value = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-11-21 07:14:28 +00:00
|
|
|
const returnToView = useRouteQuery<string>("returnToView");
|
|
|
|
|
2022-11-10 16:24:10 +00:00
|
|
|
const handlePublish = async () => {
|
|
|
|
try {
|
|
|
|
publishing.value = true;
|
|
|
|
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
const { name: singlePageName } = formState.value.page.metadata;
|
2022-11-21 07:14:28 +00:00
|
|
|
const { permalink } = formState.value.page.status || {};
|
2022-11-18 13:16:23 +00:00
|
|
|
|
|
|
|
await apiClient.singlePage.updateSinglePageContent({
|
|
|
|
name: singlePageName,
|
|
|
|
content: formState.value.content,
|
|
|
|
});
|
|
|
|
|
|
|
|
await apiClient.singlePage.publishSinglePage({
|
|
|
|
name: singlePageName,
|
|
|
|
});
|
2022-11-21 07:14:28 +00:00
|
|
|
|
|
|
|
if (returnToView.value && permalink) {
|
|
|
|
window.location.href = permalink;
|
|
|
|
} else {
|
2023-07-19 11:46:17 +00:00
|
|
|
router.back();
|
2022-11-21 07:14:28 +00:00
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
} else {
|
|
|
|
formState.value.page.spec.publish = true;
|
|
|
|
await apiClient.singlePage.draftSinglePage({
|
|
|
|
singlePageRequest: formState.value,
|
|
|
|
});
|
2023-07-28 03:09:09 +00:00
|
|
|
|
|
|
|
// Clear new page content cache
|
|
|
|
handleClearCache();
|
|
|
|
|
2022-11-24 14:59:06 +00:00
|
|
|
router.push({ name: "SinglePages" });
|
2022-11-10 16:24:10 +00:00
|
|
|
}
|
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.common.toast.publish_success"));
|
2022-11-30 07:21:47 +00:00
|
|
|
handleClearCache(routeQueryName.value as string);
|
2022-11-10 16:24:10 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error("Failed to publish single page", error);
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.error(t("core.common.toast.publish_failed_and_retry"));
|
2022-11-10 16:24:10 +00:00
|
|
|
} finally {
|
|
|
|
publishing.value = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handlePublishClick = () => {
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
handlePublish();
|
|
|
|
} else {
|
|
|
|
settingModal.value = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-09-08 08:49:42 +00:00
|
|
|
const handleFetchContent = async () => {
|
|
|
|
if (!formState.value.page.spec.headSnapshot) {
|
|
|
|
return;
|
|
|
|
}
|
2023-01-31 02:52:09 +00:00
|
|
|
const { data } = await apiClient.singlePage.fetchSinglePageHeadContent({
|
|
|
|
name: formState.value.page.metadata.name,
|
2022-09-08 08:49:42 +00:00
|
|
|
});
|
|
|
|
|
2023-03-08 02:50:11 +00:00
|
|
|
formState.value.content = Object.assign(formState.value.content, data);
|
|
|
|
|
2022-12-22 04:14:29 +00:00
|
|
|
// get editor provider
|
|
|
|
if (!currentEditorProvider.value) {
|
|
|
|
const preferredEditor = editorProviders.value.find(
|
|
|
|
(provider) =>
|
|
|
|
provider.name ===
|
|
|
|
formState.value.page.metadata.annotations?.[
|
2023-07-18 08:16:02 +00:00
|
|
|
contentAnnotations.PREFERRED_EDITOR
|
2022-12-22 04:14:29 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
const provider =
|
|
|
|
preferredEditor ||
|
|
|
|
editorProviders.value.find(
|
|
|
|
(provider) => provider.rawType === data.rawType
|
|
|
|
);
|
|
|
|
if (provider) {
|
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
formState.value.page.metadata.annotations = {
|
|
|
|
...formState.value.page.metadata.annotations,
|
2023-07-18 08:16:02 +00:00
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-22 04:14:29 +00:00
|
|
|
};
|
2022-12-29 13:42:34 +00:00
|
|
|
|
2023-07-18 08:16:02 +00:00
|
|
|
const { data } = await singlePageUpdateMutate(formState.value.page);
|
2022-12-29 13:42:34 +00:00
|
|
|
|
|
|
|
formState.value.page = data;
|
2022-12-22 04:14:29 +00:00
|
|
|
} else {
|
|
|
|
Dialog.warning({
|
2023-03-23 08:54:33 +00:00
|
|
|
title: t("core.common.dialog.titles.warning"),
|
|
|
|
description: t("core.common.dialog.descriptions.editor_not_found", {
|
|
|
|
raw_type: data.rawType,
|
|
|
|
}),
|
|
|
|
confirmText: t("core.common.buttons.confirm"),
|
2023-07-26 06:42:19 +00:00
|
|
|
showCancel: false,
|
2022-12-22 04:14:29 +00:00
|
|
|
onConfirm: () => {
|
|
|
|
router.back();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
await nextTick();
|
|
|
|
}
|
2022-09-08 08:49:42 +00:00
|
|
|
};
|
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// SinglePage settings
|
2022-11-10 16:24:10 +00:00
|
|
|
const handleOpenSettingModal = async () => {
|
|
|
|
const { data: latestSinglePage } =
|
|
|
|
await apiClient.extension.singlePage.getcontentHaloRunV1alpha1SinglePage({
|
|
|
|
name: formState.value.page.metadata.name,
|
|
|
|
});
|
|
|
|
formState.value.page = latestSinglePage;
|
|
|
|
settingModal.value = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
const onSettingSaved = (page: SinglePage) => {
|
2022-09-08 08:49:42 +00:00
|
|
|
// Set route query parameter
|
|
|
|
if (!isUpdateMode.value) {
|
2022-11-10 16:24:10 +00:00
|
|
|
routeQueryName.value = page.metadata.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
formState.value.page = page;
|
|
|
|
settingModal.value = false;
|
|
|
|
|
|
|
|
if (!isUpdateMode.value) {
|
|
|
|
handleSave();
|
2022-09-08 08:49:42 +00:00
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
};
|
2022-09-08 08:49:42 +00:00
|
|
|
|
2022-11-10 16:24:10 +00:00
|
|
|
const onSettingPublished = (singlePage: SinglePage) => {
|
|
|
|
formState.value.page = singlePage;
|
2022-09-08 08:49:42 +00:00
|
|
|
settingModal.value = false;
|
2022-11-10 16:24:10 +00:00
|
|
|
handlePublish();
|
2022-09-08 08:49:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
if (routeQueryName.value) {
|
|
|
|
const { data: singlePage } =
|
|
|
|
await apiClient.extension.singlePage.getcontentHaloRunV1alpha1SinglePage({
|
|
|
|
name: routeQueryName.value,
|
|
|
|
});
|
|
|
|
formState.value.page = singlePage;
|
|
|
|
|
|
|
|
// fetch single page content
|
|
|
|
await handleFetchContent();
|
2022-12-22 04:14:29 +00:00
|
|
|
} else {
|
|
|
|
// Set default editor
|
|
|
|
const provider =
|
|
|
|
editorProviders.value.find(
|
2022-12-29 13:46:34 +00:00
|
|
|
(provider) => provider.name === storedEditorProviderName.value
|
2022-12-22 04:14:29 +00:00
|
|
|
) || editorProviders.value[0];
|
|
|
|
if (provider) {
|
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
formState.value.content.rawType = provider.rawType;
|
|
|
|
}
|
|
|
|
formState.value.page.metadata.annotations = {
|
2023-07-18 08:16:02 +00:00
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-22 04:14:29 +00:00
|
|
|
};
|
2022-09-08 08:49:42 +00:00
|
|
|
}
|
2022-12-22 04:14:29 +00:00
|
|
|
|
2022-11-30 07:21:47 +00:00
|
|
|
handleResetCache();
|
2022-09-08 08:49:42 +00:00
|
|
|
});
|
2022-11-30 07:21:47 +00:00
|
|
|
|
2023-08-25 16:18:16 +00:00
|
|
|
const headSnapshot = computed(() => {
|
|
|
|
return formState.value.page.spec.headSnapshot;
|
|
|
|
});
|
|
|
|
|
|
|
|
const { version, handleFetchSnapshot } = useContentSnapshot(headSnapshot);
|
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// SinglePage content cache
|
2023-08-25 16:18:16 +00:00
|
|
|
const {
|
|
|
|
currentCache,
|
|
|
|
handleSetContentCache,
|
|
|
|
handleResetCache,
|
|
|
|
handleClearCache,
|
|
|
|
} = useContentCache(
|
|
|
|
"singlePage-content-cache",
|
|
|
|
routeQueryName,
|
|
|
|
toRef(formState.value.content, "raw"),
|
|
|
|
version
|
|
|
|
);
|
|
|
|
|
|
|
|
useAutoSaveContent(currentCache, toRef(formState.value.content, "raw"), () => {
|
2023-09-07 07:20:10 +00:00
|
|
|
// Do not save when the setting modal is open
|
|
|
|
if (settingModal.value) {
|
|
|
|
return;
|
|
|
|
}
|
2023-08-25 16:18:16 +00:00
|
|
|
handleSave({ mute: true });
|
|
|
|
});
|
2023-05-25 14:54:18 +00:00
|
|
|
|
|
|
|
// SinglePage preview
|
|
|
|
const previewModal = ref(false);
|
|
|
|
const previewPending = ref(false);
|
|
|
|
|
|
|
|
const handlePreview = async () => {
|
|
|
|
previewPending.value = true;
|
|
|
|
await handleSave({ mute: true });
|
|
|
|
previewModal.value = true;
|
|
|
|
previewPending.value = false;
|
|
|
|
};
|
2023-09-01 02:30:12 +00:00
|
|
|
|
|
|
|
useSaveKeybinding(handleSave);
|
2023-11-30 03:55:29 +00:00
|
|
|
|
2023-11-30 04:10:08 +00:00
|
|
|
// Keep session alive
|
|
|
|
useSessionKeepAlive();
|
|
|
|
|
2023-11-30 03:55:29 +00:00
|
|
|
// Upload image
|
|
|
|
async function handleUploadImage(file: File) {
|
2023-12-01 02:14:09 +00:00
|
|
|
if (!currentUserHasPermission(["uc:attachments:manage"])) {
|
|
|
|
return;
|
|
|
|
}
|
2023-11-30 03:55:29 +00:00
|
|
|
if (!isUpdateMode.value) {
|
|
|
|
await handleSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
const { data } = await apiClient.uc.attachment.createAttachmentForPost({
|
|
|
|
file,
|
|
|
|
singlePageName: formState.value.page.metadata.name,
|
|
|
|
waitForPermalink: true,
|
|
|
|
});
|
|
|
|
return data;
|
|
|
|
}
|
2022-09-08 08:49:42 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<SinglePageSettingModal
|
|
|
|
v-model:visible="settingModal"
|
2022-11-10 16:24:10 +00:00
|
|
|
:single-page="formState.page"
|
|
|
|
:publish-support="!isUpdateMode"
|
|
|
|
:only-emit="!isUpdateMode"
|
2022-09-08 08:49:42 +00:00
|
|
|
@saved="onSettingSaved"
|
2022-11-10 16:24:10 +00:00
|
|
|
@published="onSettingPublished"
|
2022-09-08 08:49:42 +00:00
|
|
|
/>
|
2023-05-25 14:54:18 +00:00
|
|
|
|
|
|
|
<UrlPreviewModal
|
|
|
|
v-if="isUpdateMode"
|
|
|
|
v-model:visible="previewModal"
|
|
|
|
:title="formState.page.spec.title"
|
|
|
|
:url="`/preview/singlepages/${formState.page.metadata.name}`"
|
|
|
|
/>
|
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
<VPageHeader :title="$t('core.page.title')">
|
2022-09-08 08:49:42 +00:00
|
|
|
<template #icon>
|
|
|
|
<IconPages class="mr-2 self-center" />
|
|
|
|
</template>
|
|
|
|
<template #actions>
|
|
|
|
<VSpace>
|
2022-12-29 13:46:34 +00:00
|
|
|
<EditorProviderSelector
|
2023-07-18 08:16:02 +00:00
|
|
|
v-if="editorProviders.length > 1"
|
2022-12-29 13:46:34 +00:00
|
|
|
:provider="currentEditorProvider"
|
2023-07-18 08:16:02 +00:00
|
|
|
:allow-forced-select="!isUpdateMode"
|
2022-12-29 13:46:34 +00:00
|
|
|
@select="handleChangeEditorProvider"
|
|
|
|
/>
|
2023-05-25 14:54:18 +00:00
|
|
|
<VButton
|
|
|
|
size="sm"
|
|
|
|
type="default"
|
|
|
|
:loading="previewPending"
|
|
|
|
@click="handlePreview"
|
|
|
|
>
|
|
|
|
<template #icon>
|
|
|
|
<IconEye class="h-full w-full" />
|
|
|
|
</template>
|
|
|
|
{{ $t("core.common.buttons.preview") }}
|
|
|
|
</VButton>
|
2022-09-08 08:49:42 +00:00
|
|
|
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
|
2022-11-10 16:24:10 +00:00
|
|
|
<template #icon>
|
|
|
|
<IconSave class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.save") }}
|
2022-09-08 08:49:42 +00:00
|
|
|
</VButton>
|
2022-11-10 16:24:10 +00:00
|
|
|
<VButton
|
|
|
|
v-if="isUpdateMode"
|
|
|
|
size="sm"
|
|
|
|
type="default"
|
|
|
|
@click="handleOpenSettingModal"
|
|
|
|
>
|
|
|
|
<template #icon>
|
|
|
|
<IconSettings class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.setting") }}
|
2022-11-10 16:24:10 +00:00
|
|
|
</VButton>
|
|
|
|
<VButton
|
|
|
|
type="secondary"
|
|
|
|
:loading="publishing"
|
|
|
|
@click="handlePublishClick"
|
|
|
|
>
|
2022-09-08 08:49:42 +00:00
|
|
|
<template #icon>
|
2022-11-10 16:24:10 +00:00
|
|
|
<IconSendPlaneFill class="h-full w-full" />
|
2022-09-08 08:49:42 +00:00
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.publish") }}
|
2022-09-08 08:49:42 +00:00
|
|
|
</VButton>
|
|
|
|
</VSpace>
|
|
|
|
</template>
|
|
|
|
</VPageHeader>
|
|
|
|
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">
|
2022-12-22 04:14:29 +00:00
|
|
|
<component
|
|
|
|
:is="currentEditorProvider.component"
|
|
|
|
v-if="currentEditorProvider"
|
|
|
|
v-model:raw="formState.content.raw"
|
|
|
|
v-model:content="formState.content.content"
|
2023-11-30 03:55:29 +00:00
|
|
|
:upload-image="handleUploadImage"
|
2022-12-22 04:14:29 +00:00
|
|
|
class="h-full"
|
2022-11-30 07:21:47 +00:00
|
|
|
@update="handleSetContentCache"
|
2022-11-10 06:50:09 +00:00
|
|
|
/>
|
2022-09-08 08:49:42 +00:00
|
|
|
</div>
|
|
|
|
</template>
|