diff --git a/astro.config.mjs b/astro.config.mjs index a267f04..796c8e0 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -13,7 +13,6 @@ export default defineConfig({ site: baseUrl, trailingSlash: 'never', compressHTML: false, - output: 'server', adapter: node({ mode: 'standalone', @@ -31,7 +30,7 @@ export default defineConfig({ integrations: [ mdx(), sitemap({ - filter: (page) => !['/disabled-redirect', '/journal'].find((u) => `${baseUrl}${u}` === page), + filter: (page) => !['/disabled-redirect'].find((u) => `${baseUrl}${u}` === page), }), ], }); diff --git a/src/content.config.ts b/src/content.config.ts index c33721f..38e17d7 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -23,21 +23,6 @@ const blog = defineCollection({ }), }); -// the friends thing is hosted on a separate private repository -// thats then merged to the source before building - -// huge props to gérald & gpt-5 (lol) -const journal = defineCollection({ - loader: glob({ - pattern: '**/*.{md,mdx}', - base: './src/content/friends/posts/', - }), - schema: z.object({ - title: z.string(), - createdAt: z.coerce.date(), - }), -}); - -export const collections = { blog, journal }; +export const collections = { blog }; export type BlogData = CollectionEntry<'blog'>['data']; diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 14777b0..689d13f 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -6,15 +6,15 @@ export const ui = { fr, } as const; -export const locales = { +export const LOCALES = { en: 'English', fr: 'Français', } as const; -export type Locale = keyof typeof locales; +export type Locale = keyof typeof LOCALES; -export const localeCodes = Object.keys(locales); +export const LOCALE_CODES = Object.keys(LOCALES); -export const defaultLocale: Locale = 'en'; +export const DEFAULT_LOCALE: Locale = 'en'; export * from './utils'; diff --git a/src/i18n/langs/en.ts b/src/i18n/langs/en.ts index a449a25..504ac87 100644 --- a/src/i18n/langs/en.ts +++ b/src/i18n/langs/en.ts @@ -71,9 +71,6 @@ export default { 'blog.edited_on': 'Edited on', 'blog.warning_unlocalized': 'You are reading the original version of this article, as it was not adapted to English. Sorry for the inconvenience.', - 'journal.title': 'journal', - 'journal.pwd.explaining': 'Clément should have given you a code to enter.', - 'journal.pwd.button': 'Unlock', 'projects.uniten.title': 'UNITEN', 'projects.uniten.description': 'App for tennis players to find partners. Crafting new features and redesigning the app in a 8 week-internship.', diff --git a/src/i18n/langs/fr.ts b/src/i18n/langs/fr.ts index 07175e0..1fd2364 100644 --- a/src/i18n/langs/fr.ts +++ b/src/i18n/langs/fr.ts @@ -74,9 +74,6 @@ export const fr: typeof en = { 'blog.edited_on': 'Édité le', 'blog.warning_unlocalized': "Vous lisez cet article dans sa version originale, car il n'a pas été traduit en français. Désolé pour la gêne occasionnée.", - 'journal.title': 'journal', - 'journal.pwd.explaining': 'Clément a dû vous donner un code pour rentrer.', - 'journal.pwd.button': 'Débloquer', 'projects.uniten.title': 'UNITEN', 'projects.uniten.description': "App mobile permettant aux joueurs de tennis de trouver des partenaires. Confection d'un redesign et de fonctionnalités majeures en 8 semaines.", diff --git a/src/i18n/utils.ts b/src/i18n/utils.ts index 19720cc..b094369 100644 --- a/src/i18n/utils.ts +++ b/src/i18n/utils.ts @@ -1,15 +1,15 @@ -import { defaultLocale, type Locale, ui } from '.'; +import { DEFAULT_LOCALE, type Locale, LOCALE_CODES, ui } from '.'; export function getLocaleFromUrl(url: URL): Locale { const [, lang] = url.pathname.split('/'); if (lang in ui) return lang as Locale; - return defaultLocale; + return DEFAULT_LOCALE; } export function useTranslations(locale: Locale) { - return function t(key: keyof (typeof ui)[typeof defaultLocale] | (string & {})) { + return function t(key: keyof (typeof ui)[typeof DEFAULT_LOCALE] | (string & {})) { // @ts-ignore - return ui?.[locale]?.[key] ?? ui?.[defaultLocale]?.[key] ?? ''; + return ui?.[locale]?.[key] ?? ui?.[DEFAULT_LOCALE]?.[key] ?? ''; }; } @@ -29,5 +29,9 @@ export function removeTrailingSlash(string: string) { return string.replace(/(?:\/+(\?))/, '$1').replace(/\/+$/, ''); } +export function generateLangStaticPaths() { + return LOCALE_CODES.map((l) => ({ params: { lang: l } })); +} + export const getPostSlug = (postId: string) => postId.split('/').slice(0, -1).join('/'); export const getPostLang = (postId: string) => postId.split('/').at(-1)!; diff --git a/src/pages/404.astro b/src/pages/404.astro index d2a55ee..bfb2d1d 100644 --- a/src/pages/404.astro +++ b/src/pages/404.astro @@ -1,4 +1,7 @@ --- +// to enable localization +export const prerender = false; + import Button from '@components/Button.astro'; import { getLocaleFromUrl, useTranslations, useTranslatedPaths } from '@i18n'; import Layout from 'src/layouts/Layout.astro'; diff --git a/src/pages/[...route].astro b/src/pages/[...route].astro index 3eb629a..58b3661 100644 --- a/src/pages/[...route].astro +++ b/src/pages/[...route].astro @@ -1,9 +1,12 @@ --- -import { defaultLocale, localeCodes, removeTrailingSlash, useTranslatedPaths } from '@i18n'; +// server route +export const prerender = false; + +import { DEFAULT_LOCALE, LOCALE_CODES, removeTrailingSlash, useTranslatedPaths } from '@i18n'; import { handleRedirect } from '../redirects'; const [_, langParam, ...restUrl] = Astro.url.pathname.split('/'); -const noLangPathname = localeCodes.includes(langParam) +const noLangPathname = LOCALE_CODES.includes(langParam) ? `/${restUrl.join('/')}` : Astro.url.pathname; @@ -15,7 +18,7 @@ if (redirectedUrl) { } // if there's no lang parameter, detect language and redirect -if (!langParam || !localeCodes.includes(langParam)) { +if (!langParam || !LOCALE_CODES.includes(langParam)) { const headerLang = Astro.request.headers.get('Accept-Language'); const pathnameWithParams = Astro.url.href.replace(Astro.url.origin, ''); const path = removeTrailingSlash(pathnameWithParams); @@ -27,7 +30,7 @@ if (!langParam || !localeCodes.includes(langParam)) { } // otherwise serve english - const translatePaths = useTranslatedPaths(defaultLocale); + const translatePaths = useTranslatedPaths(DEFAULT_LOCALE); return Astro.redirect(translatePaths(path)); } diff --git a/src/pages/[lang]/blog/[...slug].astro b/src/pages/[lang]/blog/[...slug].astro index 579105d..ef0fe2f 100644 --- a/src/pages/[lang]/blog/[...slug].astro +++ b/src/pages/[lang]/blog/[...slug].astro @@ -1,6 +1,19 @@ --- +// generate all possible slugs for both langs (if either is unavailable, fallback) +export async function getStaticPaths() { + const posts = await getCollection('blog'); + + const slugs = new Set(posts.map((post) => getPostSlug(post.id))); + + return Array.from(slugs).flatMap((slug) => { + return LOCALE_CODES.map((lang) => ({ + params: { lang, slug }, + })); + }); +} + import Callout from '@components/Callout.astro'; -import { getLocaleFromUrl, getPostLang, getPostSlug, useTranslations } from '@i18n'; +import { getLocaleFromUrl, getPostLang, getPostSlug, LOCALE_CODES, useTranslations } from '@i18n'; import { getCollection, render } from 'astro:content'; import Blog from '../../../layouts/Blog.astro'; diff --git a/src/pages/[lang]/blog/index.astro b/src/pages/[lang]/blog/index.astro index 2c6f1d1..44a8a68 100644 --- a/src/pages/[lang]/blog/index.astro +++ b/src/pages/[lang]/blog/index.astro @@ -1,9 +1,12 @@ --- +export const getStaticPaths = generateLangStaticPaths; + import Globe from '@assets/icons/globe.svg'; import RSS from '@assets/icons/rss.svg'; import MetaImageBlog from '@assets/meta-images/blog.webp'; import Button from '@components/Button.astro'; import { + generateLangStaticPaths, getLocaleFromUrl, getPostLang, getPostSlug, diff --git a/src/pages/[lang]/contact/index.astro b/src/pages/[lang]/contact/index.astro index 2ae278c..126ad81 100644 --- a/src/pages/[lang]/contact/index.astro +++ b/src/pages/[lang]/contact/index.astro @@ -1,4 +1,6 @@ --- +export const prerender = false; + import Bluesky from '@assets/icons/bluesky.svg'; import Codeberg from '@assets/icons/codeberg.svg'; import Email from '@assets/icons/email.svg'; diff --git a/src/pages/[lang]/index.astro b/src/pages/[lang]/index.astro index 67615c8..6b53069 100644 --- a/src/pages/[lang]/index.astro +++ b/src/pages/[lang]/index.astro @@ -1,4 +1,6 @@ --- +export const getStaticPaths = generateLangStaticPaths; + import Briefcase from '@assets/icons/briefcase.svg'; import MetaImageEn from '@assets/meta-images/index-en.webp'; import MetaImageFr from '@assets/meta-images/index-fr.webp'; @@ -12,7 +14,12 @@ import Uniten2 from '@assets/project-images/uniten-2.webp'; import Uniten3 from '@assets/project-images/uniten-3.webp'; import Button from '@components/Button.astro'; import ProjectCard from '@components/ProjectCard.astro'; -import { getLocaleFromUrl, useTranslatedPaths, useTranslations } from '@i18n'; +import { + generateLangStaticPaths, + getLocaleFromUrl, + useTranslatedPaths, + useTranslations, +} from '@i18n'; import Layout from '../../layouts/Layout.astro'; import Avatar from './_Avatar.astro'; import { atpClient } from '@atp/client'; diff --git a/src/pages/[lang]/journal/index.astro b/src/pages/[lang]/journal/index.astro deleted file mode 100644 index 9a58644..0000000 --- a/src/pages/[lang]/journal/index.astro +++ /dev/null @@ -1,194 +0,0 @@ ---- -import { getLocaleFromUrl, getPostSlug, useTranslations } from '@i18n'; -import { getCollection, render } from 'astro:content'; -import Journal from 'src/layouts/Journal.astro'; - -const lang = getLocaleFromUrl(Astro.url); -const t = useTranslations(lang); - -const posts = (await getCollection('journal')) - .filter((p) => p.id.endsWith(lang)) - .sort((a, b) => b.data.createdAt.getTime() - a.data.createdAt.getTime()) - .map((p) => ({ ...p, slug: getPostSlug(p.id) })); - -console.log(Astro.cookies.has('PASSWORD')); - -const accessPassword = import.meta.env.PASSWORD; -const hasAccess = Astro.cookies.get('PASSWORD')?.value === accessPassword; - -function grantAccess() { - Astro.cookies.set('PASSWORD', accessPassword, { - httpOnly: true, - sameSite: 'strict', - secure: true, - path: '/', - maxAge: 60 * 60 * 24 * 7, - }); - - return Astro.redirect('/journal', 303); -} - -// try using search params -const searchParamsPwd = Astro.url.searchParams.get('pwd'); - -if (searchParamsPwd && searchParamsPwd === accessPassword) { - return grantAccess(); -} - -// try using the provided password -if (Astro.request.method === 'POST') { - try { - const data = await Astro.request.formData(); - const userPwd = data.get('password'); - - if (userPwd === accessPassword) { - return grantAccess(); - } - } catch (e) { - console.error(e); - } -} - -const renderedPosts = Promise.all( - posts.map(async (post) => ({ - ...post, - rendered: await render(post), - })), -); ---- - - - { - hasAccess ? ( -
- {(await renderedPosts).map((e) => ( -
-

{e.data.title}

- - - -
- ))} -
- ) : ( -
-

{t('journal.title')}

- -

{t('journal.pwd.explaining')}

- -
- - - -
-
- ) - } -
- - diff --git a/src/pages/[lang]/login/callback.ts b/src/pages/[lang]/login/callback.ts index 9207afb..76d8277 100644 --- a/src/pages/[lang]/login/callback.ts +++ b/src/pages/[lang]/login/callback.ts @@ -1,6 +1,8 @@ import { authedAtp, oauthClient } from '@atp/client'; import type { APIRoute } from 'astro'; +export const prerender = false; + export const GET = (async (context) => { const { session } = await oauthClient.callback(context.url.searchParams); diff --git a/src/pages/[lang]/login/index.astro b/src/pages/[lang]/login/index.astro index 4c4aac8..b8ac0c4 100644 --- a/src/pages/[lang]/login/index.astro +++ b/src/pages/[lang]/login/index.astro @@ -1,4 +1,6 @@ --- +export const prerender = false; + import { authedAtp, oauthClient } from '@atp/client'; import bskyProfile from '@atp/lexicons/app/bsky/actor/profile.js'; import { getBlobCidString } from '@atproto/lex'; diff --git a/src/redirects.ts b/src/redirects.ts index cce504d..a43a706 100644 --- a/src/redirects.ts +++ b/src/redirects.ts @@ -81,7 +81,6 @@ const redirectList = [ { source: '/software', destination: '/blog#work' }, // { source: "/contact", destination: "/#contact" }, { source: '/stream', destination: '/disabled-redirect#twitch' }, - { source: /\/friends(?:\/(.*))?/, destination: '/journal/$1' }, // very old projects {