veto

Simple Sinatra voting website.
git clone git://git.knutsen.co/veto
Log | Files | Refs | README | LICENSE

commit 5639136aae14f124da8e9109cb67078969a35bfb
parent 121e64e63e7b916f2499d238661f2edd34e48f98
Author: knutsen <samuel@knutsen.co>
Date:   Sat, 19 Jun 2021 17:41:24 +0100

Few tweaks wording and UI.

Diffstat:
Mpublic/new.js | 24+++++++++++++++---------
Mpublic/poller.js | 1+
Mpublic/styles.css | 55++++++++++++++++++++++++++++++++++++++-----------------
Mserver.rb | 10++++++----
Mviews/index.erb | 11+++++------
Mviews/oops.erb | 13++++++-------
Mviews/poll.erb | 2+-
Mviews/share.erb | 2+-
8 files changed, 73 insertions(+), 45 deletions(-)

diff --git a/public/new.js b/public/new.js @@ -1,5 +1,9 @@ $('document').ready(() => { - $('.url').text(`${window.location.host}/poll/`) + $('.url').text(`${window.location.host}/poll/`); + $('#other').on('change', () => + $('#word-primary').css({ + display: $('#other').is(':checked') ? 'inline' : 'none' + })); $('#create').submit(() => { $.ajax({ @@ -49,8 +53,8 @@ $('document').ready(() => { } else if (!$('#other').is(':checked') && Array(...$('#options li span').map((i, e) => e.innerHTML)).length === 0) { $('#addition').attr('placeholder', 'Add at least 1 option.').attention(); issue(ISSUE.WARN, ` - Unless you allow for 'other' options, - you need to add at least one primary option. + Unless you allow for alternative voting options, + you must add at least one primary option. `); } else if (polls.includes($('#code').val())) { issue(ISSUE.FATAL, ` @@ -105,14 +109,15 @@ const save = () => { inputs.each(function() { const value = this.value; if (value.length === 0) { - issue(ISSUE.FATAL, `Cannot leave new value empty. Delete it if you don't want it.`); - bad_input = $(this); - return; + bad_input = 'removed'; + setTimeout(() => + $(this).parent('li').find('.option-remove').click(), 100); + return false; } if (values.includes(value)) { issue(ISSUE.FATAL, `Cannot have duplicate (primary) options/choices!`); bad_input = $(this); - return; + return false; } $(this).parent('li').removeClass('dark-option'); @@ -124,8 +129,9 @@ const save = () => { }); if (bad_input !== null) { - bad_input.attention(); - return false; + if (bad_input !== 'removed') + bad_input.attention(); + return true; } let value = $("#addition").val().trim(); diff --git a/public/poller.js b/public/poller.js @@ -9,6 +9,7 @@ const dp = (number, places = 2) => const BASE = getVarCSS('fg-rgb'); Chart.defaults.global.elements.arc.borderColor = `rgba(${BASE},0.1)`; Chart.defaults.global.defaultColor = `rgba(${BASE},0.1)`; +Chart.defaults.global.defaultFontFamily = getVarCSS('body-font'); const POLL_CODE = window.location.pathname.split('/').slice(-1); diff --git a/public/styles.css b/public/styles.css @@ -1,6 +1,12 @@ @import url('https://fonts.googleapis.com/css?family=Rubik:400,400i,500'); +@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap'); :root { + --fallback-sans: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; + --head-font: 'Rubik', var(--fallback-sans); + --body-font: 'Inter', var(--fallback-sans); + --mono-font: monospace; + /* Colours for light theme. */ --bg: #fff; --fg: #000; --bg-rgb: 255, 255, 255; @@ -9,6 +15,7 @@ @media (prefers-color-scheme: dark) { :root { + /* Colours for dark theme */ --bg: #090909; --fg: #fff; --bg-rgb: 009, 009, 009; @@ -25,7 +32,7 @@ html, body { padding: 0; font-size: 16px; min-height: 100vh; - font-family: 'Rubik', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif; + font-family: var(--body-font); color: var(--fg); background: var(--bg); overflow-x: hidden; @@ -78,18 +85,13 @@ ul { #options li input { background: var(--fg); color: var(--bg); - border-bottom: 2px solid #222; + border-bottom: 2px solid rgba(var(--bg-rgb), 0.2); padding: 0 5px; margin: 0; display: inline-block; height: 1.6em; line-height: 0px; margin: 0; - border-radius: 2px; -} - -#options li:nth-of-type(2n) { - background: rgba(var(--fg-rgb), 0.8); } #options li:hover { @@ -130,20 +132,19 @@ label { input[type=submit] { font-weight: normal; - border-color: #000; + border-color: rgba(var(--fg-bg), 0.1); color: var(--bg); background: var(--fg); transition: all .1s ease; } input[type=submit]:hover { - background: #1a1a1a; - color: #ddd; + background: rgba(var(--fg-rgb), 0.1); + color: rgba(var(--fg-rgb), 0.6); } input[type=submit]:active { - background: #555; - color: #888; + background: rgba(var(--fg-rgb), 0.5); } input[type=button], button { @@ -151,7 +152,7 @@ input[type=button], button { margin: 0 15px; border: none; border-radius: 0; - border-bottom: 1px solid #aaa; + border-bottom: 1px solid rgba(var(--fg-rgb), 0.1); height: 36px; letter-spacing: normal; font-weight: normal; @@ -164,14 +165,14 @@ input[type=text] { padding: 0; border: none; border-radius: 0px; - border-bottom: 1px solid #aaa; + border-bottom: 1px solid rgba(var(--fg-rgb), 0.1); transition: all .15s ease; } input[type=text]:focus { outline: none; border: none; - border-bottom: 1px solid #aaa; + border-bottom: 1px solid rgba(var(--fg-rgb), 0.1); } input[type=checkbox] { display:none; } @@ -179,6 +180,8 @@ input[type=checkbox] + label:before { display: inline-block; font-style: normal; font-variant: normal; + font-size: 1.3em; + vertical-align: middle; text-rendering: auto; -webkit-font-smoothing: antialiased; } @@ -196,7 +199,8 @@ input[type=checkbox]:checked + label:before { } #code { - color: #aaa; + font-family: var(--mono-font); + color: rgba(var(--fg-rgb), 0.6); } .problem:focus { @@ -206,6 +210,7 @@ input[type=checkbox]:checked + label:before { } h1, h2, h3, h4, h5, h6 { + font-family: var(--head-font); font-weight: 500; color: var(--fg); } @@ -269,10 +274,26 @@ footer span { } .url { + font-family: var(--mono-font); word-break: break-all; display: block; font-size: 1em; - color: #aaa; + color: rgba(var(--fg-rgb), 0.6); +} + +.voting-options { + border-left-width: 0.5em; + border-left-style: solid; + border-image: linear-gradient(to bottom, + rgba(var(--fg-rgb), 0.20) 0%, + rgba(var(--fg-rgb), 0.14) 11%, + rgba(var(--fg-rgb), 0.12) 28%, + rgba(var(--fg-rgb), 0.10) 43%, + rgba(var(--fg-rgb), 0.06) 57%, + rgba(var(--fg-rgb), 0.03) 75%, + rgba(var(--fg-rgb), 0.01) 90%, + rgba(var(--fg-rgb), 0.00) 100%) 1 100%; + padding-left: 1em; } .issues { diff --git a/server.rb b/server.rb @@ -42,6 +42,8 @@ class String end end +DESC = "Create real time straw polls. " + + "Easy to use, Free and Open Source Software." HEAD_TAGS = <<-HTML <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> @@ -57,20 +59,20 @@ HEAD_TAGS = <<-HTML </script> <!-- Search Engine --> - <meta name="description" content="Create a real time straw poll with veto.vote. Easy to use, completely free with graphs and statistics already provided."> + <meta name="description" content="#{DESC}"> <meta name="image" content="https://veto.vote/square.png"> <!-- Schema.org for Google --> <meta itemprop="name" content="Veto Vote — Straw Polls"> - <meta itemprop="description" content="Create a real time straw poll with veto.vote. Easy to use, completely free with graphs and statistics already provided."> + <meta itemprop="description" content="#{DESC}"> <meta itemprop="image" content="https://veto.vote/square.png"> <!-- Twitter --> <meta name="twitter:card" content="summary"> <meta name="twitter:title" content="Veto Vote — Straw Polls"> - <meta name="twitter:description" content="Create a real time straw poll with veto.vote. Easy to use, completely free with graphs and statistics already provided."> + <meta name="twitter:description" content="#{DESC}"> <meta name="twitter:image:src" content="https://veto.vote/square.png"> <!-- Open Graph general (Facebook, Pinterest & Google+) --> <meta name="og:title" content="Veto Vote — Straw Polls"> - <meta name="og:description" content="Create a real time straw poll with veto.vote. Easy to use, completely free with graphs and statistics already provided."> + <meta name="og:description" content="#{DESC}"> <meta name="og:image" content="https://veto.vote/card.png"> <meta name="og:url" content="https://veto.vote/"> <meta name="og:site_name" content="Veto Vote — Straw Polls"> diff --git a/views/index.erb b/views/index.erb @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <title>Veto Vote - Create a Poll</title> + <title>Veto Vote — Create a Poll</title> <%= head_tags %> </head> <body> @@ -22,7 +22,7 @@ <div class="row"> <div class="three columns"> - Poll URL name + Poll UID </div> <div class="three columns right"> <span class="url"><span> @@ -36,15 +36,14 @@ <div class="twelve columns" style="margin-bottom: 1em"> <input type="checkbox" checked id="other" name="other"> <label for="other" style="cursor: pointer; user-select: none;"> - Allow 'other' option, i.e. alternative choices? + Allow for respondents to write in alternative votes? </label> </div> </div> - - <div class="row"> + <div class="row voting-options"> <div class="twelve columns"> - Primary Options/Choices: + <span id="word-primary">Primary </span>Voting Options: <ul id="options"> <div class="option"> <input type="text" autocomplete="off" name="addition" id="addition" placeholder="..."> diff --git a/views/oops.erb b/views/oops.erb @@ -1,15 +1,12 @@ <!DOCTYPE html> <html lang="en" dir="ltr"> <head> - <title>404 - Veto Vote</title> + <title>404 — Veto Vote</title> <%= head_tags %> <style media="screen"> - @import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); - .container { width: 24em; } - .container p:nth-of-type(2) { color: #555; } @@ -20,8 +17,10 @@ text-align: center; } h3 span { - font-family: 'Roboto Mono', monospace; + font-family: var(--mono-font); } + a { color: #666; } + a:hover { color: #555; } </style> </head> <body> @@ -30,7 +29,7 @@ <h2>That's a 404.</h2> <h3> - <span>`<%= request.url.split('//')[-1] %>'</span> + <span>« /poll/<%= request.url.split('/')[-1] %> »</span> <br /> does not exist. </h3> @@ -41,7 +40,7 @@ <p> If you believe this link should be correct, and the webservice is at fault, please email me - at <u>moi@knutsen.co</u> with deatils of the problem. + at <a href="mailto:admin@knutsen.co">admin@knutsen.co</a> with deatils of the problem. </p> </div> </body> diff --git a/views/poll.erb b/views/poll.erb @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <title><%= name %> | Veto Vote</title> + <title><%= name %> — Veto Vote</title> <%= head_tags %> <script type="text/javascript"> let other_allowed = true; diff --git a/views/share.erb b/views/share.erb @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <title>Share Poll | Veto Vote</title> + <title>Share Poll — Veto Vote</title> <%= head_tags %> <style media="screen"> body, html {