Adrian Heine
2 years ago
3 changed files with 260 additions and 262 deletions
@ -0,0 +1,84 @@ |
|||
"use strict" |
|||
|
|||
const months = document.getElementById('months') |
|||
let selecting = null // { origin, className, range }
|
|||
let is_select = false |
|||
|
|||
months.addEventListener("pointerdown", event => { |
|||
selecting = null |
|||
is_select = false |
|||
for (const elem of document.querySelectorAll(".selecting, .unselecting")) { |
|||
elem.className = "" |
|||
} |
|||
|
|||
if (event.buttons !== 1) return |
|||
let target = event.target |
|||
if (target.nodeType == 3) target = target.parentNode |
|||
if (target.tagName !== "LABEL") return |
|||
|
|||
event.preventDefault() |
|||
|
|||
const className = target.className = document.getElementById(target.htmlFor).checked ? "unselecting" : "selecting" |
|||
selecting = { |
|||
origin: target, |
|||
className, |
|||
range: [ target ] |
|||
} |
|||
}) |
|||
|
|||
months.addEventListener('pointermove', event => { |
|||
if (selecting === null) return |
|||
event.preventDefault() |
|||
is_select = true |
|||
|
|||
const range = document.createRange() |
|||
range.selectNode(selecting.origin) |
|||
if (range.comparePoint(event.target, 0) > 0) range.setEndAfter(event.target) |
|||
else range.setStartBefore(event.target) |
|||
|
|||
const treeWalker = document.createTreeWalker( |
|||
range.commonAncestorContainer, |
|||
NodeFilter.SHOW_ELEMENT, |
|||
{ acceptNode: (node) => node.nodeName.toLowerCase() === 'label' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP } |
|||
) |
|||
|
|||
const new_range = [] |
|||
let currentNode |
|||
while (currentNode = treeWalker.nextNode()) { |
|||
if (range.intersectsNode(currentNode)) { |
|||
new_range.push(currentNode) |
|||
const idx = selecting.range.indexOf(currentNode) |
|||
if (idx !== -1) selecting.range.splice(idx, 1) |
|||
else currentNode.className = selecting.className |
|||
} |
|||
} |
|||
for (const elem of selecting.range) { |
|||
elem.className = "" |
|||
} |
|||
selecting.range = new_range |
|||
}) |
|||
|
|||
document.addEventListener('pointercancel', event => { |
|||
if (selecting === null) return |
|||
for (const elem of selecting.range) { |
|||
elem.className = "" |
|||
} |
|||
selecting = null |
|||
is_select = false |
|||
}) |
|||
|
|||
document.addEventListener('pointerup', event => { |
|||
if (selecting === null) return |
|||
event.preventDefault() |
|||
for (const elem of selecting.range) { |
|||
if (is_select) document.getElementById(elem.htmlFor).checked = selecting.className == "selecting" |
|||
elem.className = "" |
|||
} |
|||
selecting = null |
|||
}) |
|||
months.addEventListener('click', event => { |
|||
if (is_select) { |
|||
event.preventDefault() |
|||
is_select = false |
|||
} |
|||
}) |
@ -0,0 +1,174 @@ |
|||
/* LAYOUT */ |
|||
body { |
|||
margin: 0 |
|||
} |
|||
footer { |
|||
border-top: 0.3em dashed #722CA2; |
|||
padding: 1em 1em 0 1em; |
|||
background: #f1cc37; |
|||
color: #5A4B0B; |
|||
padding: 1em 0 |
|||
} |
|||
main { |
|||
background: #FFE98E; |
|||
padding: 1em 0 |
|||
} |
|||
header { |
|||
border-bottom: 0.3em dashed #722CA2; |
|||
background: #f1cc37; |
|||
color: #5A4B0B; |
|||
padding: 1em 0 |
|||
} |
|||
h1 { |
|||
margin: 0 |
|||
} |
|||
footer > *, |
|||
header > *, |
|||
main > * { |
|||
margin: 0 auto; |
|||
max-width: 80rem; |
|||
padding: 0 1rem |
|||
} |
|||
|
|||
/* CALENDAR */ |
|||
.month { |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
margin-right: 2em; |
|||
border-spacing: 0 |
|||
} |
|||
.month tbody { |
|||
border-radius: 0.3em; |
|||
color: #5A4B0B; |
|||
box-shadow: .4em .5em 0 0 RGBA(114, 44, 162,0.5) |
|||
} |
|||
.month th:first-of-type { |
|||
border-top-left-radius: 0.3em |
|||
} |
|||
.month th:last-of-type { |
|||
border-top-right-radius: 0.3em |
|||
} |
|||
.month tr > :last-of-type { |
|||
border-right-width: 1px |
|||
} |
|||
.month tr:last-of-type td:first-of-type { |
|||
border-bottom-left-radius: 0.3em |
|||
} |
|||
.month tr:last-of-type td:last-of-type { |
|||
border-bottom-right-radius: 0.3em |
|||
} |
|||
.month tr:last-of-type td { |
|||
border-bottom-width: 1px |
|||
} |
|||
|
|||
/* date in calendar */ |
|||
.month th, .month td { |
|||
width: 3.5em; |
|||
height: 3.5em; |
|||
border: 1px solid #CBC19A; |
|||
border-width: 1px 0 0 1px; |
|||
text-align: center; |
|||
padding: 0; |
|||
background: white; |
|||
box-sizing: border-box |
|||
} |
|||
.month input[type=checkbox] { |
|||
appearance: none; |
|||
position: absolute |
|||
} |
|||
.month label { |
|||
display: block; |
|||
line-height: 3.5em |
|||
} |
|||
.month :focus + label { |
|||
border: 1px solid #722CA2; |
|||
margin: -1px |
|||
} |
|||
:checked + label:not(.unselecting), |
|||
.selecting { |
|||
background: #f1cc37 |
|||
} |
|||
.invalid { |
|||
color: #CBC19A |
|||
} |
|||
|
|||
/* calendar on smaller screens */ |
|||
@media only screen and (max-width: 55em) { |
|||
.month { |
|||
margin-right: 1.5vw |
|||
} |
|||
.month th, .month td { |
|||
width: 6vw |
|||
} |
|||
} |
|||
@media only screen and (max-width: 40em) { |
|||
.month { |
|||
margin: 0 auto; |
|||
display: table |
|||
} |
|||
.month th, .month td { |
|||
width: 3.5em |
|||
} |
|||
} |
|||
|
|||
/* events in calendar */ |
|||
.event { |
|||
position: relative; |
|||
top: -3.5em; |
|||
right: -0.9em; |
|||
line-height: initial; |
|||
display: block |
|||
} |
|||
.event::before { |
|||
content: "★"; |
|||
position: absolute; |
|||
padding: 0.5em; |
|||
top: -0.5em; |
|||
right: 0.5em |
|||
} |
|||
.event-content { |
|||
visibility: hidden; |
|||
position: absolute; |
|||
background: white; |
|||
top: 0.4em; |
|||
left: 1.8em; |
|||
padding: 0.4em; |
|||
border: 1px solid #CBC19A; |
|||
border-radius: 0.2em; |
|||
box-shadow: .2em .25em 0 0 RGBA(114, 44, 162,0.5); |
|||
z-index: 1 |
|||
} |
|||
.month :focus + label .event-content, |
|||
.month td:hover .event-content, |
|||
.month td:active .event-content { |
|||
visibility: initial |
|||
} |
|||
|
|||
/* OTHER FORM ELEMENTS */ |
|||
.row { |
|||
display: block; |
|||
margin: 1em 0 |
|||
} |
|||
.row > input, |
|||
.row > select { |
|||
padding: 0.5rem; |
|||
margin-right: 1rem; |
|||
width: 12rem; |
|||
box-sizing: border-box; |
|||
border: 1px solid #5A4B0B; |
|||
border-radius: .3em; |
|||
box-shadow: .4em .5em 0 0 RGBA(114, 44, 162,0.5) |
|||
} |
|||
.row > input[type="number"] { |
|||
margin-left: 8.5rem; |
|||
width: 3.5rem |
|||
} |
|||
.row > input[type="submit"] { |
|||
background: #f1cc37 |
|||
} |
|||
.row > input[type="submit"]:active { |
|||
background: white |
|||
} |
|||
.row :focus-visible { |
|||
outline: 0.2em #722CA2 solid |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue