Compare commits
No commits in common. "aa1bb53b96733b8a97621af1650405e4356adffa" and "5e16c97462071fcb63ebc2054cc4988a84f08383" have entirely different histories.
aa1bb53b96
...
5e16c97462
11 changed files with 43 additions and 120 deletions
|
|
@ -49,11 +49,7 @@ export default defineConfig({
|
|||
// routing would add middleware that 404s the unprefixed on-demand
|
||||
// /page-card and /social-card routes (prefix-always) or /en/* (default).
|
||||
|
||||
redirects: {
|
||||
...Object.fromEntries(LEGACY_EN_PATHS.map((path) => [path, path === '/' ? '/en' : `/en${path}`])),
|
||||
// The Portuguese about page moved to /pt/sobre (slug from src/content/about/pt.md).
|
||||
'/pt/about': '/pt/sobre',
|
||||
},
|
||||
redirects: Object.fromEntries(LEGACY_EN_PATHS.map((path) => [path, path === '/' ? '/en' : `/en${path}`])),
|
||||
|
||||
integrations: [react(), mdx(), sitemap({ filter: (page) => !DRAFT_PATHS.some((path) => page.endsWith(path)) })],
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
---
|
||||
import ThemeToggle from './ThemeToggle.astro';
|
||||
import { getAboutPath } from '../lib/about';
|
||||
import { getLocalizedPath, LANG_LABELS, useTranslations, type Lang } from '../lib/i18n';
|
||||
|
||||
interface Props {
|
||||
lang: Lang;
|
||||
/** Where the language switch goes; defaults to swapping the /<lang> prefix. */
|
||||
langSwitchHref?: string;
|
||||
}
|
||||
|
||||
const { lang } = Astro.props;
|
||||
|
|
@ -16,8 +13,8 @@ const otherLang: Lang = lang === 'en' ? 'pt' : 'en';
|
|||
const pathname = Astro.url.pathname;
|
||||
const homeHref = getLocalizedPath('/', lang);
|
||||
const postsHref = getLocalizedPath('/posts', lang);
|
||||
const aboutHref = await getAboutPath(lang);
|
||||
const langSwitchHref = Astro.props.langSwitchHref ?? getLocalizedPath(pathname, otherLang);
|
||||
const aboutHref = getLocalizedPath('/about', lang);
|
||||
const langSwitchHref = getLocalizedPath(pathname, otherLang);
|
||||
|
||||
const navLinks = [
|
||||
{ href: homeHref, label: t('nav.home'), id: 'home' },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
import PostCard from './PostCard.astro';
|
||||
import { getPostsByLang } from '../lib/posts';
|
||||
import { getAboutPath } from '../lib/about';
|
||||
import { getLocalizedPath, useTranslations, type Lang } from '../lib/i18n';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -13,7 +12,7 @@ const t = useTranslations(lang);
|
|||
const posts = await getPostsByLang(lang);
|
||||
const recentPosts = posts.slice(0, 3);
|
||||
const postsHref = getLocalizedPath('/posts', lang);
|
||||
const aboutHref = await getAboutPath(lang);
|
||||
const aboutHref = getLocalizedPath('/about', lang);
|
||||
---
|
||||
|
||||
<section class="mx-10 my-10 flex flex-col gap-5 font-mono">
|
||||
|
|
|
|||
|
|
@ -18,14 +18,4 @@ const posts = defineCollection({
|
|||
}),
|
||||
});
|
||||
|
||||
// The about page, one file per language: src/content/about/<lang>.md.
|
||||
// `slug` is the URL segment for that language (about, sobre).
|
||||
const about = defineCollection({
|
||||
loader: glob({ pattern: '*.md', base: './src/content/about' }),
|
||||
schema: z.object({
|
||||
language: z.enum(['en', 'pt']),
|
||||
slug: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { posts, about };
|
||||
export const collections = { posts };
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
language: en
|
||||
slug: about
|
||||
---
|
||||
|
||||
Hi, I'm Gabe — Gabriel Franco. I'm a computer science student at PUCRS (Pontifícia Universidade Católica do Rio Grande do Sul), and this blog is where I write down the things I'm learning and thinking about along the way.
|
||||
|
||||
I care a lot about computer science as a field, not just as a set of tools to ship products with. I have a fairly specific way of doing things: I'd rather understand a system properly than memorize the steps to make it work, and I tend to slow down on purpose to figure out what's actually happening under the hood — in a compiler, an operating system, a language runtime, whatever it is. That habit shapes most of what ends up on this blog.
|
||||
|
||||
I'm also genuinely interested in the history of the open source movement: the people, the arguments, and the decisions that shaped the software we all rely on. Figures like Linus Torvalds and projects like GNU come up often in what I read and write about, not as trivia, but because understanding where a tool came from usually explains a lot about how and why it works the way it does today.
|
||||
|
||||
This site is bilingual, in English and in Portuguese, and every post exists in both languages. Thanks for stopping by.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
language: pt
|
||||
slug: sobre
|
||||
---
|
||||
|
||||
Olá, eu sou o Gabe — Gabriel Franco. Sou estudante de ciência da computação na PUCRS (Pontifícia Universidade Católica do Rio Grande do Sul), e este blog é onde registro as coisas que vou aprendendo e pensando pelo caminho.
|
||||
|
||||
Eu me importo bastante com ciência da computação como área, não só como um conjunto de ferramentas para lançar produtos. Tenho um jeito bem específico de fazer as coisas: prefiro entender um sistema de verdade do que decorar os passos para fazê-lo funcionar, e costumo desacelerar de propósito para descobrir o que realmente está acontecendo por baixo dos panos — em um compilador, em um sistema operacional, no runtime de uma linguagem, seja lá o que for. Esse hábito molda a maior parte do que acaba virando post aqui.
|
||||
|
||||
Também tenho um interesse genuíno pela história do movimento open source: as pessoas, os debates e as decisões que moldaram o software do qual todos dependemos. Figuras como Linus Torvalds e projetos como o GNU aparecem com frequência no que leio e escrevo, não como curiosidade, mas porque entender de onde uma ferramenta veio costuma explicar bastante sobre como e por que ela funciona do jeito que funciona hoje.
|
||||
|
||||
Este site é bilíngue, em inglês e em português, e todo post existe nos dois idiomas. Obrigado pela visita.
|
||||
|
|
@ -18,15 +18,9 @@ interface Props {
|
|||
image?: string;
|
||||
/** Keep the page out of search engines (used for draft posts). */
|
||||
noindex?: boolean;
|
||||
/**
|
||||
* This page's path in each language, for pages whose path isn't the same
|
||||
* across languages (the about page). Defaults to swapping the /<lang> prefix.
|
||||
*/
|
||||
alternates?: Partial<Record<Lang, string>>;
|
||||
}
|
||||
|
||||
const { title, description, lang, noindex, alternates = {} } = Astro.props;
|
||||
const alternatePath = (target: Lang) => alternates[target] ?? getLocalizedPath(Astro.url.pathname, target);
|
||||
const { title, description, lang, noindex } = Astro.props;
|
||||
const image = Astro.props.image && existsSync(`public${Astro.props.image}`) ? Astro.props.image : '/logo.png';
|
||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||
---
|
||||
|
|
@ -40,8 +34,8 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
|||
<link rel="alternate icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
<link rel="alternate" hreflang="en" href={new URL(alternatePath('en'), Astro.site)} />
|
||||
<link rel="alternate" hreflang="pt-BR" href={new URL(alternatePath('pt'), Astro.site)} />
|
||||
<link rel="alternate" hreflang="en" href={new URL(getLocalizedPath(Astro.url.pathname, 'en'), Astro.site)} />
|
||||
<link rel="alternate" hreflang="pt-BR" href={new URL(getLocalizedPath(Astro.url.pathname, 'pt'), Astro.site)} />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
|
||||
|
|
@ -88,7 +82,7 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
|||
</script>
|
||||
</head>
|
||||
<body class="flex min-h-screen flex-col bg-bg font-sans text-text antialiased selection:bg-primary selection:text-white">
|
||||
<Header lang={lang} langSwitchHref={alternates[lang === 'en' ? 'pt' : 'en']} />
|
||||
<Header lang={lang} />
|
||||
<main class="flex-1">
|
||||
<slot />
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
import { getCollection, type CollectionEntry } from 'astro:content';
|
||||
import type { Lang } from './i18n';
|
||||
|
||||
// The about page lives at src/content/about/<lang>.md; its URL segment comes
|
||||
// from the `slug` frontmatter field, so each language can have its own
|
||||
// (/en/about, /pt/sobre).
|
||||
export type AboutPage = CollectionEntry<'about'>;
|
||||
|
||||
export async function getAboutPages(): Promise<AboutPage[]> {
|
||||
return getCollection('about');
|
||||
}
|
||||
|
||||
export async function getAboutPage(lang: Lang): Promise<AboutPage> {
|
||||
const page = (await getAboutPages()).find((entry) => entry.data.language === lang);
|
||||
if (!page) throw new Error(`Missing src/content/about/${lang}.md`);
|
||||
return page;
|
||||
}
|
||||
|
||||
export function aboutPathOf(page: AboutPage): string {
|
||||
return `/${page.data.language}/${page.data.slug}`;
|
||||
}
|
||||
|
||||
export async function getAboutPath(lang: Lang): Promise<string> {
|
||||
return aboutPathOf(await getAboutPage(lang));
|
||||
}
|
||||
|
|
@ -45,6 +45,13 @@ export const ui = {
|
|||
'about.title': 'About',
|
||||
'about.description':
|
||||
'Gabriel Franco: computer science student at PUCRS, interested in how software actually works and in the history of open source.',
|
||||
// Paragraphs are separated by a blank line.
|
||||
'about.body': [
|
||||
"Hi, I'm Gabe — Gabriel Franco. I'm a computer science student at PUCRS (Pontifícia Universidade Católica do Rio Grande do Sul), and this blog is where I write down the things I'm learning and thinking about along the way.",
|
||||
"I care a lot about computer science as a field, not just as a set of tools to ship products with. I have a fairly specific way of doing things: I'd rather understand a system properly than memorize the steps to make it work, and I tend to slow down on purpose to figure out what's actually happening under the hood — in a compiler, an operating system, a language runtime, whatever it is. That habit shapes most of what ends up on this blog.",
|
||||
"I'm also genuinely interested in the history of the open source movement: the people, the arguments, and the decisions that shaped the software we all rely on. Figures like Linus Torvalds and projects like GNU come up often in what I read and write about, not as trivia, but because understanding where a tool came from usually explains a lot about how and why it works the way it does today.",
|
||||
'This site is bilingual, in English and in Portuguese, and every post exists in both languages. Thanks for stopping by.',
|
||||
].join('\n\n'),
|
||||
'footer.tagline': 'Written by hand in Porto Alegre.',
|
||||
'footer.rights': 'All rights reserved.',
|
||||
'footer.source': 'Source',
|
||||
|
|
@ -89,6 +96,12 @@ export const ui = {
|
|||
'about.title': 'Sobre',
|
||||
'about.description':
|
||||
'Gabriel Franco: estudante de ciência da computação na PUCRS, interessado em como o software realmente funciona e na história do open source.',
|
||||
'about.body': [
|
||||
'Olá, eu sou o Gabe — Gabriel Franco. Sou estudante de ciência da computação na PUCRS (Pontifícia Universidade Católica do Rio Grande do Sul), e este blog é onde registro as coisas que vou aprendendo e pensando pelo caminho.',
|
||||
'Eu me importo bastante com ciência da computação como área, não só como um conjunto de ferramentas para lançar produtos. Tenho um jeito bem específico de fazer as coisas: prefiro entender um sistema de verdade a decorar os passos para fazê-lo funcionar, e costumo desacelerar de propósito para descobrir o que realmente está acontecendo por baixo dos panos — em um compilador, em um sistema operacional, no runtime de uma linguagem, seja lá o que for. Esse hábito molda a maior parte do que acaba virando post aqui.',
|
||||
'Também tenho um interesse genuíno pela história do movimento open source: as pessoas, os debates e as decisões que moldaram o software do qual todos dependemos. Figuras como Linus Torvalds e projetos como o GNU aparecem com frequência no que leio e escrevo, não como curiosidade, mas porque entender de onde uma ferramenta veio costuma explicar bastante sobre como e por que ela funciona do jeito que funciona hoje.',
|
||||
'Este site é bilíngue, em inglês e em português, e todo post existe nos dois idiomas. Obrigado pela visita.',
|
||||
].join('\n\n'),
|
||||
'footer.tagline': 'Escrito à mão em Porto Alegre.',
|
||||
'footer.rights': 'Todos os direitos reservados.',
|
||||
'footer.source': 'Código-fonte',
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
import { render } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { aboutPathOf, getAboutPages, type AboutPage } from '../../lib/about';
|
||||
import { pageMeta, useTranslations, type Lang } from '../../lib/i18n';
|
||||
import { pageCardPath } from '../../lib/social-cards';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const pages = await getAboutPages();
|
||||
// The language switcher and hreflang links need the other language's slug.
|
||||
const alternates = Object.fromEntries(pages.map((page) => [page.data.language, `${aboutPathOf(page)}/`]));
|
||||
return pages.map((page) => ({
|
||||
params: { lang: page.data.language, about: page.data.slug },
|
||||
props: { page, alternates },
|
||||
}));
|
||||
}
|
||||
|
||||
interface Props {
|
||||
page: AboutPage;
|
||||
alternates: Record<Lang, string>;
|
||||
}
|
||||
|
||||
const { page: entry, alternates } = Astro.props;
|
||||
const lang = entry.data.language;
|
||||
const t = useTranslations(lang);
|
||||
const page = pageMeta(lang, 'about');
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<BaseLayout title={`${page.title} — ${t('site.name')}`} description={page.description} lang={lang} image={pageCardPath(lang, 'about')} alternates={alternates}>
|
||||
<section class="mx-10 mt-10 font-mono">
|
||||
<h1 class="text-3xl font-bold tracking-tight text-text sm:text-4xl">{page.title}</h1>
|
||||
|
||||
<div class="prose prose-neutral mt-6 max-w-none prose-headings:font-semibold prose-a:text-primary prose-a:no-underline hover:prose-a:underline dark:prose-invert">
|
||||
<Content />
|
||||
</div>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
21
src/pages/[lang]/about.astro
Normal file
21
src/pages/[lang]/about.astro
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { langPaths, pageMeta, useTranslations, type Lang } from '../../lib/i18n';
|
||||
import { pageCardPath } from '../../lib/social-cards';
|
||||
|
||||
export const getStaticPaths = langPaths;
|
||||
|
||||
const lang = Astro.params.lang as Lang;
|
||||
const t = useTranslations(lang);
|
||||
const page = pageMeta(lang, 'about');
|
||||
---
|
||||
|
||||
<BaseLayout title={`${page.title} — ${t('site.name')}`} description={page.description} lang={lang} image={pageCardPath(lang, 'about')}>
|
||||
<section class="mx-10 mt-10 font-mono">
|
||||
<h1 class="text-3xl font-bold tracking-tight text-text sm:text-4xl">{page.title}</h1>
|
||||
|
||||
<div class="prose prose-neutral mt-6 max-w-none prose-headings:font-semibold prose-a:text-primary prose-a:no-underline hover:prose-a:underline dark:prose-invert">
|
||||
{t('about.body').split('\n\n').map((paragraph) => <p>{paragraph}</p>)}
|
||||
</div>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
Loading…
Reference in a new issue