all tags->filters

This commit is contained in:
Lachlan Kermode
2020-06-08 15:50:39 +02:00
parent 33bbb5d0aa
commit 16358f5ab9
22 changed files with 202 additions and 177 deletions

View File

@@ -4,7 +4,7 @@ import React from 'react'
import CardTime from './presentational/Card/Time'
import CardLocation from './presentational/Card/Location'
import CardCaret from './presentational/Card/Caret'
import CardTags from './presentational/Card/Tags'
import CardFilters from './presentational/Card/Filters'
import CardSummary from './presentational/Card/Summary'
import CardSource from './presentational/Card/Source'
import CardNarrative from './presentational/Card/Narrative'
@@ -38,13 +38,13 @@ class Card extends React.Component {
)
}
renderTags () {
if (!this.props.tags || (this.props.tags && this.props.tags.length === 0)) {
renderFilters () {
if (!this.props.filters || (this.props.filters && this.props.filters.length === 0)) {
return null
}
return (
<CardTags
tags={this.props.tags || []}
<CardFilters
filters={this.props.filters || []}
language={this.props.language}
/>
)
@@ -137,7 +137,7 @@ class Card extends React.Component {
renderExtra () {
return (
<div className='card-bottomhalf'>
{this.renderTags()}
{this.renderFilters()}
{this.renderSources()}
{this.renderNarrative()}
</div>

View File

@@ -104,7 +104,7 @@ class Dashboard extends React.Component {
setNarrative (narrative) {
// only handleSelect if narrative is not null
if (narrative) {
this.props.actions.clearFilter('tags')
this.props.actions.clearFilter('filters')
this.props.actions.clearFilter('categories')
this.handleSelect([ narrative.steps[0] ])
}
@@ -152,7 +152,7 @@ class Dashboard extends React.Component {
isNarrative={!!app.narrative}
methods={{
onTitle: actions.toggleCover,
onTagFilter: tag => actions.toggleFilter('tags', tag),
onSelectFilter: filter => actions.toggleFilter('filters', filter),
onCategoryFilter: category => actions.toggleFilter('categories', category),
onSelectNarrative: this.setNarrative
}}

View File

@@ -205,6 +205,7 @@ class Map extends React.Component {
return (
<Events
svg={this.svgRef.current}
events={this.props.domain.events}
locations={this.props.domain.locations}
styleLocation={this.styleLocation}
categories={this.props.domain.categories}

View File

@@ -14,7 +14,7 @@ export default ({
{categories.map(cat => {
return (<li
key={cat.category.replace(/ /g, '_')}
className={'tag-filter active'}
className={'filter-filter active'}
style={{ marginLeft: '20px' }}
>
<Checkbox

View File

@@ -10,10 +10,10 @@ function allAssociatedKeys (node) {
return childKeys
}
function TagListPanel ({
tags,
activeTags,
onTagFilter,
function FilterListPanel ({
filters,
activeFilters,
onSelectFilter,
language
}) {
function createNodeComponent (node, depth) {
@@ -22,21 +22,21 @@ function TagListPanel ({
return (
<li
key={node.key.replace(/ /g, '_')}
className={'tag-filter'}
className={'filter-filter'}
style={{ marginLeft: `${depth * 20}px` }}
>
{/* <svg width='10' height='10'> */}
{/* <g className='tag-inline'> */}
{/* <g className='filter-inline'> */}
{/* <path d='M0,-7.847549217020565L6.796176979388489,3.9237746085102825L-6.796176979388489,3.9237746085102825Z' transform='rotate(270)' /> */}
{/* </g> */}
{/* </svg> */}
<Checkbox
label={node.key}
isActive={activeTags.includes(node.key)}
onClickCheckbox={() => onTagFilter(matchingKeys)}
isActive={activeFilters.includes(node.key)}
onClickCheckbox={() => onSelectFilter(matchingKeys)}
/>
{children.length > 0
? children.map(tag => createNodeComponent(tag, depth + 1))
? children.map(filter => createNodeComponent(filter, depth + 1))
: null}
</li>
)
@@ -45,18 +45,18 @@ function TagListPanel ({
function renderTree (children) {
return (
<div>
{Object.values(children).map(tag => createNodeComponent(tag, 1))}
{Object.values(children).map(filter => createNodeComponent(filter, 1))}
</div>
)
}
return (
<div className='react-innertabpanel'>
<h2>{copy[language].toolbar.tags}</h2>
<p>{copy[language].toolbar.explore_by_tag__description}</p>
{renderTree(tags.children)}
<h2>{copy[language].toolbar.filters}</h2>
<p>{copy[language].toolbar.explore_by_filter__description}</p>
{renderTree(filters.children)}
</div>
)
}
export default TagListPanel
export default FilterListPanel

View File

@@ -6,7 +6,7 @@ import * as selectors from '../../selectors'
import { Tabs, TabPanel } from 'react-tabs'
import Search from './Search'
import TagListPanel from './TagListPanel'
import FilterListPanel from './FilterListPanel'
import CategoriesListPanel from './CategoriesListPanel'
import BottomActions from './BottomActions'
import copy from '../../common/data/copy.json'
@@ -37,9 +37,9 @@ class Toolbar extends React.Component {
<TabPanel>
<Search
language={this.props.language}
tags={this.props.tags}
filters={this.props.filters}
categories={this.props.categories}
tagFilters={this.props.tagFilters}
filterFilters={this.props.filterFilters}
categoryFilters={this.props.categoryFilters}
filter={this.props.filter}
/>
@@ -73,7 +73,7 @@ class Toolbar extends React.Component {
}
renderToolbarCategoriesPanel () {
if (this.props.features.CATEGORIES_AS_TAGS) {
if (this.props.features.CATEGORIES_AS_FILTERS) {
return (
<TabPanel>
<CategoriesListPanel
@@ -90,10 +90,10 @@ class Toolbar extends React.Component {
renderToolbarFilterPanel () {
return (
<TabPanel>
<TagListPanel
tags={this.props.tags}
activeTags={this.props.activeTags}
onTagFilter={this.props.methods.onTagFilter}
<FilterListPanel
filters={this.props.filters}
activeFilters={this.props.activeFilters}
onSelectFilter={this.props.methods.onSelectFilter}
language={this.props.language}
/>
</TabPanel>
@@ -120,7 +120,7 @@ class Toolbar extends React.Component {
{this.renderClosePanel()}
<Tabs selectedIndex={this.state._selected}>
{features.USE_NARRATIVES ? this.renderToolbarNarrativePanel() : null}
{features.CATEGORIES_AS_TAGS ? this.renderToolbarCategoriesPanel() : null}
{features.CATEGORIES_AS_FILTERS ? this.renderToolbarCategoriesPanel() : null}
{features.USE_FILTERS ? this.renderToolbarFilterPanel() : null}
</Tabs>
</div>
@@ -149,7 +149,7 @@ class Toolbar extends React.Component {
let title = copy[this.props.language].toolbar.title
if (process.env.display_title) title = process.env.display_title
const narrativesLabel = copy[this.props.language].toolbar.narratives_label
const tagsLabel = copy[this.props.language].toolbar.tags_label
const filtersLabel = copy[this.props.language].toolbar.filters_label
const categoriesLabel = 'Categories' // TODO:
return (
@@ -157,8 +157,8 @@ class Toolbar extends React.Component {
<div className='toolbar-header'onClick={this.props.methods.onTitle}><p>{title}</p></div>
<div className='toolbar-tabs'>
{features.USE_NARRATIVES ? this.renderToolbarTab(0, narrativesLabel, 'timeline') : null}
{features.CATEGORIES_AS_TAGS ? this.renderToolbarTab(1, categoriesLabel, 'widgets') : null}
{features.USE_FILTERS ? this.renderToolbarTab(2, tagsLabel, 'filter_list') : null}
{features.CATEGORIES_AS_FILTERS ? this.renderToolbarTab(1, categoriesLabel, 'widgets') : null}
{features.USE_FILTERS ? this.renderToolbarTab(features.CATEGORIES_AS_FILTERS ? 2 : 1, filtersLabel, 'filter_list') : null}
</div>
<BottomActions
info={{
@@ -192,11 +192,11 @@ class Toolbar extends React.Component {
function mapStateToProps (state) {
return {
tags: selectors.getTagTree(state),
filters: selectors.getFilterTree(state),
categories: selectors.getCategories(state),
narratives: selectors.selectNarratives(state),
language: state.app.language,
activeTags: selectors.getActiveTags(state),
activeFilters: selectors.getActiveFilters(state),
activeCategories: selectors.getActiveCategories(state),
viewFilters: state.app.filters.views,
narrative: state.app.narrative,

View File

@@ -1,7 +1,7 @@
/* global fetch */
import React from 'react'
import copy from '../../common/data/copy.json'
import TagFilter from './TagFilter'
import SelectFilter from './SelectFilter'
export default class Search extends React.Component {
constructor (props) {
@@ -21,7 +21,7 @@ export default class Search extends React.Component {
.then(response => response.json())
.then(json => {
this.setState({
searchResults: json.tags
searchResults: json.filters
})
})
}
@@ -32,16 +32,16 @@ export default class Search extends React.Component {
renderSearchResults () {
return (
this.state.searchResults.map(tag => {
this.state.searchResults.map(filter => {
return (
<TagFilter
<SelectFilter
isShowTree
tags={this.props.tags}
filters={this.props.filters}
categories={this.props.categories}
tagFilters={this.props.tagFilters}
filterFilters={this.props.filterFilters}
categoryFilters={this.props.categoryFilters}
filter={this.props.filter}
tag={tag}
filter={filter}
isCategory={this.props.isCategory}
/>
)

View File

@@ -1,22 +1,22 @@
import React from 'react'
import Checkbox from '../presentational/Checkbox'
function TagFilter (props) {
function SelectFilter (props) {
function isActive () {
if (props.isCategory) {
return props.categoryFilters.includes(props.tag.id)
return props.categoryFilters.includes(props.filter.id)
}
return props.tagFilters.includes(props.tag.id)
return props.filterFilters.includes(props.filter.id)
}
function onClickTag () {
function onClickFilter () {
if (isActive()) {
props.filter({
tags: props.tagFilters.filter(element => element !== props.tag.id)
filters: props.filterFilters.filter(element => element !== props.filter.id)
})
} else {
props.filter({
tags: props.tagFilters.concat(props.tag.id)
filters: props.filterFilters.concat(props.filter.id)
})
}
}
@@ -24,44 +24,44 @@ function TagFilter (props) {
function onClickCategory () {
if (isActive()) {
props.filter({
categories: props.categoryFilters.filter(element => element !== props.tag.id)
categories: props.categoryFilters.filter(element => element !== props.filter.id)
})
} else {
props.filter({
categories: props.categoryFilters.concat(props.tag.id)
categories: props.categoryFilters.concat(props.filter.id)
})
}
}
function renderTag () {
const tag = props.tag
let classes = (isActive()) ? 'tag-filter active' : 'tag-filter'
let label = `${tag.name} ( ${tag.mentions} )`
function renderFilter () {
const filter = props.filter
let classes = (isActive()) ? 'filter-filter active' : 'filter-filter'
let label = `${filter.name} ( ${filter.mentions} )`
if (props.isShowTree) {
label = `${tag.group} > ${tag.subgroup} > ${tag.name} ( ${tag.mentions} )`
label = `${filter.group} > ${filter.subgroup} > ${filter.name} ( ${filter.mentions} )`
}
return (
<li
key={props.tag.id}
key={props.filter.id}
className={classes}
>
<Checkbox
isActive={isActive()}
label={label}
onClickCheckbox={() => onClickTag()}
onClickCheckbox={() => onClickFilter()}
/>
</li>
)
}
function renderCategory () {
const category = props.categories[props.tag.id]
let classes = (isActive()) ? 'tag-filter active' : 'tag-filter'
const category = props.categories[props.filter.id]
let classes = (isActive()) ? 'filter-filter active' : 'filter-filter'
if (category) {
return (
<li
key={props.tag.id}
key={props.filter.id}
className={classes}
>
<Checkbox
@@ -76,7 +76,7 @@ function TagFilter (props) {
}
if (props.isCategory) return (renderCategory())
return (renderTag())
return (renderFilter())
}
export default TagFilter
export default SelectFilter

View File

@@ -0,0 +1,36 @@
import React from 'react'
import copy from '../../../common/data/copy.json'
const CardFilters = ({ filters, language }) => {
const filtersLang = copy[language].cardstack.filters
const noFiltersLang = copy[language].cardstack.nofilters
if (filters.length > 0) {
return (
<div className='card-row card-cell filters'>
<h4>{filtersLang}:</h4>
<p>
{filters.map((filter, idx) => {
return (
<span className='filter'>
<small>{filter.name}</small>
{(idx < filters.length - 1)
? ','
: ''}
</span>
)
})}
</p>
</div>
)
}
return (
<div className='card-row card-cell filters'>
<h4>{filtersLang}</h4>
<p><small>{noFiltersLang}</small></p>
</div>
)
}
export default CardFilters

View File

@@ -1,36 +0,0 @@
import React from 'react'
import copy from '../../../common/data/copy.json'
const CardTags = ({ tags, language }) => {
const tagsLang = copy[language].cardstack.tags
const noTagsLang = copy[language].cardstack.notags
if (tags.length > 0) {
return (
<div className='card-row card-cell tags'>
<h4>{tagsLang}:</h4>
<p>
{tags.map((tag, idx) => {
return (
<span className='tag'>
<small>{tag.name}</small>
{(idx < tags.length - 1)
? ','
: ''}
</span>
)
})}
</p>
</div>
)
}
return (
<div className='card-row card-cell tags'>
<h4>{tagsLang}</h4>
<p><small>{noTagsLang}</small></p>
</div>
)
}
export default CardTags

View File

@@ -3,7 +3,17 @@ import { Portal } from 'react-portal'
import colors from '../../../common/global.js'
import { calcOpacity } from '../../../common/utilities'
function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation, selected, narrative, onSelect, svg, locations }) {
function MapEvents ({
getCategoryColor,
categories,
projectPoint,
styleLocation,
selected,
narrative,
onSelect,
svg,
locations
}) {
function getCoordinatesForPercent (radius, percent) {
const x = radius * Math.cos(2 * Math.PI * percent)
const y = radius * Math.sin(2 * Math.PI * percent)
@@ -38,7 +48,7 @@ function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation,
...extraStyles
})
const colorSlices = location.events.map(e => getCategoryColor(e.category))
const colorSlices = location.events.map(e => e.colour ? e.colour : getCategoryColor(e.category))
let cumulativeAngleSweep = 0

View File

@@ -109,7 +109,7 @@ const TimelineEvents = ({
y: eventY,
onSelect: () => onSelect(event),
dims,
highlights: features.HIGHLIGHT_GROUPS ? getHighlights(event.tags[features.HIGHLIGHT_GROUPS.tagIndexIndicatingGroup]) : [],
highlights: features.HIGHLIGHT_GROUPS ? getHighlights(event.filters[features.HIGHLIGHT_GROUPS.filterIndexIndicatingGroup]) : [],
features
})
}