├── .gitignore ├── .gitattributes ├── static ├── images │ ├── discord.png │ ├── download.png │ └── indexpagae.gif └── stylesheet.css ├── config.json.example ├── router.js ├── routes ├── index.js ├── guildroutes.js └── discord.js ├── app.js ├── views ├── partials │ └── navbar.ejs ├── serverpage.ejs ├── index.ejs └── serverinfo.ejs ├── package.json ├── LICENSE ├── README.md ├── CONTRIBUTING.md └── bot └── webapi_handler.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | config.json -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /static/images/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfweh/discord-bot-dashboard/HEAD/static/images/discord.png -------------------------------------------------------------------------------- /static/images/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfweh/discord-bot-dashboard/HEAD/static/images/download.png -------------------------------------------------------------------------------- /static/images/indexpagae.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfweh/discord-bot-dashboard/HEAD/static/images/indexpagae.gif -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | 4 | "clientId": "", 5 | "clientSecret": "", 6 | "scopes": ["identify", "guilds"], 7 | "redirectUri": "", 8 | "token":"", 9 | "inviteurl":"" 10 | } 11 | -------------------------------------------------------------------------------- /router.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | // '/' 3 | app.use('/', require('./routes/index')); 4 | // '/authorize' 5 | app.use('/authorize', require('./routes/discord')); 6 | app.use('/manage',require('./routes/guildroutes')) 7 | } 8 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | 3 | router.get('/', (req, res) => { 4 | res.render('index', { pageTitle: 'Dashboard', user: req.session.user || null}); 5 | 6 | }); 7 | // router.get('/servers',(req,res) =>{ 8 | // console.log(req.session.guilds) 9 | // res.render('serverpage',{pageTitle:'Server',guild : req.session.guilds || null }); 10 | // }) 11 | module.exports = router; 12 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | let port = require('./config.json').port || 3000; 5 | app.set('port', port); 6 | 7 | const session = require('express-session'); 8 | app.use(express.json()) // for parsing application/json 9 | app.use(express.urlencoded({ extended: true })) 10 | app.set('view engine', 'ejs'); 11 | app.use(express.static('static')); 12 | app.use(session({ 13 | secret: '48738924783748273742398747238', 14 | resave: false, 15 | saveUninitialized: false, 16 | expires: 300000, 17 | })); 18 | require('./router')(app); 19 | 20 | app.listen(port, () => console.info(`Listening on port ${port}`)); 21 | -------------------------------------------------------------------------------- /views/partials/navbar.ejs: -------------------------------------------------------------------------------- 1 |
15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord.js-dashboard", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/charfweh/discord-bot-dashboard.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/charfweh/discord-bot-dashboard.git" 19 | }, 20 | "homepage": "https://github.com/charfweh/discord-bot-dashboard.git#readme", 21 | "dependencies": { 22 | "body-parser": "^1.19.0", 23 | "ejs": "^2.6.1", 24 | "express": "^4.16.3", 25 | "express-session": "^1.17.1", 26 | "form-data": "^2.3.2", 27 | "node-fetch": "^3.1.1", 28 | "uid-safe": "^2.1.5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 caelinj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /views/serverpage.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |<%= g.name %> 19 |
21 | <% } %> 22 | <% for ( g of inviteguilds) {%> 23 |<%= g.name %> 24 | 28 |
29 | 30 | <% } %> 31 | 32 | 33 | -------------------------------------------------------------------------------- /routes/guildroutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | // post params 3 | const router = require('express').Router(); 4 | const { clientId, clientSecret, scopes, redirectUri } = require('../config.json'); 5 | const fetch = require('node-fetch'); 6 | const FormData = require('form-data'); 7 | const {userhit,manageguild,checkguild,modifyguild} = require("../bot/webapi_handler.js"); 8 | let id,guildobj,mutualguilds,webuser; 9 | // define the home page route 10 | // middleware that is specific to this router 11 | router.get('/', function (req, res) { 12 | if (!req.session.user) return res.redirect("/authorize") 13 | res_user = req.session.user 14 | res_guild = req.session.guilds 15 | returnobj = checkguild(res_user.id,res_guild) 16 | mutualguilds = returnobj.bot_guilds 17 | inviteguilds = returnobj.invitebot_guilds 18 | res.render("serverinfo",{pageTitle:"Manage Guilds",mutualguilds:mutualguilds,inviteguilds:inviteguilds,user:req.session.user}); 19 | }) 20 | // define the guild id route 21 | 22 | router.get('/:id',(req,res)=>{ 23 | if (!req.session.user) return res.redirect("/authorize") 24 | id = req.params["id"] 25 | guildobj = manageguild(id) 26 | res.render("serverpage",{user:req.session.user,count:guildobj.memberCount, pageTitle:"Edit Guild" , name:guildobj.guildname , iconurl:guildobj.iconurl , owner:guildobj.owner, guildid:guildobj.id}) 27 | }) 28 | 29 | router.post('/:id',(req,res)=>{ 30 | console.log(req.body.channels) 31 | let channels = req.body.channels 32 | let regex = /^[a-zA-Z0-9\-\,]+/gm 33 | let result = channels.match(regex) 34 | webuser = req.session.user 35 | if(result == null) return res.send("malformed argument") 36 | let res_status = modifyguild(result,guildobj.id,webuser) 37 | if(res_status == 'Error') return res.send("Error") 38 | res.send("Success!") 39 | }) 40 | 41 | 42 | 43 | module.exports = router 44 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Transcriptase 2 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: 3 | 4 | - Reporting a bug 5 | - Discussing the current state of the code 6 | - Submitting a fix 7 | - Proposing new features 8 | - Becoming a maintainer 9 | 10 | ## We Develop with Github 11 | We use github to host code, to track issues and feature requests, as well as accept pull requests. 12 | 13 | ## We Use [Github Flow](https://guides.github.com/introduction/flow/index.html), So All Code Changes Happen Through Pull Requests 14 | Pull requests are the best way to propose changes to the codebase (we use [Github Flow](https://guides.github.com/introduction/flow/index.html)). We actively welcome your pull requests: 15 | 16 | 1. Fork the repo and create your branch from `master`. 17 | 2. If you've added code that should be tested, add tests. 18 | 3. If you've changed APIs, update the documentation. 19 | 4. Ensure the test suite passes. 20 | 5. Make sure your code lints. 21 | 6. Issue that pull request! 22 | 23 | ## Any contributions you make will be under the MIT Software License 24 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern. 25 | 26 | ## Report bugs using Github's [issues](https://github.com/briandk/transcriptase-atom/issues) 27 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](); it's that easy! 28 | 29 | ## Write bug reports with detail, background, and sample code 30 | 31 | **Great Bug Reports** tend to have: 32 | 33 | - A quick summary and/or background 34 | - Steps to reproduce 35 | - Be specific! 36 | - Give sample code if you can. 37 | - What you expected would happen 38 | - What actually happens 39 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) 40 | 41 | People *love* thorough bug reports. I'm not even kidding. 42 | 43 | ## Use a Consistent Coding Style 44 | I'm borrowing these from [Facebook's Guidelines](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) 45 | 46 | * 2 spaces for indentation rather than tabs 47 | * You can try running `npm run lint` for style unification 48 | 49 | ## License 50 | By contributing, you agree that your contributions will be licensed under its MIT License. 51 | 52 | ## References 53 | This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) 54 | 55 | This was forked from [this](https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62) 56 | -------------------------------------------------------------------------------- /routes/discord.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const { clientId, clientSecret, scopes, redirectUri } = require('../config.json'); 3 | const fetch = require('node-fetch'); 4 | const FormData = require('form-data'); 5 | const {userhit} = require("../bot/webapi_handler.js"); 6 | const forceAuth = (req, res, next) => { 7 | if (!req.session.user) return res.redirect('/authorize') 8 | else return next(); 9 | } 10 | //bot 11 | router.get('/', (req, res) => { 12 | if (req.session.user) return res.redirect('/'); 13 | 14 | const authorizeUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorize%2Fcallback&response_type=code&scope=identify%20guilds`; 15 | res.redirect(authorizeUrl); 16 | }); 17 | 18 | router.get('/callback', (req, res) => { 19 | if (req.session.user) return res.redirect('/'); 20 | 21 | const accessCode = req.query.code; 22 | if (!accessCode) throw new Error('No access code returned from Discord'); 23 | 24 | const data = new FormData(); 25 | data.append('client_id', clientId); 26 | data.append('client_secret', clientSecret); 27 | data.append('grant_type', 'authorization_code'); 28 | data.append('redirect_uri', redirectUri); 29 | data.append('scope', scopes.join(' ')); 30 | data.append('code', accessCode); 31 | fetch('https://discordapp.com/api/oauth2/token', { 32 | method: 'POST', 33 | body: data 34 | }) 35 | .then(res => res.json()) 36 | .then(response => { 37 | fetch('https://discordapp.com/api/users/@me', { 38 | method: 'GET', 39 | headers: { 40 | authorization: `${response.token_type} ${response.access_token}` 41 | }, 42 | }) 43 | .then(res2 =>res2.json()) 44 | .then(userResponse => { 45 | userResponse.tag = `${userResponse.username}#${userResponse.discriminator}`; 46 | userResponse.avatarURL = userResponse.avatar ? `https://cdn.discordapp.com/avatars/${userResponse.id}/${userResponse.avatar}.png?` : null; 47 | userhit(userResponse) 48 | req.session.user = userResponse; 49 | 50 | }); 51 | fetch('https://discordapp.com/api/users/@me/guilds', { 52 | method: 'GET', 53 | headers: { 54 | authorization: `${response.token_type} ${response.access_token}` 55 | }, 56 | }) 57 | .then(res2 => res2.json()) 58 | .then(gResponse => { 59 | req.session.guilds = gResponse; 60 | res.redirect('/'); 61 | }); 62 | }); 63 | }); 64 | router.get('/logout', forceAuth, (req, res) => { 65 | req.session.destroy((err)=>{ 66 | if(err) console.log("session not destroyed") 67 | console.log("session destroyed") 68 | 69 | }); 70 | res.redirect('/') 71 | }); 72 | module.exports = router; 73 | -------------------------------------------------------------------------------- /bot/webapi_handler.js: -------------------------------------------------------------------------------- 1 | const discord = require("discord.js") 2 | const bot = new discord.Client() 3 | const {token, bot_prefix} = require("../config.json") 4 | bot.on("ready",()=>{ 5 | console.log("im ready") 6 | }) 7 | function userhit(userResponse){ 8 | //this channel id is of the server im in, please replace with channel id of your server 9 | bot.channels.cache.get('730731531428954172').send(`User authorize with ${userResponse.username}#${userResponse.discriminator}`) 10 | } 11 | function checkguild(member_id,guilds){ 12 | owner_guilds = [] 13 | bot_guilds = [] 14 | invitebot_guilds = [] 15 | guilds.forEach((item, i) => { 16 | if(item.owner == true){ 17 | owner_guilds.push({"name":item.name,"id":item.id}) 18 | if(bot.guilds.cache.get(item.id)){ 19 | bot_guilds.push({"name":item.name,"id":item.id}) 20 | } 21 | if(!bot.guilds.cache.get(item.id)){ 22 | invitebot_guilds.push({"name":item.name,"id":item.id}) 23 | } 24 | } 25 | }); 26 | return {bot_guilds,invitebot_guilds} 27 | } 28 | 29 | function manageguild(g_id){ 30 | let guild = bot.guilds.cache.get(g_id) 31 | if(guild){ 32 | let memberCount = guild.memberCount 33 | let guildname = guild.name 34 | let iconurl = guild.iconURL() 35 | let owner = guild.owner.displayName 36 | let id = guild.id 37 | return {memberCount,guildname,iconurl,owner,id} 38 | } 39 | return "You dont share mutual guild with the bot" 40 | } 41 | 42 | //parse the channels from POST request 43 | async function modifyguild(channels, g_id, webuser){ 44 | let c = channels[0].split(',') 45 | editguild = bot.guilds.cache.get(g_id) 46 | if(!editguild.channels.cache.find(c=>c.name == 'dashboard-logs')) return "Error" 47 | else{ 48 | let logs = await editguild.channels.cache.find(c => c.name == 'dashboard-logs') 49 | logs.send(`User initiated edit guild ${webuser.tag}`) 50 | c.forEach((item, i) => { 51 | editguild.channels.create(item,"text").then(()=>{ 52 | console.log("Channel created",item) 53 | }).catch((e)=>{ 54 | editguild.channels.cache.find(c => c.name == 'dashboard-logs').send(`[-] Error: ${e}`) 55 | }) 56 | }); 57 | } 58 | return "OK" 59 | } 60 | 61 | 62 | //setup function for dashboard logging 63 | bot.on("message",async message=>{ 64 | if(message.author == message.author.bot) return; 65 | if(message.content.startsWith(bot_prefix+"setup")){ 66 | await message.channel.send("[OK] starting the setup") 67 | if(message.member.hasPermission('ADMINISTRATOR')){ 68 | await message.guild.channels.create("dashboard-logs","text").then(()=>{ 69 | message.channel.send("[+] Channel created!") 70 | }).catch((e)=>{ 71 | message.channel.send(`[-] Error: ${e}`) 72 | }) 73 | }else return message.channel.send("[-] You do not have correct permission to run this command") 74 | } 75 | }) 76 | 77 | bot.on("guildCreate",async()=>{ 78 | await message.systemChannel.send('Thanks for inviting me in here\n Use ``g!setup`` to start the setup!') 79 | }) 80 | 81 | bot.login(token) 82 | module.exports = {userhit,manageguild,checkguild,modifyguild}; 83 | -------------------------------------------------------------------------------- /static/stylesheet.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto:300,500'); 2 | 3 | body { 4 | background-color: #353536; 5 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23ffffff'/%3E%3Cstop offset='1' stop-color='%23353536'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%239a9a9b'/%3E%3Cstop offset='1' stop-color='%23353536'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='rotate(0 0 0)'%3E%3Cg transform='rotate(0 0 0)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(0 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.1' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 6 | background-attachment: fixed; 7 | background-size: cover; 8 | } 9 | 10 | .page-content { 11 | padding: 4px 42px; 12 | } 13 | 14 | .page-content h1 { margin-bottom: -10px; } 15 | 16 | h1, h2, h3, h4, h5, h6 { 17 | font-family: 'Roboto', sans-serif; 18 | font-weight: 500; 19 | color: #000000; 20 | } 21 | 22 | p, a { 23 | font-family: 'Roboto', sans-serif; 24 | font-weight: 300; 25 | color: #000000; 26 | text-decoration: none; 27 | } 28 | a:hover{ 29 | color:#000000 ; 30 | text-decoration: none; 31 | } 32 | .navbar { 33 | background: #23272A; 34 | padding: 21px 42px; 35 | } 36 | 37 | .navbar a { 38 | transition: .25s ease; 39 | color: #ffffff; 40 | text-decoration: none; 41 | } 42 | 43 | .navbar a:hover { 44 | color: #7792f3; 45 | } 46 | 47 | .navbar a:not(:last-child) { 48 | margin-right: 12px; 49 | } 50 | 51 | .navbar .right { 52 | float: right; 53 | } 54 | .header1{ 55 | align-content: center; 56 | text-align: center; 57 | color: #ffffff; 58 | font-size: 5rem; 59 | padding-top: 3rem; 60 | font-weight: bold; 61 | letter-spacing: 2px; 62 | } 63 | .mainbody{ 64 | align-content: center; 65 | text-align: center; 66 | padding-top: 3rem; 67 | letter-spacing: 2px; 68 | } 69 | .avatar{ 70 | border-radius: 50%; 71 | height: 30px; 72 | width: 30px; 73 | } 74 | 75 | @import url("https://fonts.googleapis.com/css?family=Fjalla+One&display=swap"); 76 | * { 77 | margin: 0; 78 | padding: 0; 79 | } 80 | .header{ 81 | color:#000000; 82 | font-size: 1.5rem; 83 | padding:1rem; 84 | } 85 | .hreflinks{ 86 | color:"black"; 87 | } 88 | .editguild { 89 | background: #676767; 90 | padding: 3rem 100px; 91 | border: 2px solid black; 92 | box-shadow: 15px 15px 1px #778484, 15px 15px 1px 2px black; 93 | width: 50%; 94 | align-self: center; 95 | margin-left: auto; 96 | margin-right: auto; 97 | } 98 | .l1{ 99 | display: block; 100 | width: 100%; 101 | font-size: 30pt; 102 | font-family: "Fjalla One"; 103 | min-width: 250px; 104 | padding-left: 5px; 105 | outline: none; 106 | color: black; 107 | text-align: center; 108 | } 109 | .l2{ 110 | display: block; 111 | width: 100%; 112 | font-size: 18pt; 113 | font-family: "Fjalla One"; 114 | min-width: 250px; 115 | padding-left: 5px; 116 | outline: none; 117 | color: black; 118 | padding: 1rem; 119 | } 120 | input { 121 | display: block; 122 | width: 100%; 123 | font-size: 14pt; 124 | line-height: 28pt; 125 | font-family: "Fjalla One"; 126 | margin-bottom: 28pt; 127 | border: none; 128 | border-bottom: 5px solid black; 129 | background: #ffffff; 130 | min-width: 250px; 131 | padding-left: 5px; 132 | outline: none; 133 | color: black; 134 | } 135 | 136 | input:focus { 137 | border-bottom: 5px solid #95a4ff; 138 | } 139 | 140 | button { 141 | display: block; 142 | margin: 0 auto; 143 | line-height: 28pt; 144 | padding: 0 20px; 145 | background: #ffffff; 146 | letter-spacing: 2px; 147 | transition: 0.2s all ease-in-out; 148 | outline: none; 149 | border: 1px solid black; 150 | box-shadow: 3px 3px 1px #95a4ff, 3px 3px 1px 1px black; 151 | } 152 | button:hover { 153 | background: black; 154 | color: white; 155 | border: 1px solid black; 156 | } 157 | 158 | ::selection { 159 | background: #ffc8ff; 160 | } 161 | 162 | input:-webkit-autofill, 163 | input:-webkit-autofill:hover, 164 | input:-webkit-autofill:focus { 165 | border-bottom: 5px solid #95a4ff; 166 | -webkit-text-fill-color: #2A293E; 167 | -webkit-box-shadow: 0 0 0px 1000px #f8f4e5 inset; 168 | transition: background-color 5000s ease-in-out 0s; 169 | } 170 | 171 | .manage{ 172 | padding: 0.8rem; 173 | align-items: center; 174 | text-align: center; 175 | } 176 | --------------------------------------------------------------------------------