diff --git a/Menus/.gitignore b/Menus/.gitignore new file mode 100644 index 0000000..18c426d --- /dev/null +++ b/Menus/.gitignore @@ -0,0 +1,2 @@ +css/style.css.map +css/style.css \ No newline at end of file diff --git a/Menus/README.md b/Menus/README.md new file mode 100644 index 0000000..a1ae1b5 --- /dev/null +++ b/Menus/README.md @@ -0,0 +1 @@ +Menu system written in JS and Sass, uses json to markup the menus \ No newline at end of file diff --git a/Menus/css/style.sass b/Menus/css/style.sass new file mode 100644 index 0000000..b8e845f --- /dev/null +++ b/Menus/css/style.sass @@ -0,0 +1,182 @@ +$primary: rgb(66, 130, 167) +$success: rgb(95, 175, 99) +$warning: rgb(236, 136, 77) +$critical: rgb(247, 111, 111) + +$fg100: rgb(248,248,250) +$fg200: rgb(225,227,233) +$fg300: rgb(203,205,216) +$fg400: rgb(180,184,200) +$fg500: rgb(146,150,169) +$fg600: rgb(78,83,106) + +$bg100: rgb(61,66,83) +$bg200: rgb(50,54,68) +$bg300: rgb(42,45,57) +$bg400: rgb(37,39,50) +$bg500: rgb(32,35,44) +$bg600: rgb(28,30,38) + +* + box-sizing: border-box + +html + font-size: 16px + font-family: 'Roboto', sans-serif + font-weight: 400 + color: $fg100 + background-color: $bg500 + +body + display: flex + flex-direction: row + justify-content: center + align-items: center + gap: 1rem + + > button + margin: 0 + padding: 0.5rem 1rem + + width: auto + height: 3rem + + display: flex + justify-content: center + align-items: center + + color: $fg100 + background-color: $bg300 + border: 1px solid $bg200 + border-radius: 3px + + cursor: pointer + + transition: all 0.2s ease-in-out + + &:hover + background-color: $bg200 + +.contextMenuClose + width: 100vw + height: 100vh + + position: fixed + top: 0 + left: 0 + + background-color: transparent + z-index: 99998 + +.contextMenu + margin: 0 + padding: 0.25rem + + width: calc( 100vw - 10px ) + height: auto + max-width: 300px + + position: absolute + + display: flex + flex-direction: column + justify-content: flex-start + align-items: flex-start + gap: 0.25rem + + background-color: $bg300 + border: 1px solid $bg200 + border-radius: 6px + + overflow: hidden + + transition: all 0.2s ease-in-out + transform-origin: top left + opacity: 0 + transform: scale(0, 0) + z-index: 99999 + +.contextMenuTitle + margin: 0 + padding: 0.25rem 0.5rem + + width: 100% + + text-align: center + font-size: 1.2rem + font-weight: 400 + color: $fg300 + +.contextMenuItem + margin: 0 + padding: 0.25rem + + width: 100% + height: auto + + display: flex + flex-direction: row + justify-content: flex-start + align-items: center + gap: 0.5rem + + background-color: $bg300 + color: $fg300 + border: none + border-radius: 3px + + cursor: pointer +.contextMenuItem:hover + background-color: $bg200 +.contextMenuItem__critical + color: $critical +//.contextMenuItem__critical:hover +// background-color: rgba($critical, 0.1) +.contextMenuItem__warning + color: $warning +//.contextMenuItem__warning:hover +// background-color: rgba($warning, 0.1) +.contextMenuItem__success + color: $success +//.contextMenuItem__success:hover +// background-color: rgba($success, 0.1) +.contextMenuItem__info + color: $primary +//.contextMenuItem__info:hover +// background-color: rgba($primary, 0.1) + +.contextMenuText + margin: 0 + padding: 0 + + font-size: 1rem + font-weight: 400 + +.contextMenuIcon + margin: 0 + padding: 0 + + width: 1.25rem + height: 1.25rem + + display: flex + justify-content: center + align-items: center + +.contextMenuDivider + margin: 0 auto + padding: 0 + + width: 90% + height: 1px + + border: none + background-color: $bg200 + +.contextMenu__show + opacity: 1 + transform: scale(1, 1) + +.contextMenu__hide + opacity: 0 + transform: scale(0, 0) \ No newline at end of file diff --git a/Menus/index.html b/Menus/index.html new file mode 100644 index 0000000..7ac24b3 --- /dev/null +++ b/Menus/index.html @@ -0,0 +1,110 @@ + + + + + + + JS menus + + + + + + + + + + \ No newline at end of file diff --git a/Menus/js/main.js b/Menus/js/main.js new file mode 100644 index 0000000..22f3b7e --- /dev/null +++ b/Menus/js/main.js @@ -0,0 +1,130 @@ +/* + Function takes an object as a parameter to + determine where to display the context menu + + menu: + value - Text to display + icon - True for default icon, false for no icon, or a string for a custom icon + function - Function to call when clicked + type - Type of menu item (critical, warning, success, info) +*/ + +function showContextMenu(obj, menu) { + // If the context menu is already open, close it first + if (document.querySelector(".contextMenu")) { + dissmissContextMenu(); + } + + // Add span to close the context menu + var closeSpan = document.createElement("span"); + closeSpan.className = "contextMenuClose"; + closeSpan.onclick = dissmissContextMenu; + + // Create the context menu + var contextMenu = document.createElement("div"); + contextMenu.className = "contextMenu"; + + // Create the menu items + menu.forEach(array => { + if (array.value == "divider") { + // If the menu item is a divider, create a divider + var divider = document.createElement("hr"); + divider.className = "contextMenuDivider"; + contextMenu.appendChild(divider); + return; + } else if (array.value == "title") { + // Create the title and add it to the context menu + var titleP = document.createElement("p"); + titleP.className = "contextMenuTitle"; + titleP.innerHTML = array.text; + contextMenu.appendChild(titleP); + // Add a divider after the title + var divider = document.createElement("hr"); + divider.className = "contextMenuDivider"; + contextMenu.appendChild(divider); + return; + } + + // Create the menu item + itemBtn = document.createElement("button"); + itemBtn.className = "contextMenuItem"; + itemBtn.onclick = array.function; + + if (array.type == "critical") { + itemBtn.classList.add("contextMenuItem__critical"); + } else if (array.type == "warning") { + itemBtn.classList.add("contextMenuItem__warning"); + } else if (array.type == "success") { + itemBtn.classList.add("contextMenuItem__success"); + } else if (array.type == "info") { + itemBtn.classList.add("contextMenuItem__info"); + } + + // Create the icon for the action + itemIcon = document.createElement("span"); + itemIcon.className = "contextMenuIcon"; + // Determine if the menu item has an icon + if (array.icon != null) { + itemIcon.innerHTML = array.icon; + } else { + itemIcon.innerHTML = ''; + } + itemBtn.appendChild(itemIcon); + + // Create the text for the action + itemText = document.createElement("p"); + itemText.className = "contextMenuText"; + itemText.innerHTML = array.value; + itemBtn.appendChild(itemText); + + // Add menu item to the context menu + contextMenu.appendChild(itemBtn); + }); + + // Add the context menu to the body + document.body.appendChild(contextMenu); + document.body.appendChild(closeSpan); + + // Get position of the item clicked or the mouse + try { + var posX = event.clientX + 5; + var posY = event.clientY + 5; + } catch (error) { + var posX = obj.offsetLeft + (bj.offsetWidth * 0.6) + 2; + var posY = obj.offsetTop + obj.offsetHeight + 2 + } + + // Move the context menu if it is off the screen + if (posX + contextMenu.offsetWidth > window.innerWidth) { + posX = window.innerWidth - (contextMenu.offsetWidth + 5); + } + if (posY + contextMenu.offsetHeight > window.innerHeight) { + posY = window.innerHeight - (contextMenu.offsetHeight + 5); + } + + contextMenu.style.left = posX + "px"; + contextMenu.style.top = posY + "px"; + + setTimeout(function() { + contextMenu.classList.add("contextMenu__show"); + }, 1); +} + +function dissmissContextMenu() { + // Remove the close span + var contextMenu = document.querySelectorAll(".contextMenuClose"); + contextMenu.forEach(menu => { + menu.remove(); + }); + + // Get the context menu + var contextMenu = document.querySelectorAll(".contextMenu"); + + contextMenu.forEach(menu => { + menu.classList.add("contextMenu__hide"); + // Animatin should be 500ms + setTimeout(function() { + menu.remove(); + }, 500); + }); +} \ No newline at end of file