diff --git a/static/css/main.css b/static/css/main.css index b4a783f..bf68f18 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -13,6 +13,11 @@ html { *:after { box-sizing: inherit; } +*, +*:focus, +*:hover { + outline: none; +} [onClick] { cursor: pointer; } @@ -413,6 +418,7 @@ header .menu { cursor: pointer; } #checklist .checklist-item { + transform: translate(0, 0); display: grid; grid-template-columns: repeat(3, min-content); grid-gap: 0 8px; @@ -778,6 +784,24 @@ header .menu { #schedule-events .header { font-weight: bold; } +#input-text { + border: 1px solid #000 !important; + padding: 16px; + width: 300px; +} +#input-text .label { + margin-bottom: 4px; +} +#input-text input[type=text] { + width: 100%; + padding: 4px; +} +#input-text .buttons { + display: grid; + grid-template-columns: 1fr 64px 64px; + grid-gap: 8px; + margin-top: 8px; +} @media only screen and (max-width: 932px) { #app.node { grid-template-areas: "header" "crumbs" "child-nodes" "name" "content" "checklist" "schedule" "files" "blank"; diff --git a/static/js/checklist.mjs b/static/js/checklist.mjs index 1e639a8..b84cd8b 100644 --- a/static/js/checklist.mjs +++ b/static/js/checklist.mjs @@ -110,10 +110,11 @@ export class Checklist extends Component { this.groupElements = {} this.state = { confirmDeletion: true, + continueAddingItems: true, } window._checklist = this }//}}} - render({ ui, groups }, { confirmDeletion }) {//{{{ + render({ ui, groups }, { confirmDeletion, continueAddingItems }) {//{{{ this.groupElements = {} if (groups.length == 0 && !ui.node.value.ShowChecklist.value) return @@ -136,6 +137,10 @@ export class Checklist extends Component { this.setState({ confirmDeletion: !confirmDeletion })} /> +
+ this.setState({ continueAddingItems: !continueAddingItems })} /> + +
` } @@ -194,10 +199,62 @@ export class Checklist extends Component { }//}}} } +class InputElement extends Component { + render({ placeholder, label }) {//{{{ + return html` + +
+
${label}
+ +
+
+ + +
+
+
+ ` + }//}}} + componentDidMount() {//{{{ + const dlg = document.getElementById('input-text') + const input = document.getElementById('input-text-el') + dlg.showModal() + dlg.addEventListener("keydown", evt => this.keyhandler(evt)) + input.addEventListener("keydown", evt => this.keyhandler(evt)) + input.focus() + }//}}} + ok() {//{{{ + const input = document.getElementById('input-text-el') + this.props.callback(true, input.value) + }//}}} + cancel() {//{{{ + this.props.callback(false) + }//}}} + keyhandler(evt) {//{{{ + let handled = true + switch (evt.key) { + case 'Enter': + this.ok() + break; + + case 'Escape': + this.cancel() + break; + default: + handled = false + } + if (handled) { + evt.stopPropagation() + evt.preventDefault() + } + }//}}} +} + class ChecklistGroupElement extends Component { constructor() {//{{{ super() this.label = createRef() + this.addingItem = signal(false) }//}}} render({ ui, group }) {//{{{ let items = ({ ui, group }) => @@ -206,30 +263,42 @@ class ChecklistGroupElement extends Component { .map(item => html`<${ChecklistItemElement} key="item-${item.ID}" ui=${ui} group=${this} item=${item} />`) let label = () => html`
this.editLabel()}>${group.Label}
` + let addItem = () => { + if (this.addingItem.value) + return html`<${InputElement} label="New item" callback=${(ok, val) => this.addItem(ok, val)} />` + } return html` + <${addItem} />
this.delete()} /> <${label} /> - this.addItem()} /> + this.addingItem.value = true} />
<${items} ui=${ui} group=${group} />
` }//}}} - addItem() {//{{{ - let label = prompt("Create a new item") - if (label === null) + addItem(ok, label) {//{{{ + if (!ok) { + this.addingItem.value = false return + } + label = label.trim() - if (label == '') + if (label == '') { + this.addingItem.value = false return + } this.props.group.addItem(label, () => { this.forceUpdate() }) + + if (!this.props.ui.state.continueAddingItems) + this.addingItem.value = false }//}}} editLabel() {//{{{ let label = prompt('Edit label', this.props.group.Label) @@ -299,7 +368,7 @@ class ChecklistItemElement extends Component { ` }//}}} componentDidMount() {//{{{ - this.base.addEventListener('dragstart', () => this.dragStart()) + this.base.addEventListener('dragstart', evt => this.dragStart(evt)) this.base.addEventListener('dragend', () => this.dragEnd()) this.base.addEventListener('dragenter', evt => this.dragEnter(evt)) }//}}} @@ -353,10 +422,13 @@ class ChecklistItemElement extends Component { setDragTarget(state) {//{{{ this.setState({ dragTarget: state }) }//}}} - dragStart() {//{{{ + dragStart(evt) {//{{{ // Shouldn't be needed, but in case the previous drag was bungled up, we reset. this.props.ui.dragReset() this.props.ui.dragItemSource = this + + const img = new Image(); + evt.dataTransfer.setDragImage(img, 10, 10); }//}}} dragEnter(evt) {//{{{ evt.preventDefault() @@ -393,7 +465,7 @@ class ChecklistItemElement extends Component { this.props.ui.groupElements[fromGroup.ID].current.forceUpdate() this.props.ui.groupElements[toGroup.ID].current.forceUpdate() - from.move(to, ()=>console.log('ok')) + from.move(to, () => {}) }//}}} } diff --git a/static/less/main.less b/static/less/main.less index ed13f38..649a896 100644 --- a/static/less/main.less +++ b/static/less/main.less @@ -8,6 +8,10 @@ html { box-sizing: inherit; } +*,*:focus,*:hover{ + outline:none; +} + [onClick] { cursor: pointer; } @@ -476,6 +480,7 @@ header { } .checklist-item { + transform: translate(0, 0); display: grid; grid-template-columns: repeat(3, min-content); grid-gap: 0 8px; @@ -905,6 +910,28 @@ header { } } +#input-text { + border: 1px solid #000 !important; + padding: 16px; + width: 300px; + + .label { + margin-bottom: 4px; + } + + input[type=text] { + width: 100%; + padding: 4px; + } + + .buttons { + display: grid; + grid-template-columns: 1fr 64px 64px; + grid-gap: 8px; + margin-top: 8px; + } +} + @media only screen and (max-width: 932px) { #app.node { .layout-crumbs();