Add KeyStatic CMS optimizations

- Add site singleton for global settings (name, description, URL, contact, social media)
- Add brand mark (globe icon) to KeyStatic header
- Add entry layout grouping (Ana Bilgiler, Medya, Sınıflandırma, Özet, İçerik)
- Add preview URL configuration for local development
- Add published, featured, and relatedPosts fields
- Use local storage for development, GitHub storage for production
- Update Astro content schema with new fields

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Buğra Canata
2026-01-17 23:14:12 +03:00
parent 6e4dc7a33a
commit 50753b9cc7
2 changed files with 70 additions and 4 deletions
+67 -4
View File
@@ -1,19 +1,58 @@
import { config, fields, collection } from '@keystatic/core'; import { config, fields, collection, singleton } from '@keystatic/core';
// Use GitHub storage in production (when env vars are set), local storage for development
const isProd = import.meta.env.PUBLIC_KEYSTATIC_GITHUB_APP_SLUG;
export default config({ export default config({
storage: { storage: isProd ? {
kind: 'github', kind: 'github',
repo: 'YM1KTC/ARC-Web-Sitesi', repo: 'YM1KTC/ARC-Web-Sitesi',
branch: 'main', branch: 'main',
}, } : undefined,
ui: { ui: {
brand: { brand: {
name: 'ARC CMS', name: 'ARC CMS',
mark: () => '<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>',
}, },
navigation: { navigation: {
'İçerik': ['post'], 'İçerik': ['post'],
'Ayarlar': ['site'],
}, },
}, },
singletons: {
site: singleton({
label: 'Site Ayarları',
path: 'src/data/site',
schema: {
siteName: fields.text({
label: 'Site Adı',
default: 'Amatör Radyocular Derneği',
}),
siteDescription: fields.text({
label: 'Site Açıklaması',
multiline: true,
default: 'Amatör telsizciliği yaygınlaştıran Türkiye\'deki öncü dernek.',
}),
siteUrl: fields.text({
label: 'Site URL',
default: 'https://radio.org.tr',
}),
contactEmail: fields.text({
label: 'İletişim E-posta',
default: 'info@radio.org.tr',
}),
socialMedia: fields.object({
label: 'Sosyal Medya Hesapları',
schema: {
facebook: fields.text({ label: 'Facebook' }),
twitter: fields.text({ label: 'Twitter/X' }),
instagram: fields.text({ label: 'Instagram' }),
youtube: fields.text({ label: 'YouTube' }),
},
}),
},
}),
},
collections: { collections: {
post: collection({ post: collection({
label: 'Blog Yazıları', label: 'Blog Yazıları',
@@ -23,7 +62,15 @@ export default config({
contentField: 'body', contentField: 'body',
frontmatter: 'yaml', frontmatter: 'yaml',
}, },
columns: ['title', 'date', 'author'], previewURL: ({ slug }) => `http://localhost:4321/blog/${slug}`,
columns: ['title', 'date', 'author', 'published', 'featured'],
entryLayout: {
'Ana Bilgiler': ['title', 'date', 'author', 'published', 'featured'],
'Medya': ['image'],
'Sınıflandırma': ['categories', 'tags', 'layout'],
'Özet': ['excerpt'],
'İçerik': ['body', 'relatedPosts'],
},
schema: { schema: {
title: fields.slug({ title: fields.slug({
name: { name: {
@@ -40,6 +87,16 @@ export default config({
description: 'Çağrı işareti (örn: TA1SPH) veya yazar adı', description: 'Çağrı işareti (örn: TA1SPH) veya yazar adı',
default: 'TA1SPH', default: 'TA1SPH',
}), }),
published: fields.checkbox({
label: 'Yayınlandı',
description: 'Bu yazı yayınlandı mı?',
defaultValue: true,
}),
featured: fields.checkbox({
label: 'Öne Çıkan',
description: 'Ana sayfada öne çıkan yazılar',
defaultValue: false,
}),
categories: fields.array( categories: fields.array(
fields.text({ fields.text({
label: 'Kategori', label: 'Kategori',
@@ -74,6 +131,12 @@ export default config({
description: 'Blog listesinde gösterilecek özet (isteğe bağlı)', description: 'Blog listesinde gösterilecek özet (isteğe bağlı)',
multiline: true, multiline: true,
}), }),
relatedPosts: fields.relationship({
label: 'İlgili Yazılar',
description: 'Bu yazıyla ilgili diğer blog yazıları',
collection: 'post',
validation: { length: { min: 0, max: 5 } },
}),
body: fields.markdoc({ body: fields.markdoc({
label: 'İçerik', label: 'İçerik',
description: 'Blog yazısının ana içeriği (Markdown formatında yazın)', description: 'Blog yazısının ana içeriği (Markdown formatında yazın)',
+3
View File
@@ -7,11 +7,14 @@ const post = defineCollection({
title: z.string(), title: z.string(),
date: z.date(), date: z.date(),
author: z.string().default('TA1SPH'), author: z.string().default('TA1SPH'),
published: z.boolean().default(true),
featured: z.boolean().default(false),
categories: z.array(z.string()).default([]), categories: z.array(z.string()).default([]),
tags: z.array(z.string()).default([]), tags: z.array(z.string()).default([]),
layout: z.string().default('post'), layout: z.string().default('post'),
image: z.string().optional(), image: z.string().optional(),
excerpt: z.string().optional(), excerpt: z.string().optional(),
relatedPosts: z.array(z.string()).optional(),
}), }),
}); });