alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
241 lines (237 loc) • 7.97 kB
JavaScript
import {
useAtomValue,
useSetAtom
} from "../../../chunks/chunk-WF77DMLN.js";
import "../../../chunks/chunk-OBOPLPUQ.js";
import {
useQuery
} from "../../../chunks/chunk-DJKGEOOC.js";
import "../../../chunks/chunk-U5RRZUYZ.js";
// src/dashboard/view/entry/NewEntry.tsx
import {
Entry,
EntryPhase,
Type,
createId,
slugify,
track,
type
} from "alinea/core";
import {
entryChildrenDir,
entryFileName,
entryFilepath,
entryUrl
} from "alinea/core/EntryFilenames";
import { MutationType } from "alinea/core/Mutation";
import { createEntryRow } from "alinea/core/util/EntryRows";
import { generateKeyBetween } from "alinea/core/util/FractionalIndexing";
import { entries, fromEntries, keys } from "alinea/core/util/Objects";
import { dirname } from "alinea/core/util/Paths";
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 { link } from "alinea/input/link";
import { select } from "alinea/input/select";
import { text } from "alinea/input/text";
import { Button, Loader, fromModule } from "alinea/ui";
import { Link } from "alinea/ui/Link";
import { Suspense, useMemo, useState } from "react";
import { changedEntriesAtom, graphAtom, useMutate } from "../../atoms/DbAtoms.js";
import { useConfig } from "../../hook/UseConfig.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 = fromModule(NewEntry_module_default);
var parentData = {
id: Entry.entryId,
i18nId: Entry.i18nId,
type: Entry.type,
path: Entry.path,
url: Entry.url,
level: Entry.level,
parent: Entry.parent,
parentPaths({ parents }) {
return parents().select(Entry.path);
},
childrenIndex({ children }) {
return children().select(Entry.index).orderBy(Entry.index.asc()).first();
}
};
var titleField = text("Title", { autoFocus: true });
function NewEntryForm({ parentId }) {
const config = useConfig();
const graph = useAtomValue(graphAtom);
const { data: requestedParent } = useQuery(
["parent-req", parentId],
async () => {
return graph.preferDraft.get(
Entry({ entryId: parentId }).select(parentData)
);
},
{ 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 locale = useLocale();
const mutate = useMutate();
const { name: workspace } = useWorkspace();
const containerTypes = entries(config.schema).filter(([, type2]) => {
return Type.meta(type2).isContainer;
}).map((pair) => pair[0]);
const root = useRoot();
const parentField = useMemo(
() => link.entry("Parent", {
condition: Entry.type.isIn(containerTypes).and(Entry.workspace.is(workspace)).and(Entry.root.is(root.name)),
initialValue: preselectedId ? {
id: "parent",
ref: "entry",
type: "entry",
entry: preselectedId
} : void 0
}),
[]
);
const typeField = useMemo(() => {
const result = select("Select type", {});
track.options(result, async (get) => {
const types = [];
const selectedParent = get(parentField);
const parentId2 = selectedParent?.entry;
if (!parentId2) {
types.push(...root.contains ?? []);
} else {
const parent = await graph.preferDraft.get(
Entry({ entryId: parentId2 }).select(parentData)
);
const parentType = parent && config.schema[parent.type];
types.push(
...parentType && Type.meta(parentType).contains || keys(config.schema)
);
}
return {
items: fromEntries(
types.map((key) => {
return [key, config.schema[key]];
}).filter((row) => row[1]).map(([key, type2]) => {
return [key, Type.label(type2) || key];
})
)
};
});
return result;
}, []);
const [isCreating, setIsCreating] = useState(false);
const updateEntries = useSetAtom(changedEntriesAtom);
const formType = useMemo(
() => type({
parent: parentField,
title: titleField,
type: typeField
}),
[]
);
const form = useForm(formType);
async function handleCreate(e) {
e.preventDefault();
const { title, type: selected } = form.data();
if (!selected || !title)
return;
setIsCreating(true);
const path = slugify(title);
const entryId = createId();
const data = {
workspace,
root: root.name,
locale: locale ?? null,
path,
phase: config.enableDrafts ? EntryPhase.Draft : EntryPhase.Published
};
const parent = await graph.preferDraft.get(
Entry({ entryId: parentId }).select(parentData)
);
const parentPaths = parent ? parent.parentPaths.concat(parent.path) : [];
const filePath = entryFilepath(config, data, parentPaths);
const childrenDir = entryChildrenDir(config, data, parentPaths);
const parentDir = dirname(filePath);
const entryType = config.schema[selected];
const url = entryUrl(entryType, { ...data, parentPaths });
const entry = await createEntryRow(config, {
entryId,
...data,
filePath,
type: selected,
path,
title,
url,
index: generateKeyBetween(null, parent?.childrenIndex || null),
parent: parent?.id ?? null,
seeded: false,
level: parent ? parent.level + 1 : 0,
parentDir,
childrenDir,
i18nId: root.i18n ? createId() : entryId,
modifiedAt: Date.now(),
active: true,
main: false,
data: { title, path },
searchableText: ""
});
return mutate({
type: MutationType.Create,
entryId: entry.entryId,
entry,
file: entryFileName(config, data, parentPaths)
}).then(() => {
setIsCreating(false);
navigate(nav.entry({ entryId: entry.i18nId }));
if (parent)
updateEntries([parent.i18nId]);
});
}
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
};