#6, initial continuous adding of items

This commit is contained in:
Magnus Åhall 2024-04-18 07:47:35 +02:00
parent 2c16d7af60
commit 9d45d87ef3
3 changed files with 132 additions and 9 deletions

View File

@ -13,6 +13,11 @@ html {
*:after { *:after {
box-sizing: inherit; box-sizing: inherit;
} }
*,
*:focus,
*:hover {
outline: none;
}
[onClick] { [onClick] {
cursor: pointer; cursor: pointer;
} }
@ -413,6 +418,7 @@ header .menu {
cursor: pointer; cursor: pointer;
} }
#checklist .checklist-item { #checklist .checklist-item {
transform: translate(0, 0);
display: grid; display: grid;
grid-template-columns: repeat(3, min-content); grid-template-columns: repeat(3, min-content);
grid-gap: 0 8px; grid-gap: 0 8px;
@ -778,6 +784,24 @@ header .menu {
#schedule-events .header { #schedule-events .header {
font-weight: bold; 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) { @media only screen and (max-width: 932px) {
#app.node { #app.node {
grid-template-areas: "header" "crumbs" "child-nodes" "name" "content" "checklist" "schedule" "files" "blank"; grid-template-areas: "header" "crumbs" "child-nodes" "name" "content" "checklist" "schedule" "files" "blank";

View File

@ -110,10 +110,11 @@ export class Checklist extends Component {
this.groupElements = {} this.groupElements = {}
this.state = { this.state = {
confirmDeletion: true, confirmDeletion: true,
continueAddingItems: true,
} }
window._checklist = this window._checklist = this
}//}}} }//}}}
render({ ui, groups }, { confirmDeletion }) {//{{{ render({ ui, groups }, { confirmDeletion, continueAddingItems }) {//{{{
this.groupElements = {} this.groupElements = {}
if (groups.length == 0 && !ui.node.value.ShowChecklist.value) if (groups.length == 0 && !ui.node.value.ShowChecklist.value)
return return
@ -136,6 +137,10 @@ export class Checklist extends Component {
<input type="checkbox" id="confirm-checklist-delete" checked=${confirmDeletion} onchange=${() => this.setState({ confirmDeletion: !confirmDeletion })} /> <input type="checkbox" id="confirm-checklist-delete" checked=${confirmDeletion} onchange=${() => this.setState({ confirmDeletion: !confirmDeletion })} />
<label for="confirm-checklist-delete">Confirm checklist deletion</label> <label for="confirm-checklist-delete">Confirm checklist deletion</label>
</div> </div>
<div>
<input type="checkbox" id="continue-adding-items" checked=${continueAddingItems} onchange=${() => this.setState({ continueAddingItems: !continueAddingItems })} />
<label for="continue-adding-items">Continue adding items</label>
</div>
` `
} }
@ -194,10 +199,62 @@ export class Checklist extends Component {
}//}}} }//}}}
} }
class InputElement extends Component {
render({ placeholder, label }) {//{{{
return html`
<dialog id="input-text">
<div class="container">
<div class="label">${label}</div>
<input id="input-text-el" type="text" placeholder=${placeholder} />
<div class="buttons">
<div></div>
<button onclick=${()=>this.cancel()}>Cancel</button>
<button onclick=${()=>this.ok()}>OK</button>
</div>
</div>
</dialog>
`
}//}}}
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 { class ChecklistGroupElement extends Component {
constructor() {//{{{ constructor() {//{{{
super() super()
this.label = createRef() this.label = createRef()
this.addingItem = signal(false)
}//}}} }//}}}
render({ ui, group }) {//{{{ render({ ui, group }) {//{{{
let items = ({ 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} />`) .map(item => html`<${ChecklistItemElement} key="item-${item.ID}" ui=${ui} group=${this} item=${item} />`)
let label = () => html`<div class="label" style="cursor: pointer" ref=${this.label} onclick=${() => this.editLabel()}>${group.Label}</div>` let label = () => html`<div class="label" style="cursor: pointer" ref=${this.label} onclick=${() => this.editLabel()}>${group.Label}</div>`
let addItem = () => {
if (this.addingItem.value)
return html`<${InputElement} label="New item" callback=${(ok, val) => this.addItem(ok, val)} />`
}
return html` return html`
<${addItem} />
<div class="checklist-group-container"> <div class="checklist-group-container">
<div class="checklist-group ${ui.edit.value ? 'edit' : ''}"> <div class="checklist-group ${ui.edit.value ? 'edit' : ''}">
<div class="reorder" style="cursor: grab"></div> <div class="reorder" style="cursor: grab"></div>
<img src="/images/${_VERSION}/trashcan.svg" onclick=${() => this.delete()} /> <img src="/images/${_VERSION}/trashcan.svg" onclick=${() => this.delete()} />
<${label} /> <${label} />
<img src="/images/${_VERSION}/add-gray.svg" onclick=${() => this.addItem()} /> <img src="/images/${_VERSION}/add-gray.svg" onclick=${() => this.addingItem.value = true} />
</div> </div>
<${items} ui=${ui} group=${group} /> <${items} ui=${ui} group=${group} />
</div> </div>
` `
}//}}} }//}}}
addItem() {//{{{ addItem(ok, label) {//{{{
let label = prompt("Create a new item") if (!ok) {
if (label === null) this.addingItem.value = false
return return
}
label = label.trim() label = label.trim()
if (label == '') if (label == '') {
this.addingItem.value = false
return return
}
this.props.group.addItem(label, () => { this.props.group.addItem(label, () => {
this.forceUpdate() this.forceUpdate()
}) })
if (!this.props.ui.state.continueAddingItems)
this.addingItem.value = false
}//}}} }//}}}
editLabel() {//{{{ editLabel() {//{{{
let label = prompt('Edit label', this.props.group.Label) let label = prompt('Edit label', this.props.group.Label)
@ -299,7 +368,7 @@ class ChecklistItemElement extends Component {
` `
}//}}} }//}}}
componentDidMount() {//{{{ componentDidMount() {//{{{
this.base.addEventListener('dragstart', () => this.dragStart()) this.base.addEventListener('dragstart', evt => this.dragStart(evt))
this.base.addEventListener('dragend', () => this.dragEnd()) this.base.addEventListener('dragend', () => this.dragEnd())
this.base.addEventListener('dragenter', evt => this.dragEnter(evt)) this.base.addEventListener('dragenter', evt => this.dragEnter(evt))
}//}}} }//}}}
@ -353,10 +422,13 @@ class ChecklistItemElement extends Component {
setDragTarget(state) {//{{{ setDragTarget(state) {//{{{
this.setState({ dragTarget: state }) this.setState({ dragTarget: state })
}//}}} }//}}}
dragStart() {//{{{ dragStart(evt) {//{{{
// Shouldn't be needed, but in case the previous drag was bungled up, we reset. // Shouldn't be needed, but in case the previous drag was bungled up, we reset.
this.props.ui.dragReset() this.props.ui.dragReset()
this.props.ui.dragItemSource = this this.props.ui.dragItemSource = this
const img = new Image();
evt.dataTransfer.setDragImage(img, 10, 10);
}//}}} }//}}}
dragEnter(evt) {//{{{ dragEnter(evt) {//{{{
evt.preventDefault() evt.preventDefault()
@ -393,7 +465,7 @@ class ChecklistItemElement extends Component {
this.props.ui.groupElements[fromGroup.ID].current.forceUpdate() this.props.ui.groupElements[fromGroup.ID].current.forceUpdate()
this.props.ui.groupElements[toGroup.ID].current.forceUpdate() this.props.ui.groupElements[toGroup.ID].current.forceUpdate()
from.move(to, ()=>console.log('ok')) from.move(to, () => {})
}//}}} }//}}}
} }

View File

@ -8,6 +8,10 @@ html {
box-sizing: inherit; box-sizing: inherit;
} }
*,*:focus,*:hover{
outline:none;
}
[onClick] { [onClick] {
cursor: pointer; cursor: pointer;
} }
@ -476,6 +480,7 @@ header {
} }
.checklist-item { .checklist-item {
transform: translate(0, 0);
display: grid; display: grid;
grid-template-columns: repeat(3, min-content); grid-template-columns: repeat(3, min-content);
grid-gap: 0 8px; 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) { @media only screen and (max-width: 932px) {
#app.node { #app.node {
.layout-crumbs(); .layout-crumbs();