summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-06-11 02:06:51 +0200
committerTor Andersson <tor@ccxvii.net>2022-06-11 13:36:18 +0200
commit8175df9f9af2393964f053af5a98851c376e1675 (patch)
treea08a63eadf33599dc186a3586ea656bf2724969b
parenta747178b4336480feee79d8f90afc5a2ab6ffc87 (diff)
downloadserver-8175df9f9af2393964f053af5a98851c376e1675.tar.gz
Use game boxes instead of tables.
-rw-r--r--public/style.css104
-rw-r--r--server.js93
-rw-r--r--tools/gencovers.sh9
-rw-r--r--views/games_active.pug10
-rw-r--r--views/games_finished.pug2
-rw-r--r--views/games_public.pug14
-rw-r--r--views/head.pug117
-rw-r--r--views/info.pug15
8 files changed, 207 insertions, 157 deletions
diff --git a/public/style.css b/public/style.css
index f4d677c..e7a87c8 100644
--- a/public/style.css
+++ b/public/style.css
@@ -37,7 +37,7 @@ article p, article dl, article ul { max-width: 50rem; }
img.avatar {
float: left; margin: 0 20px 5px 0;
- box-shadow: 2px 2px 4px 0px rgba(0,0,0,.5);
+ box-shadow: 1px 2px 4px rgba(0,0,0,0.3);
width: 80px;
height: 80px;
}
@@ -49,30 +49,9 @@ div.logo {
height: 200px;
}
div.logo img {
- box-shadow: 2px 2px 4px 0px rgba(0,0,0,0.5);
+ box-shadow: 1px 2px 4px 0px rgba(0,0,0,0.3);
}
-table {
- min-width: min(50rem,100%);
- border-collapse: collapse;
- border: 1px solid black;
-}
-thead, tfoot {
- background-color: gainsboro;
- border: 1px solid black;
-}
-th, td {
- vertical-align: top;
- text-align: left;
- padding: 5px 10px;
-}
-tbody tr:nth-child(2n) {
- background-color: whitesmoke;
-}
-table a:not(:hover) { text-decoration: none; color: black; }
-td.command a { text-decoration: underline; color: blue; }
-td.is_active { background-color: lemonchiffon; }
-
input[type="checkbox"] {
margin-right: 7px;
}
@@ -107,10 +86,37 @@ button:disabled {
.warning { color: brown; }
p.warning::before { content: "\26a0"; }
+/* TABLES */
+
+table {
+ min-width: min(50rem,100%);
+ border-collapse: collapse;
+ border: 1px solid black;
+ box-shadow: 1px 2px 4px rgba(0,0,0,0.2);
+}
+thead, tfoot {
+ background-color: gainsboro;
+ border: 1px solid black;
+}
+th, td {
+ vertical-align: top;
+ text-align: left;
+ padding: 5px 10px;
+}
+tbody tr:nth-child(2n) {
+ background-color: whitesmoke;
+}
+table a:not(:hover) { text-decoration: none; color: black; }
+td.command a { text-decoration: underline; color: blue; }
+td.is_active { background-color: lemonchiffon; }
+
+/* FORUM AND MESSAGE POSTS */
+
div.post {
max-width: 50em;
margin-top: 24px;
border: 1px solid black;
+ box-shadow: 1px 2px 4px rgba(0,0,0,0.2);
}
div.post > div.head {
display: flex;
@@ -127,3 +133,55 @@ div.post + div.edit { max-width: 50em; margin-top: 5px; text-align:right; }
article hr { max-width: 50rem; margin-right: auto; margin-left: 0; }
article hr { border: none; border-top: 2px dotted brown; }
article hr + p { font-style: italic; }
+
+/* GAME BOXES */
+
+.game_list {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(0, 400px));
+ gap: 24px;
+}
+.game_item {
+ border: 1px solid black;
+ box-shadow: 1px 2px 4px rgba(0,0,0,0.2);
+}
+.game_head, .game_main {
+ display: flex;
+ justify-content: space-between;
+ padding: 4px 8px;
+}
+.game_head {
+ border-bottom: 1px solid black;
+}
+.game_info {
+ font-family: "Source Serif SmText", "Dingbats", "Noto Emoji", "Georgia", serif;
+ font-size: 14px;
+ line-height: 20px;
+}
+.game_item a:not(:hover) { text-decoration: none; color: black; }
+.game_item a.command { text-decoration: underline; font-weight: bold }
+.game_info .is_active { text-decoration: underline }
+.game_info div {
+ text-indent: -20px;
+ padding-left: 20px;
+}
+.game_main img {
+ display: block;
+ height: 72px;
+ margin: 4px 0;
+ border: 1px solid black;
+}
+.game_head { background-color: gainsboro }
+.game_main { background-color: whitesmoke }
+.game_list.open .game_head { background-color: lightskyblue }
+.game_list.open .game_main { background-color: aliceblue }
+.game_list.replacement .game_head { background-color: thistle }
+.game_list.replacement .game_main { background-color: lavenderblush }
+.game_list.finished .game_head { background-color: silver }
+.game_list.finished .game_main { background-color: gainsboro }
+.game_item.your_turn .game_head { background-color: gold }
+.game_item.your_turn .game_main { background-color: ivory }
+.game_list a:hover { color: navy }
+.game_list.open a:hover { color: blue }
+.game_list.replacement a:hover { color: purple }
+.game_item.your_turn a:hover { color: maroon }
diff --git a/server.js b/server.js
index ad13b88..e8d9c14 100644
--- a/server.js
+++ b/server.js
@@ -1009,14 +1009,6 @@ function is_active(game, players, user_id) {
return false
}
-function is_shared(game, players, user_id) {
- let n = 0
- for (let i = 0; i < players.length; ++i)
- if (players[i].user_id === user_id)
- ++n
- return n > 1
-}
-
function is_solo(players) {
return players.every(p => p.user_id === players[0].user_id)
}
@@ -1027,53 +1019,60 @@ function format_options(options) {
if (k === false) return 'no'
return k.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase())
}
- if (!options || options === '{}')
- return "None"
- options = JSON.parse(options)
return Object.entries(options||{}).map(([k,v]) => (v === true || v === 1) ? to_english(k) : `${to_english(k)}=${to_english(v)}`).join(", ")
}
function annotate_game(game, user_id) {
let players = SQL_SELECT_PLAYERS_JOIN.all(game.game_id)
+ let options = JSON.parse(game.options)
- game.human_options = format_options(game.options)
- game.is_ready = RULES[game.title_id].ready(game.scenario, JSON.parse(game.options), players)
- game.is_active = is_active(game, players, user_id)
- game.is_shared = is_shared(game, players, user_id)
- game.is_yours = false
- game.your_role = null
-
- game.player_names = players.map(p => {
- let name = p.name.replace(/ /g, '\xa0')
- if (p.user_id > 0)
- name = `<a href="/user/${p.name}">${name}</a>`
- return name
- }).join(", ")
-
- if (user_id > 0) {
- for (let i = 0; i < players.length; ++i) {
- if (players[i].user_id === user_id) {
- game.is_yours = 1
- game.your_role = players[i].role
- }
- }
- }
+ if (game.options === '{}')
+ game.human_options = "None"
+ else
+ game.human_options = format_options(options)
- if (!game.is_shared) {
- for (let i = 0; i < players.length; ++i) {
- if (game.active === players[i].role) {
- game.active = `<a href="/user/${players[i].name}">${players[i].name}</a>`
- break
- }
+ game.is_ready = RULES[game.title_id].ready(game.scenario, options, players)
+
+ let your_count = 0
+ let your_role = null
+ game.player_names = ""
+ for (let i = 0; i < players.length; ++i) {
+ let p = players[i]
+
+ if (p.user_id === user_id) {
+ your_role = p.role
+ your_count++
}
- if (game.status > 1) {
- for (let i = 0; i < players.length; ++i) {
- if (game.result === players[i].role) {
- game.result = `<a href="/user/${players[i].name}">${players[i].name}</a>`
- break
- }
- }
+
+ let p_is_active = false
+ if (game.status === 0 && (game.owner_id === p.user_id))
+ p_is_active = true
+ if (game.status === 1 && (game.active === p.role || game.active === "Both" || game.active === "All"))
+ p_is_active = true
+
+ let link
+ if (p_is_active) {
+ link = `<span class="is_active"><a href="/user/${p.name}">${p.name}</a></span>`
+ if (p.user_id === user_id)
+ game.your_turn = true
+ } else {
+ link = `<a href="/user/${p.name}">${p.name}</a>`
}
+
+ if (game.player_names.length > 0)
+ game.player_names += ", "
+ game.player_names += link
+
+ if (game.active === p.role)
+ game.active = link
+ if (game.result === p.role)
+ game.result = `${link} (${game.result})`
+ }
+
+ if (your_count > 0) {
+ game.is_yours = true
+ if (your_count === 1)
+ game.your_role = your_role
}
game.ctime = human_date(game.ctime)
@@ -2064,7 +2063,7 @@ app.get('/stats', function (req, res) {
let stats = SQL_GAME_STATS.all()
stats.forEach(row => {
row.title_name = TITLES[row.title_id].title_name
- row.options = format_options(row.options)
+ row.options = format_options(JSON.parse(row.options))
row.result_role = row.result_role.split(",")
row.result_count = row.result_count.split(",").map(Number)
})
diff --git a/tools/gencovers.sh b/tools/gencovers.sh
index 911a050..a0ec53d 100644
--- a/tools/gencovers.sh
+++ b/tools/gencovers.sh
@@ -2,12 +2,17 @@ for F in public/*/cover.jpg
do
echo Processing: $F
B=$(echo $F | sed s/.jpg//)
+ D=$(dirname $F)
- convert -scale 200x200 $F $B.1x.png
+ convert -resize 200x200 $F $B.1x.png
mozjpeg -q 95 -outfile $B.1x.jpg $B.1x.png
rm -f $B.1x.png
- convert -scale 400x400 $F $B.2x.png
+ convert -resize 400x400 $F $B.2x.png
mozjpeg -q 90 -outfile $B.2x.jpg $B.2x.png
rm -f $B.2x.png
+
+ convert -resize 108x144! $F $D/thumbnail.png
+ mozjpeg -q 90 -outfile $D/thumbnail.jpg $D/thumbnail.png
+ rm -f $D/thumbnail.png
done
diff --git a/views/games_active.pug b/views/games_active.pug
index 49d20d8..16d8ceb 100644
--- a/views/games_active.pug
+++ b/views/games_active.pug
@@ -13,24 +13,24 @@ html
if ready_games.length > 0
h2 Ready to start
- +gametable(0,ready_games)
+ +gamelist(ready_games, "ready")
if open_games.length > 0
h2 Open
- +gametable(0,open_games)
+ +gamelist(open_games, "open")
if replacement_games.length > 0
h2 Need replacement
- +gametable(0, replacement_games)
+ +gamelist(replacement_games, "replacement")
if active_games.length > 0
h2 Active
- +gametable(1,active_games)
+ +gamelist(active_games, "active")
if finished_games.length > 0
h2 Recently finished
- +gametable(2,finished_games)
+ +gamelist(finished_games, "finished")
p <a href="/games/finished">All your finished games</a>
diff --git a/views/games_finished.pug b/views/games_finished.pug
index 59c0491..c6fa66d 100644
--- a/views/games_finished.pug
+++ b/views/games_finished.pug
@@ -10,6 +10,6 @@ html
h1 Your finished games
if finished_games.length > 0
- +gametable(2,finished_games)
+ +gamelist(finished_games, "finished")
else
p Nothing here.
diff --git a/views/games_public.pug b/views/games_public.pug
index 4af36bd..a681419 100644
--- a/views/games_public.pug
+++ b/views/games_public.pug
@@ -12,15 +12,21 @@ html
h1 All Public Games
h2 Open
- +gametable(0, open_games)
+ if open_games.length > 0
+ +gamelist(open_games, "open")
+ else
+ p No open games.
if replacement_games.length > 0
h2 Need replacement
- +gametable(0, replacement_games)
+ +gamelist(replacement_games, "replacement")
if ready_games.length > 0
h2 Ready to start
- +gametable(0, ready_games)
+ +gamelist(ready_games, "ready")
h2 Active
- +gametable(1, active_games)
+ if active_games.length > 0
+ +gamelist(active_games, "active")
+ else
+ p No open games.
diff --git a/views/head.pug b/views/head.pug
index 0a1052a..911def4 100644
--- a/views/head.pug
+++ b/views/head.pug
@@ -34,75 +34,54 @@ mixin forumpost(row,show_buttons)
|
| #[a(href="/forum/reply/"+row.post_id) Reply]
-mixin gametable(status,table,hide_title=0)
- table
- thead
- tr
- th ID
- unless hide_title
- th Title
- th Scenario
- th Players
- th Description
- case status
- when 0
- th Date
- when 1
- th Changed
- th Turn
- when 2
- th Finished
- th Result
- th
- tbody
- each row in table
- tr
- td: a(href="/join/"+row.game_id)= row.game_id
- unless hide_title
- td.w: a(href="/"+row.title_id)= row.title_name
- td= row.scenario
- if row.player_names
- td!= row.player_names
- else
- td.error Nobody
- td= row.description
- if row.status === 0
- td.w= row.ctime
- else
- td.w= row.mtime
- case status
- when 1
- if (row.is_active)
- td.is_active!= row.active
- else
- td!= row.active
- when 2
- td!= row.result
- td.command
- if status === 0
- a(href="/join/"+row.game_id) Join
- else if status === 1
- if row.is_yours
- if row.is_shared
- a(href="/join/"+row.game_id) Play
+mixin gamelist(list,status,hide_title=0)
+ div.game_list(class=status)
+ each item in list
+ div
+ div.game_item(class=item.your_turn ? "your_turn" : "")
+ div.game_head
+ if item.scenario.length <= 2
+ div
+ | <a href="/join/#{item.game_id}">#{item.game_id}</a> &#x2013;
+ | <a href="/#{item.title_id}">#{item.title_name}</a>
+ | (#{item.scenario})
+ else
+ div
+ | <a href="/join/#{item.game_id}">#{item.game_id}</a> &#x2013;
+ | <a href="/#{item.title_id}">#{item.title_name}</a>
+
+ if item.status === 0 || !item.is_ready
+ a(class="command" href=`/join/${item.game_id}`) Join
+ else
+ if item.is_yours
+ - let verb = (item.status > 1) ? "Review" : "Play"
+ if item.your_role
+ a(class="command" href=`/${item.title_id}/play:${item.game_id}:${item.your_role}`)= verb
else
- a(href=`/${row.title_id}/play:${row.game_id}:${row.your_role}`) Play
+ a(class="command" href="/join/"+item.game_id)= verb
else
- a(href=`/${row.title_id}/play:${row.game_id}`) View
- else if status >= 2
- if row.is_yours
- if row.is_shared
- a(href="/join/"+row.game_id) View
- else
- a(href=`/${row.title_id}/play:${row.game_id}:${row.your_role}`) View
+ - let verb = (item.status > 1) ? "Review" : "View"
+ a(class="command" href=`/${item.title_id}/play:${item.game_id}`)= verb
+
+ div.game_main
+ div.game_info
+ if item.description
+ i= item.description
+ if item.scenario !== "Standard" && item.scenario !== "Historical" && item.scenario.length > 2
+ div Scenario: #{item.scenario}
+ unless item.human_options === "None"
+ div Options: #{item.human_options}
+ if item.player_names
+ div Players: !{item.player_names}
else
- a(href=`/${row.title_id}/replay:${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.
+ div Players: <span class="error">Nobody</span>
+ case item.status
+ when 0
+ div Created: #{item.ctime}
+ when 1
+ div Changed: #{item.mtime}
+ when 2
+ div Finished: #{item.mtime}
+ div Result: !{item.result}
+ unless hide_title
+ img(src=`/${item.title_id}/thumbnail.jpg`)
diff --git a/views/info.pug b/views/info.pug
index 785ee91..c7083ef 100644
--- a/views/info.pug
+++ b/views/info.pug
@@ -20,23 +20,26 @@ html
p Read more about the game on #[a(href="https://boardgamegeek.com/boardgame/"+title.bgg) boardgamegeek.com].
h2 Open
- +gametable(0,open_games,1)
+ if open_games.length > 0
+ +gamelist(open_games, "open", true)
+ else
+ p No open games.
if replacement_games.length > 0
h2 Need replacement
- +gametable(0, replacement_games)
+ +gamelist(replacement_games, "replacement", true)
p
a(href="/create/"+title.title_id) Create a new game
if ready_games.length > 0
h2 Ready to start
- +gametable(0,ready_games,1)
+ +gamelist(ready_games, "ready", true)
if active_games.length > 0
h2 Active
- +gametable(1,active_games,1)
+ +gamelist(active_games, "active", true)
if finished_games.length > 0
- h2 Finished
- +gametable(2,finished_games,1)
+ h2 Recently finished
+ +gamelist(finished_games, "finished", true)