| @@ -0,0 +1,138 @@ | ||
| // Setting up | ||
| const express = require("express"); | ||
| const passport = require("passport"); | ||
| const bodyParser = require("body-parser"); | ||
| const cookieParser = require("cookie-parser"); | ||
| const session = require("express-session"); | ||
| const connectRedis = require("connect-redis")(session); | ||
| const csrf = require("csurf"); | ||
| const cJSON = require("circular-json"); | ||
| const compression = require("compression"); | ||
| const redis = require("redis"); | ||
| const helmet = require("helmet"); | ||
| const fs = require("fs-extra"); | ||
| const path = require("path"); | ||
| const uuid = require("uuid"); | ||
| const url = require("url"); | ||
| const morgan = require("morgan"); | ||
| const http = require("http"); | ||
| const https = require("https"); | ||
| const DiscordStrategy = require("./serverModules/DiscordStratagey"); | ||
| const passportRefresh = require("passport-oauth2-refresh"); | ||
| const favicon = require("serve-favicon"); | ||
| const cluster = require("cluster"); | ||
| const constants = new (require("../Internals/Constants"))() | ||
| // const serverUtils = new (require("./serverUtils"))(); | ||
|
|
||
| exports.init = () => { | ||
|
|
||
| // This is for morgan | ||
| console.stream = { | ||
| write: (message, encoding) => { | ||
| console.log(constants.web.morgan.FORMAT(cluster.worker.id, message)); | ||
| }, | ||
| }; | ||
|
|
||
| var redisInstance = null; | ||
| // The Arguments have been temp disabled with this statement because, well I have no idea what DB should be. - Oscar (oskikiboy) | ||
| if (!config.devConfig.redisCredentials) { | ||
| redisInstance = redis.createClient(); | ||
| } else { | ||
| redisInstance = redis.createClient(config.redis.pass ? { host: config.redis.host, port: config.redis.pass, db: config.redis.db, pass: config.redis.pass } : { host: config.redis.host, port: config.redis.pass, db: config.redis.db }); | ||
| } | ||
| const app = express(), | ||
| redisPub = redis.createClient(config.redis.pass ? { host: config.redis.host, port: config.redis.pass, pass: config.redis.pass } : { host: config.redis.host, port: config.redis.pass }), | ||
| redisSub = redisPub.duplicate(), | ||
| httpServer = http.createServer(/* {cert: fs.readFileSync(path.join(__dirname, "ssl.pem")).toString()}, */app), | ||
| discordStrat = new DiscordStrategy({ | ||
| clientID: config.discord.id, | ||
| clientSecret: config.discord.clientSecret, | ||
| callbackURL: config.discord.callback, | ||
| }, | ||
| (accessToken, refreshToken, profile, done) => { | ||
| profile.refreshToken = refreshToken; | ||
| redisPub.publish(config.devConfig.instanceName || "dbots.io", cJSON.stringify({ req: "newJoinOAuthInviteRequest", access_token: accessToken, id: profile.id }), err => { | ||
| if (!err) { console.info("NOTIF - Asking bot to join new user to dbots.io guild."); } else { console.error(`An error has occoured, ${err}`); console.debug(`Error Stacktrace: ${err.stack}`); } | ||
| }); | ||
| process.nextTick(() => done(null, profile)); | ||
| }); | ||
|
|
||
| redisSub.subscribe(config.devConfig.instanceName || "dbots.io"); | ||
| app.set("views", path.join(__dirname, "views")); | ||
| app.set("view engine", "ejs"); | ||
| app.use(bodyParser.json()); | ||
| app.use(bodyParser.urlencoded({ extended: false })); | ||
| app.use(cookieParser()); | ||
| app.use(csrf({ cookie: true })); | ||
| app.enable("trust proxy"); | ||
| app.use(compression({ filter: function (req, res) { | ||
| if (req.headers["x-no-compression"]) { | ||
| return false; | ||
| } | ||
| return compression.filter(req, res); | ||
| } })); | ||
| app.use("/", express.static(`${__dirname}/static`)); | ||
| app.use("/nm", express.static(path.join(__dirname, "../../../node_modules"))); | ||
| app.use(favicon(`${__dirname}/static/img/favicon.ico`)); | ||
| app.use(require("morgan")(`${":method".bold} ${":url".italic} :response-time ~ [:remote-addr :remote-user]`, { stream: console.stream })); | ||
| //serverUtils.createSecret().then(s =>{ | ||
| app.use(session({ | ||
| store: new connectRedis({ client: redisInstance }), | ||
| genid: function () { | ||
| return uuid.v4(); | ||
| }, | ||
|
|
||
| name: "session", | ||
| secret: /*s*/ config.discord.secret, | ||
| resave: false, | ||
| saveUninitialized: false, | ||
| })); | ||
| //}) | ||
| app.use(helmet(constants.web.helmet.CONFIG)); | ||
| app.use((req, res, next) => { | ||
| res.setHeader("X-Powered-By", "Magic"); | ||
| next(); | ||
| }); | ||
| passportRefresh.use(discordStrat); | ||
| passport.use(discordStrat); | ||
| passport.serializeUser((user, done) => { | ||
| done(null, user); | ||
| }); | ||
| passport.deserializeUser((id, done) => { | ||
| done(null, id); | ||
| }); | ||
| app.use(passport.initialize()); | ||
| app.use(passport.session()); | ||
|
|
||
| fs.readdir(path.join(__dirname, "./serverModules/routers"), (err, files) => { | ||
| let count = 0; | ||
| files.forEach(file => { | ||
| loadedFiles = files; | ||
| app.use(require(`./serverModules/routers/${file}`)); | ||
| count++; | ||
| }); | ||
| console.info(`Succesfuly loaded ${count} router files!`); | ||
| app.use((req, res, next) => { | ||
| res.status(404).render("error", { title: "Error", location: "error", code: 404, msg: "Not Found", req, res }); | ||
| }); | ||
| app.use((err, req, res, next) => { | ||
| console.error(err); | ||
| if (err) { | ||
| res.status(500).render("error", { title: "Error", location: "error", code: 500, msg: "Internal Server Error", req, res }); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| // Broadcasts data saying that the webserver is ready | ||
| Utils.workerReady("web"); | ||
|
|
||
| // Start listenng on the defined port, or default to 8081 | ||
| httpServer.listen(config.port || 8081, err => { | ||
| if (err) { | ||
| console.crit("Failed to bind webserver to port", { err_name: err.name, err_message: err.message }); | ||
|
|
||
| return console.debug("Worker stack trace: ", { stack: err.stack }); | ||
| } | ||
| console.info(`Successfully started server...listening on port ${config.port || 8081}`); | ||
| }); | ||
| }; |
| @@ -0,0 +1,118 @@ | ||
| /** | ||
| * Dependencies | ||
| */ | ||
| var OAuth2Strategy = require("passport-oauth2"), | ||
| InternalOAuthError = require("passport-oauth2").InternalOAuthError, | ||
| util = require("util"); | ||
|
|
||
| let self = null; | ||
|
|
||
| /** | ||
| * `Strategy` constructor. | ||
| * | ||
| * The Discord authentication strategy authenticates requests by delegating to | ||
| * Discord via the OAuth2.0 protocol | ||
| * | ||
| * Applications must supply a `verify` callback which accepts an `accessToken`, | ||
| * `refreshToken` and service-specific `profile`, and then calls the `cb` | ||
| * callback supplying a `user`, which should be set to `false` if the | ||
| * credentials are not valid. If an exception occured, `err` should be set. | ||
| * | ||
| * Options: | ||
| * - `clientID` OAuth ID to discord | ||
| * - `clientSecret` OAuth Secret to verify client to discord | ||
| * - `callbackURL` URL that discord will redirect to after auth | ||
| * - `scope` Array of permission scopes to request | ||
| * Valid discord scopes include: 'identity', 'email', 'connections', 'guilds', 'guilds.join' | ||
| * | ||
| * @constructor | ||
| * @param {object} options | ||
| * @param {function} verify | ||
| * @access public | ||
| */ | ||
| function Strategy (options, verify) { | ||
| options = options || {}; | ||
| options.authorizationURL = options.authorizationURL || "https://discordapp.com/api/oauth2/authorize"; | ||
| options.tokenURL = options.tokenURL || "https://discordapp.com/api/oauth2/token"; | ||
| options.scopeSeparator = options.scopeSeparator || " "; | ||
|
|
||
| this.options = options; | ||
|
|
||
| self = this; | ||
|
|
||
| OAuth2Strategy.call(this, options, verify); | ||
| this.name = "discord"; | ||
| this._oauth2.useAuthorizationHeaderforGET(true); | ||
| } | ||
|
|
||
| /** | ||
| * Inherits from `OAuth2Strategy` | ||
| */ | ||
| util.inherits(Strategy, OAuth2Strategy); | ||
|
|
||
| /** | ||
| * Retrieve user profile from Discord. | ||
| * | ||
| * This function constructs a normalized profile, with the following properties: | ||
| * | ||
| * - `something` ayy lmao | ||
| * | ||
| * @param {string} accessToken | ||
| * @param {function} done | ||
| * @access protected | ||
| */ | ||
| Strategy.prototype.userProfile = function (accessToken, done) { | ||
| let self = this; | ||
| this._oauth2.get("https://discordapp.com/api/users/@me", accessToken, (err, body, res) => { | ||
| if (err) { | ||
| return done(new InternalOAuthError("Failed to fetch the user profile.", err)); | ||
| } | ||
|
|
||
| let profile = JSON.parse(body); | ||
| profile.provider = "discord"; | ||
|
|
||
| self.checkScope("connections", accessToken, (errx, connections) => { | ||
| if (errx) done(errx); | ||
| if (connections) profile.connections = connections; | ||
| self.checkScope("guilds", accessToken, (erry, guilds) => { | ||
| if (erry) done(erry); | ||
| if (guilds) profile.guilds = guilds; | ||
|
|
||
| return done(null, profile); | ||
| }); | ||
| }); | ||
| }); | ||
| }; | ||
|
|
||
| Strategy.prototype.checkScope = function (scope, accessToken, cb) { | ||
| if (self.options.scopes && self.options.scopes.indexOf(scope) !== -1) { | ||
| this._oauth2.get(`https://discordapp.com/api/users/@me/${scope}`, accessToken, (err, body, res) => { | ||
| if (err) return cb(new InternalOAuthError(`Failed to fetch user's ${scope}`, err)); | ||
|
|
||
| cb(null, JSON.parse(body)); | ||
| }); | ||
| } else { | ||
| cb(null, null); | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * Return extra parameters to be included in the authorization request. | ||
| * | ||
| * @param {Object} options | ||
| * @return {Object} | ||
| * @api protected | ||
| */ | ||
| Strategy.prototype.authorizationParams = function (options) { | ||
| let params = {}; | ||
| if (typeof options.permissions !== "undefined") { | ||
| params.permissions = options.permissions; | ||
| } | ||
| return params; | ||
| }; | ||
|
|
||
|
|
||
| /** | ||
| * Expose `Strategy`. | ||
| */ | ||
| module.exports = Strategy; |
| @@ -0,0 +1,13 @@ | ||
| // Setting up | ||
| const express = require("express"); | ||
| const app = express.Router(); | ||
|
|
||
| app.get("/", async (req, res) => { | ||
| res.render("index", { location: "index", title: "Home", req, res }); | ||
| }); | ||
|
|
||
| module.exports = app; | ||
|
|
||
| module.exports.info = { | ||
| name: "Home", | ||
| }; |
| @@ -0,0 +1,18 @@ | ||
| // Setting up | ||
| const express = require("express"); | ||
| const app = express.Router(); | ||
| const passport = require("passport"); | ||
|
|
||
| app.get("/login", passport.authenticate("discord", { scope: ["identify", "email", "guilds.join"], failureRedirect: "/" }), (req, res) => { | ||
| res.redirect("/"); | ||
| }); | ||
|
|
||
| app.get("/login/callback", passport.authenticate("discord", { failureRedirect: "/" }), (req, res) => { | ||
| res.redirect("/"); | ||
| }); | ||
|
|
||
| module.exports = app; | ||
|
|
||
| module.exports.info = { | ||
| name: "Login", | ||
| }; |
| @@ -0,0 +1,14 @@ | ||
| // Setting up | ||
| const express = require("express"); | ||
| const app = express.Router(); | ||
|
|
||
| app.get("/logout", async (req, res) => { | ||
| req.session.destroy(); | ||
| res.redirect("/"); | ||
| }); | ||
|
|
||
| module.exports = app; | ||
|
|
||
| module.exports.info = { | ||
| name: "Logout", | ||
| }; |
| @@ -0,0 +1,359 @@ | ||
| @import url("https://fonts.googleapis.com/css?family=Montserrat:400,700|Raleway:400,700|Cabin:500|Nunito+Sans:400,700|Nunito:400,700"); | ||
|
|
||
| .gradient-red .error-line { | ||
| color: #fff !important; | ||
| } | ||
| body { | ||
| margin: 0; | ||
| padding: 0; | ||
| } | ||
| a.credits { | ||
| color: #fff; | ||
| transition: ease-out 250ms; | ||
| } | ||
| .text-bold { | ||
| font-weight: 700 !important; | ||
| } | ||
| .text-regular { | ||
| font-weight: 400 !important; | ||
| } | ||
| .static-white h2.subtitle.has-text-white strong { | ||
| color: #000 !important; | ||
| } | ||
| h2.subtitle.has-text-white strong { | ||
| color: #fff !important; | ||
| } | ||
| h1.title.montserrat.has-text-white span { | ||
| font-weight: 400; | ||
| } | ||
| .montserrat { | ||
| font-family: "Montserrat", sans-serif; | ||
| } | ||
| .cabin { | ||
| font-family: "Cabin", sans-serif; | ||
| } | ||
| .nunito-sans { | ||
| font-family: "Nunito Sans", sans-serif; | ||
| } | ||
| .nunito { | ||
| font-family: "Nunito", sans-serif; | ||
| } | ||
| .nunito-sans * { | ||
| font-family: "Nunito Sans", sans-serif; | ||
| } | ||
| .nunito * { | ||
| font-family: "Nunito", sans-serif; | ||
| } | ||
| .montserrat * { | ||
| font-family: "Montserrat", sans-serif; | ||
|
|
||
| } | ||
| .cabin * { | ||
| font-family: "Cabin", sans-serif; | ||
| } | ||
| .self-clear:after { | ||
| content: ""; | ||
| clear: both; | ||
| display: table; | ||
| } | ||
| .box-blue { | ||
| /*border-radius: 7px;*/ | ||
| background: rgba(0,0,0,0.09); | ||
| color: #fff !important; | ||
| padding: 20px; | ||
| display: block; | ||
| } | ||
| span.box-blue { | ||
| margin-bottom: 20px; | ||
| } | ||
| .is-circle { | ||
| border-radius: 50%; | ||
| } | ||
| .box-blue * { | ||
| color: #fff !important; | ||
| } | ||
| .front-container { | ||
| text-align: center; | ||
| } | ||
| .front-container span.inline { | ||
| display: inline-block; | ||
| } | ||
| .front-image { | ||
| display: inline-block; | ||
| vertical-align: top; | ||
| } | ||
| .navbar-brand .navbar-item *, .montserrat { | ||
| font-family: "Montserrat", sans-serif; | ||
| } | ||
| .navbar-end .navbar-item a p, .navbar-end .navbar-item a p span, .cabin { | ||
| font-family: "Cabin", sans-serif; | ||
| font-weight: 500; | ||
| } | ||
| *, .raleway { | ||
| font-family: "Raleway", sans-serif; | ||
| } | ||
| .navbar-burger { | ||
| color: #fff; | ||
| } | ||
| .navbar-burger:hover { | ||
| background-color: rgba(0,0,0,0%); | ||
| } | ||
| .navbar,.navbar-menu { | ||
| box-shadow: none; | ||
| } | ||
| .no-overflow { | ||
| overflow: hidden; | ||
| } | ||
| .theme-modal-content { | ||
| max-width: 800px; | ||
| padding: 0px; | ||
| } | ||
| .theme-modal-content .column { | ||
| padding: 0px; | ||
| } | ||
| .theme-modal-content .columns { | ||
| margin: 0px; | ||
| } | ||
| .theme-modal-column { | ||
| padding: 20px; | ||
| } | ||
| .theme-button { | ||
| border-radius: 0px; | ||
| margin-bottom: 20px; | ||
| border: none; | ||
| background-color: rgba(0,0,0,0.09); | ||
| color: #fff; | ||
| } | ||
| .theme-button:hover { | ||
| color: #fff; | ||
| } | ||
| .media.devs { | ||
| min-height: 128px; | ||
| } | ||
| .navbar { | ||
| transition: 120ms linear; | ||
| border-top: 2px solid #fff; | ||
| } | ||
| .static-white .navbar { | ||
| border-color: #000; | ||
| } | ||
| .navbar.transparent { | ||
| background: none; | ||
| } | ||
| .footer-darkened { | ||
| padding: 50px 0px; | ||
| background: rgba(0,0,0,0.09); | ||
| } | ||
| .gradient-blue { | ||
| background: linear-gradient(to right, rgb(90, 183, 255), rgb(104, 220, 255)); | ||
| } | ||
| .gradient-red { | ||
| background: linear-gradient(to right, crimson, brown); | ||
| } | ||
| .static-blue { | ||
| background: #5ab7ff; | ||
| } | ||
| .static-purple { | ||
| background: #483d8b; | ||
| } | ||
| .static-cyan { | ||
| background: #008b8b; | ||
| } | ||
| .static-red { | ||
| background: #ba3030; | ||
| } | ||
| .static-blurple { | ||
| background: #7289da; | ||
| } | ||
| .static-dark { | ||
| background: #23272a; | ||
| } | ||
| .static-orange { | ||
| background: #ff6347; | ||
| } | ||
| .static-sand { | ||
| background: #d2b48c; | ||
| } | ||
| .static-slate { | ||
| background: #2f4f4f; | ||
| } | ||
| .static-green { | ||
| background: #9acd32; | ||
| } | ||
| .static-gray { | ||
| background: #708090; | ||
| } | ||
| .static-brown { | ||
| background: #a0522d; | ||
| } | ||
| .static-white { | ||
| background: #fff; | ||
| } | ||
| .static-white * { | ||
| color: #000 !important; | ||
| } | ||
| .static-white .dropdown-item a:hover { | ||
| color: #666 !important; | ||
| } | ||
| .static-white * strong { | ||
| color: #000 !important; | ||
| } | ||
| .static-black { | ||
| background: #000; | ||
| } | ||
| .error-line { | ||
| line-height: 1.20; | ||
| } | ||
| .font-regular { | ||
| font-weight: 400 !important; | ||
| } | ||
| .unselectable { | ||
| -moz-user-select: none; | ||
| -webkit-user-select: none; | ||
| user-select: none; | ||
| } | ||
| @media screen and (max-width: 1024px) { | ||
| #navMenuMain { | ||
| display: none; | ||
| } | ||
| .navbar-end .navbar-item.has-dropdown .navbar-dropdown .navbar-item { | ||
| padding-left: 16px; | ||
| } | ||
| .text-giant { | ||
| font-size: 386%; | ||
| font-weight: 700; | ||
| } | ||
| .text-medium { | ||
| font-size: 144%; | ||
| font-weight: 700; | ||
| } | ||
| } | ||
| @media screen and (min-width: 768px) { | ||
| .front-text { | ||
| font-size: 4.4em; | ||
| } | ||
| .front-container span { | ||
| text-align: left; | ||
| } | ||
| .front-image { | ||
| width: 111px; | ||
| margin-right: 10px; | ||
| } | ||
| } | ||
| @media screen and (max-width: 768px) { | ||
| .front-text { | ||
| font-size: calc(130% + 35px); | ||
| } | ||
| .front-image { | ||
| max-width: 328px; | ||
| width: 90%; | ||
| display: block; | ||
| margin: auto; | ||
| } | ||
| } | ||
| @media screen and (min-width: 620px) { | ||
| figure.mobile-dev-image { | ||
| display: none; | ||
| } | ||
| } | ||
| @media screen and (max-width: 620px) { | ||
| .media.devs .media-left, .media.devs .media-right { | ||
| margin-left: 0px; | ||
| width: 0px; | ||
| display: none; | ||
| } | ||
| .box-blue.devs { | ||
| width: 100%; | ||
| } | ||
| figure.mobile-dev-image { | ||
| display: block; | ||
| margin-bottom: 20px; | ||
| } | ||
| img.mobile-dev-image { | ||
| margin: auto; | ||
| max-width: 154px; | ||
| display: block; | ||
| } | ||
| } | ||
| @media screen and (min-width: 1024px) { | ||
| .navbar-end .navbar-item.has-dropdown .navbar-dropdown { | ||
| background-color: rgba(0,0,0,0.09); | ||
| border-radius: 0px; | ||
| padding: 0px; | ||
| border-top: none; | ||
| box-shadow: none; | ||
| } | ||
| .navbar-menu { | ||
| background: none; | ||
| } | ||
| .navbar { | ||
| padding: 16px 0px; | ||
| } | ||
| .text-giant { | ||
| font-size: 100px; | ||
| font-weight: 700; | ||
| } | ||
| .text-medium { | ||
| font-size: 36px; | ||
| font-weight: 700; | ||
| } | ||
| .center-error { | ||
| position: absolute; | ||
| left: 50%; | ||
| top: 50%; | ||
| transform: translate(-40%, -70%); | ||
| } | ||
| } | ||
| div.navbar-brand p { | ||
| color: #fff; | ||
| font-size: 24px; | ||
| } | ||
| .navbar-end .navbar-item { | ||
| padding: 0; | ||
| } | ||
| .navbar-end .navbar-item a { | ||
| padding: 8px 16px; | ||
| width: 100%; | ||
| height: 100%; | ||
| display: inline-block; | ||
| } | ||
| .navbar-end .navbar-item a p { | ||
| line-height: 36px; | ||
| } | ||
| .navbar-end .navbar-item * { | ||
| color: #fff; | ||
| } | ||
| .navbar-end .navbar-item:hover * { | ||
| background-color: rgba(0,0,0,0); | ||
| } | ||
| .navbar-end .navbar-item:hover { | ||
| background-color: rgba(0,0,0,0.09) | ||
| } | ||
| .theme-modal-content *:not(.has-text-black) { | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .navbar-item { | ||
| transition: ease-out 250ms; | ||
| font-weight: 500; | ||
| } | ||
|
|
||
| a.credits.white { | ||
| color: #fff !important; | ||
| transition: ease-out 250ms; | ||
| } | ||
|
|
||
| a.credits.white:hover { | ||
| color: #3273dc !important; | ||
| transition: ease-out 250ms; | ||
| } | ||
|
|
||
| a.credits.black { | ||
| color: black !important; | ||
| transition: ease-out 250ms; | ||
| } | ||
|
|
||
| a.credits.black:hover { | ||
| color: #3273dc !important; | ||
| transition: ease-out 250ms; | ||
| } |
| @@ -0,0 +1,65 @@ | ||
| /* eslint-disable */ | ||
|
|
||
| /** | ||
| * Navbar Code | ||
| */ | ||
|
|
||
| window.onload = () => { | ||
| wRs(); | ||
| /* If ($(document).width() < 1024) { | ||
| $("#navMenuMain").hide() | ||
| }*/ | ||
| if (authenticated) { | ||
| $("#navUserToggle").hover(() => { | ||
| $("#navUserToggle").addClass("is-active"); | ||
| }, () => { | ||
| $("#navUserToggle").removeClass("is-active"); | ||
| }); | ||
| } | ||
| if (transparent) { | ||
| $(window).on("scroll", () => { | ||
| if ($(window).scrollTop() > 60) { | ||
| $("#navMenu").removeClass("transparent"); | ||
| } else { | ||
| $("#navMenu").addClass("transparent"); | ||
| } | ||
| }); | ||
| } | ||
| $(window).on("scroll", () => { | ||
| if ($(window).scrollTop() > 60) { | ||
| if ($(window).width() >= 1024) { | ||
| $("#navMenu").css("padding", "0px"); | ||
| } | ||
| } else if ($(window).width() > 1024) { | ||
| $("#navMenu").css("padding", "16px"); | ||
| } | ||
| }); | ||
| $(window).resize(() => wRs()); | ||
| function wRs () { | ||
| if ($(window).width() < 1024) { | ||
| $("#navMenu").css("padding", "0px"); | ||
| $("#navMenuMain").hide(); | ||
| } | ||
| if ($(window).width() >= 1024) { | ||
| $("#navMenuMain").show(); | ||
| if ($(window).scrollTop() < 60) { | ||
| $("#navMenu").css("padding", "16px"); | ||
| } else { | ||
| $("#navMenu").css("padding", "0px"); | ||
| } | ||
| } | ||
| } | ||
| $("#navMenuToggle").click(() => { | ||
| $("#navMenuToggle").toggleClass("is-active"); | ||
| $("#navMenuMain").slideToggle(86); | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * Theme/Cookies Code | ||
| */ | ||
|
|
||
| function setTheme (theme) { | ||
| Cookies.set("theme", theme); | ||
| window.location = window.location; | ||
| } |