diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-11-13 14:56:02 +0100 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-11-13 14:56:02 +0100 |
| commit | c7b02f02ad0a7e2888f2d7d3599719e59bbd1ee2 (patch) | |
| tree | 9f782daf2e2ff78559958f15e0b9ffe5ece78334 /static/widgets/month-select | |
| parent | 7ee9d320e6ba9a84542d838892c43cf98b268552 (diff) | |
frontend: design prototype
Diffstat (limited to 'static/widgets/month-select')
| -rw-r--r-- | static/widgets/month-select/index.css | 125 | ||||
| -rw-r--r-- | static/widgets/month-select/index.js | 75 |
2 files changed, 200 insertions, 0 deletions
diff --git a/static/widgets/month-select/index.css b/static/widgets/month-select/index.css new file mode 100644 index 0000000..87b63c0 --- /dev/null +++ b/static/widgets/month-select/index.css @@ -0,0 +1,125 @@ +:host { + position: fixed; + top: 0; + left: 0; +} + +#container { + z-index: 1000; + position: fixed; + bottom: -100%; + left: 5px; + right: 5px; + background: #fff9; + backdrop-filter: blur(10px); + border-radius: var(--border-radius); + transition: bottom 0.1s ease; + height: calc(100% - 10px); + box-shadow: var(--shadow); + padding: 10px; +} + +#container.visible { + bottom: 5px; +} + +#close-button { + position: absolute; + top: 10px; + right: 10px; + width: 25px; + height: 25px; + border-radius: 100%; + background: var(--page-background); + cursor: pointer; +} + +#title { + font-size: 1.2em; + user-select: none; + margin-bottom: 10px; +} + +#month-container { + height: calc(100% - 30px); + overflow-y: auto; + overscroll-behavior: contain; +} + +.month-item { + padding: 10px; + padding-left: 20px; + margin: 5px; + border-radius: var(--border-radius); + user-select: none; + cursor: pointer; + position: relative; +} + +.month-item:before { + content: ''; + display: block; + position: absolute; + background: var(--primary); + top: 0px; + left: 0px; + width: 4px; + height: 47px; +} + +.month-item:after { + content: ''; + display: block; + position: absolute; + background: var(--primary); + top: 50%; + transform: translate(0, -50%); + left: 0px; + width: 12px; + height: 4px; +} + +.month-item:first-child:before { + top: 50%; + height: 27px; +} + +.month-item:hover { + background: var(--primary); + color: var(--fg-primary); +} + +.year-item { + padding: 10px 20px; + font-size: 1.1em; + margin: 5px; + position: relative; + font-weight: bold; + background: #fffa; + border-radius: var(--border-radius); + box-shadow: #22322355 1px 1px 2px; +} + +.year-item:before { + content: ''; + display: block; + position: absolute; + background: var(--primary); + top: 0px; + left: 0px; + width: 4px; + height: 50px; +} + +.year-item:after { + content: ''; + display: block; + position: absolute; + background: var(--primary); + top: 50%; + transform: translate(0, -50%); + left: -4px; + width: 12px; + height: 12px; + border-radius: 100%; +} diff --git a/static/widgets/month-select/index.js b/static/widgets/month-select/index.js new file mode 100644 index 0000000..d23469d --- /dev/null +++ b/static/widgets/month-select/index.js @@ -0,0 +1,75 @@ +import * as sfw from 'sfw'; +const { Div } = sfw.element.native; + +import icons from '../../icons/index.js'; + +const css = await sfw.css(import.meta.url, './index.css'); + +export default class MonthSelect extends sfw.element.Container { + #container + #month_container + + constructor() { + super({ css }); + + this.onscroll = (e) => e.stopPropagate(); + this.onmonth = () => {}; + + this.body.append( + this.#container = Div.new({ + id: 'container', + children: [ + Div.new({ id: 'title', innerText: 'Select Month' }), + Div.new({ + id: 'close-button', + children: [ icons.close ], + onclick: () => this.hide(), + }), + this.#month_container = Div.new({ + id: 'month-container', + }), + ], + }), + ); + } + + show() { + this.#container.classList.add('visible'); + } + + hide() { + this.#container.classList.remove('visible'); + } + + set months(months) { + months.sort((a, b) => a.is_before(b)); + + this.#month_container.innerHTML = ''; + + let last = null; + + for (const month of months) { + if (last != null && !last.is_same_year(month)) { + this.#month_container.append( + Div.new({ + className: 'year-item', + innerText: last.year, + }) + ); + } + + this.#month_container.append( + Div.new({ + className: 'month-item', + innerText: month.name, + onclick: () => { + this.hide(); + this.onmonth(month); + } + }) + ); + + last = month; + } + } +} |