alinea
Version:
Headless git-based CMS
275 lines (271 loc) • 9.5 kB
JavaScript
import {
dist_default
} from "../../../chunks/chunk-A5O3N2GS.js";
import {
useAtomValue
} from "../../../chunks/chunk-TOJF2G3X.js";
import "../../../chunks/chunk-WJ67RR7S.js";
import {
useQuery
} from "../../../chunks/chunk-YWCPLD22.js";
import "../../../chunks/chunk-NZLE2WMY.js";
// src/dashboard/view/entry/NewEntry.tsx
import { Entry } from "alinea/core/Entry";
import { createId } from "alinea/core/Id";
import { Reference } from "alinea/core/Reference";
import { Schema } from "alinea/core/Schema";
import { track } from "alinea/core/Tracker";
import { Type, type } from "alinea/core/Type";
import { entries, fromEntries, keys } from "alinea/core/util/Objects";
import { slugify } from "alinea/core/util/Slugs";
import { useForm } from "alinea/dashboard/atoms/FormAtoms";
import { InputForm } from "alinea/dashboard/editor/InputForm";
import { useLocation, useNavigate } from "alinea/dashboard/util/HashRouter";
import { Modal } from "alinea/dashboard/view/Modal";
import { EntryLink, entry } from "alinea/field/link";
import { select } from "alinea/field/select";
import { text } from "alinea/field/text";
import { entryPicker } from "alinea/picker/entry/EntryPicker";
import { EntryReference } from "alinea/picker/entry/EntryReference";
import { parents } from "alinea/query";
import { Button, Loader } from "alinea/ui";
import { Link } from "alinea/ui/Link";
import { Suspense, useEffect, useMemo, useState } from "react";
import { useConfig } from "../../hook/UseConfig.js";
import { useDb } from "../../hook/UseDb.js";
import { useLocale } from "../../hook/UseLocale.js";
import { useNav } from "../../hook/UseNav.js";
import { useRoot } from "../../hook/UseRoot.js";
import { useWorkspace } from "../../hook/UseWorkspace.js";
// src/dashboard/view/entry/NewEntry.module.scss
var NewEntry_module_default = {
"root": "alinea-NewEntry",
"root-header": "alinea-NewEntry-header",
"rootHeader": "alinea-NewEntry-header",
"root-footer": "alinea-NewEntry-footer",
"rootFooter": "alinea-NewEntry-footer",
"root-footer-link": "alinea-NewEntry-footer-link",
"rootFooterLink": "alinea-NewEntry-footer-link",
"form": "alinea-NewEntry-form",
"is-loading": "alinea-NewEntry-is-loading",
"isLoading": "alinea-NewEntry-is-loading"
};
// src/dashboard/view/entry/NewEntry.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var styles = dist_default(NewEntry_module_default);
var parentData = {
id: Entry.id,
type: Entry.type,
path: Entry.path,
url: Entry.url,
level: Entry.level,
parent: Entry.parentId,
parentPaths: parents({
select: Entry.path
})
};
var titleField = text("Title", { autoFocus: true });
function NewEntryForm({ parentId }) {
const config = useConfig();
const locale = useLocale();
const db = useDb();
const { data: requestedParent } = useQuery(
["parent-req", parentId],
async () => {
return parentId ? db.first({
select: parentData,
id: parentId,
locale,
status: "preferDraft"
}) : null;
},
{ suspense: true, keepPreviousData: true, staleTime: 0 }
);
const preselectedId = requestedParent && (Type.isContainer(config.schema[requestedParent.type]) ? requestedParent.id : requestedParent.parent);
const { pathname } = useLocation();
const nav = useNav();
const navigate = useNavigate();
const { name: workspace } = useWorkspace();
const containerTypes = entries(config.schema).filter(([, type2]) => {
return Type.isContainer(type2);
}).map((pair) => pair[0]);
const root = useRoot();
const parentField = useMemo(() => {
return entry("Parent", {
location: { workspace, root: root.name },
condition: { _type: { in: containerTypes } },
enableNavigation: true,
initialValue: preselectedId ? {
[Reference.id]: "parent",
[Reference.type]: "entry",
[EntryReference.entry]: preselectedId
} : void 0
});
}, []);
async function allowedTypes(parentId2) {
if (!parentId2) {
return root.contains ? Schema.contained(config.schema, root.contains) : keys(config.schema);
}
const parent = parentId2 ? await db.get({
select: parentData,
id: parentId2,
status: "preferDraft"
}) : null;
const parentType = parent && config.schema[parent.type];
if (parentType)
return Schema.contained(config.schema, Type.contains(parentType));
return keys(config.schema);
}
const typeField = useMemo(() => {
const typeField2 = select("Select type", {
options: {}
});
return track.options(typeField2, async (get) => {
const selectedParent2 = get(parentField);
const parentId2 = selectedParent2?.[EntryReference.entry];
const types = await allowedTypes(parentId2);
return {
options: fromEntries(
types.map((key) => {
return [key, config.schema[key]];
}).filter((row) => row[1]).map(([key, type2]) => {
return [key, Type.label(type2) || key];
})
)
};
});
}, []);
const insertOrderField = useMemo(() => {
const insertOrderField2 = select(
"Insert order",
{
initialValue: "last",
options: {
first: "At the top of the list",
last: "At the bottom of the list"
}
}
);
return track.options(insertOrderField2, async (get) => {
const selectedParent2 = get(parentField);
const parentId2 = selectedParent2?.[EntryReference.entry];
const parent = await db.first({
select: {
type: Entry.type
},
id: parentId2,
status: "preferDraft"
});
const parentType = parent && config.schema[parent.type];
const parentInsertOrder = parentType && Type.insertOrder(parentType);
return {
hidden: parentInsertOrder !== "free"
};
});
}, []);
const copyFromField = useMemo(() => {
const copyFromField2 = entry("Copy content from");
return track.options(copyFromField2, (get) => {
const type2 = get(typeField);
return {
readOnly: !type2,
pickers: {
entry: entryPicker({
condition: { _type: type2 },
title: "Copy content from",
max: 1,
selection: EntryLink
})
}
};
});
}, []);
const [isCreating, setIsCreating] = useState(false);
const formType = useMemo(
() => type("New entry", {
fields: {
parent: parentField,
title: titleField,
type: typeField,
order: insertOrderField,
copyFrom: copyFromField
}
}),
[]
);
const form = useForm(formType);
const parentAtoms = form.fieldInfo(parentField);
const typeAtoms = form.fieldInfo(typeField);
const copyFromAtoms = form.fieldInfo(copyFromField);
const selectedType = useAtomValue(typeAtoms.value);
const selectedParent = useAtomValue(parentAtoms.value);
useEffect(() => {
allowedTypes(selectedParent?.[EntryReference.entry]).then((types) => {
if (types.length > 0) typeAtoms.mutator(types[0]);
});
}, [selectedParent]);
useEffect(() => {
copyFromAtoms.mutator.replace(void 0);
}, [selectedType]);
async function handleCreate(e) {
e.preventDefault();
const { title, type: selected } = form.data();
if (isCreating || !selected || !title) return;
setIsCreating(true);
const path = slugify(title);
const id = createId();
const parentId2 = form.data().parent?.[EntryReference.entry];
const entryType = config.schema[selected];
const copyFrom = form.data().copyFrom?.[EntryReference.entry];
const entryData = copyFrom ? await db.first({
select: Entry.data,
id: copyFrom,
locale,
status: "preferPublished"
}) : Type.initialValue(entryType);
const parent = parentId2 ? await db.first({ id: parentId2 }) : void 0;
const parentType = parent && config.schema[parent._type];
const parentInsertOrder = parentType && Type.insertOrder(parentType);
return db.create({
type: entryType,
id,
insertOrder: !parentInsertOrder || parentInsertOrder === "free" ? form.data().order : parentInsertOrder,
parentId: parentId2,
locale,
root: root.name,
workspace,
status: config.enableDrafts ? "draft" : "published",
set: { ...entryData, title, path }
}).then((entry2) => {
navigate(nav.entry({ id: entry2._id }));
}).finally(() => {
setIsCreating(false);
});
}
return /* @__PURE__ */ jsxs(
"form",
{
onSubmit: handleCreate,
className: styles.form({ loading: isCreating }),
children: [
isCreating && /* @__PURE__ */ jsx(Loader, { absolute: true }),
/* @__PURE__ */ jsx(InputForm, { border: false, form }),
/* @__PURE__ */ jsxs("div", { className: styles.root.footer(), children: [
/* @__PURE__ */ jsx(Link, { href: pathname, className: styles.root.footer.link(), children: "Cancel" }),
/* @__PURE__ */ jsx(Button, { children: "Create" })
] })
]
}
);
}
function NewEntry({ parentId }) {
const navigate = useNavigate();
const { pathname } = useLocation();
function handleClose() {
navigate(pathname);
}
return /* @__PURE__ */ jsx(Modal, { open: true, onClose: handleClose, className: styles.root(), children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Loader, {}), children: /* @__PURE__ */ jsx(NewEntryForm, { parentId }) }) });
}
export {
NewEntry
};