Skip to content
Open
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
2 changes: 1 addition & 1 deletion app/[locale]/daily-lessons/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async function DailyLessonsPage() {
return (
<div className="page-shell">
<div className="page-shell-content section-container section-container-xl section-spacing-md space-y-6">
<section className="glass-card rounded-3xl p-6 md:p-8" data-testid="daily-lessons-hero">
<section className="glass-card rounded-3xl card-padding-lg md:p-8" data-testid="daily-lessons-hero">
<div className="flex flex-col gap-5 md:flex-row md:items-center md:justify-between">
<div className="space-y-3">
<Badge
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/notifications/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default async function NotificationsPage() {
return (
<div className="page-shell">
<div className="page-shell-content section-container section-container-xl section-spacing-md space-y-6">
<section data-testid="notifications-hero" className="glass-card rounded-3xl p-6 md:p-8">
<section data-testid="notifications-hero" className="glass-card rounded-3xl card-padding-lg md:p-8">
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div className="space-y-2">
<h1 className="text-2xl font-bold text-white md:text-3xl">{t('title')}</h1>
Expand Down
8 changes: 4 additions & 4 deletions app/[locale]/practice/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function PracticePage() {
</div>
</section>

<div className="space-y-4 rounded-3xl border border-border/60 bg-black/30 p-6">
<div className="space-y-4 rounded-3xl border border-border/60 bg-black/30 card-padding-lg md:p-7">
<div className="flex flex-wrap gap-2">
<DeckToggle
label={t('savedDeck.badge')}
Expand Down Expand Up @@ -159,20 +159,20 @@ export default function PracticePage() {
</Alert>
) : (
<div className="space-y-4">
<div className="rounded-3xl border border-border/60 bg-black/40 p-8">
<div className="rounded-3xl border border-border/60 bg-black/40 card-padding-lg md:p-8">
<div className="flex items-center justify-between text-xs uppercase tracking-[0.3em] text-muted-foreground">
<span>{currentCard?.direction === 'en-mk' ? 'EN → MK' : 'MK → EN'}</span>
<span>
{safeIndex + 1} / {total}
</span>
</div>
<div className="mt-8 space-y-4">
<div className="mt-6 space-y-4">
<p className="text-2xl font-semibold text-white">{currentCard?.source}</p>
<p className={cn('text-lg text-primary transition-opacity', revealed ? 'opacity-100' : 'opacity-0')}>
{currentCard?.target}
</p>
</div>
<div className="mt-10 grid gap-3 sm:grid-cols-3">
<div className="mt-8 grid gap-3 sm:grid-cols-3">
<Button variant="outline" className="rounded-full" onClick={goPrevious}>
<ArrowLeft className="mr-2 h-4 w-4" aria-hidden="true" />
Prev
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function ProfilePage() {
return (
<div className="page-shell">
<div className="page-shell-content section-container section-container-xl section-spacing-md space-y-6">
<section data-testid="profile-hero" className="glass-card rounded-3xl p-6 md:p-8">
<section data-testid="profile-hero" className="glass-card rounded-3xl card-padding-lg md:p-8">
<div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
<div className="space-y-3">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-primary/80">{t('title')}</p>
Expand Down
10 changes: 5 additions & 5 deletions app/[locale]/translate/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export default function TranslatePage() {
swapLabel={t('swapDirections')}
/>
<form
className="rounded-3xl border border-border/60 bg-black/30 p-6"
className="rounded-3xl border border-border/60 bg-black/30 card-padding-lg md:p-7"
onSubmit={(event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
void handleTranslate(event);
Expand Down Expand Up @@ -247,7 +247,7 @@ export default function TranslatePage() {
</div>
</form>

<section className="space-y-4 rounded-3xl border border-border/60 bg-black/30 p-6">
<section className="space-y-4 rounded-3xl border border-border/60 bg-black/30 card-padding-lg md:p-7">
<div className="flex flex-wrap items-center gap-3">
<div>
<p className="text-[11px] uppercase tracking-[0.35em] text-muted-foreground">{t('resultLabel')}</p>
Expand Down Expand Up @@ -390,7 +390,7 @@ type DirectionToggleProps = {

function DirectionToggle({ options, activeId, onChange, onSwap, label, swapLabel }: DirectionToggleProps) {
return (
<div className="rounded-3xl border border-border/60 bg-black/30 p-4">
<div className="rounded-3xl border border-border/60 bg-black/30 card-padding">
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<p className="text-[11px] uppercase tracking-[0.35em] text-muted-foreground">{label}</p>
Expand All @@ -412,7 +412,7 @@ function DirectionToggle({ options, activeId, onChange, onSwap, label, swapLabel
key={option.id}
type="button"
className={cn(
'rounded-full px-4 py-2 text-sm font-semibold transition',
'touch-target rounded-full px-4 py-2 text-sm font-semibold transition',
option.id === activeId
? 'bg-primary text-primary-foreground'
: 'bg-transparent text-muted-foreground hover:text-foreground',
Expand Down Expand Up @@ -441,7 +441,7 @@ function PanelToggleButton({ icon: Icon, label, active, onClick }: PanelToggleBu
role="tab"
aria-selected={active}
className={cn(
'flex items-center gap-2 rounded-full px-4 py-2 text-xs font-semibold transition',
'touch-target flex items-center gap-2 rounded-full px-4 py-2 text-xs font-semibold transition',
active ? 'bg-white text-black' : 'text-muted-foreground hover:text-white',
)}
onClick={onClick}
Expand Down
166 changes: 161 additions & 5 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,94 @@
--color-card: var(--card);
}

:root {
--space-gutter: clamp(1rem, 3vw, 1.5rem);
--space-gutter-wide: clamp(1.125rem, 3.5vw, 1.75rem);
--space-section-sm: clamp(1.25rem, 3vw, 2.25rem);
--space-section-md: clamp(1.75rem, 4vw, 3rem);
--space-section-lg: clamp(2.5rem, 5vw, 3.75rem);
--card-padding: clamp(1rem, 3vw, 1.5rem);
--card-padding-lg: clamp(1.25rem, 4vw, 2rem);
--gap-compact: clamp(0.5rem, 2vw, 0.75rem);
--gap-cozy: clamp(0.75rem, 2.5vw, 1.125rem);
--text-sm-mobile: clamp(0.95rem, 0.6vw + 0.88rem, 1rem);
--text-xs-mobile: clamp(0.85rem, 0.5vw + 0.8rem, 0.92rem);
--mobile-nav-height: 56px;
--mobile-nav-height-max: 64px;
--touch-target-size: 44px;
--safe-area-top: env(safe-area-inset-top, 0px);
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
}

body {
font-family: var(--font-geist-sans, "Geist", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
background: var(--mk-bg);
color: var(--mk-text);
}

.section-container {
width: 100%;
padding-inline: var(--space-gutter);
margin-inline: auto;
position: relative;
}

@media (min-width: 960px) {
.section-container {
padding-inline: var(--space-gutter-wide);
}
}

.section-container-sm {
max-width: 40rem;
}

.section-container-md {
max-width: 48rem;
}

.section-container-lg {
max-width: 64rem;
}

.section-container-xl {
max-width: 80rem;
}

.section-container-2xl {
max-width: 96rem;
}

.section-container-content {
max-width: 56rem;
}

.section-container-wide {
max-width: 70rem;
}

.section-spacing-sm {
padding-block: var(--space-section-sm);
}

.section-spacing-md {
padding-block: var(--space-section-md);
}

.section-spacing-lg {
padding-block: var(--space-section-lg);
}

.section-spacing-xl {
padding-block: calc(var(--space-section-lg) + 1rem);
}

.page-shell,
.page-shell-content {
display: flex;
flex-direction: column;
}

@layer base {
* {
@apply border-border outline-ring/30;
Expand Down Expand Up @@ -111,24 +193,28 @@ body {
min-height: 100vh;
position: relative;
z-index: 0;
padding: 1.5rem;
padding: var(--space-gutter);
padding-top: calc(var(--space-section-sm) / 2 + var(--safe-area-top));
padding-bottom: calc(var(--space-section-sm) / 2 + var(--safe-area-bottom));
}

.app-shell-scroll {
min-height: 100vh;
scroll-padding-top: calc(var(--mobile-nav-height) + var(--safe-area-top));
}

.lab-hero {
border-radius: 32px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: linear-gradient(145deg, rgba(255, 255, 255, 0.04), rgba(0, 0, 0, 0.55));
padding: 1.75rem;
padding: var(--card-padding-lg);
gap: var(--gap-cozy);
box-shadow: var(--panel-shadow);
}

.lab-grid {
display: grid;
gap: 1.5rem;
gap: var(--gap-cozy);
}

@media (min-width: 1024px) {
Expand All @@ -141,7 +227,7 @@ body {
border-radius: 28px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(8, 8, 12, 0.7);
padding: 1.25rem;
padding: var(--card-padding);
box-shadow: var(--shadow-soft);
}

Expand Down Expand Up @@ -180,7 +266,77 @@ body {

.card-grid {
display: grid;
gap: 1rem;
gap: var(--gap-cozy);
}

.safe-top {
top: var(--safe-area-top);
}

.nav-toolbar {
min-height: var(--mobile-nav-height);
padding-block: clamp(0.75rem, 2vw, 0.95rem);
}

.nav-toolbar + .nav-toolbar-helper {
padding-top: clamp(0.35rem, 2vw, 0.75rem);
}

.nav-surface {
padding-top: var(--safe-area-top);
}

.shell-surface {
border-radius: 28px;
border: 1px solid rgba(255, 255, 255, 0.06);
background: rgba(0, 0, 0, 0.24);
box-shadow: var(--shadow-soft);
}

.card-padding {
padding: var(--card-padding);
}

.card-padding-lg {
padding: var(--card-padding-lg);
}

.stack-compact {
display: flex;
flex-direction: column;
gap: var(--gap-compact);
}

.stack-cozy {
display: flex;
flex-direction: column;
gap: var(--gap-cozy);
}

.touch-target {
min-height: var(--touch-target-size);
min-width: var(--touch-target-size);
}

@media (min-width: 768px) {
.nav-toolbar {
min-height: var(--mobile-nav-height-max);
padding-block: 1.1rem;
}
}

@media (max-width: 480px) {
.lab-hero {
border-radius: 24px;
}

.app-shell-main {
padding-inline: var(--space-gutter);
}

.section-heading {
font-size: clamp(1.15rem, 3vw, 1.5rem);
}
}

@media (min-width: 960px) {
Expand Down
18 changes: 9 additions & 9 deletions components/layout/TopNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ export function TopNav({

<nav
className={cn(
'w-full border-b border-white/5 bg-[#050918]/90 backdrop-blur-xl shadow-lg shadow-black/30 z-40',
sticky && 'sticky top-0',
'nav-surface w-full border-b border-white/5 bg-[#050918]/90 backdrop-blur-xl shadow-lg shadow-black/30 z-40',
sticky && 'sticky safe-top',
className
)}
aria-label={t('label')}
>
<div className="section-container section-container-wide flex flex-wrap items-center justify-between gap-3 py-3">
<div className="section-container section-container-wide nav-toolbar flex flex-wrap items-center justify-between gap-3">
<Link
href={`/${locale}`}
className="flex items-center gap-2 transition-opacity hover:opacity-80"
Expand All @@ -108,7 +108,7 @@ export function TopNav({
</div>
</div>

<div className="section-container section-container-wide pb-3">
<div className="nav-toolbar-helper section-container section-container-wide pb-3 hidden sm:block">
<MissionSummaryBanner
mission={mission}
state={missionState}
Expand Down Expand Up @@ -137,7 +137,7 @@ type MissionSummaryBannerProps = {
function MissionSummaryBanner({ mission, state, error, onRefresh, t, buildHref }: MissionSummaryBannerProps) {
if (state === 'loading') {
return (
<div className="flex items-center gap-3 rounded-2xl border border-white/5 bg-[#0f162e]/80 px-4 py-3 text-sm text-slate-300">
<div className="flex items-center gap-3 rounded-2xl border border-white/5 bg-[#0f162e]/80 card-padding text-sm text-slate-300">
<Loader2 className="h-4 w-4 animate-spin" aria-hidden="true" />
{t('summaryLoading')}
</div>
Expand All @@ -146,15 +146,15 @@ function MissionSummaryBanner({ mission, state, error, onRefresh, t, buildHref }

if (state === 'error') {
return (
<div className="flex flex-wrap items-center gap-3 rounded-2xl border border-red-500/40 bg-red-900/20 px-4 py-3 text-sm text-red-200">
<div className="flex flex-wrap items-center gap-3 rounded-2xl border border-red-500/40 bg-red-900/20 card-padding text-sm text-red-200">
<div className="flex items-center gap-2">
<AlertCircle className="h-4 w-4" aria-hidden="true" />
<span>{error ?? t('summaryError')}</span>
</div>
<button
type="button"
onClick={onRefresh}
className="rounded-full border border-red-400/60 px-3 py-1 text-xs font-semibold text-red-100 transition-all hover:bg-red-500/20"
className="touch-target rounded-full border border-red-400/60 px-3 py-1 text-xs font-semibold text-red-100 transition-all hover:bg-red-500/20"
>
{t('retry')}
</button>
Expand All @@ -171,8 +171,8 @@ function MissionSummaryBanner({ mission, state, error, onRefresh, t, buildHref }
});

return (
<div className="flex flex-wrap items-center gap-4 rounded-2xl border border-white/5 bg-[#0f162e]/80 px-4 py-4">
<div className="flex flex-1 flex-wrap items-center gap-4">
<div className="flex flex-wrap items-center gap-3 rounded-2xl border border-white/5 bg-[#0f162e]/80 card-padding">
<div className="flex flex-1 flex-wrap items-center gap-3">
<div className="flex items-center gap-3">
<span className="flex h-11 w-11 items-center justify-center rounded-2xl bg-[var(--brand-red)]/10 text-[var(--brand-red)]">
<Flame className="h-5 w-5" aria-hidden="true" />
Expand Down
2 changes: 1 addition & 1 deletion components/notifications/NotificationsInbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function NotificationsInbox({ className, dataTestId }: NotificationsInbox
const notifications = data?.notifications || [];
const unreadCount = notifications.filter((n) => !n.isRead).length;
const cardClasses = cn(
'glass-card border border-white/10 p-6 md:p-8 text-white space-y-6',
'glass-card border border-white/10 card-padding-lg md:p-8 text-white space-y-6',
className
);

Expand Down
Loading