Improve editor + added imports
This commit is contained in:
parent
509cbdba9b
commit
4f807c410b
|
@ -4,6 +4,7 @@ MONGODB_PORT=27017
|
|||
PAYLOAD_URI=https://payload.domain.com
|
||||
PAYLOAD_SECRET=payloadsecreta5e6ea45ef4e66eaa151612bdcb599df
|
||||
PAYLOAD_PORT=3000
|
||||
RECORDER_DEFAULT_PASSWORD=somepassword
|
||||
|
||||
STRAPI_URI=https://strapi.domain.com
|
||||
STRAPI_TOKEN=strapisecreta5e6ea45ef4e66eaa151612bdcb599df
|
||||
|
|
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
|
@ -22,27 +22,28 @@
|
|||
"start": "sudo docker compose up"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/vollkorn": "^5.0.14",
|
||||
"@payloadcms/bundler-webpack": "^1.0.3",
|
||||
"@payloadcms/db-mongodb": "^1.0.3",
|
||||
"@payloadcms/richtext-lexical": "^0.1.8",
|
||||
"@fontsource/vollkorn": "^5.0.17",
|
||||
"@payloadcms/bundler-webpack": "^1.0.4",
|
||||
"@payloadcms/db-mongodb": "^1.0.4",
|
||||
"@payloadcms/richtext-lexical": "^0.1.15",
|
||||
"clean-deep": "^3.4.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"language-tags": "^1.0.9",
|
||||
"luxon": "^3.4.3",
|
||||
"payload": "^2.0.5",
|
||||
"styled-components": "^6.0.9"
|
||||
"payload": "^2.0.12",
|
||||
"styled-components": "^6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dotenv": "^8.2.0",
|
||||
"@types/express": "^4.17.18",
|
||||
"@types/language-tags": "^1.0.2",
|
||||
"@types/luxon": "^3.3.2",
|
||||
"@types/qs": "^6.9.8",
|
||||
"@types/express": "^4.17.20",
|
||||
"@types/language-tags": "^1.0.3",
|
||||
"@types/luxon": "^3.3.3",
|
||||
"@types/qs": "^6.9.9",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/styled-components": "^5.1.28",
|
||||
"@types/styled-components": "^5.1.29",
|
||||
"copyfiles": "^2.4.1",
|
||||
"nodemon": "^3.0.1",
|
||||
"npm-check-updates": "^16.14.6",
|
||||
"prettier": "^3.0.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"ts-unused-exports": "^10.0.1",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Block } from "payload/types";
|
||||
import { createEditor } from "../utils/editor";
|
||||
|
||||
export const cueBlock: Block = {
|
||||
slug: "cueBlock",
|
||||
|
@ -8,12 +9,12 @@ export const cueBlock: Block = {
|
|||
{
|
||||
name: "content",
|
||||
label: false,
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
required: true,
|
||||
admin: {
|
||||
description:
|
||||
"Parenthesis will automatically be added around cues. You don't have to include them here.",
|
||||
className: "reduced-margins",
|
||||
},
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
import { Block } from "payload/types";
|
||||
import { createEditor } from "../utils/editor";
|
||||
|
||||
export const lineBlock: Block = {
|
||||
slug: "lineBlock",
|
||||
|
@ -10,6 +11,10 @@ export const lineBlock: Block = {
|
|||
label: false,
|
||||
type: "richText",
|
||||
required: true,
|
||||
admin: {
|
||||
className: "reduced-margins",
|
||||
},
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import { Block } from "payload/types";
|
||||
import { createEditor } from "../utils/editor";
|
||||
import { transcriptBlock } from "./transcriptBlock";
|
||||
|
||||
const generateRecursiveSectionBlock = (depth = 1, maxDepth = 5): Block => ({
|
||||
slug: "sectionBlock",
|
||||
interfaceName: "SectionBlock",
|
||||
labels: { singular: "Section", plural: "Sections" },
|
||||
fields: [
|
||||
{
|
||||
name: "lines",
|
||||
type: "richText",
|
||||
label: false,
|
||||
required: true,
|
||||
editor: createEditor({
|
||||
images: true,
|
||||
inlines: true,
|
||||
lists: true,
|
||||
links: true,
|
||||
relations: true,
|
||||
alignment: true,
|
||||
blocks: [
|
||||
transcriptBlock,
|
||||
...(depth < maxDepth ? [generateRecursiveSectionBlock(depth + 1, maxDepth)] : []),
|
||||
],
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const sectionBlock: Block = generateRecursiveSectionBlock();
|
|
@ -1,6 +1,6 @@
|
|||
import { Block } from "payload/types";
|
||||
import { lineBlock } from "./lineBlock";
|
||||
import { cueBlock } from "./cueBlock";
|
||||
import { lineBlock } from "./lineBlock";
|
||||
|
||||
export const transcriptBlock: Block = {
|
||||
slug: "transcriptBlock",
|
||||
|
@ -12,7 +12,7 @@ export const transcriptBlock: Block = {
|
|||
type: "blocks",
|
||||
required: true,
|
||||
minRows: 1,
|
||||
admin: { initCollapsed: true },
|
||||
admin: { initCollapsed: true, className: "no-label" },
|
||||
blocks: [lineBlock, cueBlock],
|
||||
},
|
||||
],
|
|
@ -5,6 +5,7 @@ import { backPropagationField } from "../../fields/backPropagationField/backProp
|
|||
import { slugField } from "../../fields/slugField/slugField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { buildCollectionConfig } from "../../utils/collectionConfig";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
|
||||
import { importFromStrapi } from "./endpoints/importFromStrapi";
|
||||
import { beforeValidateEndingGreaterThanStarting } from "./hooks/beforeValidateEndingGreaterThanStarting";
|
||||
|
@ -68,7 +69,8 @@ export const ChronologyEras: CollectionConfig = buildCollectionConfig({
|
|||
{ name: fields.translationsTitle, type: "text", required: true },
|
||||
{
|
||||
name: fields.translationsDescription,
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
} from "../../components/QuickFilters";
|
||||
import { CollectionGroups, Collections } from "../../constants";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||
import { importFromStrapi } from "./endpoints/importFromStrapi";
|
||||
import { beforeValidatePopulateNameField } from "./hooks/beforeValidatePopulateNameField";
|
||||
|
@ -127,9 +128,14 @@ export const ChronologyItems: CollectionConfig = buildVersionedCollectionConfig(
|
|||
{
|
||||
name: fields.eventsTranslationsDescription,
|
||||
validate: validateEventsTranslationsDescription,
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
{
|
||||
name: fields.eventsTranslationsNotes,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
{ name: fields.eventsTranslationsNotes, type: "textarea" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { sectionBlock } from "../../blocks/sectionBlock";
|
||||
import { transcriptBlock } from "../../blocks/transcriptBlock";
|
||||
import { CollectionGroups, Collections, FileTypes, KeysTypes } from "../../constants";
|
||||
import { fileField } from "../../fields/fileField/fileField";
|
||||
import { imageField } from "../../fields/imageField/imageField";
|
||||
|
@ -8,7 +10,9 @@ import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo";
|
|||
import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping";
|
||||
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
|
||||
import { isDefined } from "../../utils/asserts";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||
import { importFromStrapi } from "./endpoints/importFromStrapi";
|
||||
|
||||
const fields = {
|
||||
slug: "slug",
|
||||
|
@ -61,6 +65,7 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
},
|
||||
preview: (doc) => `https://accords-library.com/contents/${doc.slug}`,
|
||||
},
|
||||
endpoints: [importFromStrapi],
|
||||
fields: [
|
||||
{
|
||||
type: "row",
|
||||
|
@ -103,7 +108,11 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
{ name: fields.subtitle, type: "text" },
|
||||
],
|
||||
},
|
||||
{ name: fields.summary, type: "textarea" },
|
||||
{
|
||||
name: fields.summary,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
{
|
||||
type: "tabs",
|
||||
admin: {
|
||||
|
@ -114,7 +123,20 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
{
|
||||
label: "Text",
|
||||
fields: [
|
||||
{ name: fields.textContent, type: "richText" },
|
||||
{
|
||||
name: fields.textContent,
|
||||
type: "richText",
|
||||
label: false,
|
||||
editor: createEditor({
|
||||
blocks: [sectionBlock, transcriptBlock],
|
||||
images: true,
|
||||
inlines: true,
|
||||
lists: true,
|
||||
links: true,
|
||||
relations: true,
|
||||
alignment: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
type: "row",
|
||||
fields: [
|
||||
|
@ -155,7 +177,8 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
{
|
||||
name: fields.textNotes,
|
||||
label: "Notes",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -173,7 +196,8 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
{
|
||||
name: fields.videoNotes,
|
||||
label: "Notes",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
|
@ -194,7 +218,8 @@ export const Contents = buildVersionedCollectionConfig({
|
|||
{
|
||||
name: fields.audioNotes,
|
||||
label: "Notes",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
import type { MarkOptional } from "ts-essentials";
|
||||
import { Collections } from "../../../constants";
|
||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||
import { Content } from "../../../types/collections";
|
||||
import { StrapiImage, StrapiLanguage, StrapiRecorders } from "../../../types/strapi";
|
||||
import { isNotEmpty, isUndefined } from "../../../utils/asserts";
|
||||
import {
|
||||
findCategory,
|
||||
findContentType,
|
||||
findRecorder,
|
||||
uploadStrapiImage,
|
||||
} from "../../../utils/localApi";
|
||||
import { plainTextToLexical } from "../../../utils/string";
|
||||
|
||||
type StrapiContent = {
|
||||
slug: string;
|
||||
categories: { data?: { attributes: { slug: string } }[] };
|
||||
type: { data?: { attributes: { slug: string } } };
|
||||
thumbnail: StrapiImage;
|
||||
translations: {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
pre_title?: string;
|
||||
description?: string;
|
||||
language: StrapiLanguage;
|
||||
text_set?: {
|
||||
text: string;
|
||||
notes?: string;
|
||||
source_language: StrapiLanguage;
|
||||
transcribers: StrapiRecorders;
|
||||
translators: StrapiRecorders;
|
||||
proofreaders: StrapiRecorders;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
|
||||
export const importFromStrapi = createStrapiImportEndpoint<StrapiContent>({
|
||||
strapi: {
|
||||
collection: "contents",
|
||||
params: {
|
||||
populate: [
|
||||
"type",
|
||||
"categories",
|
||||
"thumbnail",
|
||||
"translations",
|
||||
"translations.language",
|
||||
"translations.text_set",
|
||||
"translations.text_set.source_language",
|
||||
"translations.text_set.transcribers",
|
||||
"translations.text_set.translators",
|
||||
"translations.text_set.proofreaders",
|
||||
],
|
||||
},
|
||||
},
|
||||
payload: {
|
||||
collection: Collections.Contents,
|
||||
convert: async ({ slug, categories, type, thumbnail, translations }) => {
|
||||
const thumbnailId = await uploadStrapiImage({
|
||||
collection: Collections.ContentsThumbnails,
|
||||
image: thumbnail,
|
||||
});
|
||||
|
||||
const data: MarkOptional<Content, "createdAt" | "id" | "updatedAt" | "updatedBy"> = {
|
||||
slug,
|
||||
categories:
|
||||
categories.data &&
|
||||
(await Promise.all(
|
||||
categories.data.map(async (category) => await findCategory(category.attributes.slug))
|
||||
)),
|
||||
type: type.data && (await findContentType(type.data?.attributes.slug)),
|
||||
thumbnail: thumbnailId,
|
||||
translations: await Promise.all(
|
||||
translations.map(
|
||||
async ({ language, title, description, pre_title, subtitle, text_set }) => {
|
||||
if (isUndefined(language.data))
|
||||
throw new Error("A language is required for a content translation");
|
||||
if (isUndefined(text_set))
|
||||
throw new Error("Only content with text_set are supported");
|
||||
if (isUndefined(text_set.source_language.data))
|
||||
throw new Error("A language is required for a content translation text_set");
|
||||
return {
|
||||
language: language.data.attributes.code,
|
||||
sourceLanguage: text_set.source_language.data.attributes.code,
|
||||
title,
|
||||
pretitle: pre_title,
|
||||
subtitle,
|
||||
summary: isNotEmpty(description) ? plainTextToLexical(description) : undefined,
|
||||
textContent: plainTextToLexical(text_set.text),
|
||||
textNotes: isNotEmpty(text_set.notes)
|
||||
? plainTextToLexical(text_set.notes)
|
||||
: undefined,
|
||||
textTranscribers:
|
||||
text_set.transcribers.data &&
|
||||
(await Promise.all(
|
||||
text_set.transcribers.data?.map(async (recorder) =>
|
||||
findRecorder(recorder.attributes.username)
|
||||
)
|
||||
)),
|
||||
textTranslators:
|
||||
text_set.translators.data &&
|
||||
(await Promise.all(
|
||||
text_set.translators.data?.map(async (recorder) =>
|
||||
findRecorder(recorder.attributes.username)
|
||||
)
|
||||
)),
|
||||
textProofreaders:
|
||||
text_set.proofreaders.data &&
|
||||
(await Promise.all(
|
||||
text_set.proofreaders.data?.map(async (recorder) =>
|
||||
findRecorder(recorder.attributes.username)
|
||||
)
|
||||
)),
|
||||
};
|
||||
}
|
||||
)
|
||||
),
|
||||
};
|
||||
return data;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -2,6 +2,7 @@ import { CollectionGroups, Collections } from "../../constants";
|
|||
import { slugField } from "../../fields/slugField/slugField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { buildCollectionConfig } from "../../utils/collectionConfig";
|
||||
import { importFromStrapi } from "./endpoints/importFromStrapi";
|
||||
|
||||
const fields = {
|
||||
slug: "slug",
|
||||
|
@ -24,13 +25,13 @@ export const ContentsFolders = buildCollectionConfig({
|
|||
disableDuplicate: true,
|
||||
group: CollectionGroups.Collections,
|
||||
},
|
||||
endpoints: [importFromStrapi],
|
||||
timestamps: false,
|
||||
versions: false,
|
||||
fields: [
|
||||
slugField({ name: fields.slug }),
|
||||
translatedFields({
|
||||
name: fields.translations,
|
||||
interfaceName: "ContentFoldersTranslation",
|
||||
admin: {
|
||||
useAsTitle: fields.name,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
import payload from "payload";
|
||||
import QueryString from "qs";
|
||||
import { Collections } from "../../../constants";
|
||||
import { CollectionEndpoint } from "../../../types/payload";
|
||||
import { StrapiLanguage } from "../../../types/strapi";
|
||||
import { isUndefined } from "../../../utils/asserts";
|
||||
|
||||
type StrapiContentsFolder = {
|
||||
id: string;
|
||||
attributes: {
|
||||
slug: string;
|
||||
titles?: { title: string; language: StrapiLanguage }[];
|
||||
subfolders: { data: StrapiContentsFolder[] };
|
||||
contents: { data: { id: number }[] };
|
||||
};
|
||||
};
|
||||
|
||||
const getStrapiContentFolder = async (id: number): Promise<StrapiContentsFolder> => {
|
||||
const paramsWithPagination = QueryString.stringify({
|
||||
populate: [
|
||||
"subfolders",
|
||||
"subfolders.contents",
|
||||
"subfolders.titles",
|
||||
"subfolders.titles.language",
|
||||
"subfolders.subfolders",
|
||||
"subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.titles.language",
|
||||
"subfolders.subfolders.subfolders",
|
||||
"subfolders.subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.subfolders.titles.language",
|
||||
"subfolders.subfolders.subfolders.subfolders",
|
||||
"subfolders.subfolders.subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.subfolders.subfolders.titles.language",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.titles.language",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles.language",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.contents",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles",
|
||||
"subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles.language",
|
||||
],
|
||||
});
|
||||
const uri = `${process.env.STRAPI_URI}/api/contents-folders/${id}?${paramsWithPagination}`;
|
||||
const fetchResult = await fetch(uri, {
|
||||
method: "get",
|
||||
headers: { authorization: `Bearer ${process.env.STRAPI_TOKEN}` },
|
||||
});
|
||||
const { data } = await fetchResult.json();
|
||||
return data;
|
||||
};
|
||||
|
||||
export const importFromStrapi: CollectionEndpoint = {
|
||||
method: "post",
|
||||
path: "/strapi",
|
||||
handler: async (req, res) => {
|
||||
if (!req.user) {
|
||||
return res.status(403).send({
|
||||
errors: [
|
||||
{
|
||||
message: "You are not allowed to perform this action.",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
let foldersCreated = 0;
|
||||
|
||||
const createContentFolder = async (data: StrapiContentsFolder): Promise<string> => {
|
||||
const subfolders = await Promise.all(
|
||||
data.attributes.subfolders.data.map(createContentFolder)
|
||||
);
|
||||
const { slug, titles } = data.attributes;
|
||||
const result = await payload.create({
|
||||
collection: Collections.ContentsFolders,
|
||||
data: {
|
||||
slug,
|
||||
subfolders,
|
||||
translations: titles?.map(({ title, language }) => {
|
||||
if (isUndefined(language.data))
|
||||
throw new Error("A language is required for a content folder translation");
|
||||
return { language: language.data.attributes.code, name: title };
|
||||
}),
|
||||
},
|
||||
user: req.user,
|
||||
});
|
||||
foldersCreated++;
|
||||
return result.id;
|
||||
};
|
||||
|
||||
const rootFolder = await getStrapiContentFolder(72);
|
||||
try {
|
||||
await createContentFolder(rootFolder);
|
||||
} catch (e) {
|
||||
res.status(500).json({ message: "Something went wrong", error: e });
|
||||
}
|
||||
|
||||
res.status(200).json({ message: `${foldersCreated} entries have been added successfully.` });
|
||||
},
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
import { CollectionGroups, Collections } from "../../constants";
|
||||
import { slugField } from "../../fields/slugField/slugField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { buildCollectionConfig } from "../../utils/collectionConfig";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
|
||||
const fields = {
|
||||
slug: "slug",
|
||||
translations: "translations",
|
||||
name: "name",
|
||||
description: "description",
|
||||
subfolders: "subfolders",
|
||||
items: "items",
|
||||
} as const satisfies Record<string, string>;
|
||||
|
||||
export const LibraryFolders = buildCollectionConfig({
|
||||
slug: Collections.LibraryFolders,
|
||||
labels: {
|
||||
singular: "Library Folder",
|
||||
plural: "Library Folders",
|
||||
},
|
||||
defaultSort: fields.slug,
|
||||
admin: {
|
||||
useAsTitle: fields.slug,
|
||||
defaultColumns: [fields.slug, fields.translations],
|
||||
disableDuplicate: true,
|
||||
group: CollectionGroups.Collections,
|
||||
},
|
||||
timestamps: false,
|
||||
versions: false,
|
||||
fields: [
|
||||
slugField({ name: fields.slug }),
|
||||
translatedFields({
|
||||
name: fields.translations,
|
||||
admin: {
|
||||
useAsTitle: fields.name,
|
||||
},
|
||||
fields: [
|
||||
{ name: fields.name, type: "text", required: true },
|
||||
{
|
||||
name: fields.description,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
type: "row",
|
||||
fields: [
|
||||
{
|
||||
type: "relationship",
|
||||
name: fields.subfolders,
|
||||
relationTo: Collections.LibraryFolders,
|
||||
hasMany: true,
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
{
|
||||
type: "relationship",
|
||||
name: fields.items,
|
||||
relationTo: Collections.LibraryItems,
|
||||
hasMany: true,
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
|
@ -19,6 +19,7 @@ import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping";
|
|||
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
|
||||
import { LibraryItem } from "../../types/collections";
|
||||
import { isDefined } from "../../utils/asserts";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||
import { RowLabel } from "./components/RowLabel";
|
||||
|
||||
|
@ -144,6 +145,9 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
},
|
||||
preview: (doc) => `https://accords-library.com/library/${doc.slug}`,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: "row",
|
||||
fields: [
|
||||
{
|
||||
name: fields.itemType,
|
||||
|
@ -154,8 +158,22 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
})),
|
||||
admin: {
|
||||
layout: "horizontal",
|
||||
width: "0%",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: fields.digital,
|
||||
type: "checkbox",
|
||||
required: true,
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description:
|
||||
"The item is the digital version of another item, or the item is sold only digitally.",
|
||||
width: "0%",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "tabs",
|
||||
admin: {
|
||||
|
@ -209,27 +227,6 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
width: "0%",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: fields.digital,
|
||||
type: "checkbox",
|
||||
required: true,
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description:
|
||||
"The item is the digital version of another item, or the item is sold only digitally.",
|
||||
width: "0%",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: fields.downloadable,
|
||||
type: "checkbox",
|
||||
required: true,
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: "Are the scans available for download?",
|
||||
width: "0%",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -505,6 +502,16 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: fields.downloadable,
|
||||
type: "checkbox",
|
||||
required: true,
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: "Are the scans available for download?",
|
||||
width: "0%",
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
@ -559,6 +566,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
})
|
||||
),
|
||||
admin: {
|
||||
condition: (data: Partial<LibraryItem>) => !data.digital,
|
||||
layout: "horizontal",
|
||||
width: "0%",
|
||||
},
|
||||
|
@ -654,11 +662,18 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
name: fields.translations,
|
||||
label: "Descriptions",
|
||||
admin: { initCollapsed: true, useAsTitle: fields.translationsDescription },
|
||||
fields: [{ name: fields.translationsDescription, type: "textarea", required: true }],
|
||||
fields: [
|
||||
{
|
||||
name: fields.translationsDescription,
|
||||
required: true,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
}),
|
||||
optionalGroupField({
|
||||
name: fields.size,
|
||||
admin: { condition: (data) => !data.digital },
|
||||
admin: { condition: (data: Partial<LibraryItem>) => !data.digital },
|
||||
fields: [
|
||||
{
|
||||
type: "row",
|
||||
|
@ -763,7 +778,8 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
|||
},
|
||||
{
|
||||
name: fields.contentsNote,
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
admin: {
|
||||
condition: ({ itemType }) =>
|
||||
itemType === LibraryItemsTypes.Game || itemType === LibraryItemsTypes.Other,
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { CollectionConfig } from "payload/types";
|
||||
import { Collections } from "../../constants";
|
||||
import { buildCollectionConfig } from "../../utils/collectionConfig";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
|
||||
export const Notes: CollectionConfig = buildCollectionConfig({
|
||||
slug: Collections.Notes,
|
||||
labels: { singular: "Note", plural: "Notes" },
|
||||
admin: {
|
||||
// TODO: Reenable when we can use rich text as titles useAsTitle: fields.biography,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "note",
|
||||
type: "richText",
|
||||
required: true,
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
});
|
|
@ -7,6 +7,7 @@ import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo";
|
|||
import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping";
|
||||
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
|
||||
import { isDefined, isUndefined } from "../../utils/asserts";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||
|
||||
const fields = {
|
||||
|
@ -97,7 +98,11 @@ export const Posts = buildVersionedCollectionConfig({
|
|||
minRows: 1,
|
||||
fields: [
|
||||
{ name: fields.title, type: "text", required: true },
|
||||
{ name: fields.summary, type: "textarea" },
|
||||
{
|
||||
name: fields.summary,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
{
|
||||
type: "row",
|
||||
fields: [
|
||||
|
|
|
@ -6,6 +6,7 @@ import { CollectionGroups, Collections, RecordersRoles } from "../../constants";
|
|||
import { imageField } from "../../fields/imageField/imageField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { buildCollectionConfig } from "../../utils/collectionConfig";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { importFromStrapi } from "./endpoints/importFromStrapi";
|
||||
import { beforeLoginMustHaveAtLeastOneRole } from "./hooks/beforeLoginMustHaveAtLeastOneRole";
|
||||
|
||||
|
@ -107,11 +108,18 @@ export const Recorders = buildCollectionConfig({
|
|||
name: fields.biographies,
|
||||
interfaceName: "RecorderBiographies",
|
||||
admin: {
|
||||
useAsTitle: fields.biography,
|
||||
// TODO: Reenable when we can use rich text as titles useAsTitle: fields.biography,
|
||||
description:
|
||||
"A short personal description about you or your involvement with this project or the franchise",
|
||||
},
|
||||
fields: [{ name: fields.biography, required: true, type: "textarea" }],
|
||||
fields: [
|
||||
{
|
||||
name: fields.biography,
|
||||
required: true,
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true, lists: true, links: true }),
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
name: fields.role,
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Recorder } from "../../../types/collections";
|
|||
import { StrapiImage, StrapiLanguage } from "../../../types/strapi";
|
||||
import { isDefined, isUndefined } from "../../../utils/asserts";
|
||||
import { uploadStrapiImage } from "../../../utils/localApi";
|
||||
import { plainTextToLexical } from "../../../utils/string";
|
||||
|
||||
type StrapiRecorder = {
|
||||
username: string;
|
||||
|
@ -19,7 +20,7 @@ export const importFromStrapi = createStrapiImportEndpoint<StrapiRecorder>({
|
|||
strapi: {
|
||||
collection: "recorders",
|
||||
params: {
|
||||
populate: "bio.language,languages,avatar",
|
||||
populate: ["bio.language", "languages", "avatar"],
|
||||
},
|
||||
},
|
||||
payload: {
|
||||
|
@ -52,7 +53,7 @@ export const importFromStrapi = createStrapiImportEndpoint<StrapiRecorder>({
|
|||
if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography");
|
||||
return {
|
||||
language: language.data.attributes.code,
|
||||
biography: bio,
|
||||
biography: plainTextToLexical(bio),
|
||||
};
|
||||
}),
|
||||
},
|
||||
|
@ -72,10 +73,9 @@ export const importFromStrapi = createStrapiImportEndpoint<StrapiRecorder>({
|
|||
if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography");
|
||||
return {
|
||||
language: language.data.attributes.code,
|
||||
biography: bio,
|
||||
biography: plainTextToLexical(bio),
|
||||
};
|
||||
}),
|
||||
|
||||
email: `${anonymous_code}@accords-library.com`,
|
||||
password: process.env.RECORDER_DEFAULT_PASSWORD,
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@ import { imageField } from "../../fields/imageField/imageField";
|
|||
import { keysField } from "../../fields/keysField/keysField";
|
||||
import { slugField } from "../../fields/slugField/slugField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||
import { AppearanceRowLabel } from "./components/AppearanceRowLabel";
|
||||
import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint";
|
||||
|
@ -113,7 +114,8 @@ export const Weapons = buildVersionedCollectionConfig({
|
|||
},
|
||||
{
|
||||
name: fields.appearancesTranslationsDescription,
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
|
@ -124,13 +126,15 @@ export const Weapons = buildVersionedCollectionConfig({
|
|||
{
|
||||
name: fields.appearancesTranslationsLevel1,
|
||||
label: "Level 1",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
{
|
||||
name: fields.appearancesTranslationsLevel2,
|
||||
label: "Level 2",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
|
@ -141,13 +145,15 @@ export const Weapons = buildVersionedCollectionConfig({
|
|||
{
|
||||
name: fields.appearancesTranslationsLevel3,
|
||||
label: "Level 3",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
{
|
||||
name: fields.appearancesTranslationsLevel4,
|
||||
label: "Level 4",
|
||||
type: "textarea",
|
||||
type: "richText",
|
||||
editor: createEditor({ inlines: true }),
|
||||
admin: { width: "0%" },
|
||||
},
|
||||
],
|
||||
|
|
|
@ -8,10 +8,12 @@ export enum Collections {
|
|||
Files = "files",
|
||||
Keys = "keys",
|
||||
Languages = "languages",
|
||||
LibraryFolders = "library-folders",
|
||||
LibraryItems = "library-items",
|
||||
LibraryItemsThumbnails = "library-items-thumbnails",
|
||||
LibraryItemsScans = "library-items-scans",
|
||||
LibraryItemsGallery = "library-items-gallery",
|
||||
Notes = "Notes",
|
||||
Posts = "posts",
|
||||
PostsThumbnails = "posts-thumbnails",
|
||||
Recorders = "recorders",
|
||||
|
|
|
@ -43,7 +43,7 @@ type Params<S> = {
|
|||
convert?: (
|
||||
strapiObject: S,
|
||||
user: any
|
||||
) => Parameters<BasePayload<GeneratedTypes>["create"]>[0]["data"];
|
||||
) => Promise<Parameters<BasePayload<GeneratedTypes>["create"]>[0]["data"]>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -64,7 +64,7 @@ export const importStrapiEntries = async <S>({
|
|||
} else if (isDefined(payloadParams.convert)) {
|
||||
await payload.create({
|
||||
collection: payloadParams.collection,
|
||||
data: payloadParams.convert(attributes, user),
|
||||
data: await payloadParams.convert(attributes, user),
|
||||
user,
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -28,7 +28,7 @@ const languageField: Field = {
|
|||
type: "relationship",
|
||||
relationTo: Collections.Languages,
|
||||
required: true,
|
||||
admin: { allowCreate: false, width: "0%" },
|
||||
admin: { allowCreate: false },
|
||||
};
|
||||
|
||||
const sourceLanguageField: Field = {
|
||||
|
@ -36,7 +36,7 @@ const sourceLanguageField: Field = {
|
|||
type: "relationship",
|
||||
relationTo: Collections.Languages,
|
||||
required: true,
|
||||
admin: { allowCreate: false, width: "0%" },
|
||||
admin: { allowCreate: false },
|
||||
};
|
||||
|
||||
const creditFields: Field = {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { webpackBundler } from "@payloadcms/bundler-webpack";
|
||||
import { mongooseAdapter } from "@payloadcms/db-mongodb";
|
||||
import { BlocksFeature, lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||
import path from "path";
|
||||
import { buildConfig } from "payload/config";
|
||||
import { ChronologyEras } from "./collections/ChronologyEras/ChronologyEras";
|
||||
import { ChronologyItems } from "./collections/ChronologyItems/ChronologyItems";
|
||||
import { transcriptBlock } from "./collections/Contents/Blocks/transcriptBlock";
|
||||
import { Contents } from "./collections/Contents/Contents";
|
||||
import { ContentsFolders } from "./collections/ContentsFolders/ContentsFolders";
|
||||
import { ContentsThumbnails } from "./collections/ContentsThumbnails/ContentsThumbnails";
|
||||
|
@ -13,10 +11,12 @@ import { Currencies } from "./collections/Currencies/Currencies";
|
|||
import { Files } from "./collections/Files/Files";
|
||||
import { Keys } from "./collections/Keys/Keys";
|
||||
import { Languages } from "./collections/Languages/Languages";
|
||||
import { LibraryFolders } from "./collections/LibraryFolders/LibraryFolders";
|
||||
import { LibraryItems } from "./collections/LibraryItems/LibraryItems";
|
||||
import { LibraryItemsGallery } from "./collections/LibraryItemsGallery/LibraryItemsGallery";
|
||||
import { LibraryItemsScans } from "./collections/LibraryItemsScans/LibraryItemsScans";
|
||||
import { LibraryItemsThumbnails } from "./collections/LibraryItemsThumbnails/LibraryItemsThumbnails";
|
||||
import { Notes } from "./collections/Notes/Notes";
|
||||
import { Posts } from "./collections/Posts/Posts";
|
||||
import { PostsThumbnails } from "./collections/PostsThumbnails/PostsThumbnails";
|
||||
import { Recorders } from "./collections/Recorders/Recorders";
|
||||
|
@ -29,6 +29,7 @@ import { WeaponsThumbnails } from "./collections/WeaponsThumbnails/WeaponsThumbn
|
|||
import { Icon } from "./components/Icon";
|
||||
import { Logo } from "./components/Logo";
|
||||
import { Collections } from "./constants";
|
||||
import { createEditor } from "./utils/editor";
|
||||
|
||||
export default buildConfig({
|
||||
serverURL: process.env.PAYLOAD_URI,
|
||||
|
@ -43,13 +44,9 @@ export default buildConfig({
|
|||
css: path.resolve(__dirname, "styles.scss"),
|
||||
bundler: webpackBundler(),
|
||||
},
|
||||
editor: lexicalEditor({
|
||||
features: ({ defaultFeatures }) => [
|
||||
...defaultFeatures,
|
||||
BlocksFeature({ blocks: [transcriptBlock] }),
|
||||
],
|
||||
}),
|
||||
editor: createEditor({}),
|
||||
collections: [
|
||||
LibraryFolders,
|
||||
LibraryItems,
|
||||
Contents,
|
||||
ContentsFolders,
|
||||
|
@ -66,6 +63,7 @@ export default buildConfig({
|
|||
RecordersThumbnails,
|
||||
PostsThumbnails,
|
||||
Files,
|
||||
Notes,
|
||||
Videos,
|
||||
VideosChannels,
|
||||
Languages,
|
||||
|
|
|
@ -56,6 +56,23 @@ html[data-theme="light"] {
|
|||
}
|
||||
}
|
||||
|
||||
.field-type.no-label > header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lexical-block__block-pill-transcriptBlock + .section-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.blocks-field__block-pill-cueBlock + .section-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rich-text-lexical.field-type.reduced-margins {
|
||||
margin-top: -0.75em;
|
||||
margin-bottom: -2rem;
|
||||
}
|
||||
|
||||
.field-type.array-field.group-array {
|
||||
> .array-field__header {
|
||||
.array-field__header-actions {
|
||||
|
|
|
@ -14,17 +14,15 @@ export type CategoryTranslations = {
|
|||
}[];
|
||||
export type RecorderBiographies = {
|
||||
language: string | Language;
|
||||
biography: string;
|
||||
id?: string;
|
||||
biography: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
export type ContentFoldersTranslation = {
|
||||
language: string | Language;
|
||||
name: string;
|
||||
id?: string;
|
||||
}[];
|
||||
|
||||
export interface Config {
|
||||
collections: {
|
||||
'library-folders': LibraryFolder;
|
||||
'library-items': LibraryItem;
|
||||
contents: Content;
|
||||
'contents-folders': ContentsFolder;
|
||||
|
@ -41,6 +39,7 @@ export interface Config {
|
|||
'recorders-thumbnails': RecordersThumbnail;
|
||||
'posts-thumbnails': PostThumbnail;
|
||||
files: File;
|
||||
Notes: Note;
|
||||
videos: Video;
|
||||
'videos-channels': VideosChannel;
|
||||
languages: Language;
|
||||
|
@ -52,9 +51,28 @@ export interface Config {
|
|||
};
|
||||
globals: {};
|
||||
}
|
||||
export interface LibraryFolder {
|
||||
id: string;
|
||||
slug: string;
|
||||
translations?: {
|
||||
language: string | Language;
|
||||
name: string;
|
||||
description?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
}[];
|
||||
subfolders?: string[] | LibraryFolder[];
|
||||
items?: string[] | LibraryItem[];
|
||||
}
|
||||
export interface Language {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
export interface LibraryItem {
|
||||
id: string;
|
||||
itemType?: 'Textual' | 'Audio' | 'Video' | 'Game' | 'Other';
|
||||
digital: boolean;
|
||||
slug: string;
|
||||
thumbnail?: string | LibraryItemThumbnail;
|
||||
pretitle?: string;
|
||||
|
@ -62,8 +80,6 @@ export interface LibraryItem {
|
|||
subtitle?: string;
|
||||
rootItem: boolean;
|
||||
primary: boolean;
|
||||
digital: boolean;
|
||||
downloadable: boolean;
|
||||
gallery?: {
|
||||
image?: string | LibraryItemGallery;
|
||||
id?: string;
|
||||
|
@ -111,6 +127,7 @@ export interface LibraryItem {
|
|||
image: string | LibraryItemScans;
|
||||
id?: string;
|
||||
}[];
|
||||
downloadable: boolean;
|
||||
id?: string;
|
||||
}[];
|
||||
textual?: {
|
||||
|
@ -132,7 +149,9 @@ export interface LibraryItem {
|
|||
categories?: string[] | Key[];
|
||||
translations?: {
|
||||
language: string | Language;
|
||||
description: string;
|
||||
description: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
}[];
|
||||
size?: {
|
||||
|
@ -156,7 +175,9 @@ export interface LibraryItem {
|
|||
pageEnd?: number;
|
||||
timeStart?: number;
|
||||
timeEnd?: number;
|
||||
note?: string;
|
||||
note?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
}[];
|
||||
updatedBy: string | Recorder;
|
||||
|
@ -292,10 +313,6 @@ export interface Key {
|
|||
| 'Wordings';
|
||||
translations?: CategoryTranslations;
|
||||
}
|
||||
export interface Language {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
export interface File {
|
||||
id: string;
|
||||
filename: string;
|
||||
|
@ -318,16 +335,22 @@ export interface Content {
|
|||
pretitle?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
summary?: string;
|
||||
summary?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
textContent?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
textTranscribers?: string[] | Recorder[];
|
||||
textTranslators?: string[] | Recorder[];
|
||||
textProofreaders?: string[] | Recorder[];
|
||||
textNotes?: string;
|
||||
textNotes?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
video?: string | File;
|
||||
videoNotes?: string;
|
||||
videoNotes?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
audio?: string | File;
|
||||
id?: string;
|
||||
}[];
|
||||
|
@ -424,7 +447,11 @@ export interface RecordersThumbnail {
|
|||
export interface ContentsFolder {
|
||||
id: string;
|
||||
slug: string;
|
||||
translations?: ContentFoldersTranslation;
|
||||
translations?: {
|
||||
language: string | Language;
|
||||
name: string;
|
||||
id?: string;
|
||||
}[];
|
||||
subfolders?: string[] | ContentsFolder[];
|
||||
contents?: string[] | Content[];
|
||||
}
|
||||
|
@ -454,7 +481,9 @@ export interface Post {
|
|||
language: string | Language;
|
||||
sourceLanguage: string | Language;
|
||||
title: string;
|
||||
summary?: string;
|
||||
summary?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
translators?: string[] | Recorder[];
|
||||
proofreaders?: string[] | Recorder[];
|
||||
content?: {
|
||||
|
@ -529,8 +558,12 @@ export interface ChronologyItem {
|
|||
language: string | Language;
|
||||
sourceLanguage: string | Language;
|
||||
title?: string;
|
||||
description?: string;
|
||||
notes?: string;
|
||||
description?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
notes?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
transcribers?: string[] | Recorder[];
|
||||
translators?: string[] | Recorder[];
|
||||
proofreaders?: string[] | Recorder[];
|
||||
|
@ -551,7 +584,9 @@ export interface ChronologyEra {
|
|||
translations?: {
|
||||
language: string | Language;
|
||||
title: string;
|
||||
description?: string;
|
||||
description?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
}[];
|
||||
events?: string[] | ChronologyItem[];
|
||||
|
@ -570,11 +605,21 @@ export interface Weapon {
|
|||
language: string | Language;
|
||||
sourceLanguage: string | Language;
|
||||
name: string;
|
||||
description?: string;
|
||||
level1?: string;
|
||||
level2?: string;
|
||||
level3?: string;
|
||||
level4?: string;
|
||||
description?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
level1?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
level2?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
level3?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
level4?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
transcribers?: string[] | Recorder[];
|
||||
translators?: string[] | Recorder[];
|
||||
proofreaders?: string[] | Recorder[];
|
||||
|
@ -643,6 +688,14 @@ export interface WeaponsGroup {
|
|||
}[];
|
||||
weapons?: string[] | Weapon[];
|
||||
}
|
||||
export interface Note {
|
||||
id: string;
|
||||
note: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Video {
|
||||
id: string;
|
||||
uid: string;
|
||||
|
@ -690,33 +743,5 @@ export interface PayloadMigration {
|
|||
|
||||
|
||||
declare module 'payload' {
|
||||
export interface GeneratedTypes {
|
||||
collections: {
|
||||
'library-items': LibraryItem
|
||||
'contents': Content
|
||||
'contents-folders': ContentsFolder
|
||||
'posts': Post
|
||||
'chronology-items': ChronologyItem
|
||||
'chronology-eras': ChronologyEra
|
||||
'weapons': Weapon
|
||||
'weapons-groups': WeaponsGroup
|
||||
'weapons-thumbnails': WeaponsThumbnail
|
||||
'contents-thumbnails': ContentsThumbnail
|
||||
'library-items-thumbnails': LibraryItemThumbnail
|
||||
'library-items-scans': LibraryItemScans
|
||||
'library-items-gallery': LibraryItemGallery
|
||||
'recorders-thumbnails': RecordersThumbnail
|
||||
'posts-thumbnails': PostThumbnail
|
||||
'files': File
|
||||
'videos': Video
|
||||
'videos-channels': VideosChannel
|
||||
'languages': Language
|
||||
'currencies': Currency
|
||||
'recorders': Recorder
|
||||
'keys': Key
|
||||
'payload-preferences': PayloadPreference
|
||||
'payload-migrations': PayloadMigration
|
||||
}
|
||||
|
||||
}
|
||||
export interface GeneratedTypes extends Config {}
|
||||
}
|
|
@ -2,6 +2,10 @@ export type StrapiLanguage = {
|
|||
data?: { attributes: { code: string } };
|
||||
};
|
||||
|
||||
export type StrapiRecorders = {
|
||||
data?: { attributes: { username: string } }[];
|
||||
};
|
||||
|
||||
export type StrapiImage = {
|
||||
data?: {
|
||||
attributes: {
|
||||
|
@ -9,6 +13,8 @@ export type StrapiImage = {
|
|||
mime: string;
|
||||
name: string;
|
||||
size: number;
|
||||
hash: string;
|
||||
ext: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
import {
|
||||
AdapterProps,
|
||||
AlignFeature,
|
||||
BlocksFeature,
|
||||
BoldTextFeature,
|
||||
CheckListFeature,
|
||||
FeatureProvider,
|
||||
// IndentFeature,
|
||||
HeadingFeature,
|
||||
InlineCodeTextFeature,
|
||||
ItalicTextFeature,
|
||||
LinkFeature,
|
||||
// BlockQuoteFeature,
|
||||
OrderedListFeature,
|
||||
ParagraphFeature,
|
||||
RelationshipFeature,
|
||||
StrikethroughTextFeature,
|
||||
SubscriptTextFeature,
|
||||
SuperscriptTextFeature,
|
||||
TreeviewFeature,
|
||||
UnderlineTextFeature,
|
||||
UnoderedListFeature,
|
||||
UploadFeature,
|
||||
lexicalEditor,
|
||||
} from "@payloadcms/richtext-lexical";
|
||||
import { Block, RichTextAdapter } from "payload/types";
|
||||
|
||||
interface EditorOptions {
|
||||
debugs: boolean;
|
||||
blocks: Block[];
|
||||
headings: boolean;
|
||||
lists: boolean;
|
||||
inlines: boolean;
|
||||
images: boolean;
|
||||
relations: boolean;
|
||||
links: boolean;
|
||||
alignment: boolean;
|
||||
}
|
||||
|
||||
export const createEditor = ({
|
||||
debugs = false,
|
||||
blocks = [],
|
||||
headings = false,
|
||||
images = false,
|
||||
inlines = false,
|
||||
lists = false,
|
||||
links = false,
|
||||
relations = false,
|
||||
alignment = false,
|
||||
}: Partial<EditorOptions>): RichTextAdapter<any, AdapterProps> => {
|
||||
const enabledFeatures: FeatureProvider[] = [];
|
||||
|
||||
if (lists) enabledFeatures.push(OrderedListFeature(), UnoderedListFeature(), CheckListFeature());
|
||||
if (blocks.length > 0) enabledFeatures.push(BlocksFeature({ blocks }));
|
||||
if (headings) enabledFeatures.push(ParagraphFeature(), HeadingFeature({}));
|
||||
if (debugs) enabledFeatures.push(TreeviewFeature());
|
||||
if (images) enabledFeatures.push(UploadFeature({ collections: [] }));
|
||||
if (links) enabledFeatures.push(LinkFeature({}));
|
||||
if (relations) enabledFeatures.push(RelationshipFeature());
|
||||
if (alignment) enabledFeatures.push(AlignFeature());
|
||||
if (inlines)
|
||||
enabledFeatures.push(
|
||||
BoldTextFeature(),
|
||||
ItalicTextFeature(),
|
||||
UnderlineTextFeature(),
|
||||
StrikethroughTextFeature(),
|
||||
SubscriptTextFeature(),
|
||||
SuperscriptTextFeature(),
|
||||
InlineCodeTextFeature()
|
||||
);
|
||||
|
||||
return lexicalEditor({
|
||||
features: enabledFeatures,
|
||||
});
|
||||
};
|
|
@ -21,6 +21,24 @@ export const findCategory = async (name: string): Promise<string> => {
|
|||
return key.docs[0]?.id;
|
||||
};
|
||||
|
||||
export const findRecorder = async (name: string): Promise<string> => {
|
||||
const recorder = await payload.find({
|
||||
collection: Collections.Recorders,
|
||||
where: { username: { equals: name } },
|
||||
});
|
||||
if (!recorder.docs[0]) throw new Error(`Recorder ${name} wasn't found`);
|
||||
return recorder.docs[0]?.id;
|
||||
};
|
||||
|
||||
export const findContentType = async (name: string): Promise<string> => {
|
||||
const key = await payload.find({
|
||||
collection: Collections.Keys,
|
||||
where: { name: { equals: name }, type: { equals: KeysTypes.Contents } },
|
||||
});
|
||||
if (!key.docs[0]) throw new Error(`Content type ${name} wasn't found`);
|
||||
return key.docs[0]?.id;
|
||||
};
|
||||
|
||||
type UploadStrapiImage = {
|
||||
image: StrapiImage;
|
||||
collection: Collections;
|
||||
|
@ -31,6 +49,16 @@ export const uploadStrapiImage = async ({
|
|||
image,
|
||||
}: UploadStrapiImage): Promise<string | undefined> => {
|
||||
if (isDefined(image.data)) {
|
||||
const filename = image.data.attributes.hash + image.data.attributes.ext;
|
||||
|
||||
const existingImage = await payload.find({
|
||||
collection,
|
||||
where: { filename: { equals: filename } },
|
||||
});
|
||||
if (existingImage.docs[0]) {
|
||||
return existingImage.docs[0].id;
|
||||
}
|
||||
|
||||
const url = `${process.env.STRAPI_URI}${image.data.attributes.url}`;
|
||||
|
||||
const blob = await (await fetch(url)).blob();
|
||||
|
@ -41,7 +69,7 @@ export const uploadStrapiImage = async ({
|
|||
file: {
|
||||
data: buffer,
|
||||
mimetype: image.data.attributes.mime,
|
||||
name: image.data.attributes.name,
|
||||
name: filename,
|
||||
size: image.data.attributes.size,
|
||||
},
|
||||
data: {},
|
||||
|
|
|
@ -21,3 +21,37 @@ export const formatToCamelCase = (name: string): string =>
|
|||
.join("");
|
||||
|
||||
export const formatToPascalCase = (name: string): string => capitalize(formatToCamelCase(name));
|
||||
|
||||
export const plainTextToLexical = (
|
||||
text: string
|
||||
): {
|
||||
[k: string]: unknown;
|
||||
}[] => ({
|
||||
root: {
|
||||
type: "root",
|
||||
format: "",
|
||||
indent: 0,
|
||||
version: 1,
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: "normal",
|
||||
style: "",
|
||||
text,
|
||||
type: "text",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: "ltr",
|
||||
format: "",
|
||||
indent: 0,
|
||||
type: "paragraph",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: "ltr",
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue