Rework layout and refactors (#4)
Reviewed-on: https://git.juancman.dev/juancmandev/website/pulls/4 Co-authored-by: juancmandev <juancmandev@protonmail.com> Co-committed-by: juancmandev <juancmandev@protonmail.com>
This commit is contained in:

committed by
Juan Manzanero

parent
9b4a54f702
commit
b4447f0e38
@@ -6,7 +6,7 @@ import Layout from '@/layouts/Layout.astro';
|
||||
title='Not found'
|
||||
description='Error 404: Not found.'
|
||||
>
|
||||
<div class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1 class=''>Error 404: Not found</h1>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@@ -32,7 +32,7 @@ const { Content, remarkPluginFrontmatter: data } = await render(project);
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<article class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<Content components={{ ...components }} />
|
||||
</article>
|
||||
</Layout>
|
||||
|
@@ -36,7 +36,7 @@ const { Content, remarkPluginFrontmatter: data } = await render(post);
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<article class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
<hr />
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import PostItem from '@/components/post-item';
|
||||
import PostItemList from '@/components/post-items-list';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
@@ -27,26 +27,12 @@ const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<section class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
</section>
|
||||
<ul class='mt-4 flex flex-col gap-4'>
|
||||
{
|
||||
filterEnPosts.map(
|
||||
(blogpost) =>
|
||||
blogpost && (
|
||||
<li>
|
||||
<PostItem
|
||||
type='blog'
|
||||
lang={lang}
|
||||
id={blogpost.id}
|
||||
date={blogpost.data.date!}
|
||||
title={blogpost.data.title!}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<PostItemList
|
||||
items={filterEnPosts}
|
||||
lang={lang}
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@@ -32,7 +32,7 @@ const { Content, remarkPluginFrontmatter: data } = await render(page);
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<article class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<Content components={{ ...components }} />
|
||||
</article>
|
||||
</Layout>
|
||||
|
@@ -36,7 +36,7 @@ const { Content, remarkPluginFrontmatter: data } = await render(blog);
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<article class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
<hr />
|
||||
|
@@ -27,7 +27,7 @@ const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<section class='prose prose-invert'>
|
||||
<section class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
</section>
|
||||
|
@@ -12,9 +12,6 @@ const markdownParser = new MarkdownIt();
|
||||
const imagesBlog = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/assets/blog/**/**/*.{jpeg,jpg,png,gif,webp}'
|
||||
);
|
||||
const imagesPortfolio = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/assets/portfolio/**/**/*.{jpeg,jpg,png,gif,webp}'
|
||||
);
|
||||
|
||||
export async function GET(context: any) {
|
||||
const items: RSSFeedItem[] = [];
|
||||
@@ -29,16 +26,6 @@ export async function GET(context: any) {
|
||||
return lang === 'es' && post;
|
||||
});
|
||||
|
||||
const portfolio = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true && data.rss === true
|
||||
);
|
||||
const filterPortfolio = portfolio.filter((project) => {
|
||||
const [lang] = project.id.split('/');
|
||||
|
||||
return lang === 'es' && project;
|
||||
});
|
||||
|
||||
for await (const post of filterBlog) {
|
||||
const body = markdownParser.render(post.body!);
|
||||
const html = htmlParser.parse(body);
|
||||
@@ -79,47 +66,6 @@ export async function GET(context: any) {
|
||||
});
|
||||
}
|
||||
|
||||
for await (const project of filterPortfolio) {
|
||||
const body = markdownParser.render(project.body!);
|
||||
const html = htmlParser.parse(body);
|
||||
const images = html.querySelectorAll('img');
|
||||
|
||||
for await (const img of images) {
|
||||
const src = img.getAttribute('src')!;
|
||||
|
||||
if (src.startsWith('@/')) {
|
||||
const prefixRemoved = src.replace('@/', '');
|
||||
const imagePathPrefix = `/src/${prefixRemoved}`;
|
||||
const imagePath = await imagesPortfolio[imagePathPrefix]?.()?.then(
|
||||
(res: any) => res.default
|
||||
);
|
||||
|
||||
if (imagePath) {
|
||||
const optimizedImg = await getImage({ src: imagePath });
|
||||
img.setAttribute(
|
||||
'src',
|
||||
context.site + optimizedImg.src.replace('/', '')
|
||||
);
|
||||
}
|
||||
} else if (src.startsWith('/images')) {
|
||||
// images starting with `/images/` is the public dir
|
||||
img.setAttribute('src', context.site + src.replace('/', ''));
|
||||
} else {
|
||||
throw Error('src unknown');
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
title: project.data.title,
|
||||
pubDate: project.data.date,
|
||||
description: project.data.description,
|
||||
link: `/portfolio/${project.id.split('.')[0]}/`,
|
||||
content: sanitizeHtml(html.toString(), {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return rss({
|
||||
xmlns: { atom: 'http://www.w3.org/2005/Atom' },
|
||||
title: 'juancmandev',
|
||||
|
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import LinkButton from '@/components/link-button';
|
||||
import PostItem from '@/components/post-item';
|
||||
import PostItemList from '@/components/post-items-list';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
@@ -26,28 +26,11 @@ const allEsPosts = allPosts.map((post) => {
|
||||
sortContentByDate(allEsPosts);
|
||||
const last3Blogs = allEsPosts.slice(0, 3);
|
||||
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const allEnProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang !== 'en')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
sortContentByDate(allEnProjects);
|
||||
const last3Projects = allEnProjects.slice(0, 3);
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<div class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1 class='text-primary'>Bienvenido a mi dominio, extraño.</h1>
|
||||
<p>
|
||||
Soy <strong class='text-primary'>juancmandev</strong>; <strong
|
||||
@@ -63,24 +46,10 @@ const lang = getLangFromUrl(Astro.url);
|
||||
</p>
|
||||
<section>
|
||||
<h2>Últimos posts</h2>
|
||||
<ul class='mt-0 p-0 list-none'>
|
||||
{
|
||||
last3Blogs.map(
|
||||
(blogpost) =>
|
||||
blogpost && (
|
||||
<li class='p-0'>
|
||||
<PostItem
|
||||
type='blog'
|
||||
lang={lang}
|
||||
id={blogpost.id}
|
||||
date={blogpost.data.date}
|
||||
title={blogpost.data.title}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<PostItemList
|
||||
items={last3Blogs}
|
||||
lang={lang}
|
||||
/>
|
||||
<LinkButton
|
||||
variant='secondary'
|
||||
href='/es/blog'
|
||||
@@ -88,32 +57,5 @@ const lang = getLangFromUrl(Astro.url);
|
||||
>Más posts</LinkButton
|
||||
>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Últimos proyectos</h2>
|
||||
<ul class='mt-0 p-0 list-none'>
|
||||
{
|
||||
last3Projects.map(
|
||||
(project) =>
|
||||
project && (
|
||||
<li class='p-0'>
|
||||
<PostItem
|
||||
lang={lang}
|
||||
type='portfolio'
|
||||
id={project.id}
|
||||
date={project.data.date!}
|
||||
title={project.data.title!}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<LinkButton
|
||||
variant='secondary'
|
||||
href='/es/portfolio'
|
||||
className='no-underline'
|
||||
>Más proyectos</LinkButton
|
||||
>
|
||||
</section>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@@ -1,48 +0,0 @@
|
||||
---
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import components from '@/components/mdx/wrapper';
|
||||
import formatDate from '@/utils/format-date';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import { getCollection, getEntry, render } from 'astro:content';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const filterEnProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang === 'es')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
|
||||
return filterEnProjects.map((project) => ({
|
||||
params: { slug: project?.id },
|
||||
}));
|
||||
}
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const { slug } = Astro.params;
|
||||
const project = await getEntry('portfolio', `${lang}/${slug}`)!;
|
||||
const { Content, remarkPluginFrontmatter: data } = await render(project);
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<h1>{data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
<hr />
|
||||
<p>
|
||||
<strong>Publicado: </strong>
|
||||
{data.date && formatDate(new Date(data.date), lang)}
|
||||
</p>
|
||||
</article>
|
||||
</Layout>
|
@@ -1,55 +0,0 @@
|
||||
---
|
||||
import PostItem from '@/components/post-item';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
const pageData = {
|
||||
title: 'Portfolio',
|
||||
description: 'Revisa mis proyectos.',
|
||||
};
|
||||
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const allEsProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang === 'es')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
sortContentByDate(allEsProjects);
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<section class='prose prose-invert'>
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
</section>
|
||||
<ul class='mt-4 flex flex-col gap-4'>
|
||||
{
|
||||
allEsProjects.map(
|
||||
(project) =>
|
||||
project && (
|
||||
<li>
|
||||
<PostItem
|
||||
lang={lang}
|
||||
type='portfolio'
|
||||
id={project.id}
|
||||
date={project.data.date!}
|
||||
title={project.data.title!}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</Layout>
|
@@ -34,7 +34,7 @@ const { Content, remarkPluginFrontmatter: data } = await render(video);
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<article class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
<hr />
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import PostItem from '@/components/post-item';
|
||||
import PostItemList from '@/components/post-items-list';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
@@ -20,23 +20,12 @@ const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<section class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
</section>
|
||||
<ul class='mt-4 flex flex-col gap-4'>
|
||||
{
|
||||
allVideos.map((video: any) => (
|
||||
<li>
|
||||
<PostItem
|
||||
lang={lang}
|
||||
type='videos'
|
||||
id={video.id.split('.')[0]}
|
||||
date={video.data.date!}
|
||||
title={video.data.title!}
|
||||
/>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<PostItemList
|
||||
items={allVideos}
|
||||
lang={lang}
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@@ -12,9 +12,6 @@ const markdownParser = new MarkdownIt();
|
||||
const imagesBlog = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/assets/blog/**/**/*.{jpeg,jpg,png,gif,webp}'
|
||||
);
|
||||
const imagesPortfolio = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/assets/portfolio/**/**/*.{jpeg,jpg,png,gif,webp}'
|
||||
);
|
||||
|
||||
export async function GET(context: any) {
|
||||
const items: RSSFeedItem[] = [];
|
||||
@@ -29,16 +26,6 @@ export async function GET(context: any) {
|
||||
return lang !== 'es' && post;
|
||||
});
|
||||
|
||||
const portfolio = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true && data.rss === true
|
||||
);
|
||||
const filterPortfolio = portfolio.filter((project) => {
|
||||
const [lang] = project.id.split('/');
|
||||
|
||||
return lang !== 'es' && project;
|
||||
});
|
||||
|
||||
for await (const post of filterBlog) {
|
||||
const body = markdownParser.render(post.body!);
|
||||
const html = htmlParser.parse(body);
|
||||
@@ -79,47 +66,6 @@ export async function GET(context: any) {
|
||||
});
|
||||
}
|
||||
|
||||
for await (const project of filterPortfolio) {
|
||||
const body = markdownParser.render(project.body!);
|
||||
const html = htmlParser.parse(body);
|
||||
const images = html.querySelectorAll('img');
|
||||
|
||||
for await (const img of images) {
|
||||
const src = img.getAttribute('src')!;
|
||||
|
||||
if (src.startsWith('@/')) {
|
||||
const prefixRemoved = src.replace('@/', '');
|
||||
const imagePathPrefix = `/src/${prefixRemoved}`;
|
||||
const imagePath = await imagesPortfolio[imagePathPrefix]?.()?.then(
|
||||
(res: any) => res.default
|
||||
);
|
||||
|
||||
if (imagePath) {
|
||||
const optimizedImg = await getImage({ src: imagePath });
|
||||
img.setAttribute(
|
||||
'src',
|
||||
context.site + optimizedImg.src.replace('/', '')
|
||||
);
|
||||
}
|
||||
} else if (src.startsWith('/images')) {
|
||||
// images starting with `/images/` is the public dir
|
||||
img.setAttribute('src', context.site + src.replace('/', ''));
|
||||
} else {
|
||||
throw Error('src unknown');
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
title: project.data.title,
|
||||
pubDate: project.data.date,
|
||||
description: project.data.description,
|
||||
link: `/portfolio/${project.id.split('.')[0]}/`,
|
||||
content: sanitizeHtml(html.toString(), {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return rss({
|
||||
xmlns: { atom: 'http://www.w3.org/2005/Atom' },
|
||||
title: 'juancmandev',
|
||||
|
@@ -2,9 +2,10 @@
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import LinkButton from '@/components/link-button';
|
||||
import { getCollection } from 'astro:content';
|
||||
import PostItem from '@/components/post-item';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import PostItemList from '@/components/post-items-list';
|
||||
import Random from '@/components/random.astro';
|
||||
|
||||
const pageData = {
|
||||
title: 'juancmandev',
|
||||
@@ -26,31 +27,15 @@ const allEnPosts = allPosts.map((post) => {
|
||||
sortContentByDate(allEnPosts);
|
||||
const last3Blogs = allEnPosts.slice(0, 3);
|
||||
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const allEnProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang !== 'es')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
sortContentByDate(allEnProjects);
|
||||
const last3Projects = allEnProjects.slice(0, 3);
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<div class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1 class='text-primary'>Welcome to my domain, stranger.</h1>
|
||||
<!-- <Random /> -->
|
||||
<p>
|
||||
I am <strong class='text-primary'>juancmandev</strong>; <strong
|
||||
I am <strong class='text-primary'>Juan Manzanero</strong>; <strong
|
||||
>Web Developer</strong
|
||||
>, <strong>Linux</strong> enthusiast, and <strong>privacy</strong> defender.
|
||||
</p>
|
||||
@@ -61,21 +46,10 @@ const lang = getLangFromUrl(Astro.url);
|
||||
</p>
|
||||
<section>
|
||||
<h2>Latest posts</h2>
|
||||
<ul class='mt-0 p-0 list-none'>
|
||||
{
|
||||
last3Blogs.map((blogpost: any) => (
|
||||
<li class='p-0'>
|
||||
<PostItem
|
||||
type='blog'
|
||||
lang={lang}
|
||||
id={blogpost.id}
|
||||
date={blogpost.data.date!}
|
||||
title={blogpost.data.title!}
|
||||
/>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<PostItemList
|
||||
items={last3Blogs}
|
||||
lang={lang}
|
||||
/>
|
||||
<LinkButton
|
||||
variant='secondary'
|
||||
href='/blog'
|
||||
@@ -83,32 +57,5 @@ const lang = getLangFromUrl(Astro.url);
|
||||
>More posts</LinkButton
|
||||
>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Latest projects</h2>
|
||||
<ul class='mt-0 p-0 list-none'>
|
||||
{
|
||||
last3Projects.map(
|
||||
(project) =>
|
||||
project && (
|
||||
<li class='p-0'>
|
||||
<PostItem
|
||||
lang={lang}
|
||||
type='portfolio'
|
||||
id={project.id}
|
||||
date={project.data.date!}
|
||||
title={project.data.title!}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<LinkButton
|
||||
variant='secondary'
|
||||
href='/portfolio'
|
||||
className='no-underline'
|
||||
>More projects</LinkButton
|
||||
>
|
||||
</section>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@@ -14,7 +14,7 @@ const data = await pb.collection('microblogs').getFullList({
|
||||
title='Microblog'
|
||||
description='Short-format writing. Instead of using shitty social media.'
|
||||
>
|
||||
<div class='prose prose-invert'>
|
||||
<div class='prose prose-invert max-w-[800px] mx-auto'>
|
||||
<h1>Microblog</h1>
|
||||
<p>Short-format writing.</p>
|
||||
<p>Instead of using shitty social media.</p>
|
||||
|
@@ -1,48 +0,0 @@
|
||||
---
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import components from '@/components/mdx/wrapper';
|
||||
import formatDate from '@/utils/format-date';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import { getCollection, getEntry, render } from 'astro:content';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const filterEnProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang === 'en')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
|
||||
return filterEnProjects.map((project) => ({
|
||||
params: { slug: project?.id },
|
||||
}));
|
||||
}
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const { slug } = Astro.params;
|
||||
const project = await getEntry('portfolio', `${lang}/${slug}`)!;
|
||||
const { Content, remarkPluginFrontmatter: data } = await render(project);
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
>
|
||||
<article class='prose prose-invert'>
|
||||
<h1>{data.title}</h1>
|
||||
<Content components={{ ...components }} />
|
||||
<hr />
|
||||
<p>
|
||||
<strong>Posted: </strong>
|
||||
{data.date && formatDate(new Date(data.date), lang)}
|
||||
</p>
|
||||
</article>
|
||||
</Layout>
|
@@ -1,55 +0,0 @@
|
||||
---
|
||||
import PostItem from '@/components/post-item';
|
||||
import { getLangFromUrl } from '@/i18n/utils';
|
||||
import Layout from '@/layouts/Layout.astro';
|
||||
import { sortContentByDate } from '@/utils/sorts';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
const pageData = {
|
||||
title: 'Portfolio',
|
||||
description: 'Check my projects.',
|
||||
};
|
||||
|
||||
const allProjects = await getCollection(
|
||||
'portfolio',
|
||||
({ data }) => data.draft !== true
|
||||
);
|
||||
const allEnProjects = allProjects.map((project) => {
|
||||
const [lang, id] = project.id.split('/');
|
||||
|
||||
if (lang === 'en')
|
||||
return {
|
||||
...project,
|
||||
id: id.split('.')[0],
|
||||
};
|
||||
else null;
|
||||
});
|
||||
sortContentByDate(allEnProjects);
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
---
|
||||
|
||||
<Layout {...pageData}>
|
||||
<section class='prose prose-invert'>
|
||||
<h1>{pageData.title}</h1>
|
||||
<p>{pageData.description}</p>
|
||||
</section>
|
||||
<ul class='mt-4 flex flex-col gap-4'>
|
||||
{
|
||||
allEnProjects.map(
|
||||
(project) =>
|
||||
project && (
|
||||
<li>
|
||||
<PostItem
|
||||
lang={lang}
|
||||
type='portfolio'
|
||||
id={project.id}
|
||||
date={project.data.date!}
|
||||
title={project.data.title!}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</Layout>
|
@@ -4,7 +4,7 @@ const robotsTxt = `
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: ${new URL('sitemap-index.xml', import.meta.env.SITE).href}
|
||||
Sitemap: ${new URL('sitemap-index.xml', 'https://juancman.dev').href}
|
||||
`.trim();
|
||||
|
||||
export const GET: APIRoute = () => {
|
||||
|
Reference in New Issue
Block a user