start to add spanish content again

This commit is contained in:
juancmandev 2024-07-30 22:37:03 -06:00
parent 56f20e167a
commit 16f07bf63b
19 changed files with 217 additions and 199 deletions

View File

@ -2,7 +2,11 @@ import { Code, RssIcon } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import formatDate from "@/utils/format-date"; import formatDate from "@/utils/format-date";
export default function Footer() { type Props = {
lang: "en" | "es";
};
export default function Footer(props: Props) {
return ( return (
<footer className="border-t border-secondary px-4 py-12 text-center text-sm md:px-16 prose prose-invert min-w-full"> <footer className="border-t border-secondary px-4 py-12 text-center text-sm md:px-16 prose prose-invert min-w-full">
<section> <section>

View File

@ -3,6 +3,27 @@ import logo from "@/assets/logo.png";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import LinkButton from "@/components/link-button"; import LinkButton from "@/components/link-button";
import { ChevronUp, Compass } from "lucide-react"; import { ChevronUp, Compass } from "lucide-react";
type Props = {
lang: "en" | "es";
};
const locales = {
en: {
to: "/es",
switch_language: "🇲🇽",
top: "Top",
navigation: "Navigation",
},
es: {
to: "/",
switch_language: "🇺🇸",
top: "Arriba",
navigation: "Navevación",
},
} as const;
const { lang } = Astro.props;
--- ---
<header <header
@ -28,14 +49,21 @@ import { ChevronUp, Compass } from "lucide-react";
/> />
</LinkButton> </LinkButton>
</section> </section>
<section class="flex items-center gap-4"> <section class="flex items-center gap-2">
<LinkButton variant="link" className="p-0 gap-1" href="#"> <LinkButton
<ChevronUp className="w-5" /> variant="link"
Top href={locales[lang].to}
className="p-0 gap-1 text-base"
>
{locales[lang].switch_language}
</LinkButton> </LinkButton>
<LinkButton variant="link" className="p-0 gap-1" href="#navigation"> <LinkButton variant="link" className="p-0 gap-0.5" href="#">
<ChevronUp className="w-5" />
{locales[lang].top}
</LinkButton>
<LinkButton variant="link" className="p-0 gap-0.5" href="#navigation">
<Compass className="w-5" /> <Compass className="w-5" />
Navigation {locales[lang].navigation}
</LinkButton> </LinkButton>
</section> </section>
</div> </div>

View File

@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button";
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
title?: string;
href: string; href: string;
variant?: variant?:
| "default" | "default"
@ -21,6 +22,7 @@ export default function LinkButton(props: Props) {
<Button <Button
asChild asChild
size={props.size} size={props.size}
title={props.title}
variant={props.variant} variant={props.variant}
className={props.className} className={props.className}
> >

View File

@ -10,7 +10,7 @@ const { src, alt } = Astro.props;
alt={alt} alt={alt}
width={1092} width={1092}
height={986} height={986}
class=".markdown-image w-auto h-auto rounded-md aspect-auto" class="w-auto h-auto rounded-md aspect-auto"
/> />
<script> <script>

View File

@ -1,42 +0,0 @@
import { useCallback, useEffect, useState } from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { CheckIcon, CopyIcon } from "lucide-react";
interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
value: string;
}
export default function CopyButton(props: CopyButtonProps) {
const [hasCopied, setHasCopied] = useState(false);
useEffect(() => {
setTimeout(() => {
setHasCopied(false);
}, 2000);
}, [hasCopied]);
const copyToClipboard = useCallback((value: string) => {
navigator.clipboard.writeText(value);
setHasCopied(true);
}, []);
return (
<Button
title={hasCopied ? "Copied!" : "Copy to clipboard"}
size={null}
variant="ghost"
className={cn("absolute right-2 top-1.5 p-2 ", props.className)}
onClick={() => copyToClipboard(props.value)}
{...props}
>
<span className="sr-only">Copy</span>
{hasCopied ? (
<CheckIcon className="h-4 w-4" />
) : (
<CopyIcon className="h-4 w-4" />
)}
</Button>
);
}

View File

@ -34,7 +34,7 @@ export const navItems: TNavItem[] = [
), ),
}, },
{ {
to: "/videos", to: "es/videos",
child: ( child: (
<> <>
<MonitorPlay /> <MonitorPlay />
@ -80,9 +80,13 @@ export const navItems: TNavItem[] = [
}, },
]; ];
export default function Navigation() { type Props = {
lang: "en" | "es";
};
export default function Navigation(props: Props) {
return ( return (
<nav className="px-4 sm:px-0 max-w-[65ch] mx-auto prose prose-invert py-20"> <nav className="px-4 sm:px-0 max-w-[65ch] mx-auto prose prose-invert pt-5 pb-20">
<h2 id="navigation">Navigation</h2> <h2 id="navigation">Navigation</h2>
<ul className="list-none p-0 flex flex-wrap gap-4"> <ul className="list-none p-0 flex flex-wrap gap-4">
{navItems.map((navItem, index) => ( {navItems.map((navItem, index) => (

View File

@ -5,7 +5,7 @@ type Props = {
slug: string; slug: string;
date: Date | string; date: Date | string;
title: string; title: string;
type: "blog" | "portfolio" | "videos"; type: "blog" | "portfolio" | "es/videos";
}; };
export default function PostItem(props: Props) { export default function PostItem(props: Props) {

View File

@ -7,14 +7,14 @@ import "@/styles/globals.css";
interface Props { interface Props {
title: string; title: string;
description: string; description: string;
lang?: string; lang: "en" | "es";
} }
const { title, description, lang } = Astro.props; const { title, description, lang } = Astro.props;
--- ---
<!doctype html> <!doctype html>
<html lang={lang || "en"}> <html lang={lang}>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="description" content={description} /> <meta name="description" content={description} />
@ -37,11 +37,11 @@ const { title, description, lang } = Astro.props;
<title>{title}</title> <title>{title}</title>
</head> </head>
<body> <body>
<Header /> <Header lang={lang} />
<main class="px-4 sm:px-0 max-w-[65ch] pt-28 pb-14 mx-auto"> <main class="px-4 sm:px-0 max-w-[65ch] pt-28 pb-5 mx-auto">
<slot /> <slot />
</main> </main>
<Navigation /> <Navigation lang={lang} />
<Footer /> <Footer lang={lang} />
</body> </body>
</html> </html>

View File

@ -3,7 +3,7 @@ import Layout from "@/layouts/Layout.astro";
import LinkButton from "@/components/link-button"; import LinkButton from "@/components/link-button";
--- ---
<Layout title="juancmandev" description="Error 404. Not found."> <Layout lang="en" title="juancmandev" description="Error 404. Not found.">
<div class="prose prose-invert"> <div class="prose prose-invert">
<h1 class="">Error 404: Not found</h1> <h1 class="">Error 404: Not found</h1>
<p>Do not worry, you can <strong>go back to home</strong>.</p> <p>Do not worry, you can <strong>go back to home</strong>.</p>

View File

@ -21,7 +21,7 @@ const { page } = Astro.props;
const { Content } = await page.render(); const { Content } = await page.render();
--- ---
<Layout title={page.data.title} description={page.data.description}> <Layout lang="en" title={page.data.title} description={page.data.description}>
<article class="prose prose-invert"> <article class="prose prose-invert">
<Content components={{ ...components }} /> <Content components={{ ...components }} />
</article> </article>

View File

@ -12,7 +12,7 @@ interface Props {
export async function getStaticPaths() { export async function getStaticPaths() {
const allBlogPosts = await getCollection( const allBlogPosts = await getCollection(
"blog", "blog",
({ data }) => data.draft !== true, ({ data }) => data.draft !== true
); );
return allBlogPosts.map((post) => ({ return allBlogPosts.map((post) => ({
@ -25,7 +25,7 @@ const { post } = Astro.props;
const { Content } = await post.render(); const { Content } = await post.render();
--- ---
<Layout title={post.data.title} description={post.data.description}> <Layout lang="en" title={post.data.title} description={post.data.description}>
<article class="prose prose-invert"> <article class="prose prose-invert">
<h1>{post.data.title}</h1> <h1>{post.data.title}</h1>
<Content components={{ ...components }} /> <Content components={{ ...components }} />

View File

@ -13,7 +13,7 @@ const allPosts = await getCollection("blog", ({ data }) => data.draft !== true);
sortContentByDate(allPosts); sortContentByDate(allPosts);
--- ---
<Layout {...pageData}> <Layout {...pageData} lang="en">
<section class="prose prose-invert"> <section class="prose prose-invert">
<h1>{pageData.title}</h1> <h1>{pageData.title}</h1>
<p>{pageData.description}</p> <p>{pageData.description}</p>

20
src/pages/es/index.astro Normal file
View File

@ -0,0 +1,20 @@
---
import Layout from "@/layouts/Layout.astro";
---
<Layout
lang="es"
title="juancmandev"
description="Bienvenido a mi dominio, extraño. Soy juancmandev; Desarrollador Web, entusiasta de Linux, y defensor de la privacidad."
>
<div class="prose prose-invert">
<h1 class="text-primary">Bienvenido a mi dominio, extraño.</h1>
<p>
Soy <strong class="text-primary">juancmandev</strong>; <strong
>Desarrollador Web</strong
>, entusiasta de <strong>Linux</strong> y defensor de la <strong
>privacidad.</strong
>
</p>
</div>
</Layout>

View File

@ -26,7 +26,7 @@ sortContentByDate(allVideos);
allVideos.map((video: any) => ( allVideos.map((video: any) => (
<li> <li>
<PostItem <PostItem
type="videos" type="es/videos"
slug={video.slug} slug={video.slug}
date={video.data.date!} date={video.data.date!}
title={video.data.title!} title={video.data.title!}

View File

@ -11,13 +11,14 @@ const last3Blogs = allPosts.slice(0, 3);
const allProjects = await getCollection( const allProjects = await getCollection(
"portfolio", "portfolio",
({ data }) => data.draft !== true, ({ data }) => data.draft !== true
); );
sortContentByDate(allProjects); sortContentByDate(allProjects);
const last3Projects = allProjects.slice(0, 3); const last3Projects = allProjects.slice(0, 3);
--- ---
<Layout <Layout
lang="en"
title="juancmandev" title="juancmandev"
description="Welcome to my domain, stranger. I am juancmandev; Web Developer, Linux enthusiast, and privacy defender." description="Welcome to my domain, stranger. I am juancmandev; Web Developer, Linux enthusiast, and privacy defender."
> >
@ -29,9 +30,9 @@ const last3Projects = allProjects.slice(0, 3);
>, <strong>Linux</strong> enthusiast, and <strong>privacy</strong> defender. >, <strong>Linux</strong> enthusiast, and <strong>privacy</strong> defender.
</p> </p>
<p> <p>
This is my <strong>website</strong>, a piece of the Internet that I This is my <strong>website</strong>, a piece of the Internet that I could
could call my <strong>home base</strong>. Here, I share my knowledge call my <strong>home base</strong>. Here, I share my passion about open
about my career and talk about other topics. source projects and other topics.
</p> </p>
<section> <section>
<h2>Latest posts</h2> <h2>Latest posts</h2>
@ -49,10 +50,8 @@ const last3Projects = allProjects.slice(0, 3);
)) ))
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/blog" className="no-underline"
variant="secondary" >More posts</LinkButton
href="/blog"
className="no-underline">More posts</LinkButton
> >
</section> </section>
<section> <section>
@ -71,10 +70,8 @@ const last3Projects = allProjects.slice(0, 3);
)) ))
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/portfolio" className="no-underline"
variant="secondary" >More projects</LinkButton
href="/portfolio"
className="no-underline">More projects</LinkButton
> >
</section> </section>
</div> </div>

View File

@ -11,6 +11,7 @@ const data = await pb.collection("microblogs").getFullList({
--- ---
<Layout <Layout
lang="en"
title="Microblog" title="Microblog"
description="Short-format writing. Instead of using shitty social media." description="Short-format writing. Instead of using shitty social media."
> >

View File

@ -12,7 +12,7 @@ interface Props {
export async function getStaticPaths() { export async function getStaticPaths() {
const allProjects = await getCollection( const allProjects = await getCollection(
"portfolio", "portfolio",
({ data }) => data.draft !== true, ({ data }) => data.draft !== true
); );
return allProjects.map((project) => ({ return allProjects.map((project) => ({
@ -25,7 +25,11 @@ const { project } = Astro.props;
const { Content } = await project.render(); const { Content } = await project.render();
--- ---
<Layout title={project.data.title} description={project.data.description}> <Layout
lang="en"
title={project.data.title}
description={project.data.description}
>
<article class="prose prose-invert"> <article class="prose prose-invert">
<h1>{project.data.title}</h1> <h1>{project.data.title}</h1>
<Content components={{ ...components }} /> <Content components={{ ...components }} />

View File

@ -16,7 +16,7 @@ const allProjects = await getCollection(
sortContentByDate(allProjects); sortContentByDate(allProjects);
--- ---
<Layout {...pageData}> <Layout {...pageData} lang="en">
<section class="prose prose-invert"> <section class="prose prose-invert">
<h1>{pageData.title}</h1> <h1>{pageData.title}</h1>
<p>{pageData.description}</p> <p>{pageData.description}</p>