style: login page and logo
This commit is contained in:
7593
package-lock.json
generated
7593
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
"bcrypt": "^5.1.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "12.4.10",
|
||||
"i18next": "^24.2.2",
|
||||
"i18next-browser-languagedetector": "^8.0.4",
|
||||
"lucide-react": "^0.476.0",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { RegisterForm } from "@/components/auth/RegisterForm";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { useTranslate } from "@/hooks/useTranslate";
|
||||
import LanguageSelector from "@/components/LanguageSelector";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
interface LoginContentProps {
|
||||
searchParams: {
|
||||
@@ -19,20 +20,30 @@ export function LoginContent({ searchParams }: LoginContentProps) {
|
||||
|
||||
return (
|
||||
<div className="container relative min-h-screen flex-col items-center justify-center grid lg:max-w-none lg:grid-cols-2 lg:px-0">
|
||||
<div className="absolute top-4 right-4 z-50">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="absolute top-4 right-4 z-50 hover:scale-105 transition-transform"
|
||||
>
|
||||
<LanguageSelector />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="relative hidden h-full flex-col bg-slate-800/80 p-10 text-white lg:flex dark:border-r overflow-hidden">
|
||||
<div className="relative hidden h-full flex-col bg-slate-900 p-10 text-white lg:flex dark:border-r overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 bg-cover bg-center bg-no-repeat opacity-40 transition-opacity duration-200 ease-in-out"
|
||||
className="absolute inset-0 bg-cover bg-center bg-no-repeat opacity-40 transition-opacity duration-200 ease-in-out hover:opacity-50 transform hover:scale-105 transition-transform duration-10000 ease-linear"
|
||||
style={{
|
||||
backgroundImage: "url('/images/login-bg.jpg')",
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-slate-800/20 to-slate-800/70" />
|
||||
<div className="relative z-20 flex items-center text-lg font-medium">
|
||||
<svg
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-slate-900/30 via-slate-900/50 to-slate-900/90" />
|
||||
<motion.div
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="relative z-20 flex items-center text-lg font-medium"
|
||||
>
|
||||
<motion.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
@@ -41,37 +52,83 @@ export function LoginContent({ searchParams }: LoginContentProps) {
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="mr-2 h-6 w-6"
|
||||
whileHover={{ rotate: 180 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
|
||||
</svg>
|
||||
StripStream
|
||||
</div>
|
||||
<div className="relative z-20 mt-auto">
|
||||
</motion.svg>
|
||||
<span className="text-2xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent">
|
||||
StripStream
|
||||
</span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
initial={{ y: 20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.4 }}
|
||||
className="relative z-20 mt-auto"
|
||||
>
|
||||
<blockquote className="space-y-2">
|
||||
<p className="text-lg">{t("login.description")}</p>
|
||||
<p className="text-xl font-light leading-relaxed tracking-wide text-gray-200">
|
||||
{t("login.description")}
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div className="lg:p-8">
|
||||
<motion.div
|
||||
initial={{ x: 20, opacity: 0 }}
|
||||
animate={{ x: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="lg:p-8"
|
||||
>
|
||||
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
|
||||
<div className="flex flex-col space-y-2 text-center">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">{t("login.title")}</h1>
|
||||
<div className="flex flex-col items-center space-y-4 text-center">
|
||||
<div className="relative">
|
||||
<div className="absolute -inset-1 bg-gradient-to-r from-[#4F46E5] to-[#6366F1] rounded-full opacity-75 blur-md animate-pulse"></div>
|
||||
<div className="relative bg-gradient-to-br from-white to-gray-100 dark:from-slate-800 dark:to-slate-900 rounded-full shadow-xl overflow-hidden w-24 h-24 flex items-center justify-center">
|
||||
<motion.img
|
||||
src="/images/icons/apple-icon-180x180.png"
|
||||
alt="StripStream Logo"
|
||||
className="w-[100%] h-[100%] object-cover"
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<motion.h1
|
||||
initial={{ y: -20 }}
|
||||
animate={{ y: 0 }}
|
||||
className="text-3xl font-bold tracking-tight bg-gradient-to-r from-slate-900 to-slate-700 dark:from-white dark:to-gray-300 bg-clip-text text-transparent"
|
||||
>
|
||||
{t("login.title")}
|
||||
</motion.h1>
|
||||
<p className="text-sm text-muted-foreground">{t("login.subtitle")}</p>
|
||||
</div>
|
||||
<Tabs defaultValue={defaultTab} className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="login">{t("login.tabs.login")}</TabsTrigger>
|
||||
<TabsTrigger value="register">{t("login.tabs.register")}</TabsTrigger>
|
||||
<TabsList className="grid w-full grid-cols-2 p-1 bg-slate-100 dark:bg-slate-800/50 rounded-lg">
|
||||
<TabsTrigger
|
||||
value="login"
|
||||
className="data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm dark:data-[state=active]:bg-slate-700 transition-all duration-200"
|
||||
>
|
||||
{t("login.tabs.login")}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="register"
|
||||
className="data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm dark:data-[state=active]:bg-slate-700 transition-all duration-200"
|
||||
>
|
||||
{t("login.tabs.register")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="login">
|
||||
<TabsContent value="login" className="mt-6">
|
||||
<LoginForm from={searchParams.from} />
|
||||
</TabsContent>
|
||||
<TabsContent value="register">
|
||||
<TabsContent value="register" className="mt-6">
|
||||
<RegisterForm from={searchParams.from} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ export function LoginForm({ from }: LoginFormProps) {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? t("login.form.submit.loading.login") : t("login.form.submit.login")}
|
||||
</button>
|
||||
|
||||
@@ -104,7 +104,7 @@ export function RegisterForm({ from }: RegisterFormProps) {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? t("login.form.submit.loading.register") : t("login.form.submit.register")}
|
||||
</button>
|
||||
|
||||
21
yarn.lock
21
yarn.lock
@@ -2341,6 +2341,15 @@ fraction.js@^4.3.7:
|
||||
resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz"
|
||||
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
|
||||
|
||||
framer-motion@12.4.10:
|
||||
version "12.4.10"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-12.4.10.tgz#5b2aa0a18f5563edc9603c2c1cbc9d6f19a110a2"
|
||||
integrity sha512-3Msuyjcr1Pb5hjkn4EJcRe1HumaveP0Gbv4DBMKTPKcV/1GSMkQXj+Uqgneys+9DPcZM18Hac9qY9iUEF5LZtg==
|
||||
dependencies:
|
||||
motion-dom "^12.4.10"
|
||||
motion-utils "^12.4.10"
|
||||
tslib "^2.4.0"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
@@ -3159,6 +3168,18 @@ mongoose@8.1.0:
|
||||
ms "2.1.3"
|
||||
sift "16.0.1"
|
||||
|
||||
motion-dom@^12.4.10:
|
||||
version "12.4.10"
|
||||
resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-12.4.10.tgz#025886748e33e8ee77742eea7bd088b202e7c83a"
|
||||
integrity sha512-ISP5u6FTceoD6qKdLupIPU/LyXBrxGox+P2e3mBbm1+pLdlBbwv01YENJr7+1WZnW5ucVKzFScYsV1eXTCG4Xg==
|
||||
dependencies:
|
||||
motion-utils "^12.4.10"
|
||||
|
||||
motion-utils@^12.4.10:
|
||||
version "12.4.10"
|
||||
resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-12.4.10.tgz#3d93acea5454419eaaad8d5e5425cb71cbfa1e7f"
|
||||
integrity sha512-NPwZd94V013SwRf++jMrk2+HEBgPkeIE2RiOzhAuuQlqxMJPkKt/LXVh6Upl+iN8oarSGD2dlY5/bqgsYXDABA==
|
||||
|
||||
mpath@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user