mirror of
https://github.com/10h30/astroplate.git
synced 2026-06-05 15:08:00 +09:00
changed the content folder structure && fixed breadcrumps
This commit is contained in:
@@ -9,11 +9,12 @@ const CONTENT_DEPTH = 3;
|
||||
const BLOG_FOLDER = "blog";
|
||||
|
||||
// get data from markdown
|
||||
const getData = (folder, groupDepth) => {
|
||||
const getData = (folder, groupDepth, langIndex = 0) => {
|
||||
// get paths
|
||||
const getPaths = languages
|
||||
.map((lang) => {
|
||||
const dir = path.join(CONTENT_ROOT, lang.contentDir, folder);
|
||||
.map((lang, index) => {
|
||||
const langFolder = lang.contentDir ? lang.contentDir : lang.languageCode;
|
||||
const dir = path.join(CONTENT_ROOT, folder, langFolder);
|
||||
return fs
|
||||
.readdirSync(dir)
|
||||
.filter(
|
||||
@@ -27,7 +28,7 @@ const getData = (folder, groupDepth) => {
|
||||
const isFolder = stats.isDirectory();
|
||||
|
||||
if (isFolder) {
|
||||
return getData(filepath, groupDepth);
|
||||
return getData(filepath, groupDepth, index);
|
||||
} else {
|
||||
const file = fs.readFileSync(filepath, "utf-8");
|
||||
const { data, content } = matter(file);
|
||||
@@ -41,7 +42,7 @@ const getData = (folder, groupDepth) => {
|
||||
const group = pathParts[groupDepth];
|
||||
|
||||
return {
|
||||
lang: lang.languageCode,
|
||||
lang: languages[langIndex].languageCode,
|
||||
group: group,
|
||||
slug: slug,
|
||||
frontmatter: data,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"title": "Astroplate",
|
||||
"base_url": "https://astroplate.netlify.app",
|
||||
"base_path": "/",
|
||||
"trailing_slash": false,
|
||||
"trailing_slash": true,
|
||||
"favicon": "/images/favicon.png",
|
||||
"logo": "/images/logo.png",
|
||||
"logo_darkmode": "/images/logo-darkmode.png",
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const AboutSchema = z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
image: z.string(),
|
||||
draft: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export default AboutSchema;
|
||||
@@ -6,4 +6,4 @@ image: "/images/avatar.png"
|
||||
draft: false
|
||||
---
|
||||
|
||||
L'entreprise elle-même est une entreprise très prospère. Ils ne connaissent pas les bienfaits du corps, ou sauf qu'ils le recevront à d'autres moments, le tout, les temps de travail, qu'il déteste à partir de ce moment mais. Il fuit les plaisirs perçus pour être supposés n'être rien, tout ou, et la douleur est ce qui est la plus grande option, car cela lui est facile, et avec ce que cela s'ensuit, ils lui procurent de la douleur et ainsi de suite ! Car ledit expédient de la vérité repousse le plaisir et empêche la douleur, ils fournissent comme si
|
||||
L'entreprise elle-même est une entreprise très prospère. Ils ne connaissent pas les bienfaits du corps, ou sauf qu'ils le recevront à d'autres moments, le tout, les temps de travail, qu'il déteste à partir de ce moment mais. Il fuit les plaisirs perçus pour être supposés n'être rien, tout ou, et la douleur est ce qui est la plus grande option, car cela lui est facile, et avec ce que cela s'ensuit, ils lui procurent de la douleur et ainsi de suite ! Car ledit expédient de la vérité repousse le plaisir et empêche la douleur, ils fournissent comme si
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
// Author collection schema
|
||||
const authorsCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
email: z.string().optional(),
|
||||
image: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
social: z
|
||||
.array(
|
||||
z
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
icon: z.string().optional(),
|
||||
link: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
)
|
||||
.optional(),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Export collections
|
||||
export const collections = {
|
||||
authors: authorsCollection,
|
||||
};
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
// Post collection schema
|
||||
const blogCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
date: z.date().optional(),
|
||||
image: z.string().optional(),
|
||||
author: z.string().default("Admin"),
|
||||
categories: z.array(z.string()).default(["others"]),
|
||||
tags: z.array(z.string()).default(["others"]),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Pages collection schema
|
||||
const pagesCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
image: z.string().optional(),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Export collections
|
||||
export const collections = {
|
||||
blog: blogCollection,
|
||||
pages: pagesCollection,
|
||||
};
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
const contactCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string(),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
contact: contactCollection,
|
||||
};
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
// Banner schema
|
||||
const bannerSchema = z.object({
|
||||
title: z.string(),
|
||||
content: z.string(),
|
||||
image: z.string(),
|
||||
button: z.object({
|
||||
enable: z.boolean(),
|
||||
label: z.string(),
|
||||
link: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Features schema
|
||||
const featureSchema = z.object({
|
||||
title: z.string(),
|
||||
image: z.string(),
|
||||
content: z.string(),
|
||||
bulletpoints: z.array(z.string()),
|
||||
button: z.object({
|
||||
enable: z.boolean(),
|
||||
label: z.string().optional(),
|
||||
link: z.string().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Main content schema
|
||||
const contentSchema = z.object({
|
||||
banner: bannerSchema,
|
||||
features: z.array(featureSchema),
|
||||
});
|
||||
|
||||
// Define the collection
|
||||
const contentCollection = defineCollection({
|
||||
schema: contentSchema,
|
||||
});
|
||||
|
||||
// Export collections
|
||||
export const collections = {
|
||||
content: contentCollection,
|
||||
};
|
||||
@@ -50,4 +50,4 @@ features:
|
||||
enable: false
|
||||
label: ""
|
||||
link: ""
|
||||
---
|
||||
---
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
const elementsCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string(),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
const privacyCollection = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
meta_title: z.string().optional(),
|
||||
description: z.string(),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
elements: elementsCollection,
|
||||
privacy: privacyCollection,
|
||||
};
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const TestimonialSchema = z.object({
|
||||
name: z.string(),
|
||||
designation: z.string(),
|
||||
avatar: z.string(),
|
||||
content: z.string(),
|
||||
});
|
||||
|
||||
const TestimonialsSchema = z.array(TestimonialSchema);
|
||||
|
||||
const CallToActionSchema = z.object({
|
||||
enable: z.boolean(),
|
||||
title: z.string(),
|
||||
image: z.string(),
|
||||
description: z.string(),
|
||||
button: z.object({
|
||||
enable: z.boolean(),
|
||||
label: z.string(),
|
||||
link: z.string().url(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
Testimonial: TestimonialSchema,
|
||||
Testimonials: TestimonialsSchema,
|
||||
CallToAction: CallToActionSchema,
|
||||
};
|
||||
@@ -18,6 +18,11 @@ const { title, image, date, author, categories } = data.data;
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
||||
|
||||
const slugParts = data.slug.split("/");
|
||||
slugParts[0] = "blog";
|
||||
const modifiedSlug = slugParts.join("/");
|
||||
data.slug = modifiedSlug;
|
||||
---
|
||||
|
||||
<div class="bg-body dark:bg-darkmode-body">
|
||||
|
||||
@@ -11,19 +11,20 @@ if (supportedLang.includes(paths[0])) {
|
||||
lang = paths.shift()!;
|
||||
}
|
||||
|
||||
let baseHref = lang ? `/${lang}` : "/";
|
||||
let parts = [
|
||||
{
|
||||
label: "Home",
|
||||
href: `/${lang}`,
|
||||
href: baseHref,
|
||||
"aria-label":
|
||||
Astro.url.pathname === `/${lang}` || Astro.url.pathname === `/${lang}/`
|
||||
Astro.url.pathname === baseHref || Astro.url.pathname === `${baseHref}/`
|
||||
? "page"
|
||||
: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
paths.forEach((label: string, i: number) => {
|
||||
const href = `/${lang}/${paths.slice(0, i + 1).join("/")}`;
|
||||
const href = `${baseHref}${paths.slice(0, i + 1).join("/")}`;
|
||||
label !== "page" &&
|
||||
parts.push({
|
||||
label: humanize(label.replace(".html", "").replace(/[-_]/g, " ")) || "",
|
||||
|
||||
@@ -67,7 +67,7 @@ const { testimonial } = Astro.props;
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<div class="testimonial-slider-pagination mt-9 flex items-center justify-center text-center" />
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import config from "@/config/config.json";
|
||||
import languages from "@/config/language.json";
|
||||
|
||||
export const getSinglePage = async <C extends CollectionKey>(
|
||||
export const getSP = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap | undefined
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
@@ -40,7 +40,7 @@ export const getSinglePage = async <C extends CollectionKey>(
|
||||
return removeDrafts;
|
||||
};
|
||||
|
||||
export const getListPage = async <C extends CollectionKey>(
|
||||
export const getLP = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap | undefined
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
@@ -67,4 +67,68 @@ export const getListPage = async <C extends CollectionKey>(
|
||||
|
||||
return pages;
|
||||
};
|
||||
|
||||
export const getSinglePage = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap | undefined,
|
||||
subCollectionName?: string
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
const { default_language } = config.settings;
|
||||
|
||||
const selectedLanguageCode = lang || default_language;
|
||||
|
||||
const language = languages.find(
|
||||
(l: any) => l.languageCode === selectedLanguageCode
|
||||
);
|
||||
|
||||
if (!language) {
|
||||
throw new Error("Language not found");
|
||||
}
|
||||
|
||||
const { contentDir } = language;
|
||||
|
||||
const path = subCollectionName
|
||||
? `${contentDir}/${subCollectionName}`
|
||||
: contentDir;
|
||||
|
||||
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||
collectionName as any,
|
||||
({ id }: any) => {
|
||||
return id.startsWith(path) && !id.endsWith("-index.md");
|
||||
}
|
||||
)) as CollectionEntry<C>[];
|
||||
|
||||
// @ts-ignore
|
||||
const removeDrafts = pages.filter((data) => !data.data.draft);
|
||||
|
||||
return removeDrafts;
|
||||
};
|
||||
|
||||
export const getListPage = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap | undefined
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
const { default_language } = config.settings;
|
||||
|
||||
const selectedLanguageCode = lang || default_language;
|
||||
|
||||
const language = languages.find(
|
||||
(l: any) => l.languageCode == selectedLanguageCode
|
||||
);
|
||||
|
||||
if (!language) {
|
||||
throw new Error("Language not found");
|
||||
}
|
||||
|
||||
const { contentDir } = language;
|
||||
|
||||
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||
collectionName as any,
|
||||
({ id }: any) => {
|
||||
return id.startsWith(contentDir);
|
||||
}
|
||||
)) as CollectionEntry<C>[];
|
||||
|
||||
return pages;
|
||||
};
|
||||
---
|
||||
|
||||
@@ -16,7 +16,7 @@ export const getTaxonomy = async (collection: string, name: string) => {
|
||||
actualCollection = language.contentDir;
|
||||
} else {
|
||||
const defaultLanguageMatch = languages.find(
|
||||
(l) => l.languageCode === default_language,
|
||||
(l) => l.languageCode === default_language
|
||||
);
|
||||
if (defaultLanguageMatch) {
|
||||
actualCollection = defaultLanguageMatch.contentDir;
|
||||
@@ -24,10 +24,10 @@ export const getTaxonomy = async (collection: string, name: string) => {
|
||||
}
|
||||
|
||||
const singlePages = await getCollection(
|
||||
actualCollection as keyof ContentEntryMap,
|
||||
"blog" as keyof ContentEntryMap,
|
||||
({ id }: any) => {
|
||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
||||
},
|
||||
return id.startsWith(actualCollection) && !id.endsWith("-index.md");
|
||||
}
|
||||
);
|
||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||
let taxonomies: string[] = [];
|
||||
@@ -52,7 +52,7 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
|
||||
actualCollection = language.contentDir;
|
||||
} else {
|
||||
const defaultLanguageMatch = languages.find(
|
||||
(l) => l.languageCode === default_language,
|
||||
(l) => l.languageCode === default_language
|
||||
);
|
||||
if (defaultLanguageMatch) {
|
||||
actualCollection = defaultLanguageMatch.contentDir;
|
||||
@@ -60,10 +60,10 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
|
||||
}
|
||||
|
||||
const singlePages = await getCollection(
|
||||
actualCollection as keyof ContentEntryMap,
|
||||
"blog" as keyof ContentEntryMap,
|
||||
({ id }: any) => {
|
||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
||||
},
|
||||
return id.startsWith(actualCollection) && !id.endsWith("-index.md");
|
||||
}
|
||||
);
|
||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||
let taxonomies: string[] = [];
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function getStaticPaths() {
|
||||
supportedLang.map(async (lang) => {
|
||||
const pages = await getSinglePage("pages", lang as keyof ContentEntryMap);
|
||||
|
||||
return pages.map((page: any) => ({
|
||||
return pages.map((page) => ({
|
||||
params: {
|
||||
lang: lang || undefined,
|
||||
regular: page.slug.split("/").pop(),
|
||||
|
||||
@@ -4,7 +4,7 @@ import Base from "@/layouts/Base.astro";
|
||||
import { getListPage } from "@/lib/contentParser.astro";
|
||||
import { supportedLang } from "@/lib/utils/languageParser";
|
||||
import { markdownify } from "@/lib/utils/textConverter";
|
||||
import type { ContentCollectionKey, ContentEntryMap } from "astro:content";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
|
||||
export function getStaticPaths() {
|
||||
const paths = supportedLang.map((lang) => ({
|
||||
@@ -14,10 +14,7 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const about: any = await getListPage(
|
||||
"about" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
const about = await getListPage("about", lang as keyof ContentEntryMap);
|
||||
|
||||
const { Content } = await about[0].render();
|
||||
const { title, description, meta_title, image } = about[0].data;
|
||||
|
||||
@@ -14,12 +14,12 @@ export async function getStaticPaths() {
|
||||
|
||||
const paths = await Promise.all(
|
||||
supportedLang.map(async (lang) => {
|
||||
const authors: any = await getSinglePage(
|
||||
const authors = await getSinglePage(
|
||||
COLLECTION_FOLDER,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
|
||||
return authors.map((author: any) => ({
|
||||
return authors.map((author) => ({
|
||||
params: {
|
||||
lang: lang || undefined,
|
||||
single: author.slug.split("/").pop(),
|
||||
@@ -42,7 +42,7 @@ const { Content } = await author.render();
|
||||
const BLOG_FOLDER = "blog";
|
||||
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
|
||||
const postFilterByAuthor = posts.filter(
|
||||
(post: any) => slugify(post.data.author) === slugify(title)
|
||||
(post) => slugify(post.data.author) === slugify(title)
|
||||
);
|
||||
---
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const authorIndex: any = await getListPage(
|
||||
const authorIndex = await getListPage(
|
||||
COLLECTION_FOLDER,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
|
||||
@@ -10,12 +10,12 @@ export async function getStaticPaths() {
|
||||
|
||||
const paths = await Promise.all(
|
||||
supportedLang.map(async (lang) => {
|
||||
const posts: any = await getSinglePage(
|
||||
const posts = await getSinglePage(
|
||||
BLOG_FOLDER,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
|
||||
return posts.map((post: any) => ({
|
||||
return posts.map((post) => ({
|
||||
params: {
|
||||
lang: lang || undefined,
|
||||
single: post.slug.split("/").pop(),
|
||||
|
||||
@@ -19,7 +19,7 @@ export function getStaticPaths() {
|
||||
}
|
||||
const { lang } = Astro.params;
|
||||
const BLOG_FOLDER = "blog";
|
||||
const postIndex: any = await getListPage(
|
||||
const postIndex = await getListPage(
|
||||
BLOG_FOLDER,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
|
||||
@@ -4,7 +4,6 @@ import Base from "@/layouts/Base.astro";
|
||||
import { getListPage } from "@/lib/contentParser.astro";
|
||||
import { getTranslations, supportedLang } from "@/lib/utils/languageParser";
|
||||
import PageHeader from "@/partials/PageHeader.astro";
|
||||
import type { CollectionKey } from "astro:content";
|
||||
import { type ContentEntryMap } from "astro:content";
|
||||
|
||||
export function getStaticPaths() {
|
||||
@@ -15,10 +14,7 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const contact: any = await getListPage(
|
||||
"contact" as CollectionKey,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
const contact = await getListPage("contact", lang as keyof ContentEntryMap);
|
||||
|
||||
const { contact_form_action }: { contact_form_action: string } = config.params;
|
||||
const { title, description, meta_title, image } = contact[0].data;
|
||||
|
||||
@@ -6,18 +6,9 @@ import { supportedLang } from "@/lib/utils/languageParser";
|
||||
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 { ContentCollectionKey, ContentEntryMap } from "astro:content";
|
||||
import type { Feature } from "@/types";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import { FaCheck } from "react-icons/fa";
|
||||
interface Homepage {
|
||||
banner: {
|
||||
title: string;
|
||||
content: string;
|
||||
image: string;
|
||||
button: Button;
|
||||
};
|
||||
features: Feature[];
|
||||
}
|
||||
|
||||
export function getStaticPaths() {
|
||||
const paths = supportedLang.map((lang) => ({
|
||||
@@ -27,20 +18,19 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const homepage: any = await getListPage(
|
||||
"homepage" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap
|
||||
);
|
||||
const { banner, features }: Homepage = homepage[0].data;
|
||||
const homepage = await getListPage("homepage", lang as keyof ContentEntryMap);
|
||||
const { banner, features } = homepage[0].data;
|
||||
|
||||
const testimonial = await getSinglePage(
|
||||
"sections/testimonial" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap
|
||||
"sections",
|
||||
lang as keyof ContentEntryMap,
|
||||
"testimonial"
|
||||
);
|
||||
|
||||
const call_to_action = await getSinglePage(
|
||||
"sections/call-to-action" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap
|
||||
"sections",
|
||||
lang as keyof ContentEntryMap,
|
||||
"call-to-action"
|
||||
);
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user