From 26e63d64e35d33b80d2ebf6f29e6c0cd6c509d33 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 1 Nov 2018 23:42:26 -0400 Subject: [PATCH 01/16] Flexbox buttons in top bar - Makes the "Sidebar" toggle button permanent but removes the label - Did some things to the "Save" button to make it the same width whether there is a count or not (prevents the buttons from jumping when pressing undo/redo) - Removes a lot of the floated col rules that aren't used much anymore --- css/80_app.css | 273 +++++++++++------------ data/core.yaml | 2 +- dist/locales/en.json | 2 +- modules/ui/background.js | 2 +- modules/ui/confirm.js | 2 +- modules/ui/help.js | 2 +- modules/ui/init.js | 51 +++-- modules/ui/map_data.js | 2 +- modules/ui/modes.js | 4 +- modules/ui/save.js | 8 +- modules/ui/settings/custom_background.js | 6 +- modules/ui/settings/custom_data.js | 6 +- modules/ui/undo_redo.js | 2 +- 13 files changed, 180 insertions(+), 182 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 5888cd007..72c957f2d 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -61,6 +61,7 @@ body { #content > #bar { width: 100vw; } +/* #content.inactive > #bar > .spacer.col4 { width: 0px; } @@ -69,6 +70,7 @@ body { transition-duration: 200ms; transition-timing-function: step-end; } +*/ } #defs { @@ -92,12 +94,9 @@ body { height: 40px; width: 40px; border-radius: 4px; - margin-right: 10px; background: black; } [dir='rtl'] .spinner img { - margin-left: 10px; - margin-right: auto; -moz-transform: scaleX(-1); -o-transform: scaleX(-1); -webkit-transform: scaleX(-1); @@ -278,18 +277,8 @@ table.tags, table.tags td, table.tags th { /* Grid ------------------------------------------------------- */ -.col0 { float: left; width: 04.1666%; } -.col1 { float: left; width: 08.3333%; } -.col2 { float: left; width: 16.6666%; } -.col3 { float: left; width: 25.0000%; max-width: 300px; } -.col4 { float: left; width: 33.3333%; max-width: 400px; } -.col5 { float: left; width: 41.6666%; max-width: 500px; } .col6 { float: left; width: 50.0000%; max-width: 600px; } -.col7 { float: left; width: 58.3333%; } .col8 { float: left; width: 66.6666%; } -.col9 { float: left; width: 75.0000%; } -.col10 { float: left; width: 83.3333%; } -.col11 { float: left; width: 91.6666%; } .col12 { float: left; width: 100.0000%; } /* UI Lists @@ -326,7 +315,7 @@ ul li { list-style: none;} } .toggle-list > label.active { - background: #E8EBFF; + background: #e8ebff; } @@ -433,7 +422,7 @@ button.minor:hover { background-color: #f1f1f1; } -.button-wrap { +/*.button-wrap { display: inline-block; padding-right: 10px; margin: 0; @@ -455,7 +444,7 @@ button.minor:hover { } [dir='rtl'] .button-wrap:last-of-type { padding-left: 0; -} +}*/ .joined button { border-radius: 0; @@ -489,18 +478,15 @@ button.action { background: #7092ff; color: #fff; } - button[disabled].action, button[disabled].action:hover { background: #cccccc; color: #888; } - button.action:focus, button.action:hover { - background: #597BE7; + background: #597be7; } - button.secondary-action { background: #ececec; } @@ -509,61 +495,6 @@ button.secondary-action:focus, button.secondary-action:hover { background: #cccccc; } -.button-wrap.sidebar-collapse, -.button-wrap.save-wrap { - min-width: 33.3333%; -} -.button-wrap.modes { - width: 100%; -} - -button.undo-button, -button.redo-button { - width: 44px; -} -button.save { - padding: 0; - display: flex; -} -button.save .save-inner-wrap { - flex: 1; -} -button.save .count { - display: none; -} -button.save.has-count .count { - display: inline-block; - color: #333; - border: 0px solid rgba(51, 51, 51, 0.2); - border-left-width: 1px; - padding: 0px 12px; -} -[dir='rtl'] button.save.has-count .count { - border-left-width: 0px; - border-right-width: 1px; -} - -.help-wrap svg.icon.pre-text.add-note, -button.add-note svg.icon { - height: 15px; - width: 15px; - color: rgba(0,0,0,0.25); - stroke: #333; - stroke-width: 60px; - margin-top: 3px; -} -button.add-note svg.icon { - margin-left: unset; - margin-right: 7px; -} -[dir='rtl'] button.add-note svg.icon { - margin-left: 7px; - margin-right: unset; -} -.help-wrap svg.icon.pre-text.add-note { - margin-left: 3px; - margin-right: 3px; -} /* Icons @@ -622,6 +553,9 @@ button.add-note svg.icon { /* Toolbar / Persistent UI Elements ------------------------------------------------------- */ #bar { + display: flex; + flex-flow: row nowrap; + justify-content: space-between; position: absolute; padding: 10px; left: 0; @@ -629,52 +563,104 @@ button.add-note svg.icon { right: 0; height: 60px; z-index: 9; - min-width: 600px; } -[dir='rtl'] #bar .button-wrap button { - float: right; +.tool-group { + display: flex; + flex: 0 1 auto; + flex-flow: row nowrap; } -#bar .center-area, -#bar .trailing-area { - min-width: 50%; +.tool-group.leading-area { + justify-content: flex-start; } -.sidebar-collapsed #bar .leading-area, -.sidebar-collapsed #bar .center-area, -.sidebar-collapsed #bar .trailing-area { - min-width: 33.3333%; +.tool-group.center-area { + justify-content: center; } -#bar .center-area { - float: left; +.tool-group.trailing-area { + justify-content: flex-end; } -[dir='rtl'] #bar .center-area { - float: right; + +.tool-group > div { + display: flex; + margin: 0 5px; } -.sidebar-collapsed #bar .center-area { - position: absolute; - left: 50%; - transform: translateX(-50%); - float: none; + +.tool-group button { + display: flex; + flex: 1 1 auto; + flex-flow: row nowrap; + padding: 0 10px; + min-width: 30px; } -#bar .leading-area { - float: left; - display: none; + +.tool-group button .icon { + flex: 0 0 20px; } -[dir='rtl'] #bar .leading-area { - float: right; +.tool-group button .label { + flex: 0 1 auto; + padding: 0 5px; } -.sidebar-collapsed #bar .leading-area { + + +button.save .count { + visibility: hidden; display: inline-block; + border: 0px solid #ccc; + border-left-width: 1px; + padding: 0px 8px; + min-width: 32px; + text-align: center; } -#bar .trailing-area { - float: right; - text-align: right; +[dir='rtl'] button.save .count { + border-left-width: 0px; + border-right-width: 1px; } -[dir='rtl'] #bar .trailing-area { - float: left; - text-align: left; +button.save.has-count .count { + visibility: visible; } +/* if no count, shift label over where the count would be, preserving width */ +button.save .label { + margin-right: -12px; + margin-left: 15px; +} +[dir='rtl'] button.save .label { + margin-left: -12px; + margin-right: 15px; +} +button.save.has-count .label { + margin-right: 3px; + margin-left: 0; +} +[dir='rtl'] button.save.has-count .label { + margin-left: 3px; + margin-right: 0; +} + + +.help-wrap svg.icon.pre-text.add-note, +button.add-note svg.icon { + height: 15px; + width: 15px; + color: rgba(0,0,0,0.25); + stroke: #333; + stroke-width: 60px; + margin-top: 3px; +} +button.add-note svg.icon { + margin-left: unset; + margin-right: 4px; +} +[dir='rtl'] button.add-note svg.icon { + margin-left: 4px; + margin-right: unset; +} +.help-wrap svg.icon.pre-text.add-note { + margin-left: 3px; + margin-right: 3px; +} + + /* Header for modals / panes ------------------------------------------------------- */ @@ -771,14 +757,6 @@ button.add-note svg.icon { justify-content: center; } -.sidebar-component .body { - width: 100%; - overflow: auto; - top: 60px; - bottom: 0; - position: absolute; -} - /* Hide/Toggle collapsable sections (aka Disclosure) ------------------------------------------------------- */ @@ -801,6 +779,25 @@ a.hide-toggle { padding-bottom: 5px; } + +/* Sidebar / Inspector +------------------------------------------------------- */ +#sidebar { + position: relative; + float: left; + height: 100%; + z-index: 10; + background: #f6f6f6; + -ms-user-select: element; + border: 0px solid #ccc; + border-right-width: 1px; +} +[dir='rtl'] #sidebar { + float: right; + border-right-width: 0px; + border-left-width: 1px; +} + #sidebar-resizer { position: absolute; top: 0; @@ -822,23 +819,6 @@ a.hide-toggle { left: -10px; } -/* Sidebar / Inspector -------------------------------------------------------- */ -#sidebar { - position: relative; - float: left; - height: 100%; - z-index: 10; - background: #f6f6f6; - -ms-user-select: element; - border: 0px solid #ccc; - border-right-width: 1px; -} -[dir='rtl'] #sidebar { - float: right; - border-right-width: 0px; - border-left-width: 1px; -} .sidebar-component { position: absolute; @@ -848,6 +828,14 @@ a.hide-toggle { right: 0; } +.sidebar-component .body { + width: 100%; + overflow: auto; + top: 60px; + bottom: 0; + position: absolute; +} + .panewrap { position: absolute; width: 200%; @@ -935,6 +923,7 @@ a.hide-toggle { } + /* Feature List / Search Results ------------------------------------------------------- */ .feature-list { @@ -3019,6 +3008,8 @@ div.full-screen > button:hover { top: 60px; bottom: 30px; right: 0; + width: 33.3333%; + max-width: 400px; padding-bottom: 50px; overflow: hidden; z-index: -1; @@ -3028,6 +3019,11 @@ div.full-screen > button:hover { right: auto !important; } +.map-pane.help-wrap { + width: 50.0000%; + max-width: 600px; +} + .pane-heading { display: flex; flex-flow: row nowrap; @@ -3826,6 +3822,10 @@ img.tile-debug { text-align: center; } +.modal-section.buttons button { + min-width: 130px; +} + .modal-section.buttons .action { display: inline-block; margin: 0 10px; @@ -4103,9 +4103,6 @@ svg.mouseclick use.right { .settings-modal textarea { height: 70px; } -.settings-modal .buttons .button.col3 { - float: none; /* undo float left */ -} .settings-custom-background .instructions-template { margin-bottom: 20px; @@ -4508,12 +4505,12 @@ svg.mouseclick use.right { } /* Move over tooltips that are near the edge of screen */ -.add-point .tooltip .tooltip-arrow { - left: 60px; +button.sidebar-toggle .tooltip .tooltip-arrow { + left: 32px; } -[dir='rtl'] .add-point .tooltip .tooltip-arrow { +[dir='rtl'] button.sidebar-toggle .tooltip .tooltip-arrow { left: auto; - right: 60px; + right: 32px; } li:first-of-type .badge .tooltip, diff --git a/data/core.yaml b/data/core.yaml index 045db6496..bdcbcfca6 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -296,7 +296,7 @@ en: help_translate: Help translate sidebar_button: title: Sidebar - tooltip: Open the sidebar. + tooltip: Toggle the sidebar. feature_info: hidden_warning: "{count} hidden features" hidden_details: "These features are currently hidden: {details}" diff --git a/dist/locales/en.json b/dist/locales/en.json index b67bbe8be..09aa3b865 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -375,7 +375,7 @@ "help_translate": "Help translate", "sidebar_button": { "title": "Sidebar", - "tooltip": "Open the sidebar." + "tooltip": "Toggle the sidebar." }, "feature_info": { "hidden_warning": "{count} hidden features", diff --git a/modules/ui/background.js b/modules/ui/background.js index 3dbc1c454..6f91098b8 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -340,7 +340,7 @@ export function uiBackground(context) { var pane = selection .append('div') - .attr('class', 'fillL map-pane col4 hide'); + .attr('class', 'fillL map-pane hide'); var paneTooltip = tooltip() .placement((textDirection === 'rtl') ? 'right' : 'left') diff --git a/modules/ui/confirm.js b/modules/ui/confirm.js index 8eec4b6cd..a993f64c3 100644 --- a/modules/ui/confirm.js +++ b/modules/ui/confirm.js @@ -23,7 +23,7 @@ export function uiConfirm(selection) { modalSelection.okButton = function() { buttons .append('button') - .attr('class', 'button ok-button action col4') + .attr('class', 'button ok-button action') .on('click.confirm', function() { modalSelection.remove(); }) diff --git a/modules/ui/help.js b/modules/ui/help.js index a8b5bbbbd..1d350be2d 100644 --- a/modules/ui/help.js +++ b/modules/ui/help.js @@ -384,7 +384,7 @@ export function uiHelp(context) { var pane = selection.append('div') - .attr('class', 'help-wrap map-pane fillL col6 hide'); + .attr('class', 'help-wrap map-pane fillL hide'); var tooltipBehavior = tooltip() .placement((textDirection === 'rtl') ? 'right' : 'left') diff --git a/modules/ui/init.js b/modules/ui/init.js index 9ce38a042..44316c429 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -74,6 +74,7 @@ export function uiInit(context) { .attr('id', 'content') .attr('class', 'active'); + // Top toolbar var bar = content .append('div') .attr('id', 'bar') @@ -90,56 +91,62 @@ export function uiInit(context) { .call(uiInfo(context)) .call(uiNotice(context)); + // Leading area button group (sidebar toggle) var leadingArea = bar .append('div') - .attr('class', 'leading-area'); + .attr('class', 'tool-group leading-area'); var sidebarButton = leadingArea - .append('div') - .attr('class', 'button-wrap sidebar-collapse') .append('button') - .attr('class', 'col12') + .attr('class', 'sidebar-toggle') .attr('tabindex', -1) .on('click', ui.sidebar.toggleCollapse) .call(tooltip().title(t('sidebar_button.tooltip')).placement('bottom')); + var iconSuffix = textDirection === 'rtl' ? 'right' : 'left'; sidebarButton - .call(svgIcon('#iD-icon-sidebar-'+iconSuffix, 'pre-text')) - .append('span') - .attr('class', 'label') - .text(t('sidebar_button.title')); + .call(svgIcon('#iD-icon-sidebar-' + iconSuffix)); + // .append('span') + // .attr('class', 'label') + // .text(t('sidebar_button.title')); + leadingArea + .append('div') + .attr('class', 'full-screen bar-group') + .call(uiFullScreen(context)); + + + // Center area button group (mode buttons) bar .append('div') - .attr('class', 'center-area') + .attr('class', 'tool-group center-area') .append('div') - .attr('class', 'modes button-wrap joined') + .attr('class', 'modes joined') .call(uiModes(context), bar); + + // Center area button group (undo/redo save buttons) var trailingArea = bar .append('div') - .attr('class', 'trailing-area'); + .attr('class', 'tool-group trailing-area'); trailingArea .append('div') - .attr('class', 'full-screen') - .call(uiFullScreen(context)); + .attr('class', 'joined') + .call(uiUndoRedo(context)); + + trailingArea + .append('div') + .attr('class', 'save-wrap') + .call(uiSave(context)); trailingArea .append('div') .attr('class', 'spinner') .call(uiSpinner(context)); - trailingArea - .append('div') - .attr('class', 'button-wrap joined') - .call(uiUndoRedo(context)); - - trailingArea - .append('div') - .attr('class', 'button-wrap save-wrap') - .call(uiSave(context)); + // Map controls var controls = bar .append('div') .attr('class', 'map-controls'); diff --git a/modules/ui/map_data.js b/modules/ui/map_data.js index 369f8554f..9f4f96e53 100644 --- a/modules/ui/map_data.js +++ b/modules/ui/map_data.js @@ -578,7 +578,7 @@ export function uiMapData(context) { var pane = selection .append('div') - .attr('class', 'fillL map-pane col4 hide'); + .attr('class', 'fillL map-pane hide'); var paneTooltip = tooltip() .placement((textDirection === 'rtl') ? 'right' : 'left') diff --git a/modules/ui/modes.js b/modules/ui/modes.js index 3ccd5dcaf..56e501445 100644 --- a/modules/ui/modes.js +++ b/modules/ui/modes.js @@ -125,7 +125,7 @@ export function uiModes(context) { buttonsEnter .each(function(d) { d3_select(this) - .call(svgIcon('#iD-icon-' + d.button, 'pre-text')); + .call(svgIcon('#iD-icon-' + d.button)); }); buttonsEnter @@ -136,8 +136,6 @@ export function uiModes(context) { // update buttons = buttons .merge(buttonsEnter) - .classed('col3', showNotes) // 25% - .classed('col4', !showNotes) // 33% .property('disabled', function(d) { return d.id === 'add-note' ? !notesEditable() : !editable(); }); diff --git a/modules/ui/save.js b/modules/ui/save.js index fa23d3025..09d6e5d08 100644 --- a/modules/ui/save.js +++ b/modules/ui/save.js @@ -80,15 +80,15 @@ export function uiSave(context) { var button = selection .append('button') - .attr('class', 'save col12 disabled') + .attr('class', 'save disabled') .attr('tabindex', -1) .on('click', save) .call(tooltipBehavior); button - .append('div') - .attr('class', 'save-inner-wrap') - .call(svgIcon('#iD-icon-save', 'pre-text')) + .call(svgIcon('#iD-icon-save')); + + button .append('span') .attr('class', 'label') .text(t('save.title')); diff --git a/modules/ui/settings/custom_background.js b/modules/ui/settings/custom_background.js index 9b2fc4e05..7af7365a5 100644 --- a/modules/ui/settings/custom_background.js +++ b/modules/ui/settings/custom_background.js @@ -41,12 +41,12 @@ export function uiSettingsCustomBackground(context) { .property('value', _currSettings.template); - // insert a cancel button, and adjust the button widths + // insert a cancel button var buttonSection = modal.select('.modal-section.buttons'); buttonSection .insert('button', '.ok-button') - .attr('class', 'button col3 cancel-button secondary-action') + .attr('class', 'button cancel-button secondary-action') .text(t('confirm.cancel')); @@ -54,8 +54,6 @@ export function uiSettingsCustomBackground(context) { .on('click.cancel', clickCancel); buttonSection.select('.ok-button') - .classed('col3', true) - .classed('col4', false) .attr('disabled', isSaveDisabled) .on('click.save', clickSave); diff --git a/modules/ui/settings/custom_data.js b/modules/ui/settings/custom_data.js index 090a9ec42..0ba28175f 100644 --- a/modules/ui/settings/custom_data.js +++ b/modules/ui/settings/custom_data.js @@ -70,12 +70,12 @@ export function uiSettingsCustomData(context) { .property('value', _currSettings.url); - // insert a cancel button, and adjust the button widths + // insert a cancel button var buttonSection = modal.select('.modal-section.buttons'); buttonSection .insert('button', '.ok-button') - .attr('class', 'button col3 cancel-button secondary-action') + .attr('class', 'button cancel-button secondary-action') .text(t('confirm.cancel')); @@ -83,8 +83,6 @@ export function uiSettingsCustomData(context) { .on('click.cancel', clickCancel); buttonSection.select('.ok-button') - .classed('col3', true) - .classed('col4', false) .attr('disabled', isSaveDisabled) .on('click.save', clickSave); diff --git a/modules/ui/undo_redo.js b/modules/ui/undo_redo.js index 159f74c9a..e57a93140 100644 --- a/modules/ui/undo_redo.js +++ b/modules/ui/undo_redo.js @@ -48,7 +48,7 @@ export function uiUndoRedo(context) { .data(commands) .enter() .append('button') - .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; }) + .attr('class', function(d) { return 'disabled ' + d.id + '-button'; }) .on('click', function(d) { return d.action(); }) .call(tooltipBehavior); From c2971f667d2ba76f098db776e8f5174fe00f6f54 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 2 Nov 2018 10:49:55 -0400 Subject: [PATCH 02/16] Remove setCenter() from map.dimensions() This was triggering a weird redraw which made the map slow and look wrong The map will redraw again in a few milleseconds anyway. This means that the the map will not stay on the center, but rather the top-left corner, which kind of feels better anyway, as it doesn't move things around as much. --- modules/renderer/map.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 2878d8a48..2d699b862 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -662,13 +662,11 @@ export function rendererMap(context) { map.dimensions = function(_) { if (!arguments.length) return dimensions; - var center = map.center(); dimensions = _; drawLayers.dimensions(dimensions); context.background().dimensions(dimensions); projection.clipExtent([[0, 0], dimensions]); mouse = utilFastMouse(supersurface.node()); - setCenter(center); scheduleRedraw(); return map; From aecbaec896ba244556658faf3e63790c6037b919 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 2 Nov 2018 11:15:52 -0400 Subject: [PATCH 03/16] Add key to toggle the sidebar --- data/core.yaml | 5 +++-- data/shortcuts.json | 4 ++++ dist/locales/en.json | 5 +++-- modules/ui/init.js | 13 +++++++++---- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index bdcbcfca6..2f07ccd47 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -294,8 +294,8 @@ en: loading_auth: "Connecting to OpenStreetMap..." report_a_bug: Report a bug help_translate: Help translate - sidebar_button: - title: Sidebar + sidebar: + key: '`' tooltip: Toggle the sidebar. feature_info: hidden_warning: "{count} hidden features" @@ -1151,6 +1151,7 @@ en: background_switch: "Switch back to last background" map_data: "Show map data options" fullscreen: "Enter full screen mode" + sidebar: "Toggle sidebar" wireframe: "Toggle wireframe mode" minimap: "Toggle minimap" selecting: diff --git a/data/shortcuts.json b/data/shortcuts.json index fadc50fca..39a81889f 100644 --- a/data/shortcuts.json +++ b/data/shortcuts.json @@ -66,6 +66,10 @@ "shortcuts": ["F", "F11"], "text": "shortcuts.browsing.display_options.fullscreen" }, + { + "shortcuts": ["sidebar.key"], + "text": "shortcuts.browsing.display_options.sidebar" + }, { "shortcuts": ["area_fill.wireframe.key"], "text": "shortcuts.browsing.display_options.wireframe" diff --git a/dist/locales/en.json b/dist/locales/en.json index 09aa3b865..b2baab933 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -373,8 +373,8 @@ "loading_auth": "Connecting to OpenStreetMap...", "report_a_bug": "Report a bug", "help_translate": "Help translate", - "sidebar_button": { - "title": "Sidebar", + "sidebar": { + "key": "`", "tooltip": "Toggle the sidebar." }, "feature_info": { @@ -1329,6 +1329,7 @@ "background_switch": "Switch back to last background", "map_data": "Show map data options", "fullscreen": "Enter full screen mode", + "sidebar": "Toggle sidebar", "wireframe": "Toggle wireframe mode", "minimap": "Toggle minimap" }, diff --git a/modules/ui/init.js b/modules/ui/init.js index 44316c429..2b85f50cb 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -37,6 +37,7 @@ import { uiSidebar } from './sidebar'; import { uiSpinner } from './spinner'; import { uiSplash } from './splash'; import { uiStatus } from './status'; +import { uiTooltipHtml } from './tooltipHtml'; import { uiUndoRedo } from './undo_redo'; import { uiVersion } from './version'; import { uiZoom } from './zoom'; @@ -101,14 +102,17 @@ export function uiInit(context) { .attr('class', 'sidebar-toggle') .attr('tabindex', -1) .on('click', ui.sidebar.toggleCollapse) - .call(tooltip().title(t('sidebar_button.tooltip')).placement('bottom')); + .call(tooltip() + .placement('bottom') + .html(true) + .title(function(mode) { + return uiTooltipHtml(t('sidebar.tooltip'), t('sidebar.key')); + }) + ); var iconSuffix = textDirection === 'rtl' ? 'right' : 'left'; sidebarButton .call(svgIcon('#iD-icon-sidebar-' + iconSuffix)); - // .append('span') - // .attr('class', 'label') - // .text(t('sidebar_button.title')); leadingArea .append('div') @@ -287,6 +291,7 @@ export function uiInit(context) { var pa = 80; // pan amount var keybinding = d3_keybinding('main') .on('⌫', function() { d3_event.preventDefault(); }) + .on(t('sidebar.key'), ui.sidebar.toggleCollapse) .on('←', pan([pa, 0])) .on('↑', pan([0, pa])) .on('→', pan([-pa, 0])) From d4e31a82e3dfac90fb05c8cc9674bc86e8328b9e Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 2 Nov 2018 23:21:59 -0400 Subject: [PATCH 04/16] Adjust sidebar resizer to keep map still by anti-panning --- modules/ui/init.js | 15 +++-- modules/ui/sidebar.js | 138 +++++++++++++++++++++++++++--------------- 2 files changed, 100 insertions(+), 53 deletions(-) diff --git a/modules/ui/init.js b/modules/ui/init.js index 2b85f50cb..c93294375 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -105,9 +105,7 @@ export function uiInit(context) { .call(tooltip() .placement('bottom') .html(true) - .title(function(mode) { - return uiTooltipHtml(t('sidebar.tooltip'), t('sidebar.key')); - }) + .title(uiTooltipHtml(t('sidebar.tooltip'), t('sidebar.key'))) ); var iconSuffix = textDirection === 'rtl' ? 'right' : 'left'; @@ -381,10 +379,17 @@ export function uiInit(context) { ui.photoviewer = uiPhotoviewer(context); - ui.onResize = function() { + ui.onResize = function(withPan) { + var map = context.map(); var content = d3_select('#content'); var mapDimensions = utilGetDimensions(content, true); - context.map().dimensions(mapDimensions); + + if (withPan !== undefined) { + map.redrawEnable(false); + map.pan(withPan); + map.redrawEnable(true); + } + map.dimensions(mapDimensions); ui.photoviewer.onMapResize(); }; diff --git a/modules/ui/sidebar.js b/modules/ui/sidebar.js index da5028682..660d3b3b4 100644 --- a/modules/ui/sidebar.js +++ b/modules/ui/sidebar.js @@ -1,6 +1,8 @@ import _throttle from 'lodash-es/throttle'; import { drag as d3_drag } from 'd3-drag'; +import { interpolateNumber as d3_interpolateNumber } from 'd3-interpolate'; + import { select as d3_select, event as d3_event, @@ -32,43 +34,67 @@ export function uiSidebar(context) { function sidebar(selection) { + var minWidth = 280; + var sidebarWidth; + var containerWidth; + var dragOffset; var resizer = selection .append('div') .attr('id', 'sidebar-resizer'); - // set the initial width constraints - selection.style('min-width', '280px'); + // Set the initial width constraints + selection.style('min-width', minWidth + 'px'); selection.style('max-width', '400px'); selection.style('width', '33.3333%'); var container = d3_select('#id-container'); resizer.call(d3_drag() .container(container.node()) + .on('start', function() { + // offset from edge of sidebar-resizer + dragOffset = d3_event.sourceEvent.offsetX - 1; + + sidebarWidth = selection.node().getBoundingClientRect().width; + containerWidth = container.node().getBoundingClientRect().width; + var widthPct = (sidebarWidth / containerWidth) * 100; + selection + .style('width', widthPct + '%') // lock in current width + .style('max-width', '85%'); // but allow larger widths + }) .on('drag', function() { + var isRTL = (textDirection === 'rtl'); + var xMarginProperty = isRTL ? 'margin-right' : 'margin-left'; - var containerWidthPx = container.node().getBoundingClientRect().width; + var x = d3_event.x - dragOffset; + sidebarWidth = isRTL ? containerWidth - x : x; - var xMarginProperty = textDirection === 'rtl' ? 'margin-right' : 'margin-left'; + var isCollapsed = container.classed('sidebar-collapsed'); + var shouldCollapse = sidebarWidth < minWidth; - // subtact 1px so the mouse stays in the div and maintains the col-resize cursor - var newWidthPx = textDirection === 'rtl' ? containerWidthPx - d3_event.x-1 : d3_event.x-1; - - var shouldCollapse = newWidthPx < 280; container.classed('sidebar-collapsed', shouldCollapse); - // allow large widths - selection.style('max-width', '85%'); - if (shouldCollapse) { - selection.style(xMarginProperty,'-400px') - .style('width', '400px'); - } - else { - var newWidthPercent = (newWidthPx / containerWidthPx) * 100; - selection.style(xMarginProperty, null) - .style('width', newWidthPercent+'%'); + if (shouldCollapse) { + if (!isCollapsed) { + selection + .style(xMarginProperty, '-400px') + .style('width', '400px'); + + context.ui().onResize([sidebarWidth - d3_event.dx, 0]); + } + + } else { + var widthPct = (sidebarWidth / containerWidth) * 100; + selection + .style(xMarginProperty, null) + .style('width', widthPct + '%'); + + if (isCollapsed) { + context.ui().onResize([-sidebarWidth, 0]); + } else { + context.ui().onResize([-d3_event.dx, 0]); + } } - context.ui().onResize(); }) ); @@ -195,48 +221,64 @@ export function uiSidebar(context) { _current = null; }; - sidebar.toggleCollapse = function(shouldCollapse) { + sidebar.toggleCollapse = function(shouldCollapse) { if (d3_event) { d3_event.preventDefault(); } var container = d3_select('#id-container'); - var collapsing; + var isCollapsing; var isCollapsed = container.classed('sidebar-collapsed'); + if (typeof shouldCollapse !== 'undefined') { - if (shouldCollapse === isCollapsed) { - return; - } - collapsing = shouldCollapse; + if (shouldCollapse === isCollapsed) return; + isCollapsing = shouldCollapse; } else { - collapsing = !isCollapsed; + isCollapsing = !isCollapsed; } - var sidebar = d3_select('#sidebar'); + var xMarginProperty = textDirection === 'rtl' ? 'margin-right' : 'margin-left'; - if (collapsing) { - var preSidebarWidthInPx = sidebar.node().getBoundingClientRect().width; - sidebar.style('width', preSidebarWidthInPx+'px'); - sidebar.transition() - .style('width', '400px') - .style(xMarginProperty,'-400px') - .on('end',function(){ - context.ui().onResize(); - }); - container.classed('sidebar-collapsed', true); - } else { - var containerWidthPx = container.node().getBoundingClientRect().width; - var postSidebarWidthInPx = Math.max(containerWidthPx*0.333333, 280); - sidebar.transition() - .style('width', postSidebarWidthInPx) - .style(xMarginProperty, '0px') - .on('end',function(){ - sidebar.style('width', '33.3333%'); - context.ui().onResize(); - }); - container.classed('sidebar-collapsed', false); + + var sidebar = d3_select('#sidebar'); + sidebarWidth = sidebar.node().getBoundingClientRect().width; + + // switch from % to px + sidebar.style('width', sidebarWidth + 'px'); + + var startMargin, endMargin, lastMargin; + if (isCollapsing) { + startMargin = lastMargin = 0; + endMargin = -sidebarWidth; + } else { + startMargin = lastMargin = -sidebarWidth; + endMargin = 0; } + + sidebar.transition() + .style(xMarginProperty, endMargin + 'px') + .tween('panner', function() { + var i = d3_interpolateNumber(startMargin, endMargin); + return function(t) { + var dx = lastMargin - Math.round(i(t)); + lastMargin = lastMargin - dx; + context.ui().onResize([dx, 0]); + }; + }) + .on('end', function() { + container.classed('sidebar-collapsed', isCollapsing); + + // switch back from px to % + if (!isCollapsing) { + var containerWidth = container.node().getBoundingClientRect().width; + var widthPct = (sidebarWidth / containerWidth) * 100; + sidebar + .style(xMarginProperty, null) + .style('width', widthPct + '%'); + } + }); }; + // toggle the sidebar collapse when double-clicking the resizer resizer.on('dblclick', sidebar.toggleCollapse); } From c1d28d9333872013d79111cfca86e63ad746ef53 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 3 Nov 2018 00:11:10 -0400 Subject: [PATCH 05/16] Wrap sidebar button in div, so the `.tool-group > div` rule pads it --- modules/ui/init.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ui/init.js b/modules/ui/init.js index c93294375..b9136ede8 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -98,6 +98,7 @@ export function uiInit(context) { .attr('class', 'tool-group leading-area'); var sidebarButton = leadingArea + .append('div') .append('button') .attr('class', 'sidebar-toggle') .attr('tabindex', -1) From 458aeb4dbf98b464b5587c30f344830f9fdddd02 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 4 Nov 2018 10:03:55 -0500 Subject: [PATCH 06/16] Adjust tool groups slightly, let leading group shrink more. --- css/80_app.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/css/80_app.css b/css/80_app.css index 72c957f2d..e6f2d116f 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -569,15 +569,17 @@ button.secondary-action:hover { display: flex; flex: 0 1 auto; flex-flow: row nowrap; + width: 100%; } .tool-group.leading-area { + flex-shrink: 2; justify-content: flex-start; } .tool-group.center-area { justify-content: center; } .tool-group.trailing-area { - justify-content: flex-end; + justify-content: flex-start; } .tool-group > div { From 136e4556a767a8cdb88992067474d207f59c318f Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 5 Nov 2018 12:22:20 -0500 Subject: [PATCH 07/16] Move spinner to flex-end, and some css cleanups --- css/80_app.css | 103 +++++++++++---------------------------------- modules/ui/init.js | 31 ++++++++------ 2 files changed, 43 insertions(+), 91 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index e6f2d116f..a6776bd76 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -57,20 +57,11 @@ body { /* Firefox has its own ideas about fixed positioning when a css filter is active - #4348 */ /* https://stackoverflow.com/questions/37949942/firefox-position-bug-by-parent-with-filter */ +/* TODO: check whether this is necessary now with flexbox */ @-moz-document url-prefix() { #content > #bar { width: 100vw; } -/* - #content.inactive > #bar > .spacer.col4 { - width: 0px; - } - #content.active > #bar > .spacer.col4 { - width: 33.3333%; - transition-duration: 200ms; - transition-timing-function: step-end; - } -*/ } #defs { @@ -80,32 +71,6 @@ body { height: 0; } -.spacer { - height: 40px; - margin-right: 10px; -} - -.spinner { - opacity: .5; - display: inline-block; -} - -.spinner img { - height: 40px; - width: 40px; - border-radius: 4px; - background: black; -} -[dir='rtl'] .spinner img { - -moz-transform: scaleX(-1); - -o-transform: scaleX(-1); - -webkit-transform: scaleX(-1); - transform: scaleX(-1); - filter: FlipH; - -ms-filter: "FlipH"; -} - - div, textarea, label, input, form, span, ul, li, ol, a, button, h1, h2, h3, h4, h5, p, img { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -141,7 +106,6 @@ h3 { font-weight: bold; margin-bottom: 10px; } - h4, h5 { font-size: 12px; font-weight: bold; @@ -169,23 +133,18 @@ p { margin: 0; padding: 0; } - p:last-child { padding-bottom: 0; } - em { font-style: italic; } - strong { font-weight: bold; } - a:visited, a { color: #7092ff; } - a:hover { color: #597be7; } @@ -277,9 +236,9 @@ table.tags, table.tags td, table.tags th { /* Grid ------------------------------------------------------- */ -.col6 { float: left; width: 50.0000%; max-width: 600px; } -.col8 { float: left; width: 66.6666%; } -.col12 { float: left; width: 100.0000%; } +.col6 { float: left; width: 50.0000%; max-width: 600px; } +.col8 { float: left; width: 66.6666%; } +.col12 { float: left; width: 100.0000%; } /* UI Lists ------------------------------------------------------- */ @@ -417,35 +376,10 @@ button.minor { button.minor .icon { opacity: .5; } - button.minor:hover { background-color: #f1f1f1; } -/*.button-wrap { - display: inline-block; - padding-right: 10px; - margin: 0; -} -[dir='rtl'] .button-wrap { - padding-left: 10px; -} -.button-wrap button { - white-space: nowrap; - padding: 0px 8px; -} - -.button-wrap button:only-child { - width: 100%; -} - -.button-wrap:last-of-type { - padding-right: 0; -} -[dir='rtl'] .button-wrap:last-of-type { - padding-left: 0; -}*/ - .joined button { border-radius: 0; border-right: 1px solid rgba(0,0,0,.5); @@ -458,14 +392,12 @@ button.minor:hover { .fillL .joined button { border-right: 1px solid #fff; } - .joined button:first-child { border-radius: 4px 0 0 4px; } [dir='rtl'] .joined button:first-child { border-radius: 0 4px 4px 0; } - .joined button:last-child { border-right-width: 0; border-radius: 0 4px 4px 0; @@ -528,15 +460,12 @@ button.secondary-action:hover { .icon.light { color: #fff; } - .icon.created { color: #00ca07; } - .icon.modified { color: #666; } - .icon.deleted { color: #ea0000; } @@ -586,7 +515,6 @@ button.secondary-action:hover { display: flex; margin: 0 5px; } - .tool-group button { display: flex; flex: 1 1 auto; @@ -594,7 +522,6 @@ button.secondary-action:hover { padding: 0 10px; min-width: 30px; } - .tool-group button .icon { flex: 0 0 20px; } @@ -603,7 +530,6 @@ button.secondary-action:hover { padding: 0 5px; } - button.save .count { visibility: hidden; display: inline-block; @@ -639,7 +565,6 @@ button.save.has-count .label { margin-right: 0; } - .help-wrap svg.icon.pre-text.add-note, button.add-note svg.icon { height: 15px; @@ -662,6 +587,26 @@ button.add-note svg.icon { margin-right: 3px; } +.spinner { + opacity: .5; + display: flex; + flex-shrink: 2; + justify-content: flex-end; +} +.spinner img { + height: 40px; + width: 40px; + border-radius: 4px; + background: black; +} +[dir='rtl'] .spinner img { + -moz-transform: scaleX(-1); + -o-transform: scaleX(-1); + -webkit-transform: scaleX(-1); + transform: scaleX(-1); + filter: FlipH; + -ms-filter: "FlipH"; +} /* Header for modals / panes diff --git a/modules/ui/init.js b/modules/ui/init.js index b9136ede8..023ea7208 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -45,7 +45,14 @@ import { uiCmd } from './cmd'; export function uiInit(context) { - var uiInitCounter = 0; + // Selectors for elements that can be collapsed if they overflow + // (can't use a media query for this because it depends on sidebar width, not screen width) + var headerCollapsable = 'button > span.label'; + var footerCollapsable = ''; + + var _initCounter = 0; + var _initCallback; + function render(container) { container @@ -92,7 +99,7 @@ export function uiInit(context) { .call(uiInfo(context)) .call(uiNotice(context)); - // Leading area button group (sidebar toggle) + // Leading area button group (Sidebar toggle) var leadingArea = bar .append('div') .attr('class', 'tool-group leading-area'); @@ -119,7 +126,7 @@ export function uiInit(context) { .call(uiFullScreen(context)); - // Center area button group (mode buttons) + // Center area button group (Point/Line/Area/Note mode buttons) bar .append('div') .attr('class', 'tool-group center-area') @@ -128,7 +135,7 @@ export function uiInit(context) { .call(uiModes(context), bar); - // Center area button group (undo/redo save buttons) + // Trailing area button group (Undo/Redo save buttons) var trailingArea = bar .append('div') .attr('class', 'tool-group trailing-area'); @@ -143,13 +150,15 @@ export function uiInit(context) { .attr('class', 'save-wrap') .call(uiSave(context)); - trailingArea + + // For now, just put spinner at the end + bar .append('div') .attr('class', 'spinner') .call(uiSpinner(context)); - // Map controls + // Map controls (appended to #bar, but absolutely positioned) var controls = bar .append('div') .attr('class', 'map-controls'); @@ -305,7 +314,7 @@ export function uiInit(context) { context.enter(modeBrowse(context)); - if (!uiInitCounter++) { + if (!_initCounter++) { if (!hash.startWalkthrough) { context.container() .call(uiSplash(context)) @@ -330,7 +339,7 @@ export function uiInit(context) { }); } - uiInitCounter++; + _initCounter++; if (hash.startWalkthrough) { hash.startWalkthrough = false; @@ -347,10 +356,8 @@ export function uiInit(context) { } - var renderCallback; - function ui(node, callback) { - renderCallback = callback; + _initCallback = callback; var container = d3_select(node); context.container(container); context.loadLocale(function(err) { @@ -370,7 +377,7 @@ export function uiInit(context) { if (!err) { context.container().selectAll('*').remove(); render(context.container()); - if (renderCallback) renderCallback(); + if (_initCallback) _initCallback(); } }); }; From b4119ae1ad771eb94547208d73813f37e865decc Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 5 Nov 2018 17:16:50 -0500 Subject: [PATCH 08/16] Class toolbars with `narrow` if we detect overflow happening Also add css rules to drop labels from toolbar buttons if needed --- css/80_app.css | 15 +++++++++++++-- modules/ui/init.js | 34 +++++++++++++++++++++++++++++----- modules/ui/modes.js | 5 +++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index a6776bd76..16579b926 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -16,7 +16,6 @@ body { sans-serif; margin: 0; padding: 0; - min-width: 768px; color: #333; overflow: hidden; -ms-user-select: none; @@ -32,7 +31,6 @@ body { .id-container { height: 100%; width: 100%; - min-width: 768px; } #content { @@ -609,6 +607,19 @@ button.add-note svg.icon { } +#bar.narrow .tool-group { + width: unset; +} +#bar.narrow .spinner, +#bar.narrow button .label { + display: none; +} +#bar.narrow button .count { + border-left-width: 0; + border-right-width: 0; +} + + /* Header for modals / panes ------------------------------------------------------- */ .header { diff --git a/modules/ui/init.js b/modules/ui/init.js index 023ea7208..447b7d4ce 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -45,13 +45,9 @@ import { uiCmd } from './cmd'; export function uiInit(context) { - // Selectors for elements that can be collapsed if they overflow - // (can't use a media query for this because it depends on sidebar width, not screen width) - var headerCollapsable = 'button > span.label'; - var footerCollapsable = ''; - var _initCounter = 0; var _initCallback; + var _needWidth = {}; function render(container) { @@ -400,7 +396,35 @@ export function uiInit(context) { map.dimensions(mapDimensions); ui.photoviewer.onMapResize(); + + // check if header or footer have overflowed + ui.checkOverflow('#bar'); + ui.checkOverflow('#footer'); }; + + // Call checkOverflow when resizing or whenever the contents change. + ui.checkOverflow = function(selector, reset) { + if (reset) { + delete _needWidth[selector]; + } + + var element = d3_select(selector); + var scrollWidth = element.property('scrollWidth'); + var clientWidth = element.property('clientWidth'); + var needed = _needWidth[selector] || scrollWidth; + + if (scrollWidth > clientWidth) { // overflow happening + element.classed('narrow', true); + if (!_needWidth[selector]) { + _needWidth[selector] = scrollWidth; + } + + } else if (scrollWidth >= needed) { + element.classed('narrow', false); + } + }; + + return ui; } diff --git a/modules/ui/modes.js b/modules/ui/modes.js index 56e501445..4aa4f369a 100644 --- a/modules/ui/modes.js +++ b/modules/ui/modes.js @@ -133,6 +133,11 @@ export function uiModes(context) { .attr('class', 'label') .text(function(mode) { return mode.title; }); + // if we are adding/removing the buttons, check if toolbar has overflowed + if (buttons.enter().size() || buttons.exit().size()) { + context.ui().checkOverflow('#bar', true); + } + // update buttons = buttons .merge(buttonsEnter) From 08e9476f3ecd71559756694cd446774455db6c09 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 13:09:04 -0500 Subject: [PATCH 09/16] Fix photoviewer resize event --- modules/services/mapillary.js | 2 +- modules/services/openstreetcam.js | 2 +- modules/services/streetside.js | 2 +- modules/ui/photoviewer.js | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index 77d516a6d..0767f283d 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -372,7 +372,7 @@ export default { defs.call(svgDefs(context).addSprites, ['mapillary-sprite']); // Register viewer resize handler - context.ui().on('photoviewerResize', function() { + context.ui().photoviewer.on('resize', function() { if (_mlyViewer) { _mlyViewer.resize(); } diff --git a/modules/services/openstreetcam.js b/modules/services/openstreetcam.js index 40044e8ca..07ef328d4 100644 --- a/modules/services/openstreetcam.js +++ b/modules/services/openstreetcam.js @@ -327,7 +327,7 @@ export default { // Register viewer resize handler - context.ui().on('photoviewerResize', function(dimensions) { + context.ui().photoviewer.on('resize', function(dimensions) { imgZoom = d3_zoom() .extent([[0, 0], dimensions]) .translateExtent([[0, 0], dimensions]) diff --git a/modules/services/streetside.js b/modules/services/streetside.js index 8a0cd1b1e..d748d9251 100644 --- a/modules/services/streetside.js +++ b/modules/services/streetside.js @@ -626,7 +626,7 @@ export default { // Register viewer resize handler - context.ui().on('photoviewerResize', function() { + context.ui().photoviewer.on('resize', function() { if (_pannellumViewer) { _pannellumViewer.resize(); } diff --git a/modules/ui/photoviewer.js b/modules/ui/photoviewer.js index 9be65f7e9..ed20dbba6 100644 --- a/modules/ui/photoviewer.js +++ b/modules/ui/photoviewer.js @@ -11,7 +11,7 @@ import { services } from '../services'; export function uiPhotoviewer(context) { - var dispatch = d3_dispatch('photoviewerResize'); + var dispatch = d3_dispatch('resize'); function photoviewer(selection) { selection @@ -30,7 +30,7 @@ export function uiPhotoviewer(context) { .attr('class', 'resize-handle-xy') .on( 'mousedown', - buildResizeListener(selection, 'photoviewerResize', dispatch, { resizeOnX: true, resizeOnY: true }) + buildResizeListener(selection, 'resize', dispatch, { resizeOnX: true, resizeOnY: true }) ); selection @@ -38,7 +38,7 @@ export function uiPhotoviewer(context) { .attr('class', 'resize-handle-x') .on( 'mousedown', - buildResizeListener(selection, 'photoviewerResize', dispatch, { resizeOnX: true }) + buildResizeListener(selection, 'resize', dispatch, { resizeOnX: true }) ); selection @@ -46,7 +46,7 @@ export function uiPhotoviewer(context) { .attr('class', 'resize-handle-y') .on( 'mousedown', - buildResizeListener(selection, 'photoviewerResize', dispatch, { resizeOnY: true }) + buildResizeListener(selection, 'resize', dispatch, { resizeOnY: true }) ); @@ -117,7 +117,7 @@ export function uiPhotoviewer(context) { .style('width', setPhotoDimensions[0] + 'px') .style('height', setPhotoDimensions[1] + 'px'); - dispatch.call('photoviewerResize', photoviewer, setPhotoDimensions); + dispatch.call('resize', photoviewer, setPhotoDimensions); } }; From c25a21226bc08fa0b4323a5cdff0fc378eb45db8 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 13:31:05 -0500 Subject: [PATCH 10/16] Remove footer media queries, the li's will remove themselves on overflow (closes #5437) This means that the scale bar will never go away, it will be the last thing remaining. --- css/80_app.css | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 16579b926..6515645dd 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -4585,19 +4585,6 @@ li.hide + li.version .badge .tooltip .tooltip-arrow { } -/* Media Queries -------------------------------------------------------- */ -@media screen and (max-width: 1200px) { - .user-list { display: none !important; } -} -@media screen and (max-width: 1000px) { - #userLink { display: none !important; } -} -@media screen and (max-width: 900px) { - #scale-block { display: none !important; } -} - - /* Scrollbars ----------------------------------------------------- */ ::-webkit-scrollbar { From bd98b87d460ad99fafcd79d14f813970514c4fe4 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 13:46:03 -0500 Subject: [PATCH 11/16] Remove obselete Firefox rule for the bar width --- css/80_app.css | 9 --------- 1 file changed, 9 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 6515645dd..fd98de16b 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -53,15 +53,6 @@ body { transition-duration: 200ms; } -/* Firefox has its own ideas about fixed positioning when a css filter is active - #4348 */ -/* https://stackoverflow.com/questions/37949942/firefox-position-bug-by-parent-with-filter */ -/* TODO: check whether this is necessary now with flexbox */ -@-moz-document url-prefix() { - #content > #bar { - width: 100vw; - } -} - #defs { /* Can't be display: none or the clippaths are ignored. */ position: absolute; From 3d65dd89037b575b0160a365ba1952d6fc876141 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 14:16:23 -0500 Subject: [PATCH 12/16] preventDefault on sourceEvent, if present This prevents a crash when d3_event is not the actual event, but is a transition event or similar --- modules/ui/sidebar.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/ui/sidebar.js b/modules/ui/sidebar.js index 660d3b3b4..96ed54af7 100644 --- a/modules/ui/sidebar.js +++ b/modules/ui/sidebar.js @@ -223,8 +223,11 @@ export function uiSidebar(context) { sidebar.toggleCollapse = function(shouldCollapse) { - if (d3_event) { - d3_event.preventDefault(); + var e = d3_event; + if (e.sourceEvent) { + e.sourceEvent.preventDefault(); + } else if (e) { + e.preventDefault(); } var container = d3_select('#id-container'); From e31e84b109e0816baa93b0c0ebfacc531b2ef9f6 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 15:08:05 -0500 Subject: [PATCH 13/16] Simplify some things I found confusing - class the #sidebar itself as collapsed not the #id-container - the #sidebar is the selection, so just use `selection` instead of `var sidebar = d3_select('#sidebar');` (which conflicts with the closure `sidebar()` function) - have separate functions `expand` `collapse` `toggle` rather than a `toggle(shouldCollapse)` --- css/80_app.css | 14 +++++----- modules/ui/init.js | 4 +-- modules/ui/sidebar.js | 61 ++++++++++++++++++++++++------------------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index fd98de16b..eaa8e59c7 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -755,20 +755,20 @@ a.hide-toggle { width: 6px; cursor: col-resize; } -.sidebar-collapsed #sidebar-resizer { - /* make target wider to avoid the user accidentally resizing window */ - width: 10px; - right: -10px; -} [dir='rtl'] #sidebar-resizer { right: auto; left: -6px; } -.sidebar-collapsed[dir='rtl'] #sidebar-resizer { + +#sidebar.collapsed #sidebar-resizer { + /* make target wider to avoid the user accidentally resizing window */ + width: 10px; + right: -10px; +} +[dir='rtl'] #sidebar.collapsed #sidebar-resizer { left: -10px; } - .sidebar-component { position: absolute; top: 0; diff --git a/modules/ui/init.js b/modules/ui/init.js index 447b7d4ce..dfd975773 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -105,7 +105,7 @@ export function uiInit(context) { .append('button') .attr('class', 'sidebar-toggle') .attr('tabindex', -1) - .on('click', ui.sidebar.toggleCollapse) + .on('click', ui.sidebar.toggle) .call(tooltip() .placement('bottom') .html(true) @@ -295,7 +295,7 @@ export function uiInit(context) { var pa = 80; // pan amount var keybinding = d3_keybinding('main') .on('⌫', function() { d3_event.preventDefault(); }) - .on(t('sidebar.key'), ui.sidebar.toggleCollapse) + .on(t('sidebar.key'), ui.sidebar.toggle) .on('←', pan([pa, 0])) .on('↑', pan([0, pa])) .on('→', pan([-pa, 0])) diff --git a/modules/ui/sidebar.js b/modules/ui/sidebar.js index 96ed54af7..37f7e338f 100644 --- a/modules/ui/sidebar.js +++ b/modules/ui/sidebar.js @@ -34,6 +34,7 @@ export function uiSidebar(context) { function sidebar(selection) { + var container = d3_select('#id-container'); var minWidth = 280; var sidebarWidth; var containerWidth; @@ -44,11 +45,11 @@ export function uiSidebar(context) { .attr('id', 'sidebar-resizer'); // Set the initial width constraints - selection.style('min-width', minWidth + 'px'); - selection.style('max-width', '400px'); - selection.style('width', '33.3333%'); + selection + .style('min-width', minWidth + 'px') + .style('max-width', '400px') + .style('width', '33.3333%'); - var container = d3_select('#id-container'); resizer.call(d3_drag() .container(container.node()) .on('start', function() { @@ -69,10 +70,10 @@ export function uiSidebar(context) { var x = d3_event.x - dragOffset; sidebarWidth = isRTL ? containerWidth - x : x; - var isCollapsed = container.classed('sidebar-collapsed'); + var isCollapsed = selection.classed('collapsed'); var shouldCollapse = sidebarWidth < minWidth; - container.classed('sidebar-collapsed', shouldCollapse); + selection.classed('collapsed', shouldCollapse); if (shouldCollapse) { if (!isCollapsed) { @@ -167,7 +168,7 @@ export function uiSidebar(context) { sidebar.select = function(id, newFeature) { if (!_current && id) { // uncollapse the sidebar to show the editor - sidebar.toggleCollapse(false); + sidebar.expand(); featureListWrap .classed('inspector-hidden', true); @@ -222,7 +223,21 @@ export function uiSidebar(context) { }; - sidebar.toggleCollapse = function(shouldCollapse) { + sidebar.expand = function() { + if (selection.classed('collapsed')) { + sidebar.toggle(); + } + }; + + + sidebar.collapse = function() { + if (!selection.classed('collapsed')) { + sidebar.toggle(); + } + }; + + + sidebar.toggle = function() { var e = d3_event; if (e.sourceEvent) { e.sourceEvent.preventDefault(); @@ -230,24 +245,14 @@ export function uiSidebar(context) { e.preventDefault(); } - var container = d3_select('#id-container'); - var isCollapsing; - var isCollapsed = container.classed('sidebar-collapsed'); - - if (typeof shouldCollapse !== 'undefined') { - if (shouldCollapse === isCollapsed) return; - isCollapsing = shouldCollapse; - } else { - isCollapsing = !isCollapsed; - } - + var isCollapsed = selection.classed('collapsed'); + var isCollapsing = !isCollapsed; var xMarginProperty = textDirection === 'rtl' ? 'margin-right' : 'margin-left'; - var sidebar = d3_select('#sidebar'); - sidebarWidth = sidebar.node().getBoundingClientRect().width; + sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px - sidebar.style('width', sidebarWidth + 'px'); + selection.style('width', sidebarWidth + 'px'); var startMargin, endMargin, lastMargin; if (isCollapsing) { @@ -258,7 +263,7 @@ export function uiSidebar(context) { endMargin = 0; } - sidebar.transition() + selection.transition() .style(xMarginProperty, endMargin + 'px') .tween('panner', function() { var i = d3_interpolateNumber(startMargin, endMargin); @@ -269,13 +274,13 @@ export function uiSidebar(context) { }; }) .on('end', function() { - container.classed('sidebar-collapsed', isCollapsing); + selection.classed('collapsed', isCollapsing); // switch back from px to % if (!isCollapsing) { var containerWidth = container.node().getBoundingClientRect().width; var widthPct = (sidebarWidth / containerWidth) * 100; - sidebar + selection .style(xMarginProperty, null) .style('width', widthPct + '%'); } @@ -283,7 +288,7 @@ export function uiSidebar(context) { }; // toggle the sidebar collapse when double-clicking the resizer - resizer.on('dblclick', sidebar.toggleCollapse); + resizer.on('dblclick', sidebar.toggle); } @@ -292,7 +297,9 @@ export function uiSidebar(context) { sidebar.select = function() {}; sidebar.show = function() {}; sidebar.hide = function() {}; - sidebar.toggleCollapse = function() {}; + sidebar.expand = function() {}; + sidebar.collapse = function() {}; + sidebar.toggle = function() {}; return sidebar; } From cc227ed4e210bad87ba302ec7fa48b11530e4584 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 16:06:45 -0500 Subject: [PATCH 14/16] Make map panning optional on sidebar expand/collapse --- modules/ui/sidebar.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/ui/sidebar.js b/modules/ui/sidebar.js index 37f7e338f..b0836acbd 100644 --- a/modules/ui/sidebar.js +++ b/modules/ui/sidebar.js @@ -168,7 +168,7 @@ export function uiSidebar(context) { sidebar.select = function(id, newFeature) { if (!_current && id) { // uncollapse the sidebar to show the editor - sidebar.expand(); + sidebar.expand(true); featureListWrap .classed('inspector-hidden', true); @@ -223,23 +223,23 @@ export function uiSidebar(context) { }; - sidebar.expand = function() { + sidebar.expand = function(moveMap) { if (selection.classed('collapsed')) { - sidebar.toggle(); + sidebar.toggle(moveMap); } }; - sidebar.collapse = function() { + sidebar.collapse = function(moveMap) { if (!selection.classed('collapsed')) { - sidebar.toggle(); + sidebar.toggle(moveMap); } }; - sidebar.toggle = function() { + sidebar.toggle = function(moveMap) { var e = d3_event; - if (e.sourceEvent) { + if (e && e.sourceEvent) { e.sourceEvent.preventDefault(); } else if (e) { e.preventDefault(); @@ -270,7 +270,7 @@ export function uiSidebar(context) { return function(t) { var dx = lastMargin - Math.round(i(t)); lastMargin = lastMargin - dx; - context.ui().onResize([dx, 0]); + context.ui().onResize(moveMap ? undefined : [dx, 0]); }; }) .on('end', function() { From 42aa834fab6f448359f7df1557edc18eb81e7d29 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 6 Nov 2018 17:03:58 -0500 Subject: [PATCH 15/16] Avoid obscuring selected entity when expanding the sidebar --- modules/ui/sidebar.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/modules/ui/sidebar.js b/modules/ui/sidebar.js index b0836acbd..cf5064bdc 100644 --- a/modules/ui/sidebar.js +++ b/modules/ui/sidebar.js @@ -165,10 +165,23 @@ export function uiSidebar(context) { sidebar.hover = _throttle(hover, 200); + sidebar.intersects = function(extent) { + var rect = selection.node().getBoundingClientRect(); + return extent.intersects([ + context.projection.invert([0, rect.height]), + context.projection.invert([rect.width, 0]) + ]); + }; + + sidebar.select = function(id, newFeature) { if (!_current && id) { - // uncollapse the sidebar to show the editor - sidebar.expand(true); + // uncollapse the sidebar + if (selection.classed('collapsed')) { + var entity = context.entity(id); + var extent = entity.extent(context.graph()); + sidebar.expand(sidebar.intersects(extent)); + } featureListWrap .classed('inspector-hidden', true); @@ -294,6 +307,7 @@ export function uiSidebar(context) { sidebar.hover = function() {}; sidebar.hover.cancel = function() {}; + sidebar.intersects = function() {}; sidebar.select = function() {}; sidebar.show = function() {}; sidebar.hide = function() {}; From b860bbb5f0b47ee8040bc4f324567d576174e255 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 7 Nov 2018 09:54:54 -0500 Subject: [PATCH 16/16] Expand sidebar when selecting notes and data --- modules/geo/extent.js | 1 - modules/modes/select_data.js | 18 +++++++++++------- modules/modes/select_note.js | 7 +++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/geo/extent.js b/modules/geo/extent.js index bf30fd679..0b85158ea 100644 --- a/modules/geo/extent.js +++ b/modules/geo/extent.js @@ -20,7 +20,6 @@ export function geoExtent(min, max) { } } -// $FlowFixMe geoExtent.prototype = new Array(2); _extend(geoExtent.prototype, { diff --git a/modules/modes/select_data.js b/modules/modes/select_data.js index 1e433660d..89cde781e 100644 --- a/modules/modes/select_data.js +++ b/modules/modes/select_data.js @@ -1,3 +1,6 @@ + +import { geoBounds as d3_geoBounds } from 'd3-geo'; + import { event as d3_event, select as d3_select @@ -12,11 +15,8 @@ import { behaviorSelect } from '../behavior'; -import { - modeDragNode, - modeDragNote -} from '../modes'; - +import { geoExtent } from '../geo'; +import { modeDragNode, modeDragNote } from '../modes'; import { modeBrowse } from './browse'; import { uiDataEditor } from '../ui'; @@ -69,8 +69,12 @@ export function modeSelectData(context, selectedDatum) { selectData(); - context.ui().sidebar - .show(dataEditor.datum(selectedDatum)); + var sidebar = context.ui().sidebar; + sidebar.show(dataEditor.datum(selectedDatum)); + + // expand the sidebar, avoid obscuring the data if needed + var extent = geoExtent(d3_geoBounds(selectedDatum)); + sidebar.expand(sidebar.intersects(extent)); context.map() .on('drawn.select-data', selectData); diff --git a/modules/modes/select_note.js b/modules/modes/select_note.js index 36246a207..67ae6b1c5 100644 --- a/modules/modes/select_note.js +++ b/modules/modes/select_note.js @@ -105,8 +105,11 @@ export function modeSelectNote(context, selectedNoteID) { selectNote(); - context.ui().sidebar - .show(noteEditor.note(note)); + var sidebar = context.ui().sidebar; + sidebar.show(noteEditor.note(note)); + + // expand the sidebar, avoid obscuring the note if needed + sidebar.expand(sidebar.intersects(note.extent())); context.map() .on('drawn.select', selectNote);