Compare commits
8 Commits
mus
...
882729ffc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
882729ffc9
|
|||
|
dfa443d373
|
|||
|
dc17e4a8f7
|
|||
|
036acfce23
|
|||
|
606f37e78f
|
|||
|
1dd0384857
|
|||
|
d624ac6ab2
|
|||
|
409926a97b
|
@@ -23,6 +23,7 @@
|
||||
"@radix-ui/react-hover-card": "^1.0.7",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-menubar": "^1.0.4",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.4",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-progress": "^1.0.3",
|
||||
"@radix-ui/react-radio-group": "^1.1.3",
|
||||
@@ -45,6 +46,7 @@
|
||||
"embla-carousel-react": "^8.1.3",
|
||||
"framer-motion": "^11.2.10",
|
||||
"input-otp": "^1.2.4",
|
||||
"lightweight-charts": "^4.1.4",
|
||||
"lucide-react": "^0.387.0",
|
||||
"next": "14.2.3",
|
||||
"next-themes": "^0.3.0",
|
||||
@@ -60,9 +62,11 @@
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"jest": "^29.7.0",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
|
||||
2283
pnpm-lock.yaml
generated
2283
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@ import {ThemeProvider} from "@/components/providers/theme-provider";
|
||||
import type React from "react";
|
||||
import {Footer} from "@/components/footer";
|
||||
import {Header} from "@/components/header";
|
||||
import {PrimaryNavigationMenu} from "@/components/primary-nav";
|
||||
import {Providers} from "@/components/providers/providers";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "YeloBit",
|
||||
@@ -21,16 +23,14 @@ export default function RootLayout({
|
||||
<head>
|
||||
<link rel="icon" href="/public/favicon.ico" sizes="any"/>
|
||||
</head>
|
||||
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
>
|
||||
<Header></Header>
|
||||
{children}
|
||||
<Footer/>
|
||||
</ThemeProvider>
|
||||
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
|
||||
<Providers>
|
||||
<Header>
|
||||
<PrimaryNavigationMenu/>
|
||||
</Header>
|
||||
{children}
|
||||
<Footer/>
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between p-24">
|
||||
<main className="flex flex-col items-center justify-end h-full w-2/4">
|
||||
<h1>Hello world !</h1>
|
||||
</main>
|
||||
);
|
||||
|
||||
22
src/components/account-dialog.tsx
Normal file
22
src/components/account-dialog.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
"use client"
|
||||
|
||||
import {useContext} from "react";
|
||||
import {UserDataContext} from "@/components/providers/userdata-provider";
|
||||
import {AccountInfo} from "@/components/account-info";
|
||||
|
||||
|
||||
export function AccountDialog() {
|
||||
const userContext = useContext(UserDataContext)
|
||||
|
||||
if (!userContext?.userData) {
|
||||
userContext?.setUserData({name: "Mathis"})
|
||||
return (<p>Loading...</p>)
|
||||
}
|
||||
|
||||
//TODO No account context
|
||||
|
||||
//TODO Loading context
|
||||
|
||||
//TODO Account context
|
||||
return (<AccountInfo userData={userContext.userData}/>)
|
||||
}
|
||||
58
src/components/account-info.tsx
Normal file
58
src/components/account-info.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
"use client"
|
||||
|
||||
import {IUserData} from "@/interfaces/userdata.interface";
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet"
|
||||
import {User} from "lucide-react";
|
||||
|
||||
|
||||
export function AccountInfo({userData}: {userData: IUserData}) {
|
||||
return (
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline" className={"gap-1"}>
|
||||
<User />
|
||||
{userData?.name || "?"}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit profile</SheetTitle>
|
||||
<SheetDescription>
|
||||
Make changes to your profile here. Click save when you're done.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="name" className="text-right">
|
||||
Name
|
||||
</Label>
|
||||
<Input id="name" placeholder={userData.name} className="col-span-3" onChange={(event)=>{console.log(event.target.value)}} />
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="username" className="text-right">
|
||||
Username
|
||||
</Label>
|
||||
<Input id="username" value="@peduarte" className="col-span-3" />
|
||||
</div>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<SheetClose asChild>
|
||||
<Button type="submit">Save changes</Button>
|
||||
</SheetClose>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
import {ThemeBtnSelector} from "@/components/theme-btn-selector";
|
||||
import {AccountDialog} from "@/components/account-dialog";
|
||||
|
||||
|
||||
export function Header({title, children}: {title?: string, children?: React.ReactNode}) {
|
||||
@@ -16,7 +17,8 @@ export function Header({title, children}: {title?: string, children?: React.Reac
|
||||
<div className={"w-1/3 flex flex-row justify-center items-center"}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={"w-1/3 flex flex-row justify-end items-center"}>
|
||||
<div className={"w-1/3 flex flex-row justify-end gap-2 items-center"}>
|
||||
<AccountDialog/>
|
||||
<ThemeBtnSelector/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
23
src/components/providers/providers.tsx
Normal file
23
src/components/providers/providers.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client"
|
||||
import React from "react";
|
||||
import {Header} from "@/components/header";
|
||||
import {Footer} from "@/components/footer";
|
||||
import {ThemeProvider} from "@/components/providers/theme-provider";
|
||||
import {UserDataProvider} from "@/components/providers/userdata-provider";
|
||||
|
||||
|
||||
export function Providers({children}: { children: React.ReactNode }) {
|
||||
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
>
|
||||
<UserDataProvider>
|
||||
{children}
|
||||
</UserDataProvider>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
21
src/components/providers/userdata-provider.tsx
Normal file
21
src/components/providers/userdata-provider.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import {IUserData} from "@/interfaces/userdata.interface";
|
||||
import {useEncodedLocalStorage} from "@/services/localStorage";
|
||||
|
||||
export interface IUserDataProvider {
|
||||
userData: IUserData | undefined;
|
||||
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>
|
||||
}
|
||||
|
||||
export const UserDataContext = React.createContext<IUserDataProvider | undefined>(undefined);
|
||||
|
||||
export const UserDataProvider = ({children}: {children: React.ReactNode}) => {
|
||||
const [userData, setUserData] = useEncodedLocalStorage<IUserData | undefined>("user_data", undefined);
|
||||
|
||||
|
||||
return (
|
||||
<UserDataContext.Provider value={{userData, setUserData}}>
|
||||
{children}
|
||||
</UserDataContext.Provider>
|
||||
);
|
||||
};
|
||||
3
src/interfaces/userdata.interface.ts
Normal file
3
src/interfaces/userdata.interface.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface IUserData {
|
||||
name: string
|
||||
}
|
||||
14
src/services/account.handler.ts
Normal file
14
src/services/account.handler.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState } from 'react';
|
||||
import {IUserData} from "@/interfaces/userdata.interface";
|
||||
|
||||
const UserDataContext = createContext<IUserData>({name: "Avnyr"})
|
||||
|
||||
//TODO Run register task
|
||||
|
||||
//TODO Run login task
|
||||
|
||||
//TODO Run disconnect task
|
||||
|
||||
//TODO Run update user data
|
||||
0
src/services/exchange.handler.ts
Normal file
0
src/services/exchange.handler.ts
Normal file
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React, {useEffect, useState} from "react";
|
||||
import React, {useEffect, useRef, useState} from "react";
|
||||
|
||||
/**
|
||||
* A custom React hook that allows you to store and retrieve data in the browser's localStorage.
|
||||
@@ -48,12 +48,20 @@ export function useLocalStorage<T>(key: string, initial: T): [T, React.Dispatch<
|
||||
* @return {readonly [T, React.Dispatch<React.SetStateAction<T>>]} - An array containing the encoded value and a function to update the encoded value.
|
||||
*/
|
||||
export function useEncodedLocalStorage<T>(key: string, fallbackValue: T): readonly [T, React.Dispatch<React.SetStateAction<T>>] {
|
||||
console.log("Pong !")
|
||||
const [encodedValue, setEncodedValue] = useState<T>(() => {
|
||||
const stored = localStorage.getItem(key);
|
||||
return stored ? safelyParse(stored, fallbackValue) : fallbackValue;
|
||||
});
|
||||
|
||||
const prevValue = useRef(encodedValue);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem(key, safelyStringify(encodedValue));
|
||||
console.log({encodedValue})
|
||||
if (!b64ValEqual(prevValue.current, encodedValue)) {
|
||||
localStorage.setItem(key, safelyStringify(encodedValue));
|
||||
}
|
||||
prevValue.current = encodedValue; // Set ref to current value
|
||||
}, [key, encodedValue]);
|
||||
return [encodedValue, setEncodedValue] as const;
|
||||
|
||||
@@ -64,6 +72,12 @@ export function useEncodedLocalStorage<T>(key: string, fallbackValue: T): readon
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function b64ValEqual<T>(v1: T, v2: T): boolean {
|
||||
return btoa(JSON.stringify(v1)) === btoa(JSON.stringify(v2));
|
||||
}
|
||||
|
||||
|
||||
function safelyStringify(value: T): string {
|
||||
try {
|
||||
return btoa(JSON.stringify(value));
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { Config } from "tailwindcss"
|
||||
|
||||
// @ts-ignore
|
||||
import {default as flattenColorPalette} from "tailwindcss/lib/util/flattenColorPalette";
|
||||
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
@@ -74,7 +77,19 @@ const config = {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [require("tailwindcss-animate"), addVariablesForColors],
|
||||
} satisfies Config
|
||||
|
||||
// This plugin adds each Tailwind color as a global CSS variable, e.g. var(--gray-200).
|
||||
function addVariablesForColors({ addBase, theme }: any) {
|
||||
let allColors = flattenColorPalette(theme("colors"));
|
||||
let newVars = Object.fromEntries(
|
||||
Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
|
||||
);
|
||||
|
||||
addBase({
|
||||
":root": newVars,
|
||||
});
|
||||
}
|
||||
|
||||
export default config
|
||||
Reference in New Issue
Block a user