├── styles
├── globals.css
└── globalsCSS.css
├── .env.example
├── public
├── plus.png
├── logo500.png
├── logonew.png
├── logo__1_-removebg-preview.png
└── log.svg
├── images
└── image1.png
├── postcss.config.js
├── .eslintrc.json
├── next.config.js
├── pages
├── api
│ ├── checkusername
│ │ └── [username].js
│ ├── getUserInfo.js
│ ├── todo
│ │ ├── createone.js
│ │ ├── fetchall.js
│ │ └── deleteone
│ │ │ └── [id].js
│ └── auth
│ │ ├── check
│ │ └── [username].js
│ │ ├── login.js
│ │ └── createuser.js
├── _app.js
├── index.js
├── Login.js
└── Signup.js
├── tailwind.config.js
├── .vscode
└── tasks.json
├── mongoconnect.js
├── .gitignore
├── context
├── detail.js
└── data.js
├── models
├── notes.js
└── user.js
├── package.json
├── lib
└── redisConnect.js
├── README.md
└── components
├── Messages.js
└── SendMessage.js
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | MONGODB_URI=__database_uri__
2 | JWT_INFO=__JWT_INFO__
3 | REDIS_URI=__REDIS_URI__
--------------------------------------------------------------------------------
/public/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/innovatorved/LetsDo-with-TODO/HEAD/public/plus.png
--------------------------------------------------------------------------------
/images/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/innovatorved/LetsDo-with-TODO/HEAD/images/image1.png
--------------------------------------------------------------------------------
/public/logo500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/innovatorved/LetsDo-with-TODO/HEAD/public/logo500.png
--------------------------------------------------------------------------------
/public/logonew.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/innovatorved/LetsDo-with-TODO/HEAD/public/logonew.png
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals",
3 | "rules": {
4 | "@next/next/no-img-element": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/public/logo__1_-removebg-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/innovatorved/LetsDo-with-TODO/HEAD/public/logo__1_-removebg-preview.png
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | }
5 |
6 | module.exports = nextConfig
7 |
--------------------------------------------------------------------------------
/pages/api/checkusername/[username].js:
--------------------------------------------------------------------------------
1 |
2 | const {nodeRedisGet} = require('../../../lib/redisConnect')
3 |
4 | export default async function handler(req, res) {
5 |
6 | return res.status(400).json({success : false});
7 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: [
3 | "./pages/**/*.{js,ts,jsx,tsx}",
4 | "./components/**/*.{js,ts,jsx,tsx}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globalsCSS.css'
2 | import States from '../context/data';
3 |
4 | function MyApp({ Component, pageProps }) {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
12 | export default MyApp;
13 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "Run the Nextjs Application in Dev mode",
6 | "type": "shell",
7 | "command": "npm run dev",
8 | "group": "none",
9 | "presentation": {
10 | "reveal": "always",
11 | "panel": "new"
12 | },
13 | "runOptions": { "runOn": "folderOpen" }
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/pages/api/getUserInfo.js:
--------------------------------------------------------------------------------
1 | const { fetchUserDetails } = require("../../context/detail");
2 |
3 | export default async function handler(req, res) {
4 | const token = req.headers.authtoken;
5 | const data = await fetchUserDetails(token);
6 |
7 | if (data.success){
8 | return res.status(200).json({
9 | success: true,
10 | data : data.details
11 | });
12 | }
13 | return res.status(400).json({success : false});
14 | }
--------------------------------------------------------------------------------
/mongoconnect.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const mongoURI = process.env.MONGODB_URI;
3 |
4 | const connection = {};
5 |
6 | const connectToMongo = async() => {
7 | if (connection.isConnected){
8 | return ;
9 | }
10 |
11 | const db = await mongoose.connect(mongoURI, {
12 | useNewUrlParser: true,
13 | useUnifiedTopology: true
14 | })
15 |
16 | connection.isConnected = db.connections[0].readyState;
17 | }
18 |
19 | module.exports = connectToMongo;
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env.local
30 | .env.development.local
31 | .env.test.local
32 | .env.production.local
33 |
34 | # vercel
35 | .vercel
36 |
--------------------------------------------------------------------------------
/context/detail.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const JWT_KEY = process.env.JWT_INFO;
3 | const connectToMongo = require('../mongoconnect');
4 |
5 | exports.fetchUserDetails = async function (token){
6 | if (!token) {
7 | return ({success : false , details : null});
8 | }
9 | await connectToMongo();
10 | try {
11 | const userDetail = await jwt.verify(token , JWT_KEY);
12 | return ({success : true, details : userDetail.user});
13 | } catch (error) {
14 | return ({success : false , details : null});
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/models/notes.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const { Schema } = mongoose;
3 |
4 | const NotesSchema = new Schema({
5 | user : {
6 | type : mongoose.Schema.Types.ObjectId,
7 | ref : "notes"
8 | },
9 | main : {
10 | type: String,
11 | required: true
12 | },
13 | flag : {
14 | type : Boolean,
15 | default: false
16 | },
17 | timestamp : {
18 | type: Date,
19 | default: Date.now
20 |
21 | }
22 | });
23 |
24 | module.exports = mongoose.models.notes || mongoose.model('notes' , NotesSchema);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "bcryptjs": "^2.4.3",
13 | "jsonwebtoken": "^8.5.1",
14 | "mongoose": "^6.2.7",
15 | "next": "12.1.0",
16 | "react": "17.0.2",
17 | "react-dom": "17.0.2",
18 | "redis": "^4.0.4"
19 | },
20 | "devDependencies": {
21 | "autoprefixer": "^10.4.4",
22 | "eslint": "8.10.0",
23 | "eslint-config-next": "12.1.0",
24 | "postcss": "^8.4.12",
25 | "tailwindcss": "^3.0.23"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/models/user.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const { Schema } = mongoose;
3 |
4 | const UserSchema = new Schema({
5 | name : {
6 | type: String,
7 | required: true
8 | },
9 | username : {
10 | type: String,
11 | required: true,
12 | unique: true
13 | },
14 | email : {
15 | type: String,
16 | required: true,
17 | unique: true
18 | },
19 | password : {
20 | type: String,
21 | required: true
22 | },
23 | date : {
24 | type: Date,
25 | default: Date.now
26 |
27 | }
28 | });
29 | module.exports = mongoose.models.user || mongoose.model('user' , UserSchema);
--------------------------------------------------------------------------------
/pages/api/todo/createone.js:
--------------------------------------------------------------------------------
1 | const { fetchUserDetails } = require("../../../context/detail");
2 | const notes = require("../../../models/notes");
3 |
4 | export default async function handler(req, res) {
5 | const { msg } = req.body;
6 | const token = req.headers.authtoken;
7 |
8 | const data = await fetchUserDetails(token);
9 | if (!data.success || msg == ""){
10 | return res.status(401).json({
11 | success: false,
12 | message: "Unauthorized"
13 | });
14 | }
15 | const userId = data.details.id;
16 | const note = new notes({main : msg , user : userId});
17 | const savenote = await note.save();
18 | return res.status(200).json({success : true , savenote});
19 | }
--------------------------------------------------------------------------------
/lib/redisConnect.js:
--------------------------------------------------------------------------------
1 | const { createClient } = require('redis');
2 |
3 | async function nodeRedisSet ( username , msg) {
4 | try {
5 | const client = createClient({
6 | url : process.env.REDIS_URI
7 | });
8 | await client.connect();
9 | const val = await client.set(username , msg);
10 | await client.quit();
11 | return val;
12 | } catch (error) {
13 | return false;
14 | }
15 | }
16 |
17 | async function nodeRedisGet ( username ) {
18 | try {
19 | const client = createClient({
20 | url : process.env.REDIS_URI
21 | });
22 | await client.connect();
23 | const val = await client.get(username);
24 | await client.quit();
25 | return val;
26 | } catch (error) {
27 | return false;
28 | }
29 | }
30 |
31 | export {
32 | nodeRedisSet ,
33 | nodeRedisGet
34 | };
--------------------------------------------------------------------------------
/pages/api/todo/fetchall.js:
--------------------------------------------------------------------------------
1 | const { fetchUserDetails } = require("../../../context/detail");
2 | const notes = require("../../../models/notes");
3 |
4 | export default async function handler(req, res) {
5 | if (req.method !== 'GET') { return res.status(500).json({ success : false, error: "Internal Server try after some time : method Problem" }); }
6 |
7 | const token = req.headers.authtoken;
8 | const data = await fetchUserDetails(token);
9 | if (!data.success){
10 | return res.status(401).json({
11 | success: false,
12 | message: "Unauthorized"
13 | });
14 | }
15 |
16 | try {
17 | const userId = data.details.id;
18 | const note = await notes.find({user : userId} , {user : 0 , __v : 0});
19 | return res.status(200).json({success:true , note});
20 | } catch (error) {
21 | return res.status(400).json({success:false});
22 | }
23 | }
--------------------------------------------------------------------------------
/pages/api/auth/check/[username].js:
--------------------------------------------------------------------------------
1 | const bcrypt = require('bcryptjs');
2 | const jwt = require('jsonwebtoken');
3 |
4 | const user = require('../../../../models/user');
5 |
6 | const connectToMongo = require('../../../../mongoconnect');
7 | const JWT_key = process.env.JWT_INFO;
8 |
9 | export default async function handler(req, res) {
10 | let success = false;
11 | const { username } = req.query;
12 |
13 | if (req.method !== 'PUT') { return res.status(500).json({ success, error: "Internal Server try after some time : method Problem" }); }
14 |
15 | try {
16 | await connectToMongo();
17 | const UserDetails = await user.findOne({ username });
18 |
19 | success = true;
20 | if (UserDetails) {
21 | return res.json({ success, "res": true });
22 | }
23 | else {
24 | return res.json({ success, "res": false });
25 | }
26 |
27 | } catch (error) {
28 | success = false;
29 | return res.status(500).json({ success, error: "Some Error" });
30 | }
31 | }
--------------------------------------------------------------------------------
/pages/api/todo/deleteone/[id].js:
--------------------------------------------------------------------------------
1 | const { fetchUserDetails } = require("../../../../context/detail");
2 | const notes = require("../../../../models/notes");
3 |
4 | export default async function handler(req, res) {
5 | if (req.method !== 'DELETE') { return res.status(500).json({ success: false, error: "Internal Server try after some time : method Problem" }); }
6 | try {
7 | const token = req.headers.authtoken;
8 | const { id } = req.query;
9 | const data = await fetchUserDetails(token);
10 | if (!data.success) {
11 | return res.status(401).json({
12 | success: false,
13 | message: "Unauthorized"
14 | });
15 | }
16 | const noteID = id.toString();
17 | const userId = data.details.id;
18 | const delNote = await notes.findOneAndDelete({ _id: noteID, user: userId });
19 | return res.status(200).json({ success:true , msg : delNote });
20 | } catch (error) {
21 | return res.status(200).json({ success:false , msg : "note deleted" });
22 | }
23 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # LetsDo-with-TODO
6 |
7 | A todo application built with Next.js and MongoDB provides a simple and efficient way to manage tasks and stay organized.
8 |
9 | ## Demo
10 |
11 | 
12 |
13 | ## Deployment
14 |
15 | To deploy this project run
16 |
17 | ### Clone the Repo
18 |
19 | ```bash
20 | git clone https://github.com/innovatorved/LetsDo-with-TODO.git
21 | ```
22 |
23 | ### Install Dependencies and Run
24 |
25 | ```bash
26 | cd LetsDo-with-TODO
27 | npm install
28 | npm run dev
29 | ```
30 |
31 | ## Tech Stack
32 |
33 | **Client:** Nextjs , React, react-router-dom
34 |
35 | **Server:** bcryptjs ,express , express-validator , jsonwebtoken ,mongoose
36 |
37 | **Database:** MongoDB
38 |
39 | ## Screenshots
40 |
41 | 
42 |
43 |
44 | ## License
45 |
46 | [MIT](https://choosealicense.com/licenses/mit/)
47 |
48 | ## Authors
49 |
50 | - [Ved Gupta](https://www.github.com/innovatorved)
51 |
52 | ## 🚀 About Me
53 |
54 | I'm a Developer i will feel the code then write .
55 |
56 | ## Support
57 |
58 | For support, email vedgupta@protonmail.com
59 |
--------------------------------------------------------------------------------
/public/log.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
--------------------------------------------------------------------------------
/components/Messages.js:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import { StateManager } from '../context/data';
3 |
4 | export default function Messages() {
5 | const { data, changeState } = useContext(StateManager);
6 | return (
7 |
8 |
9 | {
10 | data.map((item, index) => {
11 | return (
12 |
13 |
14 | {
15 | item.state ?
16 | {item.msg}
17 | :
18 |
19 | }
20 |
21 |
changeState(index)
23 | } readOnly/>
24 |
25 | )
26 | })
27 | }
28 |
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/pages/api/auth/login.js:
--------------------------------------------------------------------------------
1 | const bcrypt = require('bcryptjs');
2 | const jwt = require('jsonwebtoken');
3 | const user = require('../../../models/user');
4 |
5 | const connectToMongo = require('../../../mongoconnect');
6 | const JWT_key = process.env.JWT_INFO;
7 |
8 | export default async function handler(req, res) {
9 | let success = false;
10 | if (req.method !== 'POST') { return res.status(500).json({ success, error: "Internal Server try after some time : method Problem" }); }
11 |
12 | try {
13 | await connectToMongo();
14 | const {email , password} = req.body;
15 | const userDetails = await user.findOne({ email });
16 |
17 | if (!userDetails) {
18 | success = false;
19 | return res.status(400).json({ success, error: "EmailId not Registered" });
20 | }
21 |
22 | const passwordCompare = await bcrypt.compare(password, userDetails.password);
23 | if (!passwordCompare) {
24 | success = false;
25 | return res.status(400).json({ success, error: "Please try to login with Correct Credentials" });
26 | }
27 | const data = {
28 | user: {
29 | id: userDetails.id,
30 | name : userDetails.name,
31 | username : userDetails.username,
32 | date : Date.now(),
33 | }
34 | };
35 |
36 | const authtoken = jwt.sign(data, JWT_key);
37 | success = true;
38 | return res.json({ success, authtoken , userDetails});
39 |
40 | } catch (error) {
41 | success = false;
42 | return res.status(500).json({ success, error: "Internal Server try after some time" });
43 | }
44 | }
--------------------------------------------------------------------------------
/pages/api/auth/createuser.js:
--------------------------------------------------------------------------------
1 | const bcrypt = require('bcryptjs');
2 | const jwt = require('jsonwebtoken');
3 | const user = require('../../../models/user');
4 |
5 | const {nodeRedisSet} = require('../../../lib/redisConnect');
6 |
7 | const connectToMongo = require('../../../mongoconnect');
8 | const JWT_key = process.env.JWT_INFO;
9 |
10 | export default async function handler(req, res) {
11 | let success = false;
12 | if (req.method !== 'POST') {return res.status(500).json({success , error :"Internal Server try after some time : method Problem"});}
13 |
14 | try {
15 | await connectToMongo();
16 | const userEmail = await user.findOne({ email: req.body.email });
17 | const userusername = await user.findOne({ username: req.body.username });
18 |
19 | if (userEmail) {
20 | success = false;
21 | return res.status(400).json({ success, error: "user with samee email id already Registered" });
22 | }
23 | if (userusername) {
24 | success = false;
25 | return res.status(400).json({ success, error: "user with samee username already Registered" });
26 | }
27 |
28 | const salt = await bcrypt.genSaltSync(10);
29 | const secPass = await bcrypt.hashSync(req.body.password, salt);
30 |
31 | const createuser = await user.create({
32 | name: req.body.name,
33 | username: req.body.username,
34 | email: req.body.email,
35 | password: secPass,
36 | });
37 |
38 | const data = {
39 | user: {
40 | id: createuser.id,
41 | name : createuser.name,
42 | username : createuser.username,
43 | date : Date.now(),
44 | }
45 | };
46 |
47 | const authtoken = jwt.sign(data, JWT_key);
48 | success = true;
49 | nodeRedisSet(createuser.username , authtoken);
50 | return res.status(200).json({ success, authtoken });
51 | } catch (error) {
52 | success = false;
53 | return res.status(500).json({success , error :"Internal Server try after some time"});
54 | }
55 | }
--------------------------------------------------------------------------------
/context/data.js:
--------------------------------------------------------------------------------
1 | import { createContext, useState, useEffect } from 'react';
2 |
3 | // Createcontext
4 | const StateManager = createContext();
5 |
6 |
7 | const States = (props) => {
8 |
9 | const host = '';
10 |
11 | const [userInfo, setUserInfo] = useState({
12 | name: '',
13 | username: ''
14 | });
15 |
16 |
17 | const list = [];
18 |
19 | const [data, setData] = useState(list);
20 |
21 | const LogOut = () => {
22 | localStorage.removeItem('token');
23 | localStorage.removeItem('name');
24 | localStorage.removeItem('username');
25 | setUserInfo({
26 | name: '',
27 | username: ''
28 | });
29 | setData([]);
30 | };
31 |
32 | const AddData = (note) => {
33 | const add = {
34 | msg: note.msg,
35 | timestamp: note.time,
36 | state: false
37 | };
38 | setData(data => [add, ...data]);
39 | fetch(host + "/api/todo/createone", {
40 | method: "POST",
41 | headers: {
42 | "Content-Type": "application/json",
43 | authtoken: localStorage.getItem("token"),
44 | },
45 | body: JSON.stringify(add),
46 | })
47 | .then((res) => res.json())
48 | .then((data) => {
49 | if (data.success) {
50 | console.log(data.success);
51 | }
52 | })
53 | .catch((err) => console.log(err));
54 | }
55 |
56 | const changeState = (index) => {
57 | const exactIndex = index;
58 | const newArray = [...data];
59 | let ele = newArray[exactIndex]
60 | localStorage.setItem(ele.id, !ele.state);
61 | newArray[exactIndex] = { ...ele, state: !ele.state }
62 | setData(newArray);
63 | }
64 |
65 |
66 | return (
67 |
68 | {props.children}
69 |
70 | )
71 | }
72 |
73 | export default States;
74 | export {
75 | StateManager
76 | };
--------------------------------------------------------------------------------
/components/SendMessage.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext } from 'react';
2 | import Image from 'next/image';
3 |
4 | import { StateManager } from '../context/data';
5 | import Router from 'next/router';
6 |
7 | export default function SendMessage() {
8 | const { AddData , userInfo , LogOut} = useContext(StateManager);
9 |
10 | const [Plus, setPlus] = useState({
11 | height: 27,
12 | weigth: 27
13 | });
14 |
15 | const messageSubmitted = (e) => {
16 | e.preventDefault();
17 | const line = e.target.elements.message.value;
18 | if (line.trim() !== "" && line.trim() !== null) {
19 | const data2 = {
20 | name: userInfo.name,
21 | msg: line,
22 | time: new Date().toLocaleTimeString()
23 | }
24 | e.target.elements.message.value = '';
25 | AddData(
26 | data2
27 | );
28 | }
29 | }
30 |
31 | return (
32 |
62 | )
63 | }
64 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head';
2 | import SendMessage from '../components/SendMessage';
3 | import Messages from '../components/Messages';
4 | import { useEffect, useContext } from 'react';
5 | import Router from 'next/router';
6 | import { StateManager } from '../context/data';
7 |
8 | export default function Home() {
9 | const { setUserInfo, LogOut, host, data, setData } = useContext(StateManager);
10 |
11 | useEffect(() => {
12 | if (!localStorage.getItem('token')) {
13 | LogOut();
14 | Router.push('/Login');
15 | }
16 | })
17 |
18 | useEffect(async() => {
19 | if (data.length === 0) {
20 | fetch(host + "/api/todo/fetchall", {
21 | method: "GET",
22 | headers: {
23 | "Content-Type": "application/json",
24 | authtoken: localStorage.getItem("token"),
25 | },
26 | })
27 | .then((res) => res.json())
28 | .then((dataNotes) => {
29 | const notes = [];
30 | if (dataNotes.success) {
31 | dataNotes.note.map((note) => {
32 | const state = localStorage.getItem(note._id);
33 | const add = {
34 | id : note._id,
35 | msg: note.main,
36 | timestamp: note.timestamp,
37 | state: state===null?false:state==="true"?true:false
38 | };
39 | notes.push(add);
40 | });
41 | // reverse notes
42 | notes.reverse();
43 | setData(notes);
44 | }
45 | })
46 | .catch((err) => {
47 | console.log(err);
48 | });
49 | }
50 | }, []);
51 |
52 |
53 |
54 | useEffect(async () => {
55 | if (localStorage.getItem('name') === null) {
56 | const tok = localStorage.getItem("token");
57 | const response = await fetch(host + '/api/getUserInfo', {
58 | method: 'GET',
59 | headers: {
60 | 'Content-Type': 'application/json',
61 | 'authtoken': tok
62 | }
63 | });
64 | const data = await response.json();
65 | if (data.success) {
66 | setUserInfo(data.data);
67 | localStorage.setItem('name', data.data.name);
68 | localStorage.setItem('username', data.data.username);
69 | }
70 | }
71 | else {
72 | setUserInfo({
73 | name: localStorage.getItem("name"),
74 | username: localStorage.getItem("username")
75 | })
76 | }
77 | }, [])
78 |
79 | return (
80 |
81 |
82 |
ToDo
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
98 |
99 |
100 |
101 |
102 | )
103 | }
104 |
--------------------------------------------------------------------------------
/pages/Login.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from 'react';
2 | import Router from 'next/router';
3 | import { StateManager } from '../context/data';
4 | import Head from 'next/head';
5 |
6 |
7 | export default function Login() {
8 | const { host } = useContext(StateManager);
9 | useEffect(() => {
10 | if (localStorage.getItem('token')) {
11 | Router.push('/');
12 | }
13 | })
14 | const [data, setData] = useState({
15 | email: "",
16 | password: ""
17 | })
18 |
19 | const OnChangeData = (e) => {
20 | setData({
21 | ...data,
22 | [e.target.name]: e.target.value
23 | })
24 | }
25 |
26 | const LoginSubitted = (e) => {
27 | e.preventDefault();
28 | fetch(host + '/api/auth/login', {
29 | method: 'POST',
30 | headers: {
31 | 'Content-Type': 'application/json'
32 | },
33 | body: JSON.stringify(data)
34 | })
35 | .then(res => res.json())
36 | .then(res => {
37 | if (res.success) {
38 | localStorage.setItem('token', res.authtoken);
39 | Router.push('/');
40 | } else {
41 | alert(res.error);
42 | }
43 | })
44 | }
45 |
46 | return (
47 | <>
48 |
49 | Login to TODO
50 |
51 |
52 |
53 |
54 |
55 |
56 |

57 |
Sign in to your TODO
58 |
59 |
60 |
61 |
62 |
63 |
71 |
72 |
We take privacy issues seriously. You can be sure that your personal data is securely protected.
73 |
74 |
79 |
80 |
81 |
112 |
113 |
114 |
115 | >
116 | )
117 | }
118 |
--------------------------------------------------------------------------------
/pages/Signup.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from 'react';
2 | import Router from 'next/router';
3 | import { StateManager } from '../context/data';
4 | import Head from 'next/head';
5 | import Link from 'next/link';
6 |
7 |
8 | export default function Signup() {
9 | const { host } = useContext(StateManager);
10 | const [data, setData] = useState({
11 | firstname: '',
12 | lastname: '',
13 | username: '',
14 | email: ""
15 | })
16 | const [state , setState] = useState(false);
17 |
18 | const [pass, setPass] = useState({
19 | password: "",
20 | confirmPassword: ""
21 | })
22 |
23 | useEffect(() => {
24 | if (localStorage.getItem('token')) {
25 | Router.push('/');
26 | }
27 | })
28 |
29 | const OnChangeData = (e) => {
30 | setData({
31 | ...data,
32 | [e.target.name]: e.target.value
33 | })
34 | }
35 | const ChangePass = (e) => {
36 | setPass({
37 | ...pass,
38 | [e.target.name]: e.target.value
39 | })
40 | };
41 |
42 | const CreateNewUser = (e) => {
43 | e.preventDefault();
44 | const user = {
45 | name: data.firstname + " " + data.lastname,
46 | username: data.username,
47 | email: data.email,
48 | password: pass.password
49 | }
50 | fetch(host + '/api/auth/createuser', {
51 | method: 'POST',
52 | headers: {
53 | 'Content-Type': 'application/json'
54 | },
55 | body: JSON.stringify(user)
56 | })
57 | .then(res => res.json())
58 | .then(newUser => {
59 | if (newUser.success) {
60 | localStorage.setItem('token', newUser.authtoken);
61 | Router.push('/Login');
62 | }
63 | else {
64 | alert(newUser.error);
65 | }
66 | }
67 | )
68 | }
69 |
70 | const runthis= async()=>{
71 | const username = data.username;
72 | const url = `${host}/api/auth/check/${username}`;
73 |
74 | if(username.length >= 5){
75 | const response = await fetch(url , {
76 | method : 'PUT',
77 | headers : {
78 | "Content-Type" : "application/json"
79 | }
80 | });
81 | const jsonRes = await response.json();
82 | if (jsonRes.res === true){
83 | setState("yes");
84 | }
85 | else if (jsonRes.res === false){
86 | setState("no");
87 | }
88 | }
89 |
90 |
91 | };
92 |
93 |
94 |
95 | return (
96 | <>
97 |
98 | Create Acoount on TODO
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |

107 |
Create Account in TODO
108 |
109 |
110 |
111 |
112 |
120 |
121 |
We take privacy issues seriously. You can be sure that your personal data is securely protected.
122 |
123 |
128 |
129 |
206 |
207 |
208 |
209 |
210 | >
211 | )
212 | }
--------------------------------------------------------------------------------
/styles/globalsCSS.css:
--------------------------------------------------------------------------------
1 | /*
2 | ! tailwindcss v3.0.23 | MIT License | https://tailwindcss.com
3 | */
4 |
5 | /*
6 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
7 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
8 | */
9 |
10 | *,
11 | ::before,
12 | ::after {
13 | box-sizing: border-box;
14 | /* 1 */
15 | border-width: 0;
16 | /* 2 */
17 | border-style: solid;
18 | /* 2 */
19 | border-color: #e5e7eb;
20 | /* 2 */
21 | }
22 |
23 | ::before,
24 | ::after {
25 | --tw-content: '';
26 | }
27 |
28 | /*
29 | 1. Use a consistent sensible line-height in all browsers.
30 | 2. Prevent adjustments of font size after orientation changes in iOS.
31 | 3. Use a more readable tab size.
32 | 4. Use the user's configured `sans` font-family by default.
33 | */
34 |
35 | html {
36 | line-height: 1.5;
37 | /* 1 */
38 | -webkit-text-size-adjust: 100%;
39 | /* 2 */
40 | -moz-tab-size: 4;
41 | /* 3 */
42 | -o-tab-size: 4;
43 | tab-size: 4;
44 | /* 3 */
45 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
46 | /* 4 */
47 | }
48 |
49 | /*
50 | 1. Remove the margin in all browsers.
51 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
52 | */
53 |
54 | body {
55 | margin: 0;
56 | /* 1 */
57 | line-height: inherit;
58 | /* 2 */
59 | }
60 |
61 | /*
62 | 1. Add the correct height in Firefox.
63 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
64 | 3. Ensure horizontal rules are visible by default.
65 | */
66 |
67 | hr {
68 | height: 0;
69 | /* 1 */
70 | color: inherit;
71 | /* 2 */
72 | border-top-width: 1px;
73 | /* 3 */
74 | }
75 |
76 | /*
77 | Add the correct text decoration in Chrome, Edge, and Safari.
78 | */
79 |
80 | abbr:where([title]) {
81 | -webkit-text-decoration: underline dotted;
82 | text-decoration: underline dotted;
83 | }
84 |
85 | /*
86 | Remove the default font size and weight for headings.
87 | */
88 |
89 | h1,
90 | h2,
91 | h3,
92 | h4,
93 | h5,
94 | h6 {
95 | font-size: inherit;
96 | font-weight: inherit;
97 | }
98 |
99 | /*
100 | Reset links to optimize for opt-in styling instead of opt-out.
101 | */
102 |
103 | a {
104 | color: inherit;
105 | text-decoration: inherit;
106 | }
107 |
108 | /*
109 | Add the correct font weight in Edge and Safari.
110 | */
111 |
112 | b,
113 | strong {
114 | font-weight: bolder;
115 | }
116 |
117 | /*
118 | 1. Use the user's configured `mono` font family by default.
119 | 2. Correct the odd `em` font sizing in all browsers.
120 | */
121 |
122 | code,
123 | kbd,
124 | samp,
125 | pre {
126 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
127 | /* 1 */
128 | font-size: 1em;
129 | /* 2 */
130 | }
131 |
132 | /*
133 | Add the correct font size in all browsers.
134 | */
135 |
136 | small {
137 | font-size: 80%;
138 | }
139 |
140 | /*
141 | Prevent `sub` and `sup` elements from affecting the line height in all browsers.
142 | */
143 |
144 | sub,
145 | sup {
146 | font-size: 75%;
147 | line-height: 0;
148 | position: relative;
149 | vertical-align: baseline;
150 | }
151 |
152 | sub {
153 | bottom: -0.25em;
154 | }
155 |
156 | sup {
157 | top: -0.5em;
158 | }
159 |
160 | /*
161 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
162 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
163 | 3. Remove gaps between table borders by default.
164 | */
165 |
166 | table {
167 | text-indent: 0;
168 | /* 1 */
169 | border-color: inherit;
170 | /* 2 */
171 | border-collapse: collapse;
172 | /* 3 */
173 | }
174 |
175 | /*
176 | 1. Change the font styles in all browsers.
177 | 2. Remove the margin in Firefox and Safari.
178 | 3. Remove default padding in all browsers.
179 | */
180 |
181 | button,
182 | input,
183 | optgroup,
184 | select,
185 | textarea {
186 | font-family: inherit;
187 | /* 1 */
188 | font-size: 100%;
189 | /* 1 */
190 | line-height: inherit;
191 | /* 1 */
192 | color: inherit;
193 | /* 1 */
194 | margin: 0;
195 | /* 2 */
196 | padding: 0;
197 | /* 3 */
198 | }
199 |
200 | /*
201 | Remove the inheritance of text transform in Edge and Firefox.
202 | */
203 |
204 | button,
205 | select {
206 | text-transform: none;
207 | }
208 |
209 | /*
210 | 1. Correct the inability to style clickable types in iOS and Safari.
211 | 2. Remove default button styles.
212 | */
213 |
214 | button,
215 | [type='button'],
216 | [type='reset'],
217 | [type='submit'] {
218 | -webkit-appearance: button;
219 | /* 1 */
220 | background-color: transparent;
221 | /* 2 */
222 | background-image: none;
223 | /* 2 */
224 | }
225 |
226 | /*
227 | Use the modern Firefox focus style for all focusable elements.
228 | */
229 |
230 | :-moz-focusring {
231 | outline: auto;
232 | }
233 |
234 | /*
235 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
236 | */
237 |
238 | :-moz-ui-invalid {
239 | box-shadow: none;
240 | }
241 |
242 | /*
243 | Add the correct vertical alignment in Chrome and Firefox.
244 | */
245 |
246 | progress {
247 | vertical-align: baseline;
248 | }
249 |
250 | /*
251 | Correct the cursor style of increment and decrement buttons in Safari.
252 | */
253 |
254 | ::-webkit-inner-spin-button,
255 | ::-webkit-outer-spin-button {
256 | height: auto;
257 | }
258 |
259 | /*
260 | 1. Correct the odd appearance in Chrome and Safari.
261 | 2. Correct the outline style in Safari.
262 | */
263 |
264 | [type='search'] {
265 | -webkit-appearance: textfield;
266 | /* 1 */
267 | outline-offset: -2px;
268 | /* 2 */
269 | }
270 |
271 | /*
272 | Remove the inner padding in Chrome and Safari on macOS.
273 | */
274 |
275 | ::-webkit-search-decoration {
276 | -webkit-appearance: none;
277 | }
278 |
279 | /*
280 | 1. Correct the inability to style clickable types in iOS and Safari.
281 | 2. Change font properties to `inherit` in Safari.
282 | */
283 |
284 | ::-webkit-file-upload-button {
285 | -webkit-appearance: button;
286 | /* 1 */
287 | font: inherit;
288 | /* 2 */
289 | }
290 |
291 | /*
292 | Add the correct display in Chrome and Safari.
293 | */
294 |
295 | summary {
296 | display: list-item;
297 | }
298 |
299 | /*
300 | Removes the default spacing and border for appropriate elements.
301 | */
302 |
303 | blockquote,
304 | dl,
305 | dd,
306 | h1,
307 | h2,
308 | h3,
309 | h4,
310 | h5,
311 | h6,
312 | hr,
313 | figure,
314 | p,
315 | pre {
316 | margin: 0;
317 | }
318 |
319 | fieldset {
320 | margin: 0;
321 | padding: 0;
322 | }
323 |
324 | legend {
325 | padding: 0;
326 | }
327 |
328 | ol,
329 | ul,
330 | menu {
331 | list-style: none;
332 | margin: 0;
333 | padding: 0;
334 | }
335 |
336 | /*
337 | Prevent resizing textareas horizontally by default.
338 | */
339 |
340 | textarea {
341 | resize: vertical;
342 | }
343 |
344 | /*
345 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
346 | 2. Set the default placeholder color to the user's configured gray 400 color.
347 | */
348 |
349 | input::-moz-placeholder, textarea::-moz-placeholder {
350 | opacity: 1;
351 | /* 1 */
352 | color: #9ca3af;
353 | /* 2 */
354 | }
355 |
356 | input:-ms-input-placeholder, textarea:-ms-input-placeholder {
357 | opacity: 1;
358 | /* 1 */
359 | color: #9ca3af;
360 | /* 2 */
361 | }
362 |
363 | input::placeholder,
364 | textarea::placeholder {
365 | opacity: 1;
366 | /* 1 */
367 | color: #9ca3af;
368 | /* 2 */
369 | }
370 |
371 | /*
372 | Set the default cursor for buttons.
373 | */
374 |
375 | button,
376 | [role="button"] {
377 | cursor: pointer;
378 | }
379 |
380 | /*
381 | Make sure disabled buttons don't get the pointer cursor.
382 | */
383 |
384 | :disabled {
385 | cursor: default;
386 | }
387 |
388 | /*
389 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
390 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
391 | This can trigger a poorly considered lint error in some tools but is included by design.
392 | */
393 |
394 | img,
395 | svg,
396 | video,
397 | canvas,
398 | audio,
399 | iframe,
400 | embed,
401 | object {
402 | display: block;
403 | /* 1 */
404 | vertical-align: middle;
405 | /* 2 */
406 | }
407 |
408 | /*
409 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
410 | */
411 |
412 | img,
413 | video {
414 | max-width: 100%;
415 | height: auto;
416 | }
417 |
418 | /*
419 | Ensure the default browser behavior of the `hidden` attribute.
420 | */
421 |
422 | [hidden] {
423 | display: none;
424 | }
425 |
426 | *, ::before, ::after {
427 | --tw-translate-x: 0;
428 | --tw-translate-y: 0;
429 | --tw-rotate: 0;
430 | --tw-skew-x: 0;
431 | --tw-skew-y: 0;
432 | --tw-scale-x: 1;
433 | --tw-scale-y: 1;
434 | --tw-pan-x: ;
435 | --tw-pan-y: ;
436 | --tw-pinch-zoom: ;
437 | --tw-scroll-snap-strictness: proximity;
438 | --tw-ordinal: ;
439 | --tw-slashed-zero: ;
440 | --tw-numeric-figure: ;
441 | --tw-numeric-spacing: ;
442 | --tw-numeric-fraction: ;
443 | --tw-ring-inset: ;
444 | --tw-ring-offset-width: 0px;
445 | --tw-ring-offset-color: #fff;
446 | --tw-ring-color: rgb(59 130 246 / 0.5);
447 | --tw-ring-offset-shadow: 0 0 #0000;
448 | --tw-ring-shadow: 0 0 #0000;
449 | --tw-shadow: 0 0 #0000;
450 | --tw-shadow-colored: 0 0 #0000;
451 | --tw-blur: ;
452 | --tw-brightness: ;
453 | --tw-contrast: ;
454 | --tw-grayscale: ;
455 | --tw-hue-rotate: ;
456 | --tw-invert: ;
457 | --tw-saturate: ;
458 | --tw-sepia: ;
459 | --tw-drop-shadow: ;
460 | --tw-backdrop-blur: ;
461 | --tw-backdrop-brightness: ;
462 | --tw-backdrop-contrast: ;
463 | --tw-backdrop-grayscale: ;
464 | --tw-backdrop-hue-rotate: ;
465 | --tw-backdrop-invert: ;
466 | --tw-backdrop-opacity: ;
467 | --tw-backdrop-saturate: ;
468 | --tw-backdrop-sepia: ;
469 | }
470 |
471 | .sr-only {
472 | position: absolute;
473 | width: 1px;
474 | height: 1px;
475 | padding: 0;
476 | margin: -1px;
477 | overflow: hidden;
478 | clip: rect(0, 0, 0, 0);
479 | white-space: nowrap;
480 | border-width: 0;
481 | }
482 |
483 | .absolute {
484 | position: absolute;
485 | }
486 |
487 | .relative {
488 | position: relative;
489 | }
490 |
491 | .inset-y-0 {
492 | top: 0px;
493 | bottom: 0px;
494 | }
495 |
496 | .left-0 {
497 | left: 0px;
498 | }
499 |
500 | .m-auto {
501 | margin: auto;
502 | }
503 |
504 | .mx-auto {
505 | margin-left: auto;
506 | margin-right: auto;
507 | }
508 |
509 | .my-10 {
510 | margin-top: 2.5rem;
511 | margin-bottom: 2.5rem;
512 | }
513 |
514 | .mx-2 {
515 | margin-left: 0.5rem;
516 | margin-right: 0.5rem;
517 | }
518 |
519 | .mt-6 {
520 | margin-top: 1.5rem;
521 | }
522 |
523 | .mt-7 {
524 | margin-top: 1.75rem;
525 | }
526 |
527 | .mt-8 {
528 | margin-top: 2rem;
529 | }
530 |
531 | .ml-2 {
532 | margin-left: 0.5rem;
533 | }
534 |
535 | .mt-16 {
536 | margin-top: 4rem;
537 | }
538 |
539 | .mt-4 {
540 | margin-top: 1rem;
541 | }
542 |
543 | .mt-3 {
544 | margin-top: 0.75rem;
545 | }
546 |
547 | .mb-4 {
548 | margin-bottom: 1rem;
549 | }
550 |
551 | .mt-14 {
552 | margin-top: 3.5rem;
553 | }
554 |
555 | .mt-2 {
556 | margin-top: 0.5rem;
557 | }
558 |
559 | .mr-3 {
560 | margin-right: 0.75rem;
561 | }
562 |
563 | .mt-10 {
564 | margin-top: 2.5rem;
565 | }
566 |
567 | .mb-5 {
568 | margin-bottom: 1.25rem;
569 | }
570 |
571 | .ml-3 {
572 | margin-left: 0.75rem;
573 | }
574 |
575 | .mt-1 {
576 | margin-top: 0.25rem;
577 | }
578 |
579 | .block {
580 | display: block;
581 | }
582 |
583 | .inline {
584 | display: inline;
585 | }
586 |
587 | .flex {
588 | display: flex;
589 | }
590 |
591 | .grid {
592 | display: grid;
593 | }
594 |
595 | .hidden {
596 | display: none;
597 | }
598 |
599 | .h-12 {
600 | height: 3rem;
601 | }
602 |
603 | .h-4 {
604 | height: 1rem;
605 | }
606 |
607 | .h-5 {
608 | height: 1.25rem;
609 | }
610 |
611 | .h-auto {
612 | height: auto;
613 | }
614 |
615 | .h-6 {
616 | height: 1.5rem;
617 | }
618 |
619 | .h-10 {
620 | height: 2.5rem;
621 | }
622 |
623 | .min-h-full {
624 | min-height: 100%;
625 | }
626 |
627 | .w-full {
628 | width: 100%;
629 | }
630 |
631 | .w-auto {
632 | width: auto;
633 | }
634 |
635 | .w-4 {
636 | width: 1rem;
637 | }
638 |
639 | .w-5 {
640 | width: 1.25rem;
641 | }
642 |
643 | .w-80 {
644 | width: 20rem;
645 | }
646 |
647 | .w-64 {
648 | width: 16rem;
649 | }
650 |
651 | .w-52 {
652 | width: 13rem;
653 | }
654 |
655 | .w-6 {
656 | width: 1.5rem;
657 | }
658 |
659 | .w-72 {
660 | width: 18rem;
661 | }
662 |
663 | .max-w-md {
664 | max-width: 28rem;
665 | }
666 |
667 | .flex-shrink-0 {
668 | flex-shrink: 0;
669 | }
670 |
671 | .cursor-pointer {
672 | cursor: pointer;
673 | }
674 |
675 | .appearance-none {
676 | -webkit-appearance: none;
677 | -moz-appearance: none;
678 | appearance: none;
679 | }
680 |
681 | .place-items-center {
682 | place-items: center;
683 | }
684 |
685 | .items-center {
686 | align-items: center;
687 | }
688 |
689 | .justify-center {
690 | justify-content: center;
691 | }
692 |
693 | .justify-between {
694 | justify-content: space-between;
695 | }
696 |
697 | .space-y-8 > :not([hidden]) ~ :not([hidden]) {
698 | --tw-space-y-reverse: 0;
699 | margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
700 | margin-bottom: calc(2rem * var(--tw-space-y-reverse));
701 | }
702 |
703 | .space-y-6 > :not([hidden]) ~ :not([hidden]) {
704 | --tw-space-y-reverse: 0;
705 | margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
706 | margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
707 | }
708 |
709 | .-space-y-px > :not([hidden]) ~ :not([hidden]) {
710 | --tw-space-y-reverse: 0;
711 | margin-top: calc(-1px * calc(1 - var(--tw-space-y-reverse)));
712 | margin-bottom: calc(-1px * var(--tw-space-y-reverse));
713 | }
714 |
715 | .rounded-lg {
716 | border-radius: 0.5rem;
717 | }
718 |
719 | .rounded {
720 | border-radius: 0.25rem;
721 | }
722 |
723 | .rounded-md {
724 | border-radius: 0.375rem;
725 | }
726 |
727 | .rounded-none {
728 | border-radius: 0px;
729 | }
730 |
731 | .rounded-t-md {
732 | border-top-left-radius: 0.375rem;
733 | border-top-right-radius: 0.375rem;
734 | }
735 |
736 | .rounded-b-md {
737 | border-bottom-right-radius: 0.375rem;
738 | border-bottom-left-radius: 0.375rem;
739 | }
740 |
741 | .border {
742 | border-width: 1px;
743 | }
744 |
745 | .border-\[1px\] {
746 | border-width: 1px;
747 | }
748 |
749 | .border-b {
750 | border-bottom-width: 1px;
751 | }
752 |
753 | .border-gray-300 {
754 | --tw-border-opacity: 1;
755 | border-color: rgb(209 213 219 / var(--tw-border-opacity));
756 | }
757 |
758 | .border-transparent {
759 | border-color: transparent;
760 | }
761 |
762 | .border-gray-200 {
763 | --tw-border-opacity: 1;
764 | border-color: rgb(229 231 235 / var(--tw-border-opacity));
765 | }
766 |
767 | .border-red-800 {
768 | --tw-border-opacity: 1;
769 | border-color: rgb(153 27 27 / var(--tw-border-opacity));
770 | }
771 |
772 | .border-stone-500 {
773 | --tw-border-opacity: 1;
774 | border-color: rgb(120 113 108 / var(--tw-border-opacity));
775 | }
776 |
777 | .border-stone-400 {
778 | --tw-border-opacity: 1;
779 | border-color: rgb(168 162 158 / var(--tw-border-opacity));
780 | }
781 |
782 | .border-gray-400 {
783 | --tw-border-opacity: 1;
784 | border-color: rgb(156 163 175 / var(--tw-border-opacity));
785 | }
786 |
787 | .bg-gray-100 {
788 | --tw-bg-opacity: 1;
789 | background-color: rgb(243 244 246 / var(--tw-bg-opacity));
790 | }
791 |
792 | .bg-indigo-600 {
793 | --tw-bg-opacity: 1;
794 | background-color: rgb(79 70 229 / var(--tw-bg-opacity));
795 | }
796 |
797 | .bg-indigo-500 {
798 | --tw-bg-opacity: 1;
799 | background-color: rgb(99 102 241 / var(--tw-bg-opacity));
800 | }
801 |
802 | .p-3 {
803 | padding: 0.75rem;
804 | }
805 |
806 | .p-2 {
807 | padding: 0.5rem;
808 | }
809 |
810 | .py-12 {
811 | padding-top: 3rem;
812 | padding-bottom: 3rem;
813 | }
814 |
815 | .px-4 {
816 | padding-left: 1rem;
817 | padding-right: 1rem;
818 | }
819 |
820 | .px-5 {
821 | padding-left: 1.25rem;
822 | padding-right: 1.25rem;
823 | }
824 |
825 | .py-4 {
826 | padding-top: 1rem;
827 | padding-bottom: 1rem;
828 | }
829 |
830 | .px-3 {
831 | padding-left: 0.75rem;
832 | padding-right: 0.75rem;
833 | }
834 |
835 | .py-2 {
836 | padding-top: 0.5rem;
837 | padding-bottom: 0.5rem;
838 | }
839 |
840 | .px-8 {
841 | padding-left: 2rem;
842 | padding-right: 2rem;
843 | }
844 |
845 | .px-2 {
846 | padding-left: 0.5rem;
847 | padding-right: 0.5rem;
848 | }
849 |
850 | .pt-16 {
851 | padding-top: 4rem;
852 | }
853 |
854 | .pl-3 {
855 | padding-left: 0.75rem;
856 | }
857 |
858 | .pb-16 {
859 | padding-bottom: 4rem;
860 | }
861 |
862 | .pr-2 {
863 | padding-right: 0.5rem;
864 | }
865 |
866 | .pl-4 {
867 | padding-left: 1rem;
868 | }
869 |
870 | .pr-4 {
871 | padding-right: 1rem;
872 | }
873 |
874 | .text-center {
875 | text-align: center;
876 | }
877 |
878 | .font-serif {
879 | font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
880 | }
881 |
882 | .font-sans {
883 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
884 | }
885 |
886 | .text-3xl {
887 | font-size: 1.875rem;
888 | line-height: 2.25rem;
889 | }
890 |
891 | .text-sm {
892 | font-size: 0.875rem;
893 | line-height: 1.25rem;
894 | }
895 |
896 | .text-xl {
897 | font-size: 1.25rem;
898 | line-height: 1.75rem;
899 | }
900 |
901 | .text-xs {
902 | font-size: 0.75rem;
903 | line-height: 1rem;
904 | }
905 |
906 | .font-extrabold {
907 | font-weight: 800;
908 | }
909 |
910 | .font-semibold {
911 | font-weight: 600;
912 | }
913 |
914 | .font-medium {
915 | font-weight: 500;
916 | }
917 |
918 | .leading-5 {
919 | line-height: 1.25rem;
920 | }
921 |
922 | .leading-none {
923 | line-height: 1;
924 | }
925 |
926 | .text-gray-900 {
927 | --tw-text-opacity: 1;
928 | color: rgb(17 24 39 / var(--tw-text-opacity));
929 | }
930 |
931 | .text-indigo-600 {
932 | --tw-text-opacity: 1;
933 | color: rgb(79 70 229 / var(--tw-text-opacity));
934 | }
935 |
936 | .text-gray-800 {
937 | --tw-text-opacity: 1;
938 | color: rgb(31 41 55 / var(--tw-text-opacity));
939 | }
940 |
941 | .text-white {
942 | --tw-text-opacity: 1;
943 | color: rgb(255 255 255 / var(--tw-text-opacity));
944 | }
945 |
946 | .text-indigo-500 {
947 | --tw-text-opacity: 1;
948 | color: rgb(99 102 241 / var(--tw-text-opacity));
949 | }
950 |
951 | .text-gray-600 {
952 | --tw-text-opacity: 1;
953 | color: rgb(75 85 99 / var(--tw-text-opacity));
954 | }
955 |
956 | .text-red-600 {
957 | --tw-text-opacity: 1;
958 | color: rgb(220 38 38 / var(--tw-text-opacity));
959 | }
960 |
961 | .text-violet-100 {
962 | --tw-text-opacity: 1;
963 | color: rgb(237 233 254 / var(--tw-text-opacity));
964 | }
965 |
966 | .text-orange-800 {
967 | --tw-text-opacity: 1;
968 | color: rgb(154 52 18 / var(--tw-text-opacity));
969 | }
970 |
971 | .text-indigo-700 {
972 | --tw-text-opacity: 1;
973 | color: rgb(67 56 202 / var(--tw-text-opacity));
974 | }
975 |
976 | .text-orange-500 {
977 | --tw-text-opacity: 1;
978 | color: rgb(249 115 22 / var(--tw-text-opacity));
979 | }
980 |
981 | .placeholder-gray-500::-moz-placeholder {
982 | --tw-placeholder-opacity: 1;
983 | color: rgb(107 114 128 / var(--tw-placeholder-opacity));
984 | }
985 |
986 | .placeholder-gray-500:-ms-input-placeholder {
987 | --tw-placeholder-opacity: 1;
988 | color: rgb(107 114 128 / var(--tw-placeholder-opacity));
989 | }
990 |
991 | .placeholder-gray-500::placeholder {
992 | --tw-placeholder-opacity: 1;
993 | color: rgb(107 114 128 / var(--tw-placeholder-opacity));
994 | }
995 |
996 | .shadow-sm {
997 | --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
998 | --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
999 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
1000 | }
1001 |
1002 | .outline-none {
1003 | outline: 2px solid transparent;
1004 | outline-offset: 2px;
1005 | }
1006 |
1007 | .hover\:rotate-\[45deg\]:hover {
1008 | --tw-rotate: 45deg;
1009 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1010 | }
1011 |
1012 | .hover\:bg-indigo-700:hover {
1013 | --tw-bg-opacity: 1;
1014 | background-color: rgb(67 56 202 / var(--tw-bg-opacity));
1015 | }
1016 |
1017 | .hover\:text-orange-600:hover {
1018 | --tw-text-opacity: 1;
1019 | color: rgb(234 88 12 / var(--tw-text-opacity));
1020 | }
1021 |
1022 | .hover\:opacity-90:hover {
1023 | opacity: 0.9;
1024 | }
1025 |
1026 | .focus\:z-10:focus {
1027 | z-index: 10;
1028 | }
1029 |
1030 | .focus\:border-indigo-500:focus {
1031 | --tw-border-opacity: 1;
1032 | border-color: rgb(99 102 241 / var(--tw-border-opacity));
1033 | }
1034 |
1035 | .focus\:border-gray-600:focus {
1036 | --tw-border-opacity: 1;
1037 | border-color: rgb(75 85 99 / var(--tw-border-opacity));
1038 | }
1039 |
1040 | .focus\:outline-none:focus {
1041 | outline: 2px solid transparent;
1042 | outline-offset: 2px;
1043 | }
1044 |
1045 | .focus\:ring-2:focus {
1046 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
1047 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
1048 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
1049 | }
1050 |
1051 | .focus\:ring-gray-700:focus {
1052 | --tw-ring-opacity: 1;
1053 | --tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity));
1054 | }
1055 |
1056 | .focus\:ring-indigo-500:focus {
1057 | --tw-ring-opacity: 1;
1058 | --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
1059 | }
1060 |
1061 | .focus\:ring-offset-2:focus {
1062 | --tw-ring-offset-width: 2px;
1063 | }
1064 |
1065 | .group:hover .group-hover\:text-indigo-400 {
1066 | --tw-text-opacity: 1;
1067 | color: rgb(129 140 248 / var(--tw-text-opacity));
1068 | }
1069 |
1070 | @media (min-width: 640px) {
1071 | .sm\:w-64 {
1072 | width: 16rem;
1073 | }
1074 |
1075 | .sm\:px-6 {
1076 | padding-left: 1.5rem;
1077 | padding-right: 1.5rem;
1078 | }
1079 |
1080 | .sm\:text-sm {
1081 | font-size: 0.875rem;
1082 | line-height: 1.25rem;
1083 | }
1084 | }
1085 |
1086 | @media (min-width: 768px) {
1087 | .md\:ml-12 {
1088 | margin-left: 3rem;
1089 | }
1090 |
1091 | .md\:mt-0 {
1092 | margin-top: 0px;
1093 | }
1094 |
1095 | .md\:mt-24 {
1096 | margin-top: 6rem;
1097 | }
1098 |
1099 | .md\:block {
1100 | display: block;
1101 | }
1102 |
1103 | .md\:flex {
1104 | display: flex;
1105 | }
1106 |
1107 | .md\:w-64 {
1108 | width: 16rem;
1109 | }
1110 |
1111 | .md\:w-80 {
1112 | width: 20rem;
1113 | }
1114 |
1115 | .md\:w-96 {
1116 | width: 24rem;
1117 | }
1118 | }
1119 |
1120 | @media (min-width: 1024px) {
1121 | .lg\:ml-24 {
1122 | margin-left: 6rem;
1123 | }
1124 |
1125 | .lg\:mt-0 {
1126 | margin-top: 0px;
1127 | }
1128 |
1129 | .lg\:flex {
1130 | display: flex;
1131 | }
1132 |
1133 | .lg\:w-96 {
1134 | width: 24rem;
1135 | }
1136 |
1137 | .lg\:px-8 {
1138 | padding-left: 2rem;
1139 | padding-right: 2rem;
1140 | }
1141 | }
1142 |
1143 | @media (min-width: 1280px) {
1144 | .xl\:w-10\/12 {
1145 | width: 83.333333%;
1146 | }
1147 |
1148 | .xl\:px-24 {
1149 | padding-left: 6rem;
1150 | padding-right: 6rem;
1151 | }
1152 | }
--------------------------------------------------------------------------------