significantly refactor presentational components

This commit is contained in:
Lachlan Kermode
2019-01-18 11:51:00 +00:00
parent f561064e6c
commit e7cac13fb5
34 changed files with 103 additions and 150 deletions

BIN
src/components/presentational/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { capitalizeFirstLetter } from '../../js/utilities.js';
import { capitalizeFirstLetter } from '../../../js/utilities.js';
const CardCategory = ({ categoryTitle, categoryLabel, color }) => (
<div className="card-row card-cell category">

View File

@@ -1,7 +1,7 @@
import React from 'react';
import copy from '../../js/data/copy.json';
import { isNotNullNorUndefined } from '../../js/utilities';
import copy from '../../../js/data/copy.json';
import { isNotNullNorUndefined } from '../../../js/utilities';
const CardLocation = ({ language, location }) => {

View File

@@ -1,6 +1,6 @@
import React from 'react';
import CardNarrativeLink from './CardNarrativeLink';
import CardNarrativeLink from './NarrativeLink';
const CardNarrative = (props) => (
<div className="card-row">

View File

@@ -1,9 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import Spinner from './Spinner'
import Img from 'react-image'
import copy from '../../js/data/copy.json'
import Spinner from '../Spinner'
import copy from '../../../js/data/copy.json'
const CardSource = ({ source, isLoading, onClickHandler }) => {
function renderIconText(type) {

View File

@@ -1,6 +1,6 @@
import React from 'react';
import copy from '../../js/data/copy.json';
import copy from '../../../js/data/copy.json';
const CardSummary = ({ language, description, isHighlighted }) => {

View File

@@ -1,6 +1,6 @@
import React from 'react';
import copy from '../../js/data/copy.json';
import copy from '../../../js/data/copy.json';
const CardTags = ({ tags, language }) => {
const tags_lang = copy[language].cardstack.tags;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import copy from '../../js/data/copy.json';
import { isNotNullNorUndefined } from '../../js/utilities';
import copy from '../../../js/data/copy.json';
import { isNotNullNorUndefined } from '../../../js/utilities';
const CardTimestamp = ({ makeTimelabel, language, timestamp }) => {

View File

@@ -0,0 +1,14 @@
import React from 'react';
const MapDefsMarkers = ({}) => (
<defs>
<marker id="arrow" viewBox="0 0 6 6" refX="3" refY="3" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,3v-3l6,3l-6,3z" style={{ fill: 'red' }}></path>
</marker>
<marker id="arrow-off" viewBox="0 0 6 6" refX="3" refY="3" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,3v-3l6,3l-6,3z" style={{ fill: 'black', fillOpacity: 0.2 }}></path>
</marker>
</defs>
);
export default MapDefsMarkers;

View File

@@ -0,0 +1,78 @@
import React from 'react';
import { Portal } from 'react-portal';
function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation, narrative, onSelect, svg, locations }){
function getLocationEventsDistribution(location) {
const eventCount = {};
const categories = categories;
categories.forEach(cat => {
eventCount[cat.category] = [];
});
location.events.forEach((event) => {;
eventCount[event.category].push(event);
});
return eventCount;
}
function renderLocation(location) {
/**
{
events: [...],
label: 'Location name',
latitude: '47.7',
longitude: '32.2'
}
*/
const { x, y } = projectPoint([location.latitude, location.longitude]);
// const eventsByCategory = getLocationEventsDistribution(location);
const locCategory = location.events.length > 0 ? location.events[0].category : 'default'
const customStyles = styleLocation ? styleLocation(location) : null
const extraStyles = customStyles[0]
const extraRender = customStyles[1]
const styles = ({
fill: getCategoryColor(locCategory),
fillOpacity: 1,
...customStyles[0]
})
// in narrative mode, only render events in narrative
if (narrative) {
const { steps } = narrative
const onlyIfInNarrative = e => steps.map(s => s.id).includes(e.id)
const eventsInNarrative = location.events.filter(onlyIfInNarrative)
if (eventsInNarrative.length <= 0) {
return null
}
}
return (
<g
className="location"
transform={`translate(${x}, ${y})`}
onClick={() => onSelect(location.events)}
>
<circle
className="location-event-marker"
r={7}
style={styles}
>
</circle>
{extraRender ? extraRender() : null}
</g>
)
}
return (
<Portal node={svg}>
{locations.map(renderLocation)}
</Portal>
);
}
export default MapEvents;

View File

@@ -0,0 +1,106 @@
import React from 'react'
import { Portal } from 'react-portal'
function MapNarratives ({ narrativeProps, onSelectNarrative, svg, narrative, narratives, projectPoint }) {
function getNarrativeStyle(narrativeId) {
const styleName = (narrativeId && narrativeId in narrativeProps)
? narrativeId
: 'default'
return narrativeProps[styleName]
}
function getStepStyle(name) {
if (name === 'None') return null
return narrativeProps.stepStyles[name]
}
function hasNoLocation(step) {
return (step.latitude === '' || step.longitude === '')
}
function renderNarrativeStep(idx, n) {
const step = n.steps[idx]
const step2 = n.steps[idx + 1]
// don't draw if one of the steps has no location
if (hasNoLocation(step) || hasNoLocation(step2))
return null
// 0 if not in narrative mode, 1 if active narrative, 0.1 if inactive
let styles = {
strokeOpacity: (n === null) ? 0
: (step && (n.id === narrative.id)) ? 1 : 0.1,
strokeWidth: 0,
strokeDasharray: 'none',
stroke: 'none'
}
const p1 = projectPoint([step.latitude, step.longitude])
const p2 = projectPoint([step2.latitude, step2.longitude])
if (step) {
if (process.env.features.NARRATIVE_STEP_STYLES) {
const _idx = step.narratives.indexOf(n.id)
const stepStyle = step.narrative___stepStyles[_idx]
return _renderNarrativeStep(
p1,
p2,
{ ...styles, ...getStepStyle(stepStyle) }
)
// otherwise steps are styled per narrative
} else {
styles = {
...styles,
...getNarrativeStyle(n.id)
}
return _renderNarrativeStep(p1,p2,styles)
}
}
}
function _renderNarrativeStep(p1, p2, styles) {
const { stroke, strokeWidth, strokeDasharray, strokeOpacity } = styles
return (
<line
className="narrative-step"
x1={p1.x}
x2={p2.x}
y1={p1.y}
y2={p2.y}
markerStart="none"
onClick={() => onSelectNarrative(n)}
style={{
strokeWidth,
strokeDasharray,
strokeOpacity,
stroke,
}}
>
</line>
)
}
function renderNarrative(n) {
const steps = n.steps.slice(0, n.steps.length - 1)
return (
<g id={`narrative-${n.id.replace(/ /g,"_")}`} className="narrative">
{steps.map((s, idx) => renderNarrativeStep(idx, n))}
</g>
)
}
if (narrative === null) return (<div />)
return (
<Portal node={svg}>
{narratives.map(n => renderNarrative(n))}
</Portal>
)
}
export default MapNarratives

View File

@@ -0,0 +1,36 @@
import React from 'react';
import { Portal } from 'react-portal';
class MapSelectedEvents extends React.Component {
renderMarker (event) {
const { x, y } = this.props.projectPoint([event.latitude, event.longitude]);
return (
<g
className="location-marker"
transform={`translate(${x - 32}, ${y})`}
>
<path
className="leaflet-interactive"
stroke="#ffffff"
stroke-opacity="1"
stroke-width="3"
stroke-linecap=""
stroke-linejoin="round"
stroke-dasharray="5,2"
fill="none"
d="M0,0a32,32 0 1,0 64,0 a32,32 0 1,0 -64,0 "
>
</path>
</g>
);
}
render() {
return (
<Portal node={this.props.svg}>
{this.props.selected.map(s => this.renderMarker(s))}
</Portal>
)
}
}
export default MapSelectedEvents;

View File

@@ -0,0 +1,48 @@
import React from 'react'
import { Portal } from 'react-portal'
function MapShapes({ svg, shapes, projectPoint }) {
function renderShape(shape, lineStyle) {
const lineCoords = []
const points = shape.points
.map(projectPoint)
points.forEach((p1, idx) => {
if (idx < shape.points.length - 1) {
const p2 = points[idx+1]
lineCoords.push({
x1: p1.x,
y1: p1.y,
x2: p2.x,
y2: p2.y
})
}
})
return lineCoords.map(coords => (
<line
className={shape.name}
markerStart="none"
{...coords}
style={lineStyle}
>
</line>
))
}
if (!shapes || !shapes.length) return null
return (
<Portal node={svg}>
<g id={`shapes-layer`} className="narrative">
{shapes.map(s => renderShape(s, {
strokeWidth: 3,
stroke: 'blue'
}))}
</g>
</Portal>
)
}
export default MapShapes

View File

@@ -0,0 +1,25 @@
import React from 'react';
function MapSites({ sites, projectPoint }) {
function renderSite(site) {
const { x, y } = projectPoint([site.latitude, site.longitude]);
return (<div
className="leaflet-tooltip site-label leaflet-zoom-animated leaflet-tooltip-top"
style={{ opacity: 1, transform: `translate3d(calc(${x}px - 50%), ${y - 25}px, 0px)`}}>
{site.site}
</div>
);
}
if (!sites || !sites.length) return null;
return (
<div className="sites-layer">
{sites.map(renderSite)}
</div>
)
}
export default MapSites;

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { connect } from 'react-redux'
import { selectActiveNarrative } from '../../selectors'
import { selectActiveNarrative } from '../../../selectors'
function NarrativeCard ({ narrative }) {
// no display if no narrative

View File

@@ -1,7 +1,7 @@
import React from 'react'
import NarrativeCard from './NarrativeCard'
import NarrativeAdjust from './NarrativeAdjust'
import NarrativeClose from './NarrativeClose'
import Card from './Card'
import Adjust from './Adjust'
import Close from './Close'
export default ({ narrative, methods }) => {
if (!narrative) return null
@@ -12,18 +12,18 @@ export default ({ narrative, methods }) => {
return (
<React.Fragment>
<NarrativeCard narrative={narrative} />
<NarrativeAdjust
<Card narrative={narrative} />
<Adjust
isDisabled={!prevExists}
direction='left'
onClickHandler={methods.onPrev}
/>
<NarrativeAdjust
<Adjust
isDisabled={!nextExists}
direction='right'
onClickHandler={methods.onNext}
/>
<NarrativeClose
<Close
onClickHandler={() => methods.onSelectNarrative(null)}
closeMsg='-- exit from narrative --'
/>

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { formatterWithYear } from '../../js/utilities.js';
import { formatterWithYear } from '../../../js/utilities.js';
const TimelineLabels = ({ dims, timelabels }) => {