Compare commits
52 Commits
82587a6211
...
astro/buil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b13935c7c5 | ||
|
|
0ef04d5f3e | ||
|
|
d9430335d5 | ||
|
|
9a92b1939c | ||
|
|
b304cc400c | ||
|
|
79e343dbdc | ||
|
|
7116aa2348 | ||
|
|
c112a69f0e | ||
|
|
4a9d0fb273 | ||
|
|
29c47ab72d | ||
|
|
27b8dc4118 | ||
|
|
45a2627ec6 | ||
|
|
eba518ccc2 | ||
|
|
3cfe6697a9 | ||
|
|
07716dae17 | ||
|
|
db65ac52a3 | ||
|
|
fdc8a0aae6 | ||
|
|
092d2a4458 | ||
|
|
760281f7a4 | ||
|
|
157cb9389c | ||
|
|
be02d749dd | ||
|
|
feac162baa | ||
|
|
f86630bcb0 | ||
|
|
abaea70c7b | ||
|
|
1fde3d4f69 | ||
|
|
7b5a8bc705 | ||
|
|
d284010e28 | ||
|
|
66409ab859 | ||
|
|
46e705f6ea | ||
|
|
3bd4de2f30 | ||
|
|
00e4826744 | ||
|
|
2744e6173c | ||
|
|
915879beac | ||
|
|
6d4a62fae7 | ||
|
|
506a5ed14e | ||
|
|
2374a6bd22 | ||
|
|
8bc95d0f50 | ||
|
|
3485c4583d | ||
|
|
ee949aa76f | ||
|
|
07d2c8628f | ||
|
|
d39a98a42f | ||
|
|
525422105c | ||
|
|
a0473094cf | ||
|
|
36004bddb0 | ||
|
|
89bbbf5595 | ||
|
|
4ccbc9d9a8 | ||
|
|
b73066352e | ||
|
|
f95f792775 | ||
|
|
5c161b8381 | ||
|
|
47e50a3ba4 | ||
|
|
cf12428f98 | ||
|
|
67362dad96 |
@@ -1,14 +1,45 @@
|
|||||||
// @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';
|
import graphql from "@rollup/plugin-graphql";
|
||||||
|
import playformCompress from "@playform/compress";
|
||||||
|
import { getFiles } from "./src/build/files.ts";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact(), playformCompress({
|
||||||
|
CSS: true,
|
||||||
|
Image: false,
|
||||||
|
JSON: true,
|
||||||
|
JavaScript: false,
|
||||||
|
HTML: true
|
||||||
|
}), {
|
||||||
|
name: "download-files",
|
||||||
|
hooks: {
|
||||||
|
"astro:build:start": async ({ }) => {
|
||||||
|
await getFiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
output: "static",
|
||||||
|
prefetch: true,
|
||||||
|
build: {
|
||||||
|
assets: "assets"
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
domains: ["development.directus.itsfinniii.com"]
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss(), graphql()]
|
plugins: [graphql(), tailwindcss()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
react: "preact/compat",
|
||||||
|
"react-dom": "preact/compat",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
exclude: ["@immich/justified-layout-wasm"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
20
astro/changelogs.md
Normal file
20
astro/changelogs.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# 1.0.0.0 - Release
|
||||||
|
**Release date: **
|
||||||
|
|
||||||
|
- Add web pages with the following components:
|
||||||
|
- Contact
|
||||||
|
- Equipment Table
|
||||||
|
- Frequently Asked Questions
|
||||||
|
- Hero
|
||||||
|
- Last Albums
|
||||||
|
- Last Blogs
|
||||||
|
- Last Projects
|
||||||
|
- Reviews
|
||||||
|
- Text with Side Image
|
||||||
|
- Upcoming Events
|
||||||
|
- Wall of Text
|
||||||
|
- Add blogs
|
||||||
|
- Add projects
|
||||||
|
- Add photo categories, photo albums and photos
|
||||||
|
- Add sitemaps
|
||||||
|
- Add robots.txt
|
||||||
3113
astro/package-lock.json
generated
3113
astro/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,12 +9,14 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/preact": "^4.1.3",
|
"@astrojs/preact": "^5.1.2",
|
||||||
"@directus/sdk": "^21.2.0",
|
"@directus/sdk": "^21.2.0",
|
||||||
|
"@immich/justified-layout-wasm": "^0.4.3",
|
||||||
|
"@playform/compress": "^0.2.3",
|
||||||
"@rollup/plugin-graphql": "^2.0.5",
|
"@rollup/plugin-graphql": "^2.0.5",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.4",
|
||||||
"astro": "^5.17.1",
|
"astro": "^6.1.9",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"markdown-it": "^14.1.1",
|
"markdown-it": "^14.1.1",
|
||||||
"markdown-it-highlightjs": "^4.3.0",
|
"markdown-it-highlightjs": "^4.3.0",
|
||||||
@@ -22,10 +24,14 @@
|
|||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"minify-xml": "^4.5.2",
|
"minify-xml": "^4.5.2",
|
||||||
"preact": "^10.28.4",
|
"preact": "^10.28.4",
|
||||||
|
"react-responsive-masonry": "^2.7.2",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"tailwindcss": "^4.2.1",
|
"tailwindcss": "^4.2.4",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"vite": "^7.0.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/markdown-it": "^14.1.2",
|
"@types/markdown-it": "^14.1.2",
|
||||||
"@types/md5": "^2.3.6"
|
"@types/md5": "^2.3.6"
|
||||||
|
|||||||
3
astro/src/build/files.ts
Normal file
3
astro/src/build/files.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// This file gets files, and puts them in the public folder before starting the build.
|
||||||
|
export async function getFiles() {
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
import { getAllPaginatedBlogs } from '@/content/blogs/blogs';
|
import { getAllPaginatedBlogs } from "@/content/blogs/blogs";
|
||||||
import { getSettings } from '@/content/settings/settings';
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { getBlogRoute } from '@/lib/routing';
|
import { getBlogRoute } from "@/lib/routing";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
page: BlogIndex;
|
page: BlogIndex;
|
||||||
@@ -30,14 +30,17 @@ const blogs = await getAllPaginatedBlogs(settings, pageNumber);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-6">
|
<div class="grid grid-cols-2 gap-6">
|
||||||
{ blogs.map((blog) => (
|
{ blogs.map((blog) => {
|
||||||
|
const imageSize = getImageSize(blog.searchEngine.thumbnail.width, blog.searchEngine.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getBlogRoute(settings.blog, blog)} class={`flex flex-col gap-2`}>
|
<a href={getBlogRoute(settings.blog, blog)} class={`flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(blog.searchEngine.thumbnail.url)}
|
src={getImageUrl(blog.searchEngine.thumbnail.url)}
|
||||||
alt={blog.title}
|
alt={blog.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h4 class="font-semibold text-[28px]">{blog.title}</h4>
|
<h4 class="font-semibold text-[28px]">{blog.title}</h4>
|
||||||
@@ -47,6 +50,8 @@ const blogs = await getAllPaginatedBlogs(settings, pageNumber);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
---
|
---
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { getTypographyClasses } from "@/styles/markdownClasses";
|
||||||
import { getTypographyClasses } from '@/styles/markdownClasses';
|
import { Image } from "astro:assets";
|
||||||
import { Image } from 'astro:assets';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
blog: BlogPost;
|
blog: BlogPost;
|
||||||
@@ -28,9 +27,9 @@ const { blog } = Astro.props;
|
|||||||
<div class="aspect-1200/630 w-full max-w-full overflow-hidden">
|
<div class="aspect-1200/630 w-full max-w-full overflow-hidden">
|
||||||
<div class="w-full h-full rounded-2xl shadow-md object-cover">
|
<div class="w-full h-full rounded-2xl shadow-md object-cover">
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(blog.searchEngine.thumbnail.url)}
|
src={blog.searchEngine.thumbnail.url}
|
||||||
width="1200"
|
width={blog.searchEngine.thumbnail.width}
|
||||||
height="630"
|
height={blog.searchEngine.thumbnail.height}
|
||||||
alt={blog.title}
|
alt={blog.title}
|
||||||
class="rounded-2xl"
|
class="rounded-2xl"
|
||||||
/>
|
/>
|
||||||
|
|||||||
24
astro/src/components/common/Pagination.astro
Normal file
24
astro/src/components/common/Pagination.astro
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
page: number;
|
||||||
|
totalPages: number;
|
||||||
|
urlTemplate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page, totalPages, urlTemplate } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
{ totalPages < 7 && (
|
||||||
|
<>
|
||||||
|
{ [...Array(totalPages)].map((_: number, i: number) => (
|
||||||
|
<a
|
||||||
|
href={`${i + 1 === 1 ? urlTemplate : `${urlTemplate}/${i + 1}`}`}
|
||||||
|
class={`flex select-none hover:cursor-pointer text-lg justify-center items-center
|
||||||
|
${(i + 1 === page) ? "bg-(--ptc) text-(--ptt)" : "bg-neutral-200"} hover:bg-(--stc) hover:text-(--stt) duration-300 shadow-md rounded-full w-12 h-12`.trim()}>
|
||||||
|
<span>{i + 1}</span>
|
||||||
|
</a>
|
||||||
|
)) }
|
||||||
|
</>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
72
astro/src/components/footer/Footer.astro
Normal file
72
astro/src/components/footer/Footer.astro
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
import { getFooter } from "@/content/footer/footer";
|
||||||
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
|
const footer = await getFooter();
|
||||||
|
---
|
||||||
|
|
||||||
|
<footer class="w-full mt-4">
|
||||||
|
<div class="flex flex-col pt-12 pb-8 px-12 lg:container mx-auto">
|
||||||
|
<div class="flex md:flex-row flex-col justify-center pt-12 pb-8 md:px-1 px-0 lg:container md:mx-auto md:gap-y-8 gap-y-12 md:gap-x-24 gap-x-0">
|
||||||
|
{ (footer.title !== null || footer.logo !== null) && (
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
{ footer.title !== null && <h2 class="text-5xl font-bold">{footer.title}</h2>}
|
||||||
|
{ footer.logo !== null && (
|
||||||
|
<Image
|
||||||
|
src={footer.logo.url}
|
||||||
|
width={footer.logo.width}
|
||||||
|
height={footer.logo.height}
|
||||||
|
alt={footer.title ?? ""}
|
||||||
|
class="md:w-50 w-[50%] h-auto"
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ footer.columns.map((column) => (
|
||||||
|
<div class="flex flex-col gap-3 w-fit">
|
||||||
|
<h2 class="text-4xl font-bold">{column.title}</h2>
|
||||||
|
<div class="flex flex-col gap-3 w-fit">
|
||||||
|
{column.links.map((link) => (
|
||||||
|
<a class="text-lg text-neutral-800 hover:text-(--ptc) duration-300" href={link.url}>
|
||||||
|
<span class="w-fit">{link.text}</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)) }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ footer.socials !== null && (
|
||||||
|
<div class="flex flex-row gap-3 justify-center">
|
||||||
|
{ footer.socials.map((social) => (
|
||||||
|
<a href={social.url} target="_blank" class="bg-neutral-300 hover:bg-neutral-200 duration-300 shadow-sm rounded-full">
|
||||||
|
<div class="p-2">
|
||||||
|
<Image
|
||||||
|
src={social.icon.url}
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
alt={social.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
)) }
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ (footer.copyright !== null || footer.secondaryLinks !== null) && (
|
||||||
|
<div class="border-t border-t-neutral-200 w-full bg-neutral-50">
|
||||||
|
<div class="flex md:flex-row flex-col justify-between py-8 px-12 lg:container mx-auto gap-y-8 gap-x-24">
|
||||||
|
{ footer.copyright !== null && (<div class="text-neutral-600">{footer.copyright}</div>) }
|
||||||
|
{ footer.secondaryLinks !== null && (
|
||||||
|
<div class="flex flex-row gap-1.5">
|
||||||
|
{ footer.secondaryLinks.map((link) => (
|
||||||
|
<a class="text-neutral-600 hover:text-(--ptc) duration-300 w-fit" href={link.url}>{link.text}</a>
|
||||||
|
)) }
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
</footer>
|
||||||
55
astro/src/components/photos/Album.astro
Normal file
55
astro/src/components/photos/Album.astro
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
import { getAlbumRoute, getPhotoRoute } from "@/lib/routing";
|
||||||
|
import { AlbumPhotos } from "./Album.tsx";
|
||||||
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import Pagination from "@/components/common/Pagination.astro";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
page: PhotoAlbumPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await getSettings();
|
||||||
|
const album = Astro.props.page;
|
||||||
|
const pageNumber = Astro.props.page.pageNumber;
|
||||||
|
|
||||||
|
const totalAlbumPages = Math.ceil(album.photos.length / settings.photo.album.perPage);
|
||||||
|
const sliceStartNumber = (pageNumber - 1) * settings.photo.album.perPage;
|
||||||
|
const sliceEndNumber = pageNumber * settings.photo.album.perPage;
|
||||||
|
|
||||||
|
const remappedPhotos: PhotoAlbumGalleryItem[] = [];
|
||||||
|
|
||||||
|
album.photos.slice(sliceStartNumber, sliceEndNumber).forEach((photo) => {
|
||||||
|
const resizedImage = getImageSize(photo.photo.width, photo.photo.height, 0.756);
|
||||||
|
|
||||||
|
remappedPhotos.push({
|
||||||
|
id: photo.id,
|
||||||
|
url: getPhotoRoute(settings.photo, album, photo),
|
||||||
|
photo: {
|
||||||
|
url: getImageUrl(photo.photo.url),
|
||||||
|
width: resizedImage.width,
|
||||||
|
height: resizedImage.height
|
||||||
|
},
|
||||||
|
text: photo.text
|
||||||
|
});
|
||||||
|
});
|
||||||
|
---
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={`album-${album.id}`}
|
||||||
|
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-10 gap-x-18 w-full"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-7">
|
||||||
|
<h1 class="text-5xl font-bold">{album.title}</h1>
|
||||||
|
|
||||||
|
<AlbumPhotos client:only photos={remappedPhotos} />
|
||||||
|
|
||||||
|
{ totalAlbumPages > 1 && (
|
||||||
|
<Pagination
|
||||||
|
page={pageNumber}
|
||||||
|
totalPages={totalAlbumPages}
|
||||||
|
urlTemplate={getAlbumRoute(settings.photo, album)}
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
87
astro/src/components/photos/Album.tsx
Normal file
87
astro/src/components/photos/Album.tsx
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
|
||||||
|
import { JustifiedLayout } from "@immich/justified-layout-wasm";
|
||||||
|
import { LoadingSpinner } from "@/icons/jsx/loadingSpinner";
|
||||||
|
|
||||||
|
export function AlbumPhotos(props: { photos: PhotoAlbumGalleryItem[] }) {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
|
||||||
|
const [ hasMounted, setHasMounted ] = useState<boolean>(false);
|
||||||
|
const [ layout, setLayout ] = useState<JustifiedLayout | null>(null);
|
||||||
|
const [ containerWidth, setContainerWidth ] = useState<number | null>(null);
|
||||||
|
const [ containerHeight, setContainerHeight ] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!hasMounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
setContainerWidth(entries[0].contentRect.width);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (containerRef.current) {
|
||||||
|
observer.observe(containerRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [ hasMounted ]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (containerWidth === null || !hasMounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aspectRatios = new Float32Array(props.photos.map((photo => photo.photo.width / photo.photo.height)));
|
||||||
|
|
||||||
|
const justifiedLayout = new JustifiedLayout(aspectRatios, {
|
||||||
|
rowHeight: 265,
|
||||||
|
rowWidth: containerWidth,
|
||||||
|
spacing: 10,
|
||||||
|
heightTolerance: 0.11
|
||||||
|
});
|
||||||
|
|
||||||
|
setContainerHeight(justifiedLayout.containerHeight);
|
||||||
|
setLayout(justifiedLayout);
|
||||||
|
}, [ containerWidth, hasMounted ])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={containerRef} id={`albumgallery`}>
|
||||||
|
{ layout !== null ? (
|
||||||
|
<div class="relative w-full" style={{ height: containerHeight }}>
|
||||||
|
{ props.photos.map((photo, index: number) => {
|
||||||
|
const layoutPosition = layout.getPosition(index);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={photo.url}
|
||||||
|
key={`photo-${index}`}
|
||||||
|
class="group absolute overflow-hidden bg-neutral-200"
|
||||||
|
style={{
|
||||||
|
top: layoutPosition.top,
|
||||||
|
left: layoutPosition.left,
|
||||||
|
width: layoutPosition.width,
|
||||||
|
height: layoutPosition.height
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={photo.photo.url}
|
||||||
|
alt={photo.text ?? ""}
|
||||||
|
class="group-hover:scale-[101.5%] duration-200 w-full h-full"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div class="flex ">
|
||||||
|
<LoadingSpinner width={50} height={50} />
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -12,8 +12,6 @@ interface Props {
|
|||||||
const category = Astro.props.category;
|
const category = Astro.props.category;
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
const categoryAlbums = await getCategoryAlbums(settings, category.category.url);
|
const categoryAlbums = await getCategoryAlbums(settings, category.category.url);
|
||||||
|
|
||||||
console.log(categoryAlbums);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -32,8 +30,8 @@ console.log(categoryAlbums);
|
|||||||
<Image
|
<Image
|
||||||
src={getImageUrl(album.thumbnail.url)}
|
src={getImageUrl(album.thumbnail.url)}
|
||||||
alt={album.title}
|
alt={album.title}
|
||||||
width="1200"
|
width={album.thumbnail.width}
|
||||||
height="630"
|
height={album.thumbnail.height}
|
||||||
class="rounded-2xl transition-transform duration-300 group-hover:scale-102"
|
class="rounded-2xl transition-transform duration-300 group-hover:scale-102"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { getAllCategories } from "@/content/photos/categories";
|
import { getAllCategories } from "@/content/photos/categories";
|
||||||
import { getSettings } from "@/content/settings/settings"
|
import { getSettings } from "@/content/settings/settings"
|
||||||
import { getImageUrl } from "@/lib/images";
|
|
||||||
import { getCategoryRoute } from "@/lib/routing";
|
import { getCategoryRoute } from "@/lib/routing";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
@@ -23,10 +22,10 @@ const categories = await getAllCategories(settings);
|
|||||||
<a href={getCategoryRoute(settings.photo, category)} class="group relative block w-[70%] overflow-hidden rounded-2xl shadow-md">
|
<a href={getCategoryRoute(settings.photo, category)} class="group relative block w-[70%] overflow-hidden rounded-2xl shadow-md">
|
||||||
<div>
|
<div>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(category.thumbnail.url)}
|
src={category.thumbnail.url}
|
||||||
alt={category.title}
|
alt={category.title}
|
||||||
width="1200"
|
width={category.thumbnail.width}
|
||||||
height="630"
|
height={category.thumbnail.height}
|
||||||
class="rounded-2xl transition-transform duration-300 group-hover:scale-102"
|
class="rounded-2xl transition-transform duration-300 group-hover:scale-102"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
100
astro/src/components/photos/Photo.astro
Normal file
100
astro/src/components/photos/Photo.astro
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
import { getAlbum } from "@/content/photos/albums";
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import ChevronUp from "@/icons/ChevronUp.astro";
|
||||||
|
import Download from "@/icons/Download.astro";
|
||||||
|
import Close from "@/icons/Close.astro";
|
||||||
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
import { getAlbumRoute, getPhotoRoute } from "@/lib/routing";
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
|
import { Image } from "astro:assets";
|
||||||
|
import { getPhotoHash } from "@/lib/hash";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
page: PhotoPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const photo = Astro.props.page;
|
||||||
|
|
||||||
|
const settings = await getSettings();
|
||||||
|
const album = await getAlbum(settings, photo.album.url);
|
||||||
|
|
||||||
|
const photoIndex = album.photos.findIndex(p => p.id === photo.id);
|
||||||
|
|
||||||
|
let previousUrl: string | null = null;
|
||||||
|
let nextUrl: string | null = null;
|
||||||
|
|
||||||
|
// Check for previous photo
|
||||||
|
if (photoIndex > 0) {
|
||||||
|
previousUrl = getPhotoRoute(settings.photo, album, album.photos[photoIndex - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for next photo
|
||||||
|
if (photoIndex + 1 < album.photos.length) {
|
||||||
|
nextUrl = getPhotoRoute(settings.photo, album, album.photos[photoIndex + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const albumPageNumber = Math.ceil((photoIndex + 1) / settings.photo.album.perPage);
|
||||||
|
const returnUrl = albumPageNumber > 1
|
||||||
|
? `${getAlbumRoute(settings.photo, album)}/${albumPageNumber}`
|
||||||
|
: getAlbumRoute(settings.photo, album);
|
||||||
|
|
||||||
|
|
||||||
|
const resizedImageSize = getImageSize(photo.photo.width, photo.photo.height, 1);
|
||||||
|
const downloadImageSize = getImageSize(photo.photo.width, photo.photo.height, 5);
|
||||||
|
|
||||||
|
const downloadUrl = await getImage({
|
||||||
|
src: getImageUrl(photo.photo.url),
|
||||||
|
width: downloadImageSize.width,
|
||||||
|
height: downloadImageSize.height,
|
||||||
|
format: "jpeg",
|
||||||
|
quality: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
const downloadFileName = `${album.url.replaceAll("/", "")}-${getPhotoHash(photo)}.jpeg`;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="h-screen flex flex-col justify-center items-center">
|
||||||
|
<div class="flex flex-col justify-center items-center h-full">
|
||||||
|
<Image
|
||||||
|
src={getImageUrl(photo.photo.url)}
|
||||||
|
width={resizedImageSize.width}
|
||||||
|
height={resizedImageSize.height}
|
||||||
|
alt={photo.text ?? ""}
|
||||||
|
class="h-full w-full object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-6 absolute top-8 right-8 text-white py-2.5 px-5 bg-[#000000aa] rounded-full z-10">
|
||||||
|
<a data-astro-prefetch href={downloadUrl.src} download={downloadFileName}>
|
||||||
|
<Download width={36} height={36} />
|
||||||
|
</a>
|
||||||
|
<a data-astro-prefetch href={returnUrl}>
|
||||||
|
<Close width={36} height={36} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ photo.text !== null && (
|
||||||
|
<div class="absolute bottom-0 text-white text-xl bg-[#000000aa] w-full px-20 py-8">{photo.text.trim()}</div>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ previousUrl !== null && (
|
||||||
|
<a
|
||||||
|
data-astro-prefetch
|
||||||
|
href={previousUrl}
|
||||||
|
class="absolute left-8 text-white p-3 bg-[#000000aa] rounded-full z-10 rotate-270"
|
||||||
|
>
|
||||||
|
<ChevronUp width={28} height={28} />
|
||||||
|
</a>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ nextUrl !== null && (
|
||||||
|
<a
|
||||||
|
data-astro-prefetch
|
||||||
|
href={nextUrl}
|
||||||
|
class="absolute right-8 text-white p-3 bg-[#000000aa] rounded-full z-10 rotate-90"
|
||||||
|
>
|
||||||
|
<ChevronUp width={28} height={28} />
|
||||||
|
</a>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
import { getSettings } from '@/content/settings/settings';
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import { getAllPaginatedProjects } from '@/content/projects/projects';
|
import { getAllPaginatedProjects } from "@/content/projects/projects";
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
import { getProjectRoute } from '@/lib/routing';
|
import { getProjectRoute } from "@/lib/routing";
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
page: ProjectIndex;
|
page: ProjectIndex;
|
||||||
@@ -30,14 +30,17 @@ const projects = await getAllPaginatedProjects(settings, pageNumber);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-6">
|
<div class="grid grid-cols-2 gap-6">
|
||||||
{ projects.map((project) => (
|
{ projects.map((project) => {
|
||||||
|
const imageSize = getImageSize(project.searchEngine.thumbnail.width, project.searchEngine.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getProjectRoute(settings.project, project)} class={`flex flex-col gap-2`}>
|
<a href={getProjectRoute(settings.project, project)} class={`flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(project.searchEngine.thumbnail.url)}
|
src={getImageUrl(project.searchEngine.thumbnail.url)}
|
||||||
alt={project.title}
|
alt={project.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h4 class="font-semibold text-[28px]">{project.title}</h4>
|
<h4 class="font-semibold text-[28px]">{project.title}</h4>
|
||||||
@@ -47,6 +50,7 @@ const projects = await getAllPaginatedProjects(settings, pageNumber);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
---
|
---
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { getImageSize } from "@/lib/images";
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { getTypographyClasses } from '@/styles/markdownClasses';
|
import { getTypographyClasses } from "@/styles/markdownClasses";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
project: ProjectPost;
|
project: ProjectPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { project } = Astro.props;
|
const { project } = Astro.props;
|
||||||
|
|
||||||
|
const imageSize = getImageSize(project.searchEngine.thumbnail.width, project.searchEngine.thumbnail.height, 1);
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -28,9 +30,9 @@ const { project } = Astro.props;
|
|||||||
<div class="aspect-1200/630 w-full max-w-full overflow-hidden">
|
<div class="aspect-1200/630 w-full max-w-full overflow-hidden">
|
||||||
<div class="w-full h-full rounded-2xl shadow-md object-cover">
|
<div class="w-full h-full rounded-2xl shadow-md object-cover">
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(project.searchEngine.thumbnail.url)}
|
src={project.searchEngine.thumbnail.url}
|
||||||
width="1200"
|
width={imageSize.width}
|
||||||
height="630"
|
height={imageSize.height}
|
||||||
alt={project.title}
|
alt={project.title}
|
||||||
class="rounded-2xl"
|
class="rounded-2xl"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contact: ContactComponent;
|
contact: ContactComponent;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
equipment: EquipmentTableComponent;
|
equipment: EquipmentTableComponent;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { QuestionList } from '@/components/web/subcomponents/QuestionList.tsx';
|
import { QuestionList } from "@/components/web/subcomponents/QuestionList.tsx";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
faq: FrequentlyAskedQuestionsComponent;
|
faq: FrequentlyAskedQuestionsComponent;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
hero: HeroComponent;
|
hero: HeroComponent;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { getLastAlbums } from "@/content/photos/albums";
|
import { getLastAlbums } from "@/content/photos/albums";
|
||||||
import { getSettings } from "@/content/settings/settings";
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from "@/lib/images";
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
import { getAlbumRoute } from "@/lib/routing";
|
import { getAlbumRoute } from "@/lib/routing";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ const lastAlbums = await getLastAlbums(albums.amount);
|
|||||||
const size = calculateSizeClasses(albums.amount, lastAlbums.length);
|
const size = calculateSizeClasses(albums.amount, lastAlbums.length);
|
||||||
---
|
---
|
||||||
|
|
||||||
{ settings.photo.enabled && (
|
{ (settings.photo.enabled && lastAlbums.length > 0) && (
|
||||||
<div
|
<div
|
||||||
id={`lastalbums-${albums.id}`}
|
id={`lastalbums-${albums.id}`}
|
||||||
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
||||||
@@ -44,14 +44,17 @@ const size = calculateSizeClasses(albums.amount, lastAlbums.length);
|
|||||||
|
|
||||||
{ lastAlbums.length >= 4 ? (
|
{ lastAlbums.length >= 4 ? (
|
||||||
<div class="grid lg:grid-cols-2 lg:grid-rows-2 grid-cols-1 grid-rows-4 gap-x-10 gap-y-8">
|
<div class="grid lg:grid-cols-2 lg:grid-rows-2 grid-cols-1 grid-rows-4 gap-x-10 gap-y-8">
|
||||||
{ lastAlbums.map((album) => (
|
{ lastAlbums.map((album) => {
|
||||||
|
const imageSize = getImageSize(album.thumbnail.width, album.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getAlbumRoute(settings.photo, album)} class={`w-full flex flex-col gap-2`}>
|
<a href={getAlbumRoute(settings.photo, album)} class={`w-full flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(album.thumbnail.url)}
|
src={getImageUrl(album.thumbnail.url)}
|
||||||
alt={album.title}
|
alt={album.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<h4 class="font-semibold text-[28px]">{album.title}</h4>
|
<h4 class="font-semibold text-[28px]">{album.title}</h4>
|
||||||
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
||||||
@@ -59,19 +62,23 @@ const size = calculateSizeClasses(albums.amount, lastAlbums.length);
|
|||||||
<div>{album.startDate}</div>
|
<div>{album.startDate}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
) : (
|
) : (
|
||||||
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
||||||
{ lastAlbums.map((album) => (
|
{ lastAlbums.map((album) => {
|
||||||
|
const imageSize = getImageSize(album.thumbnail.width, album.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getAlbumRoute(settings.photo, album)} class={`${size} flex flex-col gap-2`}>
|
<a href={getAlbumRoute(settings.photo, album)} class={`${size} flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(album.thumbnail.url)}
|
src={getImageUrl(album.thumbnail.url)}
|
||||||
alt={album.title}
|
alt={album.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<h4 class="font-semibold text-[28px]">{album.title}</h4>
|
<h4 class="font-semibold text-[28px]">{album.title}</h4>
|
||||||
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
||||||
@@ -79,7 +86,9 @@ const size = calculateSizeClasses(albums.amount, lastAlbums.length);
|
|||||||
<div>{album.startDate}</div>
|
<div>{album.startDate}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
import { getLastBlogs } from '@/content/blogs/blogs';
|
import { getLastBlogs } from "@/content/blogs/blogs";
|
||||||
import { getSettings } from '@/content/settings/settings';
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
import { getBlogRoute } from '@/lib/routing';
|
import { getBlogRoute } from "@/lib/routing";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
blogs: LastBlogsComponent;
|
blogs: LastBlogsComponent;
|
||||||
@@ -25,7 +25,7 @@ const lastBlogs = await getLastBlogs(blogs.amount);
|
|||||||
const size = calculateSizeClasses(blogs.amount, lastBlogs.length);
|
const size = calculateSizeClasses(blogs.amount, lastBlogs.length);
|
||||||
---
|
---
|
||||||
|
|
||||||
{ settings.blog.enabled && (
|
{ (settings.blog.enabled && lastBlogs.length > 0) && (
|
||||||
<div
|
<div
|
||||||
id={`lastblogs-${blogs.id}`}
|
id={`lastblogs-${blogs.id}`}
|
||||||
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
||||||
@@ -43,14 +43,17 @@ const size = calculateSizeClasses(blogs.amount, lastBlogs.length);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
||||||
{ lastBlogs.map((blog) => (
|
{ lastBlogs.map((blog) => {
|
||||||
|
const imageSize = getImageSize(blog.searchEngine.thumbnail.width, blog.searchEngine.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getBlogRoute(settings.blog, blog)} class={`${size} flex flex-col gap-2`}>
|
<a href={getBlogRoute(settings.blog, blog)} class={`${size} flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(blog.searchEngine.thumbnail.url)}
|
src={getImageUrl(blog.searchEngine.thumbnail.url)}
|
||||||
alt={blog.title}
|
alt={blog.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<h4 class="font-semibold text-[28px]">{blog.title}</h4>
|
<h4 class="font-semibold text-[28px]">{blog.title}</h4>
|
||||||
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
||||||
@@ -58,7 +61,8 @@ const size = calculateSizeClasses(blogs.amount, lastBlogs.length);
|
|||||||
<div>{blog.date}</div>
|
<div>{blog.date}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
import { getLastProjects } from '@/content/projects/projects';
|
import { getLastProjects } from "@/content/projects/projects";
|
||||||
import { getSettings } from '@/content/settings/settings';
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { getImageUrl } from '@/lib/images';
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
import { getProjectRoute } from '@/lib/routing';
|
import { getProjectRoute } from "@/lib/routing";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
projects: LastProjectsComponent;
|
projects: LastProjectsComponent;
|
||||||
@@ -25,7 +25,7 @@ const lastProjects = await getLastProjects(projects.amount);
|
|||||||
const size = calculateSizeClasses(projects.amount, lastProjects.length);
|
const size = calculateSizeClasses(projects.amount, lastProjects.length);
|
||||||
---
|
---
|
||||||
|
|
||||||
{ settings.project.enabled && (
|
{ (settings.project.enabled && lastProjects.length > 0) && (
|
||||||
<div
|
<div
|
||||||
id={`lastprojects-${projects.id}`}
|
id={`lastprojects-${projects.id}`}
|
||||||
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
class="flex lg:flex-col flex-col py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full"
|
||||||
@@ -43,14 +43,17 @@ const size = calculateSizeClasses(projects.amount, lastProjects.length);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
<div class="flex flex-col lg:flex-row lg:justify-between gap-y-6">
|
||||||
{ lastProjects.map((project) => (
|
{ lastProjects.map((project) => {
|
||||||
|
const imageSize = getImageSize(project.searchEngine.thumbnail.width, project.searchEngine.thumbnail.height, 0.5);
|
||||||
|
|
||||||
|
return (
|
||||||
<a href={getProjectRoute(settings.project, project)} class={`${size} flex flex-col gap-2`}>
|
<a href={getProjectRoute(settings.project, project)} class={`${size} flex flex-col gap-2`}>
|
||||||
<Image
|
<Image
|
||||||
src={getImageUrl(project.searchEngine.thumbnail.url)}
|
src={getImageUrl(project.searchEngine.thumbnail.url)}
|
||||||
alt={project.title}
|
alt={project.title}
|
||||||
class="flex rounded-2xl shadow-md w-full"
|
class="flex rounded-2xl shadow-md w-full"
|
||||||
width={600}
|
width={imageSize.width}
|
||||||
height={315}
|
height={imageSize.height}
|
||||||
/>
|
/>
|
||||||
<h4 class="font-semibold text-[28px]">{project.title}</h4>
|
<h4 class="font-semibold text-[28px]">{project.title}</h4>
|
||||||
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
<div class="flex flex-row items-center gap-1.5 text-neutral-900 text-sm">
|
||||||
@@ -58,7 +61,8 @@ const size = calculateSizeClasses(projects.amount, lastProjects.length);
|
|||||||
<div>{project.date}</div>
|
<div>{project.date}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)) }
|
)
|
||||||
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import StarRating from './subcomponents/StarRating.astro';
|
import StarRating from "./subcomponents/StarRating.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
reviews: ReviewListComponent;
|
reviews: ReviewListComponent;
|
||||||
@@ -37,7 +37,7 @@ const reviewsToShow = reviews.reviews.slice(0, 5);
|
|||||||
|
|
||||||
<div class="flex flex-col gap-6.5">
|
<div class="flex flex-col gap-6.5">
|
||||||
{ reviewsToShow.map((review) => (
|
{ reviewsToShow.map((review) => (
|
||||||
<div class="flex flex-col justify-center gap-3 bg-neutral-50 py-4 px-5.5 rounded-2xl shadow-sm">
|
<div class="flex flex-col justify-center gap-3 bg-neutral-100 py-4 px-5.5 rounded-2xl shadow-sm">
|
||||||
<div class="flex flex-col justify-center gap-1.25">
|
<div class="flex flex-col justify-center gap-1.25">
|
||||||
<h4 class="text-2xl font-semibold">{review.name}</h4>
|
<h4 class="text-2xl font-semibold">{review.name}</h4>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
textWithImage: TextWithImageComponent;
|
textWithImage: TextWithImageComponent;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import CalendarIcon from '@/icons/CalendarIcon.astro';
|
import CalendarIcon from "@/icons/CalendarIcon.astro";
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from "astro:assets";
|
||||||
import { upcomingEvent as UpcomingEvent } from './subcomponents/UpcomingEvent';
|
import { upcomingEvent as UpcomingEvent } from "./subcomponents/UpcomingEvent";
|
||||||
import { markdownToHtml } from '@/lib/markdown';
|
import { markdownToHtml } from "@/lib/markdown";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
upcomingEvents: UpcomingEventsComponent;
|
upcomingEvents: UpcomingEventsComponent;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
---
|
---
|
||||||
import FrequentlyAskedQuestions from '../web/FrequentlyAskedQuestions.astro';
|
import FrequentlyAskedQuestions from '@/components/web/FrequentlyAskedQuestions.astro';
|
||||||
import Hero from '../web/Hero.astro';
|
import Hero from '@/components/web/Hero.astro';
|
||||||
import TextWithImage from '../web/TextWithImage.astro';
|
import TextWithImage from '@/components/web/TextWithImage.astro';
|
||||||
import UpcomingEvents from '../web/UpcomingEvents.astro';
|
import UpcomingEvents from '@/components/web/UpcomingEvents.astro';
|
||||||
import WallOfText from '../web/WallOfText.astro';
|
import WallOfText from '@/components/web/WallOfText.astro';
|
||||||
import EquipmentTable from '../web/EquipmentTable.astro';
|
import EquipmentTable from '@/components/web/EquipmentTable.astro';
|
||||||
import Reviews from '../web/Reviews.astro';
|
import Reviews from '@/components/web/Reviews.astro';
|
||||||
import LastBlogs from '../web/LastBlogs.astro';
|
import LastBlogs from '@/components/web/LastBlogs.astro';
|
||||||
import LastProjects from '../web/LastProjects.astro';
|
import LastProjects from '@/components/web/LastProjects.astro';
|
||||||
import LastAlbums from '../web/LastAlbums.astro';
|
import LastAlbums from '@/components/web/LastAlbums.astro';
|
||||||
import Contact from '../web/Contact.astro';
|
import Contact from '@/components/web/Contact.astro';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
webpage: WebpageComponent[];
|
webpage: WebpageComponent[];
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from 'graphql';
|
import { print } from "graphql";
|
||||||
import getBlogs from '@/graphql/blogs/getBlogs.graphql';
|
import getBlogs from "@/graphql/blogs/getBlogs.graphql";
|
||||||
import getBlogPost from '@/graphql/blogs/getBlog.graphql';
|
import getBlogPost from "@/graphql/blogs/getBlog.graphql";
|
||||||
import getLastBlogPosts from '@/graphql/blogs/getLastBlogPosts.graphql';
|
import getLastBlogPosts from "@/graphql/blogs/getLastBlogPosts.graphql";
|
||||||
import getPaginatedBlogs from '@/graphql/blogs/getPaginatedBlogs.graphql';
|
import getPaginatedBlogs from "@/graphql/blogs/getPaginatedBlogs.graphql";
|
||||||
import { formatDate } from "@/lib/dates";
|
import { formatDate } from "@/lib/dates";
|
||||||
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
|
|
||||||
export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]> {
|
export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
@@ -25,6 +27,9 @@ export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]>
|
|||||||
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const blogThumbnailImage =
|
||||||
|
getImageSize(blogRecord["search_engine"][0]["thumbnail"]["width"], blogRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const blog: BlogPost = {
|
const blog: BlogPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "BlogPost",
|
type: "BlogPost",
|
||||||
@@ -34,6 +39,11 @@ export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]>
|
|||||||
content: blogRecord["content"],
|
content: blogRecord["content"],
|
||||||
date: blogRecord["date"],
|
date: blogRecord["date"],
|
||||||
url: blogRecord["url"],
|
url: blogRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: blogRecord["search_engine"][0]["title"],
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
description: blogRecord["search_engine"][0]["description"],
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
@@ -42,8 +52,8 @@ export async function getAllBlogs(settings: GlobalSettings): Promise<BlogPost[]>
|
|||||||
priority: blogRecord["search_engine"][0]["priority"],
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
width: blogThumbnailImage.width,
|
||||||
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
height: blogThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -95,6 +105,16 @@ export async function getBlog(settings: GlobalSettings, route: string): Promise<
|
|||||||
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const blogThumbnailImage = getImageSize(blogRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
blogRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: getImageUrl(blogRecord["search_engine"][0]["thumbnail"]["filename_disk"]),
|
||||||
|
width: blogThumbnailImage.width,
|
||||||
|
height: blogThumbnailImage.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
const blog: BlogPost = {
|
const blog: BlogPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "BlogPost",
|
type: "BlogPost",
|
||||||
@@ -104,6 +124,11 @@ export async function getBlog(settings: GlobalSettings, route: string): Promise<
|
|||||||
content: blogRecord["content"],
|
content: blogRecord["content"],
|
||||||
date: blogRecord["date"],
|
date: blogRecord["date"],
|
||||||
url: blogRecord["url"],
|
url: blogRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: blogRecord["search_engine"][0]["title"],
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
description: blogRecord["search_engine"][0]["description"],
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
@@ -111,9 +136,9 @@ export async function getBlog(settings: GlobalSettings, route: string): Promise<
|
|||||||
canonical: blogRecord["search_engine"][0]["canonical"],
|
canonical: blogRecord["search_engine"][0]["canonical"],
|
||||||
priority: blogRecord["search_engine"][0]["priority"],
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
width: blogThumbnailImage.width,
|
||||||
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
height: blogThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -162,6 +187,9 @@ export async function getLastBlogs(amount: number): Promise<BlogPost[]> {
|
|||||||
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const blogThumbnailImage =
|
||||||
|
getImageSize(blogRecord["search_engine"][0]["thumbnail"]["width"], blogRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const blog: BlogPost = {
|
const blog: BlogPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "BlogPost",
|
type: "BlogPost",
|
||||||
@@ -171,6 +199,11 @@ export async function getLastBlogs(amount: number): Promise<BlogPost[]> {
|
|||||||
content: blogRecord["content"],
|
content: blogRecord["content"],
|
||||||
date: blogRecord["date"],
|
date: blogRecord["date"],
|
||||||
url: blogRecord["url"],
|
url: blogRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: blogRecord["search_engine"][0]["title"],
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
description: blogRecord["search_engine"][0]["description"],
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
@@ -179,8 +212,8 @@ export async function getLastBlogs(amount: number): Promise<BlogPost[]> {
|
|||||||
priority: blogRecord["search_engine"][0]["priority"],
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
width: blogThumbnailImage.width,
|
||||||
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
height: blogThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -235,6 +268,9 @@ export async function getAllPaginatedBlogs(settings: GlobalSettings, page: numbe
|
|||||||
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
blogRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const blogThumbnailImage =
|
||||||
|
getImageSize(blogRecord["search_engine"][0]["thumbnail"]["width"], blogRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const blog: BlogPost = {
|
const blog: BlogPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "BlogPost",
|
type: "BlogPost",
|
||||||
@@ -244,6 +280,11 @@ export async function getAllPaginatedBlogs(settings: GlobalSettings, page: numbe
|
|||||||
content: blogRecord["content"],
|
content: blogRecord["content"],
|
||||||
date: blogRecord["date"],
|
date: blogRecord["date"],
|
||||||
url: blogRecord["url"],
|
url: blogRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: blogRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: blogRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: blogRecord["search_engine"][0]["title"],
|
title: blogRecord["search_engine"][0]["title"],
|
||||||
description: blogRecord["search_engine"][0]["description"],
|
description: blogRecord["search_engine"][0]["description"],
|
||||||
@@ -252,8 +293,8 @@ export async function getAllPaginatedBlogs(settings: GlobalSettings, page: numbe
|
|||||||
priority: blogRecord["search_engine"][0]["priority"],
|
priority: blogRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: blogRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
height: blogRecord["search_engine"][0]["thumbnail"]["height"],
|
width: blogThumbnailImage.width,
|
||||||
width: blogRecord["search_engine"][0]["thumbnail"]["width"]
|
height: blogThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
|
|||||||
110
astro/src/content/footer/footer.ts
Normal file
110
astro/src/content/footer/footer.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import type { Footer, FooterColumn, FooterSecondaryLink, FooterSocial } from "@/types/footers/footer";
|
||||||
|
import getFooterQuery from "@/graphql/footer/getFooter.graphql";
|
||||||
|
import { getImageUrl } from "@/lib/images";
|
||||||
|
|
||||||
|
export async function getFooter(): Promise<Footer> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getFooterQuery));
|
||||||
|
|
||||||
|
const footerRecord = result["Footer"];
|
||||||
|
|
||||||
|
let dates: string[] = [
|
||||||
|
footerRecord["date_created"],
|
||||||
|
footerRecord["date_updated"]
|
||||||
|
];
|
||||||
|
|
||||||
|
let footer: Footer = {
|
||||||
|
id: footerRecord["id"],
|
||||||
|
title: footerRecord["title"],
|
||||||
|
logo: {
|
||||||
|
url: getImageUrl(footerRecord["logo"]["filename_disk"]),
|
||||||
|
width: footerRecord["logo"]["width"],
|
||||||
|
height: footerRecord["logo"]["height"]
|
||||||
|
},
|
||||||
|
copyright: footerRecord["copyright"],
|
||||||
|
columns: [],
|
||||||
|
socials: null,
|
||||||
|
secondaryLinks: null,
|
||||||
|
lastModified: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (footerRecord["columns"] !== null) {
|
||||||
|
footerRecord["columns"].forEach((footerColumn: any) => {
|
||||||
|
const column: FooterColumn = {
|
||||||
|
id: footerColumn["id"],
|
||||||
|
title: footerColumn["title"],
|
||||||
|
links: []
|
||||||
|
};
|
||||||
|
|
||||||
|
footerColumn["links"].forEach((columnLink: any) => {
|
||||||
|
column.links.push({
|
||||||
|
id: columnLink["id"],
|
||||||
|
text: columnLink["text"],
|
||||||
|
url: columnLink["url"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(columnLink["date_created"]);
|
||||||
|
dates.push(columnLink["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
footer.columns.push(column);
|
||||||
|
|
||||||
|
dates.push(footerColumn["date_created"]);
|
||||||
|
dates.push(footerColumn["date_updated"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (footerRecord["socials"] !== null) {
|
||||||
|
let socials: FooterSocial[] = [];
|
||||||
|
|
||||||
|
footerRecord["socials"].forEach((footerSocial: any) => {
|
||||||
|
socials.push({
|
||||||
|
id: footerSocial["id"],
|
||||||
|
name: footerSocial["name"],
|
||||||
|
url: footerSocial["url"],
|
||||||
|
icon: {
|
||||||
|
url: getImageUrl(footerSocial["icon"]["filename_disk"]),
|
||||||
|
width: footerSocial["icon"]["width"],
|
||||||
|
height: footerSocial["icon"]["height"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(footerSocial["date_created"]);
|
||||||
|
dates.push(footerSocial["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
footer.socials = socials;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (footerRecord["secondary_links"] !== null) {
|
||||||
|
let secondaryLinks: FooterSecondaryLink[] = [];
|
||||||
|
|
||||||
|
footerRecord["secondary_links"].forEach((footerSecondaryLink: any) => {
|
||||||
|
secondaryLinks.push({
|
||||||
|
id: footerSecondaryLink["id"],
|
||||||
|
text: footerSecondaryLink["text"],
|
||||||
|
url: footerSecondaryLink["url"]
|
||||||
|
});
|
||||||
|
|
||||||
|
dates.push(footerSecondaryLink["date_created"]);
|
||||||
|
dates.push(footerSecondaryLink["date_updated"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
footer.secondaryLinks = secondaryLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dates.filter(e => e !== null).length === 0) {
|
||||||
|
footer.lastModified = new Date();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sortedDates: string[] = dates.sort((a: string, b: string) => {
|
||||||
|
return new Date(b).getTime() - new Date(a).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
footer.lastModified = new Date(sortedDates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return footer;
|
||||||
|
}
|
||||||
39
astro/src/content/menu/menu.ts
Normal file
39
astro/src/content/menu/menu.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import { print } from "graphql";
|
||||||
|
import getMenuQuery from "@/graphql/menu/getMenu.graphql";
|
||||||
|
|
||||||
|
export async function getMenu(): Promise<Menu> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getMenuQuery));
|
||||||
|
|
||||||
|
const menuRecord = result["Menu"];
|
||||||
|
|
||||||
|
let menu: Menu = {
|
||||||
|
id: menuRecord["id"],
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
|
||||||
|
menuRecord["items"].forEach((menuItem: any) => {
|
||||||
|
if (menuItem["collection"] === "Menu_Column") {
|
||||||
|
let menuColumnItem: MenuColumn = {
|
||||||
|
id: menuItem["item"]["id"],
|
||||||
|
type: "Column",
|
||||||
|
title: menuItem["item"]["title"],
|
||||||
|
links: []
|
||||||
|
};
|
||||||
|
|
||||||
|
menuItem["item"]["links"].forEach((menuItemLink: any) => {
|
||||||
|
menuColumnItem.links.push({
|
||||||
|
id: menuItemLink["id"],
|
||||||
|
type: "Link",
|
||||||
|
text: menuItemLink["text"],
|
||||||
|
url: menuItemLink["url"]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.items.push(menuColumnItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from 'graphql';
|
import { print } from "graphql";
|
||||||
import { formatDate } from "@/lib/dates";
|
import { formatDate } from "@/lib/dates";
|
||||||
import getAllPages from "@/graphql/pages/getAllPages.graphql";
|
import getAllPages from "@/graphql/pages/getAllPages.graphql";
|
||||||
import getPage from "@/graphql/pages/getPage.graphql";
|
import getPage from "@/graphql/pages/getPage.graphql";
|
||||||
import { getImageUrl } from "@/lib/images";
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
|
||||||
export function dataToPage(pageRecord: any): WebPage {
|
export function dataToPage(pageRecord: any): WebPage {
|
||||||
let dates: string[] = [
|
let dates: string[] = [
|
||||||
@@ -22,6 +22,9 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
|
|
||||||
switch (componentRecord["item"]["__typename"]) {
|
switch (componentRecord["item"]["__typename"]) {
|
||||||
case "Hero":
|
case "Hero":
|
||||||
|
const resizedHeroImage =
|
||||||
|
getImageSize(component["background_image"]["width"], component["background_image"]["height"], 2.5);
|
||||||
|
|
||||||
let heroComponent: HeroComponent = {
|
let heroComponent: HeroComponent = {
|
||||||
component: "Hero",
|
component: "Hero",
|
||||||
id: component["hero_id"],
|
id: component["hero_id"],
|
||||||
@@ -29,8 +32,8 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
text: component["hero_text"],
|
text: component["hero_text"],
|
||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
url: getImageUrl(component["background_image"]["filename_disk"]),
|
url: getImageUrl(component["background_image"]["filename_disk"]),
|
||||||
width: component["background_image"]["width"],
|
width: resizedHeroImage.width,
|
||||||
height: component["background_image"]["height"]
|
height: resizedHeroImage.height
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,6 +44,9 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case "Text_With_Side_Image":
|
case "Text_With_Side_Image":
|
||||||
|
const resizedTextWithSideImage =
|
||||||
|
getImageSize(component["image"]["width"], component["image"]["height"], 1.5);
|
||||||
|
|
||||||
let textWithImageComponent: TextWithImageComponent = {
|
let textWithImageComponent: TextWithImageComponent = {
|
||||||
component: "TextWithImage",
|
component: "TextWithImage",
|
||||||
id: component["twsi_id"],
|
id: component["twsi_id"],
|
||||||
@@ -50,8 +56,8 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
imageSize: component["twsi_image_size"],
|
imageSize: component["twsi_image_size"],
|
||||||
image: {
|
image: {
|
||||||
url: getImageUrl(component["image"]["filename_disk"]),
|
url: getImageUrl(component["image"]["filename_disk"]),
|
||||||
width: component["image"]["width"],
|
width: resizedTextWithSideImage.width,
|
||||||
height: component["image"]["height"]
|
height: resizedTextWithSideImage.height
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,6 +115,9 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
component["events"].forEach((eventRecord: any) => {
|
component["events"].forEach((eventRecord: any) => {
|
||||||
|
const resizedThumbnailImage =
|
||||||
|
getImageSize(eventRecord["thumbnail"]["width"], eventRecord["thumbnail"]["height"], 1);
|
||||||
|
|
||||||
upcomingEventsComponent.events.push({
|
upcomingEventsComponent.events.push({
|
||||||
id: eventRecord["id"],
|
id: eventRecord["id"],
|
||||||
title: eventRecord["title"],
|
title: eventRecord["title"],
|
||||||
@@ -120,8 +129,8 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
],
|
],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: getImageUrl(eventRecord["thumbnail"]["filename_disk"]),
|
url: getImageUrl(eventRecord["thumbnail"]["filename_disk"]),
|
||||||
width: eventRecord["thumbnail"]["width"],
|
width: resizedThumbnailImage.width,
|
||||||
height: eventRecord["thumbnail"]["height"]
|
height: resizedThumbnailImage.height
|
||||||
},
|
},
|
||||||
startDate: eventRecord["start_date"],
|
startDate: eventRecord["start_date"],
|
||||||
endDate: eventRecord["end_date"]
|
endDate: eventRecord["end_date"]
|
||||||
@@ -177,6 +186,9 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
component["reviews"].forEach((reviewRecord: any) => {
|
component["reviews"].forEach((reviewRecord: any) => {
|
||||||
|
const reviewThumbnailImage =
|
||||||
|
getImageSize(reviewRecord["thumbnail"]["width"], reviewRecord["thumbnail"]["height"], 1);
|
||||||
|
|
||||||
reviewsComponent.reviews.push({
|
reviewsComponent.reviews.push({
|
||||||
id: reviewRecord["id"],
|
id: reviewRecord["id"],
|
||||||
name: reviewRecord["name"],
|
name: reviewRecord["name"],
|
||||||
@@ -185,8 +197,8 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
date: reviewRecord["date"],
|
date: reviewRecord["date"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: getImageUrl(reviewRecord["thumbnail"]["filename_disk"]),
|
url: getImageUrl(reviewRecord["thumbnail"]["filename_disk"]),
|
||||||
width: reviewRecord["thumbnail"]["width"],
|
width: reviewThumbnailImage.width,
|
||||||
height: reviewRecord["thumbnail"]["height"]
|
height: reviewThumbnailImage.height
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -292,6 +304,9 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
lastModified = new Date(sortedDates[0]);
|
lastModified = new Date(sortedDates[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const thumbnailImage =
|
||||||
|
getImageSize(searchEngine["thumbnail"]["width"], searchEngine["thumbnail"]["width"], 0.756);
|
||||||
|
|
||||||
let page: WebPage = {
|
let page: WebPage = {
|
||||||
type: "Webpage",
|
type: "Webpage",
|
||||||
exists: true,
|
exists: true,
|
||||||
@@ -306,8 +321,8 @@ export function dataToPage(pageRecord: any): WebPage {
|
|||||||
priority: searchEngine["priority"],
|
priority: searchEngine["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: getImageUrl(searchEngine["thumbnail"]["filename_disk"]),
|
url: getImageUrl(searchEngine["thumbnail"]["filename_disk"]),
|
||||||
height: searchEngine["thumbnail"]["height"],
|
height: thumbnailImage.height,
|
||||||
width: searchEngine["thumbnail"]["width"]
|
width: thumbnailImage.width
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: components
|
components: components
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from "graphql";
|
import { print } from "graphql";
|
||||||
import getAlbums from '@/graphql/photos/getAlbums.graphql';
|
import getAlbums from "@/graphql/photos/getAlbums.graphql";
|
||||||
import getAlbumItem from '@/graphql/photos/getAlbum.graphql';
|
import getAlbumItem from "@/graphql/photos/getAlbum.graphql";
|
||||||
import getLastAlbumsQuery from '@/graphql/photos/getLastAlbums.graphql';
|
import getLastAlbumsQuery from "@/graphql/photos/getLastAlbums.graphql";
|
||||||
import getCategoryAlbumQuery from '@/graphql/photos/getCategoryAlbum.graphql';
|
import getCategoryAlbumQuery from "@/graphql/photos/getCategoryAlbum.graphql";
|
||||||
import { formatDate } from "@/lib/dates";
|
import { formatDate } from "@/lib/dates";
|
||||||
|
import { getImageSize } from "@/lib/images";
|
||||||
|
|
||||||
export async function getAllAlbums(settings: GlobalSettings): Promise<PhotoAlbum[]> {
|
export async function getAllAlbums(settings: GlobalSettings): Promise<PhotoAlbum[]> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
@@ -23,9 +24,16 @@ export async function getAllAlbums(settings: GlobalSettings): Promise<PhotoAlbum
|
|||||||
albumRecord["thumbnail"]["created_on"],
|
albumRecord["thumbnail"]["created_on"],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const categoryThumbnailImage =
|
||||||
|
getImageSize(albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"], albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
|
const thumbnailImage =
|
||||||
|
getImageSize(albumRecord["thumbnail"]["width"], albumRecord["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const album: PhotoAlbum = {
|
const album: PhotoAlbum = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "PhotoAlbum",
|
type: "PhotoAlbum",
|
||||||
|
id: albumRecord["id"],
|
||||||
title: albumRecord["title"],
|
title: albumRecord["title"],
|
||||||
description: albumRecord["description"],
|
description: albumRecord["description"],
|
||||||
url: albumRecord["url"],
|
url: albumRecord["url"],
|
||||||
@@ -38,14 +46,14 @@ export async function getAllAlbums(settings: GlobalSettings): Promise<PhotoAlbum
|
|||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
width: categoryThumbnailImage.width,
|
||||||
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
height: categoryThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["thumbnail"]["filename_disk"],
|
url: albumRecord["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["thumbnail"]["height"],
|
width: thumbnailImage.width,
|
||||||
width: albumRecord["thumbnail"]["width"]
|
height: thumbnailImage.height
|
||||||
},
|
},
|
||||||
photos: [],
|
photos: [],
|
||||||
lastModified: new Date()
|
lastModified: new Date()
|
||||||
@@ -100,9 +108,16 @@ export async function getAlbum(settings: GlobalSettings, route: string): Promise
|
|||||||
albumRecord["thumbnail"]["created_on"],
|
albumRecord["thumbnail"]["created_on"],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const categoryThumbnailImage =
|
||||||
|
getImageSize(albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"], albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
|
const thumbnailImage =
|
||||||
|
getImageSize(albumRecord["thumbnail"]["width"], albumRecord["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const album: PhotoAlbum = {
|
const album: PhotoAlbum = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "PhotoAlbum",
|
type: "PhotoAlbum",
|
||||||
|
id: albumRecord["id"],
|
||||||
title: albumRecord["title"],
|
title: albumRecord["title"],
|
||||||
description: albumRecord["description"],
|
description: albumRecord["description"],
|
||||||
url: albumRecord["url"],
|
url: albumRecord["url"],
|
||||||
@@ -115,14 +130,14 @@ export async function getAlbum(settings: GlobalSettings, route: string): Promise
|
|||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
width: categoryThumbnailImage.width,
|
||||||
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
height: categoryThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["thumbnail"]["filename_download"],
|
url: albumRecord["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["thumbnail"]["height"],
|
width: thumbnailImage.width,
|
||||||
width: albumRecord["thumbnail"]["width"]
|
height: thumbnailImage.height
|
||||||
},
|
},
|
||||||
photos: [],
|
photos: [],
|
||||||
lastModified: new Date()
|
lastModified: new Date()
|
||||||
@@ -174,9 +189,16 @@ export async function getLastAlbums(amount: number) {
|
|||||||
albumRecord["thumbnail"]["created_on"],
|
albumRecord["thumbnail"]["created_on"],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const categoryThumbnailImage =
|
||||||
|
getImageSize(albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"], albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
|
const thumbnailImage =
|
||||||
|
getImageSize(albumRecord["thumbnail"]["width"], albumRecord["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const album: PhotoAlbum = {
|
const album: PhotoAlbum = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "PhotoAlbum",
|
type: "PhotoAlbum",
|
||||||
|
id: albumRecord["id"],
|
||||||
title: albumRecord["title"],
|
title: albumRecord["title"],
|
||||||
description: albumRecord["description"],
|
description: albumRecord["description"],
|
||||||
url: albumRecord["url"],
|
url: albumRecord["url"],
|
||||||
@@ -189,14 +211,14 @@ export async function getLastAlbums(amount: number) {
|
|||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
width: categoryThumbnailImage.width,
|
||||||
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
height: categoryThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["thumbnail"]["filename_disk"],
|
url: albumRecord["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["thumbnail"]["height"],
|
width: thumbnailImage.width,
|
||||||
width: albumRecord["thumbnail"]["width"]
|
height: thumbnailImage.height
|
||||||
},
|
},
|
||||||
photos: [],
|
photos: [],
|
||||||
lastModified: new Date()
|
lastModified: new Date()
|
||||||
@@ -253,9 +275,16 @@ export async function getCategoryAlbums(settings: GlobalSettings, route: string)
|
|||||||
albumRecord["thumbnail"]["created_on"],
|
albumRecord["thumbnail"]["created_on"],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const categoryThumbnailImage =
|
||||||
|
getImageSize(albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"], albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
|
const thumbnailImage =
|
||||||
|
getImageSize(albumRecord["thumbnail"]["width"], albumRecord["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const album: PhotoAlbum = {
|
const album: PhotoAlbum = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "PhotoAlbum",
|
type: "PhotoAlbum",
|
||||||
|
id: albumRecord["id"],
|
||||||
title: albumRecord["title"],
|
title: albumRecord["title"],
|
||||||
description: albumRecord["description"],
|
description: albumRecord["description"],
|
||||||
url: albumRecord["url"],
|
url: albumRecord["url"],
|
||||||
@@ -268,20 +297,23 @@ export async function getCategoryAlbums(settings: GlobalSettings, route: string)
|
|||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
url: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["height"],
|
width: categoryThumbnailImage.width,
|
||||||
width: albumRecord["category"][0]["Photo_Categories_id"]["thumbnail"]["width"]
|
height: categoryThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: albumRecord["thumbnail"]["filename_disk"],
|
url: albumRecord["thumbnail"]["filename_disk"],
|
||||||
height: albumRecord["thumbnail"]["height"],
|
width: thumbnailImage.width,
|
||||||
width: albumRecord["thumbnail"]["width"]
|
height: thumbnailImage.height
|
||||||
},
|
},
|
||||||
photos: [],
|
photos: [],
|
||||||
lastModified: new Date()
|
lastModified: new Date()
|
||||||
};
|
};
|
||||||
|
|
||||||
albumRecord["photos"].forEach((photoRecord: any) => {
|
albumRecord["photos"].forEach((photoRecord: any) => {
|
||||||
|
const imageSize =
|
||||||
|
getImageSize(photoRecord["photo"]["width"], photoRecord["photo"]["height"], 0.8);
|
||||||
|
|
||||||
album.photos.push({
|
album.photos.push({
|
||||||
id: photoRecord["id"],
|
id: photoRecord["id"],
|
||||||
photo: {
|
photo: {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from "graphql";
|
import { print } from "graphql";
|
||||||
import getCategories from '@/graphql/photos/getCategories.graphql';
|
import getCategories from "@/graphql/photos/getCategories.graphql";
|
||||||
import getCategory from '@/graphql/photos/getCategory.graphql';
|
import getCategory from "@/graphql/photos/getCategory.graphql";
|
||||||
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
|
||||||
export async function getAllCategories(settings: GlobalSettings): Promise<PhotoAlbumCategory[]> {
|
export async function getAllCategories(settings: GlobalSettings): Promise<PhotoAlbumCategory[]> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
@@ -10,14 +11,17 @@ export async function getAllCategories(settings: GlobalSettings): Promise<PhotoA
|
|||||||
let categories: PhotoAlbumCategory[] = [];
|
let categories: PhotoAlbumCategory[] = [];
|
||||||
|
|
||||||
result["Photo_Categories"].forEach((photoCategoryRecord: any) => {
|
result["Photo_Categories"].forEach((photoCategoryRecord: any) => {
|
||||||
|
const imageSize = getImageSize(photoCategoryRecord["thumbnail"]["width"],
|
||||||
|
photoCategoryRecord["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
categories.push({
|
categories.push({
|
||||||
id: photoCategoryRecord["id"],
|
id: photoCategoryRecord["id"],
|
||||||
title: photoCategoryRecord["title"],
|
title: photoCategoryRecord["title"],
|
||||||
url: photoCategoryRecord["url"],
|
url: photoCategoryRecord["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: photoCategoryRecord["thumbnail"]["filename_disk"],
|
url: getImageUrl(photoCategoryRecord["thumbnail"]["filename_disk"]),
|
||||||
width: photoCategoryRecord["thumbnail"]["width"],
|
width: imageSize.width,
|
||||||
height: photoCategoryRecord["thumbnail"]["height"]
|
height: imageSize.height
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -33,14 +37,17 @@ export async function getPhotoCategory(url: string): Promise<PhotoAlbumCategory>
|
|||||||
|
|
||||||
const item = result["Photo_Categories"][0];
|
const item = result["Photo_Categories"][0];
|
||||||
|
|
||||||
|
const imageSize = getImageSize(item["thumbnail"]["width"],
|
||||||
|
item["thumbnail"]["height"], 1.5);
|
||||||
|
|
||||||
let categories: PhotoAlbumCategory = {
|
let categories: PhotoAlbumCategory = {
|
||||||
id: item["id"],
|
id: item["id"],
|
||||||
title: item["title"],
|
title: item["title"],
|
||||||
url: item["url"],
|
url: item["url"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: item["thumbnail"]["filename_disk"],
|
url: getImageUrl(item["thumbnail"]["filename_disk"]),
|
||||||
width: item["thumbnail"]["width"],
|
width: imageSize.width,
|
||||||
height: item["thumbnail"]["height"]
|
height: imageSize.height
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from "graphql";
|
import { print } from "graphql";
|
||||||
import getPhotos from '@/graphql/photos/getPhotos.graphql';
|
import getPhotos from "@/graphql/photos/getPhotos.graphql";
|
||||||
import md5 from "md5";
|
import md5 from "md5";
|
||||||
|
|
||||||
export async function getPhotoFromHash(albumUrl: string, hash: string): Promise<PhotoAlbumPhoto | null> {
|
export async function getPhotoFromHash(albumUrl: string, hash: string): Promise<PhotoAlbumItem | null> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
const result = await client.query(print(getPhotos), {
|
const result = await client.query(print(getPhotos), {
|
||||||
albumUrl: albumUrl
|
albumUrl: albumUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
let object: PhotoAlbumPhoto | null = null;
|
let object: PhotoAlbumItem | null = null;
|
||||||
|
|
||||||
result["Photo_Albums"][0]["photos"].forEach((photo: any) => {
|
result["Photo_Albums"][0]["photos"].forEach((photo: any) => {
|
||||||
|
/*
|
||||||
|
* I have decided to not put the getImageSize here, it can mess up the
|
||||||
|
* hashing, or anything else. It seems smarter to do this in the photo"s and galleries.
|
||||||
|
*/
|
||||||
|
|
||||||
const hashObject = md5(JSON.stringify({
|
const hashObject = md5(JSON.stringify({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
url: photo.photo.filename_disk,
|
url: photo.photo.filename_disk,
|
||||||
@@ -24,9 +29,13 @@ export async function getPhotoFromHash(albumUrl: string, hash: string): Promise<
|
|||||||
id: photo.id,
|
id: photo.id,
|
||||||
text: photo.text,
|
text: photo.text,
|
||||||
photo: {
|
photo: {
|
||||||
url: photo.photo.url,
|
url: photo.photo.filename_disk,
|
||||||
width: photo.photo.width,
|
width: photo.photo.width,
|
||||||
height: photo.photo.height
|
height: photo.photo.height
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
url: result["Photo_Albums"][0].url,
|
||||||
|
title: result["Photo_Albums"][0].title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { formatDate } from "@/lib/dates";
|
import { formatDate } from "@/lib/dates";
|
||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from "graphql";
|
import { print } from "graphql";
|
||||||
import getProjects from '@/graphql/projects/getProjects.graphql';
|
import getProjects from "@/graphql/projects/getProjects.graphql";
|
||||||
import getProjectPost from '@/graphql/projects/getProject.graphql';
|
import getProjectPost from "@/graphql/projects/getProject.graphql";
|
||||||
import getLastProjectsQuery from '@/graphql/projects/getLastProjects.graphql';
|
import getLastProjectsQuery from "@/graphql/projects/getLastProjects.graphql";
|
||||||
|
import { getImageSize, getImageUrl } from "@/lib/images";
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
|
|
||||||
export async function getAllProjects(settings: GlobalSettings): Promise<ProjectPost[]> {
|
export async function getAllProjects(settings: GlobalSettings): Promise<ProjectPost[]> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
@@ -24,6 +26,9 @@ export async function getAllProjects(settings: GlobalSettings): Promise<ProjectP
|
|||||||
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const projectThumbnailImage = getImageSize(projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
projectRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
const project: ProjectPost = {
|
const project: ProjectPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "ProjectPost",
|
type: "ProjectPost",
|
||||||
@@ -33,6 +38,11 @@ export async function getAllProjects(settings: GlobalSettings): Promise<ProjectP
|
|||||||
content: projectRecord["content"],
|
content: projectRecord["content"],
|
||||||
date: projectRecord["date"],
|
date: projectRecord["date"],
|
||||||
url: projectRecord["url"],
|
url: projectRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: getImageUrl(projectRecord["search_engine"][0]["thumbnail"]["filename_disk"]),
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: projectRecord["search_engine"][0]["title"],
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
description: projectRecord["search_engine"][0]["description"],
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
@@ -40,9 +50,9 @@ export async function getAllProjects(settings: GlobalSettings): Promise<ProjectP
|
|||||||
canonical: projectRecord["search_engine"][0]["canonical"],
|
canonical: projectRecord["search_engine"][0]["canonical"],
|
||||||
priority: projectRecord["search_engine"][0]["priority"],
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: getImageUrl(projectRecord["search_engine"][0]["thumbnail"]["filename_disk"]),
|
||||||
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
width: projectThumbnailImage.width,
|
||||||
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
height: projectThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -94,6 +104,16 @@ export async function getProject(settings: GlobalSettings, route: string): Promi
|
|||||||
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const projectThumbnailImage = getImageSize(projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
projectRecord["search_engine"][0]["thumbnail"]["height"], 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: getImageUrl(projectRecord["search_engine"][0]["thumbnail"]["filename_disk"]),
|
||||||
|
width: projectThumbnailImage.width,
|
||||||
|
height: projectThumbnailImage.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
const project: ProjectPost = {
|
const project: ProjectPost = {
|
||||||
type: "ProjectPost",
|
type: "ProjectPost",
|
||||||
exists: true,
|
exists: true,
|
||||||
@@ -104,6 +124,11 @@ export async function getProject(settings: GlobalSettings, route: string): Promi
|
|||||||
content: projectRecord["content"],
|
content: projectRecord["content"],
|
||||||
date: projectRecord["date"],
|
date: projectRecord["date"],
|
||||||
url: projectRecord["url"],
|
url: projectRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: projectRecord["search_engine"][0]["title"],
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
description: projectRecord["search_engine"][0]["description"],
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
@@ -111,9 +136,9 @@ export async function getProject(settings: GlobalSettings, route: string): Promi
|
|||||||
canonical: projectRecord["search_engine"][0]["canonical"],
|
canonical: projectRecord["search_engine"][0]["canonical"],
|
||||||
priority: projectRecord["search_engine"][0]["priority"],
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
width: projectThumbnailImage.width,
|
||||||
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
height: projectThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -162,6 +187,9 @@ export async function getLastProjects(amount: number): Promise<ProjectPost[]> {
|
|||||||
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const projectThumbnailImage =
|
||||||
|
getImageSize(projectRecord["search_engine"][0]["thumbnail"]["width"], projectRecord["search_engine"][0]["thumbnail"]["height"], 0.756)
|
||||||
|
|
||||||
const project: ProjectPost = {
|
const project: ProjectPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "ProjectPost",
|
type: "ProjectPost",
|
||||||
@@ -171,6 +199,11 @@ export async function getLastProjects(amount: number): Promise<ProjectPost[]> {
|
|||||||
content: projectRecord["content"],
|
content: projectRecord["content"],
|
||||||
date: projectRecord["date"],
|
date: projectRecord["date"],
|
||||||
url: projectRecord["url"],
|
url: projectRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: projectRecord["search_engine"][0]["title"],
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
description: projectRecord["search_engine"][0]["description"],
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
@@ -179,8 +212,8 @@ export async function getLastProjects(amount: number): Promise<ProjectPost[]> {
|
|||||||
priority: projectRecord["search_engine"][0]["priority"],
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
width: projectThumbnailImage.width,
|
||||||
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
height: projectThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
@@ -235,6 +268,9 @@ export async function getAllPaginatedProjects(settings: GlobalSettings, page: nu
|
|||||||
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
projectRecord["search_engine"][0]["thumbnail"]["created_on"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const projectThumbnailImage =
|
||||||
|
getImageSize(projectRecord["search_engine"][0]["thumbnail"]["width"], projectRecord["search_engine"][0]["thumbnail"]["height"], 0.756)
|
||||||
|
|
||||||
const project: ProjectPost = {
|
const project: ProjectPost = {
|
||||||
exists: true,
|
exists: true,
|
||||||
type: "ProjectPost",
|
type: "ProjectPost",
|
||||||
@@ -244,6 +280,11 @@ export async function getAllPaginatedProjects(settings: GlobalSettings, page: nu
|
|||||||
content: projectRecord["content"],
|
content: projectRecord["content"],
|
||||||
date: projectRecord["date"],
|
date: projectRecord["date"],
|
||||||
url: projectRecord["url"],
|
url: projectRecord["url"],
|
||||||
|
thumbnail: {
|
||||||
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
|
width: projectRecord["search_engine"][0]["thumbnail"]["width"],
|
||||||
|
height: projectRecord["search_engine"][0]["thumbnail"]["height"]
|
||||||
|
},
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: projectRecord["search_engine"][0]["title"],
|
title: projectRecord["search_engine"][0]["title"],
|
||||||
description: projectRecord["search_engine"][0]["description"],
|
description: projectRecord["search_engine"][0]["description"],
|
||||||
@@ -252,8 +293,8 @@ export async function getAllPaginatedProjects(settings: GlobalSettings, page: nu
|
|||||||
priority: projectRecord["search_engine"][0]["priority"],
|
priority: projectRecord["search_engine"][0]["priority"],
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
url: projectRecord["search_engine"][0]["thumbnail"]["filename_disk"],
|
||||||
height: projectRecord["search_engine"][0]["thumbnail"]["height"],
|
width: projectThumbnailImage.width,
|
||||||
width: projectRecord["search_engine"][0]["thumbnail"]["width"]
|
height: projectThumbnailImage.height
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: []
|
tags: []
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import { print } from 'graphql';
|
import { print } from "graphql";
|
||||||
import getRobotsQuery from '@/graphql/settings/robots.graphql';
|
import getRobotsQuery from "@/graphql/settings/robots.graphql";
|
||||||
|
|
||||||
export async function getRobotsSettings(): Promise<RobotsSettings> {
|
export async function getRobotsSettings(): Promise<RobotsSettings> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { print } from 'graphql';
|
import { print } from "graphql";
|
||||||
import { createDirectusConnection } from "@/lib/directus";
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
import getSettingsQuery from '@/graphql/settings/settings.graphql';
|
import getSettingsQuery from "@/graphql/settings/settings.graphql";
|
||||||
|
|
||||||
export async function getSettings(): Promise<GlobalSettings> {
|
export async function getSettings(): Promise<GlobalSettings> {
|
||||||
const client = await createDirectusConnection();
|
const client = await createDirectusConnection();
|
||||||
|
|||||||
50
astro/src/graphql/footer/getFooter.graphql
Normal file
50
astro/src/graphql/footer/getFooter.graphql
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
query getFooter {
|
||||||
|
Footer {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
logo {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
copyright,
|
||||||
|
columns {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
links {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
socials {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_disk,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
},
|
||||||
|
secondary_links {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
astro/src/graphql/menu/getMenu.graphql
Normal file
35
astro/src/graphql/menu/getMenu.graphql
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
query getMenu {
|
||||||
|
Menu {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
items {
|
||||||
|
id,
|
||||||
|
item {
|
||||||
|
...on Menu_Column {
|
||||||
|
__typename,
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
title,
|
||||||
|
links {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...on Menu_Link {
|
||||||
|
__typename,
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
text,
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
astro/src/icons/ChevronUp.astro
Normal file
10
astro/src/icons/ChevronUp.astro
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={Astro.props.width ?? "24"} height={Astro.props.height ?? "24"} viewBox="0 0 24 24">
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m4 15l8-8l8 8" />
|
||||||
|
</svg>
|
||||||
10
astro/src/icons/Close.astro
Normal file
10
astro/src/icons/Close.astro
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={Astro.props.width ?? "24"} height={Astro.props.height ?? "24"} viewBox="0 0 24 24">
|
||||||
|
<path fill="currentColor" d="M6.4 19L5 17.6l5.6-5.6L5 6.4L6.4 5l5.6 5.6L17.6 5L19 6.4L13.4 12l5.6 5.6l-1.4 1.4l-5.6-5.6z" />
|
||||||
|
</svg>
|
||||||
10
astro/src/icons/Download.astro
Normal file
10
astro/src/icons/Download.astro
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={Astro.props.width ?? "24"} height={Astro.props.height ?? "24"} viewBox="0 0 24 24">
|
||||||
|
<path fill="currentColor" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z" />
|
||||||
|
</svg>
|
||||||
5
astro/src/icons/jsx/loadingSpinner.tsx
Normal file
5
astro/src/icons/jsx/loadingSpinner.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function LoadingSpinner(props: { width?: number, height?: number }) {
|
||||||
|
return (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={props.width ?? "24"} height={props.height ?? "24"} viewBox="0 0 24 24"><circle cx="12" cy="2" r="0" fill="currentColor"><animate attributeName="r" begin="0" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(45 12 12)"><animate attributeName="r" begin="0.125s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(90 12 12)"><animate attributeName="r" begin="0.25s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(135 12 12)"><animate attributeName="r" begin="0.375s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(180 12 12)"><animate attributeName="r" begin="0.5s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(225 12 12)"><animate attributeName="r" begin="0.625s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(270 12 12)"><animate attributeName="r" begin="0.75s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="currentColor" transform="rotate(315 12 12)"><animate attributeName="r" begin="0.875s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle></svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
---
|
---
|
||||||
import '@/styles/global.css';
|
import "@/styles/global.css";
|
||||||
import { getSettings } from "@/content/settings/settings";
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import { getTextColor } from '@/lib/colors';
|
import { getTextColor } from "@/lib/colors";
|
||||||
|
import Footer from "@/components/footer/Footer.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settings: BlogLayoutProps;
|
settings: BlogLayoutProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tags = Astro.props.settings.tags ?? [];
|
||||||
const pageSettings = Astro.props.settings.searchEngine;
|
const pageSettings = Astro.props.settings.searchEngine;
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
|
|
||||||
@@ -41,7 +43,7 @@ const css = {
|
|||||||
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
||||||
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
||||||
<meta name="robots" content="index,follow" />
|
<meta name="robots" content="index,follow" />
|
||||||
<meta name="keywords" content={[].join(',')} />
|
<meta name="keywords" content={tags.join(",")} />
|
||||||
|
|
||||||
<!-- Low Priority Page Metadata -->
|
<!-- Low Priority Page Metadata -->
|
||||||
<meta name="description" content={pageSettings.description} />
|
<meta name="description" content={pageSettings.description} />
|
||||||
@@ -54,7 +56,7 @@ const css = {
|
|||||||
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
<meta property="og:site_name" content={settings.website.applicationName} />
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
<meta property="article:author" content={settings.website.author.name} />
|
<meta property="article:author" content={settings.website.author.name} />
|
||||||
<meta property="article:tags" content={[].join(',')} />
|
<meta property="article:tags" content={[].join(",")} />
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
@@ -77,7 +79,10 @@ const css = {
|
|||||||
|
|
||||||
<!-- Scripts and Style -->
|
<!-- Scripts and Style -->
|
||||||
</head>
|
</head>
|
||||||
<body style={ css } class="bg-[#fcfcfc]">
|
|
||||||
<slot name="content" />
|
<body style={ css } class="bg-[#fcfcfc] flex flex-col min-h-screen">
|
||||||
|
<slot class="grow" name="content" />
|
||||||
|
|
||||||
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
98
astro/src/layouts/PhotoLayout.astro
Normal file
98
astro/src/layouts/PhotoLayout.astro
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
import '@/styles/global.css';
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import { getTextColor } from '@/lib/colors';
|
||||||
|
import { getImageSize } from '@/lib/images';
|
||||||
|
import { getImage } from 'astro:assets';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
settings: WebpageLayoutProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageSettings = Astro.props.settings.searchEngine;
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const css = {
|
||||||
|
"--ptc": settings.website.colors.primary,
|
||||||
|
"--stc": settings.website.colors.secondary ?? settings.website.colors.primary,
|
||||||
|
"--ptt": getTextColor(settings.website.colors.primary),
|
||||||
|
"--stt": settings.website.colors.secondary
|
||||||
|
? getTextColor(settings.website.colors.secondary)
|
||||||
|
: getTextColor(settings.website.colors.primary)
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchengine = Astro.props.settings.searchEngine;
|
||||||
|
|
||||||
|
// Changing the thumbnail here is okay, as we now have two images: a new thumbnail, and the original image.
|
||||||
|
// Might have to make it prettier down the line?
|
||||||
|
// TODO: See comment above.
|
||||||
|
const resizedThumbnail = getImageSize(searchengine.thumbnail.width,
|
||||||
|
searchengine.thumbnail.height, 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: searchengine.thumbnail.url,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
---
|
||||||
|
|
||||||
|
<!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={`${settings.website.domainName}${thumbnail.src}`} />
|
||||||
|
<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={`${settings.website.domainName}${thumbnail.src}`} />
|
||||||
|
<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 style={ css } class="bg-neutral-950 flex flex-col min-h-screen">
|
||||||
|
<slot class="grow" name="content" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
import '@/styles/global.css';
|
import "@/styles/global.css";
|
||||||
import { getSettings } from "@/content/settings/settings";
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import { getTextColor } from '@/lib/colors';
|
import { getTextColor } from "@/lib/colors";
|
||||||
|
import Footer from "@/components/footer/Footer.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settings: BlogLayoutProps;
|
settings: BlogLayoutProps;
|
||||||
@@ -41,7 +42,7 @@ const css = {
|
|||||||
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS" />
|
||||||
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
<link rel="canonical" href={`${settings.website.domainName}/`} />
|
||||||
<meta name="robots" content="index,follow" />
|
<meta name="robots" content="index,follow" />
|
||||||
<meta name="keywords" content={[].join(',')} />
|
<meta name="keywords" content={[].join(",")} />
|
||||||
|
|
||||||
<!-- Low Priority Page Metadata -->
|
<!-- Low Priority Page Metadata -->
|
||||||
<meta name="description" content={pageSettings.description} />
|
<meta name="description" content={pageSettings.description} />
|
||||||
@@ -54,7 +55,7 @@ const css = {
|
|||||||
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
<meta property="og:site_name" content={settings.website.applicationName} />
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
<meta property="article:author" content={settings.website.author.name} />
|
<meta property="article:author" content={settings.website.author.name} />
|
||||||
<meta property="article:tags" content={[].join(',')} />
|
<meta property="article:tags" content={[].join(",")} />
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", pageSettings.title)} />
|
||||||
@@ -77,7 +78,10 @@ const css = {
|
|||||||
|
|
||||||
<!-- Scripts and Style -->
|
<!-- Scripts and Style -->
|
||||||
</head>
|
</head>
|
||||||
<body style={ css } class="bg-[#fcfcfc]">
|
|
||||||
<slot name="content" />
|
<body style={ css } class="bg-[#fcfcfc] flex flex-col min-h-screen">
|
||||||
|
<slot class="grow" name="content" />
|
||||||
|
|
||||||
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
import '@/styles/global.css';
|
import "@/styles/global.css";
|
||||||
import { getSettings } from "@/content/settings/settings";
|
import { getSettings } from "@/content/settings/settings";
|
||||||
import { getTextColor } from '@/lib/colors';
|
import { getTextColor } from "@/lib/colors";
|
||||||
|
import Footer from "@/components/footer/Footer.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settings: WebpageLayoutProps;
|
settings: WebpageLayoutProps;
|
||||||
@@ -74,7 +75,10 @@ const css = {
|
|||||||
|
|
||||||
<!-- Scripts and Style -->
|
<!-- Scripts and Style -->
|
||||||
</head>
|
</head>
|
||||||
<body style={ css } class="bg-[#fcfcfc]">
|
|
||||||
<slot name="content" />
|
<body style={ css } class="bg-[#fcfcfc] flex flex-col min-h-screen">
|
||||||
|
<slot class="grow" name="content" />
|
||||||
|
|
||||||
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export function getTextColor(bgColor: string) {
|
export function getTextColor(bgColor: string) {
|
||||||
// Remove # if present
|
// Remove # if present
|
||||||
const hex = bgColor.replace('#', '');
|
const hex = bgColor.replace("#", "");
|
||||||
|
|
||||||
// Convert hex to RGB
|
// Convert hex to RGB
|
||||||
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
||||||
@@ -19,5 +19,5 @@ export function getTextColor(bgColor: string) {
|
|||||||
const luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
const luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
||||||
|
|
||||||
// Return white for dark backgrounds, black for light backgrounds
|
// Return white for dark backgrounds, black for light backgrounds
|
||||||
return luminance > 0.179 ? '#000000' : '#fcfcfc';
|
return luminance > 0.179 ? "#000000" : "#fcfcfc";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export function formatDate(date: Date, format: string) {
|
export function formatDate(date: Date, format: string) {
|
||||||
return format
|
return format
|
||||||
.replaceAll("%Y", date.getFullYear().toString())
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, "0"))
|
||||||
.replaceAll("%D", date.getDate().toString().padStart(2, '0'));
|
.replaceAll("%D", date.getDate().toString().padStart(2, "0"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
export function getImageUrl(url: string) {
|
export function getImageUrl(url: string) {
|
||||||
return `${import.meta.env.DIRECTUS_URL}assets/${url}`;
|
return `${import.meta.env.DIRECTUS_URL}assets/${url}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getImageSize(width: number, height: number, targetMegapixels: number): ResizedImageResponse {
|
||||||
|
const originalPixels = width * height;
|
||||||
|
const targetPixels = targetMegapixels * 1000 * 1000;
|
||||||
|
|
||||||
|
if (originalPixels <= targetPixels) {
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scale = Math.sqrt(targetPixels / originalPixels);
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: Math.round(scale * width),
|
||||||
|
height: Math.round(scale * height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { getAlbum } from "@/content/photos/albums";
|
|||||||
import { getAllCategories, getPhotoCategory } from "@/content/photos/categories";
|
import { getAllCategories, getPhotoCategory } from "@/content/photos/categories";
|
||||||
import { getPhotoFromHash } from "@/content/photos/photos";
|
import { getPhotoFromHash } from "@/content/photos/photos";
|
||||||
import { getProject } from "@/content/projects/projects";
|
import { getProject } from "@/content/projects/projects";
|
||||||
|
import { getImageSize, getImageUrl } from "./images";
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
|
|
||||||
export async function getPage(settings: GlobalSettings, route: string): Promise<PageType | null> {
|
export async function getPage(settings: GlobalSettings, route: string): Promise<PageType | null> {
|
||||||
// Blog Index
|
// Blog Index
|
||||||
@@ -95,6 +97,24 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
const allCategories = await getAllCategories(settings);
|
const allCategories = await getAllCategories(settings);
|
||||||
const lastCategory = allCategories[0];
|
const lastCategory = allCategories[0];
|
||||||
|
|
||||||
|
// Changing the thumbnail here is okay, as it gets everything again in the CategoryIndex.astro file.
|
||||||
|
// Might have to make it prettier down the line?
|
||||||
|
// TODO: See comment above.
|
||||||
|
const resizedThumbnail = getImageSize(lastCategory.thumbnail.width, lastCategory.thumbnail.height, 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: lastCategory.thumbnail.url,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
|
lastCategory.thumbnail = {
|
||||||
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
route: route,
|
route: route,
|
||||||
pageType: "PhotoCategoryIndex",
|
pageType: "PhotoCategoryIndex",
|
||||||
@@ -119,6 +139,24 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
|
|
||||||
const category = await getPhotoCategory(`/${params["C"]}`);
|
const category = await getPhotoCategory(`/${params["C"]}`);
|
||||||
|
|
||||||
|
// Changing the thumbnail here is okay, as it gets everything again in the Category.astro file.
|
||||||
|
// Might have to make it prettier down the line?
|
||||||
|
// TODO: See comment above.
|
||||||
|
const resizedThumbnail = getImageSize(category.thumbnail.width, category.thumbnail.height, 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: category.thumbnail.url,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
|
category.thumbnail = {
|
||||||
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
route: route,
|
route: route,
|
||||||
pageType: "PhotoCategory",
|
pageType: "PhotoCategory",
|
||||||
@@ -144,10 +182,30 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
|
|
||||||
const photoAlbum = await getAlbum(settings, `/${params["R"]}`);
|
const photoAlbum = await getAlbum(settings, `/${params["R"]}`);
|
||||||
|
|
||||||
|
// Changing the thumbnail here is okay, as the thumbnail is unused in the Album.astro file.
|
||||||
|
// Might have to make it prettier down the line?
|
||||||
|
// TODO: See comment above.
|
||||||
|
const resizedThumbnail = getImageSize(photoAlbum.thumbnail.width, photoAlbum.thumbnail.height, 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: getImageUrl(photoAlbum.thumbnail.url),
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
route: route,
|
route: route,
|
||||||
pageType: "PhotoAlbum",
|
pageType: "PhotoAlbum",
|
||||||
page: photoAlbum
|
page: {
|
||||||
|
...photoAlbum,
|
||||||
|
thumbnail: {
|
||||||
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
|
width: resizedThumbnail.width,
|
||||||
|
height: resizedThumbnail.height
|
||||||
|
},
|
||||||
|
pageNumber: params["page"] !== undefined ? Number(params["page"]) : 1
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Photograph
|
// Photograph
|
||||||
@@ -175,7 +233,8 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
|
|
||||||
id: photo!.id,
|
id: photo!.id,
|
||||||
photo: photo!.photo,
|
photo: photo!.photo,
|
||||||
text: photo!.text
|
text: photo!.text,
|
||||||
|
album: photo!.album
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -195,6 +254,16 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resizedImage = getImageSize(webpageContent.searchEngine.thumbnail.width,
|
||||||
|
webpageContent.searchEngine.thumbnail.height, 0.756);
|
||||||
|
|
||||||
|
const thumbnail = await getImage({
|
||||||
|
src: webpageContent.searchEngine.thumbnail.url,
|
||||||
|
width: resizedImage.width,
|
||||||
|
height: resizedImage.height,
|
||||||
|
format: "jpeg"
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
route: route,
|
route: route,
|
||||||
pageType: "Webpage",
|
pageType: "Webpage",
|
||||||
@@ -204,7 +273,14 @@ export async function getPage(settings: GlobalSettings, route: string): Promise<
|
|||||||
id: webpageContent.id,
|
id: webpageContent.id,
|
||||||
lastModified: webpageContent.lastModified,
|
lastModified: webpageContent.lastModified,
|
||||||
url: webpageContent.url,
|
url: webpageContent.url,
|
||||||
searchEngine: webpageContent.searchEngine,
|
searchEngine: {
|
||||||
|
...webpageContent.searchEngine,
|
||||||
|
thumbnail: {
|
||||||
|
url: `${settings.website.domainName}${thumbnail.src}`,
|
||||||
|
width: resizedImage.width,
|
||||||
|
height: resizedImage.height
|
||||||
|
}
|
||||||
|
},
|
||||||
components: webpageContent.components
|
components: webpageContent.components
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { getAllBlogs } from "@/content/blogs/blogs";
|
|||||||
import { getAllWebpages } from "@/content/pages/pages";
|
import { getAllWebpages } from "@/content/pages/pages";
|
||||||
import { getAllAlbums } from "@/content/photos/albums";
|
import { getAllAlbums } from "@/content/photos/albums";
|
||||||
import { getAllProjects } from "@/content/projects/projects";
|
import { getAllProjects } from "@/content/projects/projects";
|
||||||
import { getPhotoHash } from "./hash";
|
import { getPhotoHash } from "@/lib/hash";
|
||||||
import { getAllCategories } from "@/content/photos/categories";
|
import { getAllCategories } from "@/content/photos/categories";
|
||||||
|
|
||||||
export async function getAllRoutesList(settings: GlobalSettings): Promise<string[]> {
|
export async function getAllRoutesList(settings: GlobalSettings): Promise<string[]> {
|
||||||
@@ -99,10 +99,10 @@ export function getBlogRoute(blogSettings: BlogSettings, blog: BlogPost) {
|
|||||||
|
|
||||||
return blogSettings.blogRouteTemplate
|
return blogSettings.blogRouteTemplate
|
||||||
.replaceAll("%Y", date.getFullYear().toString())
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, "0"))
|
||||||
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
.replaceAll("%D", date.getDate().toString().padStart(2, "0"))
|
||||||
.replaceAll("%R", blog.url)
|
.replaceAll("%R", blog.url)
|
||||||
.replace(/\/+/g, '/');
|
.replace(/\/+/g, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProjectRoute(projectSettings: ProjectSettings, project: ProjectPost) {
|
export function getProjectRoute(projectSettings: ProjectSettings, project: ProjectPost) {
|
||||||
@@ -110,16 +110,16 @@ export function getProjectRoute(projectSettings: ProjectSettings, project: Proje
|
|||||||
|
|
||||||
return projectSettings.projectRouteTemplate
|
return projectSettings.projectRouteTemplate
|
||||||
.replaceAll("%Y", date.getFullYear().toString())
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, "0"))
|
||||||
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
.replaceAll("%D", date.getDate().toString().padStart(2, "0"))
|
||||||
.replaceAll("%R", project.url)
|
.replaceAll("%R", project.url)
|
||||||
.replace(/\/+/g, '/');
|
.replace(/\/+/g, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCategoryRoute(photoSettings: WebsitePhotoSettings, category: PhotoAlbumCategory) {
|
export function getCategoryRoute(photoSettings: WebsitePhotoSettings, category: PhotoAlbumCategory) {
|
||||||
return photoSettings.category.routeTemplate
|
return photoSettings.category.routeTemplate
|
||||||
.replaceAll("%C", category.url)
|
.replaceAll("%C", category.url)
|
||||||
.replace(/\/+/g, '/');
|
.replace(/\/+/g, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAlbumRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum) {
|
export function getAlbumRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum) {
|
||||||
@@ -127,11 +127,11 @@ export function getAlbumRoute(photoSettings: WebsitePhotoSettings, album: PhotoA
|
|||||||
|
|
||||||
return photoSettings.album.routeTemplate
|
return photoSettings.album.routeTemplate
|
||||||
.replaceAll("%Y", date.getFullYear().toString())
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, "0"))
|
||||||
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
.replaceAll("%D", date.getDate().toString().padStart(2, "0"))
|
||||||
.replaceAll("%C", album.category.url)
|
.replaceAll("%C", album.category.url)
|
||||||
.replaceAll("%R", album.url)
|
.replaceAll("%R", album.url)
|
||||||
.replace(/\/+/g, '/');
|
.replace(/\/+/g, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPhotoRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum, photo: PhotoAlbumPhoto) {
|
export function getPhotoRoute(photoSettings: WebsitePhotoSettings, album: PhotoAlbum, photo: PhotoAlbumPhoto) {
|
||||||
@@ -139,10 +139,10 @@ export function getPhotoRoute(photoSettings: WebsitePhotoSettings, album: PhotoA
|
|||||||
|
|
||||||
return photoSettings.photo.routeTemplate
|
return photoSettings.photo.routeTemplate
|
||||||
.replaceAll("%Y", date.getFullYear().toString())
|
.replaceAll("%Y", date.getFullYear().toString())
|
||||||
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, '0'))
|
.replaceAll("%M", (date.getMonth() + 1).toString().padStart(2, "0"))
|
||||||
.replaceAll("%D", date.getDate().toString().padStart(2, '0'))
|
.replaceAll("%D", date.getDate().toString().padStart(2, "0"))
|
||||||
.replaceAll("%C", album.category.url)
|
.replaceAll("%C", album.category.url)
|
||||||
.replaceAll("%R", album.url)
|
.replaceAll("%R", album.url)
|
||||||
.replaceAll("%H", getPhotoHash(photo))
|
.replaceAll("%H", getPhotoHash(photo))
|
||||||
.replace(/\/+/g, '/');
|
.replace(/\/+/g, "/");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { getSettings } from "@/content/settings/settings"
|
|||||||
import WebpageLayout from "@/layouts/WebpageLayout.astro";
|
import WebpageLayout from "@/layouts/WebpageLayout.astro";
|
||||||
import BlogLayout from "@/layouts/BlogLayout.astro";
|
import BlogLayout from "@/layouts/BlogLayout.astro";
|
||||||
import ProjectLayout from "@/layouts/ProjectLayout.astro";
|
import ProjectLayout from "@/layouts/ProjectLayout.astro";
|
||||||
|
import PhotoLayout from "@/layouts/PhotoLayout.astro";
|
||||||
import BlogIndex from "@/components/blogs/BlogIndex.astro";
|
import BlogIndex from "@/components/blogs/BlogIndex.astro";
|
||||||
import ProjectIndex from "@/components/projects/ProjectIndex.astro";
|
import ProjectIndex from "@/components/projects/ProjectIndex.astro";
|
||||||
import Webpage from "@/components/webpage/Webpage.astro";
|
import Webpage from "@/components/webpage/Webpage.astro";
|
||||||
@@ -12,6 +13,9 @@ import BlogPost from "@/components/blogs/BlogPost.astro";
|
|||||||
import ProjectPost from "@/components/projects/ProjectPost.astro";
|
import ProjectPost from "@/components/projects/ProjectPost.astro";
|
||||||
import CategoryIndex from "@/components/photos/CategoryIndex.astro";
|
import CategoryIndex from "@/components/photos/CategoryIndex.astro";
|
||||||
import Category from "@/components/photos/Category.astro";
|
import Category from "@/components/photos/Category.astro";
|
||||||
|
import AlbumPage from "@/components/photos/Album.astro";
|
||||||
|
import { getImageUrl } from "@/lib/images";
|
||||||
|
import Photo from "@/components/photos/Photo.astro";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
@@ -30,8 +34,6 @@ const settings = await getSettings();
|
|||||||
const pathName = Astro.url.pathname === "/" ? "/" : Astro.url.pathname.replace(/\/$/, "");
|
const pathName = Astro.url.pathname === "/" ? "/" : Astro.url.pathname.replace(/\/$/, "");
|
||||||
const page = await getPage(settings, pathName);
|
const page = await getPage(settings, pathName);
|
||||||
|
|
||||||
console.log(pathName);
|
|
||||||
|
|
||||||
if (page === null || page.page === null || !page.page.exists) {
|
if (page === null || page.page === null || !page.page.exists) {
|
||||||
return new Response("Page not found.", {
|
return new Response("Page not found.", {
|
||||||
status: 404,
|
status: 404,
|
||||||
@@ -73,7 +75,7 @@ if (page === null || page.page === null || !page.page.exists) {
|
|||||||
{ page.page.type === "BlogPost" && (
|
{ page.page.type === "BlogPost" && (
|
||||||
<BlogLayout settings={{
|
<BlogLayout settings={{
|
||||||
searchEngine: page.page.searchEngine,
|
searchEngine: page.page.searchEngine,
|
||||||
tags: []
|
tags: page.page.tags.map((tag) => tag.text)
|
||||||
}}>
|
}}>
|
||||||
<Fragment slot="content">
|
<Fragment slot="content">
|
||||||
<BlogPost blog={page.page} />
|
<BlogPost blog={page.page} />
|
||||||
@@ -104,7 +106,7 @@ if (page === null || page.page === null || !page.page.exists) {
|
|||||||
{ page.page.type === "ProjectPost" && (
|
{ page.page.type === "ProjectPost" && (
|
||||||
<ProjectLayout settings={{
|
<ProjectLayout settings={{
|
||||||
searchEngine: page.page.searchEngine,
|
searchEngine: page.page.searchEngine,
|
||||||
tags: []
|
tags: page.page.tags.map((tag) => tag.text)
|
||||||
}}>
|
}}>
|
||||||
<Fragment slot="content">
|
<Fragment slot="content">
|
||||||
<ProjectPost project={page.page} />
|
<ProjectPost project={page.page} />
|
||||||
@@ -132,7 +134,7 @@ if (page === null || page.page === null || !page.page.exists) {
|
|||||||
<WebpageLayout settings={{
|
<WebpageLayout settings={{
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: page.page.category.title,
|
title: page.page.category.title,
|
||||||
description: `See the photos in the category ${page.page.category.title.toLowerCase()}.`,
|
description: `See the photos in the ${page.page.category.title.toLowerCase()} category.`,
|
||||||
allowCrawlers: true,
|
allowCrawlers: true,
|
||||||
canonical: null,
|
canonical: null,
|
||||||
priority: 65,
|
priority: 65,
|
||||||
@@ -144,22 +146,38 @@ if (page === null || page.page === null || !page.page.exists) {
|
|||||||
</WebpageLayout>
|
</WebpageLayout>
|
||||||
) }
|
) }
|
||||||
|
|
||||||
{ page.pageType === "Photo" && (
|
{ page.pageType === "PhotoAlbum" && (
|
||||||
<WebpageLayout settings={{
|
<WebpageLayout settings={{
|
||||||
searchEngine: {
|
searchEngine: {
|
||||||
title: "Projects",
|
title: page.page.title,
|
||||||
description: "",
|
description: `See the photos in the ${page.page.category.title.toLowerCase()} category.`,
|
||||||
|
allowCrawlers: true,
|
||||||
|
canonical: null,
|
||||||
|
priority: 65,
|
||||||
|
thumbnail: page.page.thumbnail
|
||||||
|
}}}>
|
||||||
|
<Fragment slot="content">
|
||||||
|
<AlbumPage page={page.page} />
|
||||||
|
</Fragment>
|
||||||
|
</WebpageLayout>
|
||||||
|
) }
|
||||||
|
|
||||||
|
{ page.pageType === "Photo" && (
|
||||||
|
<PhotoLayout settings={{
|
||||||
|
searchEngine: {
|
||||||
|
title: page.page.album.title,
|
||||||
|
description: `See this photo from the album ${page.page.album.title}`,
|
||||||
allowCrawlers: true,
|
allowCrawlers: true,
|
||||||
canonical: null,
|
canonical: null,
|
||||||
priority: 65,
|
priority: 65,
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: "",
|
url: getImageUrl(page.page.photo.url),
|
||||||
width: 1200,
|
width: page.page.photo.width,
|
||||||
height: 630
|
height: page.page.photo.height
|
||||||
}
|
}
|
||||||
}}}>
|
}}}>
|
||||||
<Fragment slot="content">
|
<Fragment slot="content">
|
||||||
<div>Photo</div>
|
<Photo page={page.page} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</WebpageLayout>
|
</PhotoLayout>
|
||||||
) }
|
) }
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ export const GET = (async () => {
|
|||||||
const robots = await getRobotsSettings();
|
const robots = await getRobotsSettings();
|
||||||
|
|
||||||
let crawlers = [
|
let crawlers = [
|
||||||
{ id: 'google', name: 'Googlebot' },
|
{ id: "google", name: "Googlebot" },
|
||||||
{ id: 'bing', name: "Bingbot" },
|
{ id: "bing", name: "Bingbot" },
|
||||||
{ id: "slurp", name: "Slurp" },
|
{ id: "slurp", name: "Slurp" },
|
||||||
{ id: "duckduckgo", name: "DuckDuckBot" },
|
{ id: "duckduckgo", name: "DuckDuckBot" },
|
||||||
{ id: "baidu", name: "Baiduspider" },
|
{ id: "baidu", name: "Baiduspider" },
|
||||||
@@ -53,7 +53,7 @@ export const GET = (async () => {
|
|||||||
`User-agent: ${crawlerData!.name}\nDisallow: /`
|
`User-agent: ${crawlerData!.name}\nDisallow: /`
|
||||||
}
|
}
|
||||||
|
|
||||||
crawlerContent = crawlerContent + "\n\n\n"
|
crawlerContent = crawlerContent + "\n\n"
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(crawlerContent.trim(), {
|
return new Response(crawlerContent.trim(), {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const GET = (async ({ params }) => {
|
|||||||
<loc>${settings.website.domainName}${page.url}</loc>
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export async function getStaticPaths() {
|
|||||||
let items: any[] = [];
|
let items: any[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pages; i++) {
|
for (let i = 0; i < pages; i++) {
|
||||||
items.push({ params: { page: (i + 1) } });
|
items.push({ params: { page: (i + 1).toString() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const GET = (async () => {
|
|||||||
<loc>${settings.website.domainName}${item.url}</loc>
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const GET = (async ({ params }) => {
|
|||||||
<loc>${settings.website.domainName}${page.url}</loc>
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export async function getStaticPaths() {
|
|||||||
let items: any[] = [];
|
let items: any[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pages; i++) {
|
for (let i = 0; i < pages; i++) {
|
||||||
items.push({ params: { page: (i + 1) } });
|
items.push({ params: { page: (i + 1).toString() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const GET = (async () => {
|
|||||||
<loc>${settings.website.domainName}${item.url}</loc>
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export const GET = (async () => {
|
|||||||
<loc>${settings.website.domainName}${item.url}</loc>
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ export const GET = (async ({ params }) => {
|
|||||||
let pages: SitemapPage[] = [];
|
let pages: SitemapPage[] = [];
|
||||||
|
|
||||||
selectedPages.forEach((page) => {
|
selectedPages.forEach((page) => {
|
||||||
|
if (page.exists) {
|
||||||
pages.push({
|
pages.push({
|
||||||
url: page.url,
|
url: page.url,
|
||||||
lastModified: page.lastModified
|
lastModified: page.lastModified
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let sitemapContent = `
|
let sitemapContent = `
|
||||||
@@ -31,7 +33,7 @@ export const GET = (async ({ params }) => {
|
|||||||
<loc>${settings.website.domainName}${page.url}</loc>
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ export async function getStaticPaths() {
|
|||||||
let items: any[] = [];
|
let items: any[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pages; i++) {
|
for (let i = 0; i < pages; i++) {
|
||||||
items.push({ params: { page: (i + 1) } });
|
items.push({ params: { page: (i + 1).toString() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const GET = (async () => {
|
|||||||
<loc>${settings.website.domainName}${item.url}</loc>
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const GET = (async ({ params }) => {
|
|||||||
<loc>${settings.website.domainName}${page.url}</loc>
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export async function getStaticPaths() {
|
|||||||
let items: any[] = [];
|
let items: any[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pages; i++) {
|
for (let i = 0; i < pages; i++) {
|
||||||
items.push({ params: { page: (i + 1) } });
|
items.push({ params: { page: (i + 1).toString() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const GET = (async () => {
|
|||||||
<loc>${settings.website.domainName}${item.url}</loc>
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
`).join('')}
|
`).join("")}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
2
astro/src/types/blogs/blog.d.ts
vendored
2
astro/src/types/blogs/blog.d.ts
vendored
@@ -8,6 +8,8 @@ type BlogPost = {
|
|||||||
date: string;
|
date: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
|
|
||||||
searchEngine: SearchEngine;
|
searchEngine: SearchEngine;
|
||||||
|
|||||||
5
astro/src/types/common/images.d.ts
vendored
5
astro/src/types/common/images.d.ts
vendored
@@ -3,3 +3,8 @@ type PhotoProps = {
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResizedImageResponse = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|||||||
44
astro/src/types/footers/footer.d.ts
vendored
Normal file
44
astro/src/types/footers/footer.d.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { StringValidation } from "astro:schema";
|
||||||
|
|
||||||
|
type Footer = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
title: string | null;
|
||||||
|
logo: PhotoProps | null;
|
||||||
|
copyright: string | null;
|
||||||
|
|
||||||
|
columns: FooterColumn[];
|
||||||
|
socials: FooterSocial[] | null;
|
||||||
|
secondaryLinks: FooterSecondaryLink[] | null;
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type FooterColumn = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
links: FooterColumnLink[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type FooterSocial = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
icon: PhotoProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
type FooterSecondaryLink = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
text: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type FooterColumnLink = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
text: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
20
astro/src/types/menu/menu.d.ts
vendored
Normal file
20
astro/src/types/menu/menu.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
type Menu = {
|
||||||
|
id: string;
|
||||||
|
items: MenuColumn[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type MenuColumn = {
|
||||||
|
type: "Column";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
links: MenuLink[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type MenuLink = {
|
||||||
|
type: "Link";
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
text: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
2
astro/src/types/pages/page.d.ts
vendored
2
astro/src/types/pages/page.d.ts
vendored
@@ -41,6 +41,6 @@ type PageType =
|
|||||||
| { pageType: "ProjectPost"; page: ProjectPost; route: string }
|
| { pageType: "ProjectPost"; page: ProjectPost; route: string }
|
||||||
| { pageType: "PhotoCategoryIndex"; page: PhotoCategoryIndex; route: string }
|
| { pageType: "PhotoCategoryIndex"; page: PhotoCategoryIndex; route: string }
|
||||||
| { pageType: "PhotoCategory"; page: PhotoCategory; route: string }
|
| { pageType: "PhotoCategory"; page: PhotoCategory; route: string }
|
||||||
| { pageType: "PhotoAlbum"; page: PhotoAlbum; route: string }
|
| { pageType: "PhotoAlbum"; page: PhotoAlbumPage; route: string }
|
||||||
| { pageType: "Photo"; page: PhotoPage; route: string }
|
| { pageType: "Photo"; page: PhotoPage; route: string }
|
||||||
| { pageType: "Unknown"; page: null; route: string };
|
| { pageType: "Unknown"; page: null; route: string };
|
||||||
|
|||||||
35
astro/src/types/photos/album.d.ts
vendored
35
astro/src/types/photos/album.d.ts
vendored
@@ -2,6 +2,31 @@ type PhotoAlbum = {
|
|||||||
type: "PhotoAlbum";
|
type: "PhotoAlbum";
|
||||||
exists: boolean;
|
exists: boolean;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
description: string | null;
|
||||||
|
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
|
||||||
|
startDate: string;
|
||||||
|
endDate: string | null;
|
||||||
|
location: string | null;
|
||||||
|
|
||||||
|
category: PhotoAlbumCategory;
|
||||||
|
photos: PhotoAlbumPhoto[];
|
||||||
|
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumPage = {
|
||||||
|
type: "PhotoAlbum";
|
||||||
|
exists: boolean;
|
||||||
|
pageNumber: number;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
@@ -38,3 +63,13 @@ type PhotoCategory = {
|
|||||||
category: PhotoAlbumCategory;
|
category: PhotoAlbumCategory;
|
||||||
pageNumber: number;
|
pageNumber: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumItem = {
|
||||||
|
id: string;
|
||||||
|
photo: PhotoProps;
|
||||||
|
text: string | null;
|
||||||
|
album: {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
16
astro/src/types/photos/photo.d.ts
vendored
16
astro/src/types/photos/photo.d.ts
vendored
@@ -5,4 +5,20 @@ type PhotoPage = {
|
|||||||
id: string;
|
id: string;
|
||||||
photo: PhotoProps;
|
photo: PhotoProps;
|
||||||
text: string | null;
|
text: string | null;
|
||||||
|
album: {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumItem = {
|
||||||
|
photo: PhotoProps;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoAlbumGalleryItem = {
|
||||||
|
id: string;
|
||||||
|
photo: PhotoProps;
|
||||||
|
text: string | null;
|
||||||
|
url: string;
|
||||||
}
|
}
|
||||||
|
|||||||
2
astro/src/types/projects/project.d.ts
vendored
2
astro/src/types/projects/project.d.ts
vendored
@@ -8,6 +8,8 @@ type ProjectPost = {
|
|||||||
date: string;
|
date: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
thumbnail: PhotoProps;
|
||||||
|
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
|
|
||||||
searchEngine: SearchEngine;
|
searchEngine: SearchEngine;
|
||||||
|
|||||||
@@ -3974,6 +3974,52 @@
|
|||||||
"searchable": true
|
"searchable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"collection": "Menu_Link",
|
||||||
|
"field": "Menu_Column_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"schema": {
|
||||||
|
"name": "Menu_Column_id",
|
||||||
|
"table": "Menu_Link",
|
||||||
|
"data_type": "uuid",
|
||||||
|
"default_value": null,
|
||||||
|
"generation_expression": null,
|
||||||
|
"max_length": null,
|
||||||
|
"numeric_precision": null,
|
||||||
|
"numeric_scale": null,
|
||||||
|
"is_generated": false,
|
||||||
|
"is_nullable": true,
|
||||||
|
"is_unique": false,
|
||||||
|
"is_indexed": false,
|
||||||
|
"is_primary_key": false,
|
||||||
|
"has_auto_increment": false,
|
||||||
|
"foreign_key_schema": "public",
|
||||||
|
"foreign_key_table": "Menu_Column",
|
||||||
|
"foreign_key_column": "id",
|
||||||
|
"comment": null
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"collection": "Menu_Link",
|
||||||
|
"field": "Menu_Column_id",
|
||||||
|
"special": null,
|
||||||
|
"interface": "select-dropdown-m2o",
|
||||||
|
"options": null,
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"readonly": false,
|
||||||
|
"hidden": true,
|
||||||
|
"sort": 8,
|
||||||
|
"width": "full",
|
||||||
|
"translations": null,
|
||||||
|
"note": null,
|
||||||
|
"conditions": null,
|
||||||
|
"required": false,
|
||||||
|
"group": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"searchable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collection": "Menu_items",
|
"collection": "Menu_items",
|
||||||
"field": "id",
|
"field": "id",
|
||||||
@@ -11823,7 +11869,7 @@
|
|||||||
"display_options": null,
|
"display_options": null,
|
||||||
"readonly": false,
|
"readonly": false,
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"sort": 8,
|
"sort": 7,
|
||||||
"width": "full",
|
"width": "full",
|
||||||
"translations": null,
|
"translations": null,
|
||||||
"note": null,
|
"note": null,
|
||||||
@@ -11835,6 +11881,37 @@
|
|||||||
"searchable": true
|
"searchable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"collection": "Menu_Column",
|
||||||
|
"field": "links",
|
||||||
|
"type": "alias",
|
||||||
|
"schema": null,
|
||||||
|
"meta": {
|
||||||
|
"collection": "Menu_Column",
|
||||||
|
"field": "links",
|
||||||
|
"special": [
|
||||||
|
"o2m"
|
||||||
|
],
|
||||||
|
"interface": "list-o2m",
|
||||||
|
"options": {
|
||||||
|
"template": "{{text}}"
|
||||||
|
},
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"readonly": false,
|
||||||
|
"hidden": false,
|
||||||
|
"sort": 8,
|
||||||
|
"width": "full",
|
||||||
|
"translations": null,
|
||||||
|
"note": null,
|
||||||
|
"conditions": null,
|
||||||
|
"required": true,
|
||||||
|
"group": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"searchable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collection": "Menu_Column",
|
"collection": "Menu_Column",
|
||||||
"field": "sort",
|
"field": "sort",
|
||||||
@@ -24005,6 +24082,32 @@
|
|||||||
"one_deselect_action": "nullify"
|
"one_deselect_action": "nullify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"collection": "Menu_Link",
|
||||||
|
"field": "Menu_Column_id",
|
||||||
|
"related_collection": "Menu_Column",
|
||||||
|
"schema": {
|
||||||
|
"constraint_name": "menu_link_menu_column_id_foreign",
|
||||||
|
"table": "Menu_Link",
|
||||||
|
"column": "Menu_Column_id",
|
||||||
|
"foreign_key_schema": "public",
|
||||||
|
"foreign_key_table": "Menu_Column",
|
||||||
|
"foreign_key_column": "id",
|
||||||
|
"on_update": "NO ACTION",
|
||||||
|
"on_delete": "SET NULL"
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"many_collection": "Menu_Link",
|
||||||
|
"many_field": "Menu_Column_id",
|
||||||
|
"one_collection": "Menu_Column",
|
||||||
|
"one_field": "links",
|
||||||
|
"one_collection_field": null,
|
||||||
|
"one_allowed_collections": null,
|
||||||
|
"junction_field": null,
|
||||||
|
"sort_field": null,
|
||||||
|
"one_deselect_action": "nullify"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collection": "Menu_items",
|
"collection": "Menu_items",
|
||||||
"field": "Menu_id",
|
"field": "Menu_id",
|
||||||
|
|||||||
Reference in New Issue
Block a user