Initial front end
This commit is contained in:
3
tasker-client/.eslintrc.json
Normal file
3
tasker-client/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "next/typescript"]
|
||||
}
|
||||
3
tasker-client/.prettierrc
Normal file
3
tasker-client/.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
36
tasker-client/README.md
Normal file
36
tasker-client/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
7
tasker-client/next.config.ts
Normal file
7
tasker-client/next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
6725
tasker-client/package-lock.json
generated
Normal file
6725
tasker-client/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
47
tasker-client/package.json
Normal file
47
tasker-client/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "tasker-client",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@mui/material": "^6.1.6",
|
||||
"@mui/x-data-grid": "^7.22.0",
|
||||
"@reduxjs/toolkit": "^2.3.0",
|
||||
"axios": "^1.7.7",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"gantt-task-react": "^0.3.9",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "15.0.2",
|
||||
"numeral": "^2.0.6",
|
||||
"react": "^18.3.1",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-redux": "^9.1.2",
|
||||
"recharts": "^2.13.1",
|
||||
"redux-persist": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/numeral": "^2.0.5",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.2",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.8",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
8
tasker-client/postcss.config.mjs
Normal file
8
tasker-client/postcss.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
66
tasker-client/src/app/(components)/Navbar/index.tsx
Normal file
66
tasker-client/src/app/(components)/Navbar/index.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { Menu, Moon, Search, Settings, Sun } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useAppDispatch, useAppSelector } from "@/app/redux";
|
||||
import { setIsDarkMode, setIsSidebarCollapsed } from "@/state";
|
||||
|
||||
const Navbar = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const isSidebarCollapsed = useAppSelector(
|
||||
(state) => state.global.isSidebarCollapsed,
|
||||
);
|
||||
const isDarkMode = useAppSelector((state) => state.global.isDarkMode);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between bg-white px-4 py-3 dark:bg-black">
|
||||
<div className="flex items-center gap-8">
|
||||
{!isSidebarCollapsed ? null : (
|
||||
<button
|
||||
onClick={() => dispatch(setIsSidebarCollapsed(!isSidebarCollapsed))}
|
||||
>
|
||||
<Menu className="h-8 w-8 dark:text-white" />
|
||||
</button>
|
||||
)}
|
||||
<div className="relative flex h-min w-[200px]">
|
||||
<Search className="absolute left-[6px] top-1/2 mr-2 h-5 w-5 -translate-y-1/2 transform cursor-pointer dark:text-white" />
|
||||
<input
|
||||
className="w-full rounded border-none bg-gray-100 p-2 pl-8 placeholder-gray-500 focus:border-transparent focus:outline-none dark:bg-gray-700 dark:text-white dark:placeholder-white"
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Icons */}
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
onClick={() => dispatch(setIsDarkMode(!isDarkMode))}
|
||||
className={
|
||||
isDarkMode
|
||||
? "rounded p-2 dark:hover:bg-gray-700"
|
||||
: "rounded p-2 hover:bg-gray-100"
|
||||
}
|
||||
>
|
||||
{isDarkMode ? (
|
||||
<Sun className="e-6 h-6 cursor-pointer dark:text-white" />
|
||||
) : (
|
||||
<Moon className="e-6 h-6 cursor-pointer dark:text-white" />
|
||||
)}
|
||||
</button>
|
||||
<Link
|
||||
href="settings"
|
||||
className={
|
||||
isDarkMode
|
||||
? "h-min w-min rounded p-2 dark:hover:bg-gray-700"
|
||||
: "h-min w-min rounded p-2 hover:bg-gray-100"
|
||||
}
|
||||
>
|
||||
<Settings className="h-6 w-6 cursor-pointer dark:text-white" />
|
||||
</Link>
|
||||
<div className="ml-2 mr-2 hidden min-h-[2em] w-[0.1rem] bg-gray-200 md:inline-block"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
162
tasker-client/src/app/(components)/Sidebar/index.tsx
Normal file
162
tasker-client/src/app/(components)/Sidebar/index.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
AlertCircle,
|
||||
AlertOctagon,
|
||||
AlertTriangle,
|
||||
Briefcase,
|
||||
ChevronDownCircleIcon,
|
||||
ChevronDownSquareIcon,
|
||||
ChevronUpCircleIcon,
|
||||
ChevronUpSquareIcon,
|
||||
Home,
|
||||
Layers3,
|
||||
LockIcon,
|
||||
LucideIcon,
|
||||
Search,
|
||||
Settings,
|
||||
ShieldAlert,
|
||||
User,
|
||||
Users,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { setIsSidebarCollapsed } from "@/state";
|
||||
import { useAppDispatch, useAppSelector } from "@/app/redux";
|
||||
import Link from "next/link";
|
||||
|
||||
const Sidebar = () => {
|
||||
const [showProjects, setShowProjects] = React.useState(true);
|
||||
const [showPriority, setShowPriority] = React.useState(true);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const isSidebarCollapsed = useAppSelector(
|
||||
(state) => state.global.isSidebarCollapsed,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed z-40 flex h-full w-64 flex-col justify-between overflow-y-auto bg-white shadow-xl transition-all duration-300 dark:bg-black ${isSidebarCollapsed ? "hidden w-0" : "w-64"}`}
|
||||
>
|
||||
<div className="flex h-full w-full flex-col justify-start">
|
||||
<div className="z-50 flex min-h-[56px] w-64 items-center justify-between bg-white px-6 pt-3 dark:bg-black">
|
||||
<div className="text-xl font-bold text-gray-800 dark:text-white">
|
||||
Tasker.IO
|
||||
</div>
|
||||
{isSidebarCollapsed ? null : (
|
||||
<button
|
||||
className="py-3"
|
||||
onClick={() =>
|
||||
dispatch(setIsSidebarCollapsed(!isSidebarCollapsed))
|
||||
}
|
||||
>
|
||||
<X className="h-6 w-6 text-gray-800 hover:text-gray-500 dark:text-white" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-5 border-y-[1.5px] border-gray-200 px-8 py-4 dark:border-gray-700">
|
||||
<Image src="/logo.png" alt="logo" width={40} height={40} />
|
||||
<div>
|
||||
<h3 className="text-md font-bold tracking-widest dark:text-gray-200">
|
||||
Tasker.IO
|
||||
</h3>
|
||||
<div className="mt-1 flex items-start gap-2">
|
||||
<LockIcon className="mt-[0.1rem] h-3 w-3 text-gray-500 dark:text-gray-400" />
|
||||
<p className="text-xs text-gray-500">Private</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="z-10 w-full">
|
||||
<SidebarLink icon={Home} label="Home" href="/" />
|
||||
<SidebarLink icon={Briefcase} label="Timeline" href="/timeline" />
|
||||
<SidebarLink icon={Search} label="Search" href="/search" />
|
||||
<SidebarLink icon={Settings} label="Settings" href="/settings" />
|
||||
<SidebarLink icon={User} label="Users" href="/users" />
|
||||
<SidebarLink icon={Users} label="Teams" href="/teams" />
|
||||
</nav>
|
||||
|
||||
<button
|
||||
onClick={() => setShowProjects((prev) => !prev)}
|
||||
className="flex w-full items-center justify-between px-8 py-3 text-gray-500"
|
||||
>
|
||||
<span className="">Projects</span>
|
||||
{showProjects ? (
|
||||
<ChevronDownCircleIcon className="h-5 w-5" />
|
||||
) : (
|
||||
<ChevronUpCircleIcon className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setShowPriority((prev) => !prev)}
|
||||
className="flex w-full items-center justify-between px-8 py-3 text-gray-500"
|
||||
>
|
||||
<span className="">Priority</span>
|
||||
{showPriority ? (
|
||||
<ChevronDownSquareIcon className="h-5 w-5" />
|
||||
) : (
|
||||
<ChevronUpSquareIcon className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
{showPriority && (
|
||||
<>
|
||||
<SidebarLink
|
||||
icon={AlertCircle}
|
||||
label="Urgent"
|
||||
href="/priority/urgent"
|
||||
/>
|
||||
<SidebarLink
|
||||
icon={ShieldAlert}
|
||||
label="High"
|
||||
href="/priority/high"
|
||||
/>
|
||||
<SidebarLink
|
||||
icon={AlertTriangle}
|
||||
label="Medium"
|
||||
href="/priority/medium"
|
||||
/>
|
||||
<SidebarLink icon={AlertOctagon} label="Low" href="/priority/low" />
|
||||
<SidebarLink
|
||||
icon={Layers3}
|
||||
label="Backlog"
|
||||
href="/priority/backlog"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface SidebarLinkProps {
|
||||
href: string;
|
||||
icon: LucideIcon;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const SidebarLink = ({ href, icon: Icon, label }: SidebarLinkProps) => {
|
||||
const pathname = usePathname();
|
||||
const isActive = pathname === href || (pathname === "/" && href === "/home");
|
||||
|
||||
return (
|
||||
<Link href={href} className="w-full">
|
||||
<div
|
||||
className={`relative flex cursor-pointer items-center gap-3 transition-colors hover:bg-gray-100 dark:bg-black dark:hover:bg-gray-700 ${
|
||||
isActive ? "bg-gray-100 text-white dark:bg-gray-600" : ""
|
||||
} justify-start px-8 py-3`}
|
||||
>
|
||||
{isActive && (
|
||||
<div className="absolute left-0 top-0 h-[100%] w-[5px] bg-blue-200" />
|
||||
)}
|
||||
|
||||
<Icon className="h-6 w-6 text-gray-800 dark:text-gray-100" />
|
||||
<span className={`font-medium text-gray-800 dark:text-gray-100`}>
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
43
tasker-client/src/app/dashboardWrapper.tsx
Normal file
43
tasker-client/src/app/dashboardWrapper.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import Navbar from "@/app/(components)/Navbar";
|
||||
import Sidebar from "@/app/(components)/Sidebar";
|
||||
import StoreProvider, { useAppSelector } from "./redux";
|
||||
|
||||
const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
const isSidebarCollapsed = useAppSelector(
|
||||
(state) => state.global.isSidebarCollapsed,
|
||||
);
|
||||
const isDarkMode = useAppSelector((state) => state.global.isDarkMode);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDarkMode) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen w-full bg-gray-50 text-gray-900">
|
||||
<Sidebar />
|
||||
<main
|
||||
className={`flex w-full flex-col bg-gray-50 dark:bg-dark-bg ${isSidebarCollapsed ? "" : "md:pl-64"}`}
|
||||
>
|
||||
<Navbar />
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const DashboardWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<StoreProvider>
|
||||
<DashboardLayout>{children}</DashboardLayout>
|
||||
</StoreProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardWrapper;
|
||||
BIN
tasker-client/src/app/favicon.ico
Normal file
BIN
tasker-client/src/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
tasker-client/src/app/fonts/GeistMonoVF.woff
Normal file
BIN
tasker-client/src/app/fonts/GeistMonoVF.woff
Normal file
Binary file not shown.
BIN
tasker-client/src/app/fonts/GeistVF.woff
Normal file
BIN
tasker-client/src/app/fonts/GeistVF.woff
Normal file
Binary file not shown.
20
tasker-client/src/app/globals.css
Normal file
20
tasker-client/src/app/globals.css
Normal file
@@ -0,0 +1,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root,
|
||||
.app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@apply text-sm;
|
||||
@apply bg-gray-500;
|
||||
@apply text-gray-900;
|
||||
}
|
||||
24
tasker-client/src/app/layout.tsx
Normal file
24
tasker-client/src/app/layout.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import DashboardWrapper from "./dashboardWrapper";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<DashboardWrapper>{children}</DashboardWrapper>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
7
tasker-client/src/app/page.tsx
Normal file
7
tasker-client/src/app/page.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-center h-screen">
|
||||
New
|
||||
</main>
|
||||
);
|
||||
}
|
||||
100
tasker-client/src/app/redux.tsx
Normal file
100
tasker-client/src/app/redux.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
import { useRef } from "react";
|
||||
import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
||||
import {
|
||||
TypedUseSelectorHook,
|
||||
useDispatch,
|
||||
useSelector,
|
||||
Provider,
|
||||
} from "react-redux";
|
||||
import globalReducer from "@/state";
|
||||
import { api } from "@/state/api";
|
||||
import { setupListeners } from "@reduxjs/toolkit/query";
|
||||
|
||||
import {
|
||||
persistStore,
|
||||
persistReducer,
|
||||
FLUSH,
|
||||
REHYDRATE,
|
||||
PAUSE,
|
||||
PERSIST,
|
||||
PURGE,
|
||||
REGISTER,
|
||||
} from "redux-persist";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import createWebStorage from "redux-persist/lib/storage/createWebStorage";
|
||||
|
||||
/* REDUX PERSISTENCE */
|
||||
const createNoopStorage = () => {
|
||||
return {
|
||||
getItem(_key: any) {
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
setItem(_key: any, value: any) {
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
removeItem(_key: any) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const storage =
|
||||
typeof window === "undefined"
|
||||
? createNoopStorage()
|
||||
: createWebStorage("local");
|
||||
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
whitelist: ["global"],
|
||||
};
|
||||
const rootReducer = combineReducers({
|
||||
global: globalReducer,
|
||||
[api.reducerPath]: api.reducer,
|
||||
});
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
/* REDUX STORE */
|
||||
export const makeStore = () => {
|
||||
return configureStore({
|
||||
reducer: persistedReducer,
|
||||
middleware: (getDefault) =>
|
||||
getDefault({
|
||||
serializableCheck: {
|
||||
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
|
||||
},
|
||||
}).concat(api.middleware),
|
||||
});
|
||||
};
|
||||
|
||||
/* REDUX TYPES */
|
||||
export type AppStore = ReturnType<typeof makeStore>;
|
||||
export type RootState = ReturnType<AppStore["getState"]>;
|
||||
export type AppDispatch = AppStore["dispatch"];
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
|
||||
/* PROVIDER */
|
||||
export default function StoreProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const storeRef = useRef<AppStore>();
|
||||
if (!storeRef.current) {
|
||||
storeRef.current = makeStore();
|
||||
setupListeners(storeRef.current.dispatch);
|
||||
}
|
||||
const persistor = persistStore(storeRef.current);
|
||||
|
||||
return (
|
||||
<Provider store={storeRef.current}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
{children}
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
10
tasker-client/src/state/api.ts
Normal file
10
tasker-client/src/state/api.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query";
|
||||
|
||||
export const api = createApi({
|
||||
baseQuery: fetchBaseQuery({ baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL }),
|
||||
reducerPath: "api",
|
||||
tagTypes: ["Task"],
|
||||
endpoints: (builder) => ({}),
|
||||
});
|
||||
|
||||
export const {} = api;
|
||||
27
tasker-client/src/state/index.tsx
Normal file
27
tasker-client/src/state/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
export interface initialStateType {
|
||||
isSidebarCollapsed: boolean;
|
||||
isDarkMode: boolean;
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
isSidebarCollapsed: false,
|
||||
isDarkMode: false,
|
||||
};
|
||||
|
||||
export const globalSlice = createSlice({
|
||||
name: "global",
|
||||
initialState,
|
||||
reducers: {
|
||||
setIsSidebarCollapsed: (state, action: PayloadAction<boolean>) => {
|
||||
state.isSidebarCollapsed = action.payload;
|
||||
},
|
||||
setIsDarkMode: (state, action: PayloadAction<boolean>) => {
|
||||
state.isDarkMode = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setIsSidebarCollapsed, setIsDarkMode } = globalSlice.actions;
|
||||
export default globalSlice.reducer;
|
||||
44
tasker-client/tailwind.config.ts
Normal file
44
tasker-client/tailwind.config.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config: Config = {
|
||||
darkMode: "class",
|
||||
content: [
|
||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
white: "#ffffff",
|
||||
grey: {
|
||||
100: "#f3f4f6",
|
||||
200: "#e5e7eb",
|
||||
300: "#d1d5db",
|
||||
400: "#9ca3af",
|
||||
500: "#6b7280",
|
||||
600: "#4b5563",
|
||||
700: "#374151",
|
||||
800: "#1f2937",
|
||||
},
|
||||
blue: {
|
||||
100: "#dbeafe",
|
||||
200: "#bfdbfe",
|
||||
300: "#93c5fd",
|
||||
400: "#60a5fa",
|
||||
500: "#3b82f6",
|
||||
600: "#2563eb",
|
||||
700: "#1d4ed8",
|
||||
800: "#1e40af",
|
||||
},
|
||||
"dark-bg": "#101214",
|
||||
"dark-secondary": "#1e2029",
|
||||
"dark-tertiary": "#25262d",
|
||||
"blue-primary": "#3b82f6",
|
||||
"stroke-dark": "#2d3135",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
export default config;
|
||||
27
tasker-client/tsconfig.json
Normal file
27
tasker-client/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user