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
File renamed without changes.
4 changes: 4 additions & 0 deletions app/globals.css → app/[locale]/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@
transform: translateY(0);
}
}

.input-ghost:focus {
@apply focus:outline-primary;
}
41 changes: 41 additions & 0 deletions app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { GeistSans } from "geist/font/sans";
import "./globals.css";
import {ReactNode} from 'react';
import {getTranslations, unstable_setRequestLocale} from 'next-intl/server';
import {locales} from '../../config';

type Props = {
children: ReactNode;
params: {locale: string};
};

export function generateStaticParams() {
return locales.map((locale) => ({locale}));
}

export async function generateMetadata({
params: {locale}
}: Omit<Props, 'children'>) {
const t = await getTranslations({locale, namespace: 'LocaleLayout'});

return {
title: t('title')
};
}

export default function RootLayout({
children,
params: {locale}
}: Props) {
unstable_setRequestLocale(locale);

return (
<html lang={locale} className={GeistSans.className}>
<body className="bg-base-300 text-base-content">
<main className="min-h-screen flex flex-col items-center">
{children}
</main>
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';
import { useState } from 'react';
import Eye from '../../../public/Eye.svg';
import Eye from '@/public/Eye.svg';
import Image from 'next/image';

export default function PasswordInput() {
Expand All @@ -10,9 +10,9 @@ export default function PasswordInput() {
setPasswordShown(!passwordShown);
};
return (
<div className='relative flex items-center justify-center border rounded-md'>
<div className='relative flex items-center justify-center'>
<input
className={`'text-xs rounded-md px-4 py-2 bg-inherit flex-1`}
className={`'text-xs input input-ghost input-bordered px-4 py-2 bg-inherit flex-1`}
type={passwordShown ? 'text' : 'password'}
name='password'
required
Expand All @@ -22,4 +22,4 @@ export default function PasswordInput() {
</button>
</div>
);
}
}
95 changes: 95 additions & 0 deletions app/[locale]/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import Checkbox from "./components/Checkbox";
import { signIn } from "@/utils/supabase/auth";
import Link from "next/link";
import ETSImage from "@/components/ETSImage";
import PasswordInput from "./components/PasswordInput";
import Alert from "@/components/Alert";
import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
import { useTranslations } from "next-intl";
import { unstable_setRequestLocale } from "next-intl/server";
import ThemeButton from "@/components/themeButton";
import LanguageButton from "@/components/languageButton";
import Footer from "@/components/Footer";

export default function Login({
searchParams,
params,
}: {
searchParams: { message: string; type: string };
params: { locale: string };
}) {
unstable_setRequestLocale(params.locale);
const t = useTranslations("Login");
return (
<div className="flex justify-center items-center h-screen">
<div className="grid justify-items-center content-center bg-base-100 rounded-2xl w-[36rem]">
<h1 className="py-10 text-4xl">{t("welcome")}</h1>
<div className="flex-1 flex flex-col w-full px-8 justify-center gap-2">
<div className="mx-16">
<form
className="flex-1 flex flex-col w-full justify-center gap-2"
action={signIn}
>
{searchParams?.message && (
<Alert
customStyle={
"flex flex-1 flex-col w-full pb-2 justify-center gap-2"
}
text={searchParams.message}
alertType={searchParams.type}
icon={faTriangleExclamation}
/>
)}
<label className="text-md" htmlFor="email">
{t("email")}
</label>
<input
className="input input-ghost input-bordered px-4 py-2 mb-6"
name="email"
required
/>
<label className="text-md" htmlFor="password">
{t("password")}
</label>
<PasswordInput />
<Checkbox
checked={true}
style="self-end pb-6 font-semibold"
text={t("remember-me")}
/>
<button className="btn btn-primary rounded-md text-base mb-2">
{t("login")}
</button>
</form>
</div>

<div className="text-s mt-10">
<div className="flex justify-center mb-3">
<p className="">
{t("forgot-info")}
<Link
href={"/forgotPassword"}
className="pl-1 underline text-primary font-semibold"
>
{t("reset-password")}
</Link>
</p>
</div>
<div className="flex justify-center">
<p className="pb-10">
{t("no-account")}
<Link
href={"/signUp"}
className="pl-1 underline text-primary font-semibold"
>
{t("signup")}
</Link>
</p>
</div>
</div>
</div>
</div>
<Footer locale={params.locale} />
</div>
);
}
5 changes: 5 additions & 0 deletions app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AuthButton from "../../components/AuthButton";

export default function Index() {
return <AuthButton />;
}
Binary file removed app/favicon.ico
Binary file not shown.
33 changes: 8 additions & 25 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
import { GeistSans } from "geist/font/sans";
import "./globals.css";
import {ReactNode} from 'react';

const defaultUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "http://localhost:3000";

export const metadata = {
metadataBase: new URL(defaultUrl),
title: "Next.js and Supabase Starter Kit",
description: "The fastest way to build apps with Next.js and Supabase",
type Props = {
children: ReactNode;
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={GeistSans.className}>
<body className="bg-background text-foreground">
<main className="min-h-screen flex flex-col items-center">
{children}
</main>
</body>
</html>
);
}
// Since we have a `not-found.tsx` page on the root, a layout file
// is required, even if it's just passing children through.
export default function RootLayout({children}: Props) {
return children;
}
65 changes: 0 additions & 65 deletions app/login/page.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import Error from 'next/error';

// Render the default Next.js 404 page when a route
// is requested that doesn't match the middleware and
// therefore doesn't have a locale associated with it.

export default function NotFound() {
return (
<html lang="en">
<body>
<Error statusCode={404} />
</body>
</html>
);
}
Binary file removed app/opengraph-image.png
Binary file not shown.
11 changes: 5 additions & 6 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import AuthButton from "../components/AuthButton";
import {redirect} from 'next/navigation';

export default async function Index() {
return (
<AuthButton />
);
}
// This page only renders when the app is built statically (output: 'export')
export default function RootPage() {
redirect('/fr');
}
Binary file removed app/twitter-image.png
Binary file not shown.
42 changes: 42 additions & 0 deletions components/ETSImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client';

import Image, { StaticImageData } from "next/image";
import fr_dark from "@/public/ETS/dark/fr.png";
import en_dark from "@/public/ETS/dark/en.png";
import fr_light from "@/public/ETS/light/fr.png";
import en_light from "@/public/ETS/light/en.png";

interface Props {
lang: string;
isDarkTheme: boolean;
}

export default function ETSImage(props: Props) {
const theme = props.isDarkTheme ? "dark" : "light";

const images: {
dark: Record<string, StaticImageData>;
light: Record<string, StaticImageData>;
} = {
dark: {
fr: fr_dark,
en: en_dark,
},
light: {
fr: fr_light,
en: en_light,
},
};

const defaultImage = en_light;

const imageSrc: StaticImageData = images[theme]?.[props.lang] || defaultImage;

return (
<Image
src={imageSrc}
alt="ETS Logo"
width={200}
/>
);
}
35 changes: 35 additions & 0 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client';

import ETSImage from "@/components/ETSImage";
import ThemeButton from "@/components/themeButton";
import LanguageButton from "@/components/languageButton";
import { useState } from "react";

export default function Footer({
locale,
}: {
locale: string;
}) {
const [isDarkTheme, setIsDarkTheme] = useState(
localStorage.getItem("isdark") === "true"
);

const handleThemeChange = (isDark: boolean) => {
setIsDarkTheme(isDark);
};
return (
<>
<div className="flex flex-col absolute bottom-4 left-4 gap-2">
<div className="btn btn-circle btn-ghost">
<LanguageButton />
</div>
<div className="btn btn-circle btn-ghost">
<ThemeButton onThemeChange={handleThemeChange} />
</div>
</div>
<div className={`absolute bottom-4 right-4 bg-cover`}>
<ETSImage lang={locale} isDarkTheme={isDarkTheme} />
</div>
</>
);
}
Loading