mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-04-11 00:56:16 +00:00
Added settings tab with color settings (#6)
This commit is contained in:
6
CHANGELOG.md
Normal file
6
CHANGELOG.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2021-10-25
|
||||||
|
|
||||||
|
- Added "Settings" tab in side panel
|
||||||
|
- Added color settings (none, by generation, by sex)
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -17408,9 +17408,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"topola": {
|
"topola": {
|
||||||
"version": "3.3.6",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/topola/-/topola-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/topola/-/topola-3.5.0.tgz",
|
||||||
"integrity": "sha512-ZsmJz17htEBOrIo3aKHe7i4aM+Xl8XBHRXL3P7FpKHsyd8LrsuiNLjOVNMhW2qApk6TeMmhyU4OXq9cq0zNv0w==",
|
"integrity": "sha512-w3PSG3nKgNpH3+ZiIzB5nTHaIj/mk+rVbtbQoLq9O6V2M4dBJGd+eiuUZ4BsNjbFeUR0iJ8zMYBegVRHHSg8fA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"array-flat-polyfill": "^1.0.1",
|
"array-flat-polyfill": "^1.0.1",
|
||||||
"d3-array": "^2.12.1",
|
"d3-array": "^2.12.1",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"semantic-ui-css": "^2.4.1",
|
"semantic-ui-css": "^2.4.1",
|
||||||
"semantic-ui-react": "^2.0.3",
|
"semantic-ui-react": "^2.0.3",
|
||||||
"topola": "^3.3.6"
|
"topola": "^3.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/array.prototype.flatmap": "^1.2.2",
|
"@types/array.prototype.flatmap": "^1.2.2",
|
||||||
|
|||||||
78
src/app.tsx
78
src/app.tsx
@@ -1,16 +1,23 @@
|
|||||||
import * as H from 'history';
|
import * as H from 'history';
|
||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
import * as React from 'react';
|
import React from 'react';
|
||||||
import {analyticsEvent} from './util/analytics';
|
import {analyticsEvent} from './util/analytics';
|
||||||
import {Chart, ChartComponent, ChartType} from './chart';
|
import {Chart, ChartComponent, ChartType} from './chart';
|
||||||
|
import {
|
||||||
|
argsToConfig,
|
||||||
|
Config,
|
||||||
|
ConfigPanel,
|
||||||
|
configToArgs,
|
||||||
|
DEFALUT_CONFIG,
|
||||||
|
} from './config';
|
||||||
import {DataSourceEnum, SourceSelection} from './datasource/data_source';
|
import {DataSourceEnum, SourceSelection} from './datasource/data_source';
|
||||||
import {Details} from './details';
|
import {Details} from './details';
|
||||||
import {EmbeddedDataSource, EmbeddedSourceSpec} from './datasource/embedded';
|
import {EmbeddedDataSource, EmbeddedSourceSpec} from './datasource/embedded';
|
||||||
import {FormattedMessage, WrappedComponentProps, injectIntl} from 'react-intl';
|
import {FormattedMessage, injectIntl, WrappedComponentProps} from 'react-intl';
|
||||||
import {getI18nMessage} from './util/error_i18n';
|
import {getI18nMessage} from './util/error_i18n';
|
||||||
import {IndiInfo} from 'topola';
|
import {IndiInfo} from 'topola';
|
||||||
import {Intro} from './intro';
|
import {Intro} from './intro';
|
||||||
import {Loader, Message, Portal} from 'semantic-ui-react';
|
import {Loader, Message, Portal, Tab} from 'semantic-ui-react';
|
||||||
import {Media} from './util/media';
|
import {Media} from './util/media';
|
||||||
import {Redirect, Route, RouteComponentProps, Switch} from 'react-router-dom';
|
import {Redirect, Route, RouteComponentProps, Switch} from 'react-router-dom';
|
||||||
import {TopBar} from './menu/top_bar';
|
import {TopBar} from './menu/top_bar';
|
||||||
@@ -80,7 +87,10 @@ type DataSourceSpec =
|
|||||||
| WikiTreeSourceSpec
|
| WikiTreeSourceSpec
|
||||||
| EmbeddedSourceSpec;
|
| EmbeddedSourceSpec;
|
||||||
|
|
||||||
/** Arguments passed to the application, primarily through URL parameters. */
|
/**
|
||||||
|
* Arguments passed to the application, primarily through URL parameters.
|
||||||
|
* Non-optional arguments get populated with default values.
|
||||||
|
*/
|
||||||
interface Arguments {
|
interface Arguments {
|
||||||
sourceSpec?: DataSourceSpec;
|
sourceSpec?: DataSourceSpec;
|
||||||
selection?: IndiInfo;
|
selection?: IndiInfo;
|
||||||
@@ -88,6 +98,7 @@ interface Arguments {
|
|||||||
standalone: boolean;
|
standalone: boolean;
|
||||||
freezeAnimation?: boolean;
|
freezeAnimation?: boolean;
|
||||||
showSidePanel: boolean;
|
showSidePanel: boolean;
|
||||||
|
config: Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,6 +159,7 @@ function getArguments(location: H.Location<any>): Arguments {
|
|||||||
showSidePanel: getParam('sidePanel') !== 'false', // True by default.
|
showSidePanel: getParam('sidePanel') !== 'false', // True by default.
|
||||||
standalone: getParam('standalone') !== 'false' && !embedded,
|
standalone: getParam('standalone') !== 'false' && !embedded,
|
||||||
freezeAnimation: getParam('freeze') === 'true', // False by default
|
freezeAnimation: getParam('freeze') === 'true', // False by default
|
||||||
|
config: argsToConfig(search),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +197,7 @@ interface State {
|
|||||||
sourceSpec?: DataSourceSpec;
|
sourceSpec?: DataSourceSpec;
|
||||||
/** Freeze animations after initial chart render. */
|
/** Freeze animations after initial chart render. */
|
||||||
freezeAnimation?: boolean;
|
freezeAnimation?: boolean;
|
||||||
|
config: Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppComponent extends React.Component<
|
class AppComponent extends React.Component<
|
||||||
@@ -196,6 +209,7 @@ class AppComponent extends React.Component<
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
chartType: ChartType.Hourglass,
|
chartType: ChartType.Hourglass,
|
||||||
showErrorPopup: false,
|
showErrorPopup: false,
|
||||||
|
config: DEFALUT_CONFIG,
|
||||||
};
|
};
|
||||||
chartRef: ChartComponent | null = null;
|
chartRef: ChartComponent | null = null;
|
||||||
|
|
||||||
@@ -313,6 +327,7 @@ class AppComponent extends React.Component<
|
|||||||
selection: args.selection,
|
selection: args.selection,
|
||||||
standalone: args.standalone,
|
standalone: args.standalone,
|
||||||
chartType: args.chartType,
|
chartType: args.chartType,
|
||||||
|
config: args.config,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
@@ -374,6 +389,16 @@ class AppComponent extends React.Component<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateUrl(args: queryString.ParsedQuery<any>) {
|
||||||
|
const location = this.props.location;
|
||||||
|
const search = queryString.parse(location.search);
|
||||||
|
for (const key in args) {
|
||||||
|
search[key] = args[key];
|
||||||
|
}
|
||||||
|
location.search = queryString.stringify(search);
|
||||||
|
this.props.history.push(location);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the user clicks an individual box in the chart.
|
* Called when the user clicks an individual box in the chart.
|
||||||
* Updates the browser URL.
|
* Updates the browser URL.
|
||||||
@@ -384,12 +409,10 @@ class AppComponent extends React.Component<
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
analyticsEvent('selection_changed');
|
analyticsEvent('selection_changed');
|
||||||
const location = this.props.location;
|
this.updateUrl({
|
||||||
const search = queryString.parse(location.search);
|
indi: selection.id,
|
||||||
search.indi = selection.id;
|
gen: selection.generation,
|
||||||
search.gen = String(selection.generation);
|
});
|
||||||
location.search = queryString.stringify(search);
|
|
||||||
this.props.history.push(location);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private onPrint = () => {
|
private onPrint = () => {
|
||||||
@@ -460,6 +483,35 @@ class AppComponent extends React.Component<
|
|||||||
switch (this.state.state) {
|
switch (this.state.state) {
|
||||||
case AppState.SHOWING_CHART:
|
case AppState.SHOWING_CHART:
|
||||||
case AppState.LOADING_MORE:
|
case AppState.LOADING_MORE:
|
||||||
|
const sidePanelTabs = [
|
||||||
|
{
|
||||||
|
menuItem: this.props.intl.formatMessage({
|
||||||
|
id: 'tab.info',
|
||||||
|
defaultMessage: 'Info',
|
||||||
|
}),
|
||||||
|
render: () => (
|
||||||
|
<Details
|
||||||
|
gedcom={this.state.data!.gedcom}
|
||||||
|
indi={this.state.selection!.id}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
menuItem: this.props.intl.formatMessage({
|
||||||
|
id: 'tab.settings',
|
||||||
|
defaultMessage: 'Settings',
|
||||||
|
}),
|
||||||
|
render: () => (
|
||||||
|
<ConfigPanel
|
||||||
|
config={this.state.config}
|
||||||
|
onChange={(config) => {
|
||||||
|
this.setState(Object.assign({}, this.state, {config}));
|
||||||
|
this.updateUrl(configToArgs(config));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<ErrorPopup
|
<ErrorPopup
|
||||||
@@ -476,14 +528,12 @@ class AppComponent extends React.Component<
|
|||||||
chartType={this.state.chartType}
|
chartType={this.state.chartType}
|
||||||
onSelection={this.onSelection}
|
onSelection={this.onSelection}
|
||||||
freezeAnimation={this.state.freezeAnimation}
|
freezeAnimation={this.state.freezeAnimation}
|
||||||
|
colors={this.state.config.color}
|
||||||
ref={(ref) => (this.chartRef = ref)}
|
ref={(ref) => (this.chartRef = ref)}
|
||||||
/>
|
/>
|
||||||
{this.state.showSidePanel ? (
|
{this.state.showSidePanel ? (
|
||||||
<Media at="large" className="sidePanel">
|
<Media at="large" className="sidePanel">
|
||||||
<Details
|
<Tab panes={sidePanelTabs} />
|
||||||
gedcom={this.state.data!.gedcom}
|
|
||||||
indi={this.state.selection!.id}
|
|
||||||
/>
|
|
||||||
</Media>
|
</Media>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import {ChartColors} from './config';
|
||||||
import {injectIntl, WrappedComponentProps} from 'react-intl';
|
import {injectIntl, WrappedComponentProps} from 'react-intl';
|
||||||
import {interpolateNumber} from 'd3-interpolate';
|
import {interpolateNumber} from 'd3-interpolate';
|
||||||
import {max, min} from 'd3-array';
|
import {max, min} from 'd3-array';
|
||||||
@@ -23,6 +24,7 @@ import {
|
|||||||
RelativesChart,
|
RelativesChart,
|
||||||
FancyChart,
|
FancyChart,
|
||||||
CircleRenderer,
|
CircleRenderer,
|
||||||
|
ChartColors as TopolaChartColors,
|
||||||
} from 'topola';
|
} from 'topola';
|
||||||
|
|
||||||
/** How much to zoom when using the +/- buttons. */
|
/** How much to zoom when using the +/- buttons. */
|
||||||
@@ -140,12 +142,19 @@ export enum ChartType {
|
|||||||
Fancy,
|
Fancy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chartColors = new Map<ChartColors, TopolaChartColors>([
|
||||||
|
[ChartColors.NO_COLOR, TopolaChartColors.NO_COLOR],
|
||||||
|
[ChartColors.COLOR_BY_GENERATION, TopolaChartColors.COLOR_BY_GENERATION],
|
||||||
|
[ChartColors.COLOR_BY_SEX, TopolaChartColors.COLOR_BY_SEX],
|
||||||
|
]);
|
||||||
|
|
||||||
export interface ChartProps {
|
export interface ChartProps {
|
||||||
data: JsonGedcomData;
|
data: JsonGedcomData;
|
||||||
selection: IndiInfo;
|
selection: IndiInfo;
|
||||||
chartType: ChartType;
|
chartType: ChartType;
|
||||||
onSelection: (indiInfo: IndiInfo) => void;
|
onSelection: (indiInfo: IndiInfo) => void;
|
||||||
freezeAnimation?: boolean;
|
freezeAnimation?: boolean;
|
||||||
|
colors?: ChartColors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Component showing the genealogy chart and handling transition animations. */
|
/** Component showing the genealogy chart and handling transition animations. */
|
||||||
@@ -195,7 +204,12 @@ export class ChartComponent extends React.PureComponent<
|
|||||||
* If indiInfo is not given, it means that it is the initial render and no
|
* If indiInfo is not given, it means that it is the initial render and no
|
||||||
* animation is performed.
|
* animation is performed.
|
||||||
*/
|
*/
|
||||||
private renderChart(args: {initialRender: boolean} = {initialRender: false}) {
|
private renderChart(
|
||||||
|
args: {initialRender: boolean; resetPosition: boolean} = {
|
||||||
|
initialRender: false,
|
||||||
|
resetPosition: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
// Wait for animation to finish if animation is in progress.
|
// Wait for animation to finish if animation is in progress.
|
||||||
if (!args.initialRender && this.animating) {
|
if (!args.initialRender && this.animating) {
|
||||||
this.rerenderRequired = true;
|
this.rerenderRequired = true;
|
||||||
@@ -215,6 +229,7 @@ export class ChartComponent extends React.PureComponent<
|
|||||||
renderer: this.getRendererType(),
|
renderer: this.getRendererType(),
|
||||||
svgSelector: '#chart',
|
svgSelector: '#chart',
|
||||||
indiCallback: (info) => this.props.onSelection(info),
|
indiCallback: (info) => this.props.onSelection(info),
|
||||||
|
colors: chartColors.get(this.props.colors!),
|
||||||
animate: true,
|
animate: true,
|
||||||
updateSvgSize: false,
|
updateSvgSize: false,
|
||||||
locale: this.props.intl.locale,
|
locale: this.props.intl.locale,
|
||||||
@@ -277,6 +292,7 @@ export class ChartComponent extends React.PureComponent<
|
|||||||
.attr('transform', `translate(${offsetX}, ${offsetY})`)
|
.attr('transform', `translate(${offsetX}, ${offsetY})`)
|
||||||
.attr('width', chartInfo.size[0] * scale)
|
.attr('width', chartInfo.size[0] * scale)
|
||||||
.attr('height', chartInfo.size[1] * scale);
|
.attr('height', chartInfo.size[1] * scale);
|
||||||
|
if (args.resetPosition) {
|
||||||
if (args.initialRender) {
|
if (args.initialRender) {
|
||||||
parent.scrollLeft = -dx;
|
parent.scrollLeft = -dx;
|
||||||
parent.scrollTop = -dy;
|
parent.scrollTop = -dy;
|
||||||
@@ -285,6 +301,7 @@ export class ChartComponent extends React.PureComponent<
|
|||||||
.tween('scrollLeft', scrollLeftTween(-dx))
|
.tween('scrollLeft', scrollLeftTween(-dx))
|
||||||
.tween('scrollTop', scrollTopTween(-dy));
|
.tween('scrollTop', scrollTopTween(-dy));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// After the animation is finished, rerender the chart if required.
|
// After the animation is finished, rerender the chart if required.
|
||||||
this.animating = true;
|
this.animating = true;
|
||||||
@@ -292,18 +309,21 @@ export class ChartComponent extends React.PureComponent<
|
|||||||
this.animating = false;
|
this.animating = false;
|
||||||
if (this.rerenderRequired) {
|
if (this.rerenderRequired) {
|
||||||
this.rerenderRequired = false;
|
this.rerenderRequired = false;
|
||||||
this.renderChart({initialRender: false});
|
this.renderChart({initialRender: false, resetPosition: false});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.renderChart({initialRender: true});
|
this.renderChart({initialRender: true, resetPosition: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: ChartProps) {
|
componentDidUpdate(prevProps: ChartProps) {
|
||||||
const initialRender = this.props.chartType !== prevProps.chartType;
|
const initialRender =
|
||||||
this.renderChart({initialRender});
|
this.props.chartType !== prevProps.chartType ||
|
||||||
|
this.props.colors !== prevProps.colors;
|
||||||
|
const resetPosition = this.props.chartType !== prevProps.chartType;
|
||||||
|
this.renderChart({initialRender, resetPosition});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
107
src/config.tsx
Normal file
107
src/config.tsx
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import {Checkbox, Form} from 'semantic-ui-react';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
import {ParsedQuery} from 'query-string';
|
||||||
|
|
||||||
|
export enum ChartColors {
|
||||||
|
NO_COLOR,
|
||||||
|
COLOR_BY_SEX,
|
||||||
|
COLOR_BY_GENERATION,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
color: ChartColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFALUT_CONFIG: Config = {
|
||||||
|
color: ChartColors.COLOR_BY_GENERATION,
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLOR_ARG = new Map<string, ChartColors>([
|
||||||
|
['n', ChartColors.NO_COLOR],
|
||||||
|
['g', ChartColors.COLOR_BY_GENERATION],
|
||||||
|
['s', ChartColors.COLOR_BY_SEX],
|
||||||
|
]);
|
||||||
|
const COLOR_ARG_INVERSE = new Map<ChartColors, string>();
|
||||||
|
COLOR_ARG.forEach((v, k) => COLOR_ARG_INVERSE.set(v, k));
|
||||||
|
|
||||||
|
export function argsToConfig(args: ParsedQuery<any>): Config {
|
||||||
|
const getParam = (name: string) => {
|
||||||
|
const value = args[name];
|
||||||
|
return typeof value === 'string' ? value : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: COLOR_ARG.get(getParam('c') ?? '') ?? DEFALUT_CONFIG.color,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function configToArgs(config: Config): ParsedQuery<any> {
|
||||||
|
return {c: COLOR_ARG_INVERSE.get(config.color)};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfigPanel(props: {
|
||||||
|
config: Config;
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -221,7 +221,7 @@ class DetailsComponent extends React.Component<
|
|||||||
.filter(hasData);
|
.filter(hasData);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ui segments" id="details">
|
<div className="ui segments details">
|
||||||
{getDetails(entries, ['NAME'], nameDetails)}
|
{getDetails(entries, ['NAME'], nameDetails)}
|
||||||
{getDetails(entries, EVENT_TAGS, (entry) =>
|
{getDetails(entries, EVENT_TAGS, (entry) =>
|
||||||
eventDetails(entry, this.props.intl),
|
eventDetails(entry, this.props.intl),
|
||||||
|
|||||||
@@ -141,3 +141,16 @@ div.zoom {
|
|||||||
.ui.top.attached.menu {
|
.ui.top.attached.menu {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui.segments.details {
|
||||||
|
margin: 0px !important;
|
||||||
|
border: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.form .field.no-margin {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.tabular.menu a {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,5 +70,11 @@
|
|||||||
"error.WIKITREE_ID_NOT_PROVIDED": "Identyfikator WikiTree nie został podany",
|
"error.WIKITREE_ID_NOT_PROVIDED": "Identyfikator WikiTree nie został podany",
|
||||||
"error.WIKITREE_PROFILE_NOT_ACCESSIBLE": "Profil WikiTree {id} nie jest dostępny",
|
"error.WIKITREE_PROFILE_NOT_ACCESSIBLE": "Profil WikiTree {id} nie jest dostępny",
|
||||||
"error.WIKITREE_PROFILE_NOT_FOUND": "Profil WikiTree {id} nie istnieje",
|
"error.WIKITREE_PROFILE_NOT_FOUND": "Profil WikiTree {id} nie istnieje",
|
||||||
"wikitree.private": "Prywatne"
|
"wikitree.private": "Prywatne",
|
||||||
|
"tab.info": "Info",
|
||||||
|
"tab.settings": "Ustawienia",
|
||||||
|
"config.colors": "Kolory",
|
||||||
|
"config.colors.NO_COLOR": "brak",
|
||||||
|
"config.colors.COLOR_BY_GENERATION": "według pokolenia",
|
||||||
|
"config.colors.COLOR_BY_SEX": "według płci"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user