[dyad] Giriş hatalarını doğrula
This commit is contained in:
1 parent
45b6fb7385
commit
64c950886a
5 files changed
+77
-111
No files matched your search
@@ -81,3 +81,9 @@ Caddyfile
|
|||||||
# lock files (optional - some projects include them)
|
# lock files (optional - some projects include them)
|
||||||
bun.lock
|
bun.lock
|
||||||
.dyad/
|
.dyad/
|
||||||
|
|
||||||
|
# Playwright test artifacts
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
.last-run.json
|
||||||
+3
-1
@@ -27,7 +27,8 @@
|
|||||||
"db:generate": "prisma generate",
|
"db:generate": "prisma generate",
|
||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
"db:reset": "prisma migrate reset",
|
"db:reset": "prisma migrate reset",
|
||||||
"db:seed": "bun prisma/seed.ts"
|
"db:seed": "bun prisma/seed.ts",
|
||||||
|
"test": "playwright test --config playwright-dyad.config.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
@@ -102,6 +103,7 @@
|
|||||||
"zustand": "^5.0.6"
|
"zustand": "^5.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.62.1",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/bcryptjs": "^3.0.0",
|
"@types/bcryptjs": "^3.0.0",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { defineConfig } from "@playwright/test";
|
||||||
|
|
||||||
|
// Generated by Dyad. The dev server is started separately by Dyad's
|
||||||
|
// preview, so we point baseURL at the already-running proxy URL (passed via
|
||||||
|
// env) rather than using Playwright's `webServer` (which would double-start
|
||||||
|
// the app).
|
||||||
|
// // Uses your installed Google Chrome (no extra browser download).
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: "./e2e-tests",
|
||||||
|
// Run serially against the single dev server.
|
||||||
|
workers: 1,
|
||||||
|
fullyParallel: false,
|
||||||
|
reporter: [["json", { outputFile: "test-results/results.json" }]],
|
||||||
|
use: {
|
||||||
|
baseURL: process.env.DYAD_TEST_BASE_URL || "http://localhost:32100",
|
||||||
|
channel: "chrome",
|
||||||
|
screenshot: "only-on-failure",
|
||||||
|
trace: "retain-on-failure",
|
||||||
|
},
|
||||||
|
});
|
||||||
Generated
+47
-8
@@ -148,13 +148,13 @@ importers:
|
|||||||
version: 0.525.0(react@19.2.8)
|
version: 0.525.0(react@19.2.8)
|
||||||
next:
|
next:
|
||||||
specifier: ^16.1.1
|
specifier: ^16.1.1
|
||||||
version: 16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
version: 16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
next-auth:
|
next-auth:
|
||||||
specifier: ^4.24.11
|
specifier: ^4.24.11
|
||||||
version: 4.24.15(next@16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
version: 4.24.15(next@16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
next-intl:
|
next-intl:
|
||||||
specifier: ^4.3.4
|
specifier: ^4.3.4
|
||||||
version: 4.13.4(next@16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(typescript@5.9.3)
|
version: 4.13.4(next@16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(typescript@5.9.3)
|
||||||
next-themes:
|
next-themes:
|
||||||
specifier: ^0.4.6
|
specifier: ^0.4.6
|
||||||
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
@@ -219,6 +219,9 @@ importers:
|
|||||||
specifier: ^5.0.6
|
specifier: ^5.0.6
|
||||||
version: 5.0.14(@types/react@19.2.17)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8))
|
version: 5.0.14(@types/react@19.2.17)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: ^1.62.1
|
||||||
|
version: 1.62.1
|
||||||
'@tailwindcss/postcss':
|
'@tailwindcss/postcss':
|
||||||
specifier: ^4
|
specifier: ^4
|
||||||
version: 4.3.3
|
version: 4.3.3
|
||||||
@@ -1118,6 +1121,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==}
|
resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
|
'@playwright/test@1.62.1':
|
||||||
|
resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@prisma/client@6.19.3':
|
'@prisma/client@6.19.3':
|
||||||
resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==}
|
resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==}
|
||||||
engines: {node: '>=18.18'}
|
engines: {node: '>=18.18'}
|
||||||
@@ -3035,6 +3043,11 @@ packages:
|
|||||||
react-dom:
|
react-dom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
fsevents@2.3.2:
|
||||||
|
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
function-bind@1.1.2:
|
function-bind@1.1.2:
|
||||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
@@ -3932,6 +3945,16 @@ packages:
|
|||||||
pkg-types@2.3.1:
|
pkg-types@2.3.1:
|
||||||
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
||||||
|
|
||||||
|
playwright-core@1.62.1:
|
||||||
|
resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
playwright@1.62.1:
|
||||||
|
resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
po-parser@2.1.1:
|
po-parser@2.1.1:
|
||||||
resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==}
|
resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==}
|
||||||
|
|
||||||
@@ -5718,6 +5741,10 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-arm64': 2.6.0
|
'@parcel/watcher-win32-arm64': 2.6.0
|
||||||
'@parcel/watcher-win32-x64': 2.6.0
|
'@parcel/watcher-win32-x64': 2.6.0
|
||||||
|
|
||||||
|
'@playwright/test@1.62.1':
|
||||||
|
dependencies:
|
||||||
|
playwright: 1.62.1
|
||||||
|
|
||||||
'@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)':
|
'@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
prisma: 6.19.3(typescript@5.9.3)
|
prisma: 6.19.3(typescript@5.9.3)
|
||||||
@@ -7772,6 +7799,9 @@ snapshots:
|
|||||||
react: 19.2.8
|
react: 19.2.8
|
||||||
react-dom: 19.2.8(react@19.2.8)
|
react-dom: 19.2.8(react@19.2.8)
|
||||||
|
|
||||||
|
fsevents@2.3.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
function-bind@1.1.2: {}
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
function.prototype.name@1.2.0:
|
function.prototype.name@1.2.0:
|
||||||
@@ -8715,13 +8745,13 @@ snapshots:
|
|||||||
|
|
||||||
negotiator@1.0.0: {}
|
negotiator@1.0.0: {}
|
||||||
|
|
||||||
next-auth@4.24.15(next@16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
next-auth@4.24.15(next@16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.29.7
|
'@babel/runtime': 7.29.7
|
||||||
'@panva/hkdf': 1.2.1
|
'@panva/hkdf': 1.2.1
|
||||||
cookie: 0.7.2
|
cookie: 0.7.2
|
||||||
jose: 4.15.9
|
jose: 4.15.9
|
||||||
next: 16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
next: 16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
oauth: 0.9.15
|
oauth: 0.9.15
|
||||||
openid-client: 5.7.1
|
openid-client: 5.7.1
|
||||||
preact: 10.29.7(preact-render-to-string@5.2.6)
|
preact: 10.29.7(preact-render-to-string@5.2.6)
|
||||||
@@ -8732,14 +8762,14 @@ snapshots:
|
|||||||
|
|
||||||
next-intl-swc-plugin-extractor@4.13.4: {}
|
next-intl-swc-plugin-extractor@4.13.4: {}
|
||||||
|
|
||||||
next-intl@4.13.4(next@16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(typescript@5.9.3):
|
next-intl@4.13.4(next@16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/intl-localematcher': 0.8.13
|
'@formatjs/intl-localematcher': 0.8.13
|
||||||
'@parcel/watcher': 2.6.0
|
'@parcel/watcher': 2.6.0
|
||||||
'@swc/core': 1.15.47
|
'@swc/core': 1.15.47
|
||||||
icu-minify: 4.13.4
|
icu-minify: 4.13.4
|
||||||
negotiator: 1.0.0
|
negotiator: 1.0.0
|
||||||
next: 16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
next: 16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
next-intl-swc-plugin-extractor: 4.13.4
|
next-intl-swc-plugin-extractor: 4.13.4
|
||||||
po-parser: 2.1.1
|
po-parser: 2.1.1
|
||||||
react: 19.2.8
|
react: 19.2.8
|
||||||
@@ -8756,7 +8786,7 @@ snapshots:
|
|||||||
|
|
||||||
next-tick@1.1.0: {}
|
next-tick@1.1.0: {}
|
||||||
|
|
||||||
next@16.2.12(@babel/core@7.29.7)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
next@16.2.12(@babel/core@7.29.7)(@playwright/test@1.62.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 16.2.12
|
'@next/env': 16.2.12
|
||||||
'@swc/helpers': 0.5.15
|
'@swc/helpers': 0.5.15
|
||||||
@@ -8775,6 +8805,7 @@ snapshots:
|
|||||||
'@next/swc-linux-x64-musl': 16.2.12
|
'@next/swc-linux-x64-musl': 16.2.12
|
||||||
'@next/swc-win32-arm64-msvc': 16.2.12
|
'@next/swc-win32-arm64-msvc': 16.2.12
|
||||||
'@next/swc-win32-x64-msvc': 16.2.12
|
'@next/swc-win32-x64-msvc': 16.2.12
|
||||||
|
'@playwright/test': 1.62.1
|
||||||
sharp: 0.34.5
|
sharp: 0.34.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
@@ -8927,6 +8958,14 @@ snapshots:
|
|||||||
exsolve: 1.1.1
|
exsolve: 1.1.1
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
playwright-core@1.62.1: {}
|
||||||
|
|
||||||
|
playwright@1.62.1:
|
||||||
|
dependencies:
|
||||||
|
playwright-core: 1.62.1
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
|
||||||
po-parser@2.1.1: {}
|
po-parser@2.1.1: {}
|
||||||
|
|
||||||
possible-typed-array-names@1.1.0: {}
|
possible-typed-array-names@1.1.0: {}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { BookOpen, Mail, Lock, User, ArrowRight, GraduationCap, Heart, Sparkles, Flower2, Eye, EyeOff, KeyRound, Info, Shield, Leaf, Users as UsersIcon, HelpCircle, BarChart3, LockKeyhole, GitBranch, CheckCircle2, XCircle, Globe, Github, Chrome } from 'lucide-react';
|
import { BookOpen, Mail, Lock, User, ArrowRight, GraduationCap, Heart, Sparkles, Flower2, Eye, EyeOff, KeyRound, Info, Shield, Leaf, Users as UsersIcon, HelpCircle, LockKeyhole, GitBranch, CheckCircle2, XCircle } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
@@ -275,56 +275,6 @@ function LeftIllustration({ loginRole }: { loginRole: LoginRole }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Features section below form ───────────────────────────── */
|
|
||||||
function FeaturesSection() {
|
|
||||||
const features = [
|
|
||||||
{ icon: BarChart3, labelKey: 'auth.feature_grading', descKey: 'auth.feature_grading_desc', color: 'emerald' },
|
|
||||||
{ icon: GraduationCap, labelKey: 'auth.feature_attendance', descKey: 'auth.feature_attendance_desc', color: 'teal' },
|
|
||||||
{ icon: Sparkles, labelKey: 'auth.feature_ai', descKey: 'auth.feature_ai_desc', color: 'violet' },
|
|
||||||
{ icon: Heart, labelKey: 'auth.feature_collaboration', descKey: 'auth.feature_collaboration_desc', color: 'amber' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const colorClasses: Record<string, { bg: string; text: string; border: string; iconBg: string }> = {
|
|
||||||
emerald: { bg: 'bg-emerald-50 dark:bg-emerald-900/20', text: 'text-emerald-600 dark:text-emerald-400', border: 'border-emerald-200/60 dark:border-emerald-800/40', iconBg: 'bg-gradient-to-br from-emerald-400 to-emerald-500 text-white' },
|
|
||||||
teal: { bg: 'bg-teal-50 dark:bg-teal-900/20', text: 'text-teal-600 dark:text-teal-400', border: 'border-teal-200/60 dark:border-teal-800/40', iconBg: 'bg-gradient-to-br from-teal-400 to-teal-500 text-white' },
|
|
||||||
amber: { bg: 'bg-amber-50 dark:bg-amber-900/20', text: 'text-amber-600 dark:text-amber-400', border: 'border-amber-200/60 dark:border-amber-800/40', iconBg: 'bg-gradient-to-br from-amber-400 to-amber-500 text-white' },
|
|
||||||
violet: { bg: 'bg-violet-50 dark:bg-violet-900/20', text: 'text-violet-600 dark:text-violet-400', border: 'border-violet-200/60 dark:border-violet-800/40', iconBg: 'bg-gradient-to-br from-violet-400 to-violet-500 text-white' },
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: 16 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.5, delay: 0.6 }}
|
|
||||||
className="mt-6"
|
|
||||||
>
|
|
||||||
<p className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3 text-center">{t('auth.feature_showcase')}</p>
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
|
||||||
{features.map((f, i) => {
|
|
||||||
const c = colorClasses[f.color];
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key={f.labelKey}
|
|
||||||
initial={{ opacity: 0, y: 10 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.3, delay: 0.7 + i * 0.08 }}
|
|
||||||
className={`flex items-start gap-2.5 px-3 py-3 rounded-xl ${c.bg} border ${c.border}`}
|
|
||||||
>
|
|
||||||
<div className={`flex items-center justify-center w-7 h-7 rounded-lg ${c.iconBg} shrink-0 shadow-sm`}>
|
|
||||||
<f.icon className="w-3.5 h-3.5" />
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0">
|
|
||||||
<p className="text-xs font-semibold text-gray-800 dark:text-gray-200 leading-tight">{t(f.labelKey)}</p>
|
|
||||||
<p className="text-[10px] text-gray-500 dark:text-gray-400 leading-tight mt-0.5">{t(f.descKey)}</p>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Main Auth View ────────────────────────────────────────── */
|
/* ─── Main Auth View ────────────────────────────────────────── */
|
||||||
export default function AuthView() {
|
export default function AuthView() {
|
||||||
const [mode, setMode] = useState<'login' | 'register'>('login');
|
const [mode, setMode] = useState<'login' | 'register'>('login');
|
||||||
@@ -953,57 +903,6 @@ export default function AuthView() {
|
|||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Social login buttons (visual only) */}
|
|
||||||
{mode === 'login' && (
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: 10 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ delay: 0.5, duration: 0.4 }}
|
|
||||||
className="mt-5"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-3 mb-4">
|
|
||||||
<div className="flex-1 h-px bg-gray-200 dark:bg-gray-700" />
|
|
||||||
<span className="text-xs text-gray-400 dark:text-gray-500 font-medium">{t('auth.or_continue_with') || 'or continue with'}</span>
|
|
||||||
<div className="flex-1 h-px bg-gray-200 dark:bg-gray-700" />
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-3 gap-3">
|
|
||||||
<motion.button
|
|
||||||
type="button"
|
|
||||||
whileHover={{ scale: 1.03 }}
|
|
||||||
whileTap={{ scale: 0.97 }}
|
|
||||||
className="social-btn flex items-center justify-center gap-2 h-11 rounded-xl border border-gray-200 dark:border-gray-700 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm text-gray-700 dark:text-gray-300 font-medium text-xs hover:border-gray-300 dark:hover:border-gray-600"
|
|
||||||
onClick={() => toast.info(t('auth.social_coming_soon') || 'Social login coming soon')}
|
|
||||||
>
|
|
||||||
<Chrome className="h-4 w-4 text-blue-500" />
|
|
||||||
<span className="hidden sm:inline">Google</span>
|
|
||||||
</motion.button>
|
|
||||||
<motion.button
|
|
||||||
type="button"
|
|
||||||
whileHover={{ scale: 1.03 }}
|
|
||||||
whileTap={{ scale: 0.97 }}
|
|
||||||
className="social-btn flex items-center justify-center gap-2 h-11 rounded-xl border border-gray-200 dark:border-gray-700 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm text-gray-700 dark:text-gray-300 font-medium text-xs hover:border-gray-300 dark:hover:border-gray-600"
|
|
||||||
onClick={() => toast.info(t('auth.social_coming_soon') || 'Social login coming soon')}
|
|
||||||
>
|
|
||||||
<Github className="h-4 w-4" />
|
|
||||||
<span className="hidden sm:inline">GitHub</span>
|
|
||||||
</motion.button>
|
|
||||||
<motion.button
|
|
||||||
type="button"
|
|
||||||
whileHover={{ scale: 1.03 }}
|
|
||||||
whileTap={{ scale: 0.97 }}
|
|
||||||
className="social-btn flex items-center justify-center gap-2 h-11 rounded-xl border border-gray-200 dark:border-gray-700 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm text-gray-700 dark:text-gray-300 font-medium text-xs hover:border-gray-300 dark:hover:border-gray-600"
|
|
||||||
onClick={() => toast.info(t('auth.social_coming_soon') || 'Social login coming soon')}
|
|
||||||
>
|
|
||||||
<Globe className="h-4 w-4 text-emerald-500" />
|
|
||||||
<span className="hidden sm:inline">Moodle</span>
|
|
||||||
</motion.button>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Features section below form */}
|
|
||||||
<FeaturesSection />
|
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
|
|||||||
Reference in new issue
Block a user