Finished section for music

- Finished listing of musical compositions
- Slight update to listing of blog posts
- Updating api.js
- Fixed dark/light mode in some pages (font color)
This commit is contained in:
Cyril Šebek 2024-06-17 11:58:32 +02:00
parent 915ff6ede6
commit 3b33ffa05d
Signed by: blboun3
SSH Key Fingerprint: SHA256:ESaOKDAPaR/9j4DJ3sU4VdxTcL7qWUxpAyPSK2LLKbY
18 changed files with 227 additions and 107 deletions

View File

@ -38,5 +38,4 @@ All commands are run from the root of the project, from a terminal:
| `npm run build` | Build your production site to `./dist/` | | `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying | | `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI | | `npm run astro -- --help` | Get help using the Astro CLI |

BIN
image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

View File

View File

View File

@ -0,0 +1,14 @@
---
import SingleCompositionCard from "./SingleCompositionCard.astro";
import { Separator } from "./ui/separator";
const { songs } = Astro.props
---
{
songs.map((song, index) => (
<>
<SingleCompositionCard song={song} />
{index == songs.length-1 ? <></> : <Separator className="my-2" />}
</>
))
}

View File

@ -0,0 +1,39 @@
---
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "../components/ui/card";
import { Separator } from "../components/ui/separator";
import { Image } from "astro:assets";
import { getLangFromUrl, useTranslations } from "../i18n/utils";
const t = useTranslations(getLangFromUrl(Astro.url));
const { song } = Astro.props;
---
<Card>
<CardHeader>
<Image
src={song.data.image.url}
alt={song.data.image.alt}
class="rounded-md"
inferSize
/>
<span class="py-2"></span>
<CardTitle>{song.data.name}</CardTitle>
<CardDescription>
<br />
{song.data.comment[Astro.currentLocale]}
</CardDescription>
</CardHeader>
<CardContent className="flex justify-evenly">
<a href={song.data.pdfLink} download>{t("music")["downloadPDF"]}</a>
<Separator orientation="vertical" className="mx-2 h-full"/>
<a href={song.data.mp3Link} download>{t("music")["downloadMP3"]}</a>
<Separator orientation="vertical" className="mx-2 h-full"/>
<a href={song.data.flacLink} download>{t("music")["downloadFLAC"]}</a>
</CardContent>
</Card>

View File

@ -16,10 +16,32 @@ const blogCollection = defineCollection({
tags: z.array(z.string()).optional() tags: z.array(z.string()).optional()
}) })
}); });
const musicCollection = defineCollection({
type: "content",
schema: z.object({
name: z.string(),
comment: z.object({
en: z.string(),
de: z.string(),
cs: z.string(),
fr: z.string()
}),
publishDate: z.date(),
image: z.object({
url: z.string(),
alt: z.string()
}),
pdfLink: z.string().optional(),
flacLink: z.string().optional(),
mp3Link: z.string()
})
});
// 3. Export a single `collections` object to register your collection(s) // 3. Export a single `collections` object to register your collection(s)
// This key should match your collection directory name in "src/content" // This key should match your collection directory name in "src/content"
export const collections = { export const collections = {
'blog': blogCollection, 'blog': blogCollection,
'music': musicCollection
}; };
export async function getBlogPosts() { export async function getBlogPosts() {
@ -32,4 +54,8 @@ export async function getBlogPosts() {
blog_slug blog_slug
} }
}) })
}
export async function getCompositions() {
return await getCollection('music');
} }

View File

@ -0,0 +1,15 @@
---
name: "C1"
publishDate: 2020-01-01T00:00:00Z
pdfLink: "/public/music/first/my.pdf"
mp3Link: "/public/music/first/my.mp3"
flacLink: "/public/music/first/my.flac"
image:
url: "https://images.unsplash.com/photo-1664380619395-a25d867b5fb9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=1080"
alt: "Text"
comment:
en: "comment EN1"
cs: "comment CS1"
de: "comment DE1"
fr: "comment FR1"
---

View File

@ -0,0 +1,15 @@
---
name: "C2"
publishDate: 2020-01-01T00:00:00Z
pdfLink: "/public/music/first/my.pdf"
mp3Link: "/public/music/first/my.mp3"
flacLink: "/public/music/first/my.flac"
image:
url: "https://images.unsplash.com/photo-1664380619395-a25d867b5fb9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=1080"
alt: "Text"
comment:
en: "comment EN2"
cs: "comment CS2"
de: "comment DE2"
fr: "comment FR2"
---

View File

@ -104,5 +104,24 @@ export const en = {
}, },
], ],
/*
Blog page
*/
blog: {
title: "Blog lorem",
description: "Bloog description here",
},
/*
Page with musical compositions
*/
music: {
title: "lorem ipsum dolor sit amer cons",
description: "longegengegeg eg eg e geg eg eg eg eg eg eg eg eg eg e ge ge eg eg eg eg egge eg eg eg eg eg e eg ge g g ee geg eg eg e geg eg eg eg eg eg eg eg g e",
downloadPDF: "Download PDF",
downloadMP3: "Download MP3",
downloadFLAC: "Download FLAC"
},
postsTagged: "All posts tagged with", postsTagged: "All posts tagged with",
}; };

View File

@ -1,16 +0,0 @@
---
import MainLayout from "../../../layouts/MainLayout.astro";
//@ts-ignore
import { dictionary } from "../../../i18n/dictionary";
const { title, description } = dictionary[Astro.currentLocale];
export async function getStaticPaths() {
return ["en", "fr", "cs", "de"].map((lang) => {
return { params: { lang } };
});
}
---
<MainLayout title={title} description={description} lang={Astro.currentLocale}>
</MainLayout>

View File

@ -1,4 +1,6 @@
--- ---
export const prerender = true
import { getBlogPosts } from "../../../content/config"; import { getBlogPosts } from "../../../content/config";
import BlogPost from "../../../layouts/BlogPost.astro"; import BlogPost from "../../../layouts/BlogPost.astro";
@ -19,7 +21,7 @@ export async function getStaticPaths() {
const { lang } = Astro.params; const { lang } = Astro.params;
const page = Astro.props; const page = Astro.props;
// @ts-ignore // @ts-ignore
const formattedDate = page.data.publishDate.toLocaleString(lang); const formattedDate = page.data.publishDate?.toLocaleString(lang);
const { Content } = await page.render(); const { Content } = await page.render();
--- ---

View File

@ -1,13 +1,14 @@
--- ---
export const prerender = true;
import MainLayout from "../../../layouts/MainLayout.astro"; import MainLayout from "../../../layouts/MainLayout.astro";
import { getBlogPosts } from "../../../content/config"; import { getBlogPosts } from "../../../content/config";
//@ts-ignore
import { dictionary } from "../../../i18n/dictionary";
import SinglePageBlogMode from "../../../layouts/SinglePageBlogMode.astro"; import SinglePageBlogMode from "../../../layouts/SinglePageBlogMode.astro";
import PostsList from "../../../components/PostsList.astro"; import PostsList from "../../../components/PostsList.astro";
import { getLangFromUrl, useTranslations } from "../../../i18n/utils";
import { Separator } from "../../../components/ui/separator";
const { title, description } = dictionary[Astro.currentLocale]; const t = useTranslations(getLangFromUrl(Astro.url))
export async function getStaticPaths() { export async function getStaticPaths() {
return ["en", "fr", "cs", "de"].map((lang) => { return ["en", "fr", "cs", "de"].map((lang) => {
@ -21,9 +22,13 @@ var filtered_posts = posts.filter(
--- ---
<MainLayout title={title} description={description} lang={Astro.currentLocale}> <MainLayout title={t("blog")["title"]} description={t("blog")["description"]} lang={Astro.currentLocale}>
<SinglePageBlogMode> <SinglePageBlogMode>
<PostsList filteredPosts={filtered_posts} lang={Astro.currentLocale}/> <div class="p-4">
<h4 class="mb-2 text-3xl font-semibold leading-none text-foreground">{t("blog")["title"]}</h4>
<p class="mb-4 text-md leading-none text-foreground">{t("blog")["description"]}</p>
<Separator className="my-4"/>
<PostsList filteredPosts={filtered_posts} lang={Astro.currentLocale}/>
</div> </div>
</SinglePageBlogMode> </SinglePageBlogMode>
</MainLayout> </MainLayout>

View File

@ -1,16 +0,0 @@
---
import MainLayout from "../../../layouts/MainLayout.astro";
//@ts-ignore
import { dictionary } from "../../../i18n/dictionary";
const { title, description } = dictionary[Astro.currentLocale];
export async function getStaticPaths() {
return ["en", "fr", "cs", "de"].map((lang) => {
return { params: { lang } };
});
}
---
<MainLayout title={title} description={description} lang={Astro.currentLocale}>
</MainLayout>

View File

@ -1,4 +1,6 @@
--- ---
export const prerender = true
import MainLayout from "../../layouts/MainLayout.astro"; import MainLayout from "../../layouts/MainLayout.astro";
import Hero from "../../components/Hero.astro"; import Hero from "../../components/Hero.astro";
import About from "../../components/About.astro"; import About from "../../components/About.astro";

View File

@ -1,8 +1,15 @@
--- ---
export const prerender = true;
import MainLayout from "../../../layouts/MainLayout.astro"; import MainLayout from "../../../layouts/MainLayout.astro";
//@ts-ignore //@ts-ignore
import { getLangFromUrl, useTranslations } from "../../../i18n/utils"; import { getLangFromUrl, useTranslations } from "../../../i18n/utils";
import { Separator } from "../../../components/ui/separator";
import SinglePageBlogMode from "../../../layouts/SinglePageBlogMode.astro";
import { getCompositions } from "../../../content/config";
import CompositionsList from "../../../components/CompositionsList.astro";
const t = useTranslations(getLangFromUrl(Astro.url)); const t = useTranslations(getLangFromUrl(Astro.url));
@ -11,7 +18,22 @@ export async function getStaticPaths() {
return { params: { lang } }; return { params: { lang } };
}); });
} }
const songs = await getCompositions()
--- ---
<MainLayout title={t("title")} description={t("description")} lang={Astro.currentLocale} themeOverride="theme_auto">
<MainLayout
</MainLayout> title={t("title")}
description={t("description")}
lang={Astro.currentLocale}
themeOverride="theme_auto"
>
<SinglePageBlogMode>
<div class="p-4">
<h4 class="mb-2 text-3xl font-semibold leading-none text-foreground">{t("music")["title"]}</h4>
<p class="mb-4 text-md leading-none text-foreground">{t("music")["description"]}</p>
<Separator className="my-4"/>
<CompositionsList songs={songs}/>
</div>
</SinglePageBlogMode>
</MainLayout>

View File

@ -1,70 +1,64 @@
import nodemailer from "nodemailer"; import nodemailer from "nodemailer";
import { createId } from '@paralleldrive/cuid2'; import { createId } from "@paralleldrive/cuid2";
import { InfisicalClient } from "@infisical/sdk"; import { InfisicalClient } from "@infisical/sdk";
const client = new InfisicalClient({ const client = new InfisicalClient({
siteUrl: import.meta.env.INFISICAL_URL, siteUrl: import.meta.env.INFISICAL_URL,
auth: { auth: {
universalAuth: { universalAuth: {
clientId: import.meta.env.INFISICAL_CLIENTID, clientId: import.meta.env.INFISICAL_CLIENTID,
clientSecret: import.meta.env.INFISICAL_SECRET clientSecret: import.meta.env.INFISICAL_SECRET,
} },
} },
}); });
export const POST = async ({ request }) => { export const POST = async ({ request }) => {
try { try {
var secrets = await client.listSecrets({ var secrets = await client.listSecrets({
environment: "dev", environment: "dev",
projectId: import.meta.env.INFISICAL_PROJECTID, projectId: import.meta.env.INFISICAL_PROJECTID,
path: "/email", path: "/email",
includeImports: false includeImports: false,
}); });
secrets = Object.fromEntries(secrets.map(item => [item.secretKey, item.secretValue])); secrets = Object.fromEntries(
secrets.map((item) => [item.secretKey, item.secretValue])
const thisCuid = createId(); );
const data = await request.formData(); const thisCuid = createId();
var message = { const data = await request.formData();
from: `${data.get("username")} <${secrets["EMAIL"]}>`, var message = {
to: `Site Admin <${secrets["RECEIVER"]}>`, from: `${data.get("username")} <${secrets["EMAIL"]}>`,
subject: `${secrets["EMAIL_HEAD"]} | ${thisCuid}`, to: `Site Admin <${secrets["RECEIVER"]}>`,
text: `---\n${data.get("username")}\n${data.get("email")}\n---\n${data.get("message")}`, subject: `${secrets["EMAIL_HEAD"]} | ${thisCuid}`,
html: `<p>---<br/>${data.get("username")}<br/>${data.get("email")}<br/>---<br/>${data.get("message")}</p>`, text: `---\n${data.get("username")}\n${data.get(
envelope: { "email"
from: `${data.get("username")} <${secrets["EMAIL"]}>`, )}\n---\n${data.get("message")}`,
to: `Site Admin <${secrets["RECEIVER"]}>`, html: `<p>---<br/>${data.get("username")}<br/>${data.get(
} "email"
} )}<br/>---<br/>${data.get("message")}</p>`,
var transport = nodemailer.createTransport({ envelope: {
host: secrets["SMTP_SERVER"], from: `${data.get("username")} <${secrets["EMAIL"]}>`,
port: secrets["SMTP_PORT"], to: `Site Admin <${secrets["RECEIVER"]}>`,
secure: secrets["SMTP_SECURITY"], },
auth: { };
user: secrets["EMAIL"], var transport = nodemailer.createTransport({
pass: secrets["PASSWORD"] host: secrets["SMTP_SERVER"],
} port: secrets["SMTP_PORT"],
}); secure: secrets["SMTP_SECURITY"],
auth: {
user: secrets["EMAIL"],
pass: secrets["PASSWORD"],
},
});
var mailResponse = await transport.sendMail(message); var mailResponse = await transport.sendMail(message);
console.log(mailResponse) return new Response(JSON.stringify({ message: "Success!" }), {
return new Response(JSON.stringify({ message: "Success!" }), { status: 200 }); status: 200,
});
} catch (error) { } catch (error) {
console.error("Error parsing form data:", error); console.error("Error parsing form data:", error);
return new Response(JSON.stringify({ message: "Failed to parse form data" }), { status: 400 }); return new Response(
} JSON.stringify({ message: "Failed to parse form data" }),
}; { status: 400 }
);
}
/* };
npm install --save @types/nodemailer
npm install --save @types/nodemailer
npm install --save @types/nodemailer
npm install --save @types/nodemailer
další řádka
volná řádka
další řádka
asdasdasdasdasdad dlouhá řádka asdasdasda žádný enter tady asdsadadsas
*/