Skip to content

Commit 1ed81ff

Browse files
committed
To be honest, I do not quite remember everyting I changed here today ¯\_(ツ)_/¯ But it is all good, I tell ya.
1 parent 0237a4a commit 1ed81ff

20 files changed

Lines changed: 913 additions & 835 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ out
55
.env.local
66
.env*.local
77
*.log
8-
.DS_Store
8+
.DS_Store
9+
.agent

app/globals.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@
144144
}
145145
}
146146

147+
@media (prefers-reduced-motion: reduce) {
148+
.animate-scroll,
149+
.animate-scroll-reverse {
150+
animation: none !important;
151+
overflow-x: auto;
152+
}
153+
}
154+
147155
@layer base {
148156
* {
149157
@apply border-border outline-ring/50;

app/layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type React from "react";
22
import type { Metadata } from "next";
33
import { Geist, Geist_Mono } from "next/font/google";
4-
import { Analytics } from "@vercel/analytics/next";
54
import { Providers } from "@/components/theme-provider";
65
import "./globals.css";
76

@@ -98,7 +97,6 @@ export default function RootLayout({
9897
}}
9998
/>
10099
{children}
101-
<Analytics />
102100
</Providers>
103101
</body>
104102
</html>

app/notas/[slug]/page.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { notFound } from "next/navigation";
88
import { PostHeader } from "@/components/blog/post-header";
99
import { Metadata } from "next";
1010
import { Post } from "@/interfaces/post";
11+
import Link from "next/link";
12+
import { ArrowLeft } from "lucide-react";
13+
import { Button } from "@/components/ui/button";
1114

1215
type ParamsType = {
1316
params: Promise<{
@@ -36,6 +39,8 @@ export default async function PostPage({
3639
}
3740

3841
const content = await markdownToHtml(post.content || "");
42+
const wordCount = post.content?.split(/\s+/).length || 0;
43+
const readingTime = Math.ceil(wordCount / 200);
3944

4045
// JSON-LD for better SEO
4146
const jsonLd = {
@@ -66,7 +71,7 @@ export default async function PostPage({
6671
{/* Premium Hero Section */}
6772
<section className="relative pt-32 pb-12 md:pt-40 md:pb-20 w-full backdrop-blur-3xl overflow-hidden">
6873
{/* Background grid pattern - Fixed Syntax */}
69-
<div className="absolute inset-0 bg-[linear-gradient(to_right,#1a1a2e_1px,transparent_1px),linear-gradient(to_bottom,#1a1a2e_1px,transparent_1px)] dark:bg-[linear-gradient(to_right,#4a4a5e_1px,transparent_1px),linear-gradient(to_bottom,#4a4a5e_1px,transparent_1px)] bg-size-[4rem_4rem] opacity-50 [mask-image:linear-gradient(to_bottom,black_40%,transparent_100%)] -z-10" />
74+
<div className="absolute inset-0 bg-[linear-gradient(to_right,#1a1a2e_1px,transparent_1px),linear-gradient(to_bottom,#1a1a2e_1px,transparent_1px)] dark:bg-[linear-gradient(to_right,#4a4a5e_1px,transparent_1px),linear-gradient(to_bottom,#4a4a5e_1px,transparent_1px)] bg-size-[4rem_4rem] opacity-50 mask-[linear-gradient(to_bottom,black_40%,transparent_100%)] -z-10" />
7075

7176
{/* Glow effects */}
7277
<div className="absolute top-0 left-1/4 w-96 h-96 bg-primary/40 rounded-full blur-3xl animate-pulse -z-10" />
@@ -76,12 +81,23 @@ export default async function PostPage({
7681
/>
7782

7883
<Container>
79-
<div className="max-w-4xl mx-auto text-center">
84+
<div className="max-w-4xl mx-auto">
85+
<Link href="/notas" className="inline-flex">
86+
<Button
87+
variant="ghost"
88+
size="sm"
89+
className="group mb-8 text-muted-foreground hover:text-primary transition-colors"
90+
>
91+
<ArrowLeft className="mr-2 h-4 w-4 transition-transform group-hover:-translate-x-1" />
92+
Volver a notas
93+
</Button>
94+
</Link>
8095
<PostHeader
8196
title={post.title}
8297
coverImage={post.coverImage}
8398
date={post.date}
8499
author={post.author}
100+
readingTime={`${readingTime} min`}
85101
/>
86102
</div>
87103
</Container>

app/page.tsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
import { HeroSection } from "@/components/hero-section";
2-
import { AboutSection } from "@/components/about-section";
3-
import { MembersSection } from "@/components/members-section";
4-
import { GallerySection } from "@/components/gallery-section";
5-
import { LatestPostsSection } from "@/components/latest-posts-section";
6-
import { EventsSection } from "@/components/events-section";
7-
import { ContactSection } from "@/components/contact-section";
8-
import { Footer } from "@/components/footer";
92
import { Navbar } from "@/components/navbar";
3+
import dynamic from "next/dynamic";
4+
5+
const AboutSection = dynamic(() =>
6+
import("@/components/about-section").then((mod) => mod.AboutSection),
7+
);
8+
const MembersSection = dynamic(() =>
9+
import("@/components/members-section").then((mod) => mod.MembersSection),
10+
);
11+
const GallerySection = dynamic(() =>
12+
import("@/components/gallery-section").then((mod) => mod.GallerySection),
13+
);
14+
const LatestPostsSection = dynamic(() =>
15+
import("@/components/latest-posts-section").then(
16+
(mod) => mod.LatestPostsSection,
17+
),
18+
);
19+
const EventsSection = dynamic(() =>
20+
import("@/components/events-section").then((mod) => mod.EventsSection),
21+
);
22+
const ContactSection = dynamic(() =>
23+
import("@/components/contact-section").then((mod) => mod.ContactSection),
24+
);
25+
const Footer = dynamic(() =>
26+
import("@/components/footer").then((mod) => mod.Footer),
27+
);
1028

1129
export default function Home() {
1230
return (

components/blog/blog-card.tsx

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Link from "next/link";
2+
import Image from "next/image";
23
import { type Post } from "@/interfaces/post";
34
import { Card, CardContent, CardFooter } from "@/components/ui/card";
45
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
@@ -16,67 +17,76 @@ export function BlogCard({ post, className }: Props) {
1617
return (
1718
<Card
1819
className={cn(
19-
"group flex flex-col h-full overflow-hidden border-border/50 bg-card transition-all hover:shadow-lg hover:border-border",
20-
className
20+
"group flex flex-col h-full overflow-hidden border-primary/10 bg-muted/30 backdrop-blur-md transition-all duration-500 hover:shadow-2xl hover:shadow-primary/5 hover:border-primary/30 hover:-translate-y-1 py-0 gap-0",
21+
className,
2122
)}
2223
>
23-
{/* Image Container - Switched from CardHeader to plain div to guarantee 0 padding */}
24-
<div className="w-full relative">
24+
{/* Image Container */}
25+
<div className="w-full relative overflow-hidden">
2526
<Link
2627
href={`/notas/${post.slug}`}
27-
className="block overflow-hidden active:scale-95 transition-transform duration-200"
28+
className="block active:scale-95 transition-transform duration-200"
2829
>
29-
<div className="relative aspect-video w-full overflow-hidden bg-muted">
30-
{/* bg-muted acts as placeholder if transparency exists */}
31-
<img
30+
<div className="relative aspect-video w-full overflow-hidden bg-muted/20">
31+
<Image
3232
src={post.coverImage}
3333
alt={`Cover for ${post.title}`}
34-
className="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
34+
fill
35+
className="object-cover transition-transform duration-700 ease-out group-hover:scale-110"
36+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
3537
/>
38+
<div className="absolute inset-0 bg-linear-to-t from-background/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
3639
</div>
3740
</Link>
3841
</div>
3942

40-
<CardContent className="flex-1 p-6">
41-
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-3">
42-
<Calendar className="w-4 h-4" />
43+
<CardContent className="flex-1 p-6 space-y-3">
44+
<div className="flex items-center gap-2 text-xs font-medium text-primary/80 uppercase tracking-wider">
45+
<Calendar className="w-3.5 h-3.5" />
4346
<DateFormatter dateString={post.date} />
4447
</div>
4548
<Link
4649
href={`/notas/${post.slug}`}
47-
className="block group-hover:text-primary transition-colors"
50+
className="block group/title"
4851
>
49-
<h3 className="text-xl font-bold leading-tight mb-2 line-clamp-2">
52+
<h3 className="text-xl font-bold leading-tight group-hover/title:text-primary transition-colors duration-300 line-clamp-2">
5053
{post.title}
5154
</h3>
5255
</Link>
53-
<p className="text-muted-foreground text-sm line-clamp-3 leading-relaxed">
56+
<p className="text-muted-foreground text-sm line-clamp-3 leading-relaxed opacity-80 group-hover:opacity-100 transition-opacity duration-300">
5457
{post.excerpt}
5558
</p>
5659
</CardContent>
60+
5761
<CardFooter className="p-6 pt-0 flex items-center justify-between mt-auto">
58-
<div className="flex items-center gap-2">
59-
<Avatar className="w-8 h-8 border">
62+
<div className="flex items-center gap-3">
63+
<Avatar className="w-9 h-9 border-2 border-primary/10 transition-transform duration-300 group-hover:scale-110">
6064
<AvatarImage
6165
src={post.author.picture}
6266
alt={post.author.name}
6367
/>
64-
<AvatarFallback>{post.author.name[0]}</AvatarFallback>
68+
<AvatarFallback className="bg-primary/5 text-primary">
69+
{post.author.name[0]}
70+
</AvatarFallback>
6571
</Avatar>
66-
<span className="text-sm font-medium opacity-80">
67-
{post.author.name}
68-
</span>
72+
<div className="flex flex-col">
73+
<span className="text-sm font-semibold leading-none mb-1">
74+
{post.author.name}
75+
</span>
76+
<span className="text-[10px] text-muted-foreground uppercase tracking-tighter">
77+
Autor
78+
</span>
79+
</div>
6980
</div>
7081

7182
<Button
7283
variant="ghost"
7384
size="sm"
74-
className="gap-1 px-4 hover:bg-primary hover:text-white transition-all duration-300 group/btn"
85+
className="h-9 w-9 p-0 rounded-full hover:bg-primary hover:text-white transition-all duration-300 group/btn"
7586
asChild
7687
>
77-
<Link href={`/notas/${post.slug}`}>
78-
Leer más{" "}
79-
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover/btn:translate-x-1" />
88+
<Link href={`/notas/${post.slug}`} aria-label="Leer más">
89+
<ArrowRight className="w-5 h-5 transition-transform duration-300 group-hover/btn:translate-x-0.5" />
8090
</Link>
8191
</Button>
8292
</CardFooter>

components/blog/post-body.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ type Props = {
44

55
export function PostBody({ content }: Props) {
66
return (
7-
<div className="max-w-3xl mx-auto prose prose-lg prose-slate dark:prose-invert prose-headings:font-bold prose-a:text-primary prose-img:rounded-xl [&>:first-child]:mt-0">
8-
<div dangerouslySetInnerHTML={{ __html: content }} />
7+
<div className="max-w-3xl mx-auto prose prose-sky dark:prose-invert prose-lg md:prose-xl selection:bg-primary/30 selection:text-foreground">
8+
<div
9+
className="prose-headings:tracking-tight prose-headings:font-bold prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-img:rounded-3xl prose-img:shadow-2xl prose-blockquote:border-l-primary prose-blockquote:bg-muted/50 prose-blockquote:py-1 prose-blockquote:px-6 prose-blockquote:rounded-r-lg"
10+
dangerouslySetInnerHTML={{ __html: content }}
11+
/>
912
</div>
1013
);
1114
}

components/blog/post-header.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
1-
import { Avatar } from "./avatar";
21
import { DateFormatter } from "./date-formatter";
32
import { PostTitle } from "./post-title";
43
import { type Author } from "@/interfaces/author";
4+
import Image from "next/image";
55

66
type Props = {
77
title: string;
88
coverImage: string;
99
date: string;
1010
author: Author;
11+
readingTime?: string;
1112
};
1213

13-
export function PostHeader({ title, coverImage, date, author }: Props) {
14+
export function PostHeader({
15+
title,
16+
coverImage,
17+
date,
18+
author,
19+
readingTime,
20+
}: Props) {
1421
return (
15-
<div className="space-y-6">
22+
<div className="flex flex-col items-center">
1623
<PostTitle>{title}</PostTitle>
1724

18-
<div className="flex items-center gap-2 text-muted-foreground animate-in fade-in slide-in-from-bottom-4 duration-500 delay-100">
19-
<img
25+
<div className="flex items-center gap-3 bg-card/50 backdrop-blur-sm border border-border px-4 py-2 rounded-full animate-in fade-in slide-in-from-bottom-4 duration-500 delay-100">
26+
<Image
2027
src={author.picture}
2128
alt={author.name}
29+
width={40}
30+
height={40}
2231
className="w-10 h-10 rounded-full border border-border"
2332
/>
2433
<div className="flex flex-col text-sm text-left leading-tight">
2534
<span className="font-semibold text-foreground">
2635
{author.name}
2736
</span>
28-
<DateFormatter dateString={date} />
37+
<div className="flex items-center gap-2 text-muted-foreground">
38+
<DateFormatter dateString={date} />
39+
{readingTime && (
40+
<>
41+
<span></span>
42+
<span>{readingTime} de lectura</span>
43+
</>
44+
)}
45+
</div>
2946
</div>
3047
</div>
3148
</div>

components/blog/post-pagination.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ export function PostPagination({ allPosts }: Props) {
1212
const searchParams = useSearchParams();
1313
const pageParam = searchParams.get("page");
1414
const page = pageParam ? parseInt(pageParam) : 1;
15-
const pageSize = 6;
15+
const pageSize = 12;
1616

1717
const totalPages = Math.ceil(allPosts.length / pageSize);
1818
const currentPage = page > 0 && page <= totalPages ? page : 1;
1919

2020
const posts = allPosts.slice(
2121
(currentPage - 1) * pageSize,
22-
currentPage * pageSize
22+
currentPage * pageSize,
2323
);
2424

2525
return (

components/blog/post-title.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ type Props = {
66

77
export function PostTitle({ children }: Props) {
88
return (
9-
<h1 className="text-4xl font-bold tracking-tighter leading-tight md:leading-none mb-4 text-center md:text-left">
9+
<h1 className="text-4xl sm:text-5xl lg:text-7xl font-bold tracking-tight leading-tight mb-8 text-center balance">
1010
{children}
1111
</h1>
1212
);

0 commit comments

Comments
 (0)