Skip to content

Commit

Permalink
Convert "Info Panels" -> "Info Cards", upgrade all to class components
Browse files Browse the repository at this point in the history
This includes:  Background, History, Measurement, Location

"Cards" is more the correct UI term for what these things are.
This converts them all to the newer way of organizing the UI code.

This was a tricky conversion because previously `uiInfo` managed much
 of the rendering and state for the card components
Now each component can stand alone and manage its own status.
  • Loading branch information
bhousel committed Nov 5, 2024
1 parent 6e33813 commit d7bcc5f
Show file tree
Hide file tree
Showing 20 changed files with 779 additions and 672 deletions.
166 changes: 84 additions & 82 deletions css/80_app.css
Original file line number Diff line number Diff line change
Expand Up @@ -4193,118 +4193,120 @@ li.issue-fix-item button:not(.actionable) .fix-icon {
}


/* Information Panels
/* Information Cards
------------------------------------------------------- */
.info-panels {
display: flex;
flex-flow: row wrap-reverse;
justify-content: flex-end;
width: 100%;
z-index: 10;
-ms-user-select: element;
pointer-events: none;
overflow: hidden;
}
.info-cards {
display: flex;
flex-flow: row wrap-reverse;
justify-content: flex-end;

.panel-container h1,
.panel-container h2,
.panel-container h3,
.panel-container h4,
.panel-container h5 {
display: inline-block;
margin-bottom: 0;
width: 100%;
z-index: 10;
-ms-user-select: element;
pointer-events: none;
overflow: hidden;
}

.panel-container h1,
.panel-container h2,
.panel-container h3 {
color: #ff8;
.card-container h1,
.card-container h2,
.card-container h3,
.card-container h4,
.card-container h5 {
display: inline-block;
margin-bottom: 0;
}

.panel-container {
flex: 0 0 auto;
margin: 0 2px 2px 0;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.75);
padding-bottom: 10px;
width: 250px;
max-width: 100%;
pointer-events: auto;
.card-container h1,
.card-container h2,
.card-container h3 {
color: #ff8;
}

.panel-container .panel-title {
border-radius: 4px 4px 0 0;
.card-container {
display: flex;
flex-flow: column nowrap;
flex: 0 0 auto;

margin: 0 2px 2px 0;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.75);
padding-bottom: 10px;
width: 240px;
pointer-events: auto;
}

.panel-title {
padding: 5px 10px;
display: flex;
justify-content: space-between;
.card-title {
display: flex;
justify-content: space-between;
align-items: center;

padding: 5px 10px;
border-radius: 4px 4px 0 0;
}

.panel-title button.close {
padding: 2px;
background: none;
color: #ddd;
.card-title button.close {
padding: 2px;
background: none;
color: #ddd;
}
.ideditor[dir='rtl'] .panel-title button.close {
float: left;
.ideditor[dir='rtl'] .card-title button.close {
float: left;
}
.panel-title button.close:focus,
.panel-title button.close:active {
color: #fff;
.card-title button.close:focus,
.card-title button.close:active {
color: #fff;
}
@media (hover: hover) {
.panel-title button.close:hover {
color: #fff;
}
.card-title button.close:hover {
color: #fff;
}
}
.panel-title button.close .icon {
height: 20px;
width: 16px;
.card-title button.close .icon {
height: 20px;
width: 16px;
}

.panel-content {
padding: 5px 10px;
position: relative;
.card-content {
padding: 5px 10px;
position: relative;
}

.panel-content ul:empty {
display: none;
.card-content ul:empty {
display: none;
}

.panel-content li span:not(.localized-text) {
display: inline-block;
white-space: nowrap;
margin: 0 8px;
.card-content li span:not(.localized-text) {
display: inline-block;
white-space: nowrap;
margin: 0 8px;
}

.panel-content .button {
display: inline-block;
background: #7092ff;
border-radius: 2px;
padding: 0 4px;
margin-top: 10px;
margin-right: 10px;
color: #fff;
.card-content .button {
display: inline-block;
background: #7092ff;
border-radius: 2px;
padding: 0 4px;
margin-top: 10px;
margin-right: 10px;
color: #fff;
}
.ideditor[dir='rtl'] .panel-content .button {
margin-right: auto;
margin-left: 10px;
.ideditor[dir='rtl'] .card-content .button {
margin-right: auto;
margin-left: 10px;
}

.panel-content-history .links a {
margin-left: 8px;
.card-content-history .links a {
margin-left: 8px;
}
.ideditor[dir='rtl'] .panel-content-history .links a {
margin-left: auto;
margin-right: 8px;
.ideditor[dir='rtl'] .card-content-history .links a {
margin-left: auto;
margin-right: 8px;
}
.panel-content-history h4 {
padding-bottom: 0;
.card-content-history h4 {
padding-bottom: 0;
}
.panel-content-location .location-info {
margin-top: 10px;
.card-content-location .location-info {
margin-top: 10px;
}


Expand Down Expand Up @@ -5225,7 +5227,7 @@ button.conflicts-button {
font-weight: bold;
}

/* dark tooltips for sidebar / panels */
/* dark tooltips */
.tooltip.dark.top .popover-arrow,
.map-pane .tooltip.top .popover-arrow,
.sidebar .tooltip.top .popover-arrow {
Expand Down
1 change: 0 additions & 1 deletion modules/core/GraphicsSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,6 @@ export class GraphicsSystem extends AbstractSystem {
immediateRedraw() {
this._timeToNextRender = 0; // asap
this._appPending = true;
this._drawPending = false;
}


Expand Down
6 changes: 3 additions & 3 deletions modules/core/UiSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class UiSystem extends AbstractSystem {

// These components live below in the tree, but we will hold a reference
// to them here in the UiSystem, so other code can find them easily.
this.Info = null;
this.InfoCards = null;
this.Minimap = null;
this.PhotoViewer = null;
this.Spector = null;
Expand Down Expand Up @@ -102,7 +102,7 @@ export class UiSystem extends AbstractSystem {

// These components live below in the tree, but we will hold a reference
// to them here in the UiSystem, so that other code can find them easily.
this.Info = this.Overmap.Info;
this.InfoCards = this.Overmap.InfoCards;
this.Minimap = this.Overmap.Minimap;
this.PhotoViewer = this.Overmap.PhotoViewer;
this.Spector = this.Overmap.Spector;
Expand Down Expand Up @@ -161,7 +161,7 @@ export class UiSystem extends AbstractSystem {
const map = context.systems.map;
const storage = context.systems.storage;
const urlhash = context.systems.urlhash;
const $container = this.context.container();
const $container = context.container();

if (!$container.size()) {
return Promise.reject(new Error('No container to render to.'));
Expand Down
2 changes: 1 addition & 1 deletion modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export * from './operations/index.js';
export * from './osm/index.js';
export * from './services/index.js';
export * from './svg/index.js';
export * from './ui/cards/index.js';
export * from './ui/fields/index.js';
export * from './ui/panels/index.js';
export * from './ui/panes/index.js';
export * from './ui/sections/index.js';
export * from './ui/settings/index.js';
Expand Down
123 changes: 123 additions & 0 deletions modules/ui/UiInfoCards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { selection } from 'd3-selection';

import { uiCmd } from './cmd.js';

import { UiBackgroundCard } from './cards/UiBackgroundCard.js';
import { UiHistoryCard } from './cards/UiHistoryCard.js';
import { UiLocationCard } from './cards/UiLocationCard.js';
import { UiMeasurementCard } from './cards/UiMeasurementCard.js';



/**
* UiInfoCards
* This component acts as the container for the information cards.
* "Cards" are user interface elements that can float on top of the map
* and provide extra information about the map or the selection.
*/
export class UiInfoCards {

/**
* @constructor
* @param `context` Global shared application context
*/
constructor(context) {
this.context = context;

this._wasVisible = new Set();

// Create child components
this.BackgroundCard = new UiBackgroundCard(context);
this.HistoryCard = new UiHistoryCard(context);
this.LocationCard = new UiLocationCard(context);
this.MeasurementCard = new UiMeasurementCard(context);

// Info Cards
this.cards = [
this.BackgroundCard,
this.HistoryCard,
this.LocationCard,
this.MeasurementCard
];

// D3 selections
this.$parent = null;

// Ensure methods used as callbacks always have `this` bound correctly.
// (This is also necessary when using `d3-selection.call`)
this.render = this.render.bind(this);
this.toggle = this.toggle.bind(this);

// bind ⌘I to show/hide all cards
const l10n = context.systems.l10n;
this.key = uiCmd('⌘' + l10n.t('info_panels.key'));
context.keybinding().on(this.key, this.toggle);
}


/**
* render
* Accepts a parent selection, and renders the content under it.
* (The parent selection is required the first time, but can be inferred on subsequent renders)
* @param {d3-selection} $parent - A d3-selection to a HTMLElement that this component should render itself into
*/
render($parent = this.$parent) {
if ($parent instanceof selection) {
this.$parent = $parent;
} else {
return; // no parent - called too early?
}

// .info-cards container
let $wrap = $parent.selectAll('.info-cards')
.data([0]);

const $$wrap = $wrap.enter()
.append('div')
.attr('class', 'info-cards');

$wrap = $wrap.merge($$wrap);

for (const Card of this.cards) {
$wrap.call(Card.render);
}
}


/**
* toggle
* Toggles all info cards on/off
* @param {Event} e - event that triggered the toggle (if any)
*/
toggle(e) {
if (e) e.preventDefault();

// Which cards are currently visible?
const currVisible = new Set();
for (const Card of this.cards) {
if (Card.visible) {
currVisible.add(Card);
}
}

// Some cards are shown - toggle them off
if (currVisible.size) {
this._wasVisible = currVisible;
for (const Card of currVisible) {
Card.hide(e);
}

// No cards are shown - toggle them on
} else {
if (!this._wasVisible.size) {
this._wasVisible.add(this.MeasurementCard); // at least 1 should be visible
}
for (const Card of this._wasVisible) {
Card.show(e);
}
}

this.render();
}

}
6 changes: 3 additions & 3 deletions modules/ui/UiMinimap.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ export class UiMinimap {
/**
* toggle
* Toggles the minimap on/off
* @param {Event} d3 keypress event that triggered the toggle (if any)
* @param {Event} e - event that triggered the toggle (if any)
*/
toggle(d3_event) {
if (d3_event) d3_event.preventDefault();
toggle(e) {
if (e) e.preventDefault();

const context = this.context;
const $wrap = this.$wrap;
Expand Down
Loading

0 comments on commit d7bcc5f

Please sign in to comment.