-
Notifications
You must be signed in to change notification settings - Fork 4
Feat welcom page #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat welcom page #68
Changes from all commits
4fb8f44
57cb9d2
afede97
49337b2
6200ccb
49621bd
6341082
8a008ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -175,3 +175,5 @@ output.css | |
| **/src/SmartContract/dump.rdb | ||
| make/scripts/certs/certs | ||
| .venv | ||
| *.ai | ||
| docs/welcomPage.jpg | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { motion } from 'framer-motion'; | ||
|
|
||
| interface CircleButtonProps { | ||
| children?: React.ReactNode; | ||
| } | ||
|
|
||
| const dropdownStyle = 'shadow-[0_10px_10px_1px_rgba(205,205,205,0.4)] '; | ||
|
|
||
| export const CircleButton = ({ children }: CircleButtonProps) => ( | ||
| <motion.div | ||
| whileHover={{ scale: 1.1, color: '#029c8a' }} | ||
| whileTap={{ scale: 0.95, color: '#ff0088' }} | ||
| transition={{ duration: 0.3 }} | ||
| className={` | ||
| basis-50 | ||
| h-56 m-10 p-6 | ||
| aspect-square | ||
| rounded-full | ||
| bg-slate-100/80 | ||
| flex items-center justify-center | ||
| font-quantico border border-cyan-300 | ||
| text-gray-700 | ||
| ${dropdownStyle} | ||
| `} | ||
| > | ||
| <p className="text-2xl text-center whitespace-nowrap">{children}</p> | ||
| </motion.div> | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { useState } from 'react'; | ||
| import { RegisterForm } from '../organisms/RegisterForm'; | ||
| import { LoginForm } from '../organisms/LoginForm'; | ||
| import Circle from '../atoms/Circle'; | ||
| import { useTranslation } from 'react-i18next'; | ||
|
|
||
| interface HaloProps { | ||
| isRegister: boolean; | ||
| className?: string; | ||
| size?: number; | ||
| onToggleForm: () => void; // Add this line | ||
| } | ||
| const Halo = ({ className = '', size = 80, isRegister, onToggleForm }: HaloProps) => { | ||
| const [isHovered, setIsHovered] = useState(false); | ||
| const { t } = useTranslation(); | ||
| const title = isRegister ? t('auth.signup') : t('auth.login'); | ||
|
|
||
| return ( | ||
| <div | ||
| className={`absolute ${className}`} | ||
| onMouseEnter={() => setIsHovered(true)} | ||
| onMouseLeave={() => setIsHovered(false)} | ||
| > | ||
| <Circle size={isHovered ? size : 30} className="cursor-pointer p-8"> | ||
| {/* PLAY text */} | ||
| <span className={`text-2xl font-bold ${isHovered ? 'hidden' : 'block'}`}>PLAY</span> | ||
|
|
||
| {/* Forms */} | ||
| <div className={`min-h-[100px] ${isHovered ? 'block' : 'hidden'}`}> | ||
| {isRegister ? ( | ||
| <RegisterForm onToggleForm={onToggleForm} /> | ||
| ) : ( | ||
| <LoginForm onToggleForm={onToggleForm} /> | ||
| )} | ||
| </div> | ||
| </Circle> | ||
| </div> | ||
| ); | ||
| }; | ||
| export default Halo; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,7 +79,7 @@ async function loginAction(prevState: LoginState | null, formData: FormData) { | |
| } | ||
| } | ||
|
|
||
| export const LoginForm = () => { | ||
| export const LoginForm = ({ onToggleForm }: { onToggleForm?: () => void }) => { | ||
| const { t } = useTranslation(); | ||
| const [state, formAction, isPending] = useActionState(loginAction, null); | ||
| const navigate = useNavigate(); | ||
|
|
@@ -88,10 +88,12 @@ export const LoginForm = () => { | |
| if (state?.success && state.fields?.username) { | ||
| const username = state.fields.username; | ||
| login({ username: username, avatarUrl: null }); | ||
| navigate(`/profile/${username}`, { replace: true }); | ||
| // navigate(`/profile/${username}`, { replace: true }); | ||
| navigate(`/welcome`, { replace: true }); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Je ne suis pas sûr que rajouter une page soit la meilleure solution.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. L'animation n'est pas geré dans cette PR (mis en place par francois) je ne m'en occupe pas, elle est mis en place sur la racine. Cela pourrait etre vu par la suite ? On s'etait mis d'accord pour avoir une welcome page (qui remplace /login et /signup), si ca ne te semble pas pertinent, il faudrai que tu propose une autre solution clair (et c'est bien de le proposé avant qu'on se mette a coder). Le display de la page d'acceuil pourrait tres bien se faire a la racine '/' mais la racine est deja dedié a l'animation de bienvenue. Nous pouvons redirer sur '/welcome' en cliquant sur le logo. Nous suivons le plans ce qui a été énoncé aux reunions, tu trouveras un shema UIX dans le discord ! Cette PR permet d'avoir un acces simple au /game/* afin d'avoir un developpement plus aisé de celui ci, et de construire un debut d'UIX final. Il est préferable, d'arriver sur la welcome Page plutot que sur la page profile en premier lieux.(basique UIX)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. La welcome page et la racine c'est la même chose.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, je comprends ton point de vue, et le fait qu'une page en plus ne te semble pas pertinent. Cepandant, laisse moi rectifier certains concepts... Non, la welcomePage (ou landing page) et la racine (ou nom de domaine) ne sont pas forcément la meme chose, elles peuvent l'etre, mais ce n'est pas systématique. La pattern 'www.example.com/landingpage' est régulierement utilisé sur le web (on retrouve souvent une page 'langue', derriere le nom de domaine, qui fait office de landing page). Sur certains site web, quand tu tape le nom de domaine www.example.com, tu es redirigé sur une landing page --> www.example.com/landing_page exemple: Dans notre cas (pour le moment) la racine est utilisé pour jouer une animation. Le fait d'avoir une landing page a la racine ou sur une page differente ne change pas grands chose sur notre projet (voir absolument rien). Si tu veux qu'on reste a la racine, il faudrai modifier les '/welcome' en '/' , c'est pas grands chose à faire en soit mais comme il y a l'animation sur le '/' il faut gerer ca, et comme je te le disais, ce n'est pas dans le scope de ma PR (less is more ;) ). Ceci dit, je pense que c'est facilement faisable d'associer l'animation + landing page a la racine, mais je ne voit pas pourquoi changer ce comportement (ca ne joue ni sur le rendus du site, ni sur notre eval). Personnellement je trouve que ca marche tres bien comme ca, et je vois pas pourquoi changer (l'animation qu'a fait francois est tres bien a la racine, why not ?) ! Mais on peut toujours le modifier si tu y tiens vraiment ? So what should we do ?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, ton point de vue m'a convaincu. |
||
| } | ||
| if (user?.username) { | ||
| navigate(`/profile/${user.username}`, { replace: true }); | ||
| // navigate(`/profile/${username}`, { replace: true }); | ||
| navigate(`/welcome`, { replace: true }); | ||
| } | ||
| }, [state?.success, state?.fields?.username, user, navigate, login]); | ||
| return ( | ||
|
|
@@ -119,11 +121,9 @@ export const LoginForm = () => { | |
|
|
||
| <div className="text-xs text-gray-500 mt-5"> | ||
| {t('auth.noAccount')}{' '} | ||
| <span> | ||
| <Link className="hover:text-blue-400" to={`/signup`}> | ||
| {t('auth.signup')} | ||
| </Link> | ||
| </span> | ||
| <button type="button" onClick={onToggleForm} className="hover:text-blue-400 underline"> | ||
| {t('auth.signup')} | ||
| </button> | ||
| </div> | ||
| </form> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -112,24 +112,25 @@ async function signupAction(prevState: SignupState | null, formData: FormData) { | |
| return nextState; | ||
| } | ||
| } | ||
|
|
||
| export const RegisterForm = () => { | ||
| export const RegisterForm = ({ onToggleForm }: { onToggleForm?: () => void }) => { | ||
| const { t } = useTranslation(); | ||
| const [state, formAction, isPending] = useActionState(signupAction, null); | ||
| const navigate = useNavigate(); | ||
| const { user, login, isLoggedIn } = useAuth(); | ||
|
|
||
| useEffect(() => { | ||
| if (user && isLoggedIn) { | ||
| navigate(`/profile/${user.username}`); | ||
| // navigate(`/profile/${user.username}`); | ||
| navigate(`/welcome`); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. idem register form
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Idem -> soit on reviens a la racine '/' avec l'animation, soit sur /welcome, mais pas sur /profile
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oui racine
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Il y a une discussion sur le discord, a propos de l'UIX design, ou on parle de la navigation user et du comportement du front. Ce sujet (WelcomePage) a été abordé, et a été validé avec françois. On se retrouve sur le channel pour en parler plus précisement ! C'est toujours mieux d'en parler en amont, plutot que sur les PRs (quand c'est possible). |
||
| } | ||
| }, [user, isLoggedIn]); | ||
|
|
||
| useEffect(() => { | ||
| if (state?.success && state.fields?.username) { | ||
| const username = state.fields?.username; | ||
| login({ username: username, avatarUrl: null }); | ||
| navigate(`/profile/${username}`); | ||
| // navigate(`/profile/${username}`); | ||
| navigate(`/welcome`); | ||
| } | ||
| }, [state?.success, state?.fields?.username, navigate]); | ||
|
|
||
|
|
@@ -167,11 +168,9 @@ export const RegisterForm = () => { | |
|
|
||
| <div className="text-xs text-gray-500 mt-5"> | ||
| {t('auth.hasAccount')}{' '} | ||
| <span> | ||
| <Link className="hover:text-blue-400" to={`/login`}> | ||
| {t('auth.login')} | ||
| </Link> | ||
| </span> | ||
| <button type="button" onClick={onToggleForm} className="hover:text-blue-400 underline"> | ||
| {t('auth.login')} | ||
| </button> | ||
| </div> | ||
| </form> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -66,5 +66,10 @@ | |||||||||||||
| "copyright": "© 2026 Tous droits réservés.", | ||||||||||||||
| "privacyPolicy": "Politique de confidentialité", | ||||||||||||||
| "termsOfService": "Conditions d'utilisation" | ||||||||||||||
| }, | ||||||||||||||
| "game": { | ||||||||||||||
| "playWithAI": "Joue avec un ROBOT (no friends?)", | ||||||||||||||
| "playWithFriends": "Joue avec ton copaing", | ||||||||||||||
| "tournament": "Defi tes potes en tournois" | ||||||||||||||
|
Comment on lines
+71
to
+73
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -66,5 +66,10 @@ | |||||||||||||||||
| "copyright": "© 2026 – C'est à nous.", | ||||||||||||||||||
| "privacyPolicy": "La loi du milieu (on balance rien, t'es en sécurité)", | ||||||||||||||||||
| "termsOfService": "Les règles du jeu (lis ça, sinon t’es un rigolo)" | ||||||||||||||||||
| }, | ||||||||||||||||||
| "game": { | ||||||||||||||||||
| "playWithAI": "No friends? Joue avec un ROBOT", | ||||||||||||||||||
| "playWithFriends": "Joue avec ton copaing", | ||||||||||||||||||
| "tournament": "Defi tes potes en tournois" | ||||||||||||||||||
|
Comment on lines
+70
to
+73
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. il faudrait des titres plus courts
Suggested change
|
||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import { NavBar } from '../components/molecules/NavBar'; // Adjust path based on your folder structure | ||
| import Halo from '../components/molecules/Halo'; | ||
| import { Link } from 'react-router-dom'; | ||
| import Background from '../components/atoms/Background'; | ||
| import { useTranslation } from 'react-i18next'; | ||
| import { RegisterForm } from '../components/organisms/RegisterForm'; | ||
| import { LoginForm } from '../components/organisms/LoginForm'; | ||
| import { useState } from 'react'; | ||
| import Circle from '../components/atoms/Circle'; | ||
| import { CircleButton } from '../components/molecules/CircleButton'; | ||
| import { useAuth } from '../providers/AuthProvider'; | ||
|
|
||
| const colors = { | ||
| start: '#00ff9f', | ||
| end: '#0088ff', | ||
| }; | ||
|
|
||
| interface LoginRegisterPageProps { | ||
| isRegister: boolean; | ||
| } | ||
| export const WelcomePage = () => { | ||
| const { t } = useTranslation(); | ||
| const [isRegister, setIsRegister] = useState(false); | ||
| const { user, isLoggedIn } = useAuth(); | ||
|
|
||
| const ai = t('game.playWithAI'); | ||
| const tournament = t('game.tournament'); | ||
| const friends = t('game.playWithFriends'); | ||
| return ( | ||
| <div className={`w-full h-full relative`}> | ||
| <Background | ||
| grainIntensity={4} | ||
| baseFrequency={0.28} | ||
| colorStart={colors.start} | ||
| colorEnd={colors.end} | ||
| > | ||
| <NavBar /> | ||
| {/* Not logged in - show login/register */} | ||
| {!isLoggedIn && ( | ||
| <Halo | ||
| size={80} | ||
| isRegister={isRegister} | ||
| onToggleForm={() => setIsRegister(!isRegister)} | ||
| className="top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" | ||
| /> | ||
| )} | ||
| {/* Logged in - show 3 game options */} | ||
| {isLoggedIn && ( | ||
| <div className=" flex flex-1 items-center justify-center"> | ||
| <div className="flex flex-col sm:flex-row gap-4"> | ||
| <Link to="/game/pong-ai"> | ||
| <CircleButton>{ai}</CircleButton> | ||
| </Link> | ||
|
|
||
| <Link to="/game/simple-game"> | ||
| <CircleButton>{friends}</CircleButton> | ||
| </Link> | ||
|
|
||
| <Link to="/game/tournament"> | ||
| <CircleButton>{tournament}</CircleButton> | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </Background> | ||
| </div> | ||
| ); | ||
| }; | ||
| // export const WelcomePage = () => { | ||
| // const { t } = useTranslation(); | ||
| // const [isRegister, setIsRegister] = useState(false); | ||
| // const title = isRegister ? t('auth.signup') : t('auth.login'); | ||
| // return ( | ||
| // <div className={`w-full h-full relative`}> | ||
| // <Background | ||
| // grainIntensity={4} | ||
| // baseFrequency={0.28} | ||
| // colorStart={colors.start} | ||
| // colorEnd={colors.end} | ||
| // > | ||
| // <NavBar /> | ||
| // <Halo | ||
| // size={200} | ||
| // isRegister={isRegister} | ||
| // onToggleForm={() => setIsRegister(!isRegister)} | ||
| // className="top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" | ||
| // /> | ||
| // </Background> | ||
| // </div> | ||
| // ); | ||
| // }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c'est du détail, si ça n'inclut pas d'autres composants, ce serait à ranger dans atoms plutôt que molécules