Add portafolio page

This commit is contained in:
Alexander Navarro 2023-11-18 14:02:51 -03:00
parent 0c10c3fa77
commit 318a647147
8 changed files with 166 additions and 23 deletions

View file

@ -57,6 +57,16 @@ ul {
margin: 0;
}
.list-unstyle {
list-style: none;
}
img,
video {
max-width: 100%;
height: auto;
}
li:not(:last-child) {
margin-bottom: var(--prj-spacing-1);
}

View file

@ -1,11 +1,7 @@
---
export interface Props {
title: string;
body: string;
href: string;
title?: string;
}
const { href, title, body } = Astro.props;
---
<div class="card vstack">

View file

@ -0,0 +1,44 @@
import React from 'react';
import { MediaType, type Media } from './types';
interface Props {
items: Media[];
}
// TODO: transform this component in a lightbox
export default function Gallery({ items }: Props): JSX.Element {
const renderItem = (item: Media): JSX.Element => {
// get the file id from the "share" link of google drive
const googleFileId = item.url.split('/').at(5);
let url;
switch (item.type) {
case MediaType.Image:
url =
googleFileId !== undefined
? `https://drive.google.com/uc?export=preview&id=${googleFileId}`
: item.url;
return <img src={url} alt={item.alt} />;
case MediaType.Video:
url =
googleFileId !== undefined
? `https://drive.google.com/file/d/${googleFileId}/preview`
: item.url;
return (
<iframe src={url} width="600" height="500" allow="autoplay"></iframe>
);
default:
break;
}
return <></>;
};
return (
<ul className="list-unstyle">
{items.map((item, idx) => (
<li key={idx}>{renderItem(item)}</li>
))}
</ul>
);
}

View file

@ -0,0 +1,11 @@
export enum MediaType {
Image = 'image',
Video = 'video',
}
export interface Media {
type: MediaType;
url: string;
alt: string;
mime?: string;
}

@ -1 +1 @@
Subproject commit 6b406948b70fa4c56333c0afc628e9b6618aacdc
Subproject commit e52081e1e2d2acaf810e9902a009aaa372313ae6

View file

@ -5,7 +5,15 @@ import Card from '../components/Card.astro';
import { Image } from 'astro:assets';
import portrait from '../assets/images/portrait.jpg';
const games = await getCollection('games', (_, idx) => idx < 3);
const games = await getCollection('games');
const blog = await getCollection('blog', ({ data }) =>
import.meta.env.PROD ? data.draft !== true : true,
);
// TODO: show the pinned ones, not the recents
const portafolio = await getCollection('portafolio', ({ data }) =>
import.meta.env.PROD ? data.draft !== true : true,
);
---
<Layout title="aleidk">
@ -34,29 +42,29 @@ const games = await getCollection('games', (_, idx) => idx < 3);
<Card>
<h3 slot="title">Portafolio</h3>
<ul>
<li><a href="">This is a project X</a></li>
<li><a href="">This is a project Y</a></li>
<li><a href="">This is a project Z</a></li>
{
portafolio.slice(0, 3).map((item) => (
<li>
<a href={`portafolio/${item.slug}`}>{item.data.title}</a>
</li>
))
}
</ul>
<div slot="footer" class="text-end">
<a href="">See more...</a>
<a href="/portafolio">See more...</a>
</div>
</Card>
<Card>
<h3 slot="title">Blog</h3>
<ul>
<li><a href="">How I do X thing because I wanted</a></li>
<li>
<a href=""
>The day I discover something marvelous and everything was better</a
>
</li>
<li>
<a href=""
>This is a clickbait title trying to make you enter this article</a
>
</li>
{
blog.slice(0, 3).map((item) => (
<li>
<a href={`blog/${item.slug}`}>{item.data.title}</a>
</li>
))
}
</ul>
<div slot="footer" class="text-end">
<a href="/blog">See more...</a>
@ -67,7 +75,7 @@ const games = await getCollection('games', (_, idx) => idx < 3);
<h3 slot="title">Games</h3>
<ul>
{
games.map((item) => (
games.slice(0, 3).map((item) => (
<li>
<a href={`games/${item.slug}`}>{item.data.title}</a>
</li>

View file

@ -0,0 +1,31 @@
---
import type { InferGetStaticPropsType, GetStaticPaths } from 'astro';
import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro';
import Toc from '@components/Toc/Toc';
import Gallery from '@components/MediaGallery/Gallery';
export const getStaticPaths = (async () => {
const entries = await getCollection('portafolio');
return entries.map((entry) => ({
params: { slug: entry.slug },
props: entry,
}));
}) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props;
const { Content, headings } = await entry.render();
---
<Layout title={entry.data.title}>
<h1>{entry.data.title}</h1>
<Gallery items={entry.data.media} />
<Toc headings={headings} />
<Content />
</Layout>

View file

@ -0,0 +1,43 @@
---
import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro';
import Table from '@components/Table';
import { HeaderType, type Header } from '@components/Table/types';
const rawEntries = await getCollection('portafolio', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
const entries = rawEntries.map((item, idx) => ({
...item.data,
id: idx + 1,
slug: item.slug,
}));
const headers: Header[] = [
{
key: 'id',
header: 'index',
type: HeaderType.Index,
},
{
key: 'title',
header: 'Title',
formatter: (data) => `<a href="portafolio/${data.slug}">${data.title}</a>`,
type: HeaderType.String,
},
{
key: 'technologies',
header: 'Technologies',
type: HeaderType.Multiple,
},
];
---
<Layout title="List of blog entries">
<h1>Blog's entries</h1>
<section>
<Table client:load data={entries} headers={headers} />
</section>
</Layout>