mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-04-20 21:46:17 +00:00
Refactor details panel to use React Semantic Components (#98)
This commit is contained in:
124
src/config.tsx
124
src/config.tsx
@@ -1,4 +1,4 @@
|
||||
import {Checkbox, Form} from 'semantic-ui-react';
|
||||
import {Item, Checkbox, Form, Header} from 'semantic-ui-react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {ParsedQuery} from 'query-string';
|
||||
|
||||
@@ -44,64 +44,68 @@ export function ConfigPanel(props: {
|
||||
onChange: (config: Config) => void;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<Form className="ui segments details">
|
||||
<div className="ui segment">
|
||||
<div className="ui sub header">
|
||||
<FormattedMessage id="config.colors" defaultMessage="Colors" />
|
||||
</div>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.NO_COLOR"
|
||||
defaultMessage="none"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="none"
|
||||
checked={props.config.color === ChartColors.NO_COLOR}
|
||||
onClick={() => props.onChange({color: ChartColors.NO_COLOR})}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_GENERATION"
|
||||
defaultMessage="by generation"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="generation"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_GENERATION}
|
||||
onClick={() =>
|
||||
props.onChange({color: ChartColors.COLOR_BY_GENERATION})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_SEX"
|
||||
defaultMessage="by sex"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="gender"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_SEX}
|
||||
onClick={() => props.onChange({color: ChartColors.COLOR_BY_SEX})}
|
||||
/>
|
||||
</Form.Field>
|
||||
</div>
|
||||
</Form>
|
||||
</>
|
||||
<Form className="details">
|
||||
<Item.Group>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.colors" defaultMessage="Colors" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.NO_COLOR"
|
||||
defaultMessage="none"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="none"
|
||||
checked={props.config.color === ChartColors.NO_COLOR}
|
||||
onClick={() => props.onChange({color: ChartColors.NO_COLOR})}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_GENERATION"
|
||||
defaultMessage="by generation"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="generation"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_GENERATION}
|
||||
onClick={() =>
|
||||
props.onChange({color: ChartColors.COLOR_BY_GENERATION})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_SEX"
|
||||
defaultMessage="by sex"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="gender"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_SEX}
|
||||
onClick={() =>
|
||||
props.onChange({color: ChartColors.COLOR_BY_SEX})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
</Item.Group>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Events} from './events';
|
||||
import {GedcomEntry} from 'parse-gedcom';
|
||||
import {MultilineText} from './multiline-text';
|
||||
import {TranslatedTag} from './translated-tag';
|
||||
import {Header, Item} from 'semantic-ui-react';
|
||||
|
||||
const EXCLUDED_TAGS = [
|
||||
'BIRT',
|
||||
@@ -36,9 +37,9 @@ function dataDetails(entry: GedcomEntry) {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="ui sub header">
|
||||
<Header sub>
|
||||
<TranslatedTag tag={entry.tag} />
|
||||
</div>
|
||||
</Header>
|
||||
<span>
|
||||
<MultilineText lines={lines} />
|
||||
</span>
|
||||
@@ -58,7 +59,7 @@ function noteDetails(entry: GedcomEntry) {
|
||||
|
||||
function nameDetails(entry: GedcomEntry) {
|
||||
return (
|
||||
<h2 className="ui header">
|
||||
<Header size="large">
|
||||
{entry.data
|
||||
.split('/')
|
||||
.filter((name) => !!name)
|
||||
@@ -68,7 +69,7 @@ function nameDetails(entry: GedcomEntry) {
|
||||
<br />
|
||||
</div>
|
||||
))}
|
||||
</h2>
|
||||
</Header>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,9 +85,9 @@ function getDetails(
|
||||
)
|
||||
.filter((element) => element !== null)
|
||||
.map((element, index) => (
|
||||
<div className="ui segment" key={index}>
|
||||
{element}
|
||||
</div>
|
||||
<Item key={index}>
|
||||
<Item.Content>{element}</Item.Content>
|
||||
</Item>
|
||||
));
|
||||
}
|
||||
|
||||
@@ -106,9 +107,9 @@ function getOtherDetails(entries: GedcomEntry[]) {
|
||||
.map((entry) => dataDetails(entry))
|
||||
.filter((element) => element !== null)
|
||||
.map((element, index) => (
|
||||
<div className="ui segment" key={index}>
|
||||
{element}
|
||||
</div>
|
||||
<Item key={index}>
|
||||
<Item.Content>{element}</Item.Content>
|
||||
</Item>
|
||||
));
|
||||
}
|
||||
|
||||
@@ -124,11 +125,13 @@ export function Details(props: Props) {
|
||||
.filter(hasData);
|
||||
|
||||
return (
|
||||
<div className="ui segments details">
|
||||
{getDetails(entries, ['NAME'], nameDetails)}
|
||||
<Events gedcom={props.gedcom} entries={entries} indi={props.indi} />
|
||||
{getOtherDetails(entriesWithData)}
|
||||
{getDetails(entriesWithData, ['NOTE'], noteDetails)}
|
||||
<div className="details">
|
||||
<Item.Group divided>
|
||||
{getDetails(entries, ['NAME'], nameDetails)}
|
||||
<Events gedcom={props.gedcom} entries={entries} indi={props.indi} />
|
||||
{getOtherDetails(entriesWithData)}
|
||||
{getDetails(entriesWithData, ['NOTE'], noteDetails)}
|
||||
</Item.Group>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {Link, useLocation} from 'react-router-dom';
|
||||
import {MultilineText} from './multiline-text';
|
||||
import {pointerToId} from '../util/gedcom_util';
|
||||
import {TranslatedTag} from './translated-tag';
|
||||
import {Header, Item} from 'semantic-ui-react';
|
||||
|
||||
function PersonLink(props: {person: GedcomEntry}) {
|
||||
const location = useLocation();
|
||||
@@ -23,11 +24,11 @@ function PersonLink(props: {person: GedcomEntry}) {
|
||||
search['indi'] = pointerToId(props.person.pointer);
|
||||
|
||||
return (
|
||||
<div className="meta">
|
||||
<Item.Meta>
|
||||
<Link to={{pathname: '/view', search: queryString.stringify(search)}}>
|
||||
{name}
|
||||
</Link>
|
||||
</div>
|
||||
</Item.Meta>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,14 +63,14 @@ const FAMILY_EVENT_TAGS = ['MARR', 'DIV'];
|
||||
function EventHeader(props: {event: EventData}) {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<div>
|
||||
<span style={{textTransform: 'uppercase'}} className="ui small header">
|
||||
<div className="event-header">
|
||||
<Header as="span" size="small">
|
||||
<TranslatedTag tag={props.event.type} />
|
||||
</span>
|
||||
</Header>
|
||||
{props.event.date ? (
|
||||
<span className="ui sub header right floated">
|
||||
<Header as="span" textAlign="right" sub>
|
||||
{formatDateOrRange(props.event.date, intl)}
|
||||
</span>
|
||||
</Header>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
@@ -176,18 +177,18 @@ function toFamilyEvents(
|
||||
|
||||
function Event(props: {event: EventData}) {
|
||||
return (
|
||||
<div className="ui attached item">
|
||||
<div className="content">
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<EventHeader event={props.event} />
|
||||
{!!props.event.age && <div className="meta">{props.event.age}</div>}
|
||||
{!!props.event.age && <Item.Meta>{props.event.age}</Item.Meta>}
|
||||
{!!props.event.personLink && (
|
||||
<PersonLink person={props.event.personLink} />
|
||||
)}
|
||||
{!!props.event.place && (
|
||||
<div className="description">{props.event.place}</div>
|
||||
<Item.Description>{props.event.place}</Item.Description>
|
||||
)}
|
||||
{!!props.event.notes.length && (
|
||||
<div className="description">
|
||||
<Item.Description>
|
||||
{props.event.notes.map((note, index) => (
|
||||
<div key={index}>
|
||||
<MultilineText
|
||||
@@ -197,10 +198,10 @@ function Event(props: {event: EventData}) {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Item.Description>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -216,11 +217,11 @@ export function Events(props: Props) {
|
||||
);
|
||||
if (events.length) {
|
||||
return (
|
||||
<div className="ui segment divided items">
|
||||
<>
|
||||
{events.map((event, index) => (
|
||||
<Event event={event} key={index} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -143,9 +143,25 @@ div.zoom {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.ui.segments.details {
|
||||
margin: 0px !important;
|
||||
border: 0px !important;
|
||||
.details {
|
||||
padding: 15px 0px;
|
||||
border-bottom: 1px solid rgba(34,36,38,.15);
|
||||
}
|
||||
|
||||
.details .ui.items .item .content {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.details .event-header {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.details .event-header .header {
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
min-width: 40%;
|
||||
}
|
||||
|
||||
.ui.form .field.no-margin {
|
||||
|
||||
Reference in New Issue
Block a user