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
+182
View File
@@ -0,0 +1,182 @@
import { g as getCollection, r as renderEntry } from './_astro_content_BsTdlqxn.mjs';
import { e as cleanSlug, P as POST_PERMALINK_PATTERN, t as trimSlash, A as APP_BLOG, C as CATEGORY_BASE, T as TAG_BASE, B as BLOG_BASE } from './permalinks_BMxSf01e.mjs';
const generatePermalink = async ({
id,
slug,
publishDate,
category
}) => {
const year = String(publishDate.getFullYear()).padStart(4, "0");
const month = String(publishDate.getMonth() + 1).padStart(2, "0");
const day = String(publishDate.getDate()).padStart(2, "0");
const hour = String(publishDate.getHours()).padStart(2, "0");
const minute = String(publishDate.getMinutes()).padStart(2, "0");
const second = String(publishDate.getSeconds()).padStart(2, "0");
const permalink = POST_PERMALINK_PATTERN.replace("%slug%", slug).replace("%id%", id).replace("%category%", category || "").replace("%year%", year).replace("%month%", month).replace("%day%", day).replace("%hour%", hour).replace("%minute%", minute).replace("%second%", second);
return permalink.split("/").map((el) => trimSlash(el)).filter((el) => !!el).join("/");
};
const getNormalizedPost = async (post) => {
const { id, data } = post;
const { Content, remarkPluginFrontmatter } = await renderEntry(post);
const {
publishDate: rawPublishDate = /* @__PURE__ */ new Date(),
updateDate: rawUpdateDate,
title,
excerpt,
image,
tags: rawTags = [],
category: rawCategory,
categories: rawCategories = [],
author,
draft = false,
metadata = {}
} = data;
const slug = cleanSlug(id);
const publishDate = new Date(rawPublishDate);
const updateDate = rawUpdateDate ? new Date(rawUpdateDate) : void 0;
const categoryTitle = rawCategory || (rawCategories.length > 0 ? rawCategories[0] : void 0);
const category = categoryTitle ? {
slug: cleanSlug(categoryTitle),
title: categoryTitle
} : void 0;
const tags = rawTags.map((tag) => ({
slug: cleanSlug(tag),
title: tag
}));
return {
id,
slug,
permalink: await generatePermalink({ id, slug, publishDate, category: category?.slug }),
publishDate,
updateDate,
title,
excerpt,
image,
category,
tags,
author,
draft,
metadata,
Content,
// or 'content' in case you consume from API
readingTime: remarkPluginFrontmatter?.readingTime
};
};
const load = async function() {
const posts = await getCollection("post");
const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
const results = (await Promise.all(normalizedPosts)).sort((a, b) => b.publishDate.valueOf() - a.publishDate.valueOf()).filter((post) => !post.draft);
return results;
};
let _posts;
const blogListRobots = APP_BLOG.list.robots;
const blogPostRobots = APP_BLOG.post.robots;
const blogCategoryRobots = APP_BLOG.category.robots;
const blogTagRobots = APP_BLOG.tag.robots;
const blogPostsPerPage = APP_BLOG?.postsPerPage;
const fetchPosts = async () => {
if (!_posts) {
_posts = await load();
}
return _posts;
};
const findPostsByIds = async (ids) => {
if (!Array.isArray(ids)) return [];
const posts = await fetchPosts();
return ids.reduce(function(r, id) {
posts.some(function(post) {
return id === post.id && r.push(post);
});
return r;
}, []);
};
const findLatestPosts = async ({ count }) => {
const _count = count || 4;
const posts = await fetchPosts();
return posts ? posts.slice(0, _count) : [];
};
const getStaticPathsBlogList = async ({ paginate }) => {
return paginate(await fetchPosts(), {
params: { blog: BLOG_BASE || void 0 },
pageSize: blogPostsPerPage
});
};
const getStaticPathsBlogPost = async () => {
return (await fetchPosts()).flatMap((post) => ({
params: {
blog: post.permalink
},
props: { post }
}));
};
const getStaticPathsBlogCategory = async ({ paginate }) => {
const posts = await fetchPosts();
const categories = {};
posts.map((post) => {
if (post.category?.slug) {
categories[post.category?.slug] = post.category;
}
});
return Array.from(Object.keys(categories)).flatMap(
(categorySlug) => paginate(
posts.filter((post) => post.category?.slug && categorySlug === post.category?.slug),
{
params: { category: categorySlug, blog: CATEGORY_BASE || void 0 },
pageSize: blogPostsPerPage,
props: { category: categories[categorySlug] }
}
)
);
};
const getStaticPathsBlogTag = async ({ paginate }) => {
const posts = await fetchPosts();
const tags = {};
posts.map((post) => {
if (Array.isArray(post.tags)) {
post.tags.map((tag) => {
tags[tag?.slug] = tag;
});
}
});
return Array.from(Object.keys(tags)).flatMap(
(tagSlug) => paginate(
posts.filter((post) => Array.isArray(post.tags) && post.tags.find((elem) => elem.slug === tagSlug)),
{
params: { tag: tagSlug, blog: TAG_BASE },
pageSize: blogPostsPerPage,
props: { tag: tags[tagSlug] }
}
)
);
};
async function getRelatedPosts(originalPost, maxResults = 4) {
const allPosts = await fetchPosts();
const originalTagsSet = new Set(originalPost.tags ? originalPost.tags.map((tag) => tag.slug) : []);
const postsWithScores = allPosts.reduce((acc, iteratedPost) => {
if (iteratedPost.slug === originalPost.slug) return acc;
let score = 0;
if (iteratedPost.category && originalPost.category && iteratedPost.category.slug === originalPost.category.slug) {
score += 5;
}
if (iteratedPost.tags) {
iteratedPost.tags.forEach((tag) => {
if (originalTagsSet.has(tag.slug)) {
score += 1;
}
});
}
acc.push({ post: iteratedPost, score });
return acc;
}, []);
postsWithScores.sort((a, b) => b.score - a.score);
const selectedPosts = [];
let i = 0;
while (selectedPosts.length < maxResults && i < postsWithScores.length) {
selectedPosts.push(postsWithScores[i].post);
i++;
}
return selectedPosts;
}
export { getStaticPathsBlogTag as a, blogCategoryRobots as b, blogTagRobots as c, findLatestPosts as d, getStaticPathsBlogList as e, fetchPosts as f, getStaticPathsBlogCategory as g, blogListRobots as h, findPostsByIds as i, getRelatedPosts as j, blogPostRobots as k, getStaticPathsBlogPost as l };