start to add spanish content again
This commit is contained in:
parent
56f20e167a
commit
16f07bf63b
@ -2,7 +2,11 @@ import { Code, RssIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import formatDate from "@/utils/format-date";
|
||||
|
||||
export default function Footer() {
|
||||
type Props = {
|
||||
lang: "en" | "es";
|
||||
};
|
||||
|
||||
export default function Footer(props: Props) {
|
||||
return (
|
||||
<footer className="border-t border-secondary px-4 py-12 text-center text-sm md:px-16 prose prose-invert min-w-full">
|
||||
<section>
|
||||
|
@ -3,6 +3,27 @@ import logo from "@/assets/logo.png";
|
||||
import { Image } from "astro:assets";
|
||||
import LinkButton from "@/components/link-button";
|
||||
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
|
||||
@ -28,14 +49,21 @@ import { ChevronUp, Compass } from "lucide-react";
|
||||
/>
|
||||
</LinkButton>
|
||||
</section>
|
||||
<section class="flex items-center gap-4">
|
||||
<LinkButton variant="link" className="p-0 gap-1" href="#">
|
||||
<ChevronUp className="w-5" />
|
||||
Top
|
||||
<section class="flex items-center gap-2">
|
||||
<LinkButton
|
||||
variant="link"
|
||||
href={locales[lang].to}
|
||||
className="p-0 gap-1 text-base"
|
||||
>
|
||||
{locales[lang].switch_language}
|
||||
</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" />
|
||||
Navigation
|
||||
{locales[lang].navigation}
|
||||
</LinkButton>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
title?: string;
|
||||
href: string;
|
||||
variant?:
|
||||
| "default"
|
||||
@ -21,6 +22,7 @@ export default function LinkButton(props: Props) {
|
||||
<Button
|
||||
asChild
|
||||
size={props.size}
|
||||
title={props.title}
|
||||
variant={props.variant}
|
||||
className={props.className}
|
||||
>
|
||||
|
@ -10,7 +10,7 @@ const { src, alt } = Astro.props;
|
||||
alt={alt}
|
||||
width={1092}
|
||||
height={986}
|
||||
class=".markdown-image w-auto h-auto rounded-md aspect-auto"
|
||||
class="w-auto h-auto rounded-md aspect-auto"
|
||||
/>
|
||||
|
||||
<script>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -34,7 +34,7 @@ export const navItems: TNavItem[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
to: "/videos",
|
||||
to: "es/videos",
|
||||
child: (
|
||||
<>
|
||||
<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 (
|
||||
<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>
|
||||
<ul className="list-none p-0 flex flex-wrap gap-4">
|
||||
{navItems.map((navItem, index) => (
|
@ -5,7 +5,7 @@ type Props = {
|
||||
slug: string;
|
||||
date: Date | string;
|
||||
title: string;
|
||||
type: "blog" | "portfolio" | "videos";
|
||||
type: "blog" | "portfolio" | "es/videos";
|
||||
};
|
||||
|
||||
export default function PostItem(props: Props) {
|
||||
|
@ -7,14 +7,14 @@ import "@/styles/globals.css";
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
lang?: string;
|
||||
lang: "en" | "es";
|
||||
}
|
||||
|
||||
const { title, description, lang } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang={lang || "en"}>
|
||||
<html lang={lang}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content={description} />
|
||||
@ -37,11 +37,11 @@ const { title, description, lang } = Astro.props;
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<Header />
|
||||
<main class="px-4 sm:px-0 max-w-[65ch] pt-28 pb-14 mx-auto">
|
||||
<Header lang={lang} />
|
||||
<main class="px-4 sm:px-0 max-w-[65ch] pt-28 pb-5 mx-auto">
|
||||
<slot />
|
||||
</main>
|
||||
<Navigation />
|
||||
<Footer />
|
||||
<Navigation lang={lang} />
|
||||
<Footer lang={lang} />
|
||||
</body>
|
||||
</html>
|
||||
|
@ -3,7 +3,7 @@ import Layout from "@/layouts/Layout.astro";
|
||||
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">
|
||||
<h1 class="">Error 404: Not found</h1>
|
||||
<p>Do not worry, you can <strong>go back to home</strong>.</p>
|
||||
|
@ -21,7 +21,7 @@ const { page } = Astro.props;
|
||||
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">
|
||||
<Content components={{ ...components }} />
|
||||
</article>
|
||||
|
@ -12,7 +12,7 @@ interface Props {
|
||||
export async function getStaticPaths() {
|
||||
const allBlogPosts = await getCollection(
|
||||
"blog",
|
||||
({ data }) => data.draft !== true,
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
|
||||
return allBlogPosts.map((post) => ({
|
||||
@ -25,7 +25,7 @@ const { post } = Astro.props;
|
||||
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">
|
||||
<h1>{post.data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
|
@ -13,7 +13,7 @@ const allPosts = await getCollection("blog", ({ data }) => data.draft !== true);
|
||||
sortContentByDate(allPosts);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<Layout {...pageData} lang="en">
|
||||
<section class="prose prose-invert">
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
|
20
src/pages/es/index.astro
Normal file
20
src/pages/es/index.astro
Normal 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>
|
@ -26,7 +26,7 @@ sortContentByDate(allVideos);
|
||||
allVideos.map((video: any) => (
|
||||
<li>
|
||||
<PostItem
|
||||
type="videos"
|
||||
type="es/videos"
|
||||
slug={video.slug}
|
||||
date={video.data.date!}
|
||||
title={video.data.title!}
|
@ -11,13 +11,14 @@ const last3Blogs = allPosts.slice(0, 3);
|
||||
|
||||
const allProjects = await getCollection(
|
||||
"portfolio",
|
||||
({ data }) => data.draft !== true,
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
sortContentByDate(allProjects);
|
||||
const last3Projects = allProjects.slice(0, 3);
|
||||
---
|
||||
|
||||
<Layout
|
||||
lang="en"
|
||||
title="juancmandev"
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
This is my <strong>website</strong>, a piece of the Internet that I
|
||||
could call my <strong>home base</strong>. Here, I share my knowledge
|
||||
about my career and talk about other topics.
|
||||
This is my <strong>website</strong>, a piece of the Internet that I could
|
||||
call my <strong>home base</strong>. Here, I share my passion about open
|
||||
source projects and other topics.
|
||||
</p>
|
||||
<section>
|
||||
<h2>Latest posts</h2>
|
||||
@ -49,10 +50,8 @@ const last3Projects = allProjects.slice(0, 3);
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<LinkButton
|
||||
variant="secondary"
|
||||
href="/blog"
|
||||
className="no-underline">More posts</LinkButton
|
||||
<LinkButton variant="secondary" href="/blog" className="no-underline"
|
||||
>More posts</LinkButton
|
||||
>
|
||||
</section>
|
||||
<section>
|
||||
@ -71,10 +70,8 @@ const last3Projects = allProjects.slice(0, 3);
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<LinkButton
|
||||
variant="secondary"
|
||||
href="/portfolio"
|
||||
className="no-underline">More projects</LinkButton
|
||||
<LinkButton variant="secondary" href="/portfolio" className="no-underline"
|
||||
>More projects</LinkButton
|
||||
>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ const data = await pb.collection("microblogs").getFullList({
|
||||
---
|
||||
|
||||
<Layout
|
||||
lang="en"
|
||||
title="Microblog"
|
||||
description="Short-format writing. Instead of using shitty social media."
|
||||
>
|
||||
|
@ -12,7 +12,7 @@ interface Props {
|
||||
export async function getStaticPaths() {
|
||||
const allProjects = await getCollection(
|
||||
"portfolio",
|
||||
({ data }) => data.draft !== true,
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
|
||||
return allProjects.map((project) => ({
|
||||
@ -25,7 +25,11 @@ const { project } = Astro.props;
|
||||
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">
|
||||
<h1>{project.data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
|
@ -16,7 +16,7 @@ const allProjects = await getCollection(
|
||||
sortContentByDate(allProjects);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<Layout {...pageData} lang="en">
|
||||
<section class="prose prose-invert">
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
|
Loading…
x
Reference in New Issue
Block a user