diff options
author | Tor Andersson <tor@ccxvii.net> | 2021-11-20 19:47:08 +0100 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2021-11-21 12:48:15 +0100 |
commit | a1fe768c6d40c7c885db1c9843c61527cbe583e3 (patch) | |
tree | c397e7d6796049607d6348c538621d1e8809a847 | |
parent | d1318d147297161691f5048e1f2cb4e516159144 (diff) | |
download | server-a1fe768c6d40c7c885db1c9843c61527cbe583e3.tar.gz |
Rewrite view templates to use Pug engine.
65 files changed, 1209 insertions, 989 deletions
@@ -1,7 +1,11 @@ package-lock.json node_modules db +db-wal +db-shm sessions +sessions-wal +sessions-shm log .env *.pem diff --git a/package.json b/package.json index 603974a..52a3190 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,12 @@ "connect": "^3.7.0", "connect-flash": "^0.1.1", "dotenv": "^10.0.0", - "ejs": "^3.1.5", "express": "^4.17.1", "express-session": "^1.17.1", "nodemailer": "^6.7.0", "passport": "^0.5.0", "passport-local": "^1.0.0", + "pug": "^3.0.2", "socket.io": "^4.3.1" } } diff --git a/public/style.css b/public/style.css index 1b9481c..e3c4ae6 100644 --- a/public/style.css +++ b/public/style.css @@ -26,6 +26,7 @@ header img { margin: 4px 0 -2px 2px; } header nav a { margin: 0 1em; color: black; } +header nav a:hover { color: blue; } article { margin: 2em; } article p, article dl, article ul { max-width: 50rem; } @@ -43,18 +44,36 @@ img.logo { height: 200px; } -table { min-width: min(50rem,100%); } -table { border-collapse: collapse; } -th { text-align: left; background-color: gainsboro; } -th, td { border: 1px solid black; padding: 3px 1ex; } -th a:not(:hover), td:not(.command) a:not(:hover) { text-decoration: none; } -td.body { white-space: pre-wrap; padding: 10px 10px; } +table { + min-width: min(50rem,100%); + border-collapse: collapse; +} +th, td { + border: 1px solid black; + padding: 3px 1ex; +} +th { + text-align: left; + background-color: gainsboro; +} +td.body { + white-space: pre-wrap; + padding: 10px 10px; +} +table a:not(:hover) { text-decoration: none; color: black; } +table td.command a { text-decoration: underline; color: blue; } +input[type="checkbox"] { + margin-right: 7px; +} input[type="text"], input[type="password"], textarea { padding: 5px; margin: 5px 0; border: 1px solid black; } +input:focus { + outline: 2px solid lightsteelblue; +} button, select { margin: 5px 10px 5px 0; padding: 1px 10px; @@ -80,7 +80,7 @@ if (process.env.MAIL_HOST && process.env.MAIL_PORT) { app.set('x-powered-by', false); app.set('etag', false); -app.set('view engine', 'ejs'); +app.set('view engine', 'pug'); app.use(body_parser.urlencoded({extended:false})); app.use(session); @@ -306,11 +306,11 @@ function must_be_logged_in(req, res, next) { } app.get('/', function (req, res) { - res.render('index.ejs', { user: req.user, titles: TITLES, flash: req.flash('message') }); + res.render('index.pug', { user: req.user, titles: TITLES, flash: req.flash('message') }); }); app.get('/about', function (req, res) { - res.render('about.ejs', { user: req.user }); + res.render('about.pug', { user: req.user }); }); app.get('/logout', function (req, res) { @@ -323,14 +323,14 @@ app.get('/login', function (req, res) { if (req.user) return res.redirect('/'); LOG(req, "GET /login"); - res.render('login.ejs', { user: req.user, flash: req.flash('message') }); + res.render('login.pug', { user: req.user, flash: req.flash('message') }); }); app.get('/signup', function (req, res) { if (req.user) return res.redirect('/'); LOG(req, "GET /signup"); - res.render('signup.ejs', { user: req.user, flash: req.flash('message') }); + res.render('signup.pug', { user: req.user, flash: req.flash('message') }); }); app.post('/login', @@ -355,7 +355,7 @@ app.post('/signup', app.get('/forgot_password', function (req, res) { LOG(req, "GET /forgot_password"); - res.render('forgot_password.ejs', { user: req.user, flash: req.flash('message') }); + res.render('forgot_password.pug', { user: req.user, flash: req.flash('message') }); }); app.post('/forgot_password', function (req, res) { @@ -377,20 +377,20 @@ app.post('/forgot_password', function (req, res) { app.get('/reset_password', function (req, res) { LOG(req, "GET /reset_password"); - res.render('reset_password.ejs', { user: null, mail: "", token: "", flash: req.flash('message') }); + res.render('reset_password.pug', { user: null, mail: "", token: "", flash: req.flash('message') }); }); app.get('/reset_password/:mail', function (req, res) { let mail = req.params.mail; LOG(req, "GET /reset_password", mail); - res.render('reset_password.ejs', { user: null, mail: mail, token: "", flash: req.flash('message') }); + res.render('reset_password.pug', { user: null, mail: mail, token: "", flash: req.flash('message') }); }); app.get('/reset_password/:mail/:token', function (req, res) { let mail = req.params.mail; let token = req.params.token; LOG(req, "GET /reset_password", mail, token); - res.render('reset_password.ejs', { user: null, mail: mail, token: token, flash: req.flash('message') }); + res.render('reset_password.pug', { user: null, mail: mail, token: token, flash: req.flash('message') }); }); app.post('/reset_password', function (req, res) { @@ -419,7 +419,7 @@ app.post('/reset_password', function (req, res) { app.get('/change_password', must_be_logged_in, function (req, res) { LOG(req, "GET /change_password"); - res.render('change_password.ejs', { user: req.user, flash: req.flash('message') }); + res.render('change_password.pug', { user: req.user, flash: req.flash('message') }); }); app.post('/change_password', must_be_logged_in, function (req, res) { @@ -462,7 +462,7 @@ app.get('/unsubscribe', must_be_logged_in, function (req, res) { app.get('/change_name', must_be_logged_in, function (req, res) { LOG(req, "GET /change_name"); - res.render('change_name.ejs', { user: req.user, flash: req.flash('message') }); + res.render('change_name.pug', { user: req.user, flash: req.flash('message') }); }); app.post('/change_name', must_be_logged_in, function (req, res) { @@ -482,7 +482,7 @@ app.post('/change_name', must_be_logged_in, function (req, res) { app.get('/change_mail', must_be_logged_in, function (req, res) { LOG(req, "GET /change_mail"); - res.render('change_mail.ejs', { user: req.user, flash: req.flash('message') }); + res.render('change_mail.pug', { user: req.user, flash: req.flash('message') }); }); app.post('/change_mail', must_be_logged_in, function (req, res) { @@ -503,7 +503,7 @@ app.post('/change_mail', must_be_logged_in, function (req, res) { app.get('/change_about', must_be_logged_in, function (req, res) { LOG(req, "GET /change_about"); let about = SQL_SELECT_USER_PROFILE.get(req.user.name).about; - res.render('change_about.ejs', { user: req.user, about: about || "" }); + res.render('change_about.pug', { user: req.user, about: about || "" }); }); app.post('/change_about', must_be_logged_in, function (req, res) { @@ -519,13 +519,13 @@ app.get('/user/:who_name', function (req, res) { who.avatar = get_avatar(who.mail); who.ctime = human_date(who.ctime); who.atime = human_date(who.atime); - res.render('user.ejs', { user: req.user, who: who }); + res.render('user.pug', { user: req.user, who: who }); } else { return res.status(404).send("Invalid user name."); } }); -app.get('/users', function (req, res) { +app.get('/user_list', function (req, res) { LOG(req, "GET /users"); let rows = db.prepare("SELECT * FROM user_profile_view ORDER BY atime DESC").all(); rows.forEach(row => { @@ -533,19 +533,19 @@ app.get('/users', function (req, res) { row.ctime = human_date(row.ctime); row.atime = human_date(row.atime); }); - res.render('users.ejs', { user: req.user, userList: rows }); + res.render('user_list.pug', { user: req.user, user_list: rows }); }); app.get('/chat', must_be_logged_in, function (req, res) { LOG(req, "GET /chat"); let chat = SQL_SELECT_USER_CHAT_N.all(req.user.user_id, 12*20); - res.render('chat.ejs', { user: req.user, chat: chat, page_size: 12 }); + res.render('chat.pug', { user: req.user, chat: chat, page_size: 12 }); }); app.get('/chat/all', must_be_logged_in, function (req, res) { LOG(req, "GET /chat/all"); let chat = SQL_SELECT_USER_CHAT.all(req.user.user_id); - res.render('chat.ejs', { user: req.user, chat: chat, page_size: 0 }); + res.render('chat.pug', { user: req.user, chat: chat, page_size: 0 }); }); /* @@ -577,7 +577,7 @@ app.get('/inbox', must_be_logged_in, function (req, res) { for (let i = 0; i < messages.length; ++i) messages[i].time = human_date(messages[i].time); res.set("Cache-Control", "no-store"); - res.render('message_inbox.ejs', { + res.render('message_inbox.pug', { user: req.user, messages: messages, }); @@ -589,7 +589,7 @@ app.get('/outbox', must_be_logged_in, function (req, res) { for (let i = 0; i < messages.length; ++i) messages[i].time = human_date(messages[i].time); res.set("Cache-Control", "no-store"); - res.render('message_outbox.ejs', { + res.render('message_outbox.pug', { user: req.user, messages: messages, }); @@ -607,14 +607,14 @@ app.get('/message/read/:message_id', must_be_logged_in, function (req, res) { } message.time = human_date(message.time); message.body = linkify_post(message.body); - res.render('message_read.ejs', { + res.render('message_read.pug', { user: req.user, message: message, }); }); app.get('/message/send', must_be_logged_in, function (req, res) { - res.render('message_send.ejs', { + res.render('message_send.pug', { user: req.user, to_name: "", subject: "", @@ -625,7 +625,7 @@ app.get('/message/send', must_be_logged_in, function (req, res) { app.get('/message/send/:to_name', must_be_logged_in, function (req, res) { LOG(req, "GET /message/send/" + req.params.to_name); let to_name = req.params.to_name; - res.render('message_send.ejs', { + res.render('message_send.pug', { user: req.user, to_name: to_name, subject: "", @@ -640,7 +640,7 @@ app.post('/message/send', must_be_logged_in, function (req, res) { let body = req.body.body.trim(); let to_user = SQL_SELECT_USER_BY_NAME.get(to_name); if (!to_user) { - return res.render('message_send.ejs', { + return res.render('message_send.pug', { user: req.user, to_id: 0, to_name: to_name, @@ -668,7 +668,7 @@ app.get('/message/reply/:message_id', must_be_logged_in, function (req, res) { let message = MESSAGE_FETCH.get(message_id, req.user.user_id, req.user.user_id); if (!message) return res.status(404).send("Invalid message ID."); - return res.render('message_send.ejs', { + return res.render('message_send.pug', { user: req.user, to_id: message.from_id, to_name: message.from_name, @@ -715,7 +715,7 @@ function show_forum_page(req, res, page) { thread.mtime = human_date(thread.mtime); } res.set("Cache-Control", "no-store"); - res.render('forum_view.ejs', { + res.render('forum_view.pug', { user: req.user, threads: threads, current_page: page, @@ -757,7 +757,7 @@ app.get('/forum/thread/:thread_id', function (req, res) { posts[i].mtime = human_date(posts[i].mtime); } res.set("Cache-Control", "no-store"); - res.render('forum_thread.ejs', { + res.render('forum_thread.pug', { user: req.user, thread: thread, posts: posts, @@ -766,7 +766,7 @@ app.get('/forum/thread/:thread_id', function (req, res) { app.get('/forum/post', must_be_logged_in, function (req, res) { LOG(req, "GET /forum/post"); - res.render('forum_post.ejs', { + res.render('forum_post.pug', { user: req.user, }); }); @@ -792,7 +792,7 @@ app.get('/forum/edit/:post_id', must_be_logged_in, function (req, res) { return res.status(404).send("Invalid post ID."); post.ctime = human_date(post.ctime); post.mtime = human_date(post.mtime); - res.render('forum_edit.ejs', { + res.render('forum_edit.pug', { user: req.user, post: post, }); @@ -818,7 +818,7 @@ app.get('/forum/reply/:post_id', must_be_logged_in, function (req, res) { post.edited = post.mtime !== post.ctime; post.ctime = human_date(post.ctime); post.mtime = human_date(post.mtime); - res.render('forum_reply.ejs', { + res.render('forum_reply.pug', { user: req.user, thread: thread, post: post, @@ -841,6 +841,8 @@ app.post('/forum/reply/:thread_id', must_be_logged_in, function (req, res) { let TITLES = {}; let RULES = {}; let ROLES = {}; +let HTML_ABOUT = {}; +let HTML_CREATE = {}; function load_rules() { const SQL_SELECT_TITLES = SQL("SELECT * FROM titles"); @@ -853,6 +855,8 @@ function load_rules() { TITLES[title_id] = title; RULES[title_id] = require("./public/" + title_id + "/rules.js"); ROLES[title_id] = SQL_SELECT_TITLE_ROLES.all(title_id); + HTML_ABOUT[title_id] = fs.readFileSync("./public/" + title_id + "/about.html"); + HTML_CREATE[title_id] = fs.readFileSync("./public/" + title_id + "/create.html"); } catch (err) { console.log(err); } @@ -995,7 +999,7 @@ function annotate_games(games, user_id) { } app.get('/games', function (req, res) { - LOG(req, "GET /join"); + LOG(req, "GET /games"); let open_games = QUERY_LIST_GAMES.all(0); let active_games = QUERY_LIST_GAMES.all(1); if (req.user) { @@ -1006,7 +1010,7 @@ app.get('/games', function (req, res) { annotate_games(active_games, 0); } res.set("Cache-Control", "no-store"); - res.render('games.ejs', { + res.render('games.pug', { user: req.user, open_games: open_games, active_games: active_games, @@ -1022,7 +1026,7 @@ app.get('/profile', must_be_logged_in, function (req, res) { let active_games = games.filter(game => game.status === 1); let finished_games = games.filter(game => game.status === 2); res.set("Cache-Control", "no-store"); - res.render('profile.ejs', { + res.render('profile.pug', { user: req.user, avatar: avatar, open_games: open_games, @@ -1044,9 +1048,10 @@ app.get('/info/:title_id', function (req, res) { annotate_games(open_games, req.user ? req.user.user_id : 0); annotate_games(active_games, req.user ? req.user.user_id : 0); annotate_games(finished_games, req.user ? req.user.user_id : 0); - res.render('info.ejs', { + res.render('info.pug', { user: req.user, title: title, + about_html: HTML_ABOUT[title_id], open_games: open_games, active_games: active_games, finished_games: finished_games, @@ -1059,10 +1064,11 @@ app.get('/create/:title_id', must_be_logged_in, function (req, res) { let title = TITLES[title_id]; if (!title) return res.status(404).send("Invalid title."); - res.render('create.ejs', { + res.render('create.pug', { user: req.user, title: title, scenarios: RULES[title_id].scenarios, + create_html: HTML_CREATE[title_id], flash: req.flash('message') }); }); @@ -1201,7 +1207,7 @@ app.get('/join/:game_id', must_be_logged_in, function (req, res) { let players = SQL_SELECT_PLAYERS_JOIN.all(game_id); let ready = (game.status === 0) && RULES[game.title_id].ready(game.scenario, game.options, players); res.set("Cache-Control", "no-store"); - res.render('join.ejs', { + res.render('join.pug', { user: req.user, game: game, roles: roles, @@ -1479,7 +1485,8 @@ function notify_your_turn_reminder() { function notify_ready_to_start_reminder() { for (let game of SQL_SELECT_OPEN_GAMES.all()) { let players = SQL_SELECT_PLAYERS.all(game.game_id); - if (RULES[game.title_id].ready(game.scenario, game.options, players)) { + let rules = RULES[game.title_id]; + if (rules && rules.ready(game.scenario, game.options, players)) { let owner = SQL_OFFLINE_USER.get(game.owner_id, '+3 minutes'); if (owner) { if (owner.notify) @@ -1746,7 +1753,7 @@ const QUERY_STATS = db.prepare("SELECT * FROM game_stat_view"); app.get('/stats', function (req, res) { LOG(req, "GET /stats"); let stats = QUERY_STATS.all(); - res.render('stats.ejs', { + res.render('stats.pug', { user: req.user, stats: stats, title_role_map: ROLES, diff --git a/views/TEMPLATE b/views/TEMPLATE new file mode 100644 index 0000000..06f5a94 --- /dev/null +++ b/views/TEMPLATE @@ -0,0 +1,13 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title TITLE + body + include header + article + h1 TITLE + if flash + p.error= flash + diff --git a/views/about.ejs b/views/about.ejs deleted file mode 100644 index 4418d52..0000000 --- a/views/about.ejs +++ /dev/null @@ -1,75 +0,0 @@ -<%- include('header', { title: "Rally the Troops!" }) -%> -<style> -li img{height:1.0em;vertical-align:middle} -</style> - -<p> -Rally the Troops! is created and maintained by Tor Andersson. -It is an open source project. - -<p> -Please submit problem reports and make suggestions for improvements on -<a href="https://github.com/ccxvii/rally-the-troops/issues">GitHub</a>. - -<h2> -Tips & Tricks -</h2> - -<ul> - -<li> -Open a separate browser tab or window for each side when playing solo. - -<li> -Use the middle mouse button to drag and scroll around the map. - -<li> -Hold down the Shift key when mousing over a block or counter in order to magnify it. - -<li> -The <i>Enter</i> and <i>Escape</i> keys open and close the chat box. - -<li> -To invite your friends to a private game, send them the address of the join page. - -<li> -Chat messages can only be seen by players who are part of a game. -They are hidden from observers. - -<li> -The <img src="/images/cog.svg"> menu has links to rules, player aids and other reference material. -In some games you can also choose between alternative graphics and layout options. - -<li> -The <img src="/images/earth-africa-europe.svg"> button hides all counters and markers, -if you need to check something on the map that is obscured. - -<li> -The <img src="/images/magnifying-glass.svg"> button shrinks the map to fit the screen width. - -<li> -The <img src="/images/scroll-quill.svg"> button hides the game log and player status displays, so you can -see more of the map. - -<li> -The <img src="/images/chat-bubble.svg"> button lights up if you have unread chat messages. - -<li> -The <img src="/images/cycle.svg"> button appears when the game is over, and can be used to quickly start a rematch. - -</ul> - -<h2> -Licensing -</h2> - -<p> -All games are used with consent from their respective rights holders. - -<p> -Icons are sourced from <a href="https://game-icons.net">game-icons.net</a> -by Delapouite, Lorc, and others under the -<a href="https://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a> license. -<p> -Other images and graphics are sourced from -<a href="https://commons.wikimedia.org/wiki/Main_Page">Wikimedia Commons</a>. diff --git a/views/about.pug b/views/about.pug new file mode 100644 index 0000000..382ad59 --- /dev/null +++ b/views/about.pug @@ -0,0 +1,41 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Rally the Troops! + style. + li img { height: 1.0em; vertical-align: middle; } + body + include header + article + h1 Rally the Troops! + + p Rally the Troops! is created and maintained by Tor Andersson. It is an open source project. + + p Please submit problem reports and make suggestions for improvements on #[a(href="https://github.com/ccxvii/rally-the-troops/issues") GitHub]. + + h2 Tips & Tricks + + ul + li Open a separate browser tab or window for each side when playing solo. + li Use the middle mouse button to drag and scroll around the map. + li Hold down the Shift key when mousing over a block or counter in order to magnify it. + li The #[i Enter] and #[i Escape] keys open and close the chat box. + li To invite your friends to a private game, send them the address of the join page. + li Chat messages can only be seen by players who are part of a game. They are hidden from observers. + li The #[img(src="/images/cog.svg")] menu has links to rules, player aids and other reference material. In some games you can also choose between alternative graphics and layout options. + li The #[img(src="/images/earth-africa-europe.svg")] button hides all counters and markers, if you need to check something on the map that is obscured. + li The #[img(src="/images/magnifying-glass.svg")] button shrinks the map to fit the screen width. + li The #[img(src="/images/scroll-quill.svg")] button hides the game log and player status displays, so you can see more of the map. + li The #[img(src="/images/chat-bubble.svg")] button lights up if you have unread chat messages. + li The #[img(src="/images/cycle.svg")] button appears when the game is over, and can be used to quickly start a rematch. + + h2 Licensing + + p All games are used with consent from their respective rights holders. + + p Icons are sourced from #[a(href="https://game-icons.net") game-icons.net] by Delapouite, Lorc, and others under the #[a(href="https://creativecommons.org/licenses/by/3.0/") CC BY 3.0] license. + + p Other images and graphics are sourced from #[a( href="https://commons.wikimedia.org/wiki/Main_Page") Wikimedia Commons]. + diff --git a/views/change_about.ejs b/views/change_about.ejs deleted file mode 100644 index cbea0c5..0000000 --- a/views/change_about.ejs +++ /dev/null @@ -1,11 +0,0 @@ -<%- include('header', { title: "Change profile text" }) -%> -<style> -textarea { width: 100%; max-width: 45em; } -</style> -<form action="/change_about" method="post"> -<p> -<textarea name="about" rows="20" cols="80" maxlength="32000" autofocus> -<%= about %></textarea> -<p> -<button type="submit">Submit</button> -</form> diff --git a/views/change_about.pug b/views/change_about.pug new file mode 100644 index 0000000..3232c26 --- /dev/null +++ b/views/change_about.pug @@ -0,0 +1,27 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Change profile text + style. + input, textarea { width: min(45rem,100%) } + body + include header + article + h1 Change profile text + form(method="post" action="/change_about") + p Name: #{user.name} + p Mail: #{user.mail} + p + textarea( + name="about" + rows=20 + cols=80 + maxlength=32000 + autofocus + ) + | + | #{about} + p + button(type="submit") Submit diff --git a/views/change_mail.ejs b/views/change_mail.ejs deleted file mode 100644 index 6c3ed62..0000000 --- a/views/change_mail.ejs +++ /dev/null @@ -1,12 +0,0 @@ -<%- include('header', { title: "Change mail address" }) %> -<form action="/change_mail" method="post"> -<p> -Name: <%= user.name %> -<p> -Mail: <%= user.mail %> -<p> -<label for="newmail">New mail address: </label><br> -<input type="newmail" id="newmail" name="newmail" required> -<p> -<button type="submit">Change mail</button> -</form> diff --git a/views/change_mail.pug b/views/change_mail.pug new file mode 100644 index 0000000..77ddfc2 --- /dev/null +++ b/views/change_mail.pug @@ -0,0 +1,21 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Change mail address + body + include header + article + h1 Change mail address + if flash + p.error= flash + form(method="post" action="/change_mail") + p Name: #{user.name} + p Mail: #{user.mail} + p + label New mail address: + br + input(type="text" name="newmail" required) + p + button(type="submit") Change mail diff --git a/views/change_name.ejs b/views/change_name.ejs deleted file mode 100644 index eac508f..0000000 --- a/views/change_name.ejs +++ /dev/null @@ -1,12 +0,0 @@ -<%- include('header', { title: "Change name" }) %> -<form action="/change_name" method="post"> -<p> -Name: <%= user.name %> -<p> -Mail: <%= user.mail %> -<p> -<label for="newname">New name: </label><br> -<input type="newname" id="newname" name="newname" required> -<p> -<button type="submit">Change name</button> -</form> diff --git a/views/change_name.pug b/views/change_name.pug new file mode 100644 index 0000000..2cded48 --- /dev/null +++ b/views/change_name.pug @@ -0,0 +1,21 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Change name + body + include header + article + h1 Change name + if flash + p.error= flash + form(method="post" action="/change_name") + p Name: #{user.name} + p Mail: #{user.mail} + p + label New name: + br + input(type="text" name="newname" required) + p + button(type="submit") Change name diff --git a/views/change_password.ejs b/views/change_password.ejs deleted file mode 100644 index ab15a4a..0000000 --- a/views/change_password.ejs +++ /dev/null @@ -1,15 +0,0 @@ -<%- include('header', { title: "Change password" }) %> -<form action="/change_password" method="post"> -<p> -Name: <%= user.name %> -<p> -Mail: <%= user.mail %> -<p> -<label for="password">Old Password: </label><br> -<input type="password" id="password" name="password" required> -<p> -<label for="newpass">New Password: </label><br> -<input type="password" id="newpass" name="newpass" required> -<p> -<button type="submit">Change password</button> -</form> diff --git a/views/change_password.pug b/views/change_password.pug new file mode 100644 index 0000000..feaa46c --- /dev/null +++ b/views/change_password.pug @@ -0,0 +1,26 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Change password + body + include header + article + h1 Change password + if flash + p.error= flash + + form(method="post" action="/change_password") + p Name: #{user.name} + p Mail: #{user.mail} + p + label Old Password: + br + input(type="password" name="password" required) + p + label New Password: + br + input(type="password" name="newpass" required) + p + button(type="submit") Change password diff --git a/views/chat.ejs b/views/chat.ejs deleted file mode 100644 index d217857..0000000 --- a/views/chat.ejs +++ /dev/null @@ -1,79 +0,0 @@ -<%- include('header', { title: "Chat Log" }) -%> -<style> -table{width:min(60rem,100%);} -td:nth-child(1),td:nth-child(2){white-space:nowrap;width:0} -td:nth-child(3){white-space:nowrap;width:8rem} -#foot{display:inline-block;padding-top:8px;} -table{border:1px solid black} -td{border:none} -td a{text-decoration:none;color:black;} -tr{background-color:white;} -tr.me{background-color:aliceblue;} -</style> -<% if (page_size > 0) { %> -<p> -<button onclick="oldest()">Oldest</button> -<button onclick="back()">←</button> -<button onclick="next()">→</button> -<button onclick="newest()">Newest</button> -<span id="foot"></span> -<table><thead><tr><th>Game<th>Time<th>Who<th>Message</thead><tbody></tbody></table> -<p><a href="/chat/all">All messages</a> -<% } else { %> -<table><thead><tr><th>Game<th>Time<th>Who<th>Message</thead><tbody></tbody></table> -<% } %> -<script> -let chat_data = <%- JSON.stringify(chat).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") %>; -let page_size = <%- page_size %>; -let me = <%- JSON.stringify(user.name) %>; -let table = document.querySelector("tbody"); -let foot = document.querySelector("#foot"); -let chat_lines = []; -function add(tr,text,link) { - let td = document.createElement("td"); - if (link) { - let a = document.createElement("a"); - a.href = link; - a.textContent = text; - td.appendChild(a); - } else { - td.textContent = text; - } - tr.appendChild(td); -} -function format_date(date) { - let t = date.toISOString(); - return t.substring(0,10) + " " + t.substring(11,19); -} -for (let [game_id,time,user,message] of chat_data) { - let tr = document.createElement("tr"); - if (user === me) tr.className = 'me'; - add(tr,game_id,'/join/'+game_id); - add(tr,format_date(new Date(time+'Z'))); - add(tr,user,'/user/'+user); - add(tr,message); - chat_lines.push(tr); -} -function next() { if (page > 0) --page; update(); } -function back() { if (page < page_count-1) ++page; update(); } -function newest() { page=0; update(); } -function oldest() { page=page_count-1; update(); } -let chat_size = chat_lines.length; -let page_count = Math.ceil(chat_size / page_size); -let page = 0; -function update() { - table.innerHTML = ''; - for (let i = 0; i < page_size; ++i) { - let k = page * page_size + ( page_size - i - 1); - if (k >= 0 && k < chat_size) - table.appendChild(chat_lines[k]); - foot.textContent = `${page_count-page} / ${page_count}`; - } -} -if (page_size > 0) { - newest(); -} else { - for (let i = chat_size-1; i >= 0; --i) - table.appendChild(chat_lines[i]); -} -</script> diff --git a/views/chat.pug b/views/chat.pug new file mode 100644 index 0000000..dfe6f25 --- /dev/null +++ b/views/chat.pug @@ -0,0 +1,93 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Chat Log + style. + table { width: min(60rem,100%); } + td:nth-child(1), td:nth-child(2) { white-space: nowrap; width: 0; } + td:nth-child(3) { white-space: nowrap; width: 8rem; } + #foot { display: inline-block; padding-top: 8px; } + table { border: 1px solid black; } + td { border: none; } + td a { text-decoration: none; color: black; } + tr { background-color: white; } + tr.me { background-color: aliceblue; } + body + include header + article + h1 Chat Log + if page_size > 0 + p + button(onclick="oldest()") Oldest + button(onclick="back()") ← + button(onclick="next()") → + button(onclick="newest()") Newest + span#foot + p + table + thead + tr + th Game + th Time + th Who + th Message + tbody + if page_size > 0 + p: a(href="/chat/all") All messages + + script. + let chat_data = !{ JSON.stringify(chat).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") }; + let page_size = !{ page_size }; + let me = !{ JSON.stringify(user.name) }; + let table = document.querySelector("tbody"); + let foot = document.querySelector("#foot"); + let chat_lines = []; + function add(tr,text,link) { + let td = document.createElement("td"); + if (link) { + let a = document.createElement("a"); + a.href = link; + a.textContent = text; + td.appendChild(a); + } else { + td.textContent = text; + } + tr.appendChild(td); + } + function format_date(date) { + let t = date.toISOString(); + return t.substring(0,10) + " " + t.substring(11,19); + } + for (let [game_id,time,user,message] of chat_data) { + let tr = document.createElement("tr"); + if (user === me) tr.className = "me"; + add(tr,game_id,"/join/"+game_id); + add(tr,format_date(new Date(time+"Z"))); + add(tr,user,"/user/"+user); + add(tr,message); + chat_lines.push(tr); + } + function next() { if (page > 0) --page; update(); } + function back() { if (page < page_count-1) ++page; update(); } + function newest() { page=0; update(); } + function oldest() { page=page_count-1; update(); } + let chat_size = chat_lines.length; + let page_count = Math.ceil(chat_size / page_size); + let page = 0; + function update() { + table.innerHTML = ""; + for (let i = 0; i < page_size; ++i) { + let k = page * page_size + ( page_size - i - 1); + if (k >= 0 && k < chat_size) + table.appendChild(chat_lines[k]); + foot.textContent = `${page_count-page} / ${page_count}`; + } + } + if (page_size > 0) { + newest(); + } else { + for (let i = chat_size-1; i >= 0; --i) + table.appendChild(chat_lines[i]); + } diff --git a/views/create.ejs b/views/create.ejs deleted file mode 100644 index 36b86e2..0000000 --- a/views/create.ejs +++ /dev/null @@ -1,32 +0,0 @@ -<%- include('header', { title: title.title_name }) %> -<style>form{display:block;margin-left:170px;}</style> -<a href="/info/<%= title.title_id %>"><img class="logo" src="/<%= title.title_id %>/cover.jpg"></a> -<form action="/create/<%= title.title_id %>" method="post"> -<p> -<% if (scenarios.length > 1) { %> -Scenario:<br> -<select name="scenario"> -<% scenarios.forEach((scenario) => { %> -<option value="<%= scenario %>"><%= scenario %></option> -<% }); %> -</select> -<% } else { %> -<input type="hidden" name="scenario" value="<%= scenarios[0] %>"> -<% } %> -<%- include('../public/' + title.title_id + '/create.html') %> -<p> -Description:<br> -<input type="text" autocomplete="off" name="description" size="50"> -<p> -<label> -<input type="checkbox" name="random" value="true"> -Random player roles -</label> -<p> -<label> -<input type="checkbox" name="private" value="true"> -Private -</label> -<p> -<button type="submit">Create</button> -</form> diff --git a/views/create.pug b/views/create.pug new file mode 100644 index 0000000..9196aa9 --- /dev/null +++ b/views/create.pug @@ -0,0 +1,40 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= title.title_name + style. + form { margin-left: 170px; } + body + include header + article + h1= title.title_name + if flash + p.error= flash + + a(href="/info/"+title.title_id): img.logo(src="/"+title.title_id+"/cover.jpg") + + form(method="post" action="/create/"+title.title_id) + if scenarios.length > 1 + p Scenario: + br + select(name="scenario") + each scenario in scenarios + option(value=scenario)= scenario + else + input(type="hidden" name="scenario" value=scenarios[0]) + | !{ create_html } + p Description: + br + input(type="text" autocomplete="off" name="description" size=50) + p + label + input(type="checkbox" name="random" value="true") + | Random player roles + p + label + input(type="checkbox" name="private" value="true") + | Private + p + button(type="submit") Create diff --git a/views/error.ejs b/views/error.ejs deleted file mode 100644 index b7d9632..0000000 --- a/views/error.ejs +++ /dev/null @@ -1 +0,0 @@ -<%- include('header', { title: "Error" }) %> diff --git a/views/forgot_password.ejs b/views/forgot_password.ejs deleted file mode 100644 index 1679496..0000000 --- a/views/forgot_password.ejs +++ /dev/null @@ -1,13 +0,0 @@ -<%- include('header', { title: "Forgot password" }) %> -<% if (user) { %> -<p> -You're already logged in! -<% } else { %> -<form action="/forgot_password" method="post"> -<p> -<label for="mail">Mail: </label><br> -<input type="mail" id="mail" name="mail" required> -<p> -<button type="submit">Forgot password</button> -</form> -<% } %> diff --git a/views/forgot_password.pug b/views/forgot_password.pug new file mode 100644 index 0000000..ea53ea4 --- /dev/null +++ b/views/forgot_password.pug @@ -0,0 +1,23 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Forgot password + body + include header + article + h1 Forgot password + if flash + p.error= flash + + if user + p You're already logged in! + else + form(method="post" action="/forgot_password") + p + label Mail: + br + input(type="mail" name="mail" required) + p + button(type="submit") Forgot password diff --git a/views/forum_edit.ejs b/views/forum_edit.ejs deleted file mode 100644 index 7ed1414..0000000 --- a/views/forum_edit.ejs +++ /dev/null @@ -1,11 +0,0 @@ -<%- include('header', { title: "Edit Post" }) -%> -<style> -input, textarea { width: 100%; max-width: 45em; } -</style> -<form action="/forum/edit/<%- post.post_id %>" method="post"> -<p> -<textarea name="body" rows="20" cols="80" maxlength="32000" required autofocus> -<%= post.body %></textarea> -<p> -<button type="submit">Submit</button> -</form> diff --git a/views/forum_edit.pug b/views/forum_edit.pug new file mode 100644 index 0000000..ff2a5b1 --- /dev/null +++ b/views/forum_edit.pug @@ -0,0 +1,25 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Edit Post + style. + input, textarea { width: min(45rem,100%) } + body + include header + article + h1 Edit Post + + form(method="post" action="/forum/edit/"+post.post_id) + textarea( + name="body" + rows=20 + cols=80 + maxlength=32000 + required + ) + | + | #{post.body} + p + button(type="submit") Submit diff --git a/views/forum_post.ejs b/views/forum_post.ejs deleted file mode 100644 index 98d667c..0000000 --- a/views/forum_post.ejs +++ /dev/null @@ -1,20 +0,0 @@ -<%- include('header', { title: "New Thread" }) -%> -<style> -input, textarea { width: 100%; max-width: 45em; } -</style> -<form action="/forum/post" method="post"> -<p> -Subject: -<br> -<input type="text" name="subject" size="80" maxlength="80" - onkeypress="if(event.keyCode===13){document.querySelector('textarea').focus();return false;}" - autofocus - pattern=".*\S+.*" - required> -<p> -Body: -<br> -<textarea name="body" rows="20" cols="80" maxlength="32000" required></textarea> -<p> -<button type="submit">Submit</button> -</form> diff --git a/views/forum_post.pug b/views/forum_post.pug new file mode 100644 index 0000000..d3c0e80 --- /dev/null +++ b/views/forum_post.pug @@ -0,0 +1,44 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title New Thread + style. + input, textarea { width: min(45rem,100%) } + script. + function next(event,sel) { + if (event.keyCode === 13) { + document.querySelector(sel).focus(); + return false; + } + return true; + } + body + include header + article + h1 New Thread + form(method="post" action="/forum/post") + p Subject: + br + input( + type="text" + name="subject" + size=80 + maxlength=80 + required + pattern=".*\\S+.*" + autofocus + onkeypress="return next(event,'textarea')" + ) + p Body: + br + textarea( + name="body" + rows=20 + cols=80 + maxlength=32000 + required + ) + p + button(type="submit") Submit diff --git a/views/forum_reply.ejs b/views/forum_reply.ejs deleted file mode 100644 index db777b6..0000000 --- a/views/forum_reply.ejs +++ /dev/null @@ -1,23 +0,0 @@ -<%- include('header', { title: thread.subject }) -%> -<style> -input, textarea { width: 100%; max-width: 45em; } -table { max-width: 50em; } -table .author { border-right: none; } -table .time { border-left: none; font-weight: normal; } -table .command { border: none; } -</style> -<table class="post"> -<tr> -<th class="author"><%= post.author_name %> -<th class="r time"><%= post.ctime %> <%= post.edited ? "(edited " + post.mtime + ")" : "" %> -<tr> -<td class="body" colspan="2"><%- post.body %></td> -</table> -<form action="/forum/reply/<%- thread.thread_id %>" method="post"> -<p> -Reply: -<br> -<textarea name="body" rows="15" cols="80" maxlength="32000" required autofocus></textarea> -<p> -<button type="submit">Submit</button> -</form> diff --git a/views/forum_reply.pug b/views/forum_reply.pug new file mode 100644 index 0000000..5b5a3bb --- /dev/null +++ b/views/forum_reply.pug @@ -0,0 +1,39 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= thread.subject + style. + input, textarea { width: min(45rem,100%) } + table { max-width: 50em; } + table .author { border-right: none; } + table .time { border-left: none; font-weight: normal; } + table .command { border: none; } + body + include header + article + h1= thread.subject + + table + tr + th.author: a(href="/user/"+post.author_name)= post.author_name + th.r.time= post.ctime + if post.edited + | + | (edited #{post.mtime}) + tr + td.body(colspan=2)!= post.body + + form(method="post" action="/forum/reply/"+thread.thread_id) + p Reply: + br + textarea( + name="body" + rows=15 + cols=80 + maxlength=32000 + required + ) + p + button(type="submit") Submit diff --git a/views/forum_thread.ejs b/views/forum_thread.ejs deleted file mode 100644 index 5c76704..0000000 --- a/views/forum_thread.ejs +++ /dev/null @@ -1,29 +0,0 @@ -<%- include('header', { title: thread.subject }) -%> -<style> -table { max-width: 50em; } -table .author { border-right: none; } -table .time { border-left: none; font-weight: normal; } -table .command { border: none; } -</style> -<% posts.forEach((row) => { %> -<p> -<table class="post"> -<tr> -<th class="author"><a href="/user/<%- row.author_name %>"><%= row.author_name %></a> -<th class="r time"><%= row.ctime %> -<%= row.edited ? "(edited " + row.mtime + ")" : "" %> -<tr> -<td class="body" colspan="2"><%- row.body %></td> -<% if (user) { %> -<tr> -<td class="r command" colspan=2> -<% if (row.author_id === user.user_id) { %> -<a href="/forum/edit/<%- row.post_id %>">Edit</a> -<% } %> -<a href="/forum/reply/<%- row.post_id %>">Reply</a> -<% } %> -</table> -<% }); %> -<% if (user) { %> -<p><a href="/forum/reply/<%- posts[0].post_id %>">Reply</a> -<% } %> diff --git a/views/forum_thread.pug b/views/forum_thread.pug new file mode 100644 index 0000000..bb19b61 --- /dev/null +++ b/views/forum_thread.pug @@ -0,0 +1,37 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= thread.subject + style. + table { max-width: 50em; } + table .author { border-right: none; } + table .time { border-left: none; font-weight: normal; } + table .command { border: none; } + body + include header + article + h1= thread.subject + + each row in posts + p + table + tr + th.author: a(href="/user/"+row.author_name)= row.author_name + th.r.time= row.ctime + if row.edited + | + | (edited #{row.mtime}) + tr + td.body(colspan=2)!= row.body + if user + tr + td.r.command(colspan=2) + if row.author_id === user.user_id + | #[a(href="/forum/edit/"+row.post_id) Edit] + | + | #[a(href="/forum/reply/"+row.post_id) Reply] + + if user + p: a(href="/forum/reply/"+posts[0].post_id) Reply diff --git a/views/forum_view.ejs b/views/forum_view.ejs deleted file mode 100644 index d5ebd46..0000000 --- a/views/forum_view.ejs +++ /dev/null @@ -1,37 +0,0 @@ -<%- include('header', { title: "Forum", refresh: 900 }) -%> -<style> -tfoot{background-color:gainsboro} -</style> -<table> -<tr> -<th>Subject -<th>Author -<th>Replies -<th>Time -<% threads.forEach((row) => { %> -<tr> -<td><a href="/forum/thread/<%- row.thread_id %>"><%= row.subject %></a> -<td><a href="/user/<%- row.author_name %>"><%= row.author_name %></a> -<td><%= row.replies %> -<td><%= row.mtime %> -<% }); %> -<tfoot> -<tr> -<td colspan="4"> -<% if (current_page > 1) { %> -<a href="/forum/page/<%- current_page-1 %>">←</a> -<% } %> -<% for (let p = 1; p <= page_count && p <= 30; ++p) { %> -<% if (p === current_page) { %> -(<%- p %>) -<% } else { %> -<a href="/forum/page/<%- p %>"><%- p %></a> -<% } %> -<% } %> -<% if (current_page < page_count) { %> -<a href="/forum/page/<%- current_page+1 %>">→</a> -<% } %> -</table> -<% if (user) { %> -<p><a href="/forum/post">New thread</a> -<% } %> diff --git a/views/forum_view.pug b/views/forum_view.pug new file mode 100644 index 0000000..0b9078c --- /dev/null +++ b/views/forum_view.pug @@ -0,0 +1,41 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Forum + meta(http-equiv="refresh" content=900) + style tfoot { background-color: gainsboro } + body + include header + article + h1 Forum + + table + tr + th Subject + th Author + th Replies + th Time + each row in threads + tr + td: a(href="/forum/thread/"+row.thread_id)= row.subject + td: a(href="/forum/thread/"+row.author_name)= row.author_name + td= row.replies + td= row.mtime + tfoot: tr: td(colspan=4) + if current_page > 1 + | #[a(href="/forum/page/"+(current_page-1)) ←] + | + - for (let p=1; p<=page_count && p<=30; ++p) + if p === current_page + | (#{p}) + | + else + | #[a(href="/forum/page/"+p)= p] + | + if current_page < page_count + | #[a(href="/forum/page/"+(current_page+1)) →] + + if user + p: a(href="/forum/post") New thread diff --git a/views/games.ejs b/views/games.ejs deleted file mode 100644 index 90b2f68..0000000 --- a/views/games.ejs +++ /dev/null @@ -1,51 +0,0 @@ -<%- include('header', { title: "All Public Games", refresh: (user ? 300 : 0) }) -%> - -<h2>Open</h2> -<table> -<tr><th>ID<th>Title<th>Scenario<th>Players<th>Description<th>Created<th> -<% if (open_games.length > 0) { %> -<% open_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.ctime %> -<td class="command"><a href="/join/<%= row.game_id %>">Join</a> -<% }); } else { %> -<tr><td colspan="7">No open games. -<% } %> -</table> - -<h2>Active</h2> -<table> -<tr><th>ID<th>Title<th>Scenario<th>Players<th>Description<th>Changed<th>Active<th> -<% if (active_games.length > 0) { %> -<% active_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.mtime %> -<% if (row.is_active) { %> -<td class="is_active"><%= row.active %> -<% } else { %> -<td><%= row.active %> -<% } %> -<% if (row.is_yours) { %> -<% if (row.is_shared) { %> -<td class="command"><a href="/join/<%= row.game_id %>">View</a> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>:<%- row.your_role %>">View</a> -<% } %> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>">View</a> -<% } %> -<% }); %> -<% } else { %> -<tr><td colspan="8">No active games. -<% } %> -</table> diff --git a/views/games.pug b/views/games.pug new file mode 100644 index 0000000..2ab54f1 --- /dev/null +++ b/views/games.pug @@ -0,0 +1,18 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Public Games + if user + meta(http-equiv="refresh" content=300) + body + include header + article + h1 Public Games + + h2 Open + +gametable(0, open_games) + + h2 Active + +gametable(1, active_games) diff --git a/views/head.pug b/views/head.pug new file mode 100644 index 0000000..ae6bf30 --- /dev/null +++ b/views/head.pug @@ -0,0 +1,67 @@ +//- vim:ts=4:sw=4: + +meta(name="viewport" content="width=device-width,height=device-height,initial-scale=1") +link(rel="icon" href="/favicon.svg") +link(rel="stylesheet" href="/fonts/fonts.css") +link(rel="stylesheet" href="/style.css") + +mixin gametable(status,table,hide_title=0) + table + tr + th ID + unless hide_title + th Title + th Scenario + th Players + th Description + case status + when 0 + th Created + when 1 + th Changed + th Turn + when 2 + th Finished + th Result + th + each row in table + tr + td= row.game_id + unless hide_title + td.w: a(href="/info/"+row.title_id)= row.title_name + td.w= row.scenario + td!= row.player_names + td= row.description + case status + when 0 + td.w= row.ctime + when 1 + td.w= row.mtime + if (row.is_active) + td.is_active= row.active + else + td= row.active + when 2 + td.w= row.mtime + td= row.result + td.command + if status === 0 + a(href="/join/"+row.game_id) Join + else + - let cmd = status === 1 ? "Play" : "View" + if row.is_yours + if row.is_shared + a(href="/join/"+row.game_id)= cmd + else + a(href=`/${row.title_id}/play:${row.game_id}:${row.your_role}`)= cmd + else + a(href=`/${row.title_id}/play:${row.game_id}`) View + else + tr + case status + when 0 + td(colspan=7-hide_title) No open games. + when 1 + td(colspan=8-hide_title) No active games. + when 2 + td(colspan=8-hide_title) No finished games. diff --git a/views/header.ejs b/views/header.ejs deleted file mode 100644 index 66f0f2e..0000000 --- a/views/header.ejs +++ /dev/null @@ -1,36 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> -<% if (typeof refresh !== 'undefined' && refresh > 0) { -%> -<meta http-equiv="refresh" content="<%= refresh %>"> -<% } -%> -<title><%= title %></title> -<link rel="icon" href="/favicon.svg"> -<link rel="stylesheet" href="/fonts/fonts.css"> -<link rel="stylesheet" href="/style.css"> -</head> -<body> -<header> -<a href="/"><img src="/images/rally-the-troops.svg" width="48" height="48"></a> -<nav> -<a href="/about">About</a> -<a href="/forum">Forum</a> -<% if (user) { -%> -<% if (user.unread > 0) { -%> -<a href="/inbox">Inbox (<%= unread %>)</a> -<% } else { -%> -<a href="/inbox">Inbox</a> -<% } -%> -<a href="/profile">Profile (<%= user.name %>)</a> -<% } else { -%> -<a href="/signup">Signup</a> -<a href="/login">Login</a> -<% } -%> -</nav> -</header> -<article> -<h1><%= title %></h1> -<% if (typeof flash !== 'undefined' && flash.length > 0) { -%> -<p class="error"><%= flash %></p> -<% } -%> diff --git a/views/header.pug b/views/header.pug new file mode 100644 index 0000000..7eb357b --- /dev/null +++ b/views/header.pug @@ -0,0 +1,15 @@ +header + a(href="/") + img(src="/images/rally-the-troops.svg" width=48 height=48) + nav + a(href="/about") About + a(href="/forum") Forum + if user + if user.unread > 0 + a(href="/inbox") Inbox (#{user.unread}) + else + a(href="/inbox") Inbox + a(href="/profile") Profile (#{user.name}) + else + a(href="/signup") Signup + a(href="/login") Login diff --git a/views/index.ejs b/views/index.ejs deleted file mode 100644 index 1f23381..0000000 --- a/views/index.ejs +++ /dev/null @@ -1,29 +0,0 @@ -<%- include('header', { title: "Rally the Troops!" }) _%> -<style> -.list { display: flex; flex-wrap: wrap; justify-content: left; max-width: 800px; } -.list a { margin: 1em; display: block; } -.list img { box-shadow: 2px 2px 4px 0px rgba(0,0,0,0.5); height: 200px; } -</style> - -<p> -Rally the Troops! is a website where you can play historic games with other -players. - -<p> -Registration and use is free, and there are no ads. - -<div class="list"> -<% - for (let t in titles) { - let title = titles[t]; - if (!title.hidden) { -_%> -<a href="/info/<%- title.title_id %>"><img src="/<%- title.title_id %>/cover.jpg"></a> -<% - } - } -_%> -</div> - -<p> -Join the <a href="https://discord.gg/CBrTh8k84A">Discord</a> server to find players or report bugs. diff --git a/views/index.pug b/views/index.pug new file mode 100644 index 0000000..8ada2fc --- /dev/null +++ b/views/index.pug @@ -0,0 +1,49 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Rally the Troops! + style. + div.list { + max-width: 800px; + display: flex; + flex-wrap: wrap; + justify-content: left; + } + div.list div { + margin: 10px 5px; + text-align: center; + } + div.list a:not(:hover) { + color: black; + text-decoration: none; + } + div.list img { + box-shadow: 2px 2px 4px 0px rgba(0,0,0,0.5); + height: 200px; + margin: 5px 10px; + display: block; + } + body + include header + article + h1 Rally the Troops! + if flash + p.error= flash + + p Rally the Troops! is a website where you can play historic games with other players. + + p Registration and use is free, and there are no ads. + + div.list + each title in titles + unless title.hidden + div + a(href="/info/"+title.title_id) + img(src="/"+title.title_id+"/cover.jpg") + | #{title.title_name} + + p: a(href="/games") List of all open and active games. + + p Join the #[a(href="https://discord.gg/CBrTh8k84A") Discord] server to find players or report bugs. diff --git a/views/info.ejs b/views/info.ejs deleted file mode 100644 index 49625ed..0000000 --- a/views/info.ejs +++ /dev/null @@ -1,80 +0,0 @@ -<%- include('header', { title: title.title_name, refresh: (user ? 300 : 0) }) -%> -<img class="logo" src="/<%= title.title_id %>/cover.jpg"> -<%- include('../public/' + title.title_id + '/about.html') -%> -<p> -Read more about the game on -<a href="https://boardgamegeek.com/boardgame/<%= title.bgg %>">boardgamegeek.com</a>. - -<h2>Open Games</h2> -<table> -<tr><th>ID<th>Scenario<th>Players<th>Description<th>Created<th> -<% if (open_games.length > 0) { -%> -<% open_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.ctime %> -<td class="command"><a href="/join/<%= row.game_id %>">Join</a> -<% }); } else { %> -<tr><td colspan="6">No open games. -<% } %> -</table> - -<p> -<a href="/create/<%= title.title_id %>">Create a new game</a>. - -<% if (active_games.length > 0) { %> -<h2>Active Games</h2> -<table class="game"> -<tr><th>ID<th>Scenario<th>Players<th>Description<th>Changed<th>Turn<th> -<% active_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.mtime %> -<% if (row.is_active) { %> -<td class="is_active"><%= row.active %> -<% } else { %> -<td><%= row.active %> -<% } %> -<% if (row.is_yours) { %> -<% if (row.is_shared) { %> -<td class="command"><a href="/join/<%= row.game_id %>">Play</a> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>:<%- row.your_role %>">Play</a> -<% } %> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>">View</a> -<% } %> -<% }); %> -</table> -<% } %> - -<% if (finished_games.length > 0) { %> -<h2>Finished Games</h2> -<table class="game"> -<tr><th>ID<th>Scenario<th>Players<th>Description<th>Finished<th>Result<th> -<% finished_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.mtime %> -<td><%= row.result %> -<% if (row.is_yours) { %> -<% if (row.is_shared) { %> -<td class="command"><a href="/join/<%= row.game_id %>">View</a> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>:<%- row.your_role %>">View</a> -<% } %> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>">View</a> -<% } %> -<% }); %> -</table> -<% } %> diff --git a/views/info.pug b/views/info.pug new file mode 100644 index 0000000..d3d7da2 --- /dev/null +++ b/views/info.pug @@ -0,0 +1,32 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= title.title_name + if user + meta(http-equiv="refresh" content=300) + body + include header + article + h1= title.title_name + + img.logo(src="/"+title.title_id+"/cover.jpg") + + | !{ about_html } + + p Read more about the game on #[a(href="https://boardgamegeek.com/boardgame/"+title.bgg) boardgamegeek.com]. + + h2 Open games + +gametable(0,open_games,1) + + p + a(href="/create/"+title.title_id) Create a new game + + if active_games.length > 0 + h2 Active games + +gametable(1,active_games,1) + + if finished_games.length > 0 + h2 Finished games + +gametable(2,finished_games,1) diff --git a/views/join.ejs b/views/join.ejs deleted file mode 100644 index e2c626f..0000000 --- a/views/join.ejs +++ /dev/null @@ -1,52 +0,0 @@ -<%- include('header', { title: game.title_name }) -%> -<style> -table { min-width: auto; } -th, td { min-width: 10em; } -a.red { text-decoration: none; color: brown; font-size: 14px; } -td a { text-decoration: underline; color: blue; } -.hide { display: none; } -</style> -<script> -let game = <%- JSON.stringify(game) %>; -let roles = <%- JSON.stringify(roles) %>; -let players = <%- JSON.stringify(players) %>; -let user_id = <%- user.user_id %>; -let ready = <%- ready %>; -</script> -<script src="/join.js"></script> -<p id="error" class="error"></p> - -<a href="/info/<%= game.title_id %>"><img class="logo" src="/<%= game.title_id %>/cover.jpg"></a> - -<div class="info"> -<p> -Owner: <%= game.owner_name %> -<% if (game.private) { %> -(private) -<% } %> -<br> -Scenario: <%= game.scenario %> -<br> -Options: <%= game.options %> - -<p> -<%= game.description || "No description." %> - -<br clear=left> - -<table class="small"> -<tr> -<% roles.forEach((role) => { %> -<th class="command" id="role_<%= role.replace(/ /g, '_') %>_name"><%= role %></th> -<% }); %> -<tr> -<% roles.forEach((role) => { %> -<td class="command" id="role_<%= role.replace(/ /g, '_') %>">-</td> -<% }); %> -<tr> -<td class="command" id="message" colspan="<%= roles.length %>">-</td> -</table> - -<p> -<button class="hide" id="delete_button" onclick="confirm_delete()">Delete</button> -<button class="hide" id="start_button" onclick="javascript:send('/start/<%= game.game_id %>')" disabled>Start!</button> diff --git a/views/join.pug b/views/join.pug new file mode 100644 index 0000000..be95075 --- /dev/null +++ b/views/join.pug @@ -0,0 +1,58 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= game.title_name + style. + table { min-width: auto; } + th,td { min-width: 10em; } + table td a.red { text-decoration: none; color: brown; font-size: 14px; } + td a { text-decoration: underline; color: blue; } + .hide { display: none; } + script. + let game = !{ JSON.stringify(game) }; + let roles = !{ JSON.stringify(roles) }; + let players = !{ JSON.stringify(players) }; + let user_id = !{ user.user_id }; + let ready = !{ ready }; + script(src="/join.js") + body + include header + article + h1= game.title_name + if flash + p.error#error= flash + else + p.error#error + + a(href="/info/"+game.title_id): img.logo(src="/"+game.title_id+"/cover.jpg") + + p + if game.private + | Owner: #{game.owner_name} (private) + else + | Owner: #{game.owner_name} + br + | Scenario: #{game.scenario} + br + | Options: #{game.options} + + p= game.description || "No description." + + br(clear="left") + + p + table + tr + each role in roles + th.command(id="role_"+role.replace(/ /g, "_")+"_name")= role + tr + each role in roles + td.command(id="role_"+role.replace(/ /g, "_")) - + tr + td.command#message(colspan=roles.length) - + + p + button.hide#delete_button(onclick="confirm_delete()") Delete + button.hide#start_button(onclick=`javascript:send('/start/${game.game_id}')` disabled) Start diff --git a/views/login.ejs b/views/login.ejs deleted file mode 100644 index 3e1dd43..0000000 --- a/views/login.ejs +++ /dev/null @@ -1,17 +0,0 @@ -<%- include('header', { title: "Login" }) %> -<% if (user) { %> -<p>You're already logged in! -<% } else { %> -<form action="/login" method="post"> -<p> -<label for="username">Name or mail: </label><br> -<input type="text" id="username" name="username" required> -<p> -<label for="password">Password: </label><br> -<input type="password" id="password" name="password" required> -<p> -<button type="submit">Login</button> -</form> -<p> -<a href="/forgot_password">Forgot password</a> -<% } %> diff --git a/views/login.pug b/views/login.pug new file mode 100644 index 0000000..58a1fd7 --- /dev/null +++ b/views/login.pug @@ -0,0 +1,29 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Login + body + include header + article + h1 Login + if flash + p.error= flash + + if user + p You're already logged in! + else + form(method="post" action="/login") + p + label Name or mail: + br + input(type="text" id="username" name="username" required) + p + label Password: + br + input(type="password" id="password" name="password" required) + p + button(type="submit") Login + p + a(href="/forgot_password") Forgot password diff --git a/views/message_inbox.ejs b/views/message_inbox.ejs deleted file mode 100644 index 626662d..0000000 --- a/views/message_inbox.ejs +++ /dev/null @@ -1,21 +0,0 @@ -<%- include('header', { title: "Inbox" }) -%> -<style> -.unread { background-color: lightyellow; } -</style> -<p><a href="/message/send">Send message</a> -<table class="post"> -<tr><th>From<th>Subject<th>Date -<% if (messages.length > 0) { messages.forEach((row) => { %> -<% if (row.read) { %> -<tr class="read"> -<% } else {%> -<tr> -<% } %> -<td><a href="/user/<%- row.from_name %>"><%= row.from_name %></a> -<td><a href="/message/read/<%- row.message_id %>"><%= row.subject %></a> -<td><%= row.time %> -<% }); } else { %> -<tr><td colspan="3">No messages</td> -<% } %> -</table> -<p><a href="/outbox">Outbox</a> diff --git a/views/message_inbox.pug b/views/message_inbox.pug new file mode 100644 index 0000000..28563d8 --- /dev/null +++ b/views/message_inbox.pug @@ -0,0 +1,31 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Inbox + style .unread { background-color: lightyellow } + body + include header + article + h1 Inbox + + p + a(href="/message/send") Send message + + table + tr + th From + th Subject + th Date + each row in messages + tr(class=row.read?"read":"unread") + td: a(href="/user/"+row.from_name)= row.from_name + td: a(href="/message/read/"+row.message_id)= row.subject + td= row.time + else + tr + td(colspan=3) No messages. + + p + a(href="/outbox") Outbox diff --git a/views/message_outbox.ejs b/views/message_outbox.ejs deleted file mode 100644 index a5d1abd..0000000 --- a/views/message_outbox.ejs +++ /dev/null @@ -1,28 +0,0 @@ -<%- include('header', { title: "Outbox" }) -%> -<style> -.unread { background-color: lightyellow; } -</style> -<script> -function delete_all() { - let warning = "Are you sure you want to delete ALL the messages?"; - if (window.confirm(warning)) - window.location.href = "/outbox/delete"; -} -</script> -<table class="post"> -<tr><th>To<th>Subject<th>Date -<% if (messages.length > 0) { messages.forEach((row) => { %> -<% if (row.read) { %> -<tr class="read"> -<% } else {%> -<tr> -<% } %> -<td><a href="/user/<%- row.to_name %>"><%= row.to_name %></a> -<td><a href="/message/read/<%- row.message_id %>"><%= row.subject %></a> -<td><%= row.time %> -<% }); } else { %> -<tr><td colspan="3">No messages</td> -<% } %> -</table> -<p> -<button onclick="delete_all()">Delete all</button> diff --git a/views/message_outbox.pug b/views/message_outbox.pug new file mode 100644 index 0000000..ee19a2f --- /dev/null +++ b/views/message_outbox.pug @@ -0,0 +1,36 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Outbox + script. + function delete_all() { + let warning = "Are you sure you want to delete ALL the messages?"; + if (window.confirm(warning)) + window.location.href = "/outbox/delete"; + } + body + include header + article + h1 Outbox + + p + a(href="/message/send") Send message + + table + tr + th From + th Subject + th Date + each row in messages + tr + td: a(href="/user/"+row.to_name)= row.to_name + td: a(href="/message/read/"+row.message_id)= row.subject + td= row.time + else + tr + td(colspan=3) No messages. + + p + button(onclick="delete_all()") Delete all diff --git a/views/message_read.ejs b/views/message_read.ejs deleted file mode 100644 index b2f8227..0000000 --- a/views/message_read.ejs +++ /dev/null @@ -1,25 +0,0 @@ -<%- include('header', { title: message.subject }) %> -<style> -th{font-weight:normal;width:4em;} -</style> -<script> -function delete_message(id) { - let warning = "Are you sure you want to DELETE this message?"; - if (window.confirm(warning)) - window.location.href = "/message/delete/" + id; -} -function reply_message(id) { - window.location.href = "/message/reply/" + id; -} -</script> -<table> -<tr><th>From:<td><a href="/user/<%- message.from_name %>"><%= message.from_name %></a> -<tr><th>To:<td><a href="/user/<%- message.to_name %>"><%= message.to_name %></a> -<tr><th>Date:<td><%= message.time %> -<tr><td colspan="2" class="body"><%- message.body %></td> -</table> -<p> -<% if ( 1 || message.from_id !== user.user_id ) { %> -<button onclick="reply_message(<%- message.message_id %>)">Reply</button> -<% } %> -<button onclick="delete_message(<%- message.message_id %>)">Delete</button> diff --git a/views/message_read.pug b/views/message_read.pug new file mode 100644 index 0000000..65b845d --- /dev/null +++ b/views/message_read.pug @@ -0,0 +1,38 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= message.subject + style th { font-weight: normal; width: 4em; } + script. + function delete_message(id) { + let warning = "Are you sure you want to DELETE this message?"; + if (window.confirm(warning)) + window.location.href = "/message/delete/" + id; + } + function reply_message(id) { + window.location.href = "/message/reply/" + id; + } + body + include header + article + h1= message.subject + + table + tr + th From: + td: a(href="/user/"+message.from_name)= message.from_name + tr + th To: + td: a(href="/user/"+message.to_name)= message.to_name + tr + th Date: + td= message.time + tr + td.body(colspan=2)!= message.body + + p + if message.from_id !== user.user_id + button(onclick="reply_message("+message.message_id+")") Reply + button(onclick="delete_message("+message.message_id+")") Delete diff --git a/views/message_send.ejs b/views/message_send.ejs deleted file mode 100644 index cea21e3..0000000 --- a/views/message_send.ejs +++ /dev/null @@ -1,33 +0,0 @@ -<%- include('header', { title: "Send Message" }) -%> -<style> -input, textarea { width: 100%; max-width: 45rem; } -</style> -<form action="/message/send" method="post"> -<p> -To:<br> -<input id="to" type="text" name="to" size="80" maxlength="80" - onkeypress="if(event.keyCode===13){document.querySelector('#subject').focus();return false;}" - value="<%= to_name %>" - <%= (to_name === "") ? "autofocus" : "" %> - required> - -<p> -Subject: -<br> -<input id="subject" type="text" name="subject" size="80" maxlength="80" - onkeypress="if(event.keyCode===13){document.querySelector('#body').focus();return false;}" - value="<%= subject %>" - <%= (to_name !== "" && subject === "") ? "autofocus" : "" %> - pattern=".*\S+.*" - required> - -<p> -Body: -<br> -<textarea id="body" name="body" rows="20" cols="80" maxlength="32000" - <%= (to_name !== "" && subject !== "") ? "autofocus" : "" %> - required> -<%= body %></textarea> -<p> -<button type="submit">Send</button> -</form> diff --git a/views/message_send.pug b/views/message_send.pug new file mode 100644 index 0000000..c573ef6 --- /dev/null +++ b/views/message_send.pug @@ -0,0 +1,68 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Send Message + style. + input, textarea { width: min(45rem,100%) } + script. + function next(event,sel) { + if (event.keyCode === 13) { + document.querySelector(sel).focus(); + return false; + } + return true; + } + + body + include header + article + h1 Send Message + form(method="post" action="/message/send") + + p To: + br + input( + id="to" + type="text" + name="to" + required + size=80 + maxlength=80 + value=to_name + onpress="return next(event,'#subject')" + autofocus=(to_name === "") + ) + + p Subject: + br + input( + id="subject" + type="text" + name="subject" + required + size=80 + maxlength=80 + pattern=".*\\S+.*" + value=subject + onpress="return next(event,'#body')" + autofocus=(to_name !== "" && subject === "") + ) + + p Body: + br + textarea( + id="body" + name="body" + required + cols=80 + rows=20 + maxlength=32000 + autofocus=(to_name !== "" && subject !== "") + ) + | + | #{body} + + p + button(type="submit") Send diff --git a/views/profile.ejs b/views/profile.ejs deleted file mode 100644 index a4a23fc..0000000 --- a/views/profile.ejs +++ /dev/null @@ -1,102 +0,0 @@ -<%- include('header', { title: "Rally the Troops!", refresh: (active_games.length > 0 ? 300 : 0) }) -%> -<img class="avatar" src="<%= avatar %>" width="80" height="80"> -<p> -Welcome, <%= user.name %>! -<p> -Your mail address is <%= user.mail %>. - -<br clear=left> - -<p>» -<% if (user.notify) { %> -<a href="/unsubscribe">Disable mail notifications</a> -<% } else { %> -<a href="/subscribe">Enable mail notifications</a> -<% } %> -<br>» -Change -<a href="/change_password">password</a>, -<a href="/change_mail">mail address</a>, -<a href="/change_name">name</a>, -or <a href="/change_about">profile text</a>. -<br>» -<a href="/chat">Chat log</a> -<br>» -<a href="/logout">Logout</a> - -<% if (open_games.length > 0) { %> -<h2>Open Games</h2> -<table> -<thead> -<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Created<th> -<tbody> -<% open_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.ctime %> -<td class="command"><a href="/join/<%= row.game_id %>">Join</a> -<% }); %> -</table> -<% } %> - -<% if (active_games.length > 0) { %> -<h2>Active Games</h2> -<table class="game"> -<thead> -<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Changed<th>Turn<th> -<tbody> -<% active_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.mtime %> -<% if (row.is_active) { %> -<td class="is_active"><%= row.active %> -<% } else { %> -<td><%= row.active %> -<% } %> -<% if (row.is_shared) { %> -<td class="command"><a href="/join/ -<%= row.game_id %>">Play</a> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>:<%- row.your_role %>">Play</a> -<% } %> -<% }); %> -</table> -<% } %> - -<% if (finished_games.length > 0) { %> -<h2>Finished Games</h2> -<table> -<thead> -<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Finished<th>Result<th> -<tbody> -<% finished_games.forEach((row) => { %> -<tr> -<td><%= row.game_id %> -<td class="w"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> -<td class="w"><%= row.scenario %> -<td><%- row.player_names %> -<td><%= row.description %> -<td class="w"><%= row.mtime %> -<td><%= row.result %> -<% if (row.is_shared) { %> -<td class="command"><a href="/join/<%= row.game_id %>">View</a> -<% } else { %> -<td class="command"><a href="/<%- row.title_id %>/play:<%- row.game_id %>:<%- row.your_role %>">View</a> -<% } %> -<% }); %> -</table> -<% } %> - -<% if (open_games.length === 0 && active_games.length === 0 && finished_games.length === 0) { %> -<p> -You don't have any current or finished games. -<% } %> diff --git a/views/profile.pug b/views/profile.pug new file mode 100644 index 0000000..e43a999 --- /dev/null +++ b/views/profile.pug @@ -0,0 +1,49 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Rally the Troops! + if active_games.length > 0 + meta(http-equiv="refresh" content=300) + body + include header + article + h1 Rally the Troops! + a(href="https://gravatar.com/"): img.avatar(src=avatar) + + p Welcome, #{user.name}! + p Your mail address is #{user.mail} + br(clear="left") + + p + if user.notify + | » <a href="/unsubscribe">Disable mail notifications</a> + else + | » <a href="/subscribe">Enable mail notifications</a> + br + | » + | Change + | <a href="/change_password">password</a>, + | <a href="/change_mail">mail address</a>, + | <a href="/change_name">name</a>, + | or <a href="/change_about">profile text</a>. + br + | » <a href="/chat">Chat log</a> + br + | » <a href="/logout">Logout</a> + + if open_games.length > 0 + h2 Open games + +gametable(0,open_games) + + if active_games.length > 0 + h2 Active games + +gametable(1,active_games) + + if finished_games.length > 0 + h2 Finished games + +gametable(2,finished_games) + + if open_games.length === 0 && active_games.length === 0 && finished_games.length === 0 + p You don't have any current or finished games. diff --git a/views/reset_password.ejs b/views/reset_password.ejs deleted file mode 100644 index 8920da7..0000000 --- a/views/reset_password.ejs +++ /dev/null @@ -1,14 +0,0 @@ -<%- include('header', { title: "Reset password" }) %> -<form action="/reset_password" method="post"> -<p> -<label for="mail">Mail: </label><br> -<input type="text" id="mail" name="mail" size="32" value="<%= mail %>" required> -<p> -<label for="password">New Password: </label><br> -<input type="password" id="password" name="password" size="32" required> -<p> -<label for="token">Token: </label><br> -<input type="text" id="token" name="token" size="32" value="<%= token %>" style="font-family:monospace" required> -<p> -<button type="submit">Reset password</button> -</form> diff --git a/views/reset_password.pug b/views/reset_password.pug new file mode 100644 index 0000000..856433e --- /dev/null +++ b/views/reset_password.pug @@ -0,0 +1,28 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Reset password + body + include header + article + h1 Reset password + if flash + p.error= flash + + form(method="post" action="/reset_password") + p + label Mail: + br + input(type="text" name="mail" size=32 value=mail required) + p + label New Password: + br + input(type="password" name="password" size=32 required) + p + label Token: + br + input(type="text" name="token" size=32 value=token style="font-family:monospace" required) + p + button(type="submit") Reset password diff --git a/views/signup.ejs b/views/signup.ejs deleted file mode 100644 index 819da3f..0000000 --- a/views/signup.ejs +++ /dev/null @@ -1,18 +0,0 @@ -<%- include('header', { title: "Signup" }) %> -<% if (user) { %> -<p>You're already logged in! -<% } else { %> -<form action="/signup" method="post"> -<p> -<label for="username">Name: </label><br> -<input type="text" id="username" name="username" required> -<p> -<label for="mail">Mail: </label><br> -<input type="text" id="mail" name="mail" required> -<p> -<label for="password">Password: </label><br> -<input type="password" id="password" name="password" required> -<p> -<button type="submit">Create Account</button> -</form> -<% } %> diff --git a/views/signup.pug b/views/signup.pug new file mode 100644 index 0000000..e46007a --- /dev/null +++ b/views/signup.pug @@ -0,0 +1,31 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Signup + body + include header + article + h1 Signup + if flash + p.error= flash + + if user + p You're already logged in! + else + form(method="post" action="/signup") + p + label Name: + br + input(type="text" id="username" name="username" required) + p + label Mail: + br + input(type="text" id="mail" name="mail" required) + p + label Password: + br + input(type="password" id="password" name="password" required) + p + button(type="submit") Create account diff --git a/views/stats.ejs b/views/stats.ejs deleted file mode 100644 index 95b52d2..0000000 --- a/views/stats.ejs +++ /dev/null @@ -1,39 +0,0 @@ -<%- include('header', { title: "Game Statistics" }) -%> -<style>tr.blank{height:2rem;border:none;}</style> -<table class="wide"> -<% - function total(t, s) { - return stats - .filter(entry => entry.title_id === t && entry.scenario === s) - .reduce((acc, entry) => acc + entry.count, 0); - } - function result(t, s, r) { - let info = stats.find(entry => { - return entry.title_id === t && - entry.scenario === s && - entry.result === r}); - return info ? info.count : 0; - } - for (let title_id in title_name_map) { - if (title_name_map[title_id].hidden) - continue; - let scenarios = title_rule_map[title_id].scenarios; - let roles = title_role_map[title_id].concat(['Draw']); - %><tr><th><%= title_name_map[title_id].title_name %><% - roles.forEach(role => { - %><th><%= role %><% - }); - scenarios.forEach(scenario => { - let t = total(title_id, scenario); - if (t > 0) { - %><tr><td><%= scenario %> (<%= t %>)<% - roles.forEach(role => { - let r = result(title_id, scenario, role); - %><td><%= Math.round(r * 100 / t) %>%<% - }); - } - }); - %><tr class="blank"><% - } -%> -</table> diff --git a/views/stats.pug b/views/stats.pug new file mode 100644 index 0000000..7634048 --- /dev/null +++ b/views/stats.pug @@ -0,0 +1,45 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title Game Statistics + style. + table { table-layout: fixed; min-width: auto; } + td:nth-child(1) { width: 240px; } + td { width: 100px; } + tr.blank { height: 2rem; border: none; } + body + include header + article + h1 Game Statistics + table + - + function total(t,s) { + return stats + .filter(entry => entry.title_id === t && entry.scenario === s) + .reduce((acc, entry) => acc + entry.count, 0); + } + function result(t,s,r) { + let info = stats.find(entry => entry.title_id === t && entry.scenario === s && entry.result === r); + return info ? info.count : 0; + } + each title_name, title_id in title_name_map + unless title_name_map[title_id].hidden + - let scenarios = title_rule_map[title_id].scenarios; + - let roles = title_role_map[title_id].concat(["Draw"]); + tr + th= title_name_map[title_id].title_name + each role in roles + th= role + each scenario in scenarios + - let t = total(title_id, scenario); + tr + td #{scenario} (#{t}) + each role in roles + if t > 0 + -let r = result(title_id, scenario, role); + td= Math.round(r * 100 / t) + "%" + else + td - + tr.blank diff --git a/views/user.ejs b/views/user.ejs deleted file mode 100644 index 8fd1d08..0000000 --- a/views/user.ejs +++ /dev/null @@ -1,15 +0,0 @@ -<%- include('header', { title: who.name }) %> -<img class="avatar" src="<%= who.avatar %>" width="80" height="80"> -<% if (who.about) { %> -<p style="white-space:pre-wrap;font-style:italic"><%= who.about %></p> -<% } else { %> -<br clear="left"> -<% } %> -<p> -Member since <%= who.ctime %>. -<p> -Last seen <%= who.atime %>. -<% if (user) { %> -<p> -<a href="/message/send/<%- who.name %>">Send message</a> -<% } %> diff --git a/views/user.pug b/views/user.pug new file mode 100644 index 0000000..99420cc --- /dev/null +++ b/views/user.pug @@ -0,0 +1,23 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title= who.name + body + include header + article + h1= who.name + + img.avatar(src=who.avatar width=80 height=80) + + if who.about + p(style="white-space:pre-wrap;font-style:italic")= who.about + else + br(clear="left") + + p Member since #{who.ctime}. + p Last seen #{who.atime}. + if user + p + a(href="/message/send/"+who.name) Send message diff --git a/views/user_list.pug b/views/user_list.pug new file mode 100644 index 0000000..b4383f7 --- /dev/null +++ b/views/user_list.pug @@ -0,0 +1,26 @@ +//- vim:ts=4:sw=4: +doctype html +html + head + include head + title User List + style. + td.avatar { padding: 0; width: 80px; } + td.avatar img { display: block; width: 80px; height: 80px; } + body + include header + article + h1 User List + + table + tr + th Avatar + th Name + th Member since + th Last seen + each row in user_list + tr + td.avatar: img(src=row.avatar) + td.name: a(href="/user/"+row.name)= row.name + td= row.ctime + td= row.atime diff --git a/views/users.ejs b/views/users.ejs deleted file mode 100644 index 9255d04..0000000 --- a/views/users.ejs +++ /dev/null @@ -1,14 +0,0 @@ -<%- include('header', { title: "User list" }) %> -<style> -td.avatar{padding:0;width:80px;} -td.avatar img{display:block;width:80px;height:80px;} -</style> -<table class="post"> -<tr><th>Avatar<th>Name<th>Member since<th>Last seen -<% userList.forEach((row) => { %> -<tr> -<td class="avatar"><img src="<%= row.avatar %>"> -<td class="name"><a href="/user/<%= row.name %>"><%= row.name %></a> -<td><%= row.ctime %> -<td><%= row.atime %> -<% }); %> |