Refactor details panel to use React Semantic Components (#98)

This commit is contained in:
czifumasa
2022-04-27 17:20:27 +02:00
committed by GitHub
parent 35259e5767
commit d30c038406
4 changed files with 119 additions and 95 deletions

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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;

View File

@@ -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 {