veto

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

commit 1ed896ed725a3dd477f2828d245cf6e6c86e8f7a
parent 9dfb44338e14fffd5a41f919dc45b60107a2483f
Author: Fredrik <moi@knutsen.co>
Date:   Sat, 27 Oct 2018 02:21:55 +0100

Merge pull request #4 from Demonstrandum/devel

Edit and remove option, extra style for home page + mobile improved.
Diffstat:
Mpublic/new.js | 5+++--
Mpublic/styles.css | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mserver.rb | 4++++
Mviews/index.erb | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
4 files changed, 161 insertions(+), 16 deletions(-)

diff --git a/public/new.js b/public/new.js @@ -10,7 +10,7 @@ $('document').ready(() => { name: $('#title').val().trim(), code: $('#code').val(), alt: $('#other').is(':checked'), - primary: Array(...$('#options li').map((i, e) => e.innerHTML)) + primary: Array(...$('#options li span').map((i, e) => e.innerHTML)) }, success: () => { console.info('New poll made.'); @@ -19,6 +19,7 @@ $('document').ready(() => { return false; }); $('#submit-poll').click(() => { + save(); // Save all changes let polls = []; $.ajax({ async: false, @@ -41,7 +42,7 @@ $('document').ready(() => { issue(ISSUE.FATAL, ` The poll link name (the name in the URL) cannot be left blank. `); - } else if (!$('#other').is(':checked') && Array(...$('#options li').map((i, e) => e.innerHTML)).length === 0) { + } 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, diff --git a/public/styles.css b/public/styles.css @@ -1,5 +1,5 @@ @import url('https://fonts.googleapis.com/css?family=Rubik:400,400i,500'); -@import url('//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css'); +@import url('https://use.fontawesome.com/releases/v5.4.1/css/all.css'); html, body { margin: 0; @@ -10,7 +10,7 @@ html, body { overflow-x: hidden; } -body { +html { overflow-y: scroll; } @@ -28,13 +28,86 @@ ul { } #options li { + padding: 5px 10px; margin-top: 20px; + border-radius: 5px; + background: #fff; + transition: all .1s ease; + cursor: pointer; + vertical-align: middle; +} + +#options li input { + background: #111; + color: #eee; + border-bottom: 2px solid #222; + 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: #f2f2f2; +} + +#options li:hover { + background: #222; + color: #fff; +} + +.dark-option { + background: #000 !important; + color: #fff; +} + +#options li span { + vertical-align: middle; + border-bottom: 2px solid transparent; +} + +#options li .symbols { + vertical-align: middle; + float: right; + font-size: 0.8em; +} + +#options li .symbols i { + margin: 0 0 0 3px; + padding: 7px; + vertical-align: middle; + transition: all .15s ease; +} + +#options li .symbols i:hover { + color: #999; } label { font-weight: normal; } +input[type=submit] { + font-weight: normal; + border-color: #000; + color: #fff; + background: #000; + transition: all .1s ease; +} + +input[type=submit]:hover { + background: #1a1a1a; + color: #ddd; +} + +input[type=submit]:focus { + background: #555; + color: #888; +} + input[type=button], button { padding: 0; margin: 0 15px; @@ -85,6 +158,7 @@ input[type=checkbox]:checked + label:before { letter-spacing: 8px; } h1, h2, h3, h4, h5, h6 { font-weight: 500; + color: #000; } h3 { @@ -93,7 +167,7 @@ h3 { .in { margin-left: 0; - margin-top: -7px; + margin-top: -6px; } .in input { @@ -101,7 +175,7 @@ h3 { } #addition { - margin-left: 22px; + margin-left: 32px; } .right { @@ -114,7 +188,7 @@ h3 { } .issues { - position: absolute; + position: fixed; right: 15px; /* Scroll bar */ bottom: 0; overflow: hidden; @@ -126,13 +200,13 @@ h3 { } .issues div { - height: 0; + max-height: 0; width: 15em; opacity: 0; margin: 10px; border-radius: 5px; border-left: 8px solid; - transition: all .2s ease-out; + transition: all .4s ease-out; overflow: hidden; } @@ -144,7 +218,7 @@ h3 { } .issues .show { - height: auto; + max-height: 300px; opacity: 1; } diff --git a/server.rb b/server.rb @@ -65,9 +65,13 @@ def make_poll code, name, alt end $HEAD_TAGS = <<-HTML + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css" /> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" /> <link rel="stylesheet" type="text/css" href="/styles.css" /> + <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" diff --git a/views/index.erb b/views/index.erb @@ -35,7 +35,7 @@ <div class="row"> <div class="twelve columns" style="margin-bottom: 1em"> <input type="checkbox" checked id="other" name="other"> - <label for="other" style="cursor: pointer"> + <label for="other" style="cursor: pointer; user-select: none;"> Allow 'other' option, i.e. alternative choices? </label> </div> @@ -64,19 +64,84 @@ <script src="/main.js"></script> <script src="/new.js"></script> <script> + let editing = NaN; + const add_list = option => { $('#addition').val(''); let adder = $(".option").detach(); $("#options") - .append(`<li>${option}</li>`) + .append(` + <li class="option-item"> + <span>${option}</span> + <div class="symbols"> + <i class="option-edit far fa-edit"></i> + <i class="option-remove fas fa-times"></i> + </div> + </li> + `) .append(adder); $('#addition').focus().select(); }; + + $('#options').on('click', '.option-remove', e => { + const li = $(e.target).closest('li'); + li.slideUp(100, function() { $(this).remove(); }); + console.warn(li[0], 'Element been removed!'); + }); + + const save = () => { + const inputs = $('#options li').children('input'); + + inputs.each(function() { + const value = this.value; + $(this).parent('li').removeClass('dark-option'); + $(this).siblings('span').show().text(value); + $(this).siblings('.symbols').find('.option-edit') + .removeClass('fa-save') + .addClass('fa-edit'); + this.remove(); + }); + }; + + $(document).on('click', e => { + if (!$(e.target).hasClass('editor') && !$(e.target).hasClass('option-item')) { + save(); + editing = NaN; + } + }); + + const edit_mode = li => { + const span = li.find('span'); + span.hide(); + li.addClass('dark-option'); + li.find('.option-edit') + .removeClass('fa-edit') + .addClass('fa-save'); + li.prepend(`<input class="editor" type="text" value="${span.text()}" />`); + li.find('input').focus().select(); + }; + + $('#options').on('click', 'li', e => { + if (e.target.nodeName === 'INPUT') return; + const li = $(e.currentTarget); + console.log(li.index()); + save(); + + if (editing !== li.index()) { + console.log('not same click'); + editing = li.index(); + edit_mode(li); + } else { + editing = NaN; + } + }); + $("#addition").on('keypress', key => { let value = $("#addition").val().trim(); - let values = Array(...$('#options li').map((i, e) => e.innerHTML)); + let values = Array(...$('#options li span').map((i, e) => e.innerHTML)); if (key.which === 13) { + save(); key.preventDefault(); if (value.length === 0) { return $('#addition').attention(); @@ -89,8 +154,9 @@ } }); $('.add-option').click(() => { + save(); let value = $("#addition").val().trim(); - let values = Array(...$('#options li').map((i, e) => e.innerHTML)); + let values = Array(...$('#options li span').map((i, e) => e.innerHTML)); if (value.length === 0) { return $('#addition').attention(); } @@ -104,11 +170,11 @@ </script> <script> $("#title").on('input', () => { - $("#code").val(encodeURI($("#title").val().toLowerCase().replace(/\s/g, '-'))); + $("#code").val(encodeURI($("#title").val().toLowerCase().replace(/\s|\//g, '-'))); }); $("#code").on('input', () => { - $("#code").val(encodeURI($("#code").val().replace(/\s/g, '-'))); + $("#code").val(encodeURI($("#code").val().replace(/\s|\//g, '-'))); }); </script> </body>