Skip to content

Commit 806ec7a

Browse files
Sanity (#196)
* feat(Blog):fix for clickable link in post details, fix for author details * feat(Blog):refactoring after removing author modal * feat(Blog): fix unified date format
1 parent 0da8434 commit 806ec7a

9 files changed

Lines changed: 172 additions & 305 deletions

File tree

frontend/app/[locale]/blog/[slug]/PostDetails.tsx

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import groq from 'groq';
44
import { getTranslations } from 'next-intl/server';
55
import { client } from '@/client';
66
import { Link } from '@/i18n/routing';
7+
import { formatBlogDate } from '@/lib/blog/date';
78

89
export const revalidate = 0;
910

@@ -67,6 +68,41 @@ function linkifyText(text: string) {
6768
});
6869
}
6970

71+
function renderPortableTextSpans(
72+
children: Array<{ _type?: string; text?: string; marks?: string[] }> = [],
73+
markDefs: Array<{ _key?: string; _type?: string; href?: string }> = []
74+
) {
75+
const linkMap = new Map(
76+
markDefs
77+
.filter(def => def?._type === 'link' && def?._key && def?.href)
78+
.map(def => [def._key as string, def.href as string])
79+
);
80+
81+
return children.map((child, index) => {
82+
const text = child?.text || '';
83+
if (!text) return null;
84+
const marks = child?.marks || [];
85+
const linkKey = marks.find(mark => linkMap.has(mark));
86+
87+
if (linkKey) {
88+
const href = linkMap.get(linkKey)!;
89+
return (
90+
<a
91+
key={`mark-link-${index}`}
92+
href={href}
93+
target="_blank"
94+
rel="noopener noreferrer"
95+
className="text-[var(--accent-primary)] underline underline-offset-4"
96+
>
97+
{text}
98+
</a>
99+
);
100+
}
101+
102+
return <span key={`mark-text-${index}`}>{linkifyText(text)}</span>;
103+
});
104+
}
105+
70106
function seededShuffle<T>(items: T[], seed: number) {
71107
const result = [...items];
72108
let value = seed;
@@ -219,9 +255,7 @@ export default async function PostDetails({
219255
</Link>
220256
)}
221257
{authorName && post.publishedAt && <span>·</span>}
222-
{post.publishedAt && (
223-
<span>{new Date(post.publishedAt).toLocaleDateString()}</span>
224-
)}
258+
{post.publishedAt && <span>{formatBlogDate(post.publishedAt)}</span>}
225259
</div>
226260
)}
227261

@@ -241,15 +275,12 @@ export default async function PostDetails({
241275
<article className="prose prose-gray max-w-none">
242276
{post.body?.map((block: any, index: number) => {
243277
if (block?._type === 'block') {
244-
const text = (block.children || [])
245-
.map((c: any) => c.text || '')
246-
.join('');
247278
return (
248279
<p
249280
key={block._key || `block-${index}`}
250281
className="whitespace-pre-line"
251282
>
252-
{linkifyText(text)}
283+
{renderPortableTextSpans(block.children, block.markDefs)}
253284
</p>
254285
);
255286
}
@@ -320,9 +351,7 @@ export default async function PostDetails({
320351
{item.author?.name && <span>{item.author.name}</span>}
321352
{item.author?.name && item.publishedAt && <span>·</span>}
322353
{item.publishedAt && (
323-
<span>
324-
{new Date(item.publishedAt).toLocaleDateString()}
325-
</span>
354+
<span>{formatBlogDate(item.publishedAt)}</span>
326355
)}
327356
</div>
328357
)}

frontend/app/[locale]/blog/category/[category]/page.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Image from 'next/image';
55
import { client } from '@/client';
66
import { Link } from '@/i18n/routing';
77
import { BlogCategoryGrid } from '@/components/blog/BlogCategoryGrid';
8+
import { formatBlogDate } from '@/lib/blog/date';
89

910
export const revalidate = 0;
1011

@@ -79,13 +80,7 @@ export default async function BlogCategoryPage({
7980

8081
const featuredPost = posts[0];
8182
const restPosts = posts.slice(1);
82-
const featuredDate = featuredPost?.publishedAt
83-
? new Intl.DateTimeFormat(locale, {
84-
day: '2-digit',
85-
month: '2-digit',
86-
year: 'numeric',
87-
}).format(new Date(featuredPost.publishedAt))
88-
: '';
83+
const featuredDate = formatBlogDate(featuredPost?.publishedAt);
8984

9085
return (
9186
<main className="max-w-6xl mx-auto px-6 py-12">
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import groq from 'groq';
2+
import { NextResponse } from 'next/server';
3+
import { client } from '@/client';
4+
5+
export const revalidate = 0;
6+
7+
const authorQuery = groq`
8+
*[_type == "author" && (
9+
name[$locale] == $name ||
10+
name[lower($locale)] == $name ||
11+
name.en == $name ||
12+
name.pl == $name ||
13+
name.uk == $name
14+
)][0]{
15+
"name": coalesce(name[$locale], name[lower($locale)], name.uk, name.en, name.pl, name),
16+
"company": coalesce(company[$locale], company[lower($locale)], company.uk, company.en, company.pl, company),
17+
"jobTitle": coalesce(jobTitle[$locale], jobTitle[lower($locale)], jobTitle.uk, jobTitle.en, jobTitle.pl, jobTitle),
18+
"city": coalesce(city[$locale], city[lower($locale)], city.uk, city.en, city.pl, city),
19+
"bio": coalesce(bio[$locale], bio[lower($locale)], bio.uk, bio.en, bio.pl, bio),
20+
"image": image.asset->url,
21+
socialMedia[]{ _key, platform, url }
22+
}
23+
`;
24+
25+
export async function GET(request: Request) {
26+
const { searchParams } = new URL(request.url);
27+
const name = (searchParams.get('name') || '').trim();
28+
const locale = (searchParams.get('locale') || 'en').trim();
29+
30+
if (!name) {
31+
return NextResponse.json(null, { status: 400 });
32+
}
33+
34+
const author = await client
35+
.withConfig({ useCdn: false })
36+
.fetch(authorQuery, { name, locale });
37+
38+
return NextResponse.json(author || null, {
39+
headers: { 'Cache-Control': 'no-store' },
40+
});
41+
}

0 commit comments

Comments
 (0)