Alpha Chen 9 months ago
parent 8bfd17db38
commit 5d845aa69b
Signed by: alpha
SSH Key Fingerprint: SHA256:3fOT8fiYQG/aK9ntivV3Bqtg8AYQ7q4nV6ZgihOA20g

@ -1,50 +0,0 @@
require "phlex"
module RankKing
module Views
class Layout < Phlex::HTML
def initialize(title: nil)
@title = title
end
def template(&block)
doctype
html(lang: "en") do
head do
meta(charset: "utf-8")
meta(name: "viewport", content: "width=device-width, initial-scale=1")
title { ["Rank King", @title].compact.join(" - ") }
end
body do
header do
h1 { "Rank King" }
end
nav
main(&block)
footer
end
end
end
end
class NewPool < Phlex::HTML
def initialize(csrf_token:)
@csrf_token = csrf_token
end
def template
form do
input(type: "hidden", name: "_csrf", value: @csrf_token)
label(for: "name")
input(type: "text", name: "name", id: "name", required: true)
input(type: "submit", value: "Create")
end
end
end
end
end

@ -5,71 +5,133 @@ require_relative "rank_king"
module RankKing
class Web < Roda
plugin :named_templates
plugin :public
plugin :render
plugin :symbol_views
template(:layout) { <<~ERB }
<html>
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1" />
<link rel="stylesheet" href="/static/main.css">
<!-- TODO
<link rel="icon" sizes="16x16 32x32 48x48" type="image/png" href="/icon.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/icon.png" />
<link rel="mask-icon" href="/images/icon.svg" color="#000000" />
-->
<title><%= ["Rank King", @page_title].compact.join(" - ") %></title>
</head>
<body>
<h1>Rank King</h1>
<%= yield %>
<main>
<header>
<a href="/"><h1>Rank King</h1></a>
<nav><!-- TODO --></nav>
</header>
<%= yield %>
</main>
</body>
</html>
ERB
template(:pools) { <<~ERB }
<h2>Pools</h2>
<ul>
<% @pools.each do |pool| %>
<li><a href="/pools/<%= pool.id %>"><%= pool.name %></a></li>
<% end %>
</ul>
<section>
<h1>Pools</h1>
<ul>
<% @pools.each do |pool| %>
<li><a href="/pools/<%= pool.id %>"><%= pool.name %></a></li>
<% end %>
</ul>
</section>
ERB
template(:pool) { <<~ERB }
<h2><%= @pool.name %></h2>
<h3>Axes</h3>
<ul>
<% @pool.axes.each do |axis| %>
<li><a href="/pools/<%= @pool.id %>/axes/<%= axis.id %>"><%= axis.name %></a></li>
<% end %>
</ul>
<h3>Items</h3>
<ol>
<% @pool.items.each do |item| %>
<li><%= item.title %></li>
<% end %>
</ol>
<section>
<h1><%= @pool.name %></h1>
<h2>Axes</h2>
<ul>
<% @pool.axes.each do |axis| %>
<li><a href="/pools/<%= @pool.id %>/axes/<%= axis.id %>"><%= axis.name %></a></li>
<% end %>
</ul>
<h2>Items</h2>
<ol>
<% @pool.items.each do |item| %>
<li><%= item.title %></li>
<% end %>
</ol>
</section>
ERB
template(:axis) { <<~ERB }
<h2><%= @axis.pool.name %> - <%= @axis.name %></h2>
<h3>Items</h3>
<table>
<% @axis.ratings.sort_by { -_1.ordinal }.each.with_index do |rating, i| %>
<tr>
<td><%= i+1 %></td>
<td><%= rating.item.title %></td>
<td><%= rating.ordinal.round(1) %></td>
<td><%= rating.mu.round(1) %></td>
<td><%= rating.sigma.round(1) %></td>
</tr>
<% end %>
</table>
<ul>
<% @game.each do |item| %>
<li><%= item.title %></li>
<% end %>
</ul>
<form method="post" action="/pools/<%= @pool.id %>/axes/<%= @axis.id %>/rank">
<% @game.each.with_index do |item, i| %>
<label><input type="radio" name="winner" value="<%= item.id %>"><%= item.title %></label>
<input type="hidden" name="item_<%= i %>" value="<%= item.id %>">
<section>
<h1><%= @axis.pool.name %> - <%= @axis.name %></h1>
<h2>Items</h2>
<table>
<% @axis.ratings.sort_by { -_1.ordinal }.each.with_index do |rating, i| %>
<tr>
<td><%= i+1 %></td>
<td><%= rating.item.title %></td>
<td><%= rating.ordinal.round(1) %></td>
<td><%= rating.mu.round(1) %></td>
<td><%= rating.sigma.round(1) %></td>
</tr>
<% end %>
<input type="submit">
</form>
</table>
<form method="post" action="/pools/<%= @pool.id %>/axes/<%= @axis.id %>/rank">
<% @game.each.with_index do |item, i| %>
<label><input type="radio" name="winner" value="<%= item.id %>"><%= item.title %></label>
<input type="hidden" name="item_<%= i %>" value="<%= item.id %>">
<% end %>
<input type="submit">
</form>
</section>
ERB
template(:theme) { <<~ERB }
<section>
<div class="surface-samples">
<div class="surface1">1</div>
<div class="surface2">2</div>
<div class="surface3">3</div>
<div class="surface4">4</div>
</div>
</section>
<section>
<div class="text-samples">
<h1 class="text1">
<span class="swatch accent"></span>
Accent
</h1>
<h1 class="text1">
<span class="swatch text1"></span>
Text Color 1
</h1>
<h1 class="text2">
<span class="swatch text2"></span>
Text Color 2
</h1>
<br>
<p class="text1">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p class="text2">Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</section>
ERB
route do |r|
r.on "static" do
r.public
end
r.root do
r.redirect "/pools"
end
@ -77,14 +139,14 @@ module RankKing
r.on "pools" do
r.is do
@pools = Pool.all
view :pools
:pools
end
r.on Integer do |id|
@pool = Pool[id]
r.is do
view :pool
:pool
end
r.on "axes" do
@ -102,12 +164,16 @@ module RankKing
r.is do
@game = RankKing.suggest_game(@axis).shuffle
view :axis
:axis
end
end
end
end
end
r.is "theme" do
:theme
end
end
end
end

@ -0,0 +1,209 @@
html {
max-width: 70ch;
margin: auto;
line-height: 1.75;
font-size: 1.25em;
}
/*
* OKLCH Colors
*
* - https://web.dev/building-a-color-scheme/
* - https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl
* - https://oklch.com/
*/
:root {
/* https://coolors.co/palette/000814-001d3d-003566-ffc300-ffd60a */
--background-lightness: 23%;
--background-chroma: 0.07;
--background-hue: 252;
--text-lightness: 33%;
--text-chroma: 0.10;
--text-hue: 252;
--accent-lightness: 85%;
--accent-chroma: 0.17;
--accent-hue: 86;
--accent: oklch(var(--accent-lightness) var(--accent-chroma) var(--accent-hue));
--background: oklch(90% 0.10 var(--background-hue));
--text: oklch(10% var(--text-chroma) var(--text-hue));
--text1: oklch(10% var(--text-chroma) var(--text-hue));
--text2: oklch(35% calc(0.5 * var(--text-chroma)) var(--text-hue));
/* --selection: oklch(90% 0.17 var(--accent-hue)); */
--a-background: oklch(10% 0.05 var(--background-hue));
}
::selection {
background: var(--selection);
}
body {
background-color: var(--background);
color: var(--text);
}
/* a, a:active, a:visited { */
/* color: var(--selection); */
/* background-color: var(--a-background); */
/* } */
.surface-samples {
display: grid;
--size: 20ch;
grid-template-columns: var(--size) var(--size);
grid-auto-rows: var(--size);
gap: 2ch;
@media (width <= 480px) { & {
--size: 40vw;
}}
& > * {
border-radius: 1rem;
display: grid;
place-content: center;
font-size: 3rem;
font-weight: 200;
}
}
.text-samples {
display: grid;
gap: 1.5ch;
& > h1 {
font-size: 2.5rem;
display: inline-flex;
align-items: center;
gap: 1ch;
}
}
.accent {
color: var(--accent);
background-color: var(--accent);
}
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
.text1 {
color: var(--text1);
@nest p& {
font-weight: 200;
}
}
.text2 {
color: var(--text2);
}
.swatch {
display: inline-block;
flex-shrink: 0;
inline-size: 1.5ch;
block-size: 1.5ch;
border-radius: 50%;
&.text1 { background-color: var(--text1); }
&.text2 { background-color: var(--text2); }
}
/*
* HSL Colors
*
* - https://xeiaso.net/blog/xess-css-variables
* - https://web.dev/building-a-color-scheme/
*/
/*
:root {
--background-color: 43;
--text-color: 200;
--accent-color: 32;
--selection: hsl(var(--accent-color), 80%, 30%, 100%);
--selection-light: hsl(var(--accent-color), 50%, 80%, 100%);
--background: hsl(var(--background-color), 100%, 10%, 100%);
--background-light: hsl(var(--background-color), 10%, 95%, 100%);
--text: hsl(var(--text-color), 0%, 90%, 100%);
--text-light: hsl(var(--text-color), 90%, 5%, 100%);
--pre-background: hsl(var(--background-color), 90%, 5%, 100%);
--pre-background-light: hsl(var(--background-color), 10%, 80%, 100%);
--a-background: hsl(var(--background-color), 90%, 5%, 100%);
--a-background-light: hsl(var(--background-color), 30%, 90%, 100%);
--a-color: hsl(var(--accent-color), 70%, 85%, 100%);
--a-color-light: hsl(var(--accent-color), 80%, 10%, 100%);
--blockquote-border: 0.5ch solid hsl(var(--accent-color), 80%, 80%, 100%);
--blockquote-border-light: 0.5ch solid hsl(var(--accent-color), 50%, 30%, 100%);
}
::selection {
background: var(--selection);
}
body {
background: var(--background);
color: var(--text);
}
pre {
background-color: var(--pre-background);
}
a, a:active, a:visited {
color: var(--selection);
background-color: var(--a-background);
}
blockquote {
border-left: var(--blockquote-border);
}
@media (prefers-color-scheme: light) {
::selection {
background: var(--selection-light);
}
body {
background: var(--background-light);
color: var(--text-light);
}
pre {
background-color: var(--pre-background-light);
}
a, a:active, a:visited {
color: var(--a-color-light);
background-color: var(--a-background-light);
}
blockquote {
border-left: var(--blockquote-border-light);
}
}
*/

@ -3,6 +3,10 @@ require "minitest"
require "rank_king"
class TestRankKing < Minitest::Test
def run(*args, &block)
DB.transaction(rollback: :always, auto_savepoint: true) { super }
end
def setup
@pool = Pool.create(name: "pool")
@axis = Axis.create(pool: @pool, name: "axis")

Loading…
Cancel
Save