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:
parent
915ff6ede6
commit
3b33ffa05d
@ -39,4 +39,3 @@ All commands are run from the root of the project, from a terminal:
|
|||||||
| `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 |
|
||||||
|
|
||||||
|
0
public/music/first/my.flac
Normal file
0
public/music/first/my.flac
Normal file
0
public/music/first/my.mp3
Normal file
0
public/music/first/my.mp3
Normal file
0
public/music/first/my.pdf
Normal file
0
public/music/first/my.pdf
Normal file
14
src/components/CompositionsList.astro
Normal file
14
src/components/CompositionsList.astro
Normal 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" />}
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
}
|
39
src/components/SingleCompositionCard.astro
Normal file
39
src/components/SingleCompositionCard.astro
Normal 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>
|
@ -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() {
|
||||||
@ -33,3 +55,7 @@ export async function getBlogPosts() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getCompositions() {
|
||||||
|
return await getCollection('music');
|
||||||
|
}
|
15
src/content/music/first.md
Normal file
15
src/content/music/first.md
Normal 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"
|
||||||
|
---
|
15
src/content/music/second.md
Normal file
15
src/content/music/second.md
Normal 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"
|
||||||
|
---
|
@ -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",
|
||||||
};
|
};
|
||||||
|
@ -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>
|
|
@ -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();
|
||||||
---
|
---
|
||||||
|
@ -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>
|
@ -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>
|
|
@ -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";
|
||||||
|
@ -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 } };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
---
|
|
||||||
<MainLayout title={t("title")} description={t("description")} lang={Astro.currentLocale} themeOverride="theme_auto">
|
|
||||||
|
|
||||||
|
const songs = await getCompositions()
|
||||||
|
---
|
||||||
|
|
||||||
|
<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>
|
</MainLayout>
|
116
src/pages/api.js
116
src/pages/api.js
@ -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();
|
||||||
|
var message = {
|
||||||
|
from: `${data.get("username")} <${secrets["EMAIL"]}>`,
|
||||||
|
to: `Site Admin <${secrets["RECEIVER"]}>`,
|
||||||
|
subject: `${secrets["EMAIL_HEAD"]} | ${thisCuid}`,
|
||||||
|
text: `---\n${data.get("username")}\n${data.get(
|
||||||
|
"email"
|
||||||
|
)}\n---\n${data.get("message")}`,
|
||||||
|
html: `<p>---<br/>${data.get("username")}<br/>${data.get(
|
||||||
|
"email"
|
||||||
|
)}<br/>---<br/>${data.get("message")}</p>`,
|
||||||
|
envelope: {
|
||||||
|
from: `${data.get("username")} <${secrets["EMAIL"]}>`,
|
||||||
|
to: `Site Admin <${secrets["RECEIVER"]}>`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var transport = nodemailer.createTransport({
|
||||||
|
host: secrets["SMTP_SERVER"],
|
||||||
|
port: secrets["SMTP_PORT"],
|
||||||
|
secure: secrets["SMTP_SECURITY"],
|
||||||
|
auth: {
|
||||||
|
user: secrets["EMAIL"],
|
||||||
|
pass: secrets["PASSWORD"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const thisCuid = createId();
|
var mailResponse = await transport.sendMail(message);
|
||||||
const data = await request.formData();
|
return new Response(JSON.stringify({ message: "Success!" }), {
|
||||||
var message = {
|
status: 200,
|
||||||
from: `${data.get("username")} <${secrets["EMAIL"]}>`,
|
});
|
||||||
to: `Site Admin <${secrets["RECEIVER"]}>`,
|
} catch (error) {
|
||||||
subject: `${secrets["EMAIL_HEAD"]} | ${thisCuid}`,
|
console.error("Error parsing form data:", error);
|
||||||
text: `---\n${data.get("username")}\n${data.get("email")}\n---\n${data.get("message")}`,
|
return new Response(
|
||||||
html: `<p>---<br/>${data.get("username")}<br/>${data.get("email")}<br/>---<br/>${data.get("message")}</p>`,
|
JSON.stringify({ message: "Failed to parse form data" }),
|
||||||
envelope: {
|
{ status: 400 }
|
||||||
from: `${data.get("username")} <${secrets["EMAIL"]}>`,
|
);
|
||||||
to: `Site Admin <${secrets["RECEIVER"]}>`,
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
var transport = nodemailer.createTransport({
|
|
||||||
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);
|
|
||||||
console.log(mailResponse)
|
|
||||||
return new Response(JSON.stringify({ message: "Success!" }), { status: 200 });
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error parsing form data:", error);
|
|
||||||
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
|
|
||||||
*/
|
|
Loading…
Reference in New Issue
Block a user