feat(Projects): Update project entry design

Also update project card in index and project list.
Also added portrait image.
This commit is contained in:
Alexander Navarro 2024-03-21 17:57:55 -03:00
parent 944b553e73
commit a85f9adc9b
18 changed files with 227 additions and 173 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before After
Before After

View file

@ -85,6 +85,7 @@
.vstack { .vstack {
--prj-gap: var(--prj-spacing-3); --prj-gap: var(--prj-spacing-3);
display: flex; display: flex;
gap: var(--prj-gap);
flex-direction: column; flex-direction: column;
} }
@ -133,6 +134,10 @@
justify-content: space-around !important; justify-content: space-around !important;
} }
.align-items-center {
align-items: center !important;
}
.grid { .grid {
--prj-gap: var(--prj-spacing-3); --prj-gap: var(--prj-spacing-3);
--prj-columns: repeat(3, 1fr); --prj-columns: repeat(3, 1fr);

View file

@ -35,7 +35,7 @@ h1,
.fs-1 { .fs-1 {
font-size: 3rem !important; font-size: 3rem !important;
margin-top: 0; margin-top: 0;
margin-bottom: var(--prj-spacing-4); margin-bottom: var(--prj-spacing-3);
} }
h2, h2,
.fs-2 { .fs-2 {
@ -97,6 +97,10 @@ ul {
/* Make the marker position is inside the container */ /* Make the marker position is inside the container */
list-style-position: inside; list-style-position: inside;
margin: 0; margin: 0;
ul {
margin-left: var(--prj-spacing-3);
}
} }
.list-unstyle { .list-unstyle {

View file

@ -3,29 +3,6 @@ import { z, defineCollection } from 'astro:content';
// AstroJS collection configuration // AstroJS collection configuration
const games = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
has_content: z.boolean().optional(),
date_added: z.coerce.date(),
release: z.coerce.date(),
developers: z.array(z.string()),
genres: z.array(z.string()),
status: z.enum([
'Backlog',
'On Line',
'Playing',
'Played',
'Wishlist',
'Want to Replay',
'Always Playable',
'Tried',
]),
times_played: z.number(),
}),
});
const blog = defineCollection({ const blog = defineCollection({
type: 'content', type: 'content',
schema: z.object({ schema: z.object({
@ -39,30 +16,30 @@ const blog = defineCollection({
const portafolio = defineCollection({ const portafolio = defineCollection({
type: 'content', type: 'content',
schema: z.object({ schema: ({ image }) =>
title: z.string(), z.object({
draft: z.boolean().optional(), title: z.string(),
status: z.enum(['Backlog', 'Activo', 'Fixes', 'Finalizado']), draft: z.boolean().optional(),
tags: z.array(z.string()).optional(), brief: z.string(),
technologies: z.array(z.string()), status: z.enum(['Backlog', 'Activo', 'Fixes', 'Finalizado']),
published_at: z.coerce.date().optional(), tags: z.array(z.string()).optional(),
updated_at: z.coerce.date().optional(), technologies: z.array(z.string()),
media: z created_at: z.coerce.date().optional(),
.array( updated_at: z.coerce.date().optional(),
z.object({ thumbnail: image().refine((img) => img.width >= 1080, {
type: z.nativeEnum(MediaType), message: 'Cover image must be at least 1080 pixels wide!',
url: z.string(), }),
alt: z.string(), timeframe: z.string().optional(),
mime: z.string().optional(), links: z
thumbnail: z.string().optional(), .object({
}), repo: z.string().url(),
) url: z.string().url(),
.catch([]), })
}), .optional(),
}),
}); });
export const collections = { export const collections = {
games,
blog, blog,
portafolio, portafolio,
}; };

View file

@ -0,0 +1,27 @@
---
title: Destino Temuco
status: Backlog
draft: true
created_at: 2024-01-01
updated_at: 2024-01-21
brief: "La dirección de Turismo, Patrimonio y Cultura del Municipio de Temuco, solicito una web autoadministrable, el cual pueda servir a todo turista y publico en general como una guia informativa sobre los servicios turísticos que ofrecen en Temuco. La web permite a quien la visita, saber sobre los tours, atractivos turísticos, eventos, galería de artes, biblioteca y servicios turísticos, así como las opciones para poder llegar a Temuco. También cuenta con blog de noticias y una revista digital sobre Temuco."
timeframe: 'March 2022 - October 2023'
thumbnail: './_media/temuco1.webp'
technologies:
- React
- NodeJS
- MySQL
---
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto2.png)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto3.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto4.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto5.webp)

View file

@ -1,20 +0,0 @@
---
title: Plataforma de Observación de clases
status: Backlog
draft: true
media:
- type: image
url: /images/portafolio/observacion_clases/1696878771763.jpg
alt: this an image
- type: image
url: /images/portafolio/observacion_clases/1696878771763.jpg
alt: this an image
technologies:
- React
- NodeJS
- MySQL
---
This is a web application to manage the stock of product in a construction
company and their usage across projects. It also allows to create budgets with
the interaction of different actors.

View file

@ -2,21 +2,11 @@
title: Piloto Go title: Piloto Go
status: Backlog status: Backlog
draft: true draft: true
media: created_at: 2024-01-01
- type: video updated_at: 2024-01-21
url: https://drive.google.com/file/d/198BB5RVjp2t1ExWhX0SfN20hEsW-Nk-l/view?usp=sharing brief: "Para el área de innovación de Almagro desarrollamos un producto mínimo viable que permite digitalizar las solicitudes de los nuevos productos que se utilizan en la construcción de edificios. Además permite armar digitalmente las matrices para los distintos segmentos de las propiedades."
alt: this an image timeframe: 'March 2022 - October 2023'
mime: video/mp4 thumbnail: './_media/piloto1.webp'
thumbnail: https://drive.google.com/file/d/1AuG0g4pugKE-GgwuOpb5eVvRPfR0S4D5/view?usp=drive_link
- type: image
url: https://drive.google.com/file/d/1AuG0g4pugKE-GgwuOpb5eVvRPfR0S4D5/view?usp=drive_link
alt: this an image
- type: image
url: https://drive.google.com/file/d/1hfyHV2c58MVJLofnAy67rzsqhCV1V5u8/view?usp=drive_link
alt: this an image
- type: image
url: https://drive.google.com/file/d/1doIdGSVmyzlV4CwI0KbsOTOQpeZYt9YU/view?usp=drive_link
alt: this an image
technologies: technologies:
- React - React
- NodeJS - NodeJS
@ -24,3 +14,17 @@ technologies:
--- ---
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors. This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![img2](./_media/piloto2.png)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![img3](./_media/piloto3.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![img 4](./_media/piloto4.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto5.webp)

View file

@ -0,0 +1,27 @@
---
title: Barrios Comerciales - Sercotec
status: Backlog
draft: true
created_at: 2024-01-01
updated_at: 2024-01-21
brief: "Desarrollo de sitio web para SERCOTEC donde buscan visibilizar los barrios comerciales dentro de Chile. Para esto cada uno de los barrios ya mapeados por SERCOTEC se pueden cargar con la descripción, imágenes, videos, programas y un mapa de como llegar al barrio. También es posible ingresar nuevos barrios comerciales que no estén inscritos en el sitio."
timeframe: 'March 2022 - October 2023'
thumbnail: './_media/sercotec1.webp'
technologies:
- React
- NodeJS
- MySQL
---
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto2.png)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto3.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto4.webp)
This is a web application to manage the stock of product in a construction company and their usage across projects. It also allows to create budgets with the interaction of different actors.
![](./_media/piloto5.webp)

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

View file

@ -1,5 +1,5 @@
--- ---
import { getCollection } from 'astro:content'; import { getCollection, getEntry } from 'astro:content';
import { t, changeLanguage } from 'i18next'; import { t, changeLanguage } from 'i18next';
import Layout from '../layouts/Layout.astro'; import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro'; import Card from '../components/Card.astro';
@ -12,10 +12,12 @@ changeLanguage('en');
const blog = await getCollection('blog', ({ data }) => const blog = await getCollection('blog', ({ data }) =>
import.meta.env.PROD ? data.draft !== true : true, import.meta.env.PROD ? data.draft !== true : true,
); );
// TODO: show the pinned ones, not the recents
const portafolio = await getCollection('portafolio', ({ data }) => const portafolio = [
import.meta.env.PROD ? data.draft !== true : true, await getEntry('portafolio', 'piloto-go'),
); await getEntry('portafolio', 'destino-temuco'),
await getEntry('portafolio', 'sercotec'),
];
--- ---
<Layout title="aleidk"> <Layout title="aleidk">
@ -24,16 +26,16 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
class="bg-image flex-center" class="bg-image flex-center"
style="--bg-image: url(https://placehold.co/600x400)" style="--bg-image: url(https://placehold.co/600x400)"
> >
<div class="hstack gap-5"> <div class="vstack gap-0 align-items-center">
<!-- <Image --> <Image
<!-- id="portrait" --> id="portrait"
<!-- src={portrait} --> src={portrait}
<!-- alt="portrait of Alexander Navarro" --> alt="portrait of Alexander Navarro"
<!-- loading="eager" --> loading="eager"
<!-- width={200} --> width={200}
<!-- /> --> />
<div> <div>
<h1 class="my-0">Alexander Navarro</h1> <h1 class="my-0 text-center">Alexander Navarro</h1>
<p> <p>
{t('home.brief')} {t('home.brief')}
</p> </p>
@ -45,56 +47,26 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
<h2 class="text-center">{t('titles.featuredWork')}</h2> <h2 class="text-center">{t('titles.featuredWork')}</h2>
<div class="grid grid-cols-1 grid-lg-cols-3 gap-4"> <div class="grid grid-cols-1 grid-lg-cols-3 gap-4">
<Card className="anim-hover-zoom"> {
<img portafolio.map(({ data, slug }) => (
src="https://placehold.co/600x400" <div>
alt="project img" <Card className="anim-hover-zoom h-100">
class="border-radius" <a class="clean" href={`/projects/${slug}`}>
/> <Image
<h3 class="fs-4 text-center my-1">Project N°1</h3> src={data.thumbnail}
<p class="text-justify"> alt="project img"
cillum sint consectetur cupidatat. Lorem ipsum dolor sit amet, qui class="border-radius respect-width"
minim labore adipisicing minim sint />
</p> <h3 class="fs-4 text-center my-1">{data.title}</h3>
<p class="text-justify">{data.brief}</p>
<div class="text-end"> </a>
<a href="">See more...</a> <div class="text-end" slot="footer">
</div> <a href={`/projects/${slug}`}>See more...</a>
</Card> </div>
</Card>
<Card className="anim-hover-zoom"> </div>
<img ))
src="https://placehold.co/600x400" }
alt="project img"
class="border-radius"
/>
<h3 class="fs-4 text-center my-1">Project N°1</h3>
<p class="text-justify">
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint
cillum sint consectetur cupidatat.
</p>
<div class="text-end">
<a href="">See more...</a>
</div>
</Card>
<Card className="anim-hover-zoom">
<img
src="https://placehold.co/600x400"
alt="project img"
class="border-radius"
/>
<h3 class="fs-4 text-center my-1">Project N°1</h3>
<p class="text-justify">
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint
cillum sint consectetur cupidatat.
</p>
<div class="text-end">
<a href="">See more...</a>
</div>
</Card>
</div> </div>
<div class="mt-4 text-center"> <div class="mt-4 text-center">
@ -274,10 +246,18 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
<style> <style>
#portrait { #portrait {
border-radius: 50%; border-radius: 50%;
border: 5px solid var(--prj-text); /* border: 5px solid var(--prj-accent); */
} }
#hero { #hero {
min-height: 50vh; min-height: 50vh;
} }
a.clean {
color: var(--prj-text);
&:hover {
text-decoration: none;
}
}
</style> </style>
</Layout> </Layout>

View file

@ -1,19 +1,20 @@
--- ---
import { changeLanguage } from "i18next"; import { changeLanguage } from 'i18next';
import type { InferGetStaticPropsType, GetStaticPaths } from "astro"; import type { InferGetStaticPropsType, GetStaticPaths } from 'astro';
import { getCollection } from "astro:content"; import { getCollection } from 'astro:content';
import Layout from "@layouts/Layout.astro"; import Layout from '@layouts/Layout.astro';
import Toc from "@components/Toc/Toc"; import Toc from '@components/Toc/Toc';
import Gallery from "@components/MediaGallery/Gallery"; import Card from '@components/Card.astro';
import Button from '@components/Button/Button.astro';
changeLanguage("en"); changeLanguage('en');
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const entries = await getCollection("portafolio"); const entries = await getCollection('portafolio');
return entries.map((entry) => ({ return entries.map((entry) => ({
params: { slug: entry.slug }, params: { slug: entry.slug },
props: entry, props: entry,
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>; type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props; const entry = Astro.props;
@ -22,10 +23,59 @@ const { Content, headings } = await entry.render();
<Layout title={entry.data.title}> <Layout title={entry.data.title}>
<h1>{entry.data.title}</h1> <h1>{entry.data.title}</h1>
<Card className="w-lg-50 mx-auto">
<div class="project-specs grid">
<div class="project-spec-property">Timeframe:</div>
<div class="project-spec-value">{entry.data.timeframe}</div>
<Gallery client:load items={entry.data.media} /> <div class="project-spec-property">Repo:</div>
<div class="project-spec-value">{entry.data.links?.url ?? 'Private'}</div>
<div class="project-spec-property">Website:</div>
<div class="project-spec-value">
{entry.data.links?.repo ?? 'Private'}
</div>
<div class="project-spec-property">Technologies:</div>
<div class="project-spec-value">
<ul>
{entry.data.technologies.map((item) => <li>{item}</li>)}
</ul>
</div>
</div>
</Card>
<Toc headings={headings} /> <Toc headings={headings} />
<Content /> <Content />
<div
class="position-fixed bottom-0"
style={{ top: 'unset', left: 'unset', bottom: '5%', right: '5%' }}
>
<Button className="btn-back">Go back</Button>
</div>
</Layout> </Layout>
<style is:global lang="scss">
img {
margin: 0 auto var(--prj-spacing-2) auto;
display: block;
}
.project-specs.grid {
--prj-columns: 0.2fr 1fr;
.project-spec-property {
font-weight: bold;
}
}
</style>
<script>
document.addEventListener('astro:page-load', () => {
document.querySelector('.btn-back')?.addEventListener('click', () => {
history.back();
});
});
</script>

View file

@ -5,6 +5,7 @@ import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro'; import Layout from '@layouts/Layout.astro';
import Card from '@components/Card.astro'; import Card from '@components/Card.astro';
import Pagination from '@components/Pagination.astro'; import Pagination from '@components/Pagination.astro';
import { Image } from 'astro:assets';
changeLanguage('en'); changeLanguage('en');
@ -35,24 +36,19 @@ const { page } = Astro.props;
{ {
page.data.map((item) => ( page.data.map((item) => (
<div> <div>
<Card className="anim-hover-zoom"> <Card className="anim-hover-zoom h-100">
<a class="clean" href={`/projects/${item.slug}`}> <a class="clean" href={`/projects/${item.slug}`}>
<img <Image
src="https://placehold.co/600x400" src={item.thumbnail}
alt="project img" alt="project img"
class="border-radius respect-width" class="border-radius respect-width"
slot="img-header"
/> />
<h3 class="fs-4 text-center my-1">Project N°1</h3> <h3 class="fs-4 text-center my-1">{item.title}</h3>
<p class="text-justify"> <p class="text-justify">{item.brief}</p>
cillum sint consectetur cupidatat. Lorem ipsum dolor sit amet,
qui minim labore adipisicing minim sint
</p>
<div class="text-end">
<a href={`/projects/${item.slug}`}>See more...</a>
</div>
</a> </a>
<div class="text-end" slot="footer">
<a href={`/projects/${item.slug}`}>See more...</a>
</div>
</Card> </Card>
</div> </div>
)) ))
@ -63,7 +59,11 @@ const { page } = Astro.props;
</Layout> </Layout>
<style lang="scss"> <style lang="scss">
a.clean:hover { a.clean {
text-decoration: none; color: var(--prj-text);
&:hover {
text-decoration: none;
}
} }
</style> </style>