Add footer to website
This commit is contained in:
70
astro/src/components/footer/Footer.astro
Normal file
70
astro/src/components/footer/Footer.astro
Normal 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>
|
||||
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;
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
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;
|
||||
}
|
||||
Reference in New Issue
Block a user