From 8c015e5235350db76647f208cb45703df4988c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20B=C4=82LTEANU?= Date: Mon, 13 Jul 2026 00:33:26 +0300 Subject: [PATCH] Refactor context menus to use the new dropdown component and extend dropdowns to support nested levels. --- app/assets/javascripts/context_menu.js | 1 + app/assets/stylesheets/application.css | 2 +- app/assets/stylesheets/context_menu.css | 33 +++-------- app/assets/stylesheets/dropdown.css | 77 +++++++++++++++++++++---- 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/app/assets/javascripts/context_menu.js b/app/assets/javascripts/context_menu.js index a2f7ed5b5..7feb6038a 100644 --- a/app/assets/javascripts/context_menu.js +++ b/app/assets/javascripts/context_menu.js @@ -90,6 +90,7 @@ function contextMenuCreate() { if ($('#context-menu').length < 1) { var menu = document.createElement("div"); menu.setAttribute("id", "context-menu"); + menu.setAttribute("class", "dropdown-content"); menu.setAttribute("style", "display:none;"); document.getElementsByTagName("body")[0].appendChild(menu); } diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 54579408f..6417dd7d8 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -116,7 +116,7 @@ nav.top-menu { } #account .dropdown-content .user-info { - padding-block: 10px; + padding-block: 6px; padding-inline: 16px; color: var(--oc-gray-9); } diff --git a/app/assets/stylesheets/context_menu.css b/app/assets/stylesheets/context_menu.css index 94700ff19..9225c19ca 100644 --- a/app/assets/stylesheets/context_menu.css +++ b/app/assets/stylesheets/context_menu.css @@ -4,33 +4,20 @@ * This code is released under the GNU General Public License. */ -#context-menu { position: absolute; z-index: 40; font-size: 0.9em;} - -#context-menu ul, #context-menu li, #context-menu a { - margin:0; - padding:0; - border:0; -} +#context-menu { position: absolute; z-index: 1000; font-size: 0.9em;} +#context-menu.dropdown-content { inset-block-start: auto; inset-inline-end: auto; margin-block-start: 0; } #context-menu ul { - min-inline-size: 150px; + min-inline-size: 160px; max-inline-size: 300px; - border: 1px solid var(--oc-gray-4); - background:white; list-style:none; - padding:2px; - border-radius:2px; - box-shadow: 0 2px 4px rgba(var(--oc-gray-9-rgb), 0.1); } #context-menu li { position:relative; - padding:1px; z-index:39; - border:1px solid white; - display: flex; } -#context-menu li.folder ul { position: absolute; inset-block-start: -2px; max-block-size: 300px; overflow: hidden; overflow-y: auto; } +#context-menu li.folder ul { position: absolute; inset-block-start: -4px; max-block-size: 300px; overflow: hidden; overflow-y: auto; } #context-menu li.folder>ul { inset-inline-start: 100%; } #context-menu.reverse-y li.folder>ul, #context-menu li.folder.up>ul { inset-block: auto 0; } @@ -38,22 +25,18 @@ #context-menu.reverse-x li.folder>ul { inset-inline-end: 100%; } #context-menu.reverse-y li.folder.down>ul { - position: absolute; inset-block: -2px auto; max-block-size: 300px; overflow: hidden; overflow-y: auto; + position: absolute; inset-block: -4px auto; max-block-size: 300px; overflow: hidden; overflow-y: auto; } #context-menu a { text-decoration:none !important; - padding-block: 2px; - padding-inline: 8px; + padding-block: 6px; + display: flex; + align-items: center; } #context-menu li>a { flex-grow: 1; } #context-menu a.disabled, #context-menu a.disabled:hover {color: var(--oc-gray-5);} -#context-menu li a.submenu { padding-inline-start: 28px;} -#context-menu li:hover { border:1px solid var(--oc-blue-8); background-color:var(--oc-blue-0); border-radius:3px; } #context-menu a:hover {color:var(--oc-blue-9);} -#context-menu li.folder ul li a:not(.icon) { - padding-inline-start: 28px; -} #context-menu li.folder:hover { z-index:40; } #context-menu ul ul, #context-menu li:hover ul ul { display:none; } #context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } diff --git a/app/assets/stylesheets/dropdown.css b/app/assets/stylesheets/dropdown.css index 55550e239..035426c1c 100644 --- a/app/assets/stylesheets/dropdown.css +++ b/app/assets/stylesheets/dropdown.css @@ -17,40 +17,97 @@ } .dropdown-content { + /* Configuration Variables */ + --dropdown-bg: var(--oc-white); + --dropdown-border: var(--oc-gray-4); + --dropdown-shadow: rgba(var(--oc-black-rgb), 0.1); + --dropdown-item-padding-block: 6px; + --dropdown-item-padding-inline: 16px; + --dropdown-hover-bg: var(--oc-gray-1); + --dropdown-active-color: var(--oc-blue-9); + position: absolute; inset-block-start: 100%; inset-inline-end: 0; - background-color: var(--oc-white); - border: 1px solid var(--oc-gray-4); + background-color: var(--dropdown-bg); + border: 1px solid var(--dropdown-border); border-radius: 4px; - box-shadow: 0 4px 6px rgba(var(--oc-black-rgb), 0.1); + box-shadow: 0 4px 6px var(--dropdown-shadow); z-index: 1000; min-inline-size: 160px; margin-block-start: 4px; + padding-block: 4px; } .dropdown-content ul { list-style: none; margin: 0; padding: 0; + border: 0; +} + +.dropdown-content li { + position: relative; + display: flex; + align-items: center; + width: 100%; + margin: 0; + padding: 0; + border: 0; } .dropdown-content li a, .dropdown-content .dropdown-items a { display: flex; - padding-block: 8px; - padding-inline: 16px; + align-items: center; + flex-grow: 1; + padding-block: var(--dropdown-item-padding-block); + padding-inline: var(--dropdown-item-padding-inline); font-weight: normal; margin: 0; + border: 0; + text-decoration: none; +} + +.dropdown-content li a.disabled { + color: var(--oc-gray-5) !important; + cursor: not-allowed; +} + +.dropdown-content li:hover:not(:has(> a.disabled)), +.dropdown-content .dropdown-items a:hover { + background-color: var(--dropdown-hover-bg); } -.dropdown-content li a:hover, .dropdown-content .dropdown-items a:hover { - background-color: var(--oc-gray-1); - color: var(--oc-blue-9); +.dropdown-content li:hover:not(:has(> a.disabled)) > a, +.dropdown-content .dropdown-items a:hover { + color: var(--dropdown-active-color); text-decoration: none; } -.dropdown-content li a:hover .icon-svg, .dropdown-content .dropdown-items a:hover .icon-svg { - stroke: var(--oc-blue-9); +.dropdown-content li:hover:not(:has(> a.disabled)) .icon-svg, +.dropdown-content .dropdown-items a:hover .icon-svg { + stroke: var(--dropdown-active-color); +} + +/* Align text of all items identically if any item inside the dropdown contains an icon */ +.dropdown-content:has(.icon-svg) li a, +.dropdown-content:has(.icon-svg) .dropdown-items a { + padding-inline-start: 36px; +} + +.dropdown-content li a .icon-svg, +.dropdown-content .dropdown-items a .icon-svg { + position: absolute; + inset-inline-start: 12px; +} + +/* Submenu / Nested List support */ +.dropdown-content li ul { + background-color: var(--dropdown-bg); + border: 1px solid var(--dropdown-border); + border-radius: 4px; + box-shadow: 0 4px 6px var(--dropdown-shadow); + padding-block: 4px; } .dropdown-divider { -- 2.50.1 (Apple Git-155)