added spa
This commit is contained in:
parent
8fd29f043d
commit
62617bfb6f
43
cool_todo_manager/package-lock.json
generated
43
cool_todo_manager/package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
|
"@radix-ui/react-form": "^0.1.2",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/themes": "^3.2.0",
|
"@radix-ui/themes": "^3.2.0",
|
||||||
"@tailwindcss/vite": "^4.0.6",
|
"@tailwindcss/vite": "^4.0.6",
|
||||||
@ -18,6 +19,7 @@
|
|||||||
"jotai": "^2.12.0",
|
"jotai": "^2.12.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-router-dom": "^6.26.2",
|
||||||
"tailwindcss": "^4.0.6"
|
"tailwindcss": "^4.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -2545,6 +2547,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@remix-run/router": {
|
||||||
|
"version": "1.19.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
|
||||||
|
"integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.34.7",
|
"version": "4.34.7",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz",
|
||||||
@ -5323,6 +5334,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "6.26.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz",
|
||||||
|
"integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.19.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "6.26.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.2.tgz",
|
||||||
|
"integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.19.2",
|
||||||
|
"react-router": "6.26.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-style-singleton": {
|
"node_modules/react-style-singleton": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
|
"@radix-ui/react-form": "^0.1.2",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/themes": "^3.2.0",
|
"@radix-ui/themes": "^3.2.0",
|
||||||
"@tailwindcss/vite": "^4.0.6",
|
"@tailwindcss/vite": "^4.0.6",
|
||||||
@ -20,6 +21,7 @@
|
|||||||
"jotai": "^2.12.0",
|
"jotai": "^2.12.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-router-dom": "^6.26.2",
|
||||||
"tailwindcss": "^4.0.6"
|
"tailwindcss": "^4.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -1,14 +1,21 @@
|
|||||||
import { Theme } from '@radix-ui/themes';
|
import { Theme } from '@radix-ui/themes';
|
||||||
import '@radix-ui/themes/styles.css';
|
import '@radix-ui/themes/styles.css';
|
||||||
|
import { QueryClientProvider } from '@tanstack/react-query';
|
||||||
|
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||||
|
import queryClient from './api/queryClient';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import MainBoard from './components/MainBoard/MainBoard';
|
import MyRoutes from './routes/routes';
|
||||||
|
|
||||||
|
const router = createBrowserRouter(MyRoutes);
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Theme accentColor="amber" grayColor="gray">
|
<Theme className='size-full' accentColor="amber" grayColor="gray">
|
||||||
<MainBoard />
|
<QueryClientProvider client={queryClient}>
|
||||||
{/* <ThemePanel /> */}
|
{/* <ThemePanel /> */}
|
||||||
</Theme>
|
<RouterProvider router={router} />
|
||||||
|
</QueryClientProvider>
|
||||||
|
</Theme>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
cool_todo_manager/src/api/axios.ts
Normal file
14
cool_todo_manager/src/api/axios.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const BASE_URL = 'http://localhost:4567';
|
||||||
|
|
||||||
|
export const axiosBase = axios.create({
|
||||||
|
baseURL: BASE_URL,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const axiosAuth = axios.create({
|
||||||
|
baseURL: BASE_URL,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem('token')}` // Maybe we will use cookies
|
||||||
|
}
|
||||||
|
});
|
||||||
11
cool_todo_manager/src/api/queryClient.ts
Normal file
11
cool_todo_manager/src/api/queryClient.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { QueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default queryClient;
|
||||||
@ -8,29 +8,26 @@ const tasks = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
type TCardGroup = {
|
type TCardGroup = {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function CardGroup(props: TCardGroup) {
|
export default function CardGroup(props: TCardGroup) {
|
||||||
return (
|
return (
|
||||||
<Droppable droppableId={props.id}>
|
<Droppable droppableId={props.id}>
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<Box
|
<Box ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
ref={provided.innerRef}
|
{tasks.map((task, i) => (
|
||||||
{...provided.droppableProps}
|
<TaskCard
|
||||||
>
|
key={task.id}
|
||||||
{tasks.map((task, i) => (
|
id={task.id.toString() + props.id}
|
||||||
<TaskCard
|
title={task.title}
|
||||||
key={task.id}
|
description={task.description}
|
||||||
id={task.id.toString() + props.id}
|
index={i}
|
||||||
title={task.title}
|
/>
|
||||||
description={task.description}
|
))}
|
||||||
index={i}
|
{provided.placeholder}
|
||||||
/>
|
</Box>
|
||||||
))}
|
)}
|
||||||
{provided.placeholder}
|
</Droppable>
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1,5 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
#root {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from 'react-dom/client';
|
||||||
import App from "./App.tsx";
|
import App from './App.tsx';
|
||||||
import "./index.css";
|
import './index.css';
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(<App />);
|
createRoot(document.getElementById('root')!).render(<App />);
|
||||||
|
|||||||
52
cool_todo_manager/src/pages/auth/LoginPage/LoginPage.tsx
Normal file
52
cool_todo_manager/src/pages/auth/LoginPage/LoginPage.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Button, Card, Heading, Text, TextField } from '@radix-ui/themes';
|
||||||
|
import { Form } from 'radix-ui';
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card className="absolute top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2 w-fit">
|
||||||
|
<Heading size="4" className='text-center !mb-2'>Login</Heading>
|
||||||
|
|
||||||
|
<Form.Root className="flex flex-col gap-4" onSubmit={e => e.preventDefault()}>
|
||||||
|
<Form.Field name="email">
|
||||||
|
<Form.Message match={'valueMissing'}>
|
||||||
|
<Text>Email is required</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Message match={'typeMismatch'}>
|
||||||
|
<Text>Email is not valid</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Control asChild>
|
||||||
|
<TextField.Root type="email" placeholder="Email">
|
||||||
|
<TextField.Slot />
|
||||||
|
</TextField.Root>
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
|
<Form.Field name="password">
|
||||||
|
<Form.Message match="valueMissing">
|
||||||
|
<Text>Password is required</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Control asChild>
|
||||||
|
<TextField.Root
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
>
|
||||||
|
<TextField.Slot />
|
||||||
|
</TextField.Root>
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
// onClick={(e) => e.preventDefault()}
|
||||||
|
className="mt-4"
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</Button>
|
||||||
|
</Form.Root>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import { Button, Card, Heading, Text, TextField } from '@radix-ui/themes';
|
||||||
|
import { Form } from 'radix-ui';
|
||||||
|
|
||||||
|
export default function RegisterPage() {
|
||||||
|
return (
|
||||||
|
<Card className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-fit">
|
||||||
|
<Heading size="4" className='text-center !mb-2'>Register</Heading>
|
||||||
|
<Form.Root className="flex flex-col gap-4" onSubmit={e => e.preventDefault()}>
|
||||||
|
<Form.Field name="email">
|
||||||
|
<Form.Message match="valueMissing">
|
||||||
|
<Text>Email is required</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Message match="typeMismatch">
|
||||||
|
<Text>Email is not valid</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Control asChild>
|
||||||
|
<TextField.Root
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<TextField.Slot />
|
||||||
|
</TextField.Root>
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
|
<Form.Field name="password">
|
||||||
|
<Form.Message match="valueMissing">
|
||||||
|
<Text>Password is required</Text>
|
||||||
|
</Form.Message>
|
||||||
|
|
||||||
|
<Form.Control asChild>
|
||||||
|
<TextField.Root
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<TextField.Slot />
|
||||||
|
</TextField.Root>
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Field>
|
||||||
|
|
||||||
|
<Button onClick={e => e.preventDefault()} className="mt-4">Register</Button>
|
||||||
|
</Form.Root>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
cool_todo_manager/src/pages/main/MainPage.tsx
Normal file
10
cool_todo_manager/src/pages/main/MainPage.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Box } from '@radix-ui/themes'
|
||||||
|
import { Outlet } from 'react-router-dom'
|
||||||
|
|
||||||
|
export default function MainPage() {
|
||||||
|
return (
|
||||||
|
<Box className='size-full'>
|
||||||
|
<Outlet />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
18
cool_todo_manager/src/routes/routes.tsx
Normal file
18
cool_todo_manager/src/routes/routes.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { createRoutesFromElements, Route } from 'react-router-dom';
|
||||||
|
import MainBoard from '../components/MainBoard/MainBoard';
|
||||||
|
import LoginPage from '../pages/auth/LoginPage/LoginPage';
|
||||||
|
import RegisterPage from '../pages/auth/RegisterPage/RegisterPage';
|
||||||
|
import MainPage from '../pages/main/MainPage';
|
||||||
|
|
||||||
|
const MyRoutes = createRoutesFromElements(
|
||||||
|
<>
|
||||||
|
<Route path="/" element={<MainPage />}>
|
||||||
|
<Route index element={<MainBoard />} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path="login" element={<LoginPage />} />
|
||||||
|
<Route path="register" element={<RegisterPage />} />
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
|
||||||
|
export default MyRoutes;
|
||||||
Loading…
x
Reference in New Issue
Block a user