├── public └── assets │ └── logo.png ├── src ├── views │ ├── _footer.ejs │ ├── 404.ejs │ ├── _header.ejs │ ├── index.ejs │ ├── account.ejs │ ├── cookies.ejs │ ├── privacy.ejs │ └── login.ejs └── static │ └── assets │ └── main.css ├── config.json ├── README.md ├── package.json ├── install.sql ├── index.js └── backend.js /public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Itz-Hyperz/EJS-WebTemplate/HEAD/public/assets/logo.png -------------------------------------------------------------------------------- /src/views/_footer.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Copyright © 2024 Logan's Web Services.

4 |
5 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "domain": "http://localhost:3000", 4 | "port": 3000, 5 | "debugMode": false, 6 | "seoKeywords": "expressjs, website, template", 7 | "ownerIds": ["YOUR_USER_ID"], 8 | 9 | "sql": { 10 | "host": "localhost", 11 | "user": "root", 12 | "password": "", 13 | "database": "changeme" 14 | }, 15 | 16 | "discord": { 17 | "enabled": false, 18 | "oauthId": "YOUR_OAUTH_CLIENT_ID", 19 | "oauthToken": "YOUR_OAUTH_CLIENT_SECRET" 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PLEASE ⭐ THIS REPOSITORY 2 | If you love my work and want to support it, simply star the repository, it's free!!! 3 | 4 | # EJS-WebTemplate 5 | A simple ExpressJS Web Template designed to be used for practically any project. 6 | 7 | ## Passport Options 8 | - Username / Password 9 | - Discord oAuth2 10 | 11 | ## Preview: 12 | ![home](https://cdn.bosssoftware.net/u/main/ZBrxILq.png) 13 | ![login](https://cdn.bosssoftware.net/u/main/EV38aOD.png) 14 | ![register](https://cdn.bosssoftware.net/u/main/iInp5aQ.png) 15 | ![account](https://cdn.bosssoftware.net/u/main/0Q1RG5G.png) 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperz-webtemplate", 3 | "version": "1.0.0", 4 | "description": "An ExpressJS template made by Hyperz#0001", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Hyperz#0001", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.4.0", 13 | "bcrypt": "^5.1.0", 14 | "body-parser": "^1.20.0", 15 | "chalk": "^4.1.1", 16 | "ejs": "^3.1.8", 17 | "express": "^4.18.1", 18 | "express-flash": "^0.0.2", 19 | "express-session": "^1.17.3", 20 | "figlet": "^1.5.2", 21 | "hyperz-utils": "^1.0.7", 22 | "multer": "^1.4.4", 23 | "mysql": "^2.18.1", 24 | "passport": "^0.5.2", 25 | "passport-discord-hyperz": "^0.1.4", 26 | "passport-local": "^1.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /install.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE changeme CHARACTER SET utf8; 2 | use changeme; 3 | 4 | CREATE TABLE sitesettings ( 5 | sitename TEXT, 6 | sitedesc TEXT, 7 | sitecolor TEXT 8 | ); 9 | 10 | CREATE TABLE users ( 11 | id TEXT, 12 | email TEXT, 13 | password TEXT 14 | ); 15 | 16 | CREATE TABLE staff ( 17 | userid TEXT 18 | ); 19 | 20 | ALTER DATABASE changeme CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; 21 | ALTER TABLE sitesettings CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; 22 | ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; 23 | ALTER TABLE staff CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; 24 | 25 | INSERT INTO sitesettings (sitename, sitedesc, sitecolor) VALUES ('Change Me', 'A description placeholder...', '#006fed'); -------------------------------------------------------------------------------- /src/views/404.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 - Page Not Found 5 | 26 | 27 | 28 |

404

29 |

Page Not Found

30 | 31 | 32 | -------------------------------------------------------------------------------- /src/views/_header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home - <%= sitesettings.sitename %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <%- include('_header') %> 17 |
18 |

Landing Page

19 |

This is simply the landing page for the EJS Website Template!

20 | Authenticate 21 |
22 | <%- include('_footer') %> 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/views/account.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Account - <%= sitesettings.sitename %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <%- include('_header') %> 17 |
18 |

Account ID

19 |
<%= user.id %>
20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 |
33 |
34 | Your Account ID does not ever change. It is unique to your account and cannot be replicated. 35 |
36 | <%- include('_footer') %> 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/views/cookies.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cookies - <%= sitesettings.sitename %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <%- include('_header') %> 16 |
17 |

This cookie policy outlines how <%= sitesettings.sitename %> uses “cookies” and other similar technologies, in connection with our site and related services.

18 |

What is a Cookie?

19 |

Cookies are small text files stored in a computer's browser directory. They help website providers with understanding how people use a website, remembering user login details, and storing website preferences.

20 |

Does <%= sitesettings.sitename %> use Cookies?

21 |

Yes we do use cookies to:

22 | 27 |

Who sets cookies when I use <%= sitesettings.sitename %>'s Site?

28 |

There are two types of cookies that are set;

29 | 33 |
34 | <%- include('_footer') %> 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/views/privacy.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Privacy - <%= sitesettings.sitename %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <%- include('_header') %> 16 |
17 |

Your information is valuable and we are pleased to provide information regarding your privacy.

18 |

Kinds of personal information we collect and store

19 |

As we use third parties for our login methods, we collect information provided by these services. Information we collect is.

20 | 29 |

Possible login services we can enable are; Discord, Local, these services give basic information supplied by their API. Their Terms of Service and privacy policies can be viewed on their respective platforms.

30 |

How we collect your information

31 |

Once you log in and create an account your information from there is collected and stored in our secure database. This information includes the kinds of personal information listed above. Payment information is only collected when a purchase has been made on our website.

32 |

How we use your information

33 |

We actively use your information on your account page along with administrational logs which include; payment history, audit logs, receipts.

34 |

We also use your information with our third parties which are able to request user information access, these third parties are listed below.

35 |

Additionally, we also collect data to use in advertising on various advertisement platforms. The shared information with advertising is broad and is not figures for individual user accounts. The data is collected and used as a sum total between all users to gather statistics for our website.

36 |

Verified Third Parties:

37 | 40 |
41 | <%- include('_footer') %> 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/views/login.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Login - <%= sitesettings.sitename %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <%- include('_header') %> 16 |
17 |

Login

18 |
19 |
20 | 21 | 22 | 23 | <% if(messages.error) { %> 24 |

<%= messages.error %>

25 | <% }; %> 26 |
27 | 28 | <% if(config.discord.enabled) { %> 29 | Login W/Discord 30 | <% }; %> 31 |
32 |
33 | Privacy Policy 34 |
35 |
36 | Cookie Policy 37 |
38 |
39 |
40 |
41 |
42 | 67 | <%- include('_footer') %> 68 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Basic Imports 2 | const config = require("./config.json"); 3 | const express = require("express"); 4 | const app = express(); 5 | const chalk = require('chalk'); 6 | const utils = require('hyperz-utils'); 7 | const bcrypt = require('bcrypt'); 8 | 9 | // MySQL Setup 10 | const mysql = require('mysql'); 11 | config.sql.charset = "utf8mb4"; 12 | let con = mysql.createConnection(config.sql); // set = 0 to disable 13 | 14 | // Backend Initialization 15 | const backend = require('./backend.js'); 16 | backend.init(app, con); 17 | 18 | // Passport Initialization 19 | const passport = require('passport'); 20 | const LocalStrategy = require('passport-local').Strategy; 21 | passport.serializeUser(function(user, done) { done(null, user) }); 22 | passport.deserializeUser(function(obj, done) { done(null, obj) }); 23 | passport.use(new LocalStrategy({ usernameField: 'email' }, backend.authenticateUserLocal)) 24 | 25 | if(config.discord.enabled) { 26 | const DiscordStrategy = require('passport-discord-hyperz').Strategy; 27 | passport.use(new DiscordStrategy({ 28 | clientID: config.discord.oauthId, 29 | clientSecret: config.discord.oauthToken, 30 | callbackURL: `${(config.domain.endsWith('/') ? config.domain.slice(0, -1) : config.domain)}/auth/discord/callback`, // THIS IS THE CALLBACK URL 31 | scope: ['identify', 'guilds', 'email'], 32 | prompt: 'consent' 33 | }, function(accessToken, refreshToken, profile, done) { 34 | process.nextTick(function() { 35 | return done(null, profile); 36 | }); 37 | })); 38 | app.get('/auth/discord', passport.authenticate('discord')); 39 | app.get('/auth/discord/callback', passport.authenticate('discord', {failureRedirect: '/'}), async function(req, res) { 40 | req.session?.loginRef ? res.redirect(req.session.loginRef) : res.redirect('/'); 41 | delete req.session?.loginRef 42 | }); 43 | }; 44 | 45 | // Routing 46 | app.get('', async function(req, res) { 47 | backend.resetAppLocals(app); 48 | res.render('index.ejs'); 49 | }); 50 | 51 | app.get('/login', backend.checkNotAuth, async function(req, res) { 52 | backend.resetAppLocals(app); 53 | res.render('login.ejs'); 54 | }); 55 | 56 | app.get('/cookies', async function(req, res) { 57 | await backend.resetAppLocals(app); 58 | res.render('cookies.ejs'); 59 | }); 60 | 61 | app.get('/privacy', async function(req, res) { 62 | await backend.resetAppLocals(app); 63 | res.render('privacy.ejs'); 64 | }); 65 | 66 | app.get('/account', backend.checkAuth, async function(req, res) { 67 | backend.resetAppLocals(app); 68 | res.render('account.ejs', { user: req.user }); 69 | }); 70 | 71 | // YOU SHOULD DELETE THIS BEFORE PRODUCTION BUILD 72 | app.get('/userdata', backend.checkAuth, async function(req, res) { 73 | backend.resetAppLocals(app); 74 | res.type('json').send(JSON.stringify(req.user, null, 4) + '\n'); 75 | }); 76 | 77 | app.post('/register', backend.checkNotAuth, async (req, res) => { 78 | await backend.resetAppLocals(app); 79 | for(let name of Object.keys(req.body)) { 80 | req.body[name] = await utils.sanitize(req.body[name]); 81 | }; 82 | try { 83 | let userid = await backend.generateUserId(7); 84 | let hashedPassword = await bcrypt.hash(req.body.password, 13); 85 | con.query(`SELECT * FROM users WHERE email="${req.body.email}"`, async function (err, row) { 86 | if(err) throw err; 87 | if(!row[0]) { 88 | con.query(`SELECT * FROM sitesettings`, async function(err, row) { 89 | if(err) throw err; 90 | if(!row[0]) return console.log('No site settings found.'); 91 | con.query(`INSERT INTO users (id, email, password) VALUES ("${userid}", "${req.body.email}", "${hashedPassword}")`, async function (err, row) { 92 | if(err) throw err; 93 | }); 94 | res.redirect('/login') 95 | }); 96 | } else { 97 | res.redirect('/login') 98 | }; 99 | }); 100 | } catch { 101 | res.redirect('/register') 102 | }; 103 | }); 104 | 105 | app.post('/backend/update/password', backend.checkAuth, async function(req, res) { 106 | await backend.resetAppLocals(app); 107 | if(req.body.password !== req.body.confpassword) return res.send('Your passwords do not match...'); 108 | let hashedPassword = await bcrypt.hash(req.body.confpassword, 13); 109 | con.query(`SELECT * FROM users WHERE id="${req.user.id}"`, async function(err, row) { 110 | if(err) throw err; 111 | con.query(`UPDATE users SET password="${hashedPassword}" WHERE id="${req.user.id}"`, function(err, row) { if(err) throw err; }); 112 | req.logout(function(err) { 113 | if(err) { return next(err); } 114 | }); 115 | res.redirect('/login'); 116 | }); 117 | }); 118 | 119 | app.post('/auth/local', backend.checkNotAuth, passport.authenticate('local', { 120 | successRedirect: '/account', 121 | failureRedirect: '/login', 122 | failureFlash: true 123 | })); 124 | 125 | config.ownerIds.forEach(function(item) { 126 | if(item != 'YOUR_USER_ID') { 127 | con.query(`SELECT * FROM staff WHERE userid="${item}"`, function(err, row) { 128 | if(err) throw err; 129 | if(row[0]) return; 130 | con.query(`INSERT INTO staff (userid) VALUES ("${item}")`, function(err, row) { 131 | if(err) throw err; 132 | }); 133 | }); 134 | }; 135 | }); 136 | 137 | // MAKE SURE THIS IS LAST FOR 404 PAGE REDIRECT 138 | app.get('*', function(req, res){ 139 | res.render('404.ejs'); 140 | }); 141 | 142 | // Server Initialization 143 | app.listen(config.port) 144 | 145 | // Rejection Handler 146 | process.on('unhandledRejection', (err) => { 147 | if(config.debugMode) console.log(chalk.red(err)); 148 | }); 149 | -------------------------------------------------------------------------------- /backend.js: -------------------------------------------------------------------------------- 1 | // Imports 2 | const config = require("./config.json"); 3 | const passport = require('passport'); 4 | const multer = require('multer'); 5 | const bodyParser = require('body-parser'); 6 | const session = require('express-session'); 7 | const express = require("express"); 8 | const flash = require('express-flash'); 9 | const chalk = require('chalk'); 10 | const figlet = require('figlet'); 11 | const utils = require('hyperz-utils'); 12 | const pjson = require('./package.json'); 13 | const axios = require('axios'); 14 | const bcrypt = require('bcrypt'); 15 | 16 | // Basic Variable Setup 17 | let projectName = 'CHANGE ME' 18 | let pubApiURL = `https://raw.githubusercontent.com/Itz-Hyperz/version-pub-api/main/versions.json`; 19 | let storedAppVariable; 20 | let dbcon; 21 | 22 | // Init Function 23 | async function init(app, con) { 24 | if (Number(process.version.slice(1).split(".")[0] < 16)) throw new Error(`Node.js v16 or higher is required, Discord.JS relies on this version, please update @ https://nodejs.org`); 25 | var multerStorage = multer.memoryStorage(); // req.body setup 26 | app.use(multer({ storage: multerStorage }).any()); // req.body setup 27 | app.use(bodyParser.urlencoded({ extended: false })); // req.body setup 28 | app.use(express.json()); // req.body setup 29 | app.use(flash()); // passport flash system for live messages 30 | app.use(session({ // passport session setup 31 | secret: 'keyboard cat', 32 | resave: false, 33 | saveUninitialized: false, 34 | cookie: {maxAge: 31556952000}, 35 | })); 36 | app.use(passport.initialize()); // passport initialization 37 | app.use(passport.session()); // passport session initialization 38 | app.set('views', './src/views'); // setting views folder 39 | app.set('view engine', 'ejs'); // setting views engine 40 | app.use(express.static('public')); // making public folder "public" 41 | app.use(express.static('src/static')); // making static folder "public" 42 | app.use('/assets', express.static(__dirname + 'public/assets')); // creating shortcut 43 | app.use('/static', express.static(__dirname + 'src/static/assets')); // creating shortcut 44 | dbcon = con; // setting con variable for this file (MySQL Connection) 45 | // BEGIN FANCY CONSOLE LOGGING STUFF 46 | figlet.text(projectName, { font: "Standard", width: 700 }, function(err, data) { 47 | if(err) throw err; 48 | let str = `${data}\n-------------------------------------------\n${projectName} is up and running on port ${config.port}!` 49 | console.log(chalk.bold(chalk.blue(str))); 50 | }); 51 | // Version Checking with API link above 52 | setTimeout(async () => { 53 | let currver = pjson.version 54 | let request = await axios({ 55 | method: 'get', 56 | url: pubApiURL, 57 | headers: {Accept: 'application/json, text/plain, */*','User-Agent': '*' } 58 | }); 59 | let latestver = request.data[pjson.name] 60 | if(latestver != currver) { 61 | console.log(`${chalk.yellow(`[Version Checker]`)} ${chalk.red(`You are not on the latest version.\nCurrent Version: ${currver}\nLatest Version: ${latestver || "ERR: pjson name not found in API"}`)}`) 62 | } else { 63 | console.log(`${chalk.green(`[Version Checker]`)} You are on the latest version.`) 64 | }; 65 | }, 3000); 66 | sqlLoop(con); // Keep SQL connection alive 67 | markSqlConnected(); // Mark SQL connected in console 68 | await resetAppLocals(app); // Reset app locals to be ready for next render (do this on every page load) 69 | }; 70 | 71 | // Keeps settings updated for next render 72 | async function resetAppLocals(app) { 73 | dbcon.query(`SELECT * FROM sitesettings`, function(err, settings) { 74 | if(err) throw err; 75 | app.locals = { 76 | config: config, 77 | packagejson: require('./package.json'), 78 | sitesettings: settings[0] 79 | }; 80 | storedAppVariable = app; 81 | }); 82 | }; 83 | 84 | // Keeps SQL connection alive 85 | async function sqlLoop(con) { 86 | if(con == 0) return; 87 | await con.ping(); 88 | setTimeout(() => sqlLoop(con), 60000 * 30); 89 | }; 90 | 91 | // Logs connection status in console 92 | async function markSqlConnected() { 93 | await dbcon.query(`SELECT * FROM sitesettings`, async function(err, row) { 94 | if(err) { 95 | setTimeout(() => { console.log(`${chalk.yellow(`[SQL Manager]`)} MySQL connection failed...`); }, 3400); 96 | } else { 97 | setTimeout(() => { console.log(`${chalk.yellow(`[SQL Manager]`)} MySQL successfully connected.`); }, 3400); 98 | }; 99 | }); 100 | }; 101 | 102 | // Make sure a user is logged in to view the rendered page 103 | async function checkAuth(req, res, next) { 104 | if(req.isAuthenticated()){ 105 | dbcon.query(`SELECT * FROM users WHERE id="${req.user.id}"`, function(err, row) { 106 | if(err) throw err; 107 | if(!row[0]) { 108 | dbcon.query(`INSERT INTO users (id, email, password) VALUES ("${req.user.id}", "${req.user.email}", "discord")`, function(err, row) { 109 | if(err) throw err; 110 | next(); 111 | }); 112 | } else { 113 | next(); 114 | }; 115 | }); 116 | } else{ 117 | res.redirect("/login"); 118 | } 119 | }; 120 | 121 | // Make sure the user is NOT logged in to view the rendered page 122 | async function checkNotAuth(req, res, next) { 123 | if(req.isAuthenticated()){ 124 | res.redirect("/account"); 125 | } else { 126 | next(); 127 | }; 128 | }; 129 | 130 | // Username/Password authentication 131 | async function authenticateUserLocal(email, password, done) { 132 | dbcon.query(`SELECT * FROM users WHERE email="${await utils.sanitize(email)}"`, async function(err, row) { 133 | if(err) throw err; 134 | if(!row[0]) return done(null, false, { message: 'No user with that email' }); 135 | try { 136 | if (await bcrypt.compare(password, row[0].password)) { 137 | return done(null, row[0]); 138 | } else { 139 | return done(null, false, { message: 'Password incorrect' }); 140 | }; 141 | } catch (e) { 142 | return done(e); 143 | }; 144 | }); 145 | }; 146 | 147 | // Generates a user Id for non-oauth2 users 148 | function generateUserId(length) { 149 | let result = ''; 150 | let characters = '0123456789'; 151 | let date = Date.now(); 152 | let charactersLength = characters.length; 153 | for ( let i = 0; i < length; i++ ) { 154 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 155 | } 156 | return date + result; 157 | }; 158 | 159 | // Module Exports 160 | module.exports = { 161 | init: init, 162 | checkAuth: checkAuth, 163 | checkNotAuth: checkNotAuth, 164 | authenticateUserLocal: authenticateUserLocal, 165 | generateUserId: generateUserId, 166 | resetAppLocals: resetAppLocals 167 | }; 168 | -------------------------------------------------------------------------------- /src/static/assets/main.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | overflow-x: hidden !important; 3 | } 4 | 5 | body { 6 | background-repeat: no-repeat !important; 7 | background-size: cover !important; 8 | background-position: center center !important; 9 | background-color: #1a1a1a; 10 | width: 100%; 11 | height:100%; 12 | margin: auto; 13 | padding: 0; 14 | color: white; 15 | font-family: 'Montserrat', sans-serif; 16 | font-size: 1rem; 17 | text-align: center; 18 | word-wrap: break-work; 19 | } 20 | 21 | .bg-theme { 22 | background-color: var(--theme-color) !important; 23 | } 24 | .bd-theme, .linkeditem { 25 | border-style: solid; 26 | border-color: var(--theme-color) !important; 27 | } 28 | .text-theme { 29 | color: var(--theme-color) !important; 30 | } 31 | .btn-theme { 32 | color: white; 33 | background-color: var(--theme-color); 34 | } 35 | .btn-theme:hover { 36 | color: white; 37 | box-shadow: inset 0 0 0 1000px rgba(0,0,0,.3); 38 | border-color: var(--theme-color); 39 | background-color: var(--theme-color); 40 | } 41 | .btn-outline-theme { 42 | border-color: var(--theme-color) !important; 43 | } 44 | .btn-outline-theme:hover, .btn-outline-theme:focus { 45 | background-color: var(--theme-color); 46 | border-color: var(--theme-color) !important; 47 | } 48 | .form-check-input:checked { 49 | background-color: var(--theme-color); 50 | border-color: var(--theme-color); 51 | } 52 | 53 | .btn-outline-theme { 54 | color: white; 55 | background-color: transparent; 56 | border-width: 2px; 57 | border-style: solid; 58 | border-radius: 0.4em; 59 | transition: background-color ease-in-out .2s; 60 | } 61 | 62 | .login-auth-main { 63 | width: 40%; 64 | border-radius: 0.4em; 65 | } 66 | 67 | .login-auth-inner { 68 | width: 100%; 69 | } 70 | 71 | .footermain { 72 | position: fixed; 73 | bottom: 0; 74 | left: 1em; 75 | color: white; 76 | } 77 | 78 | .navbar-nav { 79 | margin-left: auto; 80 | margin-right: 0; 81 | } 82 | 83 | .nav-link { 84 | color: white !important; 85 | } 86 | 87 | .nav-link i { 88 | margin-top: 0.2em; 89 | } 90 | 91 | .navbar-brand { 92 | color: white !important; 93 | font-weight: 700; 94 | } 95 | 96 | .navbar-toggler { 97 | color: white; 98 | border-color: white; 99 | } 100 | 101 | .navbar-toggler-icon { 102 | background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgb(255,255,255)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E"); 103 | } 104 | 105 | .bg-none { 106 | background-color: transparent !important; 107 | } 108 | 109 | .bg-discord { 110 | background-color: #5865F2 !important; 111 | } 112 | 113 | .bd-discord { 114 | border-color: #5865F2 !important; 115 | } 116 | 117 | a { 118 | color: white; 119 | text-decoration: none; 120 | transition: color 1s 121 | } 122 | 123 | a:hover { 124 | color: var(--theme-color); 125 | } 126 | 127 | .exo { 128 | font-family: 'Exo', sans-serif !important; 129 | } 130 | 131 | .montserrat { 132 | font-family: 'Montserrat', sans-serif !important; 133 | } 134 | 135 | .sourcecodepro { 136 | font-family: 'Source Code Pro', monospace !important; 137 | } 138 | 139 | .worksans { 140 | font-family: 'Work Sans', sans-serif !important; 141 | } 142 | 143 | .bigfont { 144 | font-weight: 700 !important; 145 | } 146 | 147 | pre.hljs div { 148 | position: relative; 149 | float: right; 150 | background: #2A2A2A; 151 | border-radius: 0.2em; 152 | } 153 | 154 | pre.hljs div svg { 155 | -moz-transition: fill 0.25s ease; 156 | -webkit-transition: fill 0.25s ease; 157 | -ms-transition: fill 0.25s ease; 158 | transition: fill 0.25s ease; 159 | vertical-align: middle; 160 | height: 1.5em; 161 | width: 1.5em; 162 | fill: rgba(92, 95, 110, 0.884); 163 | margin: 0.5em; 164 | } 165 | 166 | pre.hljs div svg:hover { 167 | fill: rgba(163, 164, 172, 0.884); 168 | cursor: pointer; 169 | } 170 | 171 | .hljs { 172 | display: block; 173 | padding: 9.5px; 174 | margin: 0 0 10px; 175 | font-size: 13px; 176 | line-height: 1.42857143; 177 | color: #ebebeb; 178 | font-family: 'Courier Prime', monospace; 179 | word-break: break-all; 180 | word-wrap: break-word; 181 | background-color: #1F1F1F; 182 | border: 1px solid #969696; 183 | border-radius: 4px; 184 | text-align: start; 185 | } 186 | 187 | .hljs-comment, 188 | .hljs-quote { 189 | color: #998; 190 | font-style: italic 191 | } 192 | 193 | .hljs-keyword, 194 | .hljs-selector-tag, 195 | .hljs-subst { 196 | color: #c36ec1; 197 | font-weight: bold 198 | } 199 | 200 | .hljs-number, 201 | .hljs-literal, 202 | .hljs-variable, 203 | .hljs-template-variable, 204 | .hljs-tag .hljs-attr { 205 | color: #cd9663 206 | } 207 | 208 | .hljs-string, 209 | .hljs-doctag { 210 | color: #97c075 211 | } 212 | 213 | .hljs-property { 214 | color: #dc686d 215 | } 216 | 217 | .hljs-params { 218 | color: #dc686d 219 | } 220 | 221 | .hljs-title, 222 | .hljs-section, 223 | .hljs-selector-id { 224 | color: #61a7dc; 225 | font-weight: bold; 226 | } 227 | 228 | .hljs-subst { 229 | font-weight: normal 230 | } 231 | 232 | .hljs-type, 233 | .hljs-class .hljs-title { 234 | color: #458; 235 | font-weight: bold 236 | } 237 | 238 | .hljs-tag, 239 | .hljs-name, 240 | .hljs-attribute { 241 | color: #000080; 242 | font-weight: normal 243 | } 244 | 245 | .hljs-regexp, 246 | .hljs-link { 247 | color: #009926 248 | } 249 | 250 | .hljs-symbol, 251 | .hljs-bullet { 252 | color: #990073 253 | } 254 | 255 | .hljs-built_in, 256 | .hljs-builtin-name { 257 | color: #0086b3 258 | } 259 | 260 | .hljs-meta { 261 | color: rgb(165, 50, 180); 262 | font-weight: bold 263 | } 264 | 265 | .hljs-deletion { 266 | background: #fdd 267 | } 268 | 269 | .hljs-addition { 270 | background: #dfd 271 | } 272 | 273 | .hljs-emphasis { 274 | font-style: italic 275 | } 276 | 277 | .hljs-strong { 278 | font-weight: bold 279 | } 280 | 281 | code { 282 | font-family: 'Lucida Console', 'Courier New', monospace; 283 | font-weight: normal; 284 | text-indent: 0; 285 | letter-spacing: 0; 286 | font-size: 0.9em; 287 | /* margin: 0 0.25em; */ 288 | padding: 0.25em 0.5em; 289 | background-color: rgba(144,144,144,0.25); 290 | border-radius: 0.25em; 291 | color: rgb(243, 243, 243); 292 | } 293 | 294 | pre code { 295 | display: block; 296 | padding: 9.5px; 297 | margin: 0 0 10px; 298 | font-size: 13px; 299 | line-height: 1.42857143; 300 | color: #ebebeb; 301 | font-family: 'Courier Prime', monospace; 302 | word-break: break-all; 303 | word-wrap: break-word; 304 | background-color: #4b4b4b; 305 | border: 1px solid #ccc; 306 | border-radius: 4px; 307 | } 308 | 309 | .codeforced { 310 | font-family: 'Lucida Console', 'Courier New', monospace; 311 | font-weight: normal; 312 | text-indent: 0; 313 | letter-spacing: 0; 314 | font-size: 0.9em; 315 | /* margin: 0 0.25em; */ 316 | padding: 0.25em 0.5em; 317 | background-color: rgba(144,144,144,0.25); 318 | border-radius: 0.25em; 319 | color: rgb(243, 243, 243); 320 | } 321 | 322 | .customDiv { 323 | width: 100%; 324 | max-height: 25em; 325 | overflow-y: auto; 326 | } 327 | 328 | .customDiv2 { 329 | width: 100%; 330 | height: 50em; 331 | max-height: 50em; 332 | overflow-y: auto; 333 | } 334 | 335 | .nomargin { 336 | margin: 0 !important; 337 | } 338 | 339 | table { 340 | background-color: rgba(41, 41, 41, 0.3); 341 | line-height: 1; 342 | overflow-x: auto; 343 | overflow-y: auto; 344 | } 345 | 346 | table tr:nth-child(odd) { 347 | background-color: #181818; 348 | } 349 | 350 | table tr:nth-child(even) { 351 | background-color: #111111; 352 | } 353 | 354 | .btnnostyle { 355 | margin-top: 0 !important; 356 | padding: 0 !important; 357 | background-color: transparent !important; 358 | border-style: none; 359 | border-color: transparent; 360 | } 361 | 362 | .closebutton { 363 | color: white; 364 | font-size: 2em; 365 | } 366 | 367 | .censor { 368 | filter: blur(3.5px); 369 | transition: filter 200ms ease-in-out; 370 | } 371 | 372 | /* Scrollbar */ 373 | /* width */ 374 | ::-webkit-scrollbar { 375 | width: 10px; 376 | } 377 | 378 | /* Track */ 379 | ::-webkit-scrollbar-track { 380 | /* background: #f1f1f1; */ 381 | background: rgba(255, 0, 0, 0); 382 | /* background-color: transparent; */ 383 | } 384 | 385 | /* Handle */ 386 | ::-webkit-scrollbar-thumb { 387 | background: rgba(136, 136, 136, 0.075); 388 | } 389 | 390 | /* Handle on hover */ 391 | ::-webkit-scrollbar-thumb:hover { 392 | background: rgba(136, 136, 136, 0.445); 393 | } 394 | 395 | ::-webkit-scrollbar-corner { 396 | background: rgba(136, 136, 136, 0.445); 397 | } 398 | 399 | @media only screen and (max-width: 540px) { 400 | /* For mobile view */ 401 | } 402 | --------------------------------------------------------------------------------