Add draft functionality for pages

This commit is contained in:
tfmurad
2025-10-14 12:07:37 +06:00
parent ea3e56e1ec
commit 603af67eeb
16 changed files with 102 additions and 105 deletions
+9 -10
View File
@@ -1,11 +1,11 @@
{
"name": "astroplate",
"version": "5.5.2",
"version": "5.6.0",
"description": "Astro and Tailwindcss boilerplate",
"author": "zeon.studio",
"license": "MIT",
"type": "module",
"packageManager": "yarn@1.22.22",
"type": "module",
"scripts": {
"dev": "yarn generate-json && astro dev",
"build": "yarn generate-json && astro build",
@@ -17,20 +17,19 @@
},
"dependencies": {
"@astrojs/check": "0.9.4",
"@astrojs/mdx": "4.3.6",
"@astrojs/mdx": "4.3.7",
"@astrojs/react": "4.4.0",
"@astrojs/rss": "4.0.12",
"@astrojs/sitemap": "3.6.0",
"@digi4care/astro-google-tagmanager": "^1.6.0",
"@justinribeiro/lite-youtube": "^1.8.2",
"astro": "5.14.1",
"astro-auto-import": "^0.4.4",
"astro": "5.14.4",
"astro-auto-import": "^0.4.5",
"astro-font": "^1.1.0",
"date-fns": "^4.1.0",
"disqus-react": "^1.1.7",
"github-slugger": "^2.0.0",
"gray-matter": "^4.0.3",
"marked": "^16.3.0",
"marked": "^16.4.0",
"prop-types": "^15.8.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
@@ -44,9 +43,9 @@
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.14",
"@types/node": "24.6.2",
"@types/react": "19.2.0",
"@types/react-dom": "19.2.0",
"@types/node": "24.7.2",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"eslint": "^9.37.0",
"prettier": "^3.6.2",
"prettier-plugin-astro": "^0.14.1",
+2 -2
View File
@@ -10,8 +10,8 @@
</h2>
<p align=center>
<a href="https://github.com/withastro/astro/releases/tag/astro%405.7.8">
<img src="https://img.shields.io/static/v1?label=ASTRO&message=5.7&color=000&logo=astro" alt="Astro Version 5.7"/>
<a href="https://github.com/withastro/astro/releases/tag/astro%405.14.4">
<img src="https://img.shields.io/static/v1?label=ASTRO&message=5.14&color=000&logo=astro" alt="Astro Version 5.14"/>
</a>
<a href="https://github.com/zeon-studio/astroplate/blob/main/LICENSE">
+13 -20
View File
@@ -1,6 +1,15 @@
import { glob } from "astro/loaders";
import { defineCollection, z } from "astro:content";
const commonFields = {
title: z.string(),
description: z.string(),
meta_title: z.string().optional(),
date: z.date().optional(),
image: z.string().optional(),
draft: z.boolean(),
};
// Post collection schema
const blogCollection = defineCollection({
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/content/blog" }),
@@ -21,11 +30,7 @@ const blogCollection = defineCollection({
const authorsCollection = defineCollection({
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/content/authors" }),
schema: z.object({
title: z.string(),
meta_title: z.string().optional(),
email: z.string().optional(),
image: z.string().optional(),
description: z.string().optional(),
...commonFields,
social: z
.array(
z
@@ -45,11 +50,7 @@ const authorsCollection = defineCollection({
const pagesCollection = defineCollection({
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/content/pages" }),
schema: z.object({
title: z.string(),
meta_title: z.string().optional(),
description: z.string().optional(),
image: z.string().optional(),
draft: z.boolean().optional(),
...commonFields,
}),
});
@@ -57,11 +58,7 @@ const pagesCollection = defineCollection({
const aboutCollection = defineCollection({
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/content/about" }),
schema: z.object({
title: z.string(),
meta_title: z.string().optional(),
description: z.string().optional(),
image: z.string().optional(),
draft: z.boolean().optional(),
...commonFields,
}),
});
@@ -69,11 +66,7 @@ const aboutCollection = defineCollection({
const contactCollection = defineCollection({
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/content/contact" }),
schema: z.object({
title: z.string(),
meta_title: z.string().optional(),
description: z.string().optional(),
image: z.string().optional(),
draft: z.boolean().optional(),
...commonFields,
}),
});
+2
View File
@@ -2,4 +2,6 @@
title: "Authors"
meta_title: ""
description: "this is meta description"
image: ""
draft: false
---
+2
View File
@@ -2,4 +2,6 @@
title: "Blog Posts"
meta_title: ""
description: "this is meta description"
image: ""
draft: false
---
+2 -1
View File
@@ -1,6 +1,7 @@
---
title: "Contact"
meta_title: ""
description: "this is meta description"
meta_title: ""
image: ""
draft: false
---
+3 -2
View File
@@ -133,7 +133,8 @@ window.addEventListener("load", (e) => {
### Button
<Button label="Button" link="#" style="solid" />
<Button label="Solid" link="#" style="solid" />
<Button label="Outline" link="#" style="outline" />
---
@@ -243,7 +244,7 @@ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
### Youtube video
<Youtube client:load id="C0DPdy98e4c" title="Play:Youtube"/>
<Youtube client:load id="C0DPdy98e4c" title="Play:Youtube" />
---
+1 -1
View File
@@ -14,7 +14,7 @@ const Youtube = ({
}, []);
// @ts-ignore
return <lite-youtube videoid={id} videotitle={title} {...rest} />;
return <lite-youtube className="rounded-lg" videoid={id} videotitle={title} {...rest} />;
};
export default Youtube;
+21 -7
View File
@@ -1,6 +1,7 @@
---
import {
getCollection,
getEntry,
type CollectionEntry,
type CollectionKey,
} from "astro:content";
@@ -16,15 +17,28 @@ type PageData = {
export const getSinglePage = async <C extends CollectionKey>(
collectionName: C
): Promise<CollectionEntry<C>[]> => {
const allPages = await getCollection(collectionName);
const allPages = await getCollection(
collectionName,
({ data, id }) => !(data as PageData)?.draft && !id.startsWith("-")
);
return allPages;
};
const removeIndex = allPages.filter((data) => data.id.match(/^(?!-)/));
export const getListPage = async <C extends CollectionKey>(
collectionName: C,
documentId: "-index" | string
): Promise<CollectionEntry<C>> => {
const data = (await getEntry(
collectionName,
documentId
)) as CollectionEntry<C> | null;
const removeDrafts = removeIndex.filter((data) => {
const pageData = data.data as PageData;
return pageData.draft !== true;
});
if (!data) {
throw new Error(
`No page found for the collection: ${collectionName} with filename: ${documentId}`
);
}
return removeDrafts;
return data;
};
---
+9 -5
View File
@@ -1,13 +1,17 @@
---
import ImageMod from "@/components/ImageMod.astro";
import Base from "@/layouts/Base.astro";
import { getListPage } from "@/lib/contentParser.astro";
import { markdownify } from "@/lib/utils/textConverter";
import type { CollectionEntry } from "astro:content";
import { getEntry, render } from "astro:content";
import { render } from "astro:content";
const about = (await getEntry("about", "-index")) as CollectionEntry<"about">;
const { Content } = await render(about);
const { title, description, meta_title, image } = about.data;
const aboutIndex = await getListPage("about", "-index");
const { Content } = await render(aboutIndex);
const { title, description, meta_title, image } = aboutIndex.data;
if (aboutIndex.data.draft) {
return Astro.redirect("/404");
}
---
<Base
+7 -8
View File
@@ -1,17 +1,16 @@
---
import AuthorCard from "@/components/AuthorCard.astro";
import Base from "@/layouts/Base.astro";
import { getSinglePage } from "@/lib/contentParser.astro";
import { getListPage, getSinglePage } from "@/lib/contentParser.astro";
import PageHeader from "@/partials/PageHeader.astro";
import { getEntry, type CollectionEntry } from "astro:content";
const COLLECTION_FOLDER = "authors";
const authorIndex = await getListPage("authors", "-index");
const authorIndex = (await getEntry(
COLLECTION_FOLDER,
"-index"
)) as CollectionEntry<"authors">;
const authors = await getSinglePage(COLLECTION_FOLDER);
if (authorIndex.data.draft) {
return Astro.redirect("/404");
}
const authors = await getSinglePage("authors");
---
<Base title={authorIndex.data.title}>
+5 -7
View File
@@ -3,20 +3,18 @@ import BlogCard from "@/components/BlogCard.astro";
import Pagination from "@/components/Pagination.astro";
import config from "@/config/config.json";
import Base from "@/layouts/Base.astro";
import { getSinglePage } from "@/lib/contentParser.astro";
import { getListPage, getSinglePage } from "@/lib/contentParser.astro";
import { getAllTaxonomy, getTaxonomy } from "@/lib/taxonomyParser.astro";
import { sortByDate } from "@/lib/utils/sortFunctions";
import PageHeader from "@/partials/PageHeader.astro";
import PostSidebar from "@/partials/PostSidebar.astro";
import type { CollectionEntry } from "astro:content";
import { getEntry } from "astro:content";
const BLOG_FOLDER = "blog";
const postIndex = (await getEntry(
BLOG_FOLDER,
"-index"
)) as CollectionEntry<"blog">;
const postIndex = await getListPage(BLOG_FOLDER, "-index");
if (postIndex.data.draft) {
return Astro.redirect("/404");
}
const posts = await getSinglePage(BLOG_FOLDER);
const allCategories = await getAllTaxonomy(BLOG_FOLDER, "categories");
const categories = await getTaxonomy(BLOG_FOLDER, "categories");
+7 -7
View File
@@ -3,21 +3,21 @@ import BlogCard from "@/components/BlogCard.astro";
import Pagination from "@/components/Pagination.astro";
import config from "@/config/config.json";
import Base from "@/layouts/Base.astro";
import { getSinglePage } from "@/lib/contentParser.astro";
import { getListPage, getSinglePage } from "@/lib/contentParser.astro";
import { getAllTaxonomy, getTaxonomy } from "@/lib/taxonomyParser.astro";
import { sortByDate } from "@/lib/utils/sortFunctions";
import PageHeader from "@/partials/PageHeader.astro";
import PostSidebar from "@/partials/PostSidebar.astro";
import type { CollectionEntry } from "astro:content";
import { getEntry } from "astro:content";
const BLOG_FOLDER = "blog";
const { slug } = Astro.params;
const postIndex = (await getEntry(
BLOG_FOLDER,
"-index"
)) as CollectionEntry<"blog">;
const postIndex = await getListPage(BLOG_FOLDER, "-index");
if (postIndex.data.draft) {
return Astro.redirect("/404");
}
const posts = await getSinglePage(BLOG_FOLDER);
const allCategories = await getAllTaxonomy(BLOG_FOLDER, "categories");
const categories = await getTaxonomy(BLOG_FOLDER, "categories");
+10 -7
View File
@@ -1,16 +1,16 @@
---
import config from "@/config/config.json";
import Base from "@/layouts/Base.astro";
import { getListPage } from "@/lib/contentParser.astro";
import PageHeader from "@/partials/PageHeader.astro";
import { getEntry } from "astro:content";
import type { CollectionEntry } from "astro:content";
const contact = (await getEntry(
"contact",
"-index"
)) as CollectionEntry<"contact">;
const contactIndex = await getListPage("contact", "-index");
const { contact_form_action }: { contact_form_action: string } = config.params;
const { title, description, meta_title, image } = contact.data;
const { title, description, meta_title, image } = contactIndex.data;
if (contactIndex.data.draft) {
return Astro.redirect("/404");
}
---
<Base
@@ -35,6 +35,7 @@ const { title, description, meta_title, image } = contact.data;
class="form-input"
placeholder="John Doe"
type="text"
required
/>
</div>
<div class="mb-6">
@@ -47,6 +48,7 @@ const { title, description, meta_title, image } = contact.data;
class="form-input"
placeholder="john.doe@email.com"
type="email"
required
/>
</div>
<div class="mb-6">
@@ -58,6 +60,7 @@ const { title, description, meta_title, image } = contact.data;
name="message"
class="form-input"
placeholder="Message goes here..."
required
rows="8"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
+5 -28
View File
@@ -1,40 +1,17 @@
---
import ImageMod from "@/components/ImageMod.astro";
import Base from "@/layouts/Base.astro";
import { getListPage } from "@/lib/contentParser.astro";
import { markdownify } from "@/lib/utils/textConverter";
import CallToAction from "@/partials/CallToAction.astro";
import Testimonial from "@/partials/Testimonial.astro";
import type { Button, Feature } from "@/types";
import type { CollectionEntry } from "astro:content";
import { getEntry } from "astro:content";
import { FaCheck } from "react-icons/fa";
interface Homepage {
banner: {
title: string;
content: string;
image: string;
button: Button;
};
features: Feature[];
}
const homepage = await getListPage("homepage", "-index");
const call_to_action = await getListPage("ctaSection", "call-to-action");
const testimonial = await getListPage("testimonialSection", "testimonial");
const homepage = (await getEntry(
"homepage",
"-index"
)) as CollectionEntry<"homepage">;
const testimonial = (await getEntry(
"testimonialSection",
"testimonial"
)) as CollectionEntry<"testimonialSection">;
const call_to_action = (await getEntry(
"ctaSection",
"call-to-action"
)) as CollectionEntry<"ctaSection">;
const { banner, features } = homepage.data as Homepage;
const { banner, features } = homepage.data;
---
<Base>
+4
View File
@@ -57,3 +57,7 @@ code {
blockquote > p {
@apply my-0!;
}
button {
@apply cursor-pointer;
}