Skip to content
Draft
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
6 changes: 3 additions & 3 deletions apps/landing_page/app/[locale]/i18n.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";

import { type Locale } from "@cookmate/i18n";
import { setupI18n, type Messages } from "@lingui/core";
import type { Locale } from "@cookmate/i18n";
import { type Messages, setupI18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react";
import { useMemo, type ReactNode } from "react";
import { type ReactNode, useMemo } from "react";

interface ClientI18nProviderProps {
children: ReactNode;
Expand Down
28 changes: 8 additions & 20 deletions apps/landing_page/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type React from "react";
import { defaultLocale, isValidLocale, loadCatalogMessages, type Locale, locales } from "@cookmate/i18n";
import { setupI18n } from "@lingui/core";
import { setI18n } from "@lingui/react/server";
import { Analytics } from "@vercel/analytics/next";
import type { Metadata, Viewport } from "next";
import { Barlow, Barlow_Semi_Condensed } from "next/font/google";
import { Analytics } from "@vercel/analytics/next";
import { setI18n } from "@lingui/react/server";
import { setupI18n, type Messages } from "@lingui/core";
import { locales, defaultLocale, type Locale, isValidLocale } from "@cookmate/i18n";
import type React from "react";
import { ClientI18nProvider } from "./i18n";
import "../globals.css";

Expand Down Expand Up @@ -32,11 +32,7 @@ export function generateStaticParams() {
}

// Localized metadata
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: Locale }>;
}): Promise<Metadata> {
export async function generateMetadata({ params }: { params: Promise<{ locale: Locale }> }): Promise<Metadata> {
const { locale } = await params;

const titles: Record<Locale, string> = {
Expand Down Expand Up @@ -137,13 +133,7 @@ export default async function LocaleLayout({
}>) {
const { locale: localeParam } = await params;
const validLocale = isValidLocale(localeParam) ? localeParam : defaultLocale;

const messageLoaders: Record<Locale, () => Promise<{ messages: Messages }>> = {
en: () => import("@cookmate/i18n/locales/en/messages"),
fr: () => import("@cookmate/i18n/locales/fr/messages"),
};
const loadMessages = messageLoaders[validLocale] ?? messageLoaders[defaultLocale];
const { messages } = await loadMessages();
const messages = await loadCatalogMessages(validLocale);

// Setup i18n for server components
const i18n = setupI18n({ locale: validLocale, messages: { [validLocale]: messages } });
Expand Down Expand Up @@ -207,9 +197,7 @@ export default async function LocaleLayout({

return (
<html lang={validLocale}>
<body
className={`${barlow.variable} ${barlowSemiCondensed.variable} font-sans antialiased`}
>
<body className={`${barlow.variable} ${barlowSemiCondensed.variable} font-sans antialiased`}>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
Expand Down
2 changes: 1 addition & 1 deletion apps/landing_page/app/[locale]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function Loading() {
return null
return null;
}
8 changes: 4 additions & 4 deletions apps/landing_page/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"use client"
"use client";

import { AuthProvider } from "@/lib/auth-context"
import { LandingPage } from "@/components/landing/landing-page"
import { LandingPage } from "@/components/landing/landing-page";
import { AuthProvider } from "@/lib/auth-context";

export default function Page() {
return (
<AuthProvider>
<LandingPage />
</AuthProvider>
)
);
}
36 changes: 26 additions & 10 deletions apps/landing_page/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,21 @@

/* Elevated card shadows */
.shadow-card {
box-shadow: 0 1px 3px hsl(var(--shadow-color) / 0.04), 0 4px 12px hsl(var(--shadow-color) / 0.06);
box-shadow:
0 1px 3px hsl(var(--shadow-color) / 0.04),
0 4px 12px hsl(var(--shadow-color) / 0.06);
}

.shadow-card-hover {
box-shadow: 0 2px 8px hsl(var(--shadow-color) / 0.06), 0 8px 24px hsl(var(--shadow-color) / 0.1);
box-shadow:
0 2px 8px hsl(var(--shadow-color) / 0.06),
0 8px 24px hsl(var(--shadow-color) / 0.1);
}

.shadow-elevated {
box-shadow: 0 4px 12px hsl(var(--shadow-color) / 0.08), 0 16px 48px hsl(var(--shadow-color) / 0.12);
box-shadow:
0 4px 12px hsl(var(--shadow-color) / 0.08),
0 16px 48px hsl(var(--shadow-color) / 0.12);
}

/* Scrollbar utilities */
Expand Down Expand Up @@ -314,20 +320,26 @@
background-color: var(--card);
border-radius: 1rem;
border: 1px solid var(--border);
box-shadow: 0 1px 3px hsl(var(--shadow-color) / 0.04), 0 4px 12px hsl(var(--shadow-color) / 0.06);
box-shadow:
0 1px 3px hsl(var(--shadow-color) / 0.04),
0 4px 12px hsl(var(--shadow-color) / 0.06);
transition: all 200ms ease-out;
}

.card-interactive {
background-color: var(--card);
border-radius: 1rem;
border: 1px solid var(--border);
box-shadow: 0 1px 3px hsl(var(--shadow-color) / 0.04), 0 4px 12px hsl(var(--shadow-color) / 0.06);
box-shadow:
0 1px 3px hsl(var(--shadow-color) / 0.04),
0 4px 12px hsl(var(--shadow-color) / 0.06);
transition: all 200ms ease-out;
cursor: pointer;
}
.card-interactive:hover {
box-shadow: 0 2px 8px hsl(var(--shadow-color) / 0.06), 0 8px 24px hsl(var(--shadow-color) / 0.1);
box-shadow:
0 2px 8px hsl(var(--shadow-color) / 0.06),
0 8px 24px hsl(var(--shadow-color) / 0.1);
border-color: var(--border-hover);
}

Expand All @@ -337,7 +349,8 @@

/* Floating orb animation */
@keyframes float {
0%, 100% {
0%,
100% {
transform: translate(0, 0) scale(1);
}
33% {
Expand All @@ -350,7 +363,8 @@

/* Slow pulse animation */
@keyframes slowPulse {
0%, 100% {
0%,
100% {
opacity: 0.4;
transform: scale(1);
}
Expand All @@ -362,7 +376,8 @@

/* Gentle drift animation */
@keyframes gentleDrift {
0%, 100% {
0%,
100% {
transform: translate(0, 0);
}
50% {
Expand All @@ -385,7 +400,8 @@

/* Orb glow animation */
@keyframes orbGlow {
0%, 100% {
0%,
100% {
opacity: 0.3;
filter: blur(60px);
}
Expand Down
6 changes: 3 additions & 3 deletions apps/landing_page/app/robots.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { MetadataRoute } from "next"
import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://cookmate.app"
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://cookmate.app";

return {
rules: {
userAgent: "*",
allow: "/",
},
sitemap: `${baseUrl}/sitemap.xml`,
}
};
}
2 changes: 1 addition & 1 deletion apps/landing_page/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MetadataRoute } from "next";
import { locales } from "@cookmate/i18n";
import type { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://cookmate.app";
Expand Down
57 changes: 28 additions & 29 deletions apps/landing_page/components/auth/auth-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,48 @@
"use client"
"use client";

import type React from "react"

import { useState } from "react"
import { X, Eye, EyeOff, Loader2, Mail, Lock, User } from "lucide-react"
import { useAuth } from "@/lib/auth-context"
import { Eye, EyeOff, Loader2, Lock, Mail, User, X } from "lucide-react";
import type React from "react";
import { useState } from "react";
import { useAuth } from "@/lib/auth-context";

interface AuthModalProps {
isOpen: boolean
onClose: () => void
defaultTab?: "login" | "signup"
isOpen: boolean;
onClose: () => void;
defaultTab?: "login" | "signup";
}

export function AuthModal({ isOpen, onClose, defaultTab = "login" }: AuthModalProps) {
const [activeTab, setActiveTab] = useState<"login" | "signup">(defaultTab)
const [showPassword, setShowPassword] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState("")
const [activeTab, setActiveTab] = useState<"login" | "signup">(defaultTab);
const [showPassword, setShowPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");

const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [name, setName] = useState("")
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");

const { login, signup } = useAuth()
const { login, signup } = useAuth();

if (!isOpen) return null
if (!isOpen) return null;

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError("")
setIsLoading(true)
e.preventDefault();
setError("");
setIsLoading(true);

try {
if (activeTab === "login") {
await login(email, password)
await login(email, password);
} else {
await signup(email, password, name)
await signup(email, password, name);
}
onClose()
} catch (err) {
setError("Une erreur est survenue. Veuillez réessayer.")
onClose();
} catch (_err) {
setError("Une erreur est survenue. Veuillez réessayer.");
} finally {
setIsLoading(false)
setIsLoading(false);
}
}
};

return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
Expand Down Expand Up @@ -220,5 +219,5 @@ export function AuthModal({ isOpen, onClose, defaultTab = "login" }: AuthModalPr
</form>
</div>
</div>
)
);
}
21 changes: 7 additions & 14 deletions apps/landing_page/components/landing/header.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import { Trans } from "@lingui/react/macro";
import Image from "next/image";
import Link from "next/link";
import iconImage from "@/app/icon.png";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import iconImage from "@/app/icon.png";
import { Trans } from "@lingui/react/macro";
import { useActiveSection } from "./hooks/use-active-section";
import { LocaleSwitcher } from "./locale-switcher";
import { NavButton } from "./ui/nav-button";
Expand All @@ -23,27 +23,20 @@ export function Header({ onLogin, onSignup }: HeaderProps) {
"fixed left-0 right-0 top-0 z-50 border-b border-border/60",
"bg-background/90 backdrop-blur-xl",
"shadow-[0_1px_0_rgba(0,0,0,0.04)]",
"supports-[backdrop-filter]:bg-background/80"
"supports-[backdrop-filter]:bg-background/80",
)}
>
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6">
<Link
className={cn(
"group flex items-center gap-2 rounded-full pr-2",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/40",
"focus-visible:ring-offset-2 focus-visible:ring-offset-background"
"focus-visible:ring-offset-2 focus-visible:ring-offset-background",
)}
href="/"
>
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-card/80 shadow-sm">
<Image
src={iconImage}
alt="Cookmate"
width={40}
height={40}
className="h-10 w-10"
priority
/>
<Image src={iconImage} alt="Cookmate" width={40} height={40} className="h-10 w-10" priority />
</span>
<span className="text-lg font-display text-foreground transition-colors group-hover:text-primary">
Cookmate
Expand All @@ -53,7 +46,7 @@ export function Header({ onLogin, onSignup }: HeaderProps) {
<nav
className={cn(
"hidden items-center gap-1 rounded-full p-1.5 md:flex",
"border border-border/70 bg-card/85 shadow-sm backdrop-blur"
"border border-border/70 bg-card/85 shadow-sm backdrop-blur",
)}
>
<NavButton href="#" active={activeSection === "home"}>
Expand All @@ -77,7 +70,7 @@ export function Header({ onLogin, onSignup }: HeaderProps) {
onClick={onLogin}
className={cn(
"hidden rounded-full px-4 text-sm font-medium transition-all md:flex",
"text-muted-foreground hover:bg-accent/20 hover:text-foreground"
"text-muted-foreground hover:bg-accent/20 hover:text-foreground",
)}
>
<Trans>Log in</Trans>
Expand Down
11 changes: 5 additions & 6 deletions apps/landing_page/components/landing/hooks/use-active-section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export function useActiveSection(): ActiveSection {
const featuresElement = document.getElementById("features");
const faqElement = document.getElementById("faq");

if (window.scrollY < 200 || (featuresElement && featuresElement.getBoundingClientRect().top > window.innerHeight * 0.3)) {
if (
window.scrollY < 200 ||
(featuresElement && featuresElement.getBoundingClientRect().top > window.innerHeight * 0.3)
) {
setActiveSection("home");
return;
}
Expand Down Expand Up @@ -48,11 +51,7 @@ export function useActiveSection(): ActiveSection {
const elementTop = rect.top + window.scrollY;
const distance = Math.abs(scrollPosition - elementTop);

if (
rect.top <= window.innerHeight * 0.5 &&
rect.bottom >= 0 &&
distance < closestDistance
) {
if (rect.top <= window.innerHeight * 0.5 && rect.bottom >= 0 && distance < closestDistance) {
closestDistance = distance;
closestSection = sectionId;
}
Expand Down
Loading