alinea
Version:
Headless git-based CMS
223 lines (219 loc) • 9.73 kB
JavaScript
import {
dist_default
} from "../../chunks/chunk-A5O3N2GS.js";
import {
useAtomValue,
useSetAtom
} from "../../chunks/chunk-TOJF2G3X.js";
import "../../chunks/chunk-WJ67RR7S.js";
import "../../chunks/chunk-NZLE2WMY.js";
// src/dashboard/view/EntryEdit.tsx
import { Section } from "alinea/core/Section";
import { Type } from "alinea/core/Type";
import { TabsSection } from "alinea/field/tabs/Tabs";
import { TabsHeader } from "alinea/field/tabs/Tabs.view";
import { Button, HStack, Stack, VStack } from "alinea/ui";
import { Main } from "alinea/ui/Main";
import { Statusbar } from "alinea/ui/Statusbar";
import { Tabs } from "alinea/ui/Tabs";
import { IcRoundInsertDriveFile } from "alinea/ui/icons/IcRoundInsertDriveFile";
import { IcRoundLink } from "alinea/ui/icons/IcRoundLink";
import { IcRoundTranslate } from "alinea/ui/icons/IcRoundTranslate";
import { Suspense, useEffect, useRef, useState } from "react";
import { FormProvider } from "../atoms/FormAtoms.js";
import { useRouteBlocker } from "../atoms/RouterAtoms.js";
import { InputForm } from "../editor/InputForm.js";
import { useConfig } from "../hook/UseConfig.js";
import { useDashboard } from "../hook/UseDashboard.js";
import { EntryEditorProvider } from "../hook/UseEntryEditor.js";
import { useLocale } from "../hook/UseLocale.js";
import { useNav } from "../hook/UseNav.js";
import { SuspenseBoundary } from "../util/SuspenseBoundary.js";
import { Modal } from "../view/Modal.js";
// src/dashboard/view/EntryEdit.module.scss
var EntryEdit_module_default = {
"root": "alinea-EntryEdit",
"root-tabs": "alinea-EntryEdit-tabs",
"rootTabs": "alinea-EntryEdit-tabs"
};
// src/dashboard/view/EntryEdit.tsx
import { Preview } from "./Preview.js";
import { useSidebar } from "./Sidebar.js";
import { EntryDiff } from "./diff/EntryDiff.js";
import { EditMode } from "./entry/EditModeToggle.js";
import { EntryHeader } from "./entry/EntryHeader.js";
import { EntryHistory } from "./entry/EntryHistory.js";
import { EntryNotice } from "./entry/EntryNotice.js";
import { EntryPreview } from "./entry/EntryPreview.js";
import { EntryTitle } from "./entry/EntryTitle.js";
import { FieldToolbar } from "./entry/FieldToolbar.js";
import { BrowserPreviewMetaProvider } from "./preview/BrowserPreview.js";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var styles = dist_default(EntryEdit_module_default);
function ShowChanges({ editor }) {
const draftEntry = useAtomValue(editor.draftEntry);
const hasChanges = useAtomValue(editor.hasChanges);
const compareTo = hasChanges ? editor.activeVersion : editor.statuses[editor.availableStatuses.find((status) => status !== "draft")];
return /* @__PURE__ */ jsx(EntryDiff, { entryA: compareTo, entryB: draftEntry });
}
function EntryEdit({ editor }) {
const { alineaDev } = useDashboard();
const locale = useLocale();
const config = useConfig();
const { isPreviewOpen } = useSidebar();
const nav = useNav();
const [rootTab, setRootTab] = useState();
const mode = useAtomValue(editor.editMode);
const hasChanges = useAtomValue(editor.hasChanges);
const selectedStatus = useAtomValue(editor.selectedStatus);
const ref = useRef(null);
useEffect(() => {
ref.current?.scrollTo({ top: 0 });
}, [editor.entryId, mode, selectedStatus]);
const { isBlocking, nextRoute, confirm, cancel } = useRouteBlocker(
"Are you sure you want to discard changes?",
!editor.untranslated && hasChanges
);
const isNavigationChange = nextRoute?.data.editor?.entryId !== editor.entryId;
const form = useAtomValue(editor.form);
const saveDraft = useSetAtom(editor.saveDraft);
const publishDraft = useSetAtom(editor.publishDraft);
const publishEdits = useSetAtom(editor.publishEdits);
const discardEdits = useSetAtom(editor.discardEdits);
const showHistory = useAtomValue(editor.showHistory);
const saveTranslation = useSetAtom(editor.saveTranslation);
const previewRevision = useAtomValue(editor.previewRevision);
const preview = editor.preview;
const translate = () => saveTranslation(locale);
useEffect(() => {
function listener(e) {
const isControl = e.ctrlKey || e.metaKey;
if (isControl && e.key === "s") {
e.preventDefault();
if (previewRevision) {
alert("todo");
return;
}
if (editor.untranslated && hasChanges) {
translate();
} else if (config.enableDrafts) {
if (hasChanges) saveDraft();
else if (selectedStatus === "draft") publishDraft();
} else {
if (hasChanges) publishEdits();
}
}
}
document.addEventListener("keydown", listener);
return () => {
document.removeEventListener("keydown", listener);
};
}, [editor, hasChanges, saveDraft, config.enableDrafts]);
const sections = Type.sections(editor.type);
const hasRootTabs = sections.length === 1 && sections[0][Section.Data] instanceof TabsSection;
const tabs = hasRootTabs ? sections[0][Section.Data] : void 0;
const visibleTypes = tabs?.types.filter((type) => !Type.isHidden(type));
let selectedRootTab = 0;
if (hasRootTabs && visibleTypes && rootTab !== void 0) {
selectedRootTab = rootTab;
if (rootTab >= visibleTypes.length) selectedRootTab = 0;
}
useEffect(() => {
if (isBlocking && !isNavigationChange) confirm?.();
}, [isBlocking, isNavigationChange, confirm]);
return /* @__PURE__ */ jsxs(BrowserPreviewMetaProvider, { entryId: editor.entryId, children: [
alineaDev && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(Statusbar.Slot, { children: /* @__PURE__ */ jsxs(Statusbar.Status, { icon: IcRoundInsertDriveFile, children: [
editor.activeVersion.filePath,
" @",
" ",
editor.activeVersion.fileHash.slice(0, 8)
] }) }),
/* @__PURE__ */ jsx(Statusbar.Slot, { children: /* @__PURE__ */ jsx(Statusbar.Status, { icon: IcRoundLink, children: editor.activeVersion.url }) })
] }),
isBlocking && isNavigationChange && /* @__PURE__ */ jsx(Modal, { open: true, onClose: () => cancel(), children: /* @__PURE__ */ jsxs(VStack, { gap: 30, children: [
/* @__PURE__ */ jsxs("p", { children: [
"This document was changed,",
/* @__PURE__ */ jsx("br", {}),
"would you like to save your changes?"
] }),
/* @__PURE__ */ jsx(HStack, { as: "footer", children: /* @__PURE__ */ jsx(Stack.Right, { children: /* @__PURE__ */ jsxs(HStack, { gap: 16, children: [
/* @__PURE__ */ jsx(
Button,
{
outline: true,
type: "button",
onClick: () => {
discardEdits();
confirm();
},
children: "Discard my changes"
}
),
config.enableDrafts ? /* @__PURE__ */ jsx(
Button,
{
onClick: () => {
saveDraft();
confirm();
},
children: "Save as draft"
}
) : /* @__PURE__ */ jsx(
Button,
{
onClick: () => {
publishEdits();
confirm();
},
children: "Publish changes"
}
)
] }) }) })
] }) }),
/* @__PURE__ */ jsx(Main, { scrollRef: ref, className: styles.root(), children: /* @__PURE__ */ jsxs(FieldToolbar.Provider, { children: [
/* @__PURE__ */ jsx(EntryHeader, { editor }),
showHistory && /* @__PURE__ */ jsx(EntryHistory, { editor }),
/* @__PURE__ */ jsxs(
Tabs.Root,
{
style: { flex: 1 },
selectedIndex: selectedRootTab,
onChange: (index) => setRootTab(index),
children: [
/* @__PURE__ */ jsx(
EntryTitle,
{
editor,
backLink: editor.activeVersion.parentId ? nav.entry({
id: editor.activeVersion.parentId,
workspace: editor.activeVersion.workspace
}) : nav.entry({ id: void 0 }),
children: hasRootTabs && /* @__PURE__ */ jsx("div", { className: styles.root.tabs(), children: /* @__PURE__ */ jsx(TabsHeader, { backdrop: false, section: sections[0] }) })
}
),
/* @__PURE__ */ jsxs(Main.Container, { children: [
editor.untranslated && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
EntryNotice,
{
icon: IcRoundTranslate,
title: "Untranslated",
variant: "untranslated",
children: editor.parentNeedsTranslation ? "Translate the parent page first." : "Enter the details below and save to start translating."
}
) }),
/* @__PURE__ */ jsx(EntryEditorProvider, { editor, children: /* @__PURE__ */ jsx(SuspenseBoundary, { name: "input form", children: mode === EditMode.Diff ? /* @__PURE__ */ jsx(ShowChanges, { editor }) : hasRootTabs && visibleTypes ? /* @__PURE__ */ jsx(Tabs.Panels, { children: visibleTypes.map((type, i) => {
return /* @__PURE__ */ jsx(FormProvider, { form, children: /* @__PURE__ */ jsx(Tabs.Panel, { unmount: false, tabIndex: i, children: /* @__PURE__ */ jsx(InputForm, { type }) }) }, i);
}) }) : /* @__PURE__ */ jsx(VStack, { gap: 18, children: /* @__PURE__ */ jsx(InputForm, { form }) }) }) })
] })
]
}
),
/* @__PURE__ */ jsx(FieldToolbar.Root, {})
] }) }),
preview && /* @__PURE__ */ jsx(Preview, { children: /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(EntryPreview, { preview, editor }) }) })
] });
}
export {
EntryEdit
};