i18n done?
Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
This commit is contained in:
parent
098e00e5e0
commit
0973cfe428
|
@ -3,14 +3,17 @@ import InlineLink from '../components/InlineLink.astro';
|
|||
|
||||
export interface Props {
|
||||
title: string;
|
||||
ptUrl: string;
|
||||
enUrl: string;
|
||||
lang: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
const { title, ptUrl, enUrl, lang } = Astro.props;
|
||||
const { footer } = Astro.slots;
|
||||
const hasFooter = !!footer;
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<html lang={lang}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
@ -22,23 +25,38 @@ const hasFooter = !!footer;
|
|||
<main class:list={['px-6 pt-4 md:px-20 md:pt-6', hasFooter && 'mb-32']}>
|
||||
<slot />
|
||||
</main>
|
||||
{
|
||||
hasFooter && (
|
||||
<footer class="fixed bottom-0 p-4 pb-0 flex flex-col w-full gap-2">
|
||||
<slot name="footer" />
|
||||
<div class="flex gap-3 justify-end bg-orange-50 pb-2">
|
||||
|
||||
<footer class="fixed bottom-0 p-4 pb-0 flex flex-col w-full gap-2">
|
||||
<slot name="footer" />
|
||||
<div
|
||||
class="flex justify-between max-xs:flex-col-reverse max-xs:items-center bg-orange-50 pb-2"
|
||||
>
|
||||
<ul class="flex gap-3">
|
||||
<li>
|
||||
<InlineLink href={ptUrl}>PT</InlineLink>
|
||||
</li>
|
||||
<li>
|
||||
<InlineLink href={enUrl}>EN</InlineLink>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex gap-3">
|
||||
<li>
|
||||
<InlineLink href="https://mastodon.green/@filipesm">
|
||||
Mastodon
|
||||
</InlineLink>
|
||||
</li>
|
||||
<li>
|
||||
<InlineLink href="https://codeberg.org/filipesm">
|
||||
Codeberg
|
||||
</InlineLink>
|
||||
</li>
|
||||
<li>
|
||||
<InlineLink href="https://bandcamp.com/filipesm">
|
||||
Bandcamp
|
||||
</InlineLink>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,7 +2,7 @@ import getMostRecentRevisions from '../getMostRecentRevisions';
|
|||
import groq from 'groq';
|
||||
|
||||
export const forBlogPostPage = groq`
|
||||
${getMostRecentRevisions(groq`_type == "blogPost"`)}
|
||||
${getMostRecentRevisions(groq`_type == "blogPost" && __i18n_lang == $lang`)}
|
||||
{
|
||||
"slug": slug.current,
|
||||
title,
|
||||
|
@ -24,9 +24,7 @@ export const forBlogPostPage = groq`
|
|||
}`;
|
||||
|
||||
export const forBlogPage = groq`
|
||||
${getMostRecentRevisions(
|
||||
groq`_type == "blogPost" && __i18n_lang == $locale`,
|
||||
)}
|
||||
${getMostRecentRevisions(groq`_type == "blogPost" && __i18n_lang == $lang`)}
|
||||
{
|
||||
title,
|
||||
summary,
|
||||
|
|
|
@ -3,7 +3,7 @@ import groq from 'groq';
|
|||
|
||||
export const forLibraryPage = groq`
|
||||
${getMostRecentRevisions(
|
||||
groq`_type == "libraryItem" && __i18n_lang == $locale`,
|
||||
groq`_type == "libraryItem" && __i18n_lang == $lang`,
|
||||
)}
|
||||
{
|
||||
title,
|
||||
|
|
|
@ -13,10 +13,16 @@ const libraryItems: {
|
|||
title: string;
|
||||
}[] = await client.fetch(forLibraryPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'pt_PT',
|
||||
});
|
||||
---
|
||||
|
||||
<Layout title="Biblioteca - Filipe Medeiros">
|
||||
<Layout
|
||||
title="Biblioteca - Filipe Medeiros"
|
||||
ptUrl="/biblioteca"
|
||||
enUrl="/library"
|
||||
lang="pt_PT"
|
||||
>
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Biblioteca</PageTitle>
|
||||
<h2>
|
||||
|
@ -42,7 +48,7 @@ const libraryItems: {
|
|||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
href="/blogue"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
|
|
|
@ -23,7 +23,10 @@ export interface Props {
|
|||
export async function getStaticPaths() {
|
||||
const posts: (Props & {
|
||||
slug: string;
|
||||
})[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV });
|
||||
})[] = await client.fetch(forBlogPostPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'en_EN',
|
||||
});
|
||||
|
||||
return posts.map(({ slug, ...blogPost }) => {
|
||||
return {
|
||||
|
@ -43,9 +46,16 @@ const {
|
|||
linkPreviewDescription,
|
||||
linkPreviewImage,
|
||||
} = Astro.props;
|
||||
|
||||
const { slug } = Astro.params;
|
||||
---
|
||||
|
||||
<Layout title={`${title} - Filipe Medeiros`}>
|
||||
<Layout
|
||||
title={`${title} - Filipe Medeiros`}
|
||||
ptUrl={`/blogue/${slug}`}
|
||||
enUrl={`/blog/${slug}`}
|
||||
lang="en_EN"
|
||||
>
|
||||
<BlogPostMetadata
|
||||
slot="metadata"
|
||||
title={title}
|
||||
|
@ -69,10 +79,10 @@ const {
|
|||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
href="/library"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
Library
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
|
|
|
@ -12,10 +12,18 @@ const posts: {
|
|||
publishDate: string;
|
||||
summary: string;
|
||||
slug: string;
|
||||
}[] = await client.fetch(forBlogPage, { live: !import.meta.env.DEV });
|
||||
}[] = await client.fetch(forBlogPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'en_EN',
|
||||
});
|
||||
---
|
||||
|
||||
<Layout title="Blog - Filipe Medeiros">
|
||||
<Layout
|
||||
title="Blog - Filipe Medeiros"
|
||||
ptUrl="/blogue"
|
||||
enUrl="/blog"
|
||||
lang="en_EN"
|
||||
>
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Blog</PageTitle>
|
||||
<h2>Uma coleção de artigos que vou escrevendo. Sobretudo por diversão.</h2>
|
||||
|
@ -40,16 +48,16 @@ const posts: {
|
|||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/"
|
||||
href="/home"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Início
|
||||
Home
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
href="/library"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
Library
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
|
|
89
frontend/src/pages/blogue/[slug]/index.astro
Normal file
89
frontend/src/pages/blogue/[slug]/index.astro
Normal file
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
import type { PortableTextBlock } from '@portabletext/types';
|
||||
import client from '../../../lib/cms/client';
|
||||
import { forBlogPostPage } from '../../../lib/cms/queries/blogPosts';
|
||||
import BlogPostContent from '../../../components/portableText/BlogPostContent.astro';
|
||||
import ButtonLink from '../../../components/ButtonLink.astro';
|
||||
import PageTitle from '../../../components/PageTitle.astro';
|
||||
import Layout from '../../../layouts/Layout.astro';
|
||||
import BlogPostMetadata from '../../../components/BlogPostMetadata.astro';
|
||||
import type { ImageObject } from '../../../lib/cms/types';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
content: PortableTextBlock[];
|
||||
publishDate: string;
|
||||
headerImage: ImageObject;
|
||||
summary: string;
|
||||
twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app';
|
||||
linkPreviewDescription: string;
|
||||
linkPreviewImage: ImageObject;
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts: (Props & {
|
||||
slug: string;
|
||||
})[] = await client.fetch(forBlogPostPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'pt_PT',
|
||||
});
|
||||
|
||||
return posts.map(({ slug, ...blogPost }) => {
|
||||
return {
|
||||
params: { slug },
|
||||
props: blogPost,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
content,
|
||||
publishDate,
|
||||
headerImage,
|
||||
summary,
|
||||
twitterCardType,
|
||||
linkPreviewDescription,
|
||||
linkPreviewImage,
|
||||
} = Astro.props;
|
||||
|
||||
const { slug } = Astro.params;
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={`${title} - Filipe Medeiros`}
|
||||
ptUrl={`/blogue/${slug}`}
|
||||
enUrl={`/blog/${slug}`}
|
||||
lang="pt_PT"
|
||||
>
|
||||
<BlogPostMetadata
|
||||
slot="metadata"
|
||||
title={title}
|
||||
description={linkPreviewDescription ?? summary}
|
||||
image={linkPreviewImage ?? headerImage}
|
||||
twitterCardType={twitterCardType}
|
||||
/>
|
||||
<article class="max-w-prose m-auto">
|
||||
<header class="mb-5">
|
||||
<PageTitle class="mb-2 break-words">{title}</PageTitle>
|
||||
<time datetime={publishDate} class="text-xl">{publishDate}</time>
|
||||
</header>
|
||||
<BlogPostContent content={content} />
|
||||
</article>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blogue"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
63
frontend/src/pages/blogue/index.astro
Normal file
63
frontend/src/pages/blogue/index.astro
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
import client from '../../lib/cms/client';
|
||||
import { forBlogPage } from '../../lib/cms/queries/blogPosts';
|
||||
import ButtonLink from '../../components/ButtonLink.astro';
|
||||
import CardLink from '../../components/CardLink.astro';
|
||||
import PageTitle from '../../components/PageTitle.astro';
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
const posts: {
|
||||
title: string;
|
||||
publishDate: string;
|
||||
summary: string;
|
||||
slug: string;
|
||||
}[] = await client.fetch(forBlogPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'pt_PT',
|
||||
});
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Blog - Filipe Medeiros"
|
||||
ptUrl="/blogue"
|
||||
enUrl="/blog"
|
||||
lang="pt_PT"
|
||||
>
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Blogue</PageTitle>
|
||||
<h2>Uma coleção de artigos que vou escrevendo. Sobretudo por diversão.</h2>
|
||||
</header>
|
||||
<ol>
|
||||
{
|
||||
posts.map(({ title, slug, publishDate, summary }) => (
|
||||
<CardLink link={`/blog/${slug}`}>
|
||||
<article class="flex flex-col">
|
||||
<span class="text-lg md:text-xl font-medium break-words text-primary-700">
|
||||
{title}
|
||||
</span>
|
||||
<time datetime={publishDate} class="text-sm text-primary-800">
|
||||
{publishDate}
|
||||
</time>
|
||||
<span>{summary}</span>
|
||||
</article>
|
||||
</CardLink>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Início
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
93
frontend/src/pages/home.astro
Normal file
93
frontend/src/pages/home.astro
Normal file
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
import ButtonLink from '../components/ButtonLink.astro';
|
||||
import InlineLink from '../components/InlineLink.astro';
|
||||
import PageTitle from '../components/PageTitle.astro';
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Home page - Filipe Medeiros"
|
||||
ptUrl="/"
|
||||
enUrl="/home"
|
||||
lang="en_EN"
|
||||
>
|
||||
<PageTitle class="mb-10">
|
||||
Filipe<br />Medeiros
|
||||
</PageTitle>
|
||||
|
||||
<div class="max-w-[60ch]">
|
||||
<p class="mb-3">
|
||||
Sou um engenheiro de <InlineLink
|
||||
href="https://www.usability.gov/what-and-why/user-experience.html"
|
||||
class="italic"
|
||||
>
|
||||
UX
|
||||
</InlineLink> (não me perguntem o que é, que nem eu sei bem).
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Gosto de programar interfaces e aplicações web, mas também de política, de
|
||||
ler sobre economia e de animais. Não gosto de cozinhar (ainda) nem de
|
||||
vento frio.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Estou a tentar trazer à superfície o potencial da humanidade. Sou a favor
|
||||
de <InlineLink href="https://www.w3.org/standards/faq#std" class="italic">
|
||||
standards
|
||||
</InlineLink>, software de código aberto (<InlineLink
|
||||
href="https://codeberg.org/filipesm/personal-website"
|
||||
>
|
||||
como é este site!
|
||||
</InlineLink>), <InlineLink href="https://pt.wikipedia.org/wiki/Copyleft">
|
||||
licenças <span class="italic">copyleft</span>
|
||||
</InlineLink>
|
||||
e de
|
||||
<InlineLink
|
||||
href="https://www.ica.coop/en/cooperatives/what-is-a-cooperative"
|
||||
>
|
||||
cooperativas
|
||||
</InlineLink> em vez de monopólios.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Sou apaixonado pela <InlineLink
|
||||
href="https://doughnuteconomics.org/about-doughnut-economics"
|
||||
class="italic"
|
||||
>
|
||||
Economia do Donut
|
||||
</InlineLink> e por economia social e ambiental. Gostava de, um dia, ser economista
|
||||
em vez de programador. Quem sabe, para a União Europeia.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Moro em <InlineLink href="https://www.oeiras.pt">
|
||||
Oeiras, Lisboa, Portugal
|
||||
</InlineLink>.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Se quiseres ver, tens <InlineLink href="/me.jpeg">aqui</InlineLink> uma foto
|
||||
minha!
|
||||
</p>
|
||||
<p>
|
||||
Este site tenta ser o mais sustentável possível: poupamos energia no teu
|
||||
dispositivo e em servidores. Teve muita inspiração da{' '}
|
||||
<InlineLink href="https://solar.lowtechmagazine.com">
|
||||
versão solar da Low Tech Magazine
|
||||
</InlineLink>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/library"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Library
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
|
@ -5,7 +5,12 @@ import PageTitle from '../components/PageTitle.astro';
|
|||
import Layout from '../layouts/Layout.astro';
|
||||
---
|
||||
|
||||
<Layout title="Página inicial - Filipe Medeiros">
|
||||
<Layout
|
||||
title="Página inicial - Filipe Medeiros"
|
||||
ptUrl="/"
|
||||
enUrl="/home"
|
||||
lang="pt_PT"
|
||||
>
|
||||
<PageTitle class="mb-10">
|
||||
Filipe<br />Medeiros
|
||||
</PageTitle>
|
||||
|
@ -72,10 +77,10 @@ import Layout from '../layouts/Layout.astro';
|
|||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
href="/blogue"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
Blogue
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
|
|
64
frontend/src/pages/library/index.astro
Normal file
64
frontend/src/pages/library/index.astro
Normal file
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
import client from '../../lib/cms/client';
|
||||
import { forLibraryPage } from '../../lib/cms/queries/libraryItems';
|
||||
import ButtonLink from '../../components/ButtonLink.astro';
|
||||
import CardLink from '../../components/CardLink.astro';
|
||||
import PageTitle from '../../components/PageTitle.astro';
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
const libraryItems: {
|
||||
description: string;
|
||||
checkedOut: boolean;
|
||||
link: string;
|
||||
title: string;
|
||||
}[] = await client.fetch(forLibraryPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
lang: 'en_EN',
|
||||
});
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Biblioteca - Filipe Medeiros"
|
||||
ptUrl="/biblioteca"
|
||||
enUrl="/library"
|
||||
lang="en_EN"
|
||||
>
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Library</PageTitle>
|
||||
<h2>
|
||||
Livros, artigos, <span class="italic">etc.</span> que já li e que recomendo
|
||||
ou que quero ler num futuro próximo. Se um item tiver uma marca "<span
|
||||
class="text-primary-700">✓</span
|
||||
>", siginifca que eu já li, vi, etc.
|
||||
</h2>
|
||||
</header>
|
||||
<ol>
|
||||
{
|
||||
libraryItems.map(({ title, description, link, checkedOut }) => (
|
||||
<CardLink link={link}>
|
||||
<span class="text-lg md:text-xl font-medium break-words text-primary-700 block mb-3">
|
||||
{title}
|
||||
</span>
|
||||
<p class="mb-5">{description}</p>
|
||||
{checkedOut && <span class="text-primary-700 text-3xl">✓</span>}
|
||||
</CardLink>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/home"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Home
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
|
@ -18,6 +18,14 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
screens: {
|
||||
xs: '420px',
|
||||
sm: '640px',
|
||||
md: '768px',
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
'2xl': '1536px',
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue