Enable KeyStatic CMS for production

Changes:
- Added Netlify adapter for server-side rendering
- Changed output mode from static to server
- Updated KeyStatic storage from local to GitHub
- Removed SKIP_KEYSTATIC from Netlify build
- KeyStatic Admin UI will be available at /keystatic

Features:
- Server-side rendering with Netlify Functions
- GitHub integration for content management
- Production-ready KeyStatic Admin UI

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Buğra Canata
2026-01-17 20:05:42 +03:00
parent 8f64fb1eea
commit e05f99a0d2
5312 changed files with 102603 additions and 284 deletions
@@ -0,0 +1,21 @@
export { renderers } from '../../renderers.mjs';
async function GET() {
const contacts = [
{ id: "2867241", callsign: "YM0KTC", name: "ARC Merkez", location: "Bölge 0 - İstanbul", type: "repeater" },
{ id: "2866808", callsign: "YM1KTC", name: "İstanbul Röle", location: "Bölge 1 - İstanbul", type: "repeater" },
{ id: "2867887", callsign: "YM2KTR", name: "Ankara Röle", location: "Bölge 2 - Ankara", type: "repeater" },
{ id: "2867234", callsign: "YM3KTC", name: "İzmir Röle", location: "Bölge 3 - İzmir", type: "repeater" },
{ id: "2867235", callsign: "YM4KTC", name: "Antalya Röle", location: "Bölge 4 - Antalya", type: "repeater" }
];
return Response.json(contacts);
}
const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
__proto__: null,
GET
}, Symbol.toStringTag, { value: 'Module' }));
const page = () => _page;
export { page };
@@ -0,0 +1,61 @@
import rss from '@astrojs/rss';
import { g as getCollection } from '../../../chunks/_astro_content_BsTdlqxn.mjs';
export { renderers } from '../../../renderers.mjs';
function slugify(str) {
return str.toLowerCase().replace(/ş/g, "s").replace(/ı/g, "i").replace(/ğ/g, "g").replace(/ü/g, "u").replace(/ö/g, "o").replace(/ç/g, "c").replace(/[^a-z0-9]+/g, "-");
}
async function getStaticPaths() {
const posts = await getCollection("post");
const categoryMap = /* @__PURE__ */ new Map();
posts.forEach((post) => {
if (post.data.categories) {
post.data.categories.forEach((cat) => {
if (!categoryMap.has(cat)) {
categoryMap.set(cat, slugify(cat));
}
});
}
if (post.data.category) {
if (!categoryMap.has(post.data.category)) {
categoryMap.set(post.data.category, slugify(post.data.category));
}
}
});
return Array.from(categoryMap.entries()).map(([category, slug]) => ({
params: { category: slug },
props: { originalCategory: category }
}));
}
async function GET(context) {
const posts = await getCollection("post");
const originalCategory = context.props.originalCategory;
const filteredPosts = posts.filter(
(post) => post.data.categories?.includes(originalCategory) || post.data.category === originalCategory
).filter((post) => post.data.publishDate).sort((a, b) => {
const aDate = a.data.publishDate || /* @__PURE__ */ new Date(0);
const bDate = b.data.publishDate || /* @__PURE__ */ new Date(0);
return bDate.valueOf() - aDate.valueOf();
}).slice(0, 20);
return rss({
title: `ARC - ${originalCategory} Blog Yazıları`,
description: `Amatör Radyocular Derneği - ${originalCategory} kategorisindeki blog yazıları`,
site: context.site?.toString() || "https://radio.org.tr",
items: filteredPosts.map((post) => ({
title: post.data.title,
pubDate: post.data.publishDate,
description: post.data.excerpt || "",
link: `/blog/${post.slug}/`
}))
});
}
const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
__proto__: null,
GET,
getStaticPaths
}, Symbol.toStringTag, { value: 'Module' }));
const page = () => _page;
export { page };
@@ -0,0 +1,175 @@
import { makeGenericAPIRouteHandler } from '@keystatic/core/api/generic';
import { parseString } from 'set-cookie-parser';
import { config as config$1, collection, fields } from '@keystatic/core';
export { renderers } from '../../../renderers.mjs';
function makeHandler(_config) {
return async function keystaticAPIRoute(context) {
var _context$locals, _ref, _config$clientId, _ref2, _config$clientSecret, _ref3, _config$secret;
const envVarsForCf = (_context$locals = context.locals) === null || _context$locals === void 0 || (_context$locals = _context$locals.runtime) === null || _context$locals === void 0 ? void 0 : _context$locals.env;
const handler = makeGenericAPIRouteHandler({
..._config,
clientId: (_ref = (_config$clientId = _config.clientId) !== null && _config$clientId !== void 0 ? _config$clientId : envVarsForCf === null || envVarsForCf === void 0 ? void 0 : envVarsForCf.KEYSTATIC_GITHUB_CLIENT_ID) !== null && _ref !== void 0 ? _ref : tryOrUndefined(() => {
return undefined ;
}),
clientSecret: (_ref2 = (_config$clientSecret = _config.clientSecret) !== null && _config$clientSecret !== void 0 ? _config$clientSecret : envVarsForCf === null || envVarsForCf === void 0 ? void 0 : envVarsForCf.KEYSTATIC_GITHUB_CLIENT_SECRET) !== null && _ref2 !== void 0 ? _ref2 : tryOrUndefined(() => {
return undefined ;
}),
secret: (_ref3 = (_config$secret = _config.secret) !== null && _config$secret !== void 0 ? _config$secret : envVarsForCf === null || envVarsForCf === void 0 ? void 0 : envVarsForCf.KEYSTATIC_SECRET) !== null && _ref3 !== void 0 ? _ref3 : tryOrUndefined(() => {
return undefined ;
})
}, {
slugEnvName: "PUBLIC_KEYSTATIC_GITHUB_APP_SLUG"
});
const {
body,
headers,
status
} = await handler(context.request);
let headersInADifferentStructure = /* @__PURE__ */ new Map();
if (headers) {
if (Array.isArray(headers)) {
for (const [key, value] of headers) {
if (!headersInADifferentStructure.has(key.toLowerCase())) {
headersInADifferentStructure.set(key.toLowerCase(), []);
}
headersInADifferentStructure.get(key.toLowerCase()).push(value);
}
} else if (typeof headers.entries === "function") {
for (const [key, value] of headers.entries()) {
headersInADifferentStructure.set(key.toLowerCase(), [value]);
}
if ("getSetCookie" in headers && typeof headers.getSetCookie === "function") {
const setCookieHeaders2 = headers.getSetCookie();
if (setCookieHeaders2 !== null && setCookieHeaders2 !== void 0 && setCookieHeaders2.length) {
headersInADifferentStructure.set("set-cookie", setCookieHeaders2);
}
}
} else {
for (const [key, value] of Object.entries(headers)) {
headersInADifferentStructure.set(key.toLowerCase(), [value]);
}
}
}
const setCookieHeaders = headersInADifferentStructure.get("set-cookie");
headersInADifferentStructure.delete("set-cookie");
if (setCookieHeaders) {
for (const setCookieValue of setCookieHeaders) {
var _options$sameSite;
const {
name,
value,
...options
} = parseString(setCookieValue);
const sameSite = (_options$sameSite = options.sameSite) === null || _options$sameSite === void 0 ? void 0 : _options$sameSite.toLowerCase();
context.cookies.set(name, value, {
domain: options.domain,
expires: options.expires,
httpOnly: options.httpOnly,
maxAge: options.maxAge,
path: options.path,
sameSite: sameSite === "lax" || sameSite === "strict" || sameSite === "none" ? sameSite : void 0
});
}
}
return new Response(body, {
status,
headers: [...headersInADifferentStructure.entries()].flatMap(([key, val]) => val.map((x) => [key, x]))
});
};
}
function tryOrUndefined(fn) {
try {
return fn();
} catch {
return void 0;
}
}
const config = config$1({
storage: {
kind: "github",
repo: "YM1KTC/ARC-Web-Sitesi",
branch: "main"
},
collections: {
post: collection({
label: "Blog Yazıları",
slugField: "title",
path: "src/data/post/*",
format: { contentField: "body" },
schema: {
title: fields.slug({
name: {
label: "Başlık",
description: "Blog yazısının başlığı"
}
}),
date: fields.datetime({
label: "Yayın Tarihi",
description: "Yazının yayınlanma tarihi"
}),
author: fields.text({
label: "Yazar",
description: "Çağrı işareti veya yazar adı",
default: "TA1SPH"
}),
categories: fields.array(
fields.text({
label: "Kategori"
}),
{
label: "Kategoriler",
description: "Blog yazısının kategorileri"
}
),
tags: fields.array(
fields.text({
label: "Etiket"
}),
{
label: "Etiketler",
description: "Blog yazısının etiketleri"
}
),
layout: fields.text({
label: "Düzen",
default: "post"
}),
image: fields.image({
label: "Öne Çıkan Görsel",
description: "Blog yazısı için kapak görseli"
}),
publishDate: fields.datetime({
label: "Yayınlanma Tarihi",
description: "Content collection için yayın tarihi"
}),
excerpt: fields.text({
label: "Özet",
description: "Blog yazısının kısa özeti",
multiline: true
}),
body: fields.markdoc({
label: "İçerik",
description: "Blog yazısının ana içeriği"
})
}
})
}
});
const all = makeHandler({ config });
const ALL = all;
const prerender = false;
const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
__proto__: null,
ALL,
all,
prerender
}, Symbol.toStringTag, { value: 'Module' }));
const page = () => _page;
export { page };
@@ -0,0 +1,46 @@
export { renderers } from '../../renderers.mjs';
async function GET() {
const repeaters = [
{
id: "YM1KTC",
name: "İstanbul Röle",
frequency: "439.4125+",
offset: "+7.6",
tone: "88.5",
colorCode: "1",
status: "online",
lastheard: (/* @__PURE__ */ new Date()).toISOString()
},
{
id: "YM2KTR",
name: "Ankara Röle",
frequency: "439.4750-",
offset: "-5.0",
tone: "88.5",
colorCode: "1",
status: "online",
lastheard: new Date(Date.now() - 36e5).toISOString()
},
{
id: "YM3KTC",
name: "İzmir Röle",
frequency: "439.5500+",
offset: "+7.6",
tone: "88.5",
colorCode: "1",
status: "offline",
lastheard: new Date(Date.now() - 864e5).toISOString()
}
];
return Response.json(repeaters);
}
const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
__proto__: null,
GET
}, Symbol.toStringTag, { value: 'Module' }));
const page = () => _page;
export { page };