Skip to content

Commit b90a96a

Browse files
Merge pull request #363 from DevLoversTeam/develop
Release v1.0.3
2 parents 16b2297 + 2b33396 commit b90a96a

47 files changed

Lines changed: 887 additions & 513 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,3 +684,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
684684

685685
- Stronger password validation and confirmation flow
686686
- Improved server-side validation and error reporting
687+
688+
## [1.0.3] - 2026-02-23
689+
690+
### Fixed
691+
692+
- Blog (Sanity):
693+
- Fixed images not rendering on Vercel production
694+
- Improved image optimization across blog pages and components
695+
- SSR hydration mismatch in AchievementBadge (client/server state sync)
696+
- Header hardcoded locale issues
697+
- Notification rendering consistency
698+
699+
### Changed
700+
701+
- Q&A UI:
702+
- Updated Git category tab color for stronger visual distinction from HTML
703+
704+
- Header & Localization:
705+
- Translated all header UI strings (en / uk / pl)
706+
- Notifications now fully localized with locale-aware relative time
707+
- LanguageSwitcher and User menu labels localized
708+
709+
- Dashboard UX:
710+
- Unified dashboard cards styling using shared `dashboard-card` class
711+
- Clickable profile stats with smooth scroll navigation
712+
- Improved avatar detection logic
713+
714+
### Performance & Stability
715+
716+
- Improved client-render guards using stable subscription pattern
717+
- Reduced hydration inconsistencies in production

assets/01-screencapture.png

13.4 KB
Loading

assets/02-screencapture.png

220 KB
Loading

assets/03-screencapture.png

20.8 KB
Loading

assets/04-screencapture.png

25.7 KB
Loading

assets/05-screencapture.png

18.4 KB
Loading

assets/08-screencapture.png

51 Bytes
Loading

frontend/actions/notifications.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
'use server';
22

3-
import { desc, eq, and } from 'drizzle-orm';
3+
import { and,desc, eq } from 'drizzle-orm';
44
import { revalidatePath } from 'next/cache';
55

66
import { db } from '@/db';
77
import { notifications } from '@/db/schema/notifications';
8-
98
import { getCurrentUser } from '@/lib/auth';
109

1110
export async function getNotifications() {

frontend/actions/quiz.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,15 @@ export async function submitQuizAttempt(
231231
const earnedAfter = computeAchievements(statsAfter).filter(a => a.earned);
232232
const newlyEarned = earnedAfter.filter(a => !earnedBefore.has(a.id));
233233

234-
// Trigger notifications for any newly earned achievements
234+
// Trigger notifications for any newly earned achievements.
235+
// title/message are stable English fallbacks; NotificationBell renders
236+
// them dynamically in the viewer's locale using metadata.badgeId.
235237
for (const achievement of newlyEarned) {
236-
// Find full object to get the fancy translated string (if needed) or just generic name
237238
await createNotification({
238239
userId: session.id,
239240
type: 'ACHIEVEMENT',
240241
title: 'Achievement Unlocked!',
241-
message: `You just earned the ${achievement.id} badge!`,
242+
message: achievement.id,
242243
metadata: { badgeId: achievement.id, icon: achievement.icon },
243244
});
244245
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { client } from '@/client';
77
import { DynamicGridBackground } from '@/components/shared/DynamicGridBackground';
88
import { Link } from '@/i18n/routing';
99
import { formatBlogDate } from '@/lib/blog/date';
10+
import { shouldBypassImageOptimization } from '@/lib/blog/image';
1011

1112
export const revalidate = 0;
1213

@@ -285,6 +286,7 @@ function renderPortableText(
285286
alt={postTitle || 'Post image'}
286287
width={1200}
287288
height={800}
289+
unoptimized={shouldBypassImageOptimization(block.url)}
288290
sizes="100vw"
289291
className="my-6 h-auto w-full rounded-xl border border-gray-200"
290292
/>
@@ -577,6 +579,7 @@ export default async function PostDetails({
577579
src={post.mainImage}
578580
alt={post.title || 'Post image'}
579581
fill
582+
unoptimized={shouldBypassImageOptimization(post.mainImage)}
580583
className="object-contain"
581584
/>
582585
</div>
@@ -618,6 +621,9 @@ export default async function PostDetails({
618621
src={item.mainImage}
619622
alt={item.title || 'Post image'}
620623
fill
624+
unoptimized={shouldBypassImageOptimization(
625+
item.mainImage
626+
)}
621627
className="object-cover transition-transform duration-300 group-hover:scale-[1.03]"
622628
/>
623629
</div>
@@ -640,6 +646,9 @@ export default async function PostDetails({
640646
src={item.author.image}
641647
alt={item.author.name || 'Author'}
642648
fill
649+
unoptimized={shouldBypassImageOptimization(
650+
item.author.image
651+
)}
643652
className="object-cover"
644653
/>
645654
</span>

0 commit comments

Comments
 (0)