diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-11-24 15:55:20 +0100 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-11-24 15:55:20 +0100 |
| commit | 4b6e37397d3a9a80db0c20484b712175c7b9c9c7 (patch) | |
| tree | a741d76d250b7e7a53f3ab6715106463db32215e /static/widgets/password-dialog | |
| parent | a72a9c6fa8aacbd9e945fdce64bdaf7895425e95 (diff) | |
add password-dialog
Diffstat (limited to 'static/widgets/password-dialog')
| -rw-r--r-- | static/widgets/password-dialog/index.css | 51 | ||||
| -rw-r--r-- | static/widgets/password-dialog/index.js | 60 |
2 files changed, 111 insertions, 0 deletions
diff --git a/static/widgets/password-dialog/index.css b/static/widgets/password-dialog/index.css new file mode 100644 index 0000000..ad8c1c2 --- /dev/null +++ b/static/widgets/password-dialog/index.css @@ -0,0 +1,51 @@ +#container { + position: absolute; + max-width: 500px; + width: 70%; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: grid; + gap: 10px; + background: #efefef99; + backdrop-filter: blur(10px); + padding: 10px; + border-radius: var(--border-radius); + box-shadow: var(--shadow); +} + +#title { + font-size: 1.1em; +} + +#close { + width: 25px; + height: 25px; + position: absolute; + top: 5px; + right: 5px; + cursor: pointer; + background: var(--page-background); + border-radius: 100%; + padding: 2px; +} + +#button { + background: var(--primary); + padding: 10px; + color: var(--fg-primary); + font-weight: bold; + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); + text-align: center; +} + +#error { + font-style: italic; + font-weight: bold; + color: #ee5151; +} + +#error.hidden { + display: none; +} diff --git a/static/widgets/password-dialog/index.js b/static/widgets/password-dialog/index.js new file mode 100644 index 0000000..334e02d --- /dev/null +++ b/static/widgets/password-dialog/index.js @@ -0,0 +1,60 @@ +import * as sfw from 'sfw'; +const { Div, Input } = sfw.element.native; + +import * as api from '../../api/index.js'; + +import icons from '../../icons/index.js'; + +const css = await sfw.css(import.meta.url, './index.css'); + +export default class PasswordDialog extends sfw.element.Container { + #current + #new + #confirm + #error + + constructor() { + super({ css }); + + this.callclose = () => this.close(); + + document.body.addEventListener('click', this.callclose); + this.onclick = (e) => e.stopPropagation(); + + this.body.append(Div.new({ + id: 'container', + children: [ + Div.new({ id: 'title', innerText: 'Change Password' }), + Div.new({ id: 'close', children: [ icons.close ], onclick: () => this.close() }), + this.#current = Input.new({ placeholder: 'Current Password', type: 'password' }), + this.#new = Input.new({ placeholder: 'New Password', type: 'password' }), + this.#confirm = Input.new({ placeholder: 'Confirm Password', type: 'password' }), + this.#error = Div.new({ id: 'error', className: 'hidden' }), + Div.new({ + id: 'button', + innerText: 'Update', + onclick: async () => { + if (this.#new.value !== this.#confirm.value) { + this.#error.innerText = 'Passwords do not match'; + this.#error.className = ''; + return; + } + + if (!await api.profile.update_password(this.#current.value, this.#new.value)) { + this.#error.innerText = 'invalid password'; + this.#error.className = ''; + return; + } + + this.close(); + }, + }), + ], + })); + } + + close() { + this.parentNode.removeChild(this); + document.body.removeEventListener('click', this.callclose); + } +} |