Add footer to website

This commit is contained in:
itsfinniii
2026-04-19 18:03:32 +02:00
parent 2374a6bd22
commit 506a5ed14e
8 changed files with 298 additions and 8 deletions

View File

@@ -0,0 +1,70 @@
---
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 px-12 lg:container mx-auto md:gap-y-8 gap-y-12 gap-x-24">
{ (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="w-50 h-auto"
/>
) }
</div>
) }
{ footer.columns.map((column) => (
<div class="flex flex-col gap-3">
<h2 class="text-4xl font-bold">{column.title}</h2>
<div class="flex flex-col gap-3">
{column.links.map((link) => (
<a class="text-lg text-neutral-800" href={link.url}>{link.text}</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-400 duration-300 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 w-fit" href={link.url}>{link.text}</a>
)) }
</div>
) }
</div>
</div>
) }
</footer>

View 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;
}

View 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
}
}
}

View File

@@ -2,6 +2,7 @@
import '@/styles/global.css';
import { getSettings } from "@/content/settings/settings";
import { getTextColor } from '@/lib/colors';
import Footer from '@/components/footer/Footer.astro';
interface Props {
settings: BlogLayoutProps;
@@ -77,7 +78,10 @@ const css = {
<!-- Scripts and Style -->
</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>
</html>

View File

@@ -2,6 +2,7 @@
import '@/styles/global.css';
import { getSettings } from "@/content/settings/settings";
import { getTextColor } from '@/lib/colors';
import Footer from '@/components/footer/Footer.astro';
interface Props {
settings: WebpageLayoutProps;
@@ -74,7 +75,10 @@ const css = {
<!-- Scripts and Style -->
</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>
</html>

View File

@@ -2,6 +2,7 @@
import '@/styles/global.css';
import { getSettings } from "@/content/settings/settings";
import { getTextColor } from '@/lib/colors';
import Footer from '@/components/footer/Footer.astro';
interface Props {
settings: BlogLayoutProps;
@@ -77,7 +78,10 @@ const css = {
<!-- Scripts and Style -->
</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>
</html>

View File

@@ -2,6 +2,7 @@
import '@/styles/global.css';
import { getSettings } from "@/content/settings/settings";
import { getTextColor } from '@/lib/colors';
import Footer from '@/components/footer/Footer.astro';
interface Props {
settings: WebpageLayoutProps;
@@ -74,7 +75,10 @@ const css = {
<!-- Scripts and Style -->
</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>
</html>

44
astro/src/types/footers/footer.d.ts vendored Normal file
View 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;
}