mirror of
https://github.com/Wolvan/poll.horse.git
synced 2024-11-22 04:58:00 +01:00
Create voting page
This page displays all options that have been set on creation. Thanks to `textFit` the texts in the title and options automatically get sized correctly. The create poll button has also been renamed to submit-button to make it more universal on other pages.
This commit is contained in:
parent
5b5dc9d922
commit
edff19fb5b
6 changed files with 137 additions and 10 deletions
|
@ -31,3 +31,8 @@ Execute the scripts with `npm run <script>`
|
|||
- `test` - Runs `lint`, `find-todo` and `mocha` in order
|
||||
- `debug` - Start the `./src/main.ts` with node and start the debugger on port 9229
|
||||
- `start` - Run `test` and `build`, then try and execute the `./dist/main.js` in the `./dist` directory to test
|
||||
|
||||
## Components
|
||||
This project makes use of the following components. Thanks a lot to the respective creators:
|
||||
|
||||
- [textFit](https://github.com/STRML/textFit)
|
|
@ -44,7 +44,7 @@
|
|||
<span>Multiple Choice</span>
|
||||
</label>
|
||||
<br>
|
||||
<input type="submit" name="submit" value="Create poll" id="create-poll">
|
||||
<input type="submit" name="submit" value="Create poll" id="submit-button">
|
||||
</form>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
@ -4,10 +4,56 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ TITLE }}</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<script type="text/javascript" src="/static/js/textfit.js" defer="true"></script>
|
||||
<script type="text/javascript">
|
||||
const textFitOptions = {
|
||||
multiLine: true
|
||||
};
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
textFit(document.querySelector(".poll-title"), textFitOptions);
|
||||
document.querySelectorAll(".poll-option .text").forEach(element => textFit(element, textFitOptions));
|
||||
});
|
||||
window.addEventListener("resize", function() {
|
||||
textFit(document.querySelector(".poll-title"), textFitOptions);
|
||||
document.querySelectorAll(".poll-option .text").forEach(element => textFit(element, textFitOptions));
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to poll.horse!</h1>
|
||||
<h2>{{ POLL_TITLE }}</h2>
|
||||
<header>
|
||||
<h1>Poll.horse</h1>
|
||||
<h3>Make voting on things simpler</h3>
|
||||
</header>
|
||||
<main>
|
||||
<section class="error {{ FORM_SUBMISSION_ERROR_SHOWN_CLASS }}">
|
||||
{{ FORM_SUBMISSION_ERROR }}
|
||||
</section>
|
||||
<section class="poll-id">ID: {{ POLL_ID }}</section>
|
||||
<section class="notepad">
|
||||
<div class="notepad-border"></div>
|
||||
<form action="{{ BACKEND_BASE_PATH }}/_backend/vote-form/{{ POLL_ID }}" method="POST">
|
||||
<section class="poll-title" {{ TITLE_FONT_SIZE_STYLE }}>
|
||||
{{ POLL_TITLE }}
|
||||
</section>
|
||||
<section id="poll-options" class="poll-options">
|
||||
{{ POLL_OPTION_DIVS }}
|
||||
</section>
|
||||
<section class="poll-footer">
|
||||
<input type="submit" name="submit" value="Vote" id="submit-button">
|
||||
<a href="/{{ POLL_ID }}/r"><button type="button">Results</button></a>
|
||||
</form>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
<ul>
|
||||
{{ FOOTER_LINKS }}
|
||||
</ul>
|
||||
<div class="copyright">{{ FOOTER_COPYRIGHT }}</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -76,6 +76,16 @@ main .error.error-visible {
|
|||
display: block;
|
||||
}
|
||||
/* #endregion Error */
|
||||
/* #region ID */
|
||||
main .poll-id {
|
||||
position: absolute;
|
||||
right: 30%;
|
||||
top: 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
color: #fff;
|
||||
font-size: 1.75em;
|
||||
}
|
||||
/* #endregion ID */
|
||||
/* #region notepad */
|
||||
main .notepad {
|
||||
position: relative;
|
||||
|
@ -88,6 +98,7 @@ main .notepad {
|
|||
}
|
||||
main .notepad .poll-title {
|
||||
height: 70px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
main .notepad .poll-title input {
|
||||
font-size: 2em;
|
||||
|
@ -112,6 +123,58 @@ main .notepad .poll-footer {
|
|||
padding-left: 10%;
|
||||
padding-right: 5px;
|
||||
width: calc(90% - 5px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
main .notepad .poll-options .poll-option .input-container {
|
||||
position: relative;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
top: 13px;
|
||||
}
|
||||
|
||||
main .notepad .poll-options .poll-option input[type="checkbox"],
|
||||
main .notepad .poll-options .poll-option input[type="radio"] {
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
vertical-align: top;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border: 1px solid #b1b874;
|
||||
border-radius: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
main .notepad .poll-options .poll-option svg.checkmark {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
stroke-width: 2;
|
||||
stroke: #cf2828;
|
||||
stroke-miterlimit: 10;
|
||||
stroke-dashoffset: 0;
|
||||
margin: 10% auto;
|
||||
}
|
||||
main .notepad .poll-options .poll-option div.checkmark {
|
||||
position: absolute;
|
||||
top: -25px;
|
||||
left: -20px;
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
main .notepad .poll-options .poll-option input[type="checkbox"]:checked ~ div.checkmark,
|
||||
main .notepad .poll-options .poll-option input[type="radio"]:checked ~ div.checkmark {
|
||||
display: block;
|
||||
}
|
||||
main .notepad .poll-options .poll-option .text {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: calc(100% - 25px - 5px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
main .notepad-border {
|
||||
|
@ -119,8 +182,8 @@ main .notepad-border {
|
|||
left: 5%;
|
||||
height: 100%;
|
||||
width: 5px;
|
||||
border-left: 2px solid red;
|
||||
border-right: 2px solid red;
|
||||
border-left: 2px solid #cf2828;
|
||||
border-right: 2px solid #cf2828;
|
||||
}
|
||||
/* #endregion notepad */
|
||||
/* #region notepad-footer */
|
||||
|
@ -142,10 +205,10 @@ main .notepad .poll-footer button:hover {
|
|||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
#create-poll {
|
||||
#submit-button {
|
||||
background-color: #cf2828;
|
||||
}
|
||||
#create-poll:hover {
|
||||
#submit-button:hover {
|
||||
background-color: #e94747;
|
||||
}
|
||||
main .notepad .poll-footer input[type="checkbox"] {
|
||||
|
|
1
frontend/static/js/textfit.js
Normal file
1
frontend/static/js/textfit.js
Normal file
|
@ -0,0 +1 @@
|
|||
(function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.textFit=factory()}})(typeof global==="object"?global:this,function(){"use strict";var defaultSettings={alignVert:false,alignHoriz:false,multiLine:false,detectMultiLine:true,minFontSize:6,maxFontSize:80,reProcess:true,widthOnly:false,alignVertWithFlexbox:false};return function textFit(els,options){if(!options)options={};var settings={};for(var key in defaultSettings){if(options.hasOwnProperty(key)){settings[key]=options[key]}else{settings[key]=defaultSettings[key]}}if(typeof els.toArray==="function"){els=els.toArray()}var elType=Object.prototype.toString.call(els);if(elType!=="[object Array]"&&elType!=="[object NodeList]"&&elType!=="[object HTMLCollection]"){els=[els]}for(var i=0;i<els.length;i++){processItem(els[i],settings)}};function processItem(el,settings){if(!isElement(el)||!settings.reProcess&&el.getAttribute("textFitted")){return false}if(!settings.reProcess){el.setAttribute("textFitted",1)}var innerSpan,originalHeight,originalHTML,originalWidth;var low,mid,high;originalHTML=el.innerHTML;originalWidth=innerWidth(el);originalHeight=innerHeight(el);if(!originalWidth||!settings.widthOnly&&!originalHeight){if(!settings.widthOnly)throw new Error("Set a static height and width on the target element "+el.outerHTML+" before using textFit!");else throw new Error("Set a static width on the target element "+el.outerHTML+" before using textFit!")}if(originalHTML.indexOf("textFitted")===-1){innerSpan=document.createElement("span");innerSpan.className="textFitted";innerSpan.style["display"]="inline-block";innerSpan.innerHTML=originalHTML;el.innerHTML="";el.appendChild(innerSpan)}else{innerSpan=el.querySelector("span.textFitted");if(hasClass(innerSpan,"textFitAlignVert")){innerSpan.className=innerSpan.className.replace("textFitAlignVert","");innerSpan.style["height"]="";el.className.replace("textFitAlignVertFlex","")}}if(settings.alignHoriz){el.style["text-align"]="center";innerSpan.style["text-align"]="center"}var multiLine=settings.multiLine;if(settings.detectMultiLine&&!multiLine&&innerSpan.scrollHeight>=parseInt(window.getComputedStyle(innerSpan)["font-size"],10)*2){multiLine=true}if(!multiLine){el.style["white-space"]="nowrap"}low=settings.minFontSize;high=settings.maxFontSize;var size=low;while(low<=high){mid=high+low>>1;innerSpan.style.fontSize=mid+"px";if(innerSpan.scrollWidth<=originalWidth&&(settings.widthOnly||innerSpan.scrollHeight<=originalHeight)){size=mid;low=mid+1}else{high=mid-1}}if(innerSpan.style.fontSize!=size+"px")innerSpan.style.fontSize=size+"px";if(settings.alignVert){addStyleSheet();var height=innerSpan.scrollHeight;if(window.getComputedStyle(el)["position"]==="static"){el.style["position"]="relative"}if(!hasClass(innerSpan,"textFitAlignVert")){innerSpan.className=innerSpan.className+" textFitAlignVert"}innerSpan.style["height"]=height+"px";if(settings.alignVertWithFlexbox&&!hasClass(el,"textFitAlignVertFlex")){el.className=el.className+" textFitAlignVertFlex"}}}function innerHeight(el){var style=window.getComputedStyle(el,null);return el.clientHeight-parseInt(style.getPropertyValue("padding-top"),10)-parseInt(style.getPropertyValue("padding-bottom"),10)}function innerWidth(el){var style=window.getComputedStyle(el,null);return el.clientWidth-parseInt(style.getPropertyValue("padding-left"),10)-parseInt(style.getPropertyValue("padding-right"),10)}function isElement(o){return typeof HTMLElement==="object"?o instanceof HTMLElement:o&&typeof o==="object"&&o!==null&&o.nodeType===1&&typeof o.nodeName==="string"}function hasClass(element,cls){return(" "+element.className+" ").indexOf(" "+cls+" ")>-1}function addStyleSheet(){if(document.getElementById("textFitStyleSheet"))return;var style=[".textFitAlignVert{","position: absolute;","top: 0; right: 0; bottom: 0; left: 0;","margin: auto;","display: flex;","justify-content: center;","flex-direction: column;","}",".textFitAlignVertFlex{","display: flex;","}",".textFitAlignVertFlex .textFitAlignVert{","position: static;","}"].join("");var css=document.createElement("style");css.type="text/css";css.id="textFitStyleSheet";css.innerHTML=style;document.body.appendChild(css)}});
|
|
@ -121,10 +121,22 @@ export default function init(router: Router): void {
|
|||
(program.opts().backendBaseUrl || "http://localhost:" + program.opts().port) + "/_backend/poll/" + id
|
||||
).then(r => r.json()) as Poll;
|
||||
if (!poll || poll.error) return res.redirect("/");
|
||||
await displayPage(req, res, "poll.html", {
|
||||
"POLL_ID": id,
|
||||
"POLL_TITLE": poll.title,
|
||||
|
||||
const pollOptions = poll.options.map(option =>
|
||||
`<div class="poll-option">
|
||||
<div class="input-container">
|
||||
<input type="${poll.multiSelect ? "checkbox" : "radio"}" name="poll-option" value="${option}"" /><div class="checkmark"><svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg></div>
|
||||
</div><div class="text">${option}</div>
|
||||
</div>`
|
||||
).join("");
|
||||
|
||||
await displayPage(req, res, "poll.html", {
|
||||
"POLL_ID": poll.id,
|
||||
"POLL_TITLE": poll.title,
|
||||
"POLL_OPTION_DIVS": pollOptions,
|
||||
"BACKEND_BASE_PATH": (program.opts().backendBaseUrl || ""),
|
||||
"FORM_SUBMISSION_ERROR": req.query.error,
|
||||
"FORM_SUBMISSION_ERROR_SHOWN_CLASS": req.query.error ? "error-visible" : "",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
Loading…
Reference in a new issue