From 584e77dc4f8fd0a23601d258247f67b1f15c5c05 Mon Sep 17 00:00:00 2001 From: Manjunath Paparaju Date: Fri, 13 Nov 2026 10:31:58 +0530 Subject: [PATCH] Add a finder and a section index to Data Layers The Data Layers panel gains a search field, an All / On / Off and category filter, and a tick index down its side for jumping between sections. Both sit beside the Data Library browse control. Co-authored-by: Sameh Khamis --- src/ui/styles/layer-finder.css | 187 ++++++++++++++++++++++ src/ui/styles/layer-section-index.css | 98 ++++++++++++ src/ui/views/LayerPanelsView.vue | 5 + src/ui/views/panels/LayerFinder.vue | 148 +++++++++++++++++ src/ui/views/panels/LayerSectionIndex.vue | 74 +++++++++ 5 files changed, 512 insertions(+) create mode 100644 src/ui/styles/layer-finder.css create mode 100644 src/ui/styles/layer-section-index.css create mode 100644 src/ui/views/panels/LayerFinder.vue create mode 100644 src/ui/views/panels/LayerSectionIndex.vue diff --git a/src/ui/styles/layer-finder.css b/src/ui/styles/layer-finder.css new file mode 100644 index 000000000..865e6b9c4 --- /dev/null +++ b/src/ui/styles/layer-finder.css @@ -0,0 +1,187 @@ +/* ── Data Layers search and filter ── */ +.layer-finder__btn { + display: grid; + flex: none; + place-items: center; + width: 22px; + height: 22px; + padding: 0; + color: rgba(206, 232, 239, 0.65); + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 6px; + cursor: pointer; +} + +.layer-finder__btn .material-symbols-outlined { + font-size: 14px; +} + +.layer-finder__btn:hover, +.layer-finder__btn:focus-visible { + color: #fff; + border-color: rgba(255, 255, 255, 0.24); +} + +.layer-finder__btn.active { + color: #36dcff; + background: rgba(54, 220, 255, 0.12); + border-color: rgba(54, 220, 255, 0.45); +} + +.layer-finder__filter { + position: relative; + display: inline-flex; +} + +.layer-finder__menu { + position: absolute; + top: calc(100% + 6px); + right: 0; + z-index: 20; + display: grid; + min-width: 140px; + padding: 4px; + background: rgba(16, 20, 28, 0.96); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 10px; + box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5); +} + +.layer-finder__menu button { + display: flex; + align-items: center; + gap: 0.45rem; + padding: 0.4rem 0.55rem; + color: rgba(225, 236, 242, 0.85); + font-size: 0.72rem; + text-align: start; + background: none; + border: 0; + border-radius: 7px; + cursor: pointer; +} + +.layer-finder__menu button .material-symbols-outlined { + font-size: 14px; + color: rgba(199, 214, 222, 0.6); +} + +.layer-finder__menu button:hover { + background: rgba(255, 255, 255, 0.06); +} + +.layer-finder__menu button.active, +.layer-finder__menu button.active .material-symbols-outlined { + color: #7af0ff; +} + +.layer-finder__bar { + display: flex; + flex: none; + align-items: center; + gap: 0.4rem; + margin: 0.2rem 0 0.5rem; +} + +.layer-finder__field { + display: flex; + flex: 1 1 auto; + align-items: center; + gap: 0.35rem; + padding: 0 0.55rem; + height: 30px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(54, 220, 255, 0.3); + border-radius: 8px; +} + +.layer-finder__field .material-symbols-outlined { + color: rgba(199, 214, 222, 0.6); + font-size: 15px; +} + +.layer-finder__field input { + flex: 1 1 auto; + min-width: 0; + color: rgba(236, 244, 248, 0.95); + font-size: 0.75rem; + background: none; + border: 0; + outline: none; +} + +.layer-finder__chip { + display: inline-flex; + flex: none; + align-items: center; + gap: 0.25rem; + height: 26px; + padding: 0 0.5rem; + color: #7af0ff; + font-family: var(--font-mono); + font-size: 0.56rem; + letter-spacing: 0.1rem; + text-transform: uppercase; + background: rgba(54, 220, 255, 0.12); + border: 1px solid rgba(54, 220, 255, 0.45); + border-radius: 999px; + cursor: pointer; +} + +.layer-finder__chip .material-symbols-outlined { + font-size: 12px; +} + +/* Rows and group headings the search or filter leaves out. */ +#data-toggles .is-filtered { + display: none !important; +} + +#data-toggles.is-filtering[data-shown='0']::after { + content: 'No layers match'; + display: block; + padding: 1rem 0.5rem; + color: rgba(199, 214, 222, 0.5); + font-size: 0.72rem; + text-align: center; +} + +.layer-finder__menu { + max-height: 60vh; + overflow-y: auto; + min-width: 170px; +} + +.layer-finder__menu-head { + padding: 0.45rem 0.55rem 0.2rem; + color: rgba(199, 214, 222, 0.5); + font-family: var(--font-mono); + font-size: 0.52rem; + letter-spacing: 0.14rem; + text-transform: uppercase; +} + +.layer-finder__menu-head:not(:first-child) { + margin-top: 0.2rem; + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +/* Several chips can show at once. */ +.layer-finder__bar { + flex-wrap: wrap; +} + +/* Chips sized like the rows' ON/OFF switches: small and square. */ +.layer-finder__chip { + height: 20px; + gap: 0.2rem; + padding: 0 6px 0 8px; + font-size: 9px; + letter-spacing: 0.08rem; + border-radius: 4px; +} + +.layer-finder__chip .material-symbols-outlined { + font-size: 11px; +} diff --git a/src/ui/styles/layer-section-index.css b/src/ui/styles/layer-section-index.css new file mode 100644 index 000000000..a2695e019 --- /dev/null +++ b/src/ui/styles/layer-section-index.css @@ -0,0 +1,98 @@ +/* ── Data Layers group index: ticks along the panel's right edge ─────── */ +#data-panel { + position: relative; +} + +.layer-section-index { + position: absolute; + top: 64px; + right: 2px; + bottom: 24px; + z-index: 2; + display: flex; + flex-direction: column; + justify-content: center; + gap: 6px; + width: 10px; +} + +#data-panel.collapsed .layer-section-index { + display: none; +} + +.layer-section-index__tick { + position: relative; + width: 10px; + height: 16px; + padding: 0; + background: none; + border: 0; + cursor: pointer; +} + +.layer-section-index__tick::before { + content: ''; + position: absolute; + top: 2px; + bottom: 2px; + left: 4px; + width: 2px; + border-radius: 2px; + background: rgba(199, 214, 222, 0.32); + transition: + background 140ms ease, + box-shadow 140ms ease, + transform 140ms ease; +} + +.layer-section-index__tick:hover::before, +.layer-section-index__tick:focus-visible::before { + background: rgba(236, 244, 248, 0.85); + transform: scaleX(1.5); +} + +.layer-section-index__tick.is-current::before { + background: #36dcff; + box-shadow: 0 0 6px rgba(54, 220, 255, 0.6); +} + +.layer-section-index__tick:focus-visible { + outline: none; +} + +/* The group's name, shown to the left (inside the panel) on hover or + focus. Hidden labels take no room, so nothing reaches past the panel. */ +.layer-section-index__label { + position: absolute; + top: 50%; + right: 14px; + padding: 0.25rem 0.5rem; + color: rgba(236, 244, 248, 0.92); + font-family: var(--font-mono); + font-size: 0.56rem; + letter-spacing: 0.12rem; + text-transform: uppercase; + white-space: nowrap; + background: rgba(12, 12, 20, 0.88); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + display: none; + opacity: 0; + transform: translate(4px, -50%); + pointer-events: none; + z-index: 3; + transition: + opacity 120ms ease, + transform 120ms ease; +} + +.layer-section-index__tick:hover .layer-section-index__label, +.layer-section-index__tick:focus-visible .layer-section-index__label { + display: block; + opacity: 1; + transform: translate(0, -50%); +} + +body.mobile-shell .layer-section-index { + display: none; +} diff --git a/src/ui/views/LayerPanelsView.vue b/src/ui/views/LayerPanelsView.vue index b87525530..0d577ca1d 100644 --- a/src/ui/views/LayerPanelsView.vue +++ b/src/ui/views/LayerPanelsView.vue @@ -14,6 +14,8 @@ import StreetLevelPanel from './panels/StreetLevelPanel.vue'; import DrawControls from './panels/DrawControls.vue'; import GeoImport from './panels/GeoImport.vue'; import UiSelect from '../kit/UiSelect.js'; +import LayerSectionIndex from './panels/LayerSectionIndex.vue'; +import LayerFinder from './panels/LayerFinder.vue'; import DataLibraryBrowse from './panels/DataLibraryBrowse.vue'; // Scene sharing (src/scenes/sharing.js) offers its authoring bar and presents @@ -43,7 +45,10 @@ async function importChosen(event) {
+ +
+
diff --git a/src/ui/views/panels/LayerFinder.vue b/src/ui/views/panels/LayerFinder.vue new file mode 100644 index 000000000..5d4d89601 --- /dev/null +++ b/src/ui/views/panels/LayerFinder.vue @@ -0,0 +1,148 @@ + + + diff --git a/src/ui/views/panels/LayerSectionIndex.vue b/src/ui/views/panels/LayerSectionIndex.vue new file mode 100644 index 000000000..5bf6e394d --- /dev/null +++ b/src/ui/views/panels/LayerSectionIndex.vue @@ -0,0 +1,74 @@ + + +