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
@ -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 preview` | Preview your build locally, before deploying |
|
||||
| `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()
|
||||
})
|
||||
});
|
||||
|
||||
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)
|
||||
// This key should match your collection directory name in "src/content"
|
||||
export const collections = {
|
||||
'blog': blogCollection,
|
||||
'music': musicCollection
|
||||
};
|
||||
|
||||
export async function getBlogPosts() {
|
||||
@ -32,4 +54,8 @@ export async function getBlogPosts() {
|
||||
blog_slug
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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",
|
||||
};
|
||||
|
@ -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 BlogPost from "../../../layouts/BlogPost.astro";
|
||||
|
||||
@ -19,7 +21,7 @@ export async function getStaticPaths() {
|
||||
const { lang } = Astro.params;
|
||||
const page = Astro.props;
|
||||
// @ts-ignore
|
||||
const formattedDate = page.data.publishDate.toLocaleString(lang);
|
||||
const formattedDate = page.data.publishDate?.toLocaleString(lang);
|
||||
|
||||
const { Content } = await page.render();
|
||||
---
|
||||
|
@ -1,13 +1,14 @@
|
||||
---
|
||||
export const prerender = true;
|
||||
|
||||
import MainLayout from "../../../layouts/MainLayout.astro";
|
||||
import { getBlogPosts } from "../../../content/config";
|
||||
//@ts-ignore
|
||||
import { dictionary } from "../../../i18n/dictionary";
|
||||
import SinglePageBlogMode from "../../../layouts/SinglePageBlogMode.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() {
|
||||
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>
|
||||
<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>
|
||||
</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 Hero from "../../components/Hero.astro";
|
||||
import About from "../../components/About.astro";
|
||||
|
@ -1,8 +1,15 @@
|
||||
---
|
||||
export const prerender = true;
|
||||
|
||||
import MainLayout from "../../../layouts/MainLayout.astro";
|
||||
|
||||
//@ts-ignore
|
||||
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));
|
||||
|
||||
@ -11,7 +18,22 @@ export async function getStaticPaths() {
|
||||
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>
|
||||
|
118
src/pages/api.js
118
src/pages/api.js
@ -1,70 +1,64 @@
|
||||
import nodemailer from "nodemailer";
|
||||
import { createId } from '@paralleldrive/cuid2';
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import { InfisicalClient } from "@infisical/sdk";
|
||||
|
||||
const client = new InfisicalClient({
|
||||
siteUrl: import.meta.env.INFISICAL_URL,
|
||||
auth: {
|
||||
universalAuth: {
|
||||
clientId: import.meta.env.INFISICAL_CLIENTID,
|
||||
clientSecret: import.meta.env.INFISICAL_SECRET
|
||||
}
|
||||
}
|
||||
siteUrl: import.meta.env.INFISICAL_URL,
|
||||
auth: {
|
||||
universalAuth: {
|
||||
clientId: import.meta.env.INFISICAL_CLIENTID,
|
||||
clientSecret: import.meta.env.INFISICAL_SECRET,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const POST = async ({ request }) => {
|
||||
try {
|
||||
var secrets = await client.listSecrets({
|
||||
environment: "dev",
|
||||
projectId: import.meta.env.INFISICAL_PROJECTID,
|
||||
path: "/email",
|
||||
includeImports: false
|
||||
});
|
||||
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"]
|
||||
}
|
||||
});
|
||||
try {
|
||||
var secrets = await client.listSecrets({
|
||||
environment: "dev",
|
||||
projectId: import.meta.env.INFISICAL_PROJECTID,
|
||||
path: "/email",
|
||||
includeImports: false,
|
||||
});
|
||||
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"],
|
||||
},
|
||||
});
|
||||
|
||||
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
|
||||
*/
|
||||
var mailResponse = await transport.sendMail(message);
|
||||
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 }
|
||||
);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user