5 Commits
awq ... main

Author SHA1 Message Date
4c5c7d7e31 Added general fields
All checks were successful
Build and Deploy DAVE | DMGs Site / deploy (push) Successful in 1m30s
2025-11-12 08:53:29 +01:00
af7a72d174 added Meta & Content Field Collections 2025-11-11 13:49:31 +01:00
abb694bf5b Added taxonomy/tags + reader 2025-11-11 13:32:41 +01:00
ae1cabeb97 Added Author reader 2025-11-11 13:18:37 +01:00
b30b77e6fd Added Taxonomy/Author collection 2025-11-11 11:25:12 +01:00
14 changed files with 4110 additions and 1297 deletions

View File

@@ -2,7 +2,7 @@ name: Build and Deploy DAVE | DMGs Site
on: on:
push: push:
branches: [ main ] branches: [main]
jobs: jobs:
deploy: deploy:
@@ -41,4 +41,4 @@ jobs:
mv src/app/\(cms\) src/app/_cms mv src/app/\(cms\) src/app/_cms
pnpm run build pnpm run build
rm -rf /var/www/sites/dave-dmg/blog/* rm -rf /var/www/sites/dave-dmg/blog/*
cp -r out/* /var/www/sites/dave-dmg/blog/ cp -r out/* /var/www/sites/dave-dmg/blog/

View File

@@ -1,8 +1,14 @@
import { config } from '@keystatic/core'; import { config } from '@keystatic/core';
import AuthorsCollection from '@/keystatic/collections/taxonomy/authors';
import TagsCollection from '@/keystatic/collections/taxonomy/tags';
export default config({ export default config({
storage: { storage: {
kind: 'local', kind: 'local',
}, },
collections: {}, collections: {
authors: AuthorsCollection,
tags: TagsCollection,
},
}); });

5204
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
import { collection, fields } from '@keystatic/core';
export default collection({
label: 'Authors',
slugField: 'name',
path: 'content/taxonomy/authors/*',
format: {
data: 'json',
},
schema: {
name: fields.slug({
name: {
label: 'Name',
},
}),
avatar: fields.image({
label: 'Avatar',
directory: 'public/images/authors',
publicPath: '/images/authors',
}),
description: fields.text({
label: 'Description',
multiline: true,
}),
},
});

View File

@@ -0,0 +1,19 @@
import { collection, fields } from '@keystatic/core';
export default collection({
label: 'Tags',
slugField: 'name',
path: 'content/taxonomy/tags/*',
format: { data: 'json' },
schema: {
name: fields.slug({
name: {
label: 'Name',
},
}),
description: fields.text({
label: 'Descriptions',
multiline: true,
}),
},
});

View File

@@ -0,0 +1 @@
export const generalComponents = {};

View File

@@ -0,0 +1,41 @@
import { fields } from '@keystatic/core';
import { createPathField } from '@/keystatic/fields/general/path';
import { createContentField } from '@/keystatic/fields/general/content';
import { createMetaField } from '@/keystatic/fields/general/meta';
export const createArticleField = (
imageSubfolder: string,
defaultPath: string = ''
) => ({
title: fields.slug({
name: {
label: 'Title',
},
}),
summary: fields.text({
label: 'Summary',
multiline: true,
}),
path: createPathField(defaultPath),
cover: fields.object({
src: fields.image({
label: 'Cover Image',
directory: `public/images/covers/${imageSubfolder}`,
publicPath: `/images/covers/${imageSubfolder}`,
}),
alt: fields.text({
label: 'Alt',
}),
caption: fields.text({
label: 'Caption',
multiline: true,
}),
showInHeader: fields.checkbox({
label: 'Show in Header',
defaultValue: false,
}),
}),
meta: createMetaField(),
content: createContentField(imageSubfolder),
});

View File

@@ -0,0 +1,22 @@
import { fields } from '@keystatic/core';
import type { ContentComponent } from '@keystatic/core/content-components';
import { generalComponents } from '@/keystatic/components/general';
export const createContentField = (
imageSubfolder: string,
additionalComponents?: Record<string, ContentComponent>
) =>
fields.markdoc({
label: 'Content',
options: {
image: {
directory: `public/images/content/${imageSubfolder}`,
publicPath: `/images/content/${imageSubfolder}`,
},
},
components: {
...generalComponents,
...additionalComponents,
},
});

View File

@@ -0,0 +1,52 @@
import type { ComponentSchema } from '@keystatic/core';
import { fields } from '@keystatic/core';
export const createMetaField = (): ComponentSchema =>
fields.object(
{
publicationDate: fields.datetime({
label: 'Publication Date',
defaultValue: {
kind: 'now',
},
}),
updateDate: fields.datetime({
label: 'Update Date',
}),
status: fields.select({
label: 'Status',
defaultValue: 'draft',
options: [
{
label: 'Draft',
value: 'draft',
},
{
label: 'Published',
value: 'published',
},
{
label: 'Archived',
value: 'archived',
},
],
}),
tags: fields.array(
fields.relationship({
label: 'Tags',
collection: 'tags',
}),
{
label: 'Tags',
itemLabel: (props) => props.value || 'Select Tags',
}
),
author: fields.relationship({
label: 'Author',
collection: 'authors',
}),
},
{
label: 'Meta Information',
}
);

View File

@@ -0,0 +1,8 @@
import { ComponentSchema, fields } from '@keystatic/core';
export const createPathField = (defaultValue: string): ComponentSchema =>
fields.text({
label: 'Path',
description: 'Path on Website',
defaultValue: defaultValue,
});

6
src/lib/readers/base.ts Normal file
View File

@@ -0,0 +1,6 @@
import { createReader } from '@keystatic/core/reader';
import { cache } from 'react';
import keystaticConfig from '~/keystatic.config';
export const reader = createReader(process.cwd(), keystaticConfig);
export { cache };

View File

@@ -0,0 +1,8 @@
import { cache, reader } from '@/lib/readers/base';
export const getAuthors = cache(async () => reader.collections.authors.all());
export const getAuthorBySlug = cache(async (slug: string) => {
const author = await reader.collections.authors.read(slug);
return author ? { ...author, slug } : null;
});

View File

@@ -0,0 +1,8 @@
import { cache, reader } from '@/lib/readers/base';
export const getTags = cache(async () => reader.collections.tags.all());
export const getTagBySlug = cache(async (slug: string) => {
const tag = await reader.collections.tags.read(slug);
return tag ? { ...tag, slug } : null;
});