-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { injectable } from "inversify"; | ||
import "./constraintMenu.css"; | ||
import { AbstractUIExtension } from "sprotty"; | ||
import { calculateTextSize } from "../../utils"; | ||
|
||
@injectable() | ||
export class ConstraintMenu extends AbstractUIExtension { | ||
static readonly ID = "constraint-menu"; | ||
|
||
id(): string { | ||
return ConstraintMenu.ID; | ||
} | ||
containerClass(): string { | ||
return ConstraintMenu.ID; | ||
} | ||
protected initializeContents(containerElement: HTMLElement): void { | ||
containerElement.classList.add("ui-float"); | ||
containerElement.innerHTML = ` | ||
<input type="checkbox" id="expand-state-constraint" hidden> | ||
<label id="constraint-menu-expand-label" for="expand-state-constraint"> | ||
<div class="expand-button"> | ||
Constraints | ||
</div> | ||
</label> | ||
`; | ||
containerElement.appendChild(this.buildConstraintInputWrapper()); | ||
containerElement.appendChild(this.buildConstraintListWrapper(["Test123", "Test456", "Test789"])); | ||
containerElement.appendChild(this.buildRunButton()); | ||
|
||
// Set the first item as selected | ||
setTimeout(() => this.selectConstraintListItem("Test123"), 0); | ||
} | ||
|
||
private buildConstraintInputWrapper(): HTMLElement { | ||
const wrapper = document.createElement("div"); | ||
wrapper.id = "constraint-menu-input"; | ||
wrapper.innerHTML = ` | ||
<input type="text" id="constraint-input" placeholder="Enter constraint here"> | ||
`; | ||
return wrapper; | ||
} | ||
|
||
private buildConstraintListWrapper(constrains: string[]): HTMLElement { | ||
const wrapper = document.createElement("div"); | ||
wrapper.id = "constraint-menu-list"; | ||
|
||
constrains.forEach((constraint) => { | ||
wrapper.appendChild(this.buildConstraintListItem(constraint)); | ||
}); | ||
|
||
return wrapper; | ||
} | ||
|
||
private buildConstraintListItem(constraint: string): HTMLElement { | ||
const valueElement = document.createElement("div"); | ||
valueElement.classList.add("constrain-label"); | ||
|
||
valueElement.onclick = () => { | ||
const elements = document.getElementsByClassName("constraint-label"); | ||
for (let i = 0; i < elements.length; i++) { | ||
elements[i].classList.remove("selected"); | ||
} | ||
valueElement.classList.add("selected"); | ||
this.selectConstraintListItem(constraint); | ||
}; | ||
|
||
const valueInput = document.createElement("input"); | ||
valueInput.value = constraint; | ||
valueInput.placeholder = "Name"; | ||
this.dynamicallySetInputSize(valueInput); | ||
|
||
valueElement.appendChild(valueInput); | ||
|
||
const deleteButton = document.createElement("button"); | ||
deleteButton.innerHTML = '<span class="codicon codicon-trash"></span>'; | ||
deleteButton.onclick = () => { | ||
console.log("Delete button clicked"); | ||
}; | ||
valueElement.appendChild(deleteButton); | ||
return valueElement; | ||
} | ||
|
||
private selectConstraintListItem(constraint: string): void { | ||
const input = document.getElementById("constraint-input") as HTMLInputElement; | ||
input.value = constraint; | ||
} | ||
|
||
/** | ||
* Sets and dynamically updates the size property of the passed input element. | ||
* When the text is zero the width is set to the placeholder length to make place for it. | ||
* When the text is changed the size gets updated with the keyup event. | ||
* @param inputElement the html dom input element to set the size property for | ||
*/ | ||
private dynamicallySetInputSize(inputElement: HTMLInputElement): void { | ||
const handleResize = () => { | ||
const displayText = inputElement.value || inputElement.placeholder; | ||
const { width } = calculateTextSize(displayText, window.getComputedStyle(inputElement).font); | ||
|
||
// Values have higher padding for the rounded border | ||
const widthPadding = 8; | ||
const finalWidth = width + widthPadding; | ||
|
||
inputElement.style.width = finalWidth + "px"; | ||
}; | ||
|
||
inputElement.onkeyup = handleResize; | ||
|
||
// The inputElement is not added to the DOM yet, so we cannot set the size now. | ||
// Wait for next JS tick, after which the element has been added to the DOM and we can set the initial size | ||
setTimeout(handleResize, 0); | ||
} | ||
|
||
private buildRunButton(): HTMLElement { | ||
const wrapper = document.createElement("div"); | ||
wrapper.id = "run-button-container"; | ||
|
||
const button = document.createElement("button"); | ||
button.id = "run-button"; | ||
button.innerHTML = "Run"; | ||
button.onclick = () => { | ||
console.log("Run button clicked"); | ||
}; | ||
|
||
wrapper.appendChild(button); | ||
return wrapper; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
div.constraint-menu { | ||
right: 20px; | ||
bottom: 20px; | ||
padding: 10px 10px; | ||
display: grid; | ||
grid-template-columns: auto 1fr; | ||
grid-template-rows: 1fr; | ||
grid-auto-rows: 0; | ||
overflow: hidden; | ||
gap: 8px; | ||
} | ||
|
||
div.constraint-menu:has(> input:checked) { | ||
grid-template-rows: 1fr auto 1fr; | ||
} | ||
|
||
div.constraint-menu > * { | ||
grid-column-start: 1; | ||
grid-column-end: 2; | ||
grid-row-start: 1; | ||
grid-row-end: 2; | ||
} | ||
|
||
#run-button { | ||
background-color: green; | ||
color: white; | ||
border: none; | ||
border-radius: 8px; | ||
padding: 5px 10px; | ||
text-align: center; | ||
text-decoration: none; | ||
display: inline-block; | ||
width: fit-content; | ||
} | ||
|
||
#run-button-container { | ||
grid-column-start: 2; | ||
grid-column-end: 3; | ||
grid-row-start: 1; | ||
grid-row-end: 2; | ||
} | ||
|
||
#expand-state-constraint:checked ~ #run-button-container { | ||
grid-column-start: 2; | ||
grid-column-end: 3; | ||
grid-row-start: 3; | ||
grid-row-end: 4; | ||
} | ||
|
||
#expand-state-constraint:checked ~ #run-button-container > #run-button { | ||
width: 100%; | ||
} | ||
|
||
#run-button::before { | ||
content: ""; | ||
background-image: url("@fortawesome/fontawesome-free/svgs/solid/play.svg"); | ||
display: inline-block; | ||
filter: invert(var(--dark-mode)); | ||
height: 16px; | ||
width: 16px; | ||
background-size: 16px 16px; | ||
vertical-align: text-top; | ||
} | ||
|
||
#constraint-menu-input { | ||
grid-row-start: 2; | ||
grid-row-end: 4; | ||
grid-column-start: 1; | ||
grid-column-end: 2; | ||
display: none; | ||
} | ||
|
||
#expand-state-constraint:checked ~ #constraint-menu-input { | ||
display: block; | ||
} | ||
|
||
#constraint-menu-list { | ||
grid-row-start: 2; | ||
grid-row-end: 3; | ||
grid-column-start: 2; | ||
grid-column-end: 3; | ||
display: none; | ||
} | ||
|
||
#expand-state-constraint:checked ~ #constraint-menu-list { | ||
display: block; | ||
} | ||
|
||
#constraint-menu-expand-label { | ||
padding-right: 2em; | ||
position: relative; | ||
display: flex; | ||
grid-column-start: 1; | ||
grid-column-end: 2; | ||
align-items: center; | ||
} | ||
|
||
#expand-state-constraint:checked ~ #constraint-menu-expand-label { | ||
grid-column-end: 3; | ||
} | ||
|
||
#constraint-menu-expand-label::after { | ||
content: ""; | ||
background-image: url("@fortawesome/fontawesome-free/svgs/solid/chevron-up.svg"); | ||
right: 0.5em; | ||
position: absolute; | ||
display: inline-block; | ||
|
||
/* only filter=invert(1) if dark mode is enabled aka --dark-mode is set to 1 */ | ||
filter: invert(var(--dark-mode)); | ||
|
||
width: 16px; | ||
height: 16px; | ||
background-size: 16px 16px; | ||
|
||
transition: transform 500ms ease; | ||
transform: scaleY(1); | ||
} | ||
|
||
#expand-state-constraint:checked ~ #constraint-menu-expand-label::after { | ||
transform: scaleY(-1); | ||
} | ||
|
||
.constrain-label input { | ||
background-color: var(--color-background); | ||
text-align: center; | ||
border: 1px solid var(--color-foreground); | ||
border-radius: 15px; | ||
padding: 3px; | ||
margin: 4px; | ||
} | ||
|
||
.constrain-label button { | ||
background-color: transparent; | ||
border: none; | ||
cursor: pointer; | ||
padding: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { ContainerModule } from "inversify"; | ||
import { EDITOR_TYPES } from "../../utils"; | ||
import { ConstraintMenu } from "./ConstraintMenu"; | ||
import { TYPES } from "sprotty"; | ||
|
||
// This module contains an UI extension that adds a tool palette to the editor. | ||
// This tool palette allows the user to create new nodes and edges. | ||
// Additionally it contains the tools that are used to create the nodes and edges. | ||
|
||
export const constraintMenuModule = new ContainerModule((bind) => { | ||
bind(ConstraintMenu).toSelf().inSingletonScope(); | ||
bind(TYPES.IUIExtension).toService(ConstraintMenu); | ||
bind(EDITOR_TYPES.DefaultUIElement).toService(ConstraintMenu); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters