implement basics of menu-bar
This commit is contained in:
parent
ea6813b415
commit
ba3adc63c4
17
index.html
17
index.html
|
|
@ -25,12 +25,15 @@
|
|||
<div data-section="View" data-alt="v">
|
||||
<div data-section="Test" data-alt="e">
|
||||
<div data-section="Test" data-alt="e">
|
||||
<button disabled>-</button>
|
||||
<button disabled>1</button>
|
||||
</div>
|
||||
<button disabled>2</button>
|
||||
<button>102983019283012</button>
|
||||
</div>
|
||||
<button disabled>3</button>
|
||||
</div>
|
||||
</nav>
|
||||
<nav id="left-menu" data-state="planning">
|
||||
<aside id="left-menu" data-state="planning">
|
||||
<span data-resize="left-menu"></span>
|
||||
<section id="block-picker">
|
||||
<label>
|
||||
|
|
@ -43,7 +46,7 @@
|
|||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</nav>
|
||||
</aside>
|
||||
<main>
|
||||
<div data-state="initialization">
|
||||
Select configuration file:
|
||||
|
|
@ -62,11 +65,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<nav id="right-menu">
|
||||
<aside id="right-menu">
|
||||
<span data-resize="right-menu"></span>
|
||||
</nav>
|
||||
<nav id="bottom-menu">
|
||||
</aside>
|
||||
<footer id="bottom-menu">
|
||||
<span data-resize="bottom-menu"></span>
|
||||
</nav>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1 +1,108 @@
|
|||
export function initializeMenuBar() {}
|
||||
import { positionAsTooltip } from "./tooltip.js";
|
||||
|
||||
let activeMenuBar = null;
|
||||
|
||||
export function initializeMenuBar() {
|
||||
document.querySelectorAll(".menu-bar").forEach(menuBar => {
|
||||
menuBar.querySelectorAll("button").forEach(button => {
|
||||
button.setAttribute("tabindex", "-1");
|
||||
button.replaceChildren(createAltSpan(button, button.innerText));
|
||||
button.addEventListener("click", e => {
|
||||
menuBar.classList.remove("active");
|
||||
menuBar.querySelectorAll(".active")
|
||||
.forEach(elem => elem.classList.remove("active"));
|
||||
activeMenuBar = null;
|
||||
});
|
||||
button.addEventListener("mouseenter", () => {
|
||||
if (!activeMenuBar) return;
|
||||
|
||||
button.parentElement.querySelectorAll(".active")
|
||||
.forEach(elem => elem.classList.remove("active"));
|
||||
});
|
||||
});
|
||||
menuBar.querySelectorAll("[data-section]").forEach(section => {
|
||||
const button = document.createElement("button");
|
||||
button.setAttribute("tabindex", "-1");
|
||||
button.dataset.forSection = "";
|
||||
button.appendChild(createAltSpan(section, section.dataset.section));
|
||||
section.parentElement.insertBefore(button, section);
|
||||
|
||||
section.addEventListener("click", e => e.stopPropagation());
|
||||
button.addEventListener("click", e => e.stopPropagation());
|
||||
|
||||
function updateActive() {
|
||||
if (!activeMenuBar) return;
|
||||
|
||||
button.parentElement.querySelectorAll(".active")
|
||||
.forEach(elem => elem.classList.remove("active"));
|
||||
button.classList.add("active");
|
||||
section.classList.add("active");
|
||||
positionAsTooltip(button, section, {
|
||||
horizontal: section.parentElement === menuBar ? "left" : "right",
|
||||
vertical: section.parentElement === menuBar ? "bottom" : "top",
|
||||
});
|
||||
}
|
||||
|
||||
if (section.parentElement === menuBar) {
|
||||
button.addEventListener("click", () => {
|
||||
if (section.classList.contains("active")) {
|
||||
menuBar.classList.remove("active");
|
||||
menuBar.querySelectorAll(".active")
|
||||
.forEach(elem => elem.classList.remove("active"));
|
||||
activeMenuBar = null;
|
||||
} else {
|
||||
menuBar.querySelectorAll(".active")
|
||||
.forEach(elem => elem.classList.remove("active"));
|
||||
menuBar.classList.add("active");
|
||||
section.classList.add("active");
|
||||
window.addEventListener("click", handleGlobalClick);
|
||||
activeMenuBar = menuBar;
|
||||
updateActive();
|
||||
}
|
||||
});
|
||||
}
|
||||
button.addEventListener("mouseenter", updateActive);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: keyboard navigation with alt and arrow keys
|
||||
}
|
||||
|
||||
|
||||
function handleGlobalClick() {
|
||||
console.log("Global clicked");
|
||||
if (!activeMenuBar) return;
|
||||
activeMenuBar.classList.remove("active");
|
||||
activeMenuBar.querySelectorAll(".active")
|
||||
.forEach(section => section.classList.remove("active"));
|
||||
activeMenuBar = null;
|
||||
window.removeEventListener("click", handleGlobalClick);
|
||||
}
|
||||
|
||||
function createAltSpan(element, text) {
|
||||
const altKey = element.dataset.alt;
|
||||
|
||||
if (!altKey) {
|
||||
const span = document.createElement("span");
|
||||
span.appendChild(document.createTextNode(text));
|
||||
return span;
|
||||
}
|
||||
|
||||
const [ , before, key, after ] = new RegExp(`^(.*)(${altKey})(.*)$`, "i").exec(text);
|
||||
const span = document.createElement("span");
|
||||
|
||||
if (before) {
|
||||
span.appendChild(document.createTextNode(before));
|
||||
}
|
||||
|
||||
const underlineSpan = document.createElement("span");
|
||||
underlineSpan.innerText = key;
|
||||
underlineSpan.classList.add("alt-key");
|
||||
span.appendChild(underlineSpan);
|
||||
|
||||
if (after) {
|
||||
span.appendChild(document.createTextNode(after));
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ export function deleteTooltip(id) {
|
|||
delete tooltips[id];
|
||||
}
|
||||
|
||||
export function positionAsTooltip(mainElement, tooltipElement, { horizontal = "left", vertical = "bottom" } = {}) {
|
||||
const targetRect = mainElement.getBoundingClientRect();
|
||||
const domRect = tooltipElement.getBoundingClientRect();
|
||||
const windowWidth = window.innerWidth, windowHeight = window.innerHeight;
|
||||
tooltipElement.style.left = `${Math.min(targetRect[horizontal], windowWidth - domRect.width)}px`;
|
||||
tooltipElement.style.top = `${Math.min(targetRect[vertical], windowHeight - domRect.height)}px`;
|
||||
}
|
||||
|
||||
function showTooltip() {
|
||||
if (suppressTooltips) return;
|
||||
if (!lastCoordinates) return;
|
||||
|
|
@ -66,11 +74,7 @@ function showTooltip() {
|
|||
dom.style.top = `${targetRect.bottom}px`;
|
||||
|
||||
target.appendChild(dom);
|
||||
|
||||
const domRect = dom.getBoundingClientRect();
|
||||
const windowWidth = window.innerWidth, windowHeight = window.innerHeight;
|
||||
dom.style.left = `${Math.min(targetRect.left, windowWidth - domRect.width)}px`;
|
||||
dom.style.top = `${Math.min(targetRect.bottom, windowHeight - domRect.height)}px`;
|
||||
positionAsTooltip(target, dom);
|
||||
|
||||
activeTooltipTarget = target;
|
||||
}
|
||||
|
|
|
|||
47
style.css
47
style.css
|
|
@ -14,6 +14,7 @@
|
|||
--default-size: 16px;
|
||||
|
||||
--dark-bg: #990099;
|
||||
--dark-bg-text: #fffe;
|
||||
--menu-border-color: #666;
|
||||
--resize-handle-color: #666;
|
||||
--resize-handle-width: 3px;
|
||||
|
|
@ -45,7 +46,7 @@
|
|||
body {
|
||||
display: grid;
|
||||
grid-template-columns: var(--left-menu-size, 15%) 1fr var(--right-menu-size, 10%);
|
||||
grid-template-rows: 28px 1fr var(--bottom-menu-size, 15%);
|
||||
grid-template-rows: min-content 1fr var(--bottom-menu-size, 15%);
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -54,6 +55,7 @@ body {
|
|||
grid-row: 1;
|
||||
|
||||
background-color: var(--dark-bg);
|
||||
color: var(--dark-bg-text);
|
||||
}
|
||||
#left-menu {
|
||||
grid-column: 1;
|
||||
|
|
@ -229,3 +231,46 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
|
|||
border: var(--tooltip-border-size, 1px) solid var(--tooltip-border-color, #fff);
|
||||
/*max-width: var(--tooltip-width, 200px);*/
|
||||
}
|
||||
|
||||
.menu-bar {
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
.menu-bar > [data-section] {
|
||||
display: inline;
|
||||
}
|
||||
.menu-bar [data-section]:not(.active) {
|
||||
display: none;
|
||||
}
|
||||
.menu-bar [data-section] {
|
||||
position: fixed;
|
||||
background: var(--menu-bg, #222);
|
||||
color: var(--menu-fg, #fffe);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 100;
|
||||
box-shadow: var(--menu-shadow, 0 2px 4px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
.menu-bar button {
|
||||
all: initial;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
padding: var(--menu-item-padding, 0.25em);
|
||||
font-size: var(--menu-item-font-size, 0.8em);
|
||||
cursor: default;
|
||||
}
|
||||
.menu-bar button:disabled {
|
||||
color: var(--menu-item-disabled-color, #aaae);
|
||||
}
|
||||
.menu-bar [data-section] button.active, .menu-bar [data-section] button:hover:not(:disabled) {
|
||||
background: var(--menu-bg-hover, #444);
|
||||
color: var(--menu-fg-hover, #fffe);
|
||||
}
|
||||
.menu-bar [data-section] button[data-for-section]::after {
|
||||
content: '>';
|
||||
float: right;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.menu-bar .alt-key {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue