Skip to content

Commit b4e6b14

Browse files
authored
Merge pull request #20 from coderdiaz/feat/improvements
Important improvements
2 parents bb2f3b5 + dfb3d19 commit b4e6b14

File tree

11 files changed

+114
-67
lines changed

11 files changed

+114
-67
lines changed

src/assets/images/avatar.jpeg

-124 KB
Binary file not shown.

src/assets/images/avatar.png

73.3 KB
Loading

src/components/partials/Header.astro

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,37 @@ const pathname = Astro.url.pathname;
55
66
const isHomePage = pathname === '/';
77
const isWritingPage = pathname.startsWith('/writing');
8-
98
---
109

11-
<Container as='header' class="w-full max-w-full flex justify-center items-center">
12-
<div class="w-max fixed top-0 mt-5 bg-muted-foreground/40 backdrop-blur-md border border-border rounded-full p-1">
10+
<Container
11+
as="header"
12+
class="w-full max-w-full flex justify-center items-center"
13+
>
14+
<div
15+
class="w-max fixed top-0 mt-5 bg-muted-foreground/40 backdrop-blur-3xl border border-border rounded-full p-1"
16+
>
1317
<nav class="flex items-center">
1418
<ul class="flex items-center gap-1">
1519
<li>
16-
<a href="/" class:list={[
17-
'font-medium transition-colors block px-5 py-2',
18-
'hover:text-headings',
19-
isHomePage && 'text-headings bg-muted-foreground/40 rounded-full',
20-
]}>Home</a>
20+
<a
21+
href="/"
22+
class:list={[
23+
'font-medium transition-colors block px-5 py-2',
24+
'hover:text-headings',
25+
isHomePage && 'text-headings bg-muted-foreground/40 rounded-full',
26+
]}>Home</a
27+
>
2128
</li>
2229
<li>
23-
<a href="/writing" class:list={[
24-
'font-medium transition-colors block px-5 py-2',
25-
'hover:text-headings',
26-
isWritingPage && 'text-headings bg-muted-foreground/40 rounded-full',
27-
]}>Writing</a>
30+
<a
31+
href="/writing"
32+
class:list={[
33+
'font-medium transition-colors block px-5 py-2',
34+
'hover:text-headings',
35+
isWritingPage &&
36+
'text-headings bg-muted-foreground/40 rounded-full',
37+
]}>Writing</a
38+
>
2839
</li>
2940
</ul>
3041
</nav>

src/components/ui/WorkExperience.astro

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface Props {
88
const { entry } = Astro.props;
99
const { Content } = await render(entry);
1010
11-
const images = entry.data.images
11+
const images = entry.data.images
1212
? entry.data.images.map((img) => ({
1313
src: img.src,
1414
alt: entry.data.title,
@@ -19,7 +19,9 @@ const images = entry.data.images
1919
<li class="py-0.5">
2020
<div class="flex gap-5">
2121
<div class="relative min-w-28 shrink-0">
22-
<span class="text-muted-foreground text-sm">{entry.data.from} - {entry.data.to}</span>
22+
<span class="text-muted-foreground text-sm"
23+
>{entry.data.from} - {entry.data.to ?? 'Present'}</span
24+
>
2325
</div>
2426
<div class="flex flex-col gap-3">
2527
<div class="flex flex-col">
@@ -29,24 +31,26 @@ const images = entry.data.images
2931
<div class="prose dark:prose-invert prose-sm">
3032
<Content />
3133
</div>
32-
33-
{images.length > 0 && (
34-
<div class="flex gap-2 flex-wrap mt-2">
35-
{images.map((image, idx) => (
36-
<button
37-
class="work-image-thumb overflow-hidden rounded-lg border border-border hover:opacity-80 transition-opacity"
38-
data-images={JSON.stringify(images)}
39-
data-index={idx}
40-
>
41-
<img
42-
src={image.src}
43-
alt={image.alt}
44-
class="w-20 h-20 object-cover"
45-
/>
46-
</button>
47-
))}
48-
</div>
49-
)}
34+
35+
{
36+
images.length > 0 && (
37+
<div class="flex gap-2 flex-wrap mt-2">
38+
{images.map((image, idx) => (
39+
<button
40+
class="work-image-thumb overflow-hidden rounded-lg border border-border hover:opacity-80 transition-opacity"
41+
data-images={JSON.stringify(images)}
42+
data-index={idx}
43+
>
44+
<img
45+
src={image.src}
46+
alt={image.alt}
47+
class="w-20 h-20 object-cover"
48+
/>
49+
</button>
50+
))}
51+
</div>
52+
)
53+
}
5054
</div>
5155
</div>
5256
</li>
@@ -57,19 +61,19 @@ const images = entry.data.images
5761
import { createElement } from 'react';
5862

5963
const container = document.querySelector('.flex.gap-2.flex-wrap.mt-2');
60-
64+
6165
if (container) {
6266
const clickHandler = (event: Event) => {
6367
const thumb = (event.target as HTMLElement).closest('.work-image-thumb');
6468
if (!thumb || !container.contains(thumb)) return;
65-
69+
6670
const images = JSON.parse(thumb.getAttribute('data-images') || '[]');
6771
const index = parseInt(thumb.getAttribute('data-index') || '0');
68-
72+
6973
const lightboxContainer = document.createElement('div');
7074
document.body.appendChild(lightboxContainer);
7175
const root = createRoot(lightboxContainer);
72-
76+
7377
const closeHandler = () => {
7478
root.unmount();
7579
try {
@@ -78,17 +82,17 @@ const images = entry.data.images
7882
// Container may have already been removed; ignore error
7983
}
8084
};
81-
85+
8286
root.render(
8387
createElement(ImageLightbox, {
8488
images,
8589
isOpen: true,
8690
initialIndex: index,
8791
onClose: closeHandler,
88-
})
92+
}),
8993
);
9094
};
91-
95+
9296
container.addEventListener('click', clickHandler);
9397
}
94-
</script>
98+
</script>

src/content.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const jobCollection = defineCollection({
4949
company: z.string(),
5050
location: z.string(),
5151
from: z.number(),
52-
to: z.number().or(z.enum(['Now'])),
52+
to: z.number().optional(), // optional if currently working
5353
url: z.string(),
5454
images: z.array(image()).optional(),
5555
}),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Engineering & Design
3+
company: Coderdiaz Studio
4+
location: Mexico City
5+
from: 2022
6+
url: https://coderdiaz.com
7+
---

src/content/jobs/reboot-studio/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: Product Engineer
33
company: Reboot Studio
44
location: Mexico City
55
from: 2022
6-
to: 2022 # Use 'Now' if the job is still active
6+
to: 2022
77
url: https://reboot.studio
88
images:
99
- ./image-1.jpg

src/content/jobs/sofia/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: Product Engineer
33
company: Sofia
44
location: Mexico City
55
from: 2025
6-
to: Now # Use 'Now' if the job is still active
6+
to: 2025
77
url: https://sofiasalud.com
88
---
99

src/lib/constants.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { z } from 'astro/zod';
22
import MetaDefaultImage from '@/assets/images/meta-default.jpg';
3-
import avatar from '@/assets/images/avatar.jpeg';
3+
import avatar from '@/assets/images/avatar.png';
44
import type { seoSchemaWithoutImage } from '@/content.config';
55
import astroConfig from 'astro.config.mjs';
66

@@ -11,17 +11,17 @@ export type AuthorInfo = {
1111
username?: string;
1212
location?: string;
1313
pronouns?: string;
14-
}
14+
};
1515

1616
export type Seo = z.infer<typeof seoSchemaWithoutImage> & {
1717
image?: any;
18-
}
18+
};
1919

2020
type DefaultConfigurationType = {
21-
baseUrl: string,
21+
baseUrl: string;
2222
author: AuthorInfo;
2323
seo: Seo;
24-
}
24+
};
2525

2626
export const DEFAULT_CONFIGURATION: DefaultConfigurationType = {
2727
baseUrl: astroConfig.site || 'https://getcvfolio.com',
@@ -35,12 +35,13 @@ export const DEFAULT_CONFIGURATION: DefaultConfigurationType = {
3535
},
3636
seo: {
3737
title: 'CV Folio — An Astro template inspired on Read.cv',
38-
description: 'Clean and aesthetic portfolio website for developers and designers',
38+
description:
39+
'Clean and aesthetic portfolio website for developers and designers',
3940
type: 'website',
4041
image: MetaDefaultImage,
4142
twitter: {
42-
creator: '@cvfolio'
43+
creator: '@cvfolio',
4344
},
4445
robots: 'noindex, nofollow',
45-
}
46-
};
46+
},
47+
};

src/lib/utils.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { DEFAULT_CONFIGURATION } from './constants';
2-
import type { CollectionEntry } from 'astro:content';
32

43
export const formatDate = (date: Date) => {
54
const formatter = new Intl.DateTimeFormat('en-US', {
@@ -23,18 +22,41 @@ export const includeDraft = (draft: boolean) => {
2322
return draft !== true;
2423
};
2524

26-
export const sortJobsByDate = (jobs: CollectionEntry<'jobs'>[]) => {
27-
// Convert "Now" to current year, otherwise returns the year as is
28-
const getEndYear = (job: CollectionEntry<'jobs'>) =>
29-
job.data.to === 'Now' ? new Date().getFullYear() : job.data.to;
30-
31-
return jobs.sort((current, next) => {
32-
// Compare end years first, then fall back to start years if end years are equal
33-
const [currentEnd, nextEnd] = [getEndYear(current), getEndYear(next)];
25+
/*
26+
* Generic function for sorting items with start and optional end years
27+
* - Items without an end year are considered ongoing and are sorted accordingly
28+
* - Items are sorted by end year descending, then by start year descending
29+
* - If end year is not present, current year is used for comparison
30+
*/
31+
export const sortByDateRange = <
32+
T extends { data: { from: number; to?: number } },
33+
>(
34+
items: T[],
35+
) => {
36+
const getCurrentYear = () => new Date().getFullYear();
37+
38+
return items.sort((current, next) => {
39+
// Prioritize ongoing jobs (no 'to' field) first
40+
const currentIsOngoing = current.data.to === undefined;
41+
const nextIsOngoing = next.data.to === undefined;
42+
43+
// If one is ongoing and the other isn't, ongoing comes first
44+
if (currentIsOngoing && !nextIsOngoing) return -1;
45+
if (!currentIsOngoing && nextIsOngoing) return 1;
46+
47+
// If both are ongoing or both have end dates, sort by end year then start year
48+
const currentEnd = current.data.to ?? getCurrentYear();
49+
const nextEnd = next.data.to ?? getCurrentYear();
3450
return nextEnd - currentEnd || next.data.from - current.data.from;
3551
});
3652
};
3753

38-
export const sortTalksByYear = (talks: CollectionEntry<'talks'>[]) => {
39-
return talks.sort((a, b) => b.data.year - a.data.year);
54+
/*
55+
* Generic function for sorting items by year in descending order
56+
* - Items are sorted by year descending
57+
*/
58+
export const sortByYear = <T extends { data: { year: number } }>(
59+
items: T[],
60+
) => {
61+
return items.sort((a, b) => b.data.year - a.data.year);
4062
};

0 commit comments

Comments
 (0)