feat: use astro files for slides
This commit is contained in:
parent
8ca43b3785
commit
0614e2b7ef
@ -1,14 +0,0 @@
|
|||||||
import { defineCollection, z } from "astro:content";
|
|
||||||
import { glob } from "astro/loaders"; // Not available with legacy API
|
|
||||||
|
|
||||||
const slides = defineCollection({
|
|
||||||
loader: glob({ pattern: "**/*.md", base: "./src/slides" }),
|
|
||||||
schema: z.object({
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
authors: z.array(z.string()),
|
|
||||||
publishedAt: z.coerce.date(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const collections = { slides };
|
|
||||||
@ -5,7 +5,7 @@ export interface Props {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
import Layout from "./BaseLayout.astro";
|
import Layout from "./BaseLayout.astro";
|
||||||
import "@themes/hnrq.scss";
|
import "@theme";
|
||||||
|
|
||||||
const { title, authors, description } = Astro.props;
|
const { title, authors, description } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|||||||
@ -1,21 +1,17 @@
|
|||||||
---
|
---
|
||||||
import SlideLayout from "@layouts/SlideLayout.astro";
|
import SlideLayout from "@layouts/SlideLayout.astro";
|
||||||
import { getCollection, render } from "astro:content";
|
import { getSlides } from "@utils/getSlides";
|
||||||
|
|
||||||
export const getStaticPaths = async () =>
|
export const getStaticPaths = () =>
|
||||||
(await getCollection("slides")).map((slide) => ({
|
getSlides().map((slide) => ({ params: { id: slide.id }, props: { slide } }));
|
||||||
params: { id: slide.id },
|
|
||||||
props: { slide },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { slide } = Astro.props;
|
const { slide } = Astro.props;
|
||||||
const { Content } = await render(slide);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<SlideLayout
|
<SlideLayout
|
||||||
title={slide.data.title}
|
title={slide.title}
|
||||||
authors={slide.data.authors}
|
authors={slide.authors}
|
||||||
description={slide.data.description}
|
description={slide.description}
|
||||||
>
|
>
|
||||||
<Content />
|
<slide.default />
|
||||||
</SlideLayout>
|
</SlideLayout>
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
---
|
---
|
||||||
import Layout from "@layouts/BaseLayout.astro";
|
import Layout from "@layouts/BaseLayout.astro";
|
||||||
import { getCollection } from "astro:content";
|
import { getSlides } from "@utils/getSlides";
|
||||||
|
|
||||||
const slides = (await getCollection("slides")).sort((c1, c2) =>
|
const slides = getSlides().sort((c1, c2) => (c1.title > c2.title ? -1 : 1));
|
||||||
c1.data.title > c2.data.title ? -1 : 1
|
|
||||||
);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Home">
|
<Layout title="Home">
|
||||||
@ -13,21 +11,21 @@ const slides = (await getCollection("slides")).sort((c1, c2) =>
|
|||||||
{
|
{
|
||||||
slides.map((slide) => (
|
slides.map((slide) => (
|
||||||
<a href={`/${slide.id}`}>
|
<a href={`/${slide.id}`}>
|
||||||
<h2>{slide.data.title}</h2>
|
<h2>{slide.title}</h2>
|
||||||
<p>{slide.data.description}</p>
|
<p>{slide.description}</p>
|
||||||
<small>{slide.data.publishedAt.toLocaleDateString()}</small>
|
<small>{new Date(slide.publishedAt).toLocaleDateString()}</small>
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style lang="scss">
|
<style>
|
||||||
@use "@themes/hnrq";
|
@import "@theme";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: hnrq.$backgroundColor;
|
background-color: var(--background);
|
||||||
color: hnrq.$mainColor;
|
color: var(--main-color);
|
||||||
font-family: hnrq.$mainFont;
|
font-family: var(--main-font);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -43,17 +41,17 @@ const slides = (await getCollection("slides")).sort((c1, c2) =>
|
|||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: hnrq.$headingFont;
|
font-family: var(--heading-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
color: hnrq.$mainColor;
|
color: var(--main-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: filter 0.2s ease-in-out;
|
||||||
|
background-color: var(--background);
|
||||||
&:hover {
|
&:hover {
|
||||||
background: hnrq.$mainColor;
|
filter: invert(1);
|
||||||
color: hnrq.$backgroundColor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
92
src/slides/flexbox/index.astro
Normal file
92
src/slides/flexbox/index.astro
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
export const title = "CSS Flexbox"
|
||||||
|
export const authors = ["Henrique Ramos"]
|
||||||
|
export const publishedAt = "2025-01-27"
|
||||||
|
export const description = "Do you even flex?"
|
||||||
|
---
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>What is Flexbox?</h2>
|
||||||
|
<ul>
|
||||||
|
<li>One-dimensional layout model</li>
|
||||||
|
<li>Distributes space along a single direction</li>
|
||||||
|
<li>Powerful alignment capabilities</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Basic Flexbox Container</h2>
|
||||||
|
<div class="demo">
|
||||||
|
<div class="box">1</div>
|
||||||
|
<div class="box">2</div>
|
||||||
|
<div class="box">3</div>
|
||||||
|
</div>
|
||||||
|
<pre><code data-trim>
|
||||||
|
.container {'{'}
|
||||||
|
display: flex;
|
||||||
|
{'}'}
|
||||||
|
</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>justify-content</h2>
|
||||||
|
<div class="demo" style="justify-content: space-between">
|
||||||
|
<div class="box">1</div>
|
||||||
|
<div class="box">2</div>
|
||||||
|
<div class="box">3</div>
|
||||||
|
</div>
|
||||||
|
<pre><code data-trim>
|
||||||
|
.container {'{'}
|
||||||
|
justify-content: space-between;
|
||||||
|
{'}'}
|
||||||
|
</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>align-items</h2>
|
||||||
|
<div class="demo" style="align-items: center; height: 300px">
|
||||||
|
<div class="box">1</div>
|
||||||
|
<div class="box">2</div>
|
||||||
|
<div class="box">3</div>
|
||||||
|
</div>
|
||||||
|
<pre><code data-trim>
|
||||||
|
.container {'{'}
|
||||||
|
align-items: center;
|
||||||
|
{'}'}
|
||||||
|
</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>flex-direction</h2>
|
||||||
|
<div class="demo" style="flex-direction: column">
|
||||||
|
<div class="box">1</div>
|
||||||
|
<div class="box">2</div>
|
||||||
|
<div class="box">3</div>
|
||||||
|
</div>
|
||||||
|
<pre><code data-trim>
|
||||||
|
.container {'{'}
|
||||||
|
flex-direction: column;
|
||||||
|
{'}'}
|
||||||
|
</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.demo {
|
||||||
|
display: flex;
|
||||||
|
margin: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background: #4a9eff;
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: "Finite State Machines with XState for Game Development using Three.js"
|
export const title = "Finite State Machines with XState for Game Development using Three.js"
|
||||||
authors: ["Henrique Ramos"]
|
export const authors = ["Henrique Ramos"]
|
||||||
publishedAt: 2024-12-13
|
export const publishedAt = "2024-12-13"
|
||||||
description: "Using XState Finite State Machines to coordinate character actions in a Three.js game"
|
export const description = "Using XState Finite State Machines to coordinate character actions in a Three.js game"
|
||||||
---
|
---
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
38
src/utils/getAstroPages.ts
Normal file
38
src/utils/getAstroPages.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import type { AstroInstance } from "astro";
|
||||||
|
|
||||||
|
type Opts<T extends Record<string, unknown>> = {
|
||||||
|
files: Record<string, T>;
|
||||||
|
requiredFields?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all Astro pages from a given path.
|
||||||
|
* @param opts - The options for the function.
|
||||||
|
* @param opts.files - The files to get the Astro pages from. Use import.meta.glob eager: true.
|
||||||
|
* @param opts.requiredFields - The required fields for the Astro pages.
|
||||||
|
* @returns The Astro pages in the root of the given path, or looks for index.astro files in subdirectories (single level).
|
||||||
|
*/
|
||||||
|
const getAstroPages = <T extends Record<string, unknown> & AstroInstance>({
|
||||||
|
files,
|
||||||
|
requiredFields = [],
|
||||||
|
}: Opts<T>) =>
|
||||||
|
Object.values(files).map((module) => {
|
||||||
|
if (!requiredFields.every((field) => module[field as keyof T])) {
|
||||||
|
throw new Error(
|
||||||
|
`Missing required fields for ${module.file}: ${requiredFields
|
||||||
|
.filter((field) => !module[field as keyof T])
|
||||||
|
.join(", ")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: (
|
||||||
|
module.file
|
||||||
|
.split("/")
|
||||||
|
.at(module.file.includes("index.astro") ? -2 : -1) ?? ""
|
||||||
|
).replace(".astro", ""),
|
||||||
|
...module,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getAstroPages;
|
||||||
25
src/utils/getSlides.ts
Normal file
25
src/utils/getSlides.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { AstroInstance } from "astro";
|
||||||
|
import getAstroPages from "./getAstroPages";
|
||||||
|
|
||||||
|
type Slide = AstroInstance & {
|
||||||
|
[key: string]: unknown;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
authors: string[];
|
||||||
|
publishedAt: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const slideRequiredFields = ["title", "description", "authors", "publishedAt"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all slides from the slides directory.
|
||||||
|
* @returns The slides.
|
||||||
|
*/
|
||||||
|
export const getSlides = () =>
|
||||||
|
getAstroPages<Slide>({
|
||||||
|
files: import.meta.glob<true, string, Slide>(
|
||||||
|
["@slides/**/index.astro", "@slides/*.astro"],
|
||||||
|
{ eager: true },
|
||||||
|
),
|
||||||
|
requiredFields: slideRequiredFields,
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user