├── README.md ├── .gitignore ├── postcss.config.js ├── nodemon.json ├── tailwind.config.js ├── .babelrc ├── template.js ├── client ├── index.js ├── components │ ├── useSortableData.jsx │ ├── VerificationCode.jsx │ ├── login.jsx │ ├── Signup.jsx │ └── usertable.jsx ├── App.js └── styles.css ├── server ├── models │ └── usersModels.js ├── devBundle.js ├── users.sql ├── routes │ └── api.js ├── server.js └── controllers │ └── usersController.js ├── webpack.config.server.js ├── webpack.config.client.production.js ├── webpack.config.client.js ├── package.json └── output.css /README.md: -------------------------------------------------------------------------------- 1 | # SharkProject# GoblinShark 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | pb_data/ 3 | pocketbase 4 | dist/ -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": false, 3 | "watch": [ 4 | "./server" 5 | ], 6 | "exec": "webpack --mode=development --config webpack.config.server.js && node ./dist/server.generated.js" 7 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./client/**/*.{js,jsx,ts,tsx,css}", 5 | ], 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [], 10 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ], 11 | "@babel/preset-react" 12 | ], 13 | "plugins": [ 14 | "react-hot-loader/babel" 15 | ] 16 | } -------------------------------------------------------------------------------- /template.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | return ` 3 | 4 | 5 | 6 | GoblinShark 7 | 8 | 9 |
10 | 12 | 13 | ` 14 | } -------------------------------------------------------------------------------- /client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { BrowserRouter } from 'react-router-dom'; 4 | import App from './App'; 5 | import "../output.css"; 6 | 7 | import styles from './styles.css' 8 | 9 | render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ) -------------------------------------------------------------------------------- /server/models/usersModels.js: -------------------------------------------------------------------------------- 1 | const { Pool } = require('pg'); 2 | 3 | const PG_URI = 'postgres://bgthaynj:E38mibc6iLnnkRSR51VN-LQ05nNEeFmK@heffalump.db.elephantsql.com/bgthaynj'; 4 | 5 | const pool = new Pool({ 6 | connectionString: PG_URI 7 | }); 8 | 9 | module.exports = { 10 | query: (text, params, callback) => { 11 | console.log('executed query', text); 12 | return pool.query(text, params, callback); 13 | } 14 | }; -------------------------------------------------------------------------------- /server/devBundle.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import webpackMiddleware from 'webpack-dev-middleware' 3 | import webpackHotMiddleware from 'webpack-hot-middleware' 4 | import webpackConfig from './../webpack.config.client.js' 5 | import dotenv from 'dotenv'; 6 | dotenv.config(); 7 | const compile = (app) => { 8 | if (process.env.NODE_ENV == "development") { 9 | const compiler = webpack(webpackConfig) 10 | const middleware = webpackMiddleware(compiler, { 11 | publicPath: webpackConfig.output.publicPath 12 | }) 13 | app.use(middleware) 14 | app.use(webpackHotMiddleware(compiler)) 15 | } 16 | } 17 | export default { 18 | compile 19 | } -------------------------------------------------------------------------------- /server/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.users ( 2 | "_id" serial NOT NULL, 3 | "image_url" varchar, 4 | "first_name" varchar NOT NULL, 5 | "last_name" varchar NOT NULL, 6 | "email" varchar NOT NULL, 7 | "resident_alum" varchar NOT NULL, 8 | "cohort_location" varchar NOT NULL, 9 | "city" varchar NOT NULL, 10 | "employed" boolean NOT NULL, 11 | "employer" varchar NOT NULL, 12 | "salary" bigint NOT NULL, 13 | "cohort_num" integer NOT NULL, 14 | "linkedin" varchar NOT NULL, 15 | "verification" varchar NOT NULL, 16 | CONSTRAINT "users_pk" PRIMARY KEY ("_id") 17 | ) WITH ( 18 | OIDS=FALSE 19 | ); 20 | 21 | CREATE TABLE public.verification ( 22 | "code" varchar NOT NULL 23 | ) WITH ( 24 | OIDS=FALSE 25 | ); 26 | -------------------------------------------------------------------------------- /webpack.config.server.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const CURRENT_WORKING_DIR = process.cwd() 4 | const nodeExternals = require('webpack-node-externals'); 5 | 6 | const config = { 7 | name: 'server', 8 | entry: [path.join(CURRENT_WORKING_DIR, './server/server.js')], 9 | target: "node", 10 | output: { 11 | path: path.join(CURRENT_WORKING_DIR, '/dist/'), 12 | filename: 'server.generated.js', 13 | publicPath: '/dist/', 14 | libraryTarget: 'commonjs2' 15 | }, 16 | externals: [nodeExternals()], 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | use: ['babel-loader'] 23 | } 24 | ] 25 | } 26 | } 27 | 28 | module.exports = config -------------------------------------------------------------------------------- /server/routes/api.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const usersController = require('../controllers/usersController'); 4 | 5 | const router = express.Router(); 6 | 7 | router.get('/signin', usersController.getUser, (req, res) => 8 | res.status(200).json(res.locals.userData) 9 | ); 10 | 11 | router.get('/getAll', usersController.getAll, (req, res) => { 12 | res.status(200).json(res.locals.users) 13 | }) 14 | 15 | router.post('/signup', usersController.createUser, (req, res) => { 16 | res.status(200).json(res.locals.userData) 17 | }) 18 | 19 | router.post('/verification', usersController.verification, (req, res) => { 20 | res.status(200).json(res.locals.code); 21 | }) 22 | 23 | router.get('/checkVerification', usersController.checkVerification, (req, res) => { 24 | res.status(200).json(res.locals.match); 25 | }) 26 | 27 | module.exports = router; 28 | -------------------------------------------------------------------------------- /webpack.config.client.production.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const CURRENT_WORKING_DIR = process.cwd() 4 | const config = { 5 | mode: 'production', 6 | entry: [path.join(CURRENT_WORKING_DIR, 'client/index.js')], 7 | output: { 8 | path: path.join(CURRENT_WORKING_DIR, '/dist'), 9 | filename: 'bundle.js', 10 | publicPath: '/dist/', 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.jsx?$/, 16 | exclude: /node_modules/, 17 | use: { 18 | loader: 'babel-loader', 19 | options: { 20 | presets: ['@babel/preset-env', ['@babel/preset-react', { "runtime": "automatic" }]] 21 | } 22 | }, 23 | }, 24 | ], 25 | }, 26 | }; 27 | 28 | module.exports = config -------------------------------------------------------------------------------- /client/components/useSortableData.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useMemo } from "react" 2 | 3 | export default function useSortableData(items, config = null) { 4 | const [sortConfig, setSortConfig] = useState(config); 5 | 6 | const sortedItems = useMemo(() => { 7 | let sortableItems = [...items]; 8 | if (sortConfig !== null) { 9 | sortableItems.sort((a, b) => { 10 | if (a[sortConfig.key] < b[sortConfig.key]) { 11 | return sortConfig.direction === 'ascending' ? -1 : 1; 12 | } 13 | if (a[sortConfig.key] > b[sortConfig.key]) { 14 | return sortConfig.direction === 'ascending' ? 1 : -1; 15 | } 16 | return 0; 17 | }); 18 | } 19 | return sortableItems; 20 | }, [items, sortConfig]); 21 | 22 | const requestSort = key => { 23 | let direction = 'ascending'; 24 | if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') { 25 | direction = 'descending'; 26 | } 27 | setSortConfig({ key, direction }); 28 | } 29 | 30 | return { sortedUsers: sortedItems, requestSort, sortConfig }; 31 | } -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import path from 'path' 3 | import template from './../template' 4 | import devBundle from './devBundle' 5 | import usersController from './controllers/usersController' 6 | 7 | let port = process.env.PORT || 3000 8 | const app = express() 9 | 10 | app.use(express.json()); 11 | app.use(express.urlencoded({ extended: true })); 12 | devBundle.compile(app) 13 | 14 | const apiRouter = require('./routes/api'); 15 | 16 | const CURRENT_WORKING_DIR = process.cwd() 17 | app.use('/dist', express.static(path.join(CURRENT_WORKING_DIR, 'dist'))) 18 | 19 | app.use('/api', apiRouter) 20 | 21 | app.get('/', (req, res) => { 22 | res.status(200).send(template()) 23 | }) 24 | 25 | // global error handler 26 | app.use((err, req, res, next) => { 27 | const defaultErr = { 28 | log: 'Express error handler caught unknown middleware error', 29 | status: 500, 30 | message: { err: 'An error occurred' }, 31 | }; 32 | const errorObj = Object.assign({}, defaultErr, err); 33 | console.log(errorObj.log); 34 | return res.status(errorObj.status).json(errorObj.message); 35 | }); 36 | 37 | app.listen(port, (err) => { 38 | if (err) { 39 | console.log(err) 40 | } 41 | console.info('Server started on port %s.', port) 42 | }) -------------------------------------------------------------------------------- /client/App.js: -------------------------------------------------------------------------------- 1 | import { hot } from 'react-hot-loader/root'; 2 | import UserTable from './components/usertable'; 3 | import { Switch, Route } from "react-router-dom"; 4 | import LoginButton from './components/login.jsx'; 5 | import Signup from './components/Signup.jsx'; 6 | 7 | const App = () => { 8 | 9 | return ( 10 |
11 | 12 | 17 | 22 | 27 | 28 |
29 | ) 30 | } 31 | /* 32 | 33 |
34 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
58 |
59 | ); 60 | } 61 | 62 | function Home() { 63 | return

Home

; 64 | } 65 | 66 | function About() { 67 | return

About

; 68 | } 69 | */ 70 | 71 | export default hot(App); -------------------------------------------------------------------------------- /webpack.config.client.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const CURRENT_WORKING_DIR = process.cwd() 4 | const config = { 5 | name: 'browser', 6 | mode: 'development', 7 | devtool: 'eval-source-map', 8 | entry: [ 9 | 'webpack-hot-middleware/client?reload=true', 10 | path.join(CURRENT_WORKING_DIR, 'client/index.js') 11 | ], 12 | output: { 13 | path: path.join(CURRENT_WORKING_DIR, '/dist'), 14 | filename: 'bundle.js', 15 | publicPath: '/dist/' 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.jsx?$/, 21 | exclude: /node_modules/, 22 | use: { 23 | loader: 'babel-loader', 24 | options: { 25 | presets: ['@babel/preset-env', ['@babel/preset-react', { "runtime": "automatic" }]] 26 | } 27 | }, 28 | }, 29 | { 30 | test: /\.css$/i, 31 | use: ["style-loader", "css-loader"], 32 | }, 33 | { 34 | test: /\.s[ac]ss$/i, 35 | use: ["style-loader", "css-loader", "sass-loader"] 36 | } 37 | ] 38 | }, 39 | plugins: [ 40 | new webpack.HotModuleReplacementPlugin(), 41 | new webpack.NoEmitOnErrorsPlugin() 42 | ], 43 | resolve: { 44 | alias: { 45 | 'react-dom': '@hot-loader/react-dom' 46 | }, 47 | extensions: ['', '.js', '.jsx'] 48 | } 49 | } 50 | 51 | module.exports = config -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sharkproject", 3 | "version": "1.0.0", 4 | "description": "CodeSmith Social Media Platform", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "nodemon & npx tailwindcss -i ./client/styles.css -o ./output.css --watch", 8 | "build": "webpack --config webpack.config.client.production.js && webpack --mode=production --config webpack.config.server.js", 9 | "start": "NODE_ENV=production node ./dist/server.generated.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/CSGoblinShark/SharkProject.git" 14 | }, 15 | "dependencies": { 16 | "@headlessui/react": "^1.7.4", 17 | "@heroicons/react": "^2.0.13", 18 | "@hot-loader/react-dom": "^17.0.1", 19 | "autoprefixer": "^10.4.13", 20 | "axios": "^1.1.3", 21 | "dotenv": "^16.0.3", 22 | "express": "^4.17.2", 23 | "gapi-script": "^1.2.0", 24 | "install": "^0.13.0", 25 | "npm": "^9.1.2", 26 | "pg": "^8.8.0", 27 | "postcss": "^8.4.19", 28 | "react": "^17.0.2", 29 | "react-dom": "^17.0.2", 30 | "react-google-login": "^5.2.2", 31 | "react-hot-loader": "^4.13.0", 32 | "react-router": "^4.3.1", 33 | "react-router-dom": "^5.3.0", 34 | "react-scripts": "^5.0.1", 35 | "swr": "^1.3.0", 36 | "tailwindcss": "^3.2.4" 37 | }, 38 | "devDependencies": { 39 | "@babel/core": "^7.16.5", 40 | "@babel/preset-env": "^7.16.5", 41 | "@babel/preset-react": "^7.16.5", 42 | "babel-loader": "^8.2.3", 43 | "css-loader": "^6.7.2", 44 | "nodemon": "^2.0.15", 45 | "style-loader": "^3.3.1", 46 | "webpack": "^5.65.0", 47 | "webpack-cli": "^4.9.1", 48 | "webpack-dev-middleware": "^5.3.0", 49 | "webpack-dev-server": "^4.11.1", 50 | "webpack-hot-middleware": "^2.25.1", 51 | "webpack-node-externals": "^3.0.0" 52 | }, 53 | "author": "Benjamin Margolius, Gahl Peled, Linda Ngo, Tony Lim, Andy Wong", 54 | "license": "ISC", 55 | "bugs": { 56 | "url": "https://github.com/CSGoblinShark/SharkProject/issues" 57 | }, 58 | "homepage": "https://github.com/CSGoblinShark/SharkProject#readme" 59 | } 60 | -------------------------------------------------------------------------------- /client/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .error { 6 | animation: shake 0.2s ease-in-out 0s 2; 7 | box-shadow: 0 0 0.5em red; 8 | } 9 | 10 | html, 11 | body { 12 | min-height: 100%; 13 | background-color: antiquewhite; 14 | } 15 | 16 | #loginPage { 17 | position: absolute; 18 | width: 100%; 19 | height: 100%; 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | 25 | #welcomeText { 26 | font-weight: bold; 27 | font-size: 30px; 28 | background-image: linear-gradient(90deg, red, blue); 29 | background-clip: text; 30 | color: transparent; 31 | margin-bottom: 20px; 32 | } 33 | 34 | h1 { 35 | margin-top: 20px; 36 | } 37 | 38 | #h1AndButton { 39 | display: flex; 40 | flex-direction: column; 41 | align-items: center; 42 | } 43 | 44 | #signUpBody { 45 | display: flex; 46 | flex-direction: column; 47 | align-items: center; 48 | justify-content: center; 49 | } 50 | 51 | #formBox { 52 | background-color: white; 53 | display: flex; 54 | flex-direction: column; 55 | width: 50%; 56 | border: 1px solid white; 57 | padding: 30px; 58 | border-radius: 10px; 59 | margin: 1em; 60 | } 61 | 62 | #formBox>input { 63 | border: 1px solid rgb(240, 240, 240); 64 | border-radius: 5px; 65 | margin-bottom: 15px; 66 | min-height: 22px; 67 | font-size: 20px; 68 | padding-left: 7px; 69 | } 70 | 71 | #formBox>select { 72 | margin-bottom: 15px; 73 | font-size: 20px; 74 | background-color: rgb(240, 240, 240); 75 | border-radius: 5px; 76 | padding-top: 5px; 77 | padding-bottom: 5px; 78 | padding-left: 7px; 79 | } 80 | 81 | #email { 82 | border: 1px solid white; 83 | } 84 | 85 | #submitButton { 86 | margin-top: 20px; 87 | background-color: rgb(100, 200, 254); 88 | border-radius: 10px; 89 | min-height: 40px; 90 | } 91 | 92 | #submitButton:hover { 93 | background-color: rgb(31, 176, 255); 94 | color: white; 95 | font-weight: 470; 96 | } 97 | 98 | label { 99 | font-weight: 500; 100 | color: grey; 101 | } 102 | 103 | .visibility { 104 | display: flex; 105 | justify-content: space-evenly; 106 | align-items: center; 107 | margin-bottom: 15px; 108 | } 109 | 110 | .visibility label { 111 | width: 75%; 112 | } 113 | 114 | .visibility input { 115 | align-self: center; 116 | height: 20px; 117 | width: 20px; 118 | } -------------------------------------------------------------------------------- /server/controllers/usersController.js: -------------------------------------------------------------------------------- 1 | const db = require('../models/usersModels'); 2 | 3 | const usersController = {}; 4 | 5 | usersController.createUser = (req, res, next) => { 6 | const create = `INSERT INTO users ( 7 | image_url, 8 | first_name, 9 | last_name, 10 | email, 11 | showemail, 12 | resident_alum, 13 | cohort_location, 14 | city, 15 | employed, 16 | employer, 17 | salary, 18 | showsalary, 19 | cohort_num, 20 | linkedin, 21 | verification) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)` 22 | console.log(req.body); 23 | const { 24 | imageUrl, 25 | firstName, 26 | lastName, 27 | email, 28 | showemail, 29 | residentAlum, 30 | cohortLocation, 31 | city, 32 | employed, 33 | employer, 34 | salary, 35 | showsalary, 36 | cohortNum, 37 | linkedin, 38 | verification 39 | } = req.body 40 | console.log(imageUrl, 'image') 41 | db.query(create, [imageUrl, firstName, lastName, email, showemail, residentAlum, cohortLocation, city, employed, employer, salary, showsalary, cohortNum, linkedin, verification]) 42 | .then((data) => { 43 | // console.log(data.rows); 44 | res.locals.userData = data.rows; 45 | return next(); 46 | }) 47 | .catch(e => 'Error at usersController.createUser'); 48 | }; 49 | 50 | usersController.getUser = (req, res, next) => { 51 | const findUser = "SELECT * FROM users WHERE email=$1" 52 | const email = req.query.email 53 | db.query(findUser, [email]) 54 | .then((data) => { 55 | res.locals.userData = data.rows[0]; 56 | // console.log(res.locals.userData) 57 | return next(); 58 | }) 59 | .catch(e => console.log(e, 'Error at usersController.getUser')); 60 | }; 61 | 62 | usersController.getAll = (req, res, next) => { 63 | const getUsers = "SELECT * FROM users" 64 | db.query(getUsers) 65 | .then((data) => { 66 | res.locals.users = data.rows 67 | // console.log(data.rows) 68 | return next(); 69 | }) 70 | .catch(e => console.log(e, 'Error at usersController.getAll')); 71 | } 72 | 73 | usersController.verification = (req, res, next) => { 74 | const random = "select substr(md5(random()::text), 0, 25)" 75 | const addCode = "INSERT INTO verification VALUES ($1)" 76 | db.query(random) 77 | .then((data) => { 78 | db.query(addCode, [data.rows[0].substr]) 79 | .then(() => { 80 | res.locals.code = data.rows[0].substr 81 | return next(); 82 | }) 83 | }) 84 | .catch(e => console.log(e, 'Error at usersController.verification')); 85 | // console.log(code); 86 | // res.locals.code = code; 87 | // return next(); 88 | } 89 | 90 | usersController.checkVerification = (req, res, next) => { 91 | const check = "SELECT * FROM verification WHERE code=$1" 92 | // console.log(req.query.verification) 93 | db.query(check, [req.query.verification]) 94 | .then((data) => { 95 | if (!data.rows.length) res.locals.match = false; 96 | else res.locals.match = true; 97 | return next(); 98 | }) 99 | .catch(e => console.log(e, 'Error at usersController.checkVerification')); 100 | } 101 | 102 | module.exports = usersController; 103 | -------------------------------------------------------------------------------- /client/components/VerificationCode.jsx: -------------------------------------------------------------------------------- 1 | import { Fragment, useState } from 'react' 2 | import { Transition } from '@headlessui/react' 3 | import { CheckCircleIcon } from '@heroicons/react/24/outline' 4 | import { XMarkIcon } from '@heroicons/react/20/solid' 5 | 6 | export default function VerificationCode(params) { 7 | const [show, setShow] = useState(true) 8 | 9 | return ( 10 | <> 11 | {/* Global notification live region, render this permanently at the end of the document */} 12 |
16 |
17 | {/* Notification panel, dynamically insert this into the live region when it needs to be displayed */} 18 | 28 |
29 |
30 |
31 |
32 |
34 |
35 |

Successfully created an invite code!

36 |

Anyone with this link can make an account. Only share with Codesmith Residents or Alumni!!!

37 |

Verifcation Code: {params.code}

38 |
39 |
40 | 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /client/components/login.jsx: -------------------------------------------------------------------------------- 1 | import { hot } from 'react-hot-loader/root'; 2 | import { GoogleLogin } from 'react-google-login'; 3 | import { gapi } from 'gapi-script'; 4 | import React, { Component, useState, useEffect } from 'react'; 5 | import { render } from 'react-dom' 6 | import ReactDOM from 'react-dom'; 7 | import axios from 'axios'; 8 | import { 9 | BrowserRouter as Router, 10 | Switch, 11 | Route, 12 | Link, 13 | Redirect, 14 | withRouter 15 | } from "react-router-dom"; 16 | 17 | 18 | // Create a react functional hook component that has functionality to initiate oAuth 19 | // Set up https://pocketbase.io/docs/ 20 | // pocketbase access so we can access the database 21 | // Look into Oauth through pocketbase 22 | 23 | const clientId = '210769127399-2l6p37ude8fr30ufsv4hmjkhkfdcb2jj.apps.googleusercontent.com' 24 | 25 | function LoginButton(props) { 26 | const [success, setSuccess] = useState(false); 27 | const [fail, setFail] = useState(false); 28 | const [email, setEmail] = useState(''); 29 | const [firstName, setFirstName] = useState(''); 30 | const [lastName, setLastName] = useState(''); 31 | const [imageUrl, setUrl] = useState('') 32 | let fetchEmail = ''; 33 | // let lastName; 34 | // let firstName; 35 | 36 | useEffect(() => { 37 | const initClient = () => { 38 | gapi.client.init({ 39 | clientId: clientId, 40 | scope: '' 41 | }) 42 | } 43 | }) 44 | //login verifified by google -> route to table component 45 | const onSuccess = (res) => { 46 | fetchEmail = res.profileObj.email 47 | // const emailObj = { email } 48 | console.log(res.profileObj.imageUrl); 49 | setEmail(res.profileObj.email); 50 | // lastName = res.profileObj.familyName; 51 | setFirstName(res.profileObj.givenName); 52 | // firstName = res.profileObj.givenName; 53 | setLastName(res.profileObj.familyName); 54 | //res.profileObj.givenName 55 | setUrl(res.profileObj.imageUrl); 56 | 57 | // console.log(emailObj) 58 | // console.log(`http://127.0.0.1:8090/api/collections/users/records/?filter=(email=%27${fetchEmail}%27)`) 59 | 60 | axios.get('/api/signin', { params: { email: fetchEmail } }) 61 | .then(({ data }) => { 62 | if (!Object.keys(data).length) setFail(!fail) 63 | setSuccess(!success); 64 | }) 65 | .catch(console.error); 66 | } 67 | 68 | //fail verif by google -> route to signup page 69 | const onFailure = (res) => { 70 | //on failure redirect to signup 71 | } 72 | const signup = [] 73 | if (fail) { 74 | signup.push() 84 | } 85 | 86 | return ( 87 | // 88 | //

hello from button

89 |
90 | {!success ? 91 |
92 |

Welcome to the social media app for Codesmith Residents/Alumni!

93 | 102 |
103 | : 104 | 106 | } 107 | {signup} 108 |
109 | ) 110 | } 111 | // 112 | export default withRouter(LoginButton); 113 | -------------------------------------------------------------------------------- /client/components/Signup.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, useState, useEffect } from 'react'; 2 | import axios from 'axios'; 3 | import { 4 | BrowserRouter as Router, 5 | Switch, 6 | Route, 7 | Link, 8 | Redirect, 9 | useLocation, 10 | withRouter 11 | } from "react-router-dom"; 12 | import ReactDOM from 'react-dom'; 13 | 14 | // const { mutate } = params; 15 | 16 | function Signup() { 17 | const [signupPage, setSignPage] = useState(false); 18 | const [matchVer, setMatchVer] = useState(''); 19 | const { state } = useLocation(); 20 | const [firstName, setFirstName] = useState(state.firstName); 21 | const [lastName, setLastName] = useState(state.lastName); 22 | let showSalary = false; 23 | let showEmail = false; 24 | 25 | let element = document.getElementById('verification'); 26 | let addError = function () { element.classList.add('error'); }; 27 | const removeError = function () { setMatchVer('') }; 28 | 29 | const handleSubmit = (event) => { 30 | event.preventDefault(); 31 | axios.get('/api/checkVerification', { params: { verification: event.target.verification.value } }) 32 | .then((data) => { 33 | if (!data.data) { 34 | setMatchVer('error') 35 | alert('Invalid Verification Code') 36 | } 37 | else { 38 | axios.post('/api/signup', { 39 | imageUrl: state.imageUrl, 40 | firstName: event.target.firstName.value.charAt(0).toUpperCase() + event.target.firstName.value.slice(1), 41 | lastName: event.target.lastName.value, 42 | email: event.target.email.value, 43 | showemail: showEmail, 44 | residentAlum: event.target.residentAlum.value, 45 | cohortLocation: event.target.cohortLocation.value, 46 | city: event.target.city.value.charAt(0).toUpperCase() + event.target.city.value.slice(1), 47 | employed: event.target.employed.value, 48 | employer: event.target.employer.value.charAt(0).toUpperCase() + event.target.employer.value.slice(1), 49 | salary: event.target.salary.value, 50 | showsalary: showSalary, 51 | cohortNum: event.target.cohortNum.value, 52 | // password: '00000000', 53 | // passwordConfirm: '00000000', 54 | linkedin: event.target.linkedin.value, 55 | verification: event.target.verification.value, 56 | }) 57 | .then((data) => { 58 | setSignPage(!signupPage); 59 | }) 60 | .catch(console.log('error')); 61 | } 62 | }) 63 | // axios.post('/api/signup', { 64 | // imageUrl: state.imageUrl, 65 | // firstName: event.target.firstName.value.charAt(0).toUpperCase() + event.target.firstName.value.slice(1), 66 | // lastName: event.target.lastName.value, 67 | // email: event.target.email.value, 68 | // residentAlum: event.target.residentAlum.value, 69 | // cohortLocation: event.target.cohortLocation.value, 70 | // city: event.target.city.value.charAt(0).toUpperCase() + event.target.city.value.slice(1), 71 | // employed: event.target.employed.value, 72 | // employer: event.target.employer.value.charAt(0).toUpperCase() + event.target.employer.value.slice(1), 73 | // salary: event.target.salary.value, 74 | // cohortNum: event.target.cohortNum.value, 75 | // // password: '00000000', 76 | // // passwordConfirm: '00000000', 77 | // linkedin: event.target.linkedin.value, 78 | // verification: event.target.verification.value, 79 | // }) 80 | // .then((data) => { 81 | // setSignPage(!signupPage); 82 | // console.log(signupPage) 83 | // }) 84 | // .catch(console.log('error')); 85 | } 86 | 87 | return ( 88 |
89 |

Sign up

90 | {!signupPage ? 91 |
92 | 93 | setFirstName(e.target.value)} required> 94 | 95 | 96 | setLastName(e.target.value)} required> 97 | 98 | 99 | 100 | 101 |
102 | 103 | showEmail = !showEmail} id='emailVisibility'> 104 |
105 | 106 | 107 | 111 | 112 | 113 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 | showSalary = !showSalary} id='salaryVisibility'> 144 |
145 | 146 | 147 | 148 | 149 | 150 |
151 | : } 152 |
153 | ) 154 | } 155 | 156 | export default withRouter(Signup) 157 | 158 | -------------------------------------------------------------------------------- /client/components/usertable.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import useSWR from 'swr' 3 | import axios from 'axios' 4 | import VerificationCode from "./VerificationCode" 5 | import useSortableData from "./useSortableData" 6 | import { ChevronDownIcon } from '@heroicons/react/20/solid' 7 | import ReactDOM, { render } from 'react-dom'; 8 | import { 9 | BrowserRouter as Router, 10 | Switch, 11 | Route, 12 | Link, 13 | Redirect, 14 | withRouter 15 | } from "react-router-dom"; 16 | 17 | const fetcher = url => axios.get(url).then(res => res.data) 18 | 19 | export default function UserTable() { 20 | const { data, error } = useSWR("/api/getAll", fetcher) 21 | const [showVerification, setShowVerification] = useState(false) 22 | const [verificationCode, setVerificationCode] = useState("") 23 | const [clicked, setClick] = useState(false); 24 | const [logout, setLogout] = useState(false); 25 | const users = data || [] 26 | const { sortedUsers, requestSort, sortConfig } = useSortableData(users) 27 | 28 | function handleClickToLogout() { 29 | setLogout(!logout); 30 | } 31 | 32 | const redirect = [] 33 | if (logout) { 34 | redirect.push() 39 | } 40 | 41 | function handleShowVerification() { 42 | if (!clicked) { 43 | axios.post('/api/verification') 44 | .then((data) => { 45 | setVerificationCode(data.data) 46 | }) 47 | setClick(true); 48 | } 49 | setShowVerification(!showVerification); 50 | } 51 | 52 | const getClassNamesFor = (name) => { 53 | if (!sortConfig) { 54 | return "invisible ml-2 flex-none rounded text-gray-400 group-hover:visible group-focus:visible" 55 | } 56 | if (sortConfig.key === name) { 57 | return sortConfig.direction === "ascending" ? "ml-2 flex-none rounded bg-gray-200 text-gray-900 group-hover:bg-gray-300" : "ml-2 flex-none rounded bg-gray-200 text-gray-900 group-hover:bg-gray-300 -rotate-180" 58 | } else { 59 | return "invisible ml-2 flex-none rounded text-gray-400 group-hover:visible group-focus:visible"; 60 | } 61 | }; 62 | 63 | return ( 64 |
65 | {showVerification && } 66 |
67 |
68 |

Codesmith Residents and Alumni

69 |

70 | 71 |

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