aboutsummaryrefslogtreecommitdiff
path: root/static/widgets/editable
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-11-13 14:56:02 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2025-11-13 14:56:02 +0100
commitc7b02f02ad0a7e2888f2d7d3599719e59bbd1ee2 (patch)
tree9f782daf2e2ff78559958f15e0b9ffe5ece78334 /static/widgets/editable
parent7ee9d320e6ba9a84542d838892c43cf98b268552 (diff)
frontend: design prototype
Diffstat (limited to 'static/widgets/editable')
-rw-r--r--static/widgets/editable/index.css36
-rw-r--r--static/widgets/editable/index.js65
2 files changed, 101 insertions, 0 deletions
diff --git a/static/widgets/editable/index.css b/static/widgets/editable/index.css
new file mode 100644
index 0000000..b474370
--- /dev/null
+++ b/static/widgets/editable/index.css
@@ -0,0 +1,36 @@
+
+#container {
+ width: 100%;
+ background: var(--card-background);
+ box-shadow: var(--shadow);
+ border-radius: var(--border-radius);
+ display: grid;
+ grid-template-columns: min-content auto min-content;
+}
+
+#container label {
+ user-select: none;
+ font-weight: bold;
+ background: var(--primary);
+ color: var(--fg-primary);
+ align-content: center;
+ padding: 10px;
+ border-top-left-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
+}
+
+#container input {
+ background: var(--card-background);
+ user-select: none;
+ font-size: 1em;
+}
+
+#container input:read-only {
+ caret-color: transparent;
+}
+
+#edit {
+ width: 35px;
+ padding: 10px;
+ cursor: pointer;
+}
diff --git a/static/widgets/editable/index.js b/static/widgets/editable/index.js
new file mode 100644
index 0000000..8a72aff
--- /dev/null
+++ b/static/widgets/editable/index.js
@@ -0,0 +1,65 @@
+import * as sfw from 'sfw';
+const { Div, Label, Input } = sfw.element.native;
+
+import icons from '../../icons/index.js';
+
+const css = await sfw.css(import.meta.url, './index.css');
+
+export default class Editable extends sfw.element.Container {
+ #label
+ #input
+ #edit
+
+ constructor() {
+ super({ css });
+
+ this.body.append(
+ Div.new({
+ id: 'container',
+ children: [
+ this.#label = Label.new({ htmlFor: 'input' }),
+ this.#input = Input.new({
+ readOnly: true,
+ onkeydown: (e) => {
+ if (e.key === 'Enter') {
+ this.#input.readOnly = true;
+ this.#update()
+ }
+ },
+ }),
+ this.#edit = Div.new({
+ id: 'edit',
+ children: [ icons.edit ],
+ onclick: () => {
+ this.#input.readOnly = !this.#input.readOnly;
+ this.#update();
+ }
+ }),
+ ],
+ })
+ );
+ }
+
+ #update() {
+ this.#edit.innerHTML = '';
+ this.#edit.append(
+ this.#input.readOnly ? icons.edit : icons.check
+ );
+
+ if (!this.#input.readOnly) {
+ this.#input.select();
+ }
+ }
+
+ set title(value) {
+ this.#label.innerText = value;
+ }
+
+ set value(value) {
+ this.#input.value = value;
+ }
+
+ set type(type) {
+ this.#input.type = type;
+ }
+}