Compare commits
46 Commits
astro/setu
...
dcaf313745
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcaf313745 | ||
|
|
0d329d1e9c | ||
|
|
d5c8b166bc | ||
|
|
266e5d1b35 | ||
|
|
94aa8c356e | ||
|
|
a5efc7415b | ||
|
|
50dc6ec4c0 | ||
|
|
423a4b74dd | ||
|
|
a0f2c93a23 | ||
|
|
d53df4b898 | ||
|
|
b6f3fdd15e | ||
|
|
4bb3fa3671 | ||
|
|
cb4cb9e578 | ||
|
|
6a14aca8ff | ||
|
|
21d5ba23a4 | ||
|
|
bc11be5669 | ||
|
|
4f3cc40041 | ||
|
|
ff811327bb | ||
|
|
6e26af71f4 | ||
|
|
6dcac27de8 | ||
|
|
c1b89c5823 | ||
|
|
ad73ab5672 | ||
|
|
44437c766b | ||
|
|
a5bc93f4d6 | ||
|
|
52d8102d67 | ||
|
|
8f2e3bcde1 | ||
|
|
f5c25dea75 | ||
|
|
4d220e1be7 | ||
|
|
3317926f61 | ||
|
|
4d56dce1af | ||
|
|
2411c6fdc8 | ||
|
|
a1b202686f | ||
|
|
8f0ede76f8 | ||
|
|
f971e84f17 | ||
|
|
640097c072 | ||
|
|
b62865cf04 | ||
|
|
403f8146d9 | ||
|
|
dc22676254 | ||
|
|
5ac9285248 | ||
|
|
e23c077a05 | ||
|
|
f914b7db1c | ||
|
|
770198bb5b | ||
|
|
025a84b2ef | ||
|
|
5caf0424cc | ||
|
|
3865b4b089 | ||
| 231b8cddc3 |
2
astro/.env.example
Normal file
2
astro/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DIRECTUS_URL="https://"
|
||||||
|
DIRECTUS_TOKEN=""
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
import preact from '@astrojs/preact';
|
import preact from '@astrojs/preact';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
import graphql from '@rollup/plugin-graphql';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
|
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()]
|
plugins: [tailwindcss(), graphql()]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
2097
astro/package-lock.json
generated
2097
astro/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,11 +11,22 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/preact": "^4.1.3",
|
"@astrojs/preact": "^4.1.3",
|
||||||
"@directus/sdk": "^21.2.0",
|
"@directus/sdk": "^21.2.0",
|
||||||
|
"@rollup/plugin-graphql": "^2.0.5",
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.1",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
|
"markdown-it": "^14.1.1",
|
||||||
|
"markdown-it-highlightjs": "^4.3.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
|
"minify-xml": "^4.5.2",
|
||||||
"preact": "^10.28.4",
|
"preact": "^10.28.4",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"tailwindcss": "^4.2.1"
|
"tailwindcss": "^4.2.1",
|
||||||
|
"tslib": "^2.8.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
|
"@types/md5": "^2.3.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
astro/src/components/blogs/BlogIndex.astro
Normal file
9
astro/src/components/blogs/BlogIndex.astro
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
page: BlogIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div>Blog Index</div>
|
||||||
9
astro/src/components/projects/ProjectIndex.astro
Normal file
9
astro/src/components/projects/ProjectIndex.astro
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
page: ProjectIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div>Project Index</div>
|
||||||
32
astro/src/components/web/Hero.astro
Normal file
32
astro/src/components/web/Hero.astro
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
hero: HeroComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hero = Astro.props.hero;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div id={`hero-${hero.id}`} class="flex w-full">
|
||||||
|
<div class="flex w-full h-screen static">
|
||||||
|
<Image
|
||||||
|
src={hero.backgroundImage.url}
|
||||||
|
width={hero.backgroundImage.width}
|
||||||
|
height={hero.backgroundImage.height}
|
||||||
|
class="flex w-full h-screen object-cover z-1"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="absolute flex items-center w-full h-screen bg-[#00000082] z-10">
|
||||||
|
<div class="absolute text-white lg:left-40 lg:p-8 p-16 z-30">
|
||||||
|
<div class="flex flex-col gap-2.5 text-left">
|
||||||
|
<h1 class="text-white font-bold md:text-8xl sm:text-7xl text-6xl w-fit">{hero.title}</h1>
|
||||||
|
{ hero.text !== null && (
|
||||||
|
<div class="lg:text-2xl text-lg max-w-170">{hero.text}</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
37
astro/src/components/web/TextWithImage.astro
Normal file
37
astro/src/components/web/TextWithImage.astro
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
import { markdownToHtml } from '@/lib/markdown';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
textWithImage: TextWithImageComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const textWithImage = Astro.props.textWithImage;
|
||||||
|
|
||||||
|
const imageSize = () => {
|
||||||
|
if (textWithImage.imageSize === "small") return "aspect-2/1";
|
||||||
|
else if (textWithImage.imageSize === "medium") return "aspect-26/17";
|
||||||
|
else return "aspect-39/29";
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={`textwithimage-${textWithImage.id}`}
|
||||||
|
class={`flex ${textWithImage.imageSide === "right" ? "lg:flex-row flex-col" : "lg:flex-row-reverse flex-col"} justify-between items-center py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18`}
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-2.5 lg:w-[50%] w-full">
|
||||||
|
<h2 class="text-5xl font-bold">{textWithImage.title}</h2>
|
||||||
|
{ textWithImage.text !== null && (
|
||||||
|
<div set:html={markdownToHtml(textWithImage.text)}></div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
<div class="lg:w-[50%] w-full">
|
||||||
|
<Image
|
||||||
|
src={textWithImage.image.url}
|
||||||
|
width={textWithImage.image.width}
|
||||||
|
height={textWithImage.image.height}
|
||||||
|
class={`rounded-2xl shadow-sm ${imageSize()} object-cover`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
14
astro/src/components/web/WallOfText.astro
Normal file
14
astro/src/components/web/WallOfText.astro
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
wallOfText: WallOfTextComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallOfText = Astro.props.wallOfText;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div id={`walloftext-${wallOfText.id}`} class="flex flex-col py-12 px-12 container mx-auto gap-4">
|
||||||
|
<h2 class="text-5xl font-bold">{wallOfText.title}</h2>
|
||||||
|
<div set:html={markdownToHtml(wallOfText.text)}></div>
|
||||||
|
</div>
|
||||||
23
astro/src/components/webpage/Webpage.astro
Normal file
23
astro/src/components/webpage/Webpage.astro
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
import Hero from '../web/Hero.astro';
|
||||||
|
import TextWithImage from '../web/TextWithImage.astro';
|
||||||
|
import WallOfText from '../web/WallOfText.astro';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
webpage: WebpageComponent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const components = Astro.props.webpage;
|
||||||
|
|
||||||
|
console.log(Astro.props.webpage);
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{ components.map((component) => (
|
||||||
|
<Fragment>
|
||||||
|
{ component.component === "Hero" && <Hero hero={component} /> }
|
||||||
|
{ component.component === "TextWithImage" && <TextWithImage textWithImage={component} /> }
|
||||||
|
{ component.component === "WallOfText" && <WallOfText wallOfText={component} /> }
|
||||||
|
</Fragment>
|
||||||
|
)) }
|
||||||
|
</div>
|
||||||
142
astro/src/content/blogs/blogs.ts
Normal file
142
astro/src/content/blogs/blogs.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from 'graphql';
|
||||||
|
import getBlogs from '@/graphql/blogs/getBlogs.graphql';
|
||||||
|
import getBlogPost from '@/graphql/blogs/getBlog.graphql';
|
||||||
|
import { formatDate } from "@/lib/dates";
|
||||||
|
|
||||||
|
export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getBlogs), {
|
||||||
|
date: formatDate(new Date(), "%Y-%M-%D")
|
||||||
|
});
|
||||||
|
|
||||||
|
let blogs: BlogPost[] = [];
|
||||||
|
|
||||||
|
result["Blogs"].forEach((blogRecord: any) => {
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.blog.lastModified.toISOString(),
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
blogRecord["date_created"],
|
||||||
|
blogRecord["date_updated"],
|
||||||
|
blogRecord["search_engine"][0]["date_created"],
|
||||||
|
blogRecord["search_engine"][0]["date_updated"],
|
||||||
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const blog: BlogPost = {
|
||||||
|
type: "BlogPost",
|
||||||
|
id: blogRecord["id"],
|
||||||
|
lastModified: new Date(),
|
||||||
|
title: blogRecord["title"],
|
||||||
|
content: blogRecord["content"],
|
||||||
|
date: blogRecord["date"],
|
||||||
|
url: blogRecord["url"],
|
||||||
|
searchEngine: {
|
||||||
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
|
allowCrawlers: blogRecord["search_engine"][0]["allow_crawler"],
|
||||||
|
canonical: blogRecord["search_engine"][0]["canonical"],
|
||||||
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
blogRecord["tags"].forEach((tagRecord: any) => {
|
||||||
|
blog["tags"].push({
|
||||||
|
text: tagRecord["Tags_id"]["text"],
|
||||||
|
code: tagRecord["Tags_id"]["code"],
|
||||||
|
color: tagRecord["Tags_id"]["color"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_created"]);
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
blog.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
blog.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
blogs.push(blog);
|
||||||
|
});
|
||||||
|
|
||||||
|
return blogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getBlog(settings: GlobalSettings, route: string): Promise<BlogPost> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getBlogPost), {
|
||||||
|
route: route
|
||||||
|
});
|
||||||
|
|
||||||
|
const blogRecord = result["Blogs"][0];
|
||||||
|
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.blog.lastModified.toISOString(),
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
blogRecord["date_created"],
|
||||||
|
blogRecord["date_updated"],
|
||||||
|
blogRecord["search_engine"][0]["date_created"],
|
||||||
|
blogRecord["search_engine"][0]["date_updated"],
|
||||||
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const blog: BlogPost = {
|
||||||
|
type: "BlogPost",
|
||||||
|
exists: true,
|
||||||
|
id: blogRecord["id"],
|
||||||
|
lastModified: new Date(),
|
||||||
|
title: blogRecord["title"],
|
||||||
|
content: blogRecord["content"],
|
||||||
|
date: blogRecord["date"],
|
||||||
|
url: blogRecord["url"],
|
||||||
|
searchEngine: {
|
||||||
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
|
allowCrawlers: blogRecord["search_engine"][0]["allow_crawler"],
|
||||||
|
canonical: blogRecord["search_engine"][0]["canonical"],
|
||||||
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
blogRecord["tags"].forEach((tagRecord: any) => {
|
||||||
|
blog["tags"].push({
|
||||||
|
text: tagRecord["Tags_id"]["text"],
|
||||||
|
code: tagRecord["Tags_id"]["code"],
|
||||||
|
color: tagRecord["Tags_id"]["color"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_created"]);
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
blog.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
blog.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return blog;
|
||||||
|
}
|
||||||
357
astro/src/content/pages/pages.ts
Normal file
357
astro/src/content/pages/pages.ts
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from 'graphql';
|
||||||
|
import { formatDate } from "@/lib/dates";
|
||||||
|
import getAllPages from "@/graphql/pages/getAllPages.graphql";
|
||||||
|
import getPage from "@/graphql/pages/getPage.graphql";
|
||||||
|
import { getImageUrl } from "@/lib/images";
|
||||||
|
|
||||||
|
export function dataToPage(pageRecord: any): WebPage {
|
||||||
|
let dates: string[] = [
|
||||||
|
pageRecord["date_created"],
|
||||||
|
pageRecord["date_updated"],
|
||||||
|
pageRecord["search_engine"][0]["date_created"],
|
||||||
|
pageRecord["search_engine"][0]["date_updated"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const searchEngine = pageRecord["search_engine"][0];
|
||||||
|
|
||||||
|
let components: WebpageComponent[] = [];
|
||||||
|
|
||||||
|
pageRecord["components"].forEach((componentRecord: any) => {
|
||||||
|
const component = componentRecord["item"];
|
||||||
|
|
||||||
|
switch (componentRecord["item"]["__typename"]) {
|
||||||
|
case "Hero":
|
||||||
|
let heroComponent: HeroComponent = {
|
||||||
|
component: "Hero",
|
||||||
|
id: component["hero_id"],
|
||||||
|
title: component["hero_title"],
|
||||||
|
text: component["hero_text"],
|
||||||
|
backgroundImage: {
|
||||||
|
url: getImageUrl(component["background_image"]["filename_disk"]),
|
||||||
|
width: component["background_image"]["width"],
|
||||||
|
height: component["background_image"]["height"]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(heroComponent);
|
||||||
|
dates.push(component["hero_created"]);
|
||||||
|
dates.push(component["hero_updated"]);
|
||||||
|
dates.push(component["background_image"]["created_on"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Text_With_Side_Image":
|
||||||
|
let textWithImageComponent: TextWithImageComponent = {
|
||||||
|
component: "TextWithImage",
|
||||||
|
id: component["twsi_id"],
|
||||||
|
title: component["twsi_title"],
|
||||||
|
text: component["twsi_text"],
|
||||||
|
imageSide: component["twsi_image_side"],
|
||||||
|
imageSize: component["twsi_image_size"],
|
||||||
|
image: {
|
||||||
|
url: getImageUrl(component["image"]["filename_disk"]),
|
||||||
|
width: component["image"]["width"],
|
||||||
|
height: component["image"]["height"]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(textWithImageComponent);
|
||||||
|
dates.push(component["twsi_created"]);
|
||||||
|
dates.push(component["twsi_updated"]);
|
||||||
|
dates.push(component["image"]["created_on"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Wall_Of_Text":
|
||||||
|
let wallOfTextComponent: WallOfTextComponent = {
|
||||||
|
component: "WallOfText",
|
||||||
|
id: component["wot_id"],
|
||||||
|
title: component["wot_title"],
|
||||||
|
text: component["wot_text"]
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(wallOfTextComponent);
|
||||||
|
dates.push(component["wot_created"]);
|
||||||
|
dates.push(component["wot_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Frequently_Asked_Questions":
|
||||||
|
let faqComponent: FrequentlyAskedQuestionsComponent = {
|
||||||
|
component: "FrequentlyAskedQuestions",
|
||||||
|
id: component["faq_id"],
|
||||||
|
title: component["faq_title"],
|
||||||
|
text: component["faq_text"],
|
||||||
|
questions: []
|
||||||
|
};
|
||||||
|
|
||||||
|
component["questions"].forEach((faqQuestionRecord: any) => {
|
||||||
|
faqComponent.questions.push({
|
||||||
|
id: faqQuestionRecord["id"],
|
||||||
|
question: faqQuestionRecord["question"],
|
||||||
|
answer: faqQuestionRecord["answer"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(faqQuestionRecord["date_created"]);
|
||||||
|
dates.push(faqQuestionRecord["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
components.push(faqComponent);
|
||||||
|
dates.push(component["faq_created"]);
|
||||||
|
dates.push(component["faq_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Upcoming_Events":
|
||||||
|
let upcomingEventsComponent: UpcomingEventsComponent = {
|
||||||
|
component: "UpcomingEvents",
|
||||||
|
id: component["ue_id"],
|
||||||
|
title: component["ue_title"],
|
||||||
|
text: component["ue_text"],
|
||||||
|
events: []
|
||||||
|
};
|
||||||
|
|
||||||
|
component["events"].forEach((eventRecord: any) => {
|
||||||
|
upcomingEventsComponent.events.push({
|
||||||
|
id: eventRecord["id"],
|
||||||
|
title: eventRecord["title"],
|
||||||
|
description: eventRecord["description"],
|
||||||
|
location: eventRecord["location"],
|
||||||
|
mapLocation: [
|
||||||
|
eventRecord["map_location"]["coordinates"][1],
|
||||||
|
eventRecord["map_location"]["coordinates"][0]
|
||||||
|
],
|
||||||
|
startDate: eventRecord["start_date"],
|
||||||
|
endDate: eventRecord["end_date"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(eventRecord["date_created"]);
|
||||||
|
dates.push(eventRecord["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
components.push(upcomingEventsComponent);
|
||||||
|
dates.push(component["ue_created"]);
|
||||||
|
dates.push(component["ue_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Equipment_Table":
|
||||||
|
let equipmentTableComponent: EquipmentTableComponent = {
|
||||||
|
component: "EquipmentTable",
|
||||||
|
id: component["et_id"],
|
||||||
|
title: component["et_title"],
|
||||||
|
text: component["et_text"],
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
|
||||||
|
component["items"].forEach((itemRecord: any) => {
|
||||||
|
equipmentTableComponent.items.push({
|
||||||
|
id: itemRecord["id"],
|
||||||
|
title: itemRecord["title"],
|
||||||
|
text: itemRecord["text"],
|
||||||
|
icon: {
|
||||||
|
url: getImageUrl(itemRecord["icon"]["filename_disk"]),
|
||||||
|
width: itemRecord["icon"]["width"],
|
||||||
|
height: itemRecord["icon"]["height"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(itemRecord["date_created"]);
|
||||||
|
dates.push(itemRecord["date_updated"]);
|
||||||
|
dates.push(itemRecord["icon"]["created_on"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
components.push(equipmentTableComponent);
|
||||||
|
dates.push(component["et_created"]);
|
||||||
|
dates.push(component["et_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Review_List":
|
||||||
|
let reviewsComponent: ReviewListComponent = {
|
||||||
|
component: "Reviews",
|
||||||
|
id: component["rl_id"],
|
||||||
|
title: component["rl_title"],
|
||||||
|
text: component["rl_text"],
|
||||||
|
reviews: []
|
||||||
|
};
|
||||||
|
|
||||||
|
component["reviews"].forEach((reviewRecord: any) => {
|
||||||
|
reviewsComponent.reviews.push({
|
||||||
|
id: reviewRecord["id"],
|
||||||
|
name: reviewRecord["name"],
|
||||||
|
review: reviewRecord["review"],
|
||||||
|
stars: reviewRecord["stars"],
|
||||||
|
date: reviewRecord["date"],
|
||||||
|
thumbnail: {
|
||||||
|
url: getImageUrl(reviewRecord["thumbnail"]["filename_disk"]),
|
||||||
|
width: reviewRecord["thumbnail"]["width"],
|
||||||
|
height: reviewRecord["thumbnail"]["height"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(reviewRecord["date_created"]);
|
||||||
|
dates.push(reviewRecord["date_updated"]);
|
||||||
|
dates.push(reviewRecord["thumbnail"]["created_on"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
components.push(reviewsComponent);
|
||||||
|
dates.push(component["rl_created"]);
|
||||||
|
dates.push(component["rl_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Contact":
|
||||||
|
let contactComponent: ContactComponent = {
|
||||||
|
component: "Contact",
|
||||||
|
id: component["c_id"],
|
||||||
|
title: component["c_title"],
|
||||||
|
text: component["c_text"],
|
||||||
|
methods: []
|
||||||
|
};
|
||||||
|
|
||||||
|
component["methods"].forEach((contactMethodRecord: any) => {
|
||||||
|
contactComponent.methods.push({
|
||||||
|
id: contactMethodRecord["id"],
|
||||||
|
title: contactMethodRecord["title"],
|
||||||
|
text: contactMethodRecord["text"],
|
||||||
|
color: contactMethodRecord["color"],
|
||||||
|
icon: {
|
||||||
|
url: getImageUrl(contactMethodRecord["icon"]["filename_disk"]),
|
||||||
|
width: contactMethodRecord["icon"]["width"],
|
||||||
|
height: contactMethodRecord["icon"]["height"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(contactMethodRecord["date_created"]);
|
||||||
|
dates.push(contactMethodRecord["date_updated"]);
|
||||||
|
dates.push(contactMethodRecord["icon"]["created_on"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
components.push(contactComponent);
|
||||||
|
dates.push(component["c_created"]);
|
||||||
|
dates.push(component["c_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Last_Blogs":
|
||||||
|
let lastBlogsComponent: LastBlogsComponent = {
|
||||||
|
component: "LastBlogs",
|
||||||
|
id: component["lb_id"],
|
||||||
|
title: component["lb_title"],
|
||||||
|
readMoreButtonText: component["lb_read_more_button_text"],
|
||||||
|
amount: component["lb_amount"]
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(lastBlogsComponent);
|
||||||
|
dates.push(component["lb_created"]);
|
||||||
|
dates.push(component["lb_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Last_Projects":
|
||||||
|
let lastProjectsComponent: LastProjectsComponent = {
|
||||||
|
component: "LastProjects",
|
||||||
|
id: component["lp_id"],
|
||||||
|
title: component["lp_title"],
|
||||||
|
readMoreButtonText: component["lp_read_more_button_text"],
|
||||||
|
amount: component["lp_amount"]
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(lastProjectsComponent);
|
||||||
|
dates.push(component["lp_created"]);
|
||||||
|
dates.push(component["lp_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Last_Galleries":
|
||||||
|
let lastGalleriesComponent: LastGalleriesComponent = {
|
||||||
|
component: "LastGalleries",
|
||||||
|
id: component["lg_id"],
|
||||||
|
title: component["lg_title"],
|
||||||
|
readMoreButtonText: component["lg_read_more_button_text"],
|
||||||
|
amount: component["lg_amount"]
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(lastGalleriesComponent);
|
||||||
|
dates.push(component["lg_created"]);
|
||||||
|
dates.push(component["lg_updated"]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastModified: Date;
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let page: WebPage = {
|
||||||
|
type: "Webpage",
|
||||||
|
exists: true,
|
||||||
|
id: pageRecord["id"],
|
||||||
|
lastModified: lastModified,
|
||||||
|
url: pageRecord["url"],
|
||||||
|
searchEngine: {
|
||||||
|
title: searchEngine["title"],
|
||||||
|
description: searchEngine["description"],
|
||||||
|
canonical: searchEngine["canonical"],
|
||||||
|
allowCrawlers: searchEngine["allow_crawler"],
|
||||||
|
priority: searchEngine["priority"],
|
||||||
|
thumbnail: {
|
||||||
|
url: getImageUrl(searchEngine["thumbnail"]["filename_disk"]),
|
||||||
|
height: searchEngine["thumbnail"]["height"],
|
||||||
|
width: searchEngine["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: components
|
||||||
|
}
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllWebpages(): Promise<WebPage[]> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getAllPages), {
|
||||||
|
date: formatDate(new Date(), "%Y-%M-%D")
|
||||||
|
});
|
||||||
|
|
||||||
|
let pages: WebPage[] = [];
|
||||||
|
|
||||||
|
result["Pages"].forEach((pageRecord: any) => {
|
||||||
|
pages.push(dataToPage(pageRecord));
|
||||||
|
});
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWebpage(route: string): Promise<WebPage | null> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getPage), {
|
||||||
|
date: formatDate(new Date(), "%Y-%M-%D"),
|
||||||
|
route: route
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result["Pages"].length === 0) {
|
||||||
|
return {
|
||||||
|
type: "Webpage",
|
||||||
|
exists: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = dataToPage(result["Pages"][0]);
|
||||||
|
|
||||||
|
if (!page.exists) {
|
||||||
|
return {
|
||||||
|
type: "Webpage",
|
||||||
|
exists: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...page,
|
||||||
|
type: "Webpage",
|
||||||
|
exists: true
|
||||||
|
}
|
||||||
|
}
|
||||||
155
astro/src/content/photos/albums.ts
Normal file
155
astro/src/content/photos/albums.ts
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import getAlbums from '@/graphql/photos/getAlbums.graphql';
|
||||||
|
import getAlbumItem from '@/graphql/photos/getAlbum.graphql';
|
||||||
|
import { formatDate } from "@/lib/dates";
|
||||||
|
|
||||||
|
export async function getAllAlbums(settings: GlobalSettings): Promise<PhotoAlbum[]> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getAlbums), {
|
||||||
|
date: formatDate(new Date(), "%Y-%M-%D")
|
||||||
|
});
|
||||||
|
|
||||||
|
let albums: PhotoAlbum[] = [];
|
||||||
|
|
||||||
|
result["Photo_Albums"].forEach((albumRecord: any) => {
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
settings.photo.lastModified.toISOString(),
|
||||||
|
albumRecord["date_created"],
|
||||||
|
albumRecord["date_updated"],
|
||||||
|
albumRecord["thumbnail"]["created_on"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const album: PhotoAlbum = {
|
||||||
|
type: "PhotoAlbum",
|
||||||
|
title: albumRecord["title"],
|
||||||
|
description: albumRecord["description"],
|
||||||
|
url: albumRecord["url"],
|
||||||
|
startDate: albumRecord["start_date"],
|
||||||
|
endDate: albumRecord["end_date"],
|
||||||
|
location: albumRecord["location"],
|
||||||
|
category: {
|
||||||
|
id: albumRecord["category"][0]["Photo_Categories_id"]["id"],
|
||||||
|
title: albumRecord["category"][0]["Photo_Categories_id"]["title"],
|
||||||
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
|
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
||||||
|
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url: albumRecord["thumbnail"]["filename_download"],
|
||||||
|
height: albumRecord["thumbnail"]["height"],
|
||||||
|
width: albumRecord["thumbnail"]["width"]
|
||||||
|
},
|
||||||
|
photos: [],
|
||||||
|
lastModified: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
albumRecord["photos"].forEach((photoRecord: any) => {
|
||||||
|
album.photos.push({
|
||||||
|
id: photoRecord["id"],
|
||||||
|
photo: {
|
||||||
|
url: photoRecord["photo"]["filename_disk"],
|
||||||
|
width: photoRecord["photo"]["width"],
|
||||||
|
height: photoRecord["photo"]["height"]
|
||||||
|
},
|
||||||
|
text: photoRecord["text"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(photoRecord["date_created"]);
|
||||||
|
dates.push(photoRecord["date_updated"]);
|
||||||
|
dates.push(photoRecord["photo"]["created_on"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
album.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
album.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
albums.push(album);
|
||||||
|
});
|
||||||
|
|
||||||
|
return albums;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAlbum(settings: GlobalSettings, route: string): Promise<PhotoAlbum> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getAlbumItem), {
|
||||||
|
route: route
|
||||||
|
});
|
||||||
|
|
||||||
|
const albumRecord = result["Photo_Albums"][0];
|
||||||
|
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
settings.photo.lastModified.toISOString(),
|
||||||
|
albumRecord["date_created"],
|
||||||
|
albumRecord["date_updated"],
|
||||||
|
albumRecord["thumbnail"]["created_on"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const album: PhotoAlbum = {
|
||||||
|
type: "PhotoAlbum",
|
||||||
|
title: albumRecord["title"],
|
||||||
|
description: albumRecord["description"],
|
||||||
|
url: albumRecord["url"],
|
||||||
|
startDate: albumRecord["start_date"],
|
||||||
|
endDate: albumRecord["end_date"],
|
||||||
|
location: albumRecord["location"],
|
||||||
|
category: {
|
||||||
|
id: albumRecord["category"][0]["Photo_Categories_id"]["id"],
|
||||||
|
title: albumRecord["category"][0]["Photo_Categories_id"]["title"],
|
||||||
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
|
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
||||||
|
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url: albumRecord["thumbnail"]["filename_download"],
|
||||||
|
height: albumRecord["thumbnail"]["height"],
|
||||||
|
width: albumRecord["thumbnail"]["width"]
|
||||||
|
},
|
||||||
|
photos: [],
|
||||||
|
lastModified: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
albumRecord["photos"].forEach((photoRecord: any) => {
|
||||||
|
album.photos.push({
|
||||||
|
id: photoRecord["id"],
|
||||||
|
photo: {
|
||||||
|
url: photoRecord["photo"]["filename_disk"],
|
||||||
|
width: photoRecord["photo"]["width"],
|
||||||
|
height: photoRecord["photo"]["height"]
|
||||||
|
},
|
||||||
|
text: photoRecord["text"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(photoRecord["date_created"]);
|
||||||
|
dates.push(photoRecord["date_updated"]);
|
||||||
|
dates.push(photoRecord["photo"]["created_on"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
album.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
album.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return album;
|
||||||
|
}
|
||||||
25
astro/src/content/photos/categories.ts
Normal file
25
astro/src/content/photos/categories.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import getCategories from '@/graphql/photos/getCategories.graphql';
|
||||||
|
|
||||||
|
export async function getAllCategories(settings: GlobalSettings): Promise<PhotoAlbumCategory[]> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getCategories));
|
||||||
|
|
||||||
|
let categories: PhotoAlbumCategory[] = [];
|
||||||
|
|
||||||
|
result["Photo_Categories"].forEach((photoCategoryRecord: any) => {
|
||||||
|
categories.push({
|
||||||
|
id: photoCategoryRecord["id"],
|
||||||
|
title: photoCategoryRecord["title"],
|
||||||
|
url: photoCategoryRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: photoCategoryRecord["thumbnail"]["filename_disk"],
|
||||||
|
width: photoCategoryRecord["thumbnail"]["width"],
|
||||||
|
height: photoCategoryRecord["thumbnail"]["height"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
36
astro/src/content/photos/photos.ts
Normal file
36
astro/src/content/photos/photos.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import getPhotos from '@/graphql/photos/getPhotos.graphql';
|
||||||
|
import md5 from "md5";
|
||||||
|
|
||||||
|
export async function getPhotoFromHash(albumUrl: string, hash: string): Promise<PhotoAlbumPhoto | null> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getPhotos), {
|
||||||
|
albumUrl: albumUrl
|
||||||
|
});
|
||||||
|
|
||||||
|
let object: PhotoAlbumPhoto | null = null;
|
||||||
|
|
||||||
|
result["Photo_Albums"][0]["photos"].forEach((photo: any) => {
|
||||||
|
const hashObject = md5(JSON.stringify({
|
||||||
|
id: photo.id,
|
||||||
|
url: photo.photo.filename_disk,
|
||||||
|
width: photo.photo.width,
|
||||||
|
height: photo.photo.height
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (hashObject.substring(hashObject.length - 10) === hash) {
|
||||||
|
object = {
|
||||||
|
id: photo.id,
|
||||||
|
text: photo.text,
|
||||||
|
photo: {
|
||||||
|
url: photo.photo.url,
|
||||||
|
width: photo.photo.width,
|
||||||
|
height: photo.photo.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
143
astro/src/content/projects/projects.ts
Normal file
143
astro/src/content/projects/projects.ts
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { formatDate } from "@/lib/dates";
|
||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import getProjects from '@/graphql/projects/getProjects.graphql';
|
||||||
|
import getProjectPost from '@/graphql/projects/getProject.graphql';
|
||||||
|
|
||||||
|
export async function getAllProjects(settings: GlobalSettings): Promise<ProjectPost[]> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getProjects), {
|
||||||
|
date: formatDate(new Date(), "%Y-%M-%D")
|
||||||
|
});
|
||||||
|
|
||||||
|
let projects: ProjectPost[] = [];
|
||||||
|
|
||||||
|
result["Projects"].forEach((projectRecord: any) => {
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.project.lastModified.toISOString(),
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
projectRecord["date_created"],
|
||||||
|
projectRecord["date_updated"],
|
||||||
|
projectRecord["search_engine"][0]["date_created"],
|
||||||
|
projectRecord["search_engine"][0]["date_updated"],
|
||||||
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const project: ProjectPost = {
|
||||||
|
type: "ProjectPost",
|
||||||
|
exists: true,
|
||||||
|
|
||||||
|
lastModified: new Date(),
|
||||||
|
title: projectRecord["title"],
|
||||||
|
content: projectRecord["content"],
|
||||||
|
date: projectRecord["date"],
|
||||||
|
url: projectRecord["url"],
|
||||||
|
searchEngine: {
|
||||||
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
|
allowCrawlers: projectRecord["search_engine"][0]["allow_crawler"],
|
||||||
|
canonical: projectRecord["search_engine"][0]["canonical"],
|
||||||
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
|
thumbnail: {
|
||||||
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
projectRecord["tags"].forEach((tagRecord: any) => {
|
||||||
|
project["tags"].push({
|
||||||
|
text: tagRecord["Tags_id"]["text"],
|
||||||
|
code: tagRecord["Tags_id"]["code"],
|
||||||
|
color: tagRecord["Tags_id"]["color"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_created"]);
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
project.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
project.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
projects.push(project);
|
||||||
|
});
|
||||||
|
|
||||||
|
return projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getProject(settings: GlobalSettings, route: string): Promise<ProjectPost> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getProjectPost), {
|
||||||
|
route: route
|
||||||
|
});
|
||||||
|
|
||||||
|
const projectRecord = result["Projects"][0];
|
||||||
|
|
||||||
|
let dates: string[] = [
|
||||||
|
settings.project.lastModified.toISOString(),
|
||||||
|
settings.website.lastModified.toISOString(),
|
||||||
|
projectRecord["date_created"],
|
||||||
|
projectRecord["date_updated"],
|
||||||
|
projectRecord["search_engine"][0]["date_created"],
|
||||||
|
projectRecord["search_engine"][0]["date_updated"],
|
||||||
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const project: ProjectPost = {
|
||||||
|
type: "ProjectPost",
|
||||||
|
exists: true,
|
||||||
|
|
||||||
|
lastModified: new Date(),
|
||||||
|
title: projectRecord["title"],
|
||||||
|
content: projectRecord["content"],
|
||||||
|
date: projectRecord["date"],
|
||||||
|
url: projectRecord["url"],
|
||||||
|
searchEngine: {
|
||||||
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
|
allowCrawlers: projectRecord["search_engine"][0]["allow_crawler"],
|
||||||
|
canonical: projectRecord["search_engine"][0]["canonical"],
|
||||||
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
|
thumbnail: {
|
||||||
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
projectRecord["tags"].forEach((tagRecord: any) => {
|
||||||
|
project["tags"].push({
|
||||||
|
text: tagRecord["Tags_id"]["text"],
|
||||||
|
code: tagRecord["Tags_id"]["code"],
|
||||||
|
color: tagRecord["Tags_id"]["color"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_created"]);
|
||||||
|
dates.push(tagRecord["Tags_id"]["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
project.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
project.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return project;
|
||||||
|
}
|
||||||
15
astro/src/content/settings/robots.ts
Normal file
15
astro/src/content/settings/robots.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from 'graphql';
|
||||||
|
import getRobotsQuery from '@/graphql/settings/robots.graphql';
|
||||||
|
|
||||||
|
export async function getRobotsSettings(): Promise<RobotsSettings> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getRobotsQuery));
|
||||||
|
|
||||||
|
const robotsResult = result["Robots"];
|
||||||
|
|
||||||
|
return {
|
||||||
|
crawlers: robotsResult["crawlers"],
|
||||||
|
extraContent: robotsResult["extra_content"]
|
||||||
|
};
|
||||||
|
}
|
||||||
169
astro/src/content/settings/settings.ts
Normal file
169
astro/src/content/settings/settings.ts
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { print } from 'graphql';
|
||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import getSettingsQuery from '@/graphql/settings/settings.graphql';
|
||||||
|
|
||||||
|
export async function getSettings(): Promise<GlobalSettings> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getSettingsQuery));
|
||||||
|
|
||||||
|
const websiteResults = result["Website_Settings"];
|
||||||
|
const websiteSettings: WebsiteSettings = {
|
||||||
|
domainName: websiteResults["domain_name"],
|
||||||
|
titleTemplate: websiteResults["title_template"],
|
||||||
|
applicationName: websiteResults["application_name"],
|
||||||
|
colors: {
|
||||||
|
primary: websiteResults["primary_color"],
|
||||||
|
secondary: websiteResults["secondary_color"]
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
name: websiteResults["author_name"],
|
||||||
|
url: websiteResults["author_url"]
|
||||||
|
},
|
||||||
|
owner: websiteResults["owner"],
|
||||||
|
designer: websiteResults["designer"],
|
||||||
|
developer: websiteResults["developer"],
|
||||||
|
copyright: websiteResults["copyright"],
|
||||||
|
twitter: {
|
||||||
|
id: websiteResults["twitter_id"],
|
||||||
|
handle: websiteResults["twitter_handle"]
|
||||||
|
},
|
||||||
|
lastModified: websiteResults["date_updated"] !== null ?
|
||||||
|
new Date(websiteResults["date_updated"]) :
|
||||||
|
new Date(websiteResults["date_created"])
|
||||||
|
};
|
||||||
|
|
||||||
|
const blogResults = result["Blog_Settings"];
|
||||||
|
const blogSettings: BlogSettings = {
|
||||||
|
enabled: blogResults["enabled"],
|
||||||
|
title: blogResults["title"],
|
||||||
|
subtext: blogResults["subtext"],
|
||||||
|
indexRouteTemplate: blogResults["index_route_template"],
|
||||||
|
blogRouteTemplate: blogResults["blog_route_template"],
|
||||||
|
lastModified: blogResults["date_updated"] !== null ?
|
||||||
|
new Date(blogResults["date_updated"]) :
|
||||||
|
new Date(blogResults["date_created"])
|
||||||
|
};
|
||||||
|
|
||||||
|
const projectResults = result["Project_Settings"];
|
||||||
|
const projectSettings: ProjectSettings = {
|
||||||
|
enabled: projectResults["enabled"],
|
||||||
|
title: projectResults["title"],
|
||||||
|
subtext: projectResults["subtext"],
|
||||||
|
indexRouteTemplate: projectResults["index_route_template"],
|
||||||
|
projectRouteTemplate: projectResults["project_route_template"],
|
||||||
|
lastModified: projectResults["date_updated"] !== null ?
|
||||||
|
new Date(projectResults["date_updated"]) :
|
||||||
|
new Date(projectResults["date_created"])
|
||||||
|
};
|
||||||
|
|
||||||
|
const photoResults = result["Photo_Settings"];
|
||||||
|
let photoResultsLastModifiedTimestamps: string[] = [
|
||||||
|
photoResults["date_created"],
|
||||||
|
photoResults["date_updated"],
|
||||||
|
photoResults["category_icons"]["date_created"],
|
||||||
|
photoResults["category_icons"]["date_updated"],
|
||||||
|
photoResults["category_icons"]["photos_icon"]["created_on"],
|
||||||
|
photoResults["category_icons"]["location_icon"]["created_on"],
|
||||||
|
photoResults["category_icons"]["date_icon"]["created_on"],
|
||||||
|
photoResults["photo_icons"]["date_created"],
|
||||||
|
photoResults["photo_icons"]["date_updated"],
|
||||||
|
photoResults["photo_icons"]["previous_icon"]["created_on"],
|
||||||
|
photoResults["photo_icons"]["next_icon"]["created_on"],
|
||||||
|
photoResults["photo_icons"]["close_icon"]["created_on"],
|
||||||
|
photoResults["photo_icons"]["download_icon"]["created_on"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const photoResultsLastModified = photoResultsLastModifiedTimestamps.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
const photoSettings: WebsitePhotoSettings = {
|
||||||
|
enabled: photoResults["enabled"],
|
||||||
|
categoryIndex: {
|
||||||
|
indexRouteTemplate: photoResults["categories_index_route_template_url"]
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
routeTemplate: photoResults["category_route_template_url"],
|
||||||
|
perPage: photoResults["albums_per_category_page"],
|
||||||
|
icons: {
|
||||||
|
photos: {
|
||||||
|
url: photoResults["category_icons"]["photos_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["photos_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["photos_icon"]["width"]
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
url: photoResults["category_icons"]["location_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["location_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["location_icon"]["width"]
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
url: photoResults["category_icons"]["date_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["date_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["date_icon"]["width"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
routeTemplate: photoResults["album_route_template_url"],
|
||||||
|
perPage: photoResults["photos_per_album_page"]
|
||||||
|
},
|
||||||
|
photo: {
|
||||||
|
routeTemplate: photoResults["photo_route_template_url"],
|
||||||
|
icons: {
|
||||||
|
previous: {
|
||||||
|
url: photoResults["photo_icons"]["previous_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["previous_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["previous_icon"]["width"]
|
||||||
|
},
|
||||||
|
next: {
|
||||||
|
url: photoResults["photo_icons"]["next_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["next_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["next_icon"]["width"]
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
url: photoResults["photo_icons"]["close_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["close_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["close_icon"]["width"]
|
||||||
|
},
|
||||||
|
download: {
|
||||||
|
url: photoResults["photo_icons"]["download_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["download_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["download_icon"]["width"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lastModified: new Date(photoResultsLastModified[0])
|
||||||
|
};
|
||||||
|
|
||||||
|
const sitemapResults = result["Sitemap_Settings"];
|
||||||
|
const sitemapSettings: SitemapSettings = {
|
||||||
|
perPage: sitemapResults["per_page"],
|
||||||
|
lastModified: sitemapResults["date_updated"] !== null ?
|
||||||
|
new Date(sitemapResults["date_updated"]) :
|
||||||
|
new Date(sitemapResults["date_created"])
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginResults = result["Plugin_Settings"];
|
||||||
|
const pluginSettings: PluginSettings = {
|
||||||
|
swetrix: {
|
||||||
|
id: pluginResults["swetrix_id"],
|
||||||
|
url: pluginResults["swetrix_url"]
|
||||||
|
},
|
||||||
|
lastModified: pluginResults["date_updated"] !== null ?
|
||||||
|
new Date(pluginResults["date_updated"]) :
|
||||||
|
new Date(pluginResults["date_created"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluginResults["swetrix_id"] === null && pluginResults["swetrix_url"] === null) {
|
||||||
|
pluginSettings.swetrix = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
website: websiteSettings,
|
||||||
|
blog: blogSettings,
|
||||||
|
project: projectSettings,
|
||||||
|
photo: photoSettings,
|
||||||
|
sitemap: sitemapSettings,
|
||||||
|
plugins: pluginSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
8
astro/src/env.d.ts
vendored
Normal file
8
astro/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly DIRECTUS_TOKEN: string;
|
||||||
|
readonly DIRECTUS_URL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
5
astro/src/graphql.d.ts
vendored
Normal file
5
astro/src/graphql.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.graphql' {
|
||||||
|
import { DocumentNode } from 'graphql';
|
||||||
|
const Schema: DocumentNode;
|
||||||
|
export default Schema;
|
||||||
|
}
|
||||||
39
astro/src/graphql/blogs/getBlog.graphql
Normal file
39
astro/src/graphql/blogs/getBlog.graphql
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
query getAllBlogs($route: String!) {
|
||||||
|
Blogs(sort: ["-date", "-date_created"], filter: { status: { _eq: "published" }, url: { _eq: $route } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
date,
|
||||||
|
content,
|
||||||
|
tags {
|
||||||
|
Tags_id {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
code,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
astro/src/graphql/blogs/getBlogs.graphql
Normal file
39
astro/src/graphql/blogs/getBlogs.graphql
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
query getAllBlogs($date: String!) {
|
||||||
|
Blogs(sort: ["-date", "-date_created"], filter: { status: { _eq: "published" }, date: { _lte: $date } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
date,
|
||||||
|
content,
|
||||||
|
tags {
|
||||||
|
Tags_id {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
code,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
217
astro/src/graphql/pages/getAllPages.graphql
Normal file
217
astro/src/graphql/pages/getAllPages.graphql
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
query getAllPages($date: String!) {
|
||||||
|
Pages(filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
url,
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
},
|
||||||
|
components {
|
||||||
|
id,
|
||||||
|
__typename,
|
||||||
|
item {
|
||||||
|
__typename,
|
||||||
|
|
||||||
|
...on Hero {
|
||||||
|
hero_id: id,
|
||||||
|
hero_created: date_created,
|
||||||
|
hero_updated: date_updated,
|
||||||
|
hero_title: title,
|
||||||
|
hero_text: subtext,
|
||||||
|
background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
hero_image: background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Text_With_Side_Image {
|
||||||
|
twsi_id: id,
|
||||||
|
twsi_created: date_created,
|
||||||
|
twsi_updated: date_updated,
|
||||||
|
twsi_title: title,
|
||||||
|
twsi_text: text,
|
||||||
|
image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
twsi_image_side: image_side,
|
||||||
|
twsi_image_size: image_size
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Wall_Of_Text {
|
||||||
|
wot_id: id,
|
||||||
|
wot_created: date_created,
|
||||||
|
wot_updated: date_updated,
|
||||||
|
wot_title: title,
|
||||||
|
wot_text: text
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Frequently_Asked_Questions {
|
||||||
|
faq_id: id,
|
||||||
|
faq_created: date_created,
|
||||||
|
faq_updated: date_updated,
|
||||||
|
faq_title: title,
|
||||||
|
faq_text: text,
|
||||||
|
questions {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
question,
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Upcoming_Events {
|
||||||
|
ue_id: id,
|
||||||
|
ue_created: date_created,
|
||||||
|
ue_updated: date_updated,
|
||||||
|
ue_title: title,
|
||||||
|
ue_text: text,
|
||||||
|
events(filter: { start_date: { _gte: $date } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
location,
|
||||||
|
map_location,
|
||||||
|
start_date,
|
||||||
|
end_date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Equipment_Table {
|
||||||
|
et_id: id,
|
||||||
|
et_created: date_created,
|
||||||
|
et_updated: date_updated,
|
||||||
|
et_title: title,
|
||||||
|
et_text: text,
|
||||||
|
items {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Review_List {
|
||||||
|
rl_id: id,
|
||||||
|
rl_created: date_created,
|
||||||
|
rl_updated: date_updated,
|
||||||
|
rl_title: title,
|
||||||
|
rl_text: text,
|
||||||
|
reviews(sort: ["date"], filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
name,
|
||||||
|
review,
|
||||||
|
date,
|
||||||
|
stars,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Contact {
|
||||||
|
c_id: id,
|
||||||
|
c_created: date_created,
|
||||||
|
c_updated: date_updated,
|
||||||
|
c_title: title,
|
||||||
|
c_text: text,
|
||||||
|
methods {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Blogs {
|
||||||
|
lb_id: id,
|
||||||
|
lb_created: date_created,
|
||||||
|
lb_updated: date_updated,
|
||||||
|
lb_title: title,
|
||||||
|
lb_read_more_button_text: read_more_button_text,
|
||||||
|
lb_amount: amount
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Projects {
|
||||||
|
lp_id: id,
|
||||||
|
lp_created: date_created,
|
||||||
|
lp_updated: date_updated,
|
||||||
|
lp_title: title,
|
||||||
|
lp_read_more_button_text: read_more_button_text,
|
||||||
|
lp_amount: amount
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Galleries {
|
||||||
|
lg_id: id,
|
||||||
|
lg_created: date_created,
|
||||||
|
lg_updated: date_updated,
|
||||||
|
lg_title: title,
|
||||||
|
lg_read_more_button_text: read_more_button_text,
|
||||||
|
lg_amount: amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
217
astro/src/graphql/pages/getPage.graphql
Normal file
217
astro/src/graphql/pages/getPage.graphql
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
query getAllPages($date: String!, $route: String!) {
|
||||||
|
Pages(filter: { status: { _eq: "published" }, url: { _eq: $route } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
url,
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
},
|
||||||
|
components {
|
||||||
|
id,
|
||||||
|
__typename,
|
||||||
|
item {
|
||||||
|
__typename,
|
||||||
|
|
||||||
|
...on Hero {
|
||||||
|
hero_id: id,
|
||||||
|
hero_created: date_created,
|
||||||
|
hero_updated: date_updated,
|
||||||
|
hero_title: title,
|
||||||
|
hero_text: subtext,
|
||||||
|
background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
hero_image: background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
background_image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Text_With_Side_Image {
|
||||||
|
twsi_id: id,
|
||||||
|
twsi_created: date_created,
|
||||||
|
twsi_updated: date_updated,
|
||||||
|
twsi_title: title,
|
||||||
|
twsi_text: text,
|
||||||
|
image {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
twsi_image_side: image_side,
|
||||||
|
twsi_image_size: image_size
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Wall_Of_Text {
|
||||||
|
wot_id: id,
|
||||||
|
wot_created: date_created,
|
||||||
|
wot_updated: date_updated,
|
||||||
|
wot_title: title,
|
||||||
|
wot_text: text
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Frequently_Asked_Questions {
|
||||||
|
faq_id: id,
|
||||||
|
faq_created: date_created,
|
||||||
|
faq_updated: date_updated,
|
||||||
|
faq_title: title,
|
||||||
|
faq_text: text,
|
||||||
|
questions {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
question,
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Upcoming_Events {
|
||||||
|
ue_id: id,
|
||||||
|
ue_created: date_created,
|
||||||
|
ue_updated: date_updated,
|
||||||
|
ue_title: title,
|
||||||
|
ue_text: text,
|
||||||
|
events(filter: { start_date: { _gte: $date } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
location,
|
||||||
|
map_location,
|
||||||
|
start_date,
|
||||||
|
end_date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Equipment_Table {
|
||||||
|
et_id: id,
|
||||||
|
et_created: date_created,
|
||||||
|
et_updated: date_updated,
|
||||||
|
et_title: title,
|
||||||
|
et_text: text,
|
||||||
|
items {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Review_List {
|
||||||
|
rl_id: id,
|
||||||
|
rl_created: date_created,
|
||||||
|
rl_updated: date_updated,
|
||||||
|
rl_title: title,
|
||||||
|
rl_text: text,
|
||||||
|
reviews(sort: ["date"], filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
name,
|
||||||
|
review,
|
||||||
|
date,
|
||||||
|
stars,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Contact {
|
||||||
|
c_id: id,
|
||||||
|
c_created: date_created,
|
||||||
|
c_updated: date_updated,
|
||||||
|
c_title: title,
|
||||||
|
c_text: text,
|
||||||
|
methods {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Blogs {
|
||||||
|
lb_id: id,
|
||||||
|
lb_created: date_created,
|
||||||
|
lb_updated: date_updated,
|
||||||
|
lb_title: title,
|
||||||
|
lb_read_more_button_text: read_more_button_text,
|
||||||
|
lb_amount: amount
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Projects {
|
||||||
|
lp_id: id,
|
||||||
|
lp_created: date_created,
|
||||||
|
lp_updated: date_updated,
|
||||||
|
lp_title: title,
|
||||||
|
lp_read_more_button_text: read_more_button_text,
|
||||||
|
lp_amount: amount
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Last_Galleries {
|
||||||
|
lg_id: id,
|
||||||
|
lg_created: date_created,
|
||||||
|
lg_updated: date_updated,
|
||||||
|
lg_title: title,
|
||||||
|
lg_read_more_button_text: read_more_button_text,
|
||||||
|
lg_amount: amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
astro/src/graphql/photos/getAlbum.graphql
Normal file
51
astro/src/graphql/photos/getAlbum.graphql
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
query getAllAlbums($route: String!) {
|
||||||
|
Photo_Albums(sort: ["-start_date", "-date_created"], filter: { status: { _eq: "published" }, url: { _eq: $route }, category: { Photo_Categories_id: { status: { _eq: "published" } } } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
location,
|
||||||
|
category {
|
||||||
|
Photo_Categories_id {
|
||||||
|
id,
|
||||||
|
status,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
photos(filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
photo {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
sort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
astro/src/graphql/photos/getAlbums.graphql
Normal file
51
astro/src/graphql/photos/getAlbums.graphql
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
query getAllAlbums($date: String!) {
|
||||||
|
Photo_Albums(sort: ["-start_date", "-date_created"], filter: { status: { _eq: "published" }, start_date: { _lte: $date }, category: { Photo_Categories_id: { status: { _eq: "published" } } } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
location,
|
||||||
|
category {
|
||||||
|
Photo_Categories_id {
|
||||||
|
id,
|
||||||
|
status,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
photos(filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
photo {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
sort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
astro/src/graphql/photos/getCategories.graphql
Normal file
17
astro/src/graphql/photos/getCategories.graphql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
query getAllCategories {
|
||||||
|
Photo_Categories(filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
astro/src/graphql/photos/getPhotos.graphql
Normal file
51
astro/src/graphql/photos/getPhotos.graphql
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
query getPhotos($albumUrl: String!) {
|
||||||
|
Photo_Albums(sort: ["-start_date", "-date_created"], filter: { status: { _eq: "published" }, url: { _eq: $albumUrl }, category: { Photo_Categories_id: { status: { _eq: "published" } } } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
location,
|
||||||
|
category {
|
||||||
|
Photo_Categories_id {
|
||||||
|
id,
|
||||||
|
status,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
photos(filter: { status: { _eq: "published" } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
photo {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
sort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
astro/src/graphql/projects/getProject.graphql
Normal file
39
astro/src/graphql/projects/getProject.graphql
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
query getAllProjects($route: String!) {
|
||||||
|
Projects(sort: ["-date", "-date_created"], filter: { status: { _eq: "published" }, url: { _eq: $route } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
date,
|
||||||
|
content,
|
||||||
|
tags {
|
||||||
|
Tags_id {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
code,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
astro/src/graphql/projects/getProjects.graphql
Normal file
39
astro/src/graphql/projects/getProjects.graphql
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
query getAllProjects($date: String!) {
|
||||||
|
Projects(sort: ["-date", "-date_created"], filter: { status: { _eq: "published" }, date: { _lte: $date } }) {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
date,
|
||||||
|
content,
|
||||||
|
tags {
|
||||||
|
Tags_id {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
code,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
search_engine {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
canonical,
|
||||||
|
allow_crawler,
|
||||||
|
priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
astro/src/graphql/settings/robots.graphql
Normal file
9
astro/src/graphql/settings/robots.graphql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
query Robots {
|
||||||
|
Robots {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
crawlers,
|
||||||
|
extra_content
|
||||||
|
}
|
||||||
|
}
|
||||||
124
astro/src/graphql/settings/settings.graphql
Normal file
124
astro/src/graphql/settings/settings.graphql
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
query getAllSettings {
|
||||||
|
Website_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
domain_name,
|
||||||
|
title_template,
|
||||||
|
application_name,
|
||||||
|
primary_color,
|
||||||
|
secondary_color,
|
||||||
|
author_name,
|
||||||
|
author_url,
|
||||||
|
designer,
|
||||||
|
developer,
|
||||||
|
owner,
|
||||||
|
copyright,
|
||||||
|
twitter_id,
|
||||||
|
twitter_handle
|
||||||
|
},
|
||||||
|
Blog_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
title,
|
||||||
|
subtext,
|
||||||
|
index_route_template,
|
||||||
|
blog_route_template
|
||||||
|
},
|
||||||
|
Project_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
title,
|
||||||
|
subtext,
|
||||||
|
index_route_template,
|
||||||
|
project_route_template
|
||||||
|
},
|
||||||
|
Photo_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
categories_index_route_template_url,
|
||||||
|
category_route_template_url,
|
||||||
|
albums_per_category_page,
|
||||||
|
category_icons {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
photos_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
location_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
date_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
},
|
||||||
|
album_route_template_url,
|
||||||
|
photos_per_album_page,
|
||||||
|
photo_route_template_url,
|
||||||
|
photo_icons {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
previous_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
next_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
close_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
download_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Sitemap_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
per_page
|
||||||
|
},
|
||||||
|
Plugin_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
swetrix_id,
|
||||||
|
swetrix_url
|
||||||
|
}
|
||||||
|
}
|
||||||
73
astro/src/layouts/BlogLayout.astro
Normal file
73
astro/src/layouts/BlogLayout.astro
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
import '@/styles/global.css';
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
settings: BlogLayoutProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageSettings = Astro.props.settings.searchEngine;
|
||||||
|
const settings = await getSettings();
|
||||||
|
---
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- High Priority Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="lanuage" content="en" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta name="theme-color" content={settings.website.colors.primary} />
|
||||||
|
|
||||||
|
<!-- High Priority Page Metadata -->
|
||||||
|
<title>{settings.website.titleTemplate.replaceAll("%T", pageSettings.title)}</title>
|
||||||
|
|
||||||
|
<!-- Medium Priority Metadata -->
|
||||||
|
<meta name="msapplication-TileColor" content={settings.website.colors.primary} />
|
||||||
|
<meta name="msapplication-TileImage" content="" />
|
||||||
|
<link rel="sitemap" href="/sitemap/index.xml" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
||||||
|
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
||||||
|
<meta name="robots" content="index,follow" />
|
||||||
|
<meta name="keywords" content={[].join(',')} />
|
||||||
|
|
||||||
|
<!-- Low Priority Page Metadata -->
|
||||||
|
<meta name="description" content={pageSettings.description} />
|
||||||
|
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta property="og:locale" content="en-GB" />
|
||||||
|
<meta property="og:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta property="og:description" content={pageSettings.description} />
|
||||||
|
<meta property="og:image:url" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
|
<meta property="article:author" content={settings.website.author.name} />
|
||||||
|
<meta property="article:tags" content={[].join(',')} />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta name="twitter:description" content={pageSettings.description} />
|
||||||
|
<meta name="twitter:image" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta name="twitter:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta name="twitter:site" content={settings.website.twitter.handle} />
|
||||||
|
<meta name="twitter:creator" content={settings.website.twitter.handle} />
|
||||||
|
|
||||||
|
<meta name="pagename" content={pageSettings.title} />
|
||||||
|
<meta name="category" content="webpage" />
|
||||||
|
|
||||||
|
<!-- Low Priority Metadata -->
|
||||||
|
<meta name="copyright" content={settings.website.copyright} />
|
||||||
|
<meta name="author" content={`${settings.website.author.name}, ${settings.website.author.url}`} />
|
||||||
|
<meta name="designer" content={settings.website.designer} />
|
||||||
|
<meta name="owner" content={settings.website.owner} />
|
||||||
|
<meta name="developer" content={settings.website.developer} />
|
||||||
|
<meta name="application-name" content={settings.website.applicationName} />
|
||||||
|
|
||||||
|
<!-- Scripts and Style -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot name="content" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
73
astro/src/layouts/ProjectLayout.astro
Normal file
73
astro/src/layouts/ProjectLayout.astro
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
import '@/styles/global.css';
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
settings: BlogLayoutProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageSettings = Astro.props.settings.searchEngine;
|
||||||
|
const settings = await getSettings();
|
||||||
|
---
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- High Priority Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="lanuage" content="en" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta name="theme-color" content={settings.website.colors.primary} />
|
||||||
|
|
||||||
|
<!-- High Priority Page Metadata -->
|
||||||
|
<title>{settings.website.titleTemplate.replaceAll("%T", pageSettings.title)}</title>
|
||||||
|
|
||||||
|
<!-- Medium Priority Metadata -->
|
||||||
|
<meta name="msapplication-TileColor" content={settings.website.colors.primary} />
|
||||||
|
<meta name="msapplication-TileImage" content="" />
|
||||||
|
<link rel="sitemap" href="/sitemap/index.xml" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
||||||
|
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
||||||
|
<meta name="robots" content="index,follow" />
|
||||||
|
<meta name="keywords" content={[].join(',')} />
|
||||||
|
|
||||||
|
<!-- Low Priority Page Metadata -->
|
||||||
|
<meta name="description" content={pageSettings.description} />
|
||||||
|
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta property="og:locale" content="en-GB" />
|
||||||
|
<meta property="og:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta property="og:description" content={pageSettings.description} />
|
||||||
|
<meta property="og:image:url" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
|
<meta property="article:author" content={settings.website.author.name} />
|
||||||
|
<meta property="article:tags" content={[].join(',')} />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta name="twitter:description" content={pageSettings.description} />
|
||||||
|
<meta name="twitter:image" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta name="twitter:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta name="twitter:site" content={settings.website.twitter.handle} />
|
||||||
|
<meta name="twitter:creator" content={settings.website.twitter.handle} />
|
||||||
|
|
||||||
|
<meta name="pagename" content={pageSettings.title} />
|
||||||
|
<meta name="category" content="webpage" />
|
||||||
|
|
||||||
|
<!-- Low Priority Metadata -->
|
||||||
|
<meta name="copyright" content={settings.website.copyright} />
|
||||||
|
<meta name="author" content={`${settings.website.author.name}, ${settings.website.author.url}`} />
|
||||||
|
<meta name="designer" content={settings.website.designer} />
|
||||||
|
<meta name="owner" content={settings.website.owner} />
|
||||||
|
<meta name="developer" content={settings.website.developer} />
|
||||||
|
<meta name="application-name" content={settings.website.applicationName} />
|
||||||
|
|
||||||
|
<!-- Scripts and Style -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot name="content" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
70
astro/src/layouts/WebpageLayout.astro
Normal file
70
astro/src/layouts/WebpageLayout.astro
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
import '@/styles/global.css';
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
settings: WebpageLayoutProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageSettings = Astro.props.settings.searchEngine;
|
||||||
|
const settings = await getSettings();
|
||||||
|
---
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- High Priority Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="lanuage" content="en" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta name="theme-color" content={settings.website.colors.primary} />
|
||||||
|
|
||||||
|
<!-- High Priority Page Metadata -->
|
||||||
|
<title>{settings.website.titleTemplate.replaceAll("%T", pageSettings.title)}</title>
|
||||||
|
|
||||||
|
<!-- Medium Priority Metadata -->
|
||||||
|
<meta name="msapplication-TileColor" content={settings.website.colors.primary} />
|
||||||
|
<meta name="msapplication-TileImage" content="" />
|
||||||
|
<link rel="sitemap" href="/sitemap/index.xml" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
||||||
|
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
||||||
|
<meta name="robots" content="index,follow" />
|
||||||
|
|
||||||
|
<!-- Low Priority Page Metadata -->
|
||||||
|
<meta name="description" content={pageSettings.description} />
|
||||||
|
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:locale" content="en-GB" />
|
||||||
|
<meta property="og:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta property="og:description" content={pageSettings.description} />
|
||||||
|
<meta property="og:image:url" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
|
<meta name="twitter:description" content={pageSettings.description} />
|
||||||
|
<meta name="twitter:image" content={pageSettings.thumbnail.url} />
|
||||||
|
<meta name="twitter:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta name="twitter:site" content={settings.website.twitter.handle} />
|
||||||
|
<meta name="twitter:creator" content={settings.website.twitter.handle} />
|
||||||
|
|
||||||
|
<meta name="pagename" content={pageSettings.title} />
|
||||||
|
<meta name="category" content="webpage" />
|
||||||
|
|
||||||
|
<!-- Low Priority Metadata -->
|
||||||
|
<meta name="copyright" content={settings.website.copyright} />
|
||||||
|
<meta name="author" content={`${settings.website.author.name}, ${settings.website.author.url}`} />
|
||||||
|
<meta name="designer" content={settings.website.designer} />
|
||||||
|
<meta name="owner" content={settings.website.owner} />
|
||||||
|
<meta name="developer" content={settings.website.developer} />
|
||||||
|
<meta name="application-name" content={settings.website.applicationName} />
|
||||||
|
|
||||||
|
<!-- Scripts and Style -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot name="content" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
astro/src/lib/dates.ts
Normal file
6
astro/src/lib/dates.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function formatDate(date: Date, format: string) {
|
||||||
|
return format
|
||||||
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%D", date.getDate().toString().padStart(2, '0'));
|
||||||
|
}
|
||||||
9
astro/src/lib/directus.ts
Normal file
9
astro/src/lib/directus.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createDirectus, graphql, staticToken } from "@directus/sdk";
|
||||||
|
|
||||||
|
export async function createDirectusConnection() {
|
||||||
|
const directus = await createDirectus(import.meta.env.DIRECTUS_URL)
|
||||||
|
.with(graphql())
|
||||||
|
.with(staticToken(import.meta.env.DIRECTUS_TOKEN));
|
||||||
|
|
||||||
|
return directus;
|
||||||
|
}
|
||||||
12
astro/src/lib/hash.ts
Normal file
12
astro/src/lib/hash.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import md5 from "md5";
|
||||||
|
|
||||||
|
export function getPhotoHash(photo: PhotoAlbumPhoto) {
|
||||||
|
const hash = md5(JSON.stringify({
|
||||||
|
id: photo.id,
|
||||||
|
url: photo.photo.url,
|
||||||
|
width: photo.photo.width,
|
||||||
|
height: photo.photo.height
|
||||||
|
}));
|
||||||
|
|
||||||
|
return hash.substring(hash.length - 10);
|
||||||
|
}
|
||||||
3
astro/src/lib/images.ts
Normal file
3
astro/src/lib/images.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function getImageUrl(url: string) {
|
||||||
|
return `${import.meta.env.DIRECTUS_URL}assets/${url}`;
|
||||||
|
}
|
||||||
9
astro/src/lib/markdown.ts
Normal file
9
astro/src/lib/markdown.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import markdownit from "markdown-it";
|
||||||
|
import markdownitHighlightjs from "markdown-it-highlightjs";
|
||||||
|
|
||||||
|
export function markdownToHtml(markdown: string) {
|
||||||
|
const md = markdownit()
|
||||||
|
.use(markdownitHighlightjs);
|
||||||
|
|
||||||
|
return md.render(markdown);
|
||||||
|
}
|
||||||
231
astro/src/lib/pages.ts
Normal file
231
astro/src/lib/pages.ts
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import { getBlog } from "@/content/blogs/blogs";
|
||||||
|
import { getWebpage } from "@/content/pages/pages";
|
||||||
|
import { getAlbum } from "@/content/photos/albums";
|
||||||
|
import { getPhotoFromHash } from "@/content/photos/photos";
|
||||||
|
import { getProject } from "@/content/projects/projects";
|
||||||
|
|
||||||
|
export async function getPage(settings: GlobalSettings, route: string): Promise<PageType | null> {
|
||||||
|
// Blog Index
|
||||||
|
if (regexToRoute({ template: settings.blog.indexRouteTemplate, allowPagination: true }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.blog.indexRouteTemplate, allowPagination: true });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "BlogIndex",
|
||||||
|
page: {
|
||||||
|
type: "BlogIndex",
|
||||||
|
exists: true,
|
||||||
|
pageNumber: params["page"] !== undefined ? Number(params["page"]) : 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Blog Post
|
||||||
|
else if (regexToRoute({ template: settings.blog.blogRouteTemplate, allowPagination: false }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.blog.blogRouteTemplate, allowPagination: false });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
const blog = await getBlog(settings, `/${params["R"]}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "BlogPost",
|
||||||
|
page: blog
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Project Index
|
||||||
|
else if (regexToRoute({ template: settings.project.indexRouteTemplate, allowPagination: true }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.project.indexRouteTemplate, allowPagination: true });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "ProjectIndex",
|
||||||
|
page: {
|
||||||
|
type: "ProjectIndex",
|
||||||
|
exists: true,
|
||||||
|
pageNumber: params["page"] !== undefined ? Number(params["page"]) : 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Project Post
|
||||||
|
else if (regexToRoute({ template: settings.project.projectRouteTemplate, allowPagination: false }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.project.projectRouteTemplate, allowPagination: false });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
const project = await getProject(settings, `/${params["R"]}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "ProjectPost",
|
||||||
|
page: project
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Photo Category Index
|
||||||
|
else if (regexToRoute({ template: settings.photo.categoryIndex.indexRouteTemplate, allowPagination: false }).regex.test(route)) {
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "PhotoCategoryIndex",
|
||||||
|
page: {
|
||||||
|
type: "PhotoCategoryIndex",
|
||||||
|
exists: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Photo Category / Album List
|
||||||
|
else if (regexToRoute({ template: settings.photo.category.routeTemplate, allowPagination: true }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.photo.category.routeTemplate, allowPagination: true });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "PhotoCategory",
|
||||||
|
page: {
|
||||||
|
type: "PhotoCategory",
|
||||||
|
exists: true,
|
||||||
|
category: params["category"],
|
||||||
|
pageNumber: params["page"] !== undefined ? Number(params["page"]) : 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Photo Album
|
||||||
|
else if (regexToRoute({ template: settings.photo.album.routeTemplate, allowPagination: true }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.photo.album.routeTemplate, allowPagination: true });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
const photoAlbum = await getAlbum(settings, `/${params["R"]}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "PhotoAlbum",
|
||||||
|
page: photoAlbum
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Photograph
|
||||||
|
else if (regexToRoute({ template: settings.photo.photo.routeTemplate, allowPagination: false }).regex.test(route)) {
|
||||||
|
const { regex, keys } = regexToRoute({ template: settings.photo.photo.routeTemplate, allowPagination: false });
|
||||||
|
const match = route.match(regex);
|
||||||
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
params[key] = match[i + 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
const photo = await getPhotoFromHash(`/${params["R"]}`, params["H"]);
|
||||||
|
|
||||||
|
if (photo === null) {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "Photo",
|
||||||
|
page: {
|
||||||
|
type: "PhotoPage",
|
||||||
|
exists: true,
|
||||||
|
|
||||||
|
id: photo!.id,
|
||||||
|
photo: photo!.photo,
|
||||||
|
text: photo!.text
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Regular webpage
|
||||||
|
else if (regexToRoute({ template: "/", allowPagination: false }).regex.test(route) ||
|
||||||
|
regexToRoute({ template: "/%R", allowPagination: false }).regex.test(route)) {
|
||||||
|
const webpageContent = await getWebpage(route);
|
||||||
|
|
||||||
|
if (webpageContent === null || !webpageContent.exists) {
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "Webpage",
|
||||||
|
page: {
|
||||||
|
type: "Webpage",
|
||||||
|
exists: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: route,
|
||||||
|
pageType: "Webpage",
|
||||||
|
page: {
|
||||||
|
type: "Webpage",
|
||||||
|
exists: true,
|
||||||
|
id: webpageContent.id,
|
||||||
|
lastModified: webpageContent.lastModified,
|
||||||
|
url: webpageContent.url,
|
||||||
|
searchEngine: webpageContent.searchEngine,
|
||||||
|
components: webpageContent.components
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function regexToRoute(template: PageRegexMatchProps) {
|
||||||
|
const keys: string[] = [];
|
||||||
|
|
||||||
|
let pattern = template.template
|
||||||
|
.replaceAll("%Y", () => { keys.push("Y"); return "(\\d{4})"; })
|
||||||
|
.replaceAll("%M", () => { keys.push("M"); return "(\\d{2})"; })
|
||||||
|
.replaceAll("%D", () => { keys.push("D"); return "(\\d{2})"; })
|
||||||
|
.replaceAll("%R", () => { keys.push("R"); return "([^/]+)"; })
|
||||||
|
.replaceAll("%C", () => { keys.push("C"); return "([^/]+)"; })
|
||||||
|
.replaceAll("%H", () => { keys.push("H"); return "([^/]+)"; })
|
||||||
|
.replace(/\/+/g, "/");
|
||||||
|
|
||||||
|
if (template.allowPagination) {
|
||||||
|
keys.push("page");
|
||||||
|
pattern += "(?:\\/(\\d+))?";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
regex: new RegExp(`^${pattern}$`),
|
||||||
|
keys
|
||||||
|
};
|
||||||
|
}
|
||||||
143
astro/src/lib/routing.ts
Normal file
143
astro/src/lib/routing.ts
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { getAllBlogs } from "@/content/blogs/blogs";
|
||||||
|
import { getAllWebpages } from "@/content/pages/pages";
|
||||||
|
import { getAllAlbums } from "@/content/photos/albums";
|
||||||
|
import { getAllProjects } from "@/content/projects/projects";
|
||||||
|
import { getPhotoHash } from "./hash";
|
||||||
|
import { getAllCategories } from "@/content/photos/categories";
|
||||||
|
|
||||||
|
export async function getAllRoutesList(settings: GlobalSettings): Promise<string[]> {
|
||||||
|
let routes: string[] = [];
|
||||||
|
|
||||||
|
const webpages = await getAllWebpages();
|
||||||
|
|
||||||
|
webpages.forEach((webpage) => {
|
||||||
|
routes.push(webpage.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (settings.blog.enabled) {
|
||||||
|
const blogs = await getAllBlogs(settings);
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.ceil(blogs.length / 6); i++) {
|
||||||
|
if (i !== 0) {
|
||||||
|
routes.push(`${settings.blog.indexRouteTemplate}/${i + 1}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
routes.push(settings.blog.indexRouteTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blogs.forEach((blog) => {
|
||||||
|
routes.push(getBlogRoute(settings.blog, blog));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (settings.project.enabled) {
|
||||||
|
const projects = await getAllProjects(settings);
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.ceil(projects.length / 4); i++) {
|
||||||
|
if (i !== 0) {
|
||||||
|
routes.push(`${settings.project.indexRouteTemplate}/${i + 1}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
routes.push(settings.project.indexRouteTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projects.forEach((project) => {
|
||||||
|
routes.push(getProjectRoute(settings.project, project));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (settings.photo.enabled) {
|
||||||
|
const categories = await getAllCategories(settings);
|
||||||
|
const galleries = await getAllAlbums(settings);
|
||||||
|
|
||||||
|
routes.push(settings.photo.categoryIndex.indexRouteTemplate);
|
||||||
|
|
||||||
|
categories.forEach((category) => {
|
||||||
|
let albums = galleries.filter(g => g.category.id === category.id);
|
||||||
|
const pages = Math.ceil(albums.length / settings.photo.category.perPage);
|
||||||
|
const categoryRoute = getCategoryRoute(settings.photo, category);
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
if (i !== 0) {
|
||||||
|
routes.push(`${categoryRoute}/${i + 1}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
routes.push(`${categoryRoute}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
galleries.forEach((gallery) => {
|
||||||
|
const pages = Math.ceil(gallery.photos.length / settings.photo.album.perPage);
|
||||||
|
const galleryRoute = getAlbumRoute(settings.photo, gallery);
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
if (i !== 0) {
|
||||||
|
routes.push(`${galleryRoute}/${i + 1}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
routes.push(`${galleryRoute}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gallery.photos.forEach((photo) => {
|
||||||
|
routes.push(getPhotoRoute(settings.photo, gallery, photo));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBlogRoute(blogSettings: BlogSettings, blog: BlogPost) {
|
||||||
|
const date = new Date(blog.date);
|
||||||
|
|
||||||
|
return blogSettings.blogRouteTemplate
|
||||||
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%R", blog.url)
|
||||||
|
.replace(/\/+/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProjectRoute(projectSettings: ProjectSettings, project: ProjectPost) {
|
||||||
|
const date = new Date(project.date);
|
||||||
|
|
||||||
|
return projectSettings.projectRouteTemplate
|
||||||
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%R", project.url)
|
||||||
|
.replace(/\/+/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCategoryRoute(photoSettings: WebsitePhotoSettings, category: PhotoAlbumCategory) {
|
||||||
|
return photoSettings.category.routeTemplate
|
||||||
|
.replaceAll("%C", category.url)
|
||||||
|
.replace(/\/+/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAlbumRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum) {
|
||||||
|
const date = new Date(album.startDate);
|
||||||
|
|
||||||
|
return photoSettings.album.routeTemplate
|
||||||
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%C", album.category.url)
|
||||||
|
.replaceAll("%R", album.url)
|
||||||
|
.replace(/\/+/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPhotoRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum, photo: PhotoAlbumPhoto) {
|
||||||
|
const date = new Date(album.startDate);
|
||||||
|
|
||||||
|
return photoSettings.photo.routeTemplate
|
||||||
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
||||||
|
.replaceAll("%C", album.category.url)
|
||||||
|
.replaceAll("%R", album.url)
|
||||||
|
.replaceAll("%H", getPhotoHash(photo))
|
||||||
|
.replace(/\/+/g, '/');
|
||||||
|
}
|
||||||
178
astro/src/pages/[...route].astro
Normal file
178
astro/src/pages/[...route].astro
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
---
|
||||||
|
import { getAllRoutesList } from "@/lib/routing";
|
||||||
|
import { getPage } from "@/lib/pages";
|
||||||
|
import { getSettings } from "@/content/settings/settings"
|
||||||
|
import WebpageLayout from "@/layouts/WebpageLayout.astro";
|
||||||
|
import BlogLayout from "@/layouts/BlogLayout.astro";
|
||||||
|
import ProjectLayout from "@/layouts/ProjectLayout.astro";
|
||||||
|
import BlogIndex from "@/components/blogs/BlogIndex.astro";
|
||||||
|
import ProjectIndex from "@/components/projects/ProjectIndex.astro";
|
||||||
|
import Webpage from "@/components/webpage/Webpage.astro";
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const pages = await getAllRoutesList(settings);
|
||||||
|
|
||||||
|
let routes: any[] = [];
|
||||||
|
|
||||||
|
pages.forEach((page) => {
|
||||||
|
routes.push({ params: { route: page } });
|
||||||
|
});
|
||||||
|
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await getSettings();
|
||||||
|
const page = await getPage(settings, Astro.url.pathname);
|
||||||
|
|
||||||
|
if (page === null || page.page === null) {
|
||||||
|
return new Response("Page not found.", {
|
||||||
|
status: 404,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
{ page.page.type === "Webpage" && page.page.exists && (
|
||||||
|
<WebpageLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: page.page.searchEngine.title,
|
||||||
|
description: page.page.searchEngine.description,
|
||||||
|
allowCrawlers: page.page.searchEngine.allowCrawlers,
|
||||||
|
canonical: page.page.searchEngine.canonical,
|
||||||
|
priority: page.page.searchEngine.priority,
|
||||||
|
thumbnail: {
|
||||||
|
url: page.page.searchEngine.thumbnail.url,
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<Webpage webpage={page.page.components} />
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.page.type === "BlogIndex" && (
|
||||||
|
<WebpageLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: "Blogs",
|
||||||
|
description: "",
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: {
|
||||||
|
url: "",
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<BlogIndex page={page.page} />
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.page.type === "BlogPost" && (
|
||||||
|
<BlogLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: page.page.searchEngine.title,
|
||||||
|
description: page.page.searchEngine.description,
|
||||||
|
allowCrawlers: page.page.searchEngine.allowCrawlers,
|
||||||
|
canonical: page.page.searchEngine.canonical,
|
||||||
|
priority: page.page.searchEngine.priority,
|
||||||
|
thumbnail: {
|
||||||
|
url: page.page.searchEngine.thumbnail.url,
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<dib>BlogPost</dib>
|
||||||
|
</Fragment>
|
||||||
|
</BlogLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.page.type === "ProjectIndex" && (
|
||||||
|
<WebpageLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: "Projects",
|
||||||
|
description: "",
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: {
|
||||||
|
url: "",
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<ProjectIndex page={page.page as ProjectIndex} />
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.page.type === "ProjectPost" && (
|
||||||
|
<ProjectLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: "Projects",
|
||||||
|
description: "",
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: {
|
||||||
|
url: "",
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tags: []
|
||||||
|
}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<div>ProjectPost</div>
|
||||||
|
</Fragment>
|
||||||
|
</ProjectLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.pageType === "PhotoCategoryIndex" && (
|
||||||
|
<WebpageLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: "Projects",
|
||||||
|
description: "",
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: {
|
||||||
|
url: "",
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<div>PhotoCategoryIndex</div>
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.pageType === "Photo" && (
|
||||||
|
<WebpageLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: "Projects",
|
||||||
|
description: "",
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: {
|
||||||
|
url: "",
|
||||||
|
width: 1200,
|
||||||
|
height: 630
|
||||||
|
}
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<div>Photo</div>
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<meta name="generator" content={Astro.generator} />
|
|
||||||
<title>Astro</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Astro</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
66
astro/src/pages/robots.txt.ts
Normal file
66
astro/src/pages/robots.txt.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { getRobotsSettings } from "@/content/settings/robots";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const robots = await getRobotsSettings();
|
||||||
|
|
||||||
|
let crawlers = [
|
||||||
|
{ id: 'google', name: 'Googlebot' },
|
||||||
|
{ id: 'bing', name: "Bingbot" },
|
||||||
|
{ id: "slurp", name: "Slurp" },
|
||||||
|
{ id: "duckduckgo", name: "DuckDuckBot" },
|
||||||
|
{ id: "baidu", name: "Baiduspider" },
|
||||||
|
{ id: "yandex", name: "YandexBot" },
|
||||||
|
{ id: "sogou", name: "Sogou web spider" },
|
||||||
|
{ id: "seznam", name: "SeznamBot" },
|
||||||
|
{ id: "qwantbot", name: "Qwantbot" },
|
||||||
|
{ id: "naverbot", name: "Naverbot" },
|
||||||
|
{ id: "coccocbot", name: "Coccocbot" },
|
||||||
|
{ id: "mojeekbot", name: "Mojeekbot" },
|
||||||
|
{ id: "ahrefs", name: "Ahrefsbot" },
|
||||||
|
{ id: "semrush", name: "SemrushBot" },
|
||||||
|
{ id: "mj12bot", name: "MJ12Bot" },
|
||||||
|
{ id: "dotbot", name: "DotBot" },
|
||||||
|
{ id: "petalbot", name: "PetalBot" },
|
||||||
|
{ id: "gptbot", name: "GPTBot" },
|
||||||
|
{ id: "ccbot", name: "CCBot" },
|
||||||
|
{ id: "ia_archiver", name: "ia_archiver" },
|
||||||
|
{ id: "claudebot", name: "ClaudeBot" },
|
||||||
|
{ id: "perplexity", name: "PerplexityBot" },
|
||||||
|
{ id: "facebookexternalhit", name: "facebookexternalhit/1.1" },
|
||||||
|
{ id: "twitterbot", name: "Twitterbot" },
|
||||||
|
{ id: "linkedinbot", name: "LinkedInBot" },
|
||||||
|
{ id: "bytespider", name: "ByteSpider" },
|
||||||
|
{ id: "applebot", name: "AppleBot" },
|
||||||
|
{ id: "amazonbot", name: "AmazonBot" }
|
||||||
|
]
|
||||||
|
|
||||||
|
let crawlerContent = "";
|
||||||
|
|
||||||
|
crawlers.forEach((crawler) => {
|
||||||
|
if (robots.crawlers.some(c => c === crawler.id)) {
|
||||||
|
const crawlerData = crawlers.find(c => c.id === crawler.id);
|
||||||
|
|
||||||
|
crawlerContent = crawlerContent +
|
||||||
|
`User-agent: ${crawlerData!.name}\nAllow: /\nCrawl-delay: 5\nSitemap: ${settings.website.domainName}/sitemap/index.xml`
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const crawlerData = crawlers.find(c => c.id === crawler.id);
|
||||||
|
|
||||||
|
crawlerContent = crawlerContent +
|
||||||
|
`User-agent: ${crawlerData!.name}\nDisallow: /`
|
||||||
|
}
|
||||||
|
|
||||||
|
crawlerContent = crawlerContent + "\n\n\n"
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(crawlerContent.trim(), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "text/plain"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
27
astro/src/pages/rss.xml.ts
Normal file
27
astro/src/pages/rss.xml.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>${settings.website.applicationName}</title>
|
||||||
|
<description>This is the RSS feed of ${settings.website.applicationName}</description>
|
||||||
|
<link>${settings.website.domainName}</link>
|
||||||
|
<lastBuildDate>Sat, 13 Dec 2003 18:30:02 GMT</lastBuildDate>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
70
astro/src/pages/sitemap/albums-[page].xml.ts
Normal file
70
astro/src/pages/sitemap/albums-[page].xml.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { getAllAlbums } from "@/content/photos/albums";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import { getAlbumRoute } from "@/lib/routing";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.photo.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
const albums = await getAllAlbums(settings);
|
||||||
|
const selectedAlbums = albums.slice(
|
||||||
|
((Number(currentPage) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(currentPage) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [];
|
||||||
|
|
||||||
|
selectedAlbums.forEach((album) => {
|
||||||
|
pages.push({
|
||||||
|
url: getAlbumRoute(settings.photo, album),
|
||||||
|
lastModified: album.lastModified
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const albums = await getAllAlbums(settings);
|
||||||
|
|
||||||
|
const albumCount = albums.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(albumCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
68
astro/src/pages/sitemap/albums.xml.ts
Normal file
68
astro/src/pages/sitemap/albums.xml.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { getAllAlbums } from "@/content/photos/albums";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.photo.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const albums = await getAllAlbums(settings);
|
||||||
|
const albumCount = albums.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(albumCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
const selectedProjects = albums.slice(
|
||||||
|
((Number(i + 1) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(i + 1) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let dates = [
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.photo.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
selectedProjects.forEach((project) => {
|
||||||
|
dates.push(project.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModified = dates.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/albums-${i + 1}.xml`,
|
||||||
|
lastModified: lastModified[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
70
astro/src/pages/sitemap/blogs-[page].xml.ts
Normal file
70
astro/src/pages/sitemap/blogs-[page].xml.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { getAllBlogs } from "@/content/blogs/blogs";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import { getBlogRoute } from "@/lib/routing";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
const blogs = await getAllBlogs(settings);
|
||||||
|
const selectedBlogs = blogs.slice(
|
||||||
|
((Number(currentPage) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(currentPage) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [];
|
||||||
|
|
||||||
|
selectedBlogs.forEach((blog) => {
|
||||||
|
pages.push({
|
||||||
|
url: getBlogRoute(settings.blog, blog),
|
||||||
|
lastModified: blog.lastModified
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const blogs = await getAllBlogs(settings);
|
||||||
|
|
||||||
|
const blogCount = blogs.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(blogCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
68
astro/src/pages/sitemap/blogs.xml.ts
Normal file
68
astro/src/pages/sitemap/blogs.xml.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { getAllBlogs } from "@/content/blogs/blogs";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const blogs = await getAllBlogs(settings);
|
||||||
|
const blogCount = blogs.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(blogCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
const selectedBlogs = blogs.slice(
|
||||||
|
((Number(i + 1) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(i + 1) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let dates = [
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.blog.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
selectedBlogs.forEach((blog) => {
|
||||||
|
dates.push(blog.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModified = dates.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/blogs-${i + 1}.xml`,
|
||||||
|
lastModified: lastModified[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
104
astro/src/pages/sitemap/index.xml.ts
Normal file
104
astro/src/pages/sitemap/index.xml.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import { getAllBlogs } from "@/content/blogs/blogs";
|
||||||
|
import { getAllAlbums } from "@/content/photos/albums";
|
||||||
|
import { getAllProjects } from "@/content/projects/projects";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
let sitemapIndex: SitemapIndex[] = [
|
||||||
|
{
|
||||||
|
url: "/sitemap/pages.xml",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (settings.blog.enabled) {
|
||||||
|
const blogLastModifieds = [
|
||||||
|
settings.blog.lastModified,
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
let blogs = await getAllBlogs(settings);
|
||||||
|
|
||||||
|
blogs.forEach((blog) => {
|
||||||
|
blogLastModifieds.push(blog.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModifiedBlogs = blogLastModifieds.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/blogs.xml",
|
||||||
|
lastModified: lastModifiedBlogs[0]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (settings.project.enabled) {
|
||||||
|
const projectLastModifieds = [
|
||||||
|
settings.project.lastModified,
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
let projects = await getAllProjects(settings);
|
||||||
|
|
||||||
|
projects.forEach((project) => {
|
||||||
|
projectLastModifieds.push(project.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModifiedProjects = projectLastModifieds.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/projects.xml",
|
||||||
|
lastModified: lastModifiedProjects[0]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (settings.photo.enabled) {
|
||||||
|
const photoLastModifieds = [
|
||||||
|
settings.photo.lastModified,
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
let albums = await getAllAlbums(settings);
|
||||||
|
|
||||||
|
albums.forEach((album) => {
|
||||||
|
photoLastModifieds.push(album.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModifiedAlbums = photoLastModifieds.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/albums.xml",
|
||||||
|
lastModified: lastModifiedAlbums[0]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemapIndex.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
62
astro/src/pages/sitemap/pages-[page].xml.ts
Normal file
62
astro/src/pages/sitemap/pages-[page].xml.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { getAllWebpages } from "@/content/pages/pages";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
const webPages = await getAllWebpages();
|
||||||
|
const selectedPages = webPages.slice(
|
||||||
|
((Number(currentPage) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(currentPage) * settings.sitemap.perPage - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [];
|
||||||
|
|
||||||
|
selectedPages.forEach((page) => {
|
||||||
|
pages.push({
|
||||||
|
url: page.url,
|
||||||
|
lastModified: page.lastModified
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const webPages = await getAllWebpages();
|
||||||
|
|
||||||
|
const pageCount = webPages.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(pageCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
42
astro/src/pages/sitemap/pages.xml.ts
Normal file
42
astro/src/pages/sitemap/pages.xml.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { getAllWebpages } from "@/content/pages/pages";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const webPages = await getAllWebpages();
|
||||||
|
const pageCount = webPages.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(pageCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/pages-${i + 1}.xml`,
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
70
astro/src/pages/sitemap/projects-[page].xml.ts
Normal file
70
astro/src/pages/sitemap/projects-[page].xml.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { getAllProjects } from "@/content/projects/projects";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import { getProjectRoute } from "@/lib/routing";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.project.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
const projects = await getAllProjects(settings);
|
||||||
|
const selectedProjects = projects.slice(
|
||||||
|
((Number(currentPage) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(currentPage) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [];
|
||||||
|
|
||||||
|
selectedProjects.forEach((project) => {
|
||||||
|
pages.push({
|
||||||
|
url: getProjectRoute(settings.project, project),
|
||||||
|
lastModified: project.lastModified
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
const projects = await getAllProjects(settings);
|
||||||
|
|
||||||
|
const projectCount = projects.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(projectCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
68
astro/src/pages/sitemap/projects.xml.ts
Normal file
68
astro/src/pages/sitemap/projects.xml.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { getAllProjects } from "@/content/projects/projects";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = await getAllProjects(settings);
|
||||||
|
const projectCount = projects.length;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(projectCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
const selectedProjects = projects.slice(
|
||||||
|
((Number(i + 1) - 1) * settings.sitemap.perPage),
|
||||||
|
Number(i + 1) * settings.sitemap.perPage - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let dates = [
|
||||||
|
settings.sitemap.lastModified,
|
||||||
|
settings.project.lastModified,
|
||||||
|
settings.website.lastModified
|
||||||
|
];
|
||||||
|
|
||||||
|
selectedProjects.forEach((project) => {
|
||||||
|
dates.push(project.lastModified);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastModified = dates.sort((a: Date, b: Date) => {
|
||||||
|
return b.getTime() - a.getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/projects-${i + 1}.xml`,
|
||||||
|
lastModified: lastModified[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
22
astro/src/types/blogs/blog.d.ts
vendored
Normal file
22
astro/src/types/blogs/blog.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
type BlogPost = {
|
||||||
|
type: "BlogPost";
|
||||||
|
exists: boolean;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
tags: Tag[];
|
||||||
|
|
||||||
|
searchEngine: SearchEngine;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlogIndex = {
|
||||||
|
type: "BlogIndex";
|
||||||
|
exists: boolean;
|
||||||
|
pageNumber: number;
|
||||||
|
}
|
||||||
5
astro/src/types/common/images.d.ts
vendored
Normal file
5
astro/src/types/common/images.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
type PhotoProps = {
|
||||||
|
url: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
8
astro/src/types/common/searchEngine.d.ts
vendored
Normal file
8
astro/src/types/common/searchEngine.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type SearchEngine = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
canonical: string | null;
|
||||||
|
allowCrawlers: boolean;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
5
astro/src/types/common/tag.d.ts
vendored
Normal file
5
astro/src/types/common/tag.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
type Tag = {
|
||||||
|
text: string;
|
||||||
|
code: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
16
astro/src/types/components/contact.d.ts
vendored
Normal file
16
astro/src/types/components/contact.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
type ContactComponent = {
|
||||||
|
component: "Contact";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
methods: ContactMethod[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContactMethod = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
color: string;
|
||||||
|
icon: PhotoProps;
|
||||||
|
}
|
||||||
15
astro/src/types/components/equipment.d.ts
vendored
Normal file
15
astro/src/types/components/equipment.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
type EquipmentTableComponent = {
|
||||||
|
component: "EquipmentTable";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
items: EquipmentTableItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type EquipmentTableItem = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
icon: PhotoProps;
|
||||||
|
}
|
||||||
18
astro/src/types/components/events.d.ts
vendored
Normal file
18
astro/src/types/components/events.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
type UpcomingEventsComponent = {
|
||||||
|
component: "UpcomingEvents";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
events: UpcomingEvent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpcomingEvent = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
location: string;
|
||||||
|
mapLocation: [number, number];
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
14
astro/src/types/components/faq.d.ts
vendored
Normal file
14
astro/src/types/components/faq.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
type FrequentlyAskedQuestionsComponent = {
|
||||||
|
component: "FrequentlyAskedQuestions";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
questions: FrequentlyAskedQuestion[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type FrequentlyAskedQuestion = {
|
||||||
|
id: string;
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
}
|
||||||
8
astro/src/types/components/hero.d.ts
vendored
Normal file
8
astro/src/types/components/hero.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type HeroComponent = {
|
||||||
|
component: "Hero";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
backgroundImage: PhotoProps;
|
||||||
|
}
|
||||||
26
astro/src/types/components/lastContent.d.ts
vendored
Normal file
26
astro/src/types/components/lastContent.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
type LastBlogsComponent = {
|
||||||
|
component: "LastBlogs";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
readMoreButtonText: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type LastProjectsComponent = {
|
||||||
|
component: "LastProjects";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
readMoreButtonText: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type LastGalleriesComponent = {
|
||||||
|
component: "LastGalleries";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
readMoreButtonText: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
17
astro/src/types/components/reviews.d.ts
vendored
Normal file
17
astro/src/types/components/reviews.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
type ReviewListComponent = {
|
||||||
|
component: "Reviews";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
reviews: Review[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Review = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
review: string;
|
||||||
|
date: string;
|
||||||
|
stars: number;
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
}
|
||||||
10
astro/src/types/components/textWithImage.d.ts
vendored
Normal file
10
astro/src/types/components/textWithImage.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
type TextWithImageComponent = {
|
||||||
|
component: "TextWithImage";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string | null;
|
||||||
|
image: PhotoProps;
|
||||||
|
imageSide: "left" | "right";
|
||||||
|
imageSize: "small" | "medium" | "large";
|
||||||
|
}
|
||||||
7
astro/src/types/components/wallOfText.d.ts
vendored
Normal file
7
astro/src/types/components/wallOfText.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
type WallOfTextComponent = {
|
||||||
|
component: "WallOfText";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
8
astro/src/types/layouts/webpageLayout.d.ts
vendored
Normal file
8
astro/src/types/layouts/webpageLayout.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type WebpageLayoutProps = {
|
||||||
|
searchEngine: SearchEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlogLayoutProps = {
|
||||||
|
searchEngine: SearchEngine;
|
||||||
|
tags: string[] | null;
|
||||||
|
}
|
||||||
46
astro/src/types/pages/page.d.ts
vendored
Normal file
46
astro/src/types/pages/page.d.ts
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
type WebPage =
|
||||||
|
| {
|
||||||
|
type: "Webpage";
|
||||||
|
exists: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "Webpage";
|
||||||
|
exists: true;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
lastModified: Date;
|
||||||
|
url: string;
|
||||||
|
searchEngine: SearchEngine;
|
||||||
|
components: WebpageComponent[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type WebpageComponent =
|
||||||
|
ContactComponent |
|
||||||
|
EquipmentTableComponent |
|
||||||
|
UpcomingEventsComponent |
|
||||||
|
FrequentlyAskedQuestionsComponent |
|
||||||
|
HeroComponent |
|
||||||
|
LastBlogsComponent |
|
||||||
|
LastProjectsComponent |
|
||||||
|
LastGalleriesComponent |
|
||||||
|
ReviewListComponent |
|
||||||
|
TextWithImageComponent |
|
||||||
|
WallOfTextComponent;
|
||||||
|
|
||||||
|
|
||||||
|
type PageRegexMatchProps = {
|
||||||
|
template: string;
|
||||||
|
allowPagination: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PageType =
|
||||||
|
| { pageType: "Webpage"; page: WebPage; route: string }
|
||||||
|
| { pageType: "BlogIndex"; page: BlogIndex; route: string }
|
||||||
|
| { pageType: "BlogPost"; page: BlogPost; route: string }
|
||||||
|
| { pageType: "ProjectIndex"; page: ProjectIndex; route: string }
|
||||||
|
| { pageType: "ProjectPost"; page: ProjectPost; route: string }
|
||||||
|
| { pageType: "PhotoCategoryIndex"; page: PhotoCategoryIndex; route: string }
|
||||||
|
| { pageType: "PhotoCategory"; page: PhotoCategory; route: string }
|
||||||
|
| { pageType: "PhotoAlbum"; page: PhotoAlbum; route: string }
|
||||||
|
| { pageType: "Photo"; page: PhotoPage; route: string }
|
||||||
|
| { pageType: "Unknown"; page: null; route: string };
|
||||||
40
astro/src/types/photos/album.d.ts
vendored
Normal file
40
astro/src/types/photos/album.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
type PhotoAlbum = {
|
||||||
|
type: "PhotoAlbum";
|
||||||
|
exists: boolean;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
description: string | null;
|
||||||
|
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
|
||||||
|
startDate: string;
|
||||||
|
endDate: string | null;
|
||||||
|
location: string | null;
|
||||||
|
|
||||||
|
category: PhotoAlbumCategory;
|
||||||
|
photos: PhotoAlbumPhoto[];
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumCategory = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumPhoto = {
|
||||||
|
id: string;
|
||||||
|
photo: PhotoProps;
|
||||||
|
text: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoCategory = {
|
||||||
|
type: "PhotoCategory";
|
||||||
|
exists: boolean;
|
||||||
|
|
||||||
|
category: string;
|
||||||
|
pageNumber: number;
|
||||||
|
}
|
||||||
4
astro/src/types/photos/category.d.ts
vendored
Normal file
4
astro/src/types/photos/category.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
type PhotoCategoryIndex = {
|
||||||
|
type: "PhotoCategoryIndex";
|
||||||
|
exists: boolean;
|
||||||
|
}
|
||||||
8
astro/src/types/photos/photo.d.ts
vendored
Normal file
8
astro/src/types/photos/photo.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type PhotoPage = {
|
||||||
|
type: "PhotoPage";
|
||||||
|
exists: boolean;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
photo: PhotoProps;
|
||||||
|
text: string | null;
|
||||||
|
}
|
||||||
21
astro/src/types/projects/project.d.ts
vendored
Normal file
21
astro/src/types/projects/project.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
type ProjectPost = {
|
||||||
|
type: "ProjectPost";
|
||||||
|
exists: boolean;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
tags: Tag[];
|
||||||
|
|
||||||
|
searchEngine: SearchEngine;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectIndex = {
|
||||||
|
type: "ProjectIndex";
|
||||||
|
exists: boolean;
|
||||||
|
pageNumber: number;
|
||||||
|
}
|
||||||
11
astro/src/types/settings/blog.d.ts
vendored
Normal file
11
astro/src/types/settings/blog.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
type BlogSettings = {
|
||||||
|
enabled: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
subtext: string | null;
|
||||||
|
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
blogRouteTemplate: string;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
39
astro/src/types/settings/photo.d.ts
vendored
Normal file
39
astro/src/types/settings/photo.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
type WebsitePhotoSettings = {
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
categoryIndex: WebsitePhotoSettingsCategoryIndex;
|
||||||
|
category: WebsitePhotoSettingsCategory;
|
||||||
|
album: WebsitePhotoSettingsAlbum;
|
||||||
|
photo: WebsitePhotoSettingsPhoto;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsCategoryIndex = {
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsCategory = {
|
||||||
|
routeTemplate: string;
|
||||||
|
perPage: number;
|
||||||
|
icons: {
|
||||||
|
photos: PhotoProps;
|
||||||
|
location: PhotoProps;
|
||||||
|
date: PhotoProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsAlbum = {
|
||||||
|
routeTemplate: string;
|
||||||
|
perPage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsPhoto = {
|
||||||
|
routeTemplate: string;
|
||||||
|
icons: {
|
||||||
|
previous: PhotoProps;
|
||||||
|
next: PhotoProps;
|
||||||
|
close: PhotoProps;
|
||||||
|
download: PhotoProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
astro/src/types/settings/plugin.d.ts
vendored
Normal file
10
astro/src/types/settings/plugin.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
type PluginSettings = {
|
||||||
|
swetrix: PluginSettingsSwetrix | null;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginSettingsSwetrix = {
|
||||||
|
id: string | null;
|
||||||
|
url: string | null;
|
||||||
|
}
|
||||||
11
astro/src/types/settings/project.d.ts
vendored
Normal file
11
astro/src/types/settings/project.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
type ProjectSettings = {
|
||||||
|
enabled: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
subtext: string | null;
|
||||||
|
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
projectRouteTemplate: string;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
4
astro/src/types/settings/robots.d.ts
vendored
Normal file
4
astro/src/types/settings/robots.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
type RobotsSettings = {
|
||||||
|
crawlers: string[];
|
||||||
|
extraContent: string | null;
|
||||||
|
}
|
||||||
8
astro/src/types/settings/setting.d.ts
vendored
Normal file
8
astro/src/types/settings/setting.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type GlobalSettings = {
|
||||||
|
website: WebsiteSettings;
|
||||||
|
blog: BlogSettings;
|
||||||
|
project: ProjectSettings;
|
||||||
|
photo: WebsitePhotoSettings;
|
||||||
|
sitemap: SitemapSettings;
|
||||||
|
plugins: PluginSettings;
|
||||||
|
}
|
||||||
5
astro/src/types/settings/sitemap.d.ts
vendored
Normal file
5
astro/src/types/settings/sitemap.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
type SitemapSettings = {
|
||||||
|
perPage: number;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
34
astro/src/types/settings/website.d.ts
vendored
Normal file
34
astro/src/types/settings/website.d.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
type WebsiteSettings = {
|
||||||
|
domainName: string;
|
||||||
|
titleTemplate: string;
|
||||||
|
applicationName: string;
|
||||||
|
|
||||||
|
colors: WebsiteSettingsColors;
|
||||||
|
|
||||||
|
author: WebsiteSettingsAuthor;
|
||||||
|
|
||||||
|
owner: string;
|
||||||
|
designer: string;
|
||||||
|
developer: string;
|
||||||
|
copyright: string;
|
||||||
|
|
||||||
|
twitter: WebsiteSettingsTwitter;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsColors = {
|
||||||
|
primary: string;
|
||||||
|
secondary: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsAuthor = {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsTwitter = {
|
||||||
|
id: string;
|
||||||
|
handle: string;
|
||||||
|
}
|
||||||
|
|
||||||
9
astro/src/types/sitemaps/sitemap.d.ts
vendored
Normal file
9
astro/src/types/sitemaps/sitemap.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
type SitemapIndex = {
|
||||||
|
url: string;
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SitemapPage = {
|
||||||
|
url: string;
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
@@ -9,6 +9,9 @@
|
|||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "preact"
|
"jsxImportSource": "preact",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user