mirror of
https://github.com/aurora-dot/pastel.codes.git
synced 2024-11-24 00:52:19 +00:00
Add linting, formatting and pre-commit (#53)
* Add dev-dependancies * Security update npm packages * Force audit fix * Add linting, formatting and precommit * Format files
This commit is contained in:
parent
80813d48e3
commit
8449b30401
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[pug.ts]
|
||||||
|
indent_size = 4
|
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": ["prettier"]
|
||||||
|
}
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx lint-staged
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"semi": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"]
|
||||||
|
}
|
70
app.js
70
app.js
@ -4,7 +4,7 @@ var path = require('path');
|
|||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
var mLogger = require('morgan');
|
var mLogger = require('morgan');
|
||||||
var logger = require('./config/winston');
|
var logger = require('./config/winston');
|
||||||
const helmet = require("helmet");
|
const helmet = require('helmet');
|
||||||
|
|
||||||
var indexRouter = require('./routes/index');
|
var indexRouter = require('./routes/index');
|
||||||
var aboutRouter = require('./routes/about');
|
var aboutRouter = require('./routes/about');
|
||||||
@ -12,7 +12,8 @@ var contactRouter = require('./routes/contact');
|
|||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
if (process.env.IS_DOCKER != 'true') app.set('trust proxy', 'loopback,uniquelocal');
|
if (process.env.IS_DOCKER != 'true')
|
||||||
|
app.set('trust proxy', 'loopback,uniquelocal');
|
||||||
app.disable('x-powered-by');
|
app.disable('x-powered-by');
|
||||||
|
|
||||||
// view engine setup
|
// view engine setup
|
||||||
@ -20,26 +21,43 @@ app.set('views', path.join(__dirname, 'views'));
|
|||||||
app.set('view engine', 'pug');
|
app.set('view engine', 'pug');
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
app.use(mLogger("common", { "stream": logger.stream }));
|
app.use(mLogger('common', { stream: logger.stream }));
|
||||||
} else {
|
} else {
|
||||||
app.use(mLogger('dev'));
|
app.use(mLogger('dev'));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(helmet());
|
app.use(helmet());
|
||||||
app.use(
|
app.use(
|
||||||
helmet.contentSecurityPolicy({
|
helmet.contentSecurityPolicy({
|
||||||
directives: {
|
directives: {
|
||||||
defaultSrc: ["'self'"],
|
defaultSrc: ["'self'"],
|
||||||
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://hcaptcha.com", "https://*.hcaptcha.com", "https://cdn.ravenjs.com/"],
|
scriptSrc: [
|
||||||
imgSrc: ["'self'", "https://blog.pastel.codes", "https://static.ghost.org", "https://secure.gravatar.com"],
|
"'self'",
|
||||||
styleSrc: ["'self'", "'unsafe-inline'", "https://hcaptcha.com", "https://*.hcaptcha.com"],
|
"'unsafe-inline'",
|
||||||
fontSrc: ["'self'", "data:"],
|
"'unsafe-eval'",
|
||||||
frameSrc: ["https://hcaptcha.com", "https://*.hcaptcha.com"],
|
'https://hcaptcha.com',
|
||||||
objectSrc: ["'none'"],
|
'https://*.hcaptcha.com',
|
||||||
upgradeInsecureRequests: [],
|
'https://cdn.ravenjs.com/',
|
||||||
},
|
],
|
||||||
})
|
imgSrc: [
|
||||||
);
|
"'self'",
|
||||||
|
'https://blog.pastel.codes',
|
||||||
|
'https://static.ghost.org',
|
||||||
|
'https://secure.gravatar.com',
|
||||||
|
],
|
||||||
|
styleSrc: [
|
||||||
|
"'self'",
|
||||||
|
"'unsafe-inline'",
|
||||||
|
'https://hcaptcha.com',
|
||||||
|
'https://*.hcaptcha.com',
|
||||||
|
],
|
||||||
|
fontSrc: ["'self'", 'data:'],
|
||||||
|
frameSrc: ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
||||||
|
objectSrc: ["'none'"],
|
||||||
|
upgradeInsecureRequests: [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
@ -51,19 +69,19 @@ app.use('/about', aboutRouter);
|
|||||||
app.use('/contact', contactRouter);
|
app.use('/contact', contactRouter);
|
||||||
|
|
||||||
// catch 404 and forward to error handler
|
// catch 404 and forward to error handler
|
||||||
app.use(function(req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
next(createError(404));
|
next(createError(404));
|
||||||
});
|
});
|
||||||
|
|
||||||
// error handler
|
// error handler
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function (err, req, res, _next) {
|
||||||
// set locals, only providing error in development
|
// set locals, only providing error in development
|
||||||
res.locals.message = err.message;
|
res.locals.message = err.message;
|
||||||
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
||||||
|
|
||||||
// render the error page
|
// render the error page
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
res.render('error', { title: 'Error', description: "Error" });
|
res.render('error', { title: 'Error', description: 'Error' });
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
64
bin/www
64
bin/www
@ -35,19 +35,19 @@ server.on('listening', onListening);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function normalizePort(val) {
|
function normalizePort(val) {
|
||||||
var port = parseInt(val, 10);
|
var port = parseInt(val, 10);
|
||||||
|
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
// named pipe
|
// named pipe
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port >= 0) {
|
if (port >= 0) {
|
||||||
// port number
|
// port number
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,27 +55,25 @@ function normalizePort(val) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function onError(error) {
|
function onError(error) {
|
||||||
if (error.syscall !== 'listen') {
|
if (error.syscall !== 'listen') {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bind = typeof port === 'string'
|
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
||||||
? 'Pipe ' + port
|
|
||||||
: 'Port ' + port;
|
|
||||||
|
|
||||||
// handle specific listen errors with friendly messages
|
// handle specific listen errors with friendly messages
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case 'EACCES':
|
case 'EACCES':
|
||||||
console.error(bind + ' requires elevated privileges');
|
console.error(bind + ' requires elevated privileges');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
case 'EADDRINUSE':
|
case 'EADDRINUSE':
|
||||||
console.error(bind + ' is already in use');
|
console.error(bind + ' is already in use');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,9 +81,7 @@ function onError(error) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function onListening() {
|
function onListening() {
|
||||||
var addr = server.address();
|
var addr = server.address();
|
||||||
var bind = typeof addr === 'string'
|
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
|
||||||
? 'pipe ' + addr
|
debug('Listening on ' + bind);
|
||||||
: 'port ' + addr.port;
|
|
||||||
debug('Listening on ' + bind);
|
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,29 @@ var winston = require('winston');
|
|||||||
var appRoot = require('app-root-path');
|
var appRoot = require('app-root-path');
|
||||||
|
|
||||||
var logger = new winston.createLogger({
|
var logger = new winston.createLogger({
|
||||||
transports: [
|
transports: [
|
||||||
new winston.transports.File({
|
new winston.transports.File({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
filename: `${appRoot}/logs/app.log`,
|
filename: `${appRoot}/logs/app.log`,
|
||||||
handleExceptions: true,
|
handleExceptions: true,
|
||||||
json: true,
|
json: true,
|
||||||
maxsize: 5242880, //5MB
|
maxsize: 5242880, //5MB
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
colorize: false
|
colorize: false,
|
||||||
}),
|
}),
|
||||||
new winston.transports.Console({
|
new winston.transports.Console({
|
||||||
level: 'debug',
|
level: 'debug',
|
||||||
handleExceptions: true,
|
handleExceptions: true,
|
||||||
json: false,
|
json: false,
|
||||||
colorize: true
|
colorize: true,
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
exitOnError: false
|
exitOnError: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.stream = {
|
logger.stream = {
|
||||||
write: function(message, encoding){
|
write: function (message, _encoding) {
|
||||||
logger.info(message);
|
logger.info(message);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
module.exports = logger
|
module.exports = logger;
|
||||||
|
20
eslint.config.mjs
Normal file
20
eslint.config.mjs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import globals from 'globals';
|
||||||
|
import pluginJs from '@eslint/js';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{ files: ['**/*.js'], languageOptions: { sourceType: 'commonjs' } },
|
||||||
|
{ languageOptions: { globals: { ...globals.browser, ...globals.node } } },
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
5272
package-lock.json
generated
5272
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@ -12,14 +12,19 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"start": "npx nodemon ./bin/www -e js,pug,sass",
|
"dev": "npx nodemon ./bin/www -e js,pug,sass",
|
||||||
|
"start": "npx ./bin/www -e js,pug,sass",
|
||||||
"watch-tailwind": "npx npm-watch",
|
"watch-tailwind": "npx npm-watch",
|
||||||
"build-tailwind": "npx postcss src/tailwind.css -o public/stylesheets/style.css"
|
"build-tailwind": "npx postcss src/tailwind.css -o public/stylesheets/style.css",
|
||||||
|
"lint": "prettier --check . && eslint .",
|
||||||
|
"format": "prettier --write --ignore-path .gitignore .",
|
||||||
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sendgrid/mail": "^7.4.4",
|
"@sendgrid/mail": "^8.1.3",
|
||||||
"app-root-path": "^3.0.0",
|
"app-root-path": "^3.0.0",
|
||||||
"axios": "^0.21.3",
|
"autoprefixer": "^10.3.4",
|
||||||
|
"axios": "^1.6.8",
|
||||||
"cookie-parser": "^1.4.5",
|
"cookie-parser": "^1.4.5",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-rate-limit": "^5.2.6",
|
"express-rate-limit": "^5.2.6",
|
||||||
@ -28,12 +33,25 @@
|
|||||||
"http-errors": "^1.8.0",
|
"http-errors": "^1.8.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"nodemailer": "^6.6.1",
|
"nodemailer": "^6.6.1",
|
||||||
"pug": "^3.0.2",
|
|
||||||
"tailwind-hamburgers": "^1.1.1",
|
|
||||||
"winston": "^3.3.3",
|
|
||||||
"autoprefixer": "^10.3.4",
|
|
||||||
"npm-watch": "^0.11.0",
|
"npm-watch": "^0.11.0",
|
||||||
"postcss-cli": "^8.3.1",
|
"postcss-cli": "^8.3.1",
|
||||||
"tailwindcss": "^2.2.15"
|
"pug": "^3.0.2",
|
||||||
|
"tailwind-hamburgers": "^1.1.1",
|
||||||
|
"tailwindcss": "^2.2.15",
|
||||||
|
"winston": "^3.3.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.1.1",
|
||||||
|
"eslint": "^9.1.1",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"globals": "^15.1.0",
|
||||||
|
"husky": "^9.0.11",
|
||||||
|
"lint-staged": "^15.2.2",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.14"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.js": "eslint --cache --fix",
|
||||||
|
"*.{js,css,md,pug}": "prettier --write"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [require('tailwindcss'), require('autoprefixer')],
|
||||||
require('tailwindcss'),
|
};
|
||||||
require('autoprefixer')
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
@ -3,293 +3,289 @@ $black: #002234
|
|||||||
$green: #CDE7B0
|
$green: #CDE7B0
|
||||||
|
|
||||||
@font-face
|
@font-face
|
||||||
font-family: 'Titling Gothic FB'
|
font-family: 'Titling Gothic FB'
|
||||||
src: url("../fonts/TITLINGGOTHICFB-WIDE.OTF") format('opentype')
|
src: url("../fonts/TITLINGGOTHICFB-WIDE.OTF") format('opentype')
|
||||||
|
|
||||||
@font-face
|
@font-face
|
||||||
font-family: 'Gilroy'
|
font-family: 'Gilroy'
|
||||||
src: url("../fonts/Gilroy-ExtraBold.otf") format('opentype')
|
src: url("../fonts/Gilroy-ExtraBold.otf") format('opentype')
|
||||||
|
|
||||||
@font-face
|
@font-face
|
||||||
font-family: 'Apercu Mono'
|
font-family: 'Apercu Mono'
|
||||||
src: url("../fonts/ApercuMono.ttf") format('truetype')
|
src: url("../fonts/ApercuMono.ttf") format('truetype')
|
||||||
|
|
||||||
html, body
|
html, body
|
||||||
width: 100%
|
width: 100%
|
||||||
height: 100%
|
height: 100%
|
||||||
|
|
||||||
body
|
body
|
||||||
background-color: $black
|
background-color: $black
|
||||||
color: $pink
|
color: $pink
|
||||||
|
|
||||||
h1
|
h1
|
||||||
font-family: "Gilroy", sans-serif
|
font-family: "Gilroy", sans-serif
|
||||||
|
|
||||||
h2
|
h2
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
font-family: "Apercu Mono", monospace
|
font-family: "Apercu Mono", monospace
|
||||||
|
|
||||||
p, label, input, textarea
|
p, label, input, textarea
|
||||||
font-family: "Apercu Mono", monospace
|
font-family: "Apercu Mono", monospace
|
||||||
|
|
||||||
label
|
label
|
||||||
font-size: 3vh
|
font-size: 3vh
|
||||||
|
|
||||||
a:hover
|
a:hover
|
||||||
color: $green
|
color: $green
|
||||||
|
|
||||||
article
|
article
|
||||||
min-height: 100%
|
min-height: 100%
|
||||||
display: grid
|
display: grid
|
||||||
grid-template-rows: auto 1fr auto
|
grid-template-rows: auto 1fr auto
|
||||||
grid-template-columns: 100%
|
grid-template-columns: 100%
|
||||||
|
|
||||||
header
|
header
|
||||||
nav
|
nav
|
||||||
a
|
a
|
||||||
span
|
span
|
||||||
font-size: 2rem
|
font-size: 2rem
|
||||||
font-family: 'Titling Gothic FB', sans-serif
|
font-family: 'Titling Gothic FB', sans-serif
|
||||||
color: $pink
|
color: $pink
|
||||||
|
|
||||||
#navbarSupportedContent23
|
#navbarSupportedContent23
|
||||||
ul
|
ul
|
||||||
background-color: $pink
|
background-color: $pink
|
||||||
li
|
li
|
||||||
transition: 0.5s
|
transition: 0.5s
|
||||||
background-color: $pink
|
background-color: $pink
|
||||||
text-align: center
|
text-align: center
|
||||||
a
|
a
|
||||||
span
|
span
|
||||||
transition: 0.2s
|
transition: 0.2s
|
||||||
color: $black
|
color: $black
|
||||||
font-family: "Apercu Mono", monospace
|
font-family: "Apercu Mono", monospace
|
||||||
|
|
||||||
li:hover
|
li:hover
|
||||||
background-color: $black
|
background-color: $black
|
||||||
a
|
a
|
||||||
span
|
span
|
||||||
color: $pink
|
color: $pink
|
||||||
|
|
||||||
.active
|
.active
|
||||||
background-color: $black
|
background-color: $black
|
||||||
a
|
a
|
||||||
span
|
span
|
||||||
color: $green
|
color: $green
|
||||||
|
|
||||||
.active:hover
|
.active:hover
|
||||||
background-color: $pink
|
background-color: $pink
|
||||||
a
|
a
|
||||||
span
|
span
|
||||||
color: $black
|
color: $black
|
||||||
main
|
main
|
||||||
padding: 0.5rem
|
padding: 0.5rem
|
||||||
h1
|
h1
|
||||||
padding-bottom: 1rem
|
padding-bottom: 1rem
|
||||||
font-size: 4.5rem
|
font-size: 4.5rem
|
||||||
span
|
span
|
||||||
text-decoration: underline $pink
|
text-decoration: underline $pink
|
||||||
text-decoration-style: wavy
|
text-decoration-style: wavy
|
||||||
p
|
p
|
||||||
font-size: 2rem
|
font-size: 2rem
|
||||||
margin-bottom: 5px
|
margin-bottom: 5px
|
||||||
|
|
||||||
|
|
||||||
footer
|
footer
|
||||||
text-align: center
|
text-align: center
|
||||||
font-size: 1rem
|
font-size: 1rem
|
||||||
padding: 0.5rem
|
padding: 0.5rem
|
||||||
a
|
a
|
||||||
color: $pink
|
color: $pink
|
||||||
text-decoration: underline $pink
|
text-decoration: underline $pink
|
||||||
|
|
||||||
.ef
|
.ef
|
||||||
max-height: 85vh
|
max-height: 85vh
|
||||||
min-height: 85vh !important
|
min-height: 85vh !important
|
||||||
|
|
||||||
.error
|
.error
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|
||||||
.pink-block
|
.pink-block
|
||||||
background-color: $pink
|
background-color: $pink
|
||||||
min-height: 100vh
|
min-height: 100vh
|
||||||
|
|
||||||
.center-v
|
.center-v
|
||||||
min-height: 100% /* Fallback for browsers do NOT support vh unit */
|
min-height: 100% /* Fallback for browsers do NOT support vh unit */
|
||||||
min-height: 100vh /* These two lines are counted as one :-) */
|
min-height: 100vh /* These two lines are counted as one :-) */
|
||||||
|
|
||||||
display: flex
|
display: flex
|
||||||
align-items: center
|
align-items: center
|
||||||
|
|
||||||
.center-v-h
|
.center-v-h
|
||||||
display: flex
|
display: flex
|
||||||
justify-content: center
|
justify-content: center
|
||||||
align-items: center
|
align-items: center
|
||||||
min-height: 100vh
|
min-height: 100vh
|
||||||
|
|
||||||
.logos-container
|
.logos-container
|
||||||
width: 3.5rem
|
width: 3.5rem
|
||||||
|
|
||||||
.logo
|
.logo
|
||||||
width: auto
|
width: auto
|
||||||
height: 3.5rem
|
height: 3.5rem
|
||||||
fill: $black
|
fill: $black
|
||||||
margin-bottom: 2.5rem
|
margin-bottom: 2.5rem
|
||||||
|
|
||||||
.logo-container
|
.logo-container
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
.about-pos
|
.about-pos
|
||||||
p
|
p
|
||||||
font-size: 3vh
|
font-size: 3vh
|
||||||
margin-bottom: 3vh
|
margin-bottom: 3vh
|
||||||
|
|
||||||
.pr
|
.pr
|
||||||
img
|
img
|
||||||
width: 100%
|
width: 100%
|
||||||
border: 2vh solid $pink
|
border: 2vh solid $pink
|
||||||
margin-bottom: 3vh
|
margin-bottom: 3vh
|
||||||
margin-top: 1vh
|
margin-top: 1vh
|
||||||
|
|
||||||
|
|
||||||
.pr-text
|
.pr-text
|
||||||
a
|
a
|
||||||
color: $pink
|
color: $pink
|
||||||
h1
|
h1
|
||||||
|
|
||||||
font-size: 4vh
|
font-size: 4vh
|
||||||
margin-bottom: 0
|
margin-bottom: 0
|
||||||
padding-bottom: 0
|
padding-bottom: 0
|
||||||
a:hover
|
a:hover
|
||||||
color: $green
|
color: $green
|
||||||
p
|
p
|
||||||
font-size: 3vh
|
font-size: 3vh
|
||||||
|
|
||||||
.start
|
.start
|
||||||
margin-top: 3vh
|
margin-top: 3vh
|
||||||
|
|
||||||
#contact-message
|
#contact-message
|
||||||
margin-top: 2vh
|
margin-top: 2vh
|
||||||
p
|
p
|
||||||
color: $green
|
color: $green
|
||||||
span
|
span
|
||||||
text-decoration: underline $green
|
text-decoration: underline $green
|
||||||
|
|
||||||
.h-captcha
|
.h-captcha
|
||||||
margin-bottom: 0.5vh
|
margin-bottom: 0.5vh
|
||||||
|
|
||||||
.button-c
|
.button-c
|
||||||
display: inline-block
|
display: inline-block
|
||||||
font-weight: 400
|
font-weight: 400
|
||||||
color: #212529
|
color: #212529
|
||||||
text-align: center
|
text-align: center
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
user-select: none
|
user-select: none
|
||||||
border: 1px solid $black
|
border: 1px solid $black
|
||||||
padding: 0.375rem 0.75rem
|
padding: 0.375rem 0.75rem
|
||||||
font-size: 1rem
|
font-size: 1rem
|
||||||
line-height: 1.5
|
line-height: 1.5
|
||||||
border-radius: 0.25rem
|
border-radius: 0.25rem
|
||||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out
|
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out
|
||||||
font-family: "Apercu Mono"
|
font-family: "Apercu Mono"
|
||||||
|
|
||||||
.button-c
|
.button-c
|
||||||
background-color: $pink
|
background-color: $pink
|
||||||
|
|
||||||
.button-c:hover
|
.button-c:hover
|
||||||
background-color: $black
|
background-color: $black
|
||||||
color: $pink
|
color: $pink
|
||||||
border-color: $pink
|
border-color: $pink
|
||||||
|
|
||||||
// Nav stuff
|
// Nav stuff
|
||||||
|
|
||||||
.ham
|
.ham
|
||||||
width: 30px
|
width: 30px
|
||||||
height: 20px
|
height: 20px
|
||||||
position: relative
|
position: relative
|
||||||
margin: 0px
|
margin: 0px
|
||||||
-webkit-transform: rotate(0deg)
|
-webkit-transform: rotate(0deg)
|
||||||
-moz-transform: rotate(0deg)
|
-moz-transform: rotate(0deg)
|
||||||
-o-transform: rotate(0deg)
|
-o-transform: rotate(0deg)
|
||||||
transform: rotate(0deg)
|
transform: rotate(0deg)
|
||||||
-webkit-transition: .5s ease-in-out
|
-webkit-transition: .5s ease-in-out
|
||||||
-moz-transition: .5s ease-in-out
|
-moz-transition: .5s ease-in-out
|
||||||
-o-transition: .5s ease-in-out
|
-o-transition: .5s ease-in-out
|
||||||
transition: .5s ease-in-out
|
transition: .5s ease-in-out
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
.ham span
|
.ham span
|
||||||
display: block
|
display: block
|
||||||
position: absolute
|
position: absolute
|
||||||
height: 3px
|
height: 3px
|
||||||
width: 100%
|
width: 100%
|
||||||
border-radius: 9px
|
border-radius: 9px
|
||||||
opacity: 1
|
opacity: 1
|
||||||
left: 0
|
left: 0
|
||||||
-webkit-transform: rotate(0deg)
|
-webkit-transform: rotate(0deg)
|
||||||
-moz-transform: rotate(0deg)
|
-moz-transform: rotate(0deg)
|
||||||
-o-transform: rotate(0deg)
|
-o-transform: rotate(0deg)
|
||||||
transform: rotate(0deg)
|
transform: rotate(0deg)
|
||||||
-webkit-transition: .25s ease-in-out
|
-webkit-transition: .25s ease-in-out
|
||||||
-moz-transition: .25s ease-in-out
|
-moz-transition: .25s ease-in-out
|
||||||
-o-transition: .25s ease-in-out
|
-o-transition: .25s ease-in-out
|
||||||
transition: .25s ease-in-out
|
transition: .25s ease-in-out
|
||||||
background: $pink
|
background: $pink
|
||||||
|
|
||||||
.ham span:nth-child(1)
|
.ham span:nth-child(1)
|
||||||
top: 0
|
top: 0
|
||||||
|
|
||||||
.ham span:nth-child(2), .ham span:nth-child(3)
|
.ham span:nth-child(2), .ham span:nth-child(3)
|
||||||
top: 10px
|
top: 10px
|
||||||
|
|
||||||
.ham span:nth-child(4)
|
.ham span:nth-child(4)
|
||||||
top: 20px
|
top: 20px
|
||||||
|
|
||||||
.ham.open span:nth-child(1)
|
.ham.open span:nth-child(1)
|
||||||
top: 11px
|
top: 11px
|
||||||
width: 0
|
width: 0
|
||||||
left: 50%
|
left: 50%
|
||||||
|
|
||||||
.ham.open span:nth-child(2)
|
.ham.open span:nth-child(2)
|
||||||
-webkit-transform: rotate(45deg)
|
-webkit-transform: rotate(45deg)
|
||||||
-moz-transform: rotate(45deg)
|
-moz-transform: rotate(45deg)
|
||||||
-o-transform: rotate(45deg)
|
-o-transform: rotate(45deg)
|
||||||
transform: rotate(45deg)
|
transform: rotate(45deg)
|
||||||
|
|
||||||
.ham.open span:nth-child(3)
|
.ham.open span:nth-child(3)
|
||||||
-webkit-transform: rotate(-45deg)
|
-webkit-transform: rotate(-45deg)
|
||||||
-moz-transform: rotate(-45deg)
|
-moz-transform: rotate(-45deg)
|
||||||
-o-transform: rotate(-45deg)
|
-o-transform: rotate(-45deg)
|
||||||
transform: rotate(-45deg)
|
transform: rotate(-45deg)
|
||||||
|
|
||||||
.ham.open span:nth-child(4)
|
.ham.open span:nth-child(4)
|
||||||
top: 11px
|
top: 11px
|
||||||
width: 0
|
width: 0
|
||||||
left: 50%
|
left: 50%
|
||||||
|
|
||||||
@media only screen and (max-height: 421px)
|
@media only screen and (max-height: 421px)
|
||||||
.pr-text
|
.pr-text
|
||||||
margin-bottom: 5vh !important
|
margin-bottom: 5vh !important
|
||||||
|
|
||||||
@media only screen and (max-width: 575px)
|
@media only screen and (max-width: 575px)
|
||||||
.logo
|
.logo
|
||||||
height: 5rem
|
height: 5rem
|
||||||
.logos-container
|
.logos-container
|
||||||
width: 5rem
|
width: 5rem
|
||||||
.aaa
|
.aaa
|
||||||
min-height: 40vh !important
|
min-height: 40vh !important
|
||||||
.aaaa
|
.aaaa
|
||||||
margin-top: 5vh !important
|
margin-top: 5vh !important
|
||||||
.ef
|
.ef
|
||||||
max-height: none !important
|
max-height: none !important
|
||||||
min-height: 0 !important
|
min-height: 0 !important
|
||||||
.ff
|
.ff
|
||||||
min-height: 82.8vh !important
|
min-height: 82.8vh !important
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-height: 815px)
|
@media only screen and (max-height: 815px)
|
||||||
.ef
|
.ef
|
||||||
max-height: none !important
|
max-height: none !important
|
||||||
min-height: 0 !important
|
min-height: 0 !important
|
||||||
|
|
||||||
|
@ -3,25 +3,35 @@ const axios = require('axios');
|
|||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/', function(req, res, next) {
|
router.get('/', function (req, res, _next) {
|
||||||
const GHOST_KEY = process.env.GHOST_KEY
|
const GHOST_KEY = process.env.GHOST_KEY;
|
||||||
const base_url = `https://blog.pastel.codes/ghost/api/v3/content/posts/?key=${GHOST_KEY}`
|
const base_url = `https://blog.pastel.codes/ghost/api/v3/content/posts/?key=${GHOST_KEY}`;
|
||||||
|
|
||||||
axios.all([
|
axios
|
||||||
axios.get(`${base_url}&limit=3`),
|
.all([
|
||||||
axios.get(`${base_url}&limit=3&filter=tag:project`),
|
axios.get(`${base_url}&limit=3`),
|
||||||
|
axios.get(`${base_url}&limit=3&filter=tag:project`),
|
||||||
])
|
])
|
||||||
.then(axios.spread((response1, response2) => {
|
.then(
|
||||||
var base = { title: 'About', description: 'Who??? What??? AAAAaaa, about me.'};
|
axios.spread((response1, response2) => {
|
||||||
var blog = JSON.parse(JSON.stringify(response1.data).split('"posts":').join('"blog":'));
|
var base = {
|
||||||
var projects = JSON.parse(JSON.stringify(response2.data).split('"posts":').join('"project":'));
|
title: 'About',
|
||||||
var out = Object.assign(base, blog, projects);
|
description: 'Who??? What??? AAAAaaa, about me.',
|
||||||
|
};
|
||||||
|
var blog = JSON.parse(
|
||||||
|
JSON.stringify(response1.data).split('"posts":').join('"blog":')
|
||||||
|
);
|
||||||
|
var projects = JSON.parse(
|
||||||
|
JSON.stringify(response2.data).split('"posts":').join('"project":')
|
||||||
|
);
|
||||||
|
var out = Object.assign(base, blog, projects);
|
||||||
|
|
||||||
res.render('about', out);
|
res.render('about', out);
|
||||||
}))
|
})
|
||||||
.catch(error => {
|
)
|
||||||
console.log(error);
|
.catch((error) => {
|
||||||
});
|
console.log(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -1,73 +1,80 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
var rate_limit = require("express-rate-limit")
|
var rate_limit = require('express-rate-limit');
|
||||||
const {verify} = require('hcaptcha');
|
const { verify } = require('hcaptcha');
|
||||||
const nodemailer = require('nodemailer')
|
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
|
||||||
const sgMail = require('@sendgrid/mail');
|
const sgMail = require('@sendgrid/mail');
|
||||||
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
|
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
|
||||||
|
|
||||||
const contact_rate_limit = rate_limit({
|
const contact_rate_limit = rate_limit({
|
||||||
windowMs: 10 * 60 * 1000, // 10 minutes
|
windowMs: 10 * 60 * 1000, // 10 minutes
|
||||||
max: 5, // limit each IP to 10 requests per windowMs
|
max: 5, // limit each IP to 10 requests per windowMs
|
||||||
message: "Too many contact requests, try again later.",
|
message: 'Too many contact requests, try again later.',
|
||||||
handler: function (req, res /*, next*/) {
|
handler: function (req, res /*, next*/) {
|
||||||
res.render('error', {
|
res.render('error', {
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
message: "Too many contact requests, try again later.",
|
message: 'Too many contact requests, try again later.',
|
||||||
error: {status: null}
|
error: { status: null },
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST route from contact form
|
// POST route from contact form
|
||||||
router.post('/', contact_rate_limit, (req, res) => {
|
router.post('/', contact_rate_limit, (req, res) => {
|
||||||
const TO_MAIL_USER = process.env.TO_MAIL_USER
|
const TO_MAIL_USER = process.env.TO_MAIL_USER;
|
||||||
const FROM_MAIL_USER = process.env.FROM_MAIL_USER
|
const FROM_MAIL_USER = process.env.FROM_MAIL_USER;
|
||||||
const HCAPTCHA_KEY = process.env.HCAPTCHA_KEY
|
const HCAPTCHA_KEY = process.env.HCAPTCHA_KEY;
|
||||||
const REPLY_TO_MAIL = process.env.REPLY_TO_MAIL
|
const REPLY_TO_MAIL = process.env.REPLY_TO_MAIL;
|
||||||
const token = req.body["g-recaptcha-response"];
|
const token = req.body['g-recaptcha-response'];
|
||||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||||
|
|
||||||
verify(HCAPTCHA_KEY, token)
|
verify(HCAPTCHA_KEY, token)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.success === true) {
|
if (data.success === true) {
|
||||||
const msg = {
|
const msg = {
|
||||||
to: TO_MAIL_USER,
|
to: TO_MAIL_USER,
|
||||||
from: FROM_MAIL_USER,
|
from: FROM_MAIL_USER,
|
||||||
subject: 'New message from contact form at pastel.codes',
|
subject: 'New message from contact form at pastel.codes',
|
||||||
text: `${req.body.firstname} ${req.body.lastname} (${req.body.email})\nsays: ${req.body.message}\n\nip: ${ip}`
|
text: `${req.body.firstname} ${req.body.lastname} (${req.body.email})\nsays: ${req.body.message}\n\nip: ${ip}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
sgMail
|
sgMail
|
||||||
.send(msg)
|
.send(msg)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.render('contact', {
|
res.render('contact', {
|
||||||
title: 'Contact',
|
title: 'Contact',
|
||||||
message: "I will get back to you soon!",
|
message: 'I will get back to you soon!',
|
||||||
success: "Make sure the email is from ",
|
success: 'Make sure the email is from ',
|
||||||
email: REPLY_TO_MAIL
|
email: REPLY_TO_MAIL,
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.log(error)
|
|
||||||
res.render('error', {title: 'Contact', message: "Email did not send"})
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// rerender with same info in the text box and show error message
|
|
||||||
res.render('contact', {title: 'Contact', message: "Captcha failed, try again"});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.render('contact', {title: 'Contact', message: "Something wrong happened, try again later"});
|
res.render('error', {
|
||||||
|
title: 'Contact',
|
||||||
|
message: 'Email did not send',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// rerender with same info in the text box and show error message
|
||||||
|
res.render('contact', {
|
||||||
|
title: 'Contact',
|
||||||
|
message: 'Captcha failed, try again',
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
res.render('contact', {
|
||||||
|
title: 'Contact',
|
||||||
|
message: 'Something wrong happened, try again later',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/', function (req, res, next) {
|
router.get('/', function (req, res, _next) {
|
||||||
res.render('contact', {title: 'Contact', description: "Contact me!"});
|
res.render('contact', { title: 'Contact', description: 'Contact me!' });
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -2,8 +2,8 @@ var express = require('express');
|
|||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/', function(req, res, next) {
|
router.get('/', function (req, res, _next) {
|
||||||
res.render('index', { title: 'Home', description: "Hello, I'm E" });
|
res.render('index', { title: 'Home', description: "Hello, I'm E" });
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Titling Gothic FB';
|
font-family: 'Titling Gothic FB';
|
||||||
src: url("../fonts/TITLINGGOTHICFB-WIDE.OTF") format('opentype')
|
src: url('../fonts/TITLINGGOTHICFB-WIDE.OTF') format('opentype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Gilroy';
|
font-family: 'Gilroy';
|
||||||
src: url("../fonts/Gilroy-ExtraBold.otf") format('opentype')
|
src: url('../fonts/Gilroy-ExtraBold.otf') format('opentype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Apercu Mono';
|
font-family: 'Apercu Mono';
|
||||||
src: url("../fonts/ApercuMono.ttf") format('truetype');
|
src: url('../fonts/ApercuMono.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.wavy {
|
.wavy {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-decoration-style: wavy;
|
text-decoration-style: wavy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
mode: "jit",
|
mode: 'jit',
|
||||||
purge: ['views/*.pug'],
|
purge: ['views/*.pug'],
|
||||||
darkMode: false, // or 'media' or 'class'
|
darkMode: false, // or 'media' or 'class'
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
'extra': ['"Titling Gothic FB"'],
|
extra: ['"Titling Gothic FB"'],
|
||||||
'sans': ['Gilroy'],
|
sans: ['Gilroy'],
|
||||||
'mono': ['"Apercu Mono"'],
|
mono: ['"Apercu Mono"'],
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
transparent: 'transparent',
|
transparent: 'transparent',
|
||||||
@ -20,14 +20,12 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
green: {
|
green: {
|
||||||
DEFAULT: '#CDE7B0',
|
DEFAULT: '#CDE7B0',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [require('tailwind-hamburgers')],
|
||||||
require('tailwind-hamburgers'),
|
};
|
||||||
],
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user