diff --git a/gulpfile.js b/gulpfile.js index 64d5e1f..4c0f9b1 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -31,7 +31,7 @@ gulp.task("serve_dev", (cb) => { gulp.task("serve", (cb) => { console.log('Launching node...'); - spawn('node', [, 'index.js'], {stdio: 'inherit'}) + spawn('node', ['index.js'], {stdio: 'inherit'}) cb(); }); diff --git a/helpers/view_loader.js b/helpers/view_loader.js index d1ef5c2..64c128f 100644 --- a/helpers/view_loader.js +++ b/helpers/view_loader.js @@ -1,6 +1,7 @@ const pug = require('pug'); -const fs = require('fs/promises'); +const fs = require('fs'); const glob = require('glob'); +const path = require('path'); const cwd = process.cwd(); const layoutdir = cwd + '/view'; @@ -14,17 +15,26 @@ async function loadFile(file) { } async function load(name, data) { + if (!(await exists(name))) + throw new Error("This view does not exist."); return (await loadFile(layoutdir + '/' + name))(data); } +async function exists(name) { + return fs.promises.access(layoutdir + '/' + name, fs.constants.R_OK) + .then(() => true) + .catch(() => false); +} + async function preload() { - await glob(layoutdir + '/**/*', (err, files) => { + await glob(layoutdir + '/**/*.pug', (err, files) => { files.filter(file => { - return !file.startsWith('.'); + return !file.startsWith('.') && + (!fs.lstatSync(file).isDirectory()) }).forEach(file => { loadFile(file); }); }); } -module.exports = { load, loadFile, preload } \ No newline at end of file +module.exports = { load, loadFile, preload, exists } \ No newline at end of file diff --git a/index.js b/index.js index d4ef49a..7021bed 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ const app = express(); const { APP_PORT } = process.env; app.use(require('./routes')); +app.use(express.static('public')) const server = app.listen(APP_PORT, () => { console.log("Listening on port " + APP_PORT); diff --git a/install b/install index 61e6333..3798f39 100755 --- a/install +++ b/install @@ -1,6 +1,6 @@ #!/bin/bash -PACKAGES="gulp-cli" +PACKAGES="gulp-cli gulper gulp" if [[ $APP_DEBUG == 'true' ]]; then npm i diff --git a/package.json b/package.json index 266fe56..d1aa79b 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,9 @@ "dotenv": "^16.0.3", "express": "^4.18.2", "glob": "^8.1.0", - "pug": "^3.0.2" + "pug": "^3.0.2", + "gulp": "^4.0.2" }, "devDependencies": { - "gulp": "^4.0.2" } } diff --git a/public/content/cuteschedule.png b/public/content/cuteschedule.png new file mode 100644 index 0000000..89c3cef Binary files /dev/null and b/public/content/cuteschedule.png differ diff --git a/public/content/vrplauncher.png b/public/content/vrplauncher.png new file mode 100644 index 0000000..b60cca0 Binary files /dev/null and b/public/content/vrplauncher.png differ diff --git a/public/content/winterredit.png b/public/content/winterredit.png new file mode 100644 index 0000000..1fd168b Binary files /dev/null and b/public/content/winterredit.png differ diff --git a/public/static/image/ui/back_button_1.png b/public/static/image/ui/back_button_1.png new file mode 100644 index 0000000..dfba1fb Binary files /dev/null and b/public/static/image/ui/back_button_1.png differ diff --git a/public/static/image/ui/back_button_2.png b/public/static/image/ui/back_button_2.png new file mode 100644 index 0000000..0f014a4 Binary files /dev/null and b/public/static/image/ui/back_button_2.png differ diff --git a/public/static/image/ui/back_button_3.png b/public/static/image/ui/back_button_3.png new file mode 100644 index 0000000..7a05f9d Binary files /dev/null and b/public/static/image/ui/back_button_3.png differ diff --git a/public/static/main.css b/public/static/main.css new file mode 100644 index 0000000..dece447 --- /dev/null +++ b/public/static/main.css @@ -0,0 +1,65 @@ +html { + background-color: #f2faea; +} + +body { + padding:0; + margin:0; + height:100%; + width:100%; + position:fixed; + top:0; + left:0; + font-family: 'Open Sans', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} +table.body_table, table.body_table th, table.body_table tr { + border: 1px solid gray +} +table.body_table { + width:100%; + border-collapse: collapse; +} +tr { + vertical-align: top; +} + +.side_menu { + width: 200px; + border-right: 1px solid #c2c4c2; + padding: 16px 12px; +} +.side_menu h1 { + font-size: 1.25em; + font-weight: 500; + padding-left: 3px; +} +a { + color: rgb(70, 92, 133) +} +a:visited { + color: rgb(55, 84, 138) +} +.side_menu ul { + list-style: none; + padding: 0; + font-size: 11pt; + padding-top: 32px; +} +.main_contents { + padding: 16px 12px; +} + +.flag_hr { + background: linear-gradient(0,#5BCEFA 20%,#F5A9B8 20%,40%,#FFFFFF 40%,60%,#F5A9B8 60%,80%,#5BCEFA 80%); + position: absolute; + left: 0px; + width: 226px; + height: 24px; + padding: 0; + margin: 0; +} + +hr { + border: 0; + border-bottom: 1px solid #C2C4C2; +} \ No newline at end of file diff --git a/public/static/ui/back_button.css b/public/static/ui/back_button.css new file mode 100644 index 0000000..07993d4 --- /dev/null +++ b/public/static/ui/back_button.css @@ -0,0 +1,30 @@ + +.back_button_1 { + box-shadow:inset 0px 1px 0px 0px #bee2f9; + background:linear-gradient(to bottom, #63b8ee 5%, #468ccf 100%); + background-color:#63b8ee; + border-radius:5px; + border:1px solid #3866a3; + display:inline-block; + cursor:pointer; + color:#14396a; + font-family:Arial; + font-size:11px; + font-weight:bold; + padding:3px 7px; + text-decoration:none; + text-shadow:0px 1px 0px #7cacde; + box-shadow: 1px 1px 2px #30303030; + margin:0 +} +.back_button_1:hover { + background:linear-gradient(to bottom, #468ccf 5%, #63b8ee 100%); + background-color:#468ccf; +} +.back_button_1:active { + position:relative; + top:1px; +} +.back_button_1::before { + content: '← go back' +} \ No newline at end of file diff --git a/routes/homepage.js b/routes/homepage.js index 52bd6d0..0749702 100644 --- a/routes/homepage.js +++ b/routes/homepage.js @@ -1,7 +1,15 @@ const Helpers = require('../helpers'); async function handler(req, res) { - res.send(await Helpers.ViewLoader.load('hi.pug')); + res.send( + await Helpers.ViewLoader.load( + 'main.pug', + { + current_route: '/' + } + ) + ); + return; } module.exports = (router) => { diff --git a/routes/proj.js b/routes/proj.js new file mode 100644 index 0000000..84da5ff --- /dev/null +++ b/routes/proj.js @@ -0,0 +1,44 @@ +const Helpers = require('../helpers'); + +async function handler(req, res) { + res.send( + await Helpers.ViewLoader.load( + 'project.pug', + { + current_route: '/' + } + ) + ); + return; +} + +async function viewer(req, res) { + const id = req.params.id; + const view = 'projects/' + id + '.pug'; + if (!(await Helpers.ViewLoader.exists(view))) { + res.status(404).send( + await Helpers.ViewLoader.load( + 'error.pug', + { + current_route: req.originalUrl, + error: '404 Not Found', + message: 'Requested project does not exists. Are you sure this is the valid link?' + } + ) + ); + return; + } + res.send( + await Helpers.ViewLoader.load( + view, + { + current_route: req.originalUrl + } + ) + ) +} + +module.exports = (router) => { + router.get('/project', handler); + router.get('/project/:id', viewer); +} \ No newline at end of file diff --git a/startup.js b/startup.js index ad58bd6..4fd6976 100644 --- a/startup.js +++ b/startup.js @@ -1,5 +1,9 @@ console.log('Executing startup jobs...'); +if (process.env.APP_DEBUG) { + process.env.DEBUG = '*/*'; +} + const fs = require('fs'); const hrt = () => { diff --git a/view/error.pug b/view/error.pug new file mode 100644 index 0000000..3dbcfbc --- /dev/null +++ b/view/error.pug @@ -0,0 +1,7 @@ +extends layout/main.pug +block root + - var title = error + +block content + h1(align='center')= error + p(align='center')= message \ No newline at end of file diff --git a/view/hi.pug b/view/hi.pug deleted file mode 100644 index 2dd9f5a..0000000 --- a/view/hi.pug +++ /dev/null @@ -1 +0,0 @@ -p hi \ No newline at end of file diff --git a/view/layout/main.pug b/view/layout/main.pug new file mode 100644 index 0000000..15ed973 --- /dev/null +++ b/view/layout/main.pug @@ -0,0 +1,36 @@ +block root + +- + let routes = { + "Main page": '/', + "Projects": "/project", + "About me": "/about" + } + +doctype html +html + head + title blek! Site #{title ? "- " + title : ""} + + link(rel='stylesheet' href='/static/main.css') + + block head + body + table(width='100%' height='100%' class='body_table') + tr + td(class='side_menu') + h1 + a(href='/') blek! Site + hr(class='flag_hr') + ul + each route, name in routes + li + if current_route == route + | > #{name} + else + a(href=route) #{name} + td(class='main_contents') + block content + block foot + block scripts + \ No newline at end of file diff --git a/view/layout/project.pug b/view/layout/project.pug new file mode 100644 index 0000000..f6e4578 --- /dev/null +++ b/view/layout/project.pug @@ -0,0 +1,9 @@ +extends main.pug + +block append head + + +block content + p(style='margin:0') + a(href='/project' title='go back to projects page' class='back_button_1') + hr \ No newline at end of file diff --git a/view/main.pug b/view/main.pug new file mode 100644 index 0000000..e4a045a --- /dev/null +++ b/view/main.pug @@ -0,0 +1,45 @@ +extends layout/main.pug +block root + - var title = 'Main page' +block content + // + h1(align='center') Welcome on my website! + p + | Hi there! My name is Alice and I like to build software. + hr + p + | Currently I am working on a college project (which is going to air in june) + br + | This website was built using Express.js + p + | Check out my + a(href='https://github.com/b1ek') GitHub page + | and my + a(href='/resume') resume + table(width='100%') + tr + td(width='20%') + h4 Guest book + | ( + a(href='/guestbook.rss') RSS + | ) + ul + li entry + li entry + li entry + li entry + li entry + a(href='/guestbook') Write something in my guestbook! + td(width='60%' style='border-left:1px solid #c2c4c2;border-right:1px solid #c2c4c2;padding:0 1%') + h3 Blog + ul + each i in [0,0,0,0,0] + li(style='font-size:16pt') + | entry + ul + li data + + td(width='20%') + h4 Links + a(href='https://cameronsworld.net') cameronsworld.net + a(href='https://') \ No newline at end of file diff --git a/view/project.pug b/view/project.pug new file mode 100644 index 0000000..d8130ac --- /dev/null +++ b/view/project.pug @@ -0,0 +1,27 @@ +extends layout/main.pug +block root + - var title = 'Projects' +block content + h2 My projects + + ul + li + a(href='/project/blek_sail') blek! Sail + li + a(href='/project/blek_id') blek! ID + li + a(href='/project/cuteschedule') CuteSchedule + li + a(href='/project/vrplauncher') VRPLauncher + + h2 Projects I participated in + + ul + li + a(href='/project/winterredit') WinTerrEdit + + h2 Planned projects + + ul + li blek! Analytics + li blek! Launcher \ No newline at end of file diff --git a/view/projects/blek_id.pug b/view/projects/blek_id.pug new file mode 100644 index 0000000..b97980e --- /dev/null +++ b/view/projects/blek_id.pug @@ -0,0 +1,10 @@ +extends ../layout/project.pug +block root + - var title = 'blek! Sail' + +block append content + h2 blek! ID + p + | blek! ID provides authentication functionality for all blek! Services. + br + | It was supposed to be something like OpenID Connect server, and perhaps you should use a production-ready implementation of this (like ory hydra) \ No newline at end of file diff --git a/view/projects/blek_sail.pug b/view/projects/blek_sail.pug new file mode 100644 index 0000000..e7ace68 --- /dev/null +++ b/view/projects/blek_sail.pug @@ -0,0 +1,16 @@ +extends ../layout/project.pug +block root + - var title = 'blek! Sail' + +block append content + h2 blek! Sail + p + | blek! Sail is a production-ready alternative to Laravel Sail. + br + | It runs on nginx + php-fpm on alpine linux + p + | Read the github + a(href='https://github.com/b1ek/sail') page + | for more info. + p + a(href='https://hub.docker.com/r/blekii/sail') Docker hub repo \ No newline at end of file diff --git a/view/projects/cuteschedule.pug b/view/projects/cuteschedule.pug new file mode 100644 index 0000000..cc1bf67 --- /dev/null +++ b/view/projects/cuteschedule.pug @@ -0,0 +1,23 @@ +extends ../layout/project.pug +block root + - var title = 'CuteSchedule' + +block append content + p(align='center') + img(src='/content/cuteschedule.png' height=128) +
+ | CuteSchedule is an interactive menu with a school schedule. + br + hr + p. + The idea is that the user comes to a big touchscreen TV, selects their class and sees the schedule for the week. + p. + The whole thing was made for a school project and the code is not very good. + I am planning to re write it to electron+vue sometime to have better UI/UX + p. + Also, the original task requested a feature to track a teacher by schedule (to see the cabinet the teacher is in), + but i never got around to implementing it. + p. + It loads the config from a YAML file with + yaml-cpp
+ Funny part: it is stored in git as precompiled binary. \ No newline at end of file diff --git a/view/projects/vrplauncher.pug b/view/projects/vrplauncher.pug new file mode 100644 index 0000000..bab1330 --- /dev/null +++ b/view/projects/vrplauncher.pug @@ -0,0 +1,22 @@ +extends ../layout/project.pug +block root + - var title = 'VRPLauncher' + +block append content + h2 VRPLauncher + p. + VRPLauncher is a custom minecraft launcher for another project (a minecraft server with mods).
+ It is written in C# with WinForms and is made to keep only specific mods in mods folder (it reports any modifications to the server). + p(align='center') + img(src='/content/vrplauncher.png' height=351) +
+ | I have bothered to download the archive with this
+ | and run it with Wine (unfourtunately, i dont run windows) + hr + p. + The interface is written and hardcoded in Russian because the server was made for russians.
+ It was, though planned to implement localization but the project was shut down before i ever got to this. + p. + The design is not very good, but its as good as it gets with WinForms (i guess?)
+ Perhaps it could be better, but that's the best i could do at the time.
+ Should've made the thing with WPF \ No newline at end of file diff --git a/view/projects/winterredit.pug b/view/projects/winterredit.pug new file mode 100644 index 0000000..f175c7d --- /dev/null +++ b/view/projects/winterredit.pug @@ -0,0 +1,16 @@ +extends ../layout/project.pug +block root + - var title = 'WinTerrEdit' + +block append content + p(align='center') + a(href='https://github.com/nymda/WinTerrEdit' target='_blank') + img(src='/content/winterredit.png' height=100) + + p. + WinTerrEdit is a GUI based terraria inventory/player editor.
+ My affilation with the project was adding a couple of things and refactoring the code to make it more readable
+ The thing was a complete mess before i refactored it. (although it still needs some work) + + p. + See the github page. \ No newline at end of file