Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 26 additions & 32 deletions frontend/app/[locale]/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PostAuthQuizSync } from '@/components/auth/PostAuthQuizSync';
import { ProfileCard } from '@/components/dashboard/ProfileCard';
import { QuizSavedBanner } from '@/components/dashboard/QuizSavedBanner';
import { StatsCard } from '@/components/dashboard/StatsCard';
import { DynamicGridBackground } from '@/components/shared/DynamicGridBackground';
import { getUserQuizStats } from '@/db/queries/quiz';
import { getUserProfile } from '@/db/queries/users';
import { redirect } from '@/i18n/routing';
Expand Down Expand Up @@ -75,42 +76,35 @@ export default async function DashboardPage({
};

const outlineBtnStyles =
'inline-flex items-center justify-center rounded-full border border-slate-200 dark:border-slate-700 bg-white/50 dark:bg-slate-900/50 backdrop-blur-sm px-6 py-2 text-sm font-medium text-slate-600 dark:text-slate-300 transition-colors hover:bg-white hover:text-sky-600 dark:hover:bg-slate-800 dark:hover:text-sky-400';
'inline-flex items-center justify-center rounded-full border border-gray-200 dark:border-white/10 bg-white/50 dark:bg-neutral-900/50 backdrop-blur-sm px-6 py-2 text-sm font-medium text-gray-600 dark:text-gray-300 transition-colors hover:bg-white hover:text-(--accent-primary) dark:hover:bg-neutral-800 dark:hover:text-(--accent-primary)';

return (
<main className="relative min-h-[calc(100vh-80px)] overflow-hidden">
<div className="min-h-screen">
<PostAuthQuizSync />
<div
className="pointer-events-none absolute inset-0 -z-10"
aria-hidden="true"
<DynamicGridBackground
showStaticGrid
className="min-h-screen bg-gray-50 py-12 transition-colors duration-300 dark:bg-transparent"
>
<div className="absolute inset-0 bg-linear-to-b from-sky-50 via-white to-rose-50 dark:from-slate-950 dark:via-slate-950 dark:to-black" />
<div className="absolute top-0 left-1/4 h-96 w-xl -translate-x-1/2 rounded-full bg-sky-300/20 blur-3xl dark:bg-sky-500/10" />
<div className="absolute right-0 bottom-0 h-104 w-104 rounded-full bg-violet-300/30 blur-3xl dark:bg-violet-500/10" />
<div className="absolute bottom-10 left-10 h-80 w-[20rem] rounded-full bg-pink-300/20 blur-3xl dark:bg-fuchsia-500/10" />
</div>

<div className="relative z-10 mx-auto max-w-5xl px-6 py-12">
<header className="mb-12 flex flex-col justify-between gap-6 md:flex-row md:items-center">
<div>
<h1 className="text-4xl font-black tracking-tight drop-shadow-sm md:text-5xl">
<span className="bg-linear-to-r from-sky-400 via-violet-400 to-pink-400 bg-clip-text text-transparent dark:from-sky-400 dark:via-indigo-400 dark:to-fuchsia-500">
{t('title')}
</span>
</h1>
<p className="mt-2 text-lg text-slate-600 dark:text-slate-400">
{t('subtitle')}
</p>
<main className="relative z-10 mx-auto max-w-5xl px-6">
<header className="mb-12 flex flex-col justify-between gap-6 md:flex-row md:items-center">
<div>
<h1 className="text-4xl font-black tracking-tight md:text-5xl">
<span className="text-(--accent-primary)">{t('title')}</span>
</h1>
<p className="mt-2 text-lg text-gray-600 dark:text-gray-400">
{t('subtitle')}
</p>
</div>

<span className={outlineBtnStyles}>{t('supportLink')}</span>
</header>
<QuizSavedBanner />
<div className="grid gap-8 md:grid-cols-2">
<ProfileCard user={userForDisplay} locale={locale} />
<StatsCard stats={stats} />
</div>

<span className={outlineBtnStyles}>{t('supportLink')}</span>
</header>
<QuizSavedBanner />
<div className="grid gap-8 md:grid-cols-2">
<ProfileCard user={userForDisplay} locale={locale} />
<StatsCard stats={stats} />
</div>
</div>
</main>
</main>
</DynamicGridBackground>
</div>
);
}
22 changes: 11 additions & 11 deletions frontend/app/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ export default async function NotFound() {
return (
<main className="bg-background relative flex min-h-screen items-center justify-center overflow-hidden transition-colors duration-300">
<div className="pointer-events-none absolute inset-0 opacity-60">
<div className="absolute -top-32 left-1/2 h-96 w-[36rem] -translate-x-1/2 rounded-full bg-[var(--accent-primary)]/20 blur-3xl" />
<div className="absolute bottom-[-12rem] left-1/4 h-[22rem] w-[22rem] rounded-full bg-[var(--accent-hover)]/15 blur-3xl" />
<div className="absolute right-0 bottom-[-10rem] h-[26rem] w-[26rem] rounded-full bg-[var(--accent-primary)]/25 blur-3xl" />
<div className="absolute -top-32 left-1/2 h-96 w-xl -translate-x-1/2 rounded-full bg-(--accent-primary)/20 blur-3xl" />
<div className="absolute -bottom-48 left-1/4 h-88 w-88 rounded-full bg-(--accent-hover)/15 blur-3xl" />
<div className="absolute -bottom-40 right-0 h-104 w-104 rounded-full bg-(--accent-primary)/25 blur-3xl" />
Comment on lines +29 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find Tailwind configuration files
fd -E node_modules -type f -name 'tailwind.config.*' -o -name 'tailwind.js'

Repository: DevLoversTeam/devlovers.net

Length of output: 241


🏁 Script executed:

# Check for common config locations and list the repository root
git ls-files | head -30

Repository: DevLoversTeam/devlovers.net

Length of output: 913


🏁 Script executed:

# Look for postcss or other config files that might define Tailwind extensions
fd -E node_modules -type f \( -name 'postcss.config.*' -o -name 'tsconfig.json' -o -name 'next.config.*' \)

Repository: DevLoversTeam/devlovers.net

Length of output: 241


🏁 Script executed:

# Find tailwind config files
find . -name "tailwind.config.*" -o -name "tailwind.js" 2>/dev/null

Repository: DevLoversTeam/devlovers.net

Length of output: 53


🏁 Script executed:

# Check the frontend directory structure
ls -la frontend/ | grep -E "config|tailwind"

Repository: DevLoversTeam/devlovers.net

Length of output: 483


🏁 Script executed:

# Also check for CSS files that might define these tokens
find frontend -name "*.css" -o -name "globals.css" 2>/dev/null | head -20

Repository: DevLoversTeam/devlovers.net

Length of output: 95


🏁 Script executed:

# Check postcss config
cat frontend/postcss.config.mjs

Repository: DevLoversTeam/devlovers.net

Length of output: 164


🏁 Script executed:

# Check globals CSS file
cat frontend/app/globals.css

Repository: DevLoversTeam/devlovers.net

Length of output: 12494


🏁 Script executed:

# Search for tailwind configuration in all files
rg "tailwindConfig|theme.*extend" frontend/ -A 5 -B 2

Repository: DevLoversTeam/devlovers.net

Length of output: 53


🏁 Script executed:

# Also search for these specific size definitions
rg "w-xl|h-88|h-104|w-104" frontend/ --type ts --type tsx --type css

Repository: DevLoversTeam/devlovers.net

Length of output: 98


🏁 Script executed:

# Read the not-found.tsx file to see the actual code
cat -n frontend/app/not-found.tsx

Repository: DevLoversTeam/devlovers.net

Length of output: 3959


🏁 Script executed:

# Search for custom size definitions in CSS or config files
rg "w-xl|h-88|w-88|h-104|w-104|spacing|width|height" frontend/app/globals.css

Repository: DevLoversTeam/devlovers.net

Length of output: 141


🏁 Script executed:

# Search across entire frontend for these custom classes
rg "w-xl|h-88|w-88|h-104|w-104" frontend/ -t css

Repository: DevLoversTeam/devlovers.net

Length of output: 53


🏁 Script executed:

# Search for any other file that might define these custom sizing tokens
rg "@theme|extend.*spacing|extend.*width|extend.*height" frontend/ -A 10

Repository: DevLoversTeam/devlovers.net

Length of output: 1328


🏁 Script executed:

# Check if there are any CSS module files that might define these
find frontend -name "*.module.css" -o -name "*.module.scss" 2>/dev/null

Repository: DevLoversTeam/devlovers.net

Length of output: 53


🏁 Script executed:

# Verify these are not standard Tailwind v4 defaults by checking what h-96 maps to
rg "h-96|w-80" frontend/app/globals.css

Repository: DevLoversTeam/devlovers.net

Length of output: 53


Add missing custom size tokens to Tailwind configuration.

The custom size utilities used in the decorative elements—w-xl, h-88, w-88, h-104, w-104—are not defined in the Tailwind v4 theme configuration in frontend/app/globals.css. These classes will not be generated, causing the blur divs to fail to render with intended dimensions.

Add these spacing definitions to the @theme block in frontend/app/globals.css:

--spacing-xl: /* define appropriate size */
--spacing-88: /* define appropriate size */
--spacing-104: /* define appropriate size */

Alternatively, if using custom names, ensure they map correctly to width/height utilities in the Tailwind configuration.

🤖 Prompt for AI Agents
In `@frontend/app/not-found.tsx` around lines 29 - 31, The decorative divs use
custom utilities (w-xl, h-88, w-88, h-104, w-104) that are not defined — update
your Tailwind/theme setup in frontend/app/globals.css by adding the missing size
tokens (e.g. --spacing-xl, --spacing-88, --spacing-104) inside the `@theme` block
and ensure your Tailwind theme/spacing extension maps those tokens to concrete
values (or add matching spacing keys like xl, 88, 104 in the Tailwind config) so
the width/height utilities referenced by w-xl, h-88, w-88, h-104 and w-104 are
generated and usable.

</div>

<div className="pointer-events-none absolute inset-0 opacity-40 dark:opacity-60">
<span className="absolute top-[18%] left-[10%] h-1 w-1 rounded-full bg-[var(--accent-primary)]" />
<span className="absolute top-[8%] left-[35%] h-1 w-1 rounded-full bg-[var(--accent-hover)]" />
<span className="absolute top-[16%] left-[70%] h-1 w-1 rounded-full bg-[var(--accent-primary)]" />
<span className="absolute top-[40%] left-[80%] h-1 w-1 rounded-full bg-[var(--accent-hover)]" />
<span className="absolute top-[60%] left-[18%] h-1 w-1 rounded-full bg-[var(--accent-primary)]" />
<span className="absolute top-[18%] left-[10%] h-1 w-1 rounded-full bg-(--accent-primary)" />
<span className="absolute top-[8%] left-[35%] h-1 w-1 rounded-full bg-(--accent-hover)" />
<span className="absolute top-[16%] left-[70%] h-1 w-1 rounded-full bg-(--accent-primary)" />
<span className="absolute top-[40%] left-[80%] h-1 w-1 rounded-full bg-(--accent-hover)" />
<span className="absolute top-[60%] left-[18%] h-1 w-1 rounded-full bg-(--accent-primary)" />
</div>

<div className="relative z-10 px-6 py-12 text-center">
<div className="relative mt-4 inline-block">
<h1 className="text-4xl font-black tracking-tight sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl">
<span className="relative inline-block bg-gradient-to-r from-[var(--accent-primary)]/70 via-[color-mix(in_srgb,var(--accent-primary)_70%,white)]/70 to-[var(--accent-hover)]/70 bg-clip-text text-transparent">
<span className="relative inline-block bg-linear-to-r from-(--accent-primary)/70 via-[color-mix(in_srgb,var(--accent-primary)_70%,white)]/70 to-(--accent-hover)/70 bg-clip-text text-transparent">
DevL
</span>
<span
Expand All @@ -51,7 +51,7 @@ export default async function NotFound() {
>
Ø
</span>
<span className="relative inline-block bg-gradient-to-r from-[var(--accent-primary)]/70 via-[color-mix(in_srgb,var(--accent-primary)_70%,white)]/70 to-[var(--accent-hover)]/70 bg-clip-text text-transparent">
<span className="relative inline-block bg-linear-to-r from-(--accent-primary)/70 via-[color-mix(in_srgb,var(--accent-primary)_70%,white)]/70 to-(--accent-hover)/70 bg-clip-text text-transparent">
vers
</span>
</h1>
Expand All @@ -67,7 +67,7 @@ export default async function NotFound() {

<a
href={`/${locale}`}
className="mt-8 inline-flex items-center justify-center rounded-full bg-[var(--accent-primary)] px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-[var(--accent-hover)]"
className="mt-8 inline-flex items-center justify-center rounded-full bg-(--accent-primary) px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-(--accent-hover)"
>
{t.backHome}
</a>
Expand Down
30 changes: 14 additions & 16 deletions frontend/components/dashboard/ProfileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,56 @@ export function ProfileCard({ user, locale }: ProfileCardProps) {
const t = useTranslations('dashboard.profile');

const cardStyles = `
relative overflow-hidden rounded-[2rem]
border border-slate-200/70 dark:border-slate-700/80
bg-white/60 dark:bg-slate-900/60 backdrop-blur-md
shadow-[0_18px_45px_rgba(15,23,42,0.05)]
dark:shadow-[0_22px_60px_rgba(0,0,0,0.2)]
p-8 transition-all hover:border-sky-200 dark:hover:border-sky-800
relative overflow-hidden rounded-2xl
border border-gray-100 dark:border-white/5
bg-white/60 dark:bg-neutral-900/60 backdrop-blur-xl
p-8 transition-all hover:border-(--accent-primary)/30 dark:hover:border-(--accent-primary)/30
`;

return (
<section className={cardStyles} aria-labelledby="profile-heading">
<div className="flex items-start gap-6">
<div
className="relative rounded-full bg-gradient-to-br from-sky-400 to-pink-400 p-[3px]"
className="relative rounded-full bg-linear-to-br from-(--accent-primary) to-(--accent-hover) p-0.75"
aria-hidden="true"
>
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-white text-3xl font-bold text-slate-700 dark:bg-slate-900 dark:text-slate-200">
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-white text-3xl font-bold text-gray-700 dark:bg-neutral-900 dark:text-gray-200">
{user.name?.[0]?.toUpperCase() || user.email[0].toUpperCase()}
</div>
</div>

<div className="flex-1">
<h2
id="profile-heading"
className="text-2xl font-bold text-slate-800 dark:text-slate-100"
className="text-2xl font-bold text-gray-900 dark:text-white"
>
{user.name || t('defaultName')}
</h2>
<p className="font-mono text-sm text-slate-500 dark:text-slate-400">
<p className="font-mono text-sm text-gray-500 dark:text-gray-400">
{user.email}
</p>

<div className="mt-3 inline-flex items-center rounded-full bg-sky-100 px-3 py-1 text-xs font-bold tracking-wider text-sky-700 uppercase dark:bg-sky-900/30 dark:text-sky-300">
<div className="mt-3 inline-flex items-center rounded-full bg-(--accent-primary)/10 px-3 py-1 text-xs font-bold tracking-wider text-(--accent-primary) uppercase">
{user.role || t('defaultRole')}
</div>
</div>
</div>

<dl className="mt-8 grid grid-cols-2 gap-6 border-t border-slate-100 pt-6 dark:border-slate-800/50">
<dl className="mt-8 grid grid-cols-2 gap-6 border-t border-gray-100 pt-6 dark:border-white/5">
<div>
<dt className="text-xs font-semibold tracking-wider text-slate-400 uppercase">
<dt className="text-xs font-semibold tracking-wider text-gray-400 uppercase">
{t('totalPoints')}
</dt>

<dd className="mt-1 text-3xl font-black text-slate-800 dark:text-white">
<dd className="mt-1 text-3xl font-black text-gray-900 dark:text-white">
{user.points}
</dd>
</div>
<div>
<dt className="text-xs font-semibold tracking-wider text-slate-400 uppercase">
<dt className="text-xs font-semibold tracking-wider text-gray-400 uppercase">
{t('joined')}
</dt>
<dd className="mt-2 text-lg font-medium text-slate-700 dark:text-slate-300">
<dd className="mt-2 text-lg font-medium text-gray-700 dark:text-gray-300">
{user.createdAt
? new Date(user.createdAt).toLocaleDateString(locale)
: '-'}
Expand Down
10 changes: 5 additions & 5 deletions frontend/components/dashboard/QuizSavedBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ export function QuizSavedBanner() {
if (!info) return null;

return (
<div className="mb-6 rounded-xl border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-900/20">
<div className="mb-6 rounded-xl border border-green-500/20 bg-green-500/10 p-4 backdrop-blur-sm">
<div className="space-y-2 text-center">
<p className="text-lg font-medium text-green-800 dark:text-green-200">
<p className="text-lg font-medium text-green-700 dark:text-green-300">
🎉 {t('title')}
</p>
<p className="text-green-700 dark:text-green-300">
<p className="text-green-600 dark:text-green-400">
{t('scored')}{' '}
<strong>
{info.score}/{info.total}
Expand All @@ -62,13 +62,13 @@ export function QuizSavedBanner() {
<div className="flex justify-center gap-3 pt-2">
<Link
href="/leaderboard"
className="text-green-600 underline hover:no-underline dark:text-green-400"
className="font-medium text-green-600 underline hover:no-underline dark:text-green-400"
>
{t('viewLeaderboard')}
</Link>
<Link
href={`/quiz/${info.quizSlug}`}
className="text-green-600 underline hover:no-underline dark:text-green-400"
className="font-medium text-green-600 underline hover:no-underline dark:text-green-400"
>
{t('tryAgain')}
</Link>
Expand Down
38 changes: 15 additions & 23 deletions frontend/components/dashboard/StatsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,69 +18,61 @@ export function StatsCard({ stats }: StatsCardProps) {
const hasActivity = stats && stats.totalAttempts > 0;

const cardStyles = `
relative overflow-hidden rounded-[2rem]
border border-slate-200/70 dark:border-slate-700/80
bg-white/60 dark:bg-slate-900/60 backdrop-blur-md
shadow-[0_18px_45px_rgba(15,23,42,0.05)]
dark:shadow-[0_22px_60px_rgba(0,0,0,0.2)]
p-8 transition-all hover:border-sky-200 dark:hover:border-sky-800
relative overflow-hidden rounded-2xl
border border-gray-100 dark:border-white/5
bg-white/60 dark:bg-neutral-900/60 backdrop-blur-xl
p-8 transition-all hover:border-[var(--accent-primary)]/30 dark:hover:border-[var(--accent-primary)]/30
flex flex-col items-center justify-center text-center
`;

const primaryBtnStyles = `
group relative inline-flex items-center justify-center rounded-full
px-8 py-3 text-sm font-semibold tracking-widest uppercase text-white
bg-gradient-to-r from-sky-500 via-indigo-500 to-pink-500
shadow-[0_4px_14px_rgba(56,189,248,0.4)]
dark:shadow-[0_4px_20px_rgba(129,140,248,0.4)]
transition-all hover:scale-105 hover:shadow-lg
bg-[var(--accent-primary)] hover:bg-[var(--accent-hover)]
transition-all hover:scale-105
`;

return (
<section className={cardStyles} aria-labelledby="stats-heading">
<div
className="mb-6 rounded-full bg-slate-50 p-4 shadow-inner dark:bg-slate-800/50"
className="mb-6 rounded-full bg-gray-100 p-4 dark:bg-neutral-800/50"
aria-hidden="true"
>
<span className="text-4xl">📊</span>
</div>

<h3
id="stats-heading"
className="mb-2 text-xl font-bold text-slate-800 dark:text-slate-100"
className="mb-2 text-xl font-bold text-gray-900 dark:text-white"
>
{t('title')}
</h3>

{!hasActivity ? (
<>
<p className="mx-auto mb-8 max-w-xs text-slate-500 dark:text-slate-400">
<p className="mx-auto mb-8 max-w-xs text-gray-500 dark:text-gray-400">
{t('noActivity')}
</p>
<Link href="/quizzes" className={primaryBtnStyles}>
<span className="relative z-10">{t('startQuiz')}</span>
<span
className="absolute inset-0 rounded-full bg-gradient-to-r from-white/20 to-transparent opacity-0 transition-opacity group-hover:opacity-100"
aria-hidden="true"
/>
</Link>
</>
) : (
<dl className="mt-2 grid w-full grid-cols-2 gap-4">
<div className="rounded-2xl border border-slate-100 bg-slate-50/50 p-4 dark:border-slate-700 dark:bg-slate-800/50">
<dt className="mb-1 flex items-center justify-center gap-2 text-xs font-semibold tracking-wider text-slate-400 uppercase">
<div className="rounded-xl border border-gray-100 bg-gray-50/50 p-4 dark:border-white/5 dark:bg-neutral-800/50">
<dt className="mb-1 flex items-center justify-center gap-2 text-xs font-semibold tracking-wider text-gray-400 uppercase">
<History className="h-3 w-3" /> {t('attempts')}
</dt>
<dd className="text-2xl font-black text-slate-800 dark:text-white">
<dd className="text-2xl font-black text-gray-900 dark:text-white">
{stats?.totalAttempts}
</dd>
</div>

<div className="rounded-2xl border border-slate-100 bg-slate-50/50 p-4 dark:border-slate-700 dark:bg-slate-800/50">
<dt className="mb-1 flex items-center justify-center gap-2 text-xs font-semibold tracking-wider text-slate-400 uppercase">
<div className="rounded-xl border border-gray-100 bg-gray-50/50 p-4 dark:border-white/5 dark:bg-neutral-800/50">
<dt className="mb-1 flex items-center justify-center gap-2 text-xs font-semibold tracking-wider text-gray-400 uppercase">
<TrendingUp className="h-3 w-3" /> {t('avgScore')}
</dt>
<dd className="text-2xl font-black text-slate-800 dark:text-white">
<dd className="text-2xl font-black text-gray-900 dark:text-white">
{stats?.averageScore}%
</dd>
</div>
Expand Down
Loading