Skip to content

Instantly share code, notes, and snippets.

@nexpr
Last active January 25, 2022 12:11
Show Gist options
  • Save nexpr/bf735bde467427b9c80210ed6b83e667 to your computer and use it in GitHub Desktop.
Save nexpr/bf735bde467427b9c80210ed6b83e667 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<meta charset="utf-8" />
<style>
body {
margin: 0;
}
.control {
display: inline-block;
padding: 10px;
position: sticky;
top: 0;
background: white;
border-bottom: 1px solid #aaa;
}
.result {
margin: 0 10px;
}
.date-range {
display: flex;
align-items: center;
gap: 10px;
}
.flex-center {
display: flex;
justify-content: center;
margin: 5px;
gap: 10px;
}
</style>
<script type="module">
import { html, render } from "https://unpkg.com/lit-html@2.1.1/lit-html.js"
const formatDate = date => date.toLocaleString("ja-JP", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" })
const addDate = (base, diff) => new Date(base.getFullYear() + (diff.year || 0), base.getMonth() + (diff.month || 0), base.getDate() + (diff.date || 0), base.getHours() + (diff.hour || 0), base.getMinutes() + (diff.minute || 0), base.getSeconds() + (diff.second || 0))
const values = {
data: [],
rows: [],
from: new Date("2022-01-01 00:00:00"),
to: new Date("2022-02-01 00:00:00"),
}
values.data = Array.from(Array(1000), (x, i) => {
const from = +new Date("2021-01-01 00:00:00")
const to = +new Date("2023-01-01 00:00:00")
const offset = ~~(Math.random() * (to - from) / 1000) * 1000
return new Date(from + offset)
})
.sort((a, b) => a - b)
.map((date, i) => ({ date, text: String(i).padStart(4, "0") }))
const updateFilter = () => {
const from = values.from ? +values.from : 0
const to = values.to ? values.to : Infinity
values.rows = values.data.filter(row => from <= row.date && row.date < to)
update()
}
const changeRange = (type, move) => () => {
if (move) {
switch (type) {
case "day":
if (values.from) {
values.from = addDate(values.from, { date: move })
}
if (values.to) {
values.to = addDate(values.to, { date: move })
}
break
case "week":
if (values.from) {
values.from = addDate(values.from, { date: move * 7 })
}
if (values.to) {
values.to = addDate(values.to, { date: move * 7 })
}
break
case "month":
if (values.from) {
values.from = addDate(values.from, { month: move })
}
if (values.to) {
values.to = addDate(values.to, { month: move })
}
break
case "year":
if (values.from) {
values.from = addDate(values.from, { year: move })
}
if (values.to) {
values.to = addDate(values.to, { year: move })
}
break
}
} else {
switch (type) {
case "day":
if (values.from) {
values.to = addDate(values.from, { date: 1 })
} else if (values.to) {
values.from = addDate(values.to, { date: -1 })
}
break
case "week":
if (values.from) {
values.to = addDate(values.from, { date: 7 })
} else if (values.to) {
values.from = addDate(values.to, { date: -7 })
}
break
case "month":
if (values.from) {
values.to = addDate(values.from, { month: 1 })
} else if (values.to) {
values.from = addDate(values.to, { month: -1 })
}
break
case "year":
if (values.from) {
values.to = addDate(values.from, { year: 1 })
} else if (values.to) {
values.from = addDate(values.to, { year: -1 })
}
break
}
}
updateFilter()
}
const inputTemplate = (date, onchange) => {
const date_utc = date ? addDate(date, { minute: -date.getTimezoneOffset() }) : null
const handler = (eve) => {
const date_utc = eve.target.valueAsDate
onchange(date_utc ? addDate(date_utc, { minute: date_utc.getTimezoneOffset() }) : null)
}
return html`<input type="date" .valueAsDate=${date_utc} @change=${handler}>`
}
const rangeTemplate = (label, onclick) => html`
<div class="flex-center">
<button @click=${onclick(-1)}>◀</button>
<button @click=${onclick()}>${label}</button>
<button @click=${onclick(1)}>▶</button>
</div>
`
const template = () => html`
<div class="container flex-row">
<div class="control">
<div class="date-range">
${inputTemplate(values.from, date => { values.from = date; updateFilter() })}
${inputTemplate(values.to, date => { values.to = date; updateFilter() })}
</div>
${rangeTemplate("日", x => changeRange("day", x))}
${rangeTemplate("週", x => changeRange("week", x))}
${rangeTemplate("月", x => changeRange("month", x))}
${rangeTemplate("年", x => changeRange("year", x))}
</div>
<div class="result">
${values.rows.map(row => html`<div>${formatDate(row.date)} | ${row.text}</div>`)}
</div>
</div>
`
const root_element = document.getElementById("root")
const update = () => render(template(), root_element)
updateFilter()
</script>
<div id="root"></div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment