From 5826ac5cd8ddcf3ed7ccf615ab4d4fe8bdd3f49a Mon Sep 17 00:00:00 2001 From: Cesar Ferreyra-Mansilla Date: Tue, 19 Nov 2024 13:39:00 -0500 Subject: [PATCH 1/3] -chore: add buttons for feedback -style: reorganize buttons -feat: new mail icon -feat: set variable to hold email address --- src/App.css | 184 +++++++++++++++++++++++++++++++++------------------- src/App.tsx | 24 +++++-- src/icon.ts | 10 +++ 3 files changed, 147 insertions(+), 71 deletions(-) diff --git a/src/App.css b/src/App.css index ea02fe9c..e3e184b4 100644 --- a/src/App.css +++ b/src/App.css @@ -994,97 +994,147 @@ a:hover { .open-in-chromoscope-link:hover { text-decoration: none; - cursor: pointer; - background-color: #ebebeb; } .open-in-chromoscope-link:active { background-color: #e6e4e4; } - .export-links { - border-radius: 4px; - margin-top: 4px; - - .export-dropdown { - height: auto; - background-color: #f6f6f6; - right: 0px; - border-radius: 8px; - border: 1px solid #d3d3d3; - transition: all 100ms; - overflow: hidden; - - .export-button { - box-sizing: border-box !important; - width: 210px; - height: 35px; - border-radius: inherit; - border: 0px solid; - font-weight: 400; - background-color: transparent; + .button-group { + display: flex; + gap: 4px; + + .export-links { + position: relative; + border-radius: 4px; + margin-top: 4px; + + .export-dropdown { + height: auto; + /* background-color: #f6f6f6; */ + right: 0px; + border-radius: 8px; + transition: all 100ms; + overflow: hidden; + + .export-button { + position: relative; + box-sizing: border-box !important; + width: 120px; + height: 35px; + border: 1px solid #d3d3d3; + border-radius: inherit; + font-weight: 400; + + .export-title { + font-size: 0.9rem; + font-family: Inter; + } - .export-title { - font-size: 0.9rem; - font-family: Inter; + .button.triangle-down { + width: 11px; + height: 7px; + margin-left: 8px; + } } - .button.triangle-down { - width: 11px; - height: 7px; - margin-left: 8px; + .nav-list { + list-style-type: none; + padding: 0px; + display: flex; + flex-direction: row; + height: 50px; + background-color: white; + border: 1px solid rgb(221, 221, 221); + margin: 0px; + border-radius: 10px; + width: 150px; + position: absolute; + /* left: 50%; */ + /* transform: translate(-50%, 0px); */ + top: 105%; + + .nav-list-item { + display: flex; + margin: auto; + padding: 8px; + } + + .nav-list-item:hover { + cursor: pointer; + background-color: #f4f4f4; + border-radius: 5px; + } + + .title-btn { + display: flex; + position: relative; + width: 25px; + height: 25px; + margin-left: 0px; + } + + .title-btn.png { + padding: 0px; + border: none; + background-color: transparent; + } + + svg.button:focus-visible { + outline-offset: 3px; + } } } - .export-button:hover { - cursor: pointer; - background-color: #ebebeb; - } + .export-dropdown.open { + background-color: #f9f9f9; + border-radius: 8px; + transition: all 100ms; - .export-button:active { - background-color: #e6e4e4; + .export-button { + border: none; + } } + } - .nav-list { - list-style-type: none; - padding: 0px 10px; - display: flex; - flex-direction: row; - height: 50px; - background-color: white; - margin: 0px 8px 8px 8px; - border-radius: 3px; + .feedback { + display: flex; + justify-content: center; + margin-top: 4px; - .nav-list-item { - display: flex; + a { + box-sizing: border-box !important; + display: flex; + background-color: #f6f6f6; + font-size: 0.9rem; + font-family: Inter; + font-weight: 400; + width: 120px; + height: 35px; + border-radius: 8px; + padding: 1px 6px; + border: 1px solid #d3d3d3; + text-decoration: none; + color: #000000; + + svg { + width: 12px; margin: auto; + margin-right: 8px; } - - .title-btn { - display: flex; - position: relative; - width: 25px; - height: 25px; + span { + margin: auto; margin-left: 0px; } - - .title-btn.png { - padding: 0px; - border: none; - background-color: transparent; - } } } - .export-dropdown.open { + .link-button:hover { + cursor: pointer; background-color: #ebebeb; - border-radius: 8px; - border: 1px solid #c3c3c3; - transition: all 100ms; - - .export-button { - border: none; - } + } + .link-button:active { + background-color: #e6e4e4; } } } diff --git a/src/App.tsx b/src/App.tsx index da2256be..52f74cef 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -43,6 +43,8 @@ const INIT_VIS_PANEL_WIDTH = window.innerWidth; const ZOOM_PADDING = 200; const ZOOM_DURATION = 500; +const FEEDBACK_EMAIL_ADDRESS = 'dominik_glodzik@hms.harvard.edu'; + const allDrivers = [ ...(_allDrivers as any), ..._customDrivers.map(d => { @@ -1135,14 +1137,14 @@ function App(props: RouteComponentProps) { }} /> )} - + { // External links and export buttons isMinimalMode ? (
-
- +
diff --git a/src/icon.ts b/src/icon.ts index 76a7a041..f794622f 100644 --- a/src/icon.ts +++ b/src/icon.ts @@ -341,5 +341,15 @@ export const ICONS: Record = { path: ['M0.5 1H10.5L5.5 6L0.5 1Z', 'M5.5 6L0.5 1H10.5L5.5 6ZM5.5 6V5.28571'], stroke: 'currentColor', fill: 'none' + }, + MAIL: { + width: 14, + height: 12, + viewBox: '0 0 14 12', + path: [ + 'M1.3125 0C0.587891 0 0 0.635015 0 1.41771C0 1.8637 0.194141 2.2831 0.525 2.55187L6.475 7.37208C6.78672 7.62314 7.21328 7.62314 7.525 7.37208L13.475 2.55187C13.8059 2.2831 14 1.8637 14 1.41771C14 0.635015 13.4121 0 12.6875 0H1.3125ZM0 3.30799V9.45139C0 10.494 0.784766 11.3417 1.75 11.3417H12.25C13.2152 11.3417 14 10.494 14 9.45139V3.30799L8.05 8.12819C7.42656 8.63325 6.57344 8.63325 5.95 8.12819L0 3.30799Z' + ], + stroke: 'currentColor', + fill: 'none' } }; From ac558651a89af421787c31fafedd83d6414bf6b9 Mon Sep 17 00:00:00 2001 From: Cesar Ferreyra-Mansilla Date: Tue, 10 Dec 2024 11:20:58 -0500 Subject: [PATCH 2/3] -feat: abstract navigation bar -style: update navigation bar -feat: add menu icon -chore: add types --- src/App.css | 567 +++++++++++++++++++++++---------------- src/App.tsx | 372 +++++++------------------ src/icon.ts | 10 + src/ui/NavigationBar.tsx | 215 +++++++++++++++ 4 files changed, 667 insertions(+), 497 deletions(-) create mode 100644 src/ui/NavigationBar.tsx diff --git a/src/App.css b/src/App.css index e3e184b4..1bb7fc40 100644 --- a/src/App.css +++ b/src/App.css @@ -40,9 +40,319 @@ a:hover { text-decoration: 3px underline #5bb6ea; } +/* NavigationBar styles */ +.navigation-container { + box-sizing: border-box !important; + position: absolute; + display: flex; + justify-content: space-between; + height: 50px; + width: 100%; + z-index: 999; + background-color: white; + padding: 0px 20px; + + .navigation-links-container { + display: flex; + gap: 4px; + + .title-github-link, + .title-doc-link, + .feedback { + display: flex; + justify-content: center; + background-color: transparent; + padding: 4px 10px; + border-radius: 4px; + + svg { + height: 20px; + vertical-align: middle; + margin: auto 5px auto auto; + color: black; + } + span { + font-size: 1rem; + } + } + + .title-github-link:hover, + .title-doc-link:hover, + .feedback:hover { + background-color: #f6f6f6; + } + + .title-github-link { + position: relative; + text-decoration: none; + } + + .title-doc-link { + color: black; + position: relative; + text-decoration: none; + } + + .feedback { + display: flex; + justify-content: center; + + a { + box-sizing: border-box !important; + display: flex; + font-size: 0.9rem; + font-family: Inter; + font-weight: 400; + text-decoration: none; + color: #000000; + + svg.button { + position: relative; + height: 16px; + margin: auto; + margin-right: 5px; + top: auto; + right: auto; + } + span { + margin: auto; + margin-left: 0px; + } + } + } + } + + .links-left { + display: flex; + + .config-button { + position: relative; + margin: auto; + width: 25px; + height: 25px; + cursor: pointer; + z-index: 999; + color: black; + stroke: black; + stroke-width: 0.5px; + } + .sample-information { + position: relative; + display: flex; + align-items: center; + margin-left: 18px; + text-shadow: 0px 0px 6px white; + font-size: 18px; + z-index: 999; + + .dimed { + margin-right: 12px; + } + + small { + margin-left: 12px; + font-size: 12px; + color: gray; + margin-right: 10px; + } + + .title-btn { + position: relative; + height: 25px; + width: 25px; + font-size: 14px; + margin-left: 10px; + cursor: pointer; + z-index: 999; + color: #333333; + + svg { + vertical-align: inherit; + } + } + } + } + + .links-right { + display: flex; + justify-content: end; + align-items: center; + } +} + +.vis-panel { + .vis-overview-panel { + position: absolute; + width: 100%; + height: 100%; + border-right: 1px solid lightgray; + background-color: white; + overflow-y: none; + z-index: 999; + left: 0px; + transition: left 0.2s ease; + + .navigation-container { + padding: 10px; + font-size: 18px; + border-bottom: 1px solid lightgray; + background: #f6f6f6; + } + } + + .hide { + left: -100%; + } + + .vis-overview-panel .gosling-component { + cursor: pointer; + pointer-events: none; + } + + .gosling-component { + z-index: 1; + } + + .vis-overview-panel .title { + padding: 10px; + font-size: 18px; + border-bottom: 1px solid lightgray; + background: #f6f6f6; + } + + .vis-overview-panel .title small { + font-weight: normal; + } + + .vis-overview-panel .button { + width: 30px; + height: 30px; + cursor: pointer; + position: absolute; + right: 5px; + top: 12px; + } + + .vis-overview-panel .config { + min-height: 100px; + background: #f6f6f6; + border-top: 1px solid lightgray; + position: relative; + padding: 30px; + } + + .vis-overview-panel .config .button { + font-size: 14px; + height: 30px; + width: calc(100% - 20px); + text-align: center; + line-height: 30px; + border: 1px solid black; + border-radius: 3px; + background: white; + cursor: pointer; + left: 10px; + } + + .vis-overview-panel .overview-container { + display: flex; + flex-wrap: wrap; + height: calc(100% - 41px - 20px); + padding: 20px; + gap: 20px; + overflow-y: auto; + } + + .overview-root { + margin-top: 50px; + gap: 0px; + height: calc(100% - 50px); + } + + .overview-container { + width: calc(100% - 400px - 40px); + float: left; + } + + .overview-status { + background: rgba(210, 210, 210, 0.1); + width: calc(100% - 400px); + height: 25px; + float: left; + border-bottom: 1px solid lightgrey; + padding: 0px; + margin: 0px; + color: grey; + align-content: middle; + display: flex; + justify-content: center; + } + + .overview-left { + float: left; + height: 100%; + width: 398px; + border-right: 1px solid lightgrey; + overflow-y: auto; + overflow-x: hidden; + background: rgba(210, 210, 210, 0.1); + } + + .vis-overview-panel table { + width: 100%; + border-spacing: 0px 0px; + border-collapse: collapse; + } + + .vis-overview-panel tr /* :nth-child(even) */ { + border-top: 1px solid lightgray; + } + + .vis-overview-panel td { + border-radius: 0px; + padding-left: 90px !important; + } + + .vis-overview-panel .overview-title { + position: absolute; + left: -10px; + top: 120px; + transform: rotate(-90deg); + font-weight: bold; + font-size: 18px; + text-shadow: 0px 0px 12px #f6f6f6; + } + + .overview-container > div { + padding: 4px; + } + + .vis-overview-panel .selected-overview, + .vis-overview-panel .unselected-overview { + display: block; + text-align: center; + flex: 1; + } + + .vis-overview-panel .selected-overview { + box-shadow: inset 0px 0px 0px 2px #2e94ff; + } + + .vis-overview-panel .unselected-overview { + cursor: pointer; + } + + .vis-overview-panel .unselected-overview:hover { + box-shadow: inset 0px 0px 0px 2px lightgray; + } + + .vis-overview-panel td { + padding: 20px; + } +} + .chromoscope-title { font-weight: bold; - margin-right: 4px; text-decoration: none; } .dimed { @@ -131,21 +441,6 @@ a:hover { border: none; } -.title-github-link { - display: inline-block; - position: fixed; - right: 200px; - text-decoration: none; -} - -.title-doc-link { - color: black; - display: inline-block; - position: fixed; - right: 20px; - text-decoration: none; -} - .title-about-link { margin: auto 12px; font-size: 12px; @@ -154,14 +449,6 @@ a:hover { text-decoration: none; } -.title-github-link svg, -.title-doc-link svg { - height: 25px; - vertical-align: middle; - padding-right: 8px; - color: black; -} - .title-about-link svg { height: 16px; padding-right: 4px; @@ -285,7 +572,14 @@ a:hover { .zoom-out-button:hover, .zoom-left-button:hover, .zoom-right-button:hover { - background: lightgrey; + background: #ebebeb; +} + +.zoom-in-button:active, +.zoom-out-button:active, +.zoom-left-button:active, +.zoom-right-button:active { + background: #e6e4e4; } .gene-search { @@ -345,23 +639,6 @@ a:hover { width: 100%; } -.title-btn { - font-size: 14px; - margin-left: 10px; - text-align: center; - line-height: 30px; - position: absolute; - width: 25px; - height: 25px; - cursor: pointer; - z-index: 999; - color: #333333; - - svg { - vertical-align: inherit; - } -} - .tag-parent { margin: 4px; max-width: 200px; @@ -454,18 +731,6 @@ a:hover { /* color: black; */ } -.config-button { - width: 25px; - height: 25px; - position: absolute; - top: 10px; - left: 10px; - cursor: pointer; - z-index: 999; - stroke: black; - stroke-width: 0.5px; -} - .jump-to-bp-btn { font-weight: bold; color: black; @@ -524,17 +789,6 @@ a:hover { line-height: 20px; } -.sample-label { - position: absolute; - top: 12px; - left: 40px; - text-shadow: 0px 0px 6px white; - font-size: 18px; - z-index: 999; - line-height: normal; - /* background: #ffffff99; */ -} - .menu-title svg { vertical-align: middle; } @@ -555,168 +809,6 @@ a:hover { background: #ffffff99; } -.vis-overview-panel { - position: absolute; - width: 100%; - height: 100%; - border-right: 1px solid lightgray; - background-color: white; - /* box-shadow: 0px 0px 12px #00000032; */ - overflow-y: none; - z-index: 999; - left: 0px; - transition: left 0.2s ease; -} - -.hide { - left: -100%; -} - -.vis-overview-panel .gosling-component { - cursor: pointer; - pointer-events: none; -} - -.gosling-component { - z-index: 1; -} - -.vis-overview-panel .title { - padding: 10px; - font-size: 18px; - border-bottom: 1px solid lightgray; - background: #f6f6f6; -} - -.vis-overview-panel .title small { - font-weight: normal; -} - -.vis-overview-panel .button { - width: 30px; - height: 30px; - cursor: pointer; - position: absolute; - right: 5px; - top: 12px; -} - -.vis-overview-panel .config { - min-height: 100px; - background: #f6f6f6; - border-top: 1px solid lightgray; - position: relative; - padding: 30px; -} - -.vis-overview-panel .config .button { - font-size: 14px; - height: 30px; - width: calc(100% - 20px); - text-align: center; - line-height: 30px; - border: 1px solid black; - border-radius: 3px; - background: white; - cursor: pointer; - left: 10px; -} - -.vis-overview-panel .overview-container { - display: flex; - flex-wrap: wrap; - height: calc(100% - 41px - 20px); - padding: 20px; - gap: 20px; - overflow-y: auto; -} - -.overview-root { - gap: 0px; - height: calc(100% - 50px); -} - -.overview-container { - width: calc(100% - 400px - 40px); - float: left; -} - -.overview-status { - background: rgba(210, 210, 210, 0.1); - width: calc(100% - 400px); - height: 25px; - float: left; - border-bottom: 1px solid lightgrey; - padding: 0px; - margin: 0px; - color: grey; - align-content: middle; - display: flex; - justify-content: center; -} - -.overview-left { - float: left; - height: 100%; - width: 398px; - border-right: 1px solid lightgrey; - overflow-y: auto; - overflow-x: hidden; - background: rgba(210, 210, 210, 0.1); -} - -.vis-overview-panel table { - width: 100%; - border-spacing: 0px 0px; - border-collapse: collapse; -} - -.vis-overview-panel tr /* :nth-child(even) */ { - border-top: 1px solid lightgray; -} - -.vis-overview-panel td { - border-radius: 0px; - padding-left: 90px !important; -} - -.vis-overview-panel .overview-title { - position: absolute; - left: -10px; - top: 120px; - transform: rotate(-90deg); - font-weight: bold; - font-size: 18px; - text-shadow: 0px 0px 12px #f6f6f6; -} - -.overview-container > div { - padding: 4px; -} - -.vis-overview-panel .selected-overview, -.vis-overview-panel .unselected-overview { - display: block; - text-align: center; - flex: 1; -} - -.vis-overview-panel .selected-overview { - box-shadow: inset 0px 0px 0px 2px #2e94ff; -} - -.vis-overview-panel .unselected-overview { - cursor: pointer; -} - -.vis-overview-panel .unselected-overview:hover { - box-shadow: inset 0px 0px 0px 2px lightgray; -} - -.vis-overview-panel td { - padding: 20px; -} - .gosling-panel { /* http://iros.github.io/patternfills/sample_d3.html */ background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc1JyBoZWlnaHQ9JzUnPgo8cmVjdCB3aWR0aD0nNScgaGVpZ2h0PSc1JyBmaWxsPScjZmZmJy8+CjxyZWN0IHdpZHRoPScxJyBoZWlnaHQ9JzEnIGZpbGw9JyNjY2MnLz4KPC9zdmc+'); @@ -907,6 +999,7 @@ a:hover { margin-top: 4px; } +.navigation-button:focus, .navigation-button:focus-visible { outline-offset: -1px; } @@ -994,6 +1087,8 @@ a:hover { .open-in-chromoscope-link:hover { text-decoration: none; + cursor: pointer; + background-color: #ebebeb; } .open-in-chromoscope-link:active { @@ -1011,7 +1106,6 @@ a:hover { .export-dropdown { height: auto; - /* background-color: #f6f6f6; */ right: 0px; border-radius: 8px; transition: all 100ms; @@ -1020,6 +1114,7 @@ a:hover { .export-button { position: relative; box-sizing: border-box !important; + background-color: #f6f6f6; width: 120px; height: 35px; border: 1px solid #d3d3d3; @@ -1072,6 +1167,7 @@ a:hover { width: 25px; height: 25px; margin-left: 0px; + color: black; } .title-btn.png { @@ -1080,8 +1176,9 @@ a:hover { background-color: transparent; } + svg.button:focus, svg.button:focus-visible { - outline-offset: 3px; + outline-offset: 6px; } } } @@ -1093,6 +1190,18 @@ a:hover { .export-button { border: none; + background-color: #ebebeb; + } + } + + .export-dropdown.closed { + .export-button:hover { + cursor: pointer; + background-color: #ebebeb; + } + + .export-button:active { + background-color: #e6e4e4; } } } diff --git a/src/App.tsx b/src/App.tsx index 52f74cef..e3a534dc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,6 +31,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import * as bootstrap from 'bootstrap/dist/js/bootstrap.bundle.min'; import { Track, getTrackDocData } from './ui/getTrackDocData.js'; +import { NavigationBar } from './ui/NavigationBar'; const db = new Database(); const log = new BrowserDatabase(); @@ -759,231 +760,94 @@ function App(props: RouteComponentProps) { }} > {!isMinimalMode && ( - - )} - {!isMinimalMode && ( - { - setShowSamples(true); - }} - > - Menu - - + )} -
- {!isMinimalMode && ( - <> - - CHROMOSCOPE - - { - setShowAbout(true); - }} - > - - - - About - - {' | '} - {/* {demo.cancer.charAt(0).toUpperCase() + demo.cancer.slice(1) + ' • ' + demo.id} */} - {demo.cancer.charAt(0).toUpperCase() + demo.cancer.slice(1)} - {demo.id} - - )} - {!isMinimalMode && ( - <> - gosRef.current?.api.exportPng()}> - - Export Image - {ICONS.PNG.path.map(p => ( - - ))} - - - { - const a = document.createElement('a'); - a.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent( - getHtmlTemplate(currentSpec.current) - )}` - ); - a.download = 'visualization.html'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - }} - style={{ marginLeft: 40 }} - > - - Export HTML - {ICONS.HTML.path.map(p => ( - - ))} - - - { - const a = document.createElement('a'); - a.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent(currentSpec.current)}` - ); - a.download = 'visualization.json'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - }} - style={{ marginLeft: 70 }} - > - - Export Gosling Spec (JSON) - {ICONS.JSON.path.map(p => ( - - ))} - - - { - const { xDomain } = gosRef.current.hgApi.api.getLocation(`${demo.id}-mid-ideogram`); - if (xDomain) { - // urlParams.set('demoIndex', demoIndex.current + ''); - // urlParams.set('domain', xDomain.join('-')); - let newUrl = window.location.origin + window.location.pathname + '?'; - newUrl += `demoIndex=${demoIndex.current}`; - newUrl += `&domain=${xDomain.join('-')}`; - if (externalDemoUrl.current) { - newUrl += `&external=${externalDemoUrl.current}`; - } else if (externalUrl) { - newUrl += `&external=${externalUrl}`; - } - navigator.clipboard - .writeText(newUrl) - .then(() => - alert( - 'The URL of the current session has been copied to your clipboard.' - ) - ); - } - }} - style={{ marginLeft: 100 }} - > - - Export Link - - - - - - )} - {!isChrome() ? ( - - ⚠️ Chromoscope is optimized for Google Chrome - - ) : null} - {!isMinimalMode && ( - <> - - - GitHub - - - GitHub - - - - - - Documentation - - - )} -
{!isMinimalMode && (
-
{ - if (e.target === e.currentTarget) setShowSamples(false); - }} - > - { - setShowSamples(false); +
+
{ + if (e.target === e.currentTarget) setShowSamples(false); }} > - Close - - - +
+ + + GitHub + + + GitHub + + - + - About + Documentation - {' | '} Samples - setFilterSampleBy(e.target.value)} - hidden - /> -
- - - GitHub - - - GitHub - - - + + + Mail + + + Feedback + +
+ + {generateThumbnails + ? 'Stop Generating Thumbnails' + : 'Generate Missing Thumbnails'} + +
diff --git a/src/icon.ts b/src/icon.ts index f794622f..29bd8e16 100644 --- a/src/icon.ts +++ b/src/icon.ts @@ -351,5 +351,15 @@ export const ICONS: Record = { ], stroke: 'currentColor', fill: 'none' + }, + MENU: { + width: 16, + height: 16, + viewBox: '0 0 16 16', + path: [ + 'M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z' + ], + stroke: 'currentColor', + fill: 'none' } }; diff --git a/src/ui/NavigationBar.tsx b/src/ui/NavigationBar.tsx new file mode 100644 index 00000000..cf7758e2 --- /dev/null +++ b/src/ui/NavigationBar.tsx @@ -0,0 +1,215 @@ +import React, { MutableRefObject } from 'react'; + +import { ICONS } from '../icon'; + +type NavigationBarProps = { + demo: any; + demoIndex: MutableRefObject; + showSmallMultiples: boolean; + gosRef: any; + currentSpec: MutableRefObject; + externalUrl: string; + externalDemoUrl: MutableRefObject; + FEEDBACK_EMAIL_ADDRESS: string; + isChrome: () => boolean; + setShowAbout: (show: boolean) => void; + setShowSamples: (show: boolean) => void; + getHtmlTemplate: (spec: string) => string; +}; + +export const NavigationBar = ({ + demo, + demoIndex, + showSmallMultiples, + gosRef, + currentSpec, + externalUrl, + externalDemoUrl, + isChrome, + FEEDBACK_EMAIL_ADDRESS, + setShowAbout, + setShowSamples, + getHtmlTemplate +}: NavigationBarProps) => { + return ( +
+
+ { + setShowSamples(true); + }} + > + Menu + + +
+ + CHROMOSCOPE + + { + setShowAbout(true); + }} + > + + + + About + + {' | '} + {/* {demo.cancer.charAt(0).toUpperCase() + demo.cancer.slice(1) + ' • ' + demo.id} */} + {demo.cancer.charAt(0).toUpperCase() + demo.cancer.slice(1)} + {demo.id} + + <> + gosRef.current?.api.exportPng()}> + + Export Image + {ICONS.PNG.path.map(p => ( + + ))} + + + { + const a = document.createElement('a'); + a.setAttribute( + 'href', + `data:text/plain;charset=utf-8,${encodeURIComponent( + getHtmlTemplate(currentSpec.current) + )}` + ); + a.download = 'visualization.html'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }} + > + + Export HTML + {ICONS.HTML.path.map(p => ( + + ))} + + + { + const a = document.createElement('a'); + a.setAttribute( + 'href', + `data:text/plain;charset=utf-8,${encodeURIComponent(currentSpec.current)}` + ); + a.download = 'visualization.json'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }} + > + + Export Gosling Spec (JSON) + {ICONS.JSON.path.map(p => ( + + ))} + + + { + const { xDomain } = gosRef.current.hgApi.api.getLocation(`${demo.id}-mid-ideogram`); + if (xDomain) { + // urlParams.set('demoIndex', demoIndex.current + ''); + // urlParams.set('domain', xDomain.join('-')); + let newUrl = window.location.origin + window.location.pathname + '?'; + newUrl += `demoIndex=${demoIndex.current}`; + newUrl += `&domain=${xDomain.join('-')}`; + if (externalDemoUrl.current) { + newUrl += `&external=${externalDemoUrl.current}`; + } else if (externalUrl) { + newUrl += `&external=${externalUrl}`; + } + navigator.clipboard + .writeText(newUrl) + .then(() => + alert('The URL of the current session has been copied to your clipboard.') + ); + } + }} + > + + Export Link + + + + + +
+ {!isChrome() ? ( + + ⚠️ Chromoscope is optimized for Google Chrome + + ) : null} +
+ +
+ ); +}; From 96db17f7579a337695a68fbcf460b89ae8f11d32 Mon Sep 17 00:00:00 2001 From: Cesar Ferreyra-Mansilla Date: Wed, 11 Dec 2024 14:45:31 -0500 Subject: [PATCH 3/3] -chore: fix tab navigation -style: match navigation bar styles for vis-overview-panel -style: add hover state for overview panel links -chore: separate navigation bar styles -chore: create css folder --- src/App.tsx | 66 ++++++----- src/{ => css}/App.css | 217 +++++++++------------------------- src/css/NavigationBar.css | 220 +++++++++++++++++++++++++++++++++++ src/ui/ExportDropdown.tsx | 6 +- src/ui/NavigationBar.tsx | 191 +++++++++++++++--------------- src/ui/NavigationButtons.tsx | 16 ++- 6 files changed, 424 insertions(+), 292 deletions(-) rename src/{ => css}/App.css (89%) create mode 100644 src/css/NavigationBar.css diff --git a/src/App.tsx b/src/App.tsx index e3a534dc..033403a5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,8 @@ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 're import { GoslingComponent, GoslingRef, embed } from 'gosling.js'; import { debounce, sample } from 'lodash'; import type { RouteComponentProps } from 'react-router-dom'; +import * as bootstrap from 'bootstrap/dist/js/bootstrap.bundle.min'; + import generateSpec from './main-spec'; import ErrorBoundary from './error'; import _allDrivers from './data/driver.json'; @@ -10,7 +12,6 @@ import samples, { SampleType } from './data/samples'; import getOneOfSmallMultiplesSpec from './small-multiples-spec'; import { CHROMOSOMES, THEME, WHOLE_CHROMOSOME_STR } from './constants'; import { ICONS } from './icon'; -import './App.css'; import { INTERNAL_SAVED_THUMBNAILS } from './data/external-thumbnails'; import { isChrome } from './utils'; import THUMBNAIL_PLACEHOLDER from './script/img/placeholder.png'; @@ -26,13 +27,12 @@ import { ExportDropdown } from './ui/ExportDropdown'; import { GenomeViewModal } from './ui/GenomeViewModal'; import { VariantViewModal } from './ui/VariantViewModal'; import { NavigationButtons } from './ui/NavigationButtons'; - -import 'bootstrap/dist/css/bootstrap.min.css'; -import * as bootstrap from 'bootstrap/dist/js/bootstrap.bundle.min'; - import { Track, getTrackDocData } from './ui/getTrackDocData.js'; import { NavigationBar } from './ui/NavigationBar'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import './css/App.css'; + const db = new Database(); const log = new BrowserDatabase(); @@ -586,7 +586,7 @@ function App(props: RouteComponentProps) { return ( @@ -622,7 +622,7 @@ function App(props: RouteComponentProps) { })}
); - }, [demo, visPanelWidth, selectedSvId]); + }, [demo, visPanelWidth, selectedSvId, showSamples]); useLayoutEffect(() => { if (!gosRef.current) return; @@ -764,6 +764,7 @@ function App(props: RouteComponentProps) { demo={demo} setShowAbout={setShowAbout} showSmallMultiples={showSmallMultiples} + showSamples={showSamples} setShowSamples={setShowSamples} gosRef={gosRef} currentSpec={currentSpec} @@ -785,22 +786,28 @@ function App(props: RouteComponentProps) { if (e.target === e.currentTarget) setShowSamples(false); }} > - { setShowSamples(false); }} > - Close - - + + Close + + + +
- CHROMOSCOPE + + CHROMOSCOPE + { setShowAbout(true); @@ -833,6 +840,7 @@ function App(props: RouteComponentProps) { href="https://github.com/hms-dbmi/chromoscope" target="_blank" rel="noreferrer" + tabIndex={showSamples ? 0 : -1} > GitHub @@ -848,6 +856,7 @@ function App(props: RouteComponentProps) { href="https://chromoscope.bio/" target="_blank" rel="noreferrer" + tabIndex={showSamples ? 0 : -1} > - Documentation + Docs
Mail @@ -935,7 +945,6 @@ function App(props: RouteComponentProps) { }} > {goslingComponent} - {trackTooltips} {jumpButtonInfo ? ( )} - + { // External links and export buttons isMinimalMode ? ( @@ -981,7 +990,7 @@ function App(props: RouteComponentProps) {
+ {trackTooltips}
{!isMinimalMode && ( @@ -1429,7 +1439,7 @@ function App(props: RouteComponentProps) { )}
- + CHROMOSCOPE { setShowAbout(true); @@ -71,89 +79,82 @@ export const NavigationBar = ({ {demo.cancer.charAt(0).toUpperCase() + demo.cancer.slice(1)} {demo.id} - <> - gosRef.current?.api.exportPng()}> - - Export Image - {ICONS.PNG.path.map(p => ( - - ))} - - - { - const a = document.createElement('a'); - a.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent( - getHtmlTemplate(currentSpec.current) - )}` - ); - a.download = 'visualization.html'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - }} - > - - Export HTML - {ICONS.HTML.path.map(p => ( - - ))} - - - { - const a = document.createElement('a'); - a.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent(currentSpec.current)}` - ); - a.download = 'visualization.json'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - }} - > - - Export Gosling Spec (JSON) - {ICONS.JSON.path.map(p => ( - - ))} - - - { - const { xDomain } = gosRef.current.hgApi.api.getLocation(`${demo.id}-mid-ideogram`); - if (xDomain) { - // urlParams.set('demoIndex', demoIndex.current + ''); - // urlParams.set('domain', xDomain.join('-')); - let newUrl = window.location.origin + window.location.pathname + '?'; - newUrl += `demoIndex=${demoIndex.current}`; - newUrl += `&domain=${xDomain.join('-')}`; - if (externalDemoUrl.current) { - newUrl += `&external=${externalDemoUrl.current}`; - } else if (externalUrl) { - newUrl += `&external=${externalUrl}`; +
    +
  • + +
  • + +
  • + { + e.stopPropagation(); + }} + > + + +
  • +
  • + { + e.stopPropagation(); + }} + > + + +
  • +
  • + +
  • +
+
{!isChrome() ? ( GitHub @@ -185,7 +187,13 @@ export const NavigationBar = ({ GitHub - + Mail diff --git a/src/ui/NavigationButtons.tsx b/src/ui/NavigationButtons.tsx index a69a5b0d..487330c8 100644 --- a/src/ui/NavigationButtons.tsx +++ b/src/ui/NavigationButtons.tsx @@ -1,13 +1,19 @@ import React from 'react'; import { ICONS } from '../icon'; -export const NavigationButtons = () => { +type NavigationButtonsProps = { + showSamples: boolean; + isMinimalMode: boolean; +} + +export const NavigationButtons = ({ showSamples, isMinimalMode } : NavigationButtonsProps) => { + return (