Show header information of the gedcom file on the side panel (#252)

* Show header information of the gedcom file on the side panel #251

* Format creation date in HEAD section
This commit is contained in:
Frank Buchholz 2026-02-13 23:55:23 +01:00 committed by GitHub
parent 24a0f336ac
commit 7c5203b263
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 127 additions and 3 deletions

View File

@ -178,6 +178,10 @@ div.zoom {
text-transform: uppercase; text-transform: uppercase;
} }
.ui.sub.header, .ui.list {
margin-left: 20px;
}
.limit-height { .limit-height {
height: 300px; height: 300px;
overflow-y: scroll; overflow-y: scroll;

View File

@ -1,3 +1,5 @@
import {SourceHead} from '../head/head';
import {GedcomData} from '../../util/gedcom_util';
import {ParsedQuery} from 'query-string'; import {ParsedQuery} from 'query-string';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {Checkbox, Form, Header, Item} from 'semantic-ui-react'; import {Checkbox, Form, Header, Item} from 'semantic-ui-react';
@ -74,11 +76,13 @@ export function configToArgs(config: Config): ParsedQuery<any> {
} }
export function ConfigPanel(props: { export function ConfigPanel(props: {
gedcom: GedcomData;
config: Config; config: Config;
onChange: (config: Config) => void; onChange: (config: Config) => void;
}) { }) {
return ( return (
<Form className="details"> <>
{SourceHead(props.gedcom)}<Form className="details">
<Item.Group> <Item.Group>
<Item> <Item>
<Item.Content> <Item.Content>
@ -230,5 +234,6 @@ export function ConfigPanel(props: {
</Item> </Item>
</Item.Group> </Item.Group>
</Form> </Form>
</>
); );
} }

108
src/sidepanel/head/head.tsx Normal file
View File

@ -0,0 +1,108 @@
import {
dereference,
GedcomData,
} from '../../util/gedcom_util';
import {FormattedMessage, useIntl} from 'react-intl';
import {Header, Divider, List} from 'semantic-ui-react';
import {getDate} from 'topola';
import {formatDateOrRange} from '../../util/date_util';
export function SourceHead(gedcom: GedcomData){
const head = gedcom.head;
/* Don't show the section if there is no relevant information */
if (!head || !head.tree) {
return null;
}
const sour = head.tree.find((entry) => entry.tag === 'SOUR');
const sour_name = sour && sour.tree && sour.tree.find((entry) => entry.tag === 'NAME')?.data; // Software name
const date = head.tree.find((entry) => entry.tag === 'DATE'); // Creation date
const intl = useIntl();
const dateFormatted = date ? formatDateOrRange(getDate(date.data), intl) : null; // Formatted creation date
const file = head.tree.find((entry) => entry.tag === 'FILE')?.data; // File path
const filename = file && ( file.split('\\').pop() || file.split('/').pop() ); // Extract file name from path
const copr = head.tree.find((entry) => entry.tag === 'COPR')?.data; // Copyright
// Reference to submitter
const submReference = head.tree.find((entry) => entry.tag === 'SUBM');
const subm = submReference && dereference(submReference, gedcom, (gedcom) => gedcom.other);
const name = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'NAME')?.data; // Submitter name
const phon = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'PHON')?.data; // Phone number
const email = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'EMAIL')?.data; // Email
const addr = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'ADDR'); // Address
const adr1 = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'ADR1')?.data; // Street address
const city = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'CITY')?.data; // City
const post = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'POST')?.data; // Postal code
const location = [adr1, post, city].filter(Boolean).join(', '); // Combined location
/* Don't show the section if there is no relevant information */
if (!(sour_name || dateFormatted || filename || copr || name || phon || email || location)) {
return null;
}
// Icons: https://react.semantic-ui.com/elements/icon/
return (
<>
<Header sub>
<FormattedMessage id="head.source" defaultMessage="Data source" />
</Header>
<List>
{sour_name && (
<List.Item>
<List.Icon name='edit' />
<List.Content>{sour_name}</List.Content>
</List.Item>
)}
{date && (
<List.Item>
<List.Icon name='calendar' />
<List.Content>{dateFormatted}</List.Content>
</List.Item>
)}
{file && (
<List.Item>
<List.Icon name='file' />
<List.Content>{filename}</List.Content>
</List.Item>
)}
{name && (
<List.Item>
<List.Icon name='user' />
<List.Content>{name}</List.Content>
</List.Item>
)}
{adr1 && (
<List.Item>
<List.Icon name='marker' />
<List.Content>{location}</List.Content>
</List.Item>
)}
{phon && (
<List.Item>
<List.Icon name='phone' />
<List.Content>{phon}</List.Content>
</List.Item>
)}
{email && (
<List.Item>
<List.Icon name='mail' />
<List.Content>{email}</List.Content>
</List.Item>
)}
{copr && (
<List.Item>
<List.Icon name='copyright' />
<List.Content>{copr}</List.Content>
</List.Item>
)}
</List>
<Divider />
</>
);
}

View File

@ -37,7 +37,7 @@ export function SidePanel({
id: 'tab.settings', id: 'tab.settings',
defaultMessage: 'Settings', defaultMessage: 'Settings',
}), }),
render: () => <ConfigPanel config={config} onChange={onConfigChange} />, render: () => <ConfigPanel gedcom={data.gedcom} config={config} onChange={onConfigChange} />,
}, },
]; ];

View File

@ -129,6 +129,7 @@
"config.sex": "Пол", "config.sex": "Пол",
"config.sex.HIDE": "Скриване", "config.sex.HIDE": "Скриване",
"config.sex.SHOW": "Показване", "config.sex.SHOW": "Показване",
"head.source": "Източник на данни",
"name.unknown_name": "Неизвестно име", "name.unknown_name": "Неизвестно име",
"extras.images": "Изображение", "extras.images": "Изображение",
"extras.notes": "Бележки", "extras.notes": "Бележки",

View File

@ -129,6 +129,7 @@
"config.sex": "Pohlaví", "config.sex": "Pohlaví",
"config.sex.HIDE": "skrýt", "config.sex.HIDE": "skrýt",
"config.sex.SHOW": "zobrazit", "config.sex.SHOW": "zobrazit",
"head.source": "Zdroj dat",
"name.unknown_name": "N.N.", "name.unknown_name": "N.N.",
"extras.images": "Obrázky", "extras.images": "Obrázky",
"extras.notes": "Poznámky", "extras.notes": "Poznámky",

View File

@ -129,6 +129,7 @@
"config.sex": "Geschlecht", "config.sex": "Geschlecht",
"config.sex.HIDE": "verbergen", "config.sex.HIDE": "verbergen",
"config.sex.SHOW": "anzeigen", "config.sex.SHOW": "anzeigen",
"head.source": "Datenquelle",
"name.unknown_name": "N.N.", "name.unknown_name": "N.N.",
"extras.images": "Bilder", "extras.images": "Bilder",
"extras.notes": "Notizen", "extras.notes": "Notizen",

View File

@ -129,6 +129,7 @@
"config.sex": "Sexe", "config.sex": "Sexe",
"config.sex.HIDE": "cacher", "config.sex.HIDE": "cacher",
"config.sex.SHOW": "afficher", "config.sex.SHOW": "afficher",
"head.source": "Source de données",
"name.unknown_name": "?", "name.unknown_name": "?",
"extras.images": "Images", "extras.images": "Images",
"extras.notes": "Notes", "extras.notes": "Notes",

View File

@ -129,6 +129,7 @@
"config.sex": "Sesso", "config.sex": "Sesso",
"config.sex.HIDE": "nascondere", "config.sex.HIDE": "nascondere",
"config.sex.SHOW": "visualizzare", "config.sex.SHOW": "visualizzare",
"head.source": "Origine dati",
"name.unknown_name": "N.N.", "name.unknown_name": "N.N.",
"extras.images": "Immagini", "extras.images": "Immagini",
"extras.notes": "Appunti", "extras.notes": "Appunti",

View File

@ -129,6 +129,7 @@
"config.sex": "Płeć", "config.sex": "Płeć",
"config.sex.HIDE": "ukryj", "config.sex.HIDE": "ukryj",
"config.sex.SHOW": "pokaż", "config.sex.SHOW": "pokaż",
"head.source": "Źródło danych",
"name.unknown_name": "N.N.", "name.unknown_name": "N.N.",
"extras.images": "Zdjęcia", "extras.images": "Zdjęcia",
"extras.notes": "Notatki", "extras.notes": "Notatki",

View File

@ -129,6 +129,7 @@
"config.sex": "Пол", "config.sex": "Пол",
"config.sex.HIDE": "Скрыть", "config.sex.HIDE": "Скрыть",
"config.sex.SHOW": "Показать", "config.sex.SHOW": "Показать",
"head.source": "Источник данных",
"name.unknown_name": "Неизвестно", "name.unknown_name": "Неизвестно",
"extras.images": "Картинки", "extras.images": "Картинки",
"extras.notes": "Примечание", "extras.notes": "Примечание",