Refactor UI components for people management by introducing tabbed navigation between map and people views. Enhance styling for better layout and responsiveness, ensuring a clear distinction between the two panels. Update localization strings to include new titles for the people tab. Improve the people panel functionality to support selection events, allowing for a seamless user experience when inspecting individuals. Revise related styles to maintain consistency across the UI.
This commit is contained in:
@@ -74,6 +74,7 @@ const ru = {
|
|||||||
eventsTitle: 'События',
|
eventsTitle: 'События',
|
||||||
eventsEmpty: 'Пока ничего не происходит.',
|
eventsEmpty: 'Пока ничего не происходит.',
|
||||||
locationName: 'Локация',
|
locationName: 'Локация',
|
||||||
|
personTitle: 'Человек',
|
||||||
locationItems: 'Предметы',
|
locationItems: 'Предметы',
|
||||||
locationCharacters: 'Персонажи',
|
locationCharacters: 'Персонажи',
|
||||||
locationActivities: 'Сейчас',
|
locationActivities: 'Сейчас',
|
||||||
@@ -201,6 +202,7 @@ const en: Messages = {
|
|||||||
eventsTitle: 'Events',
|
eventsTitle: 'Events',
|
||||||
eventsEmpty: 'Nothing is happening yet.',
|
eventsEmpty: 'Nothing is happening yet.',
|
||||||
locationName: 'Location',
|
locationName: 'Location',
|
||||||
|
personTitle: 'Person',
|
||||||
locationItems: 'Items',
|
locationItems: 'Items',
|
||||||
locationCharacters: 'People',
|
locationCharacters: 'People',
|
||||||
locationActivities: 'Now',
|
locationActivities: 'Now',
|
||||||
|
|||||||
@@ -18,6 +18,14 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `hidden` is a UA rule, so any author `display` beats it — a flex panel body stayed on screen
|
||||||
|
* with the attribute set. Everything here toggles visibility through `hidden`, so it has to win.
|
||||||
|
*/
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 100dvh;
|
min-height: 100dvh;
|
||||||
@@ -29,9 +37,13 @@ body {
|
|||||||
* as a half-loaded document rather than a game, so every screen is a full-height flex column and
|
* as a half-loaded document rather than a game, so every screen is a full-height flex column and
|
||||||
* decides its own comfortable width.
|
* decides its own comfortable width.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* A fixed height, not just a minimum: with only a minimum the shell grows to whatever its tallest
|
||||||
|
* panel wants, and a table of four hundred people made the page twice the window.
|
||||||
|
*/
|
||||||
#app {
|
#app {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 100dvh;
|
height: 100dvh;
|
||||||
padding: 24px 24px 52px;
|
padding: 24px 24px 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,21 +256,18 @@ body {
|
|||||||
|
|
||||||
/* Manager */
|
/* Manager */
|
||||||
|
|
||||||
.shell {
|
/*
|
||||||
display: flex;
|
* Two panels, both full height. Left is a list — the map tree or the people table, whichever tab
|
||||||
flex-direction: column;
|
* is up. Right inspects whatever was picked last, a room or a person. Nothing lives below the
|
||||||
|
* fold: the people list used to sit in a bottom row that had to be scrolled to.
|
||||||
|
*/
|
||||||
|
.manager {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(340px, 1.05fr) minmax(320px, 1fr);
|
||||||
|
gap: 16px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.manager {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(210px, 0.85fr) minmax(240px, 1fr) minmax(280px, 1.25fr);
|
|
||||||
gap: 16px;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@@ -283,6 +292,36 @@ body {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A tab strip sits where a title would, and reads like one until you pick the other tab. */
|
||||||
|
.panel__tabs {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__tab {
|
||||||
|
padding: 11px 16px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font: inherit;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__tab:hover {
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__tab--active {
|
||||||
|
border-bottom-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
/* The body scrolls, the title stays: a long tree must not push the panel out of the window. */
|
/* The body scrolls, the title stays: a long tree must not push the panel out of the window. */
|
||||||
.panel__body {
|
.panel__body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -365,18 +404,19 @@ body {
|
|||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel--people {
|
/* The table scrolls, not the panel body around it — otherwise the pager scrolls away with it. */
|
||||||
flex: 0 1 38vh;
|
.panel__body--fill {
|
||||||
min-height: 220px;
|
display: flex;
|
||||||
max-height: 42vh;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.people {
|
.people {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.people__toolbar {
|
.people__toolbar {
|
||||||
@@ -403,17 +443,10 @@ body {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.people__main {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(240px, 0.42fr);
|
|
||||||
gap: 12px;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.people__list {
|
.people__list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
@@ -530,7 +563,8 @@ body {
|
|||||||
/* Below three columns the panels stop competing for height and the page scrolls instead. */
|
/* Below three columns the panels stop competing for height and the page scrolls instead. */
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
#app {
|
#app {
|
||||||
min-height: 0;
|
height: auto;
|
||||||
|
min-height: 100dvh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.manager {
|
.manager {
|
||||||
@@ -543,13 +577,12 @@ body {
|
|||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel--people {
|
.panel__body--fill {
|
||||||
flex: 0 0 auto;
|
overflow: visible;
|
||||||
max-height: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.people__main {
|
.people__table-wrap {
|
||||||
grid-template-columns: 1fr;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ export class GameScreen {
|
|||||||
private readonly playPauseButton = el('button', { class: 'button button--icon', type: 'button', text: '▶' });
|
private readonly playPauseButton = el('button', { class: 'button button--icon', type: 'button', text: '▶' });
|
||||||
private readonly speedButtons: HTMLButtonElement[];
|
private readonly speedButtons: HTMLButtonElement[];
|
||||||
|
|
||||||
private readonly mapTitle = el('h2', { class: 'panel__title' });
|
private readonly mapTab = el('button', { class: 'panel__tab', type: 'button' });
|
||||||
|
private readonly peopleTab = el('button', { class: 'panel__tab', type: 'button' });
|
||||||
private readonly tree = el('ul', { class: 'tree' });
|
private readonly tree = el('ul', { class: 'tree' });
|
||||||
private readonly eventsTitle = el('h2', { class: 'panel__title' });
|
private readonly mapBody = el('div', { class: 'panel__body' });
|
||||||
private readonly eventsEmpty = el('p', { class: 'panel__empty' });
|
private readonly peopleBody = el('div', { class: 'panel__body panel__body--fill' });
|
||||||
private readonly locationTitle = el('h2', { class: 'panel__title' });
|
private readonly inspectTitle = el('h2', { class: 'panel__title' });
|
||||||
|
private readonly locationBody = el('div', { class: 'panel__body' });
|
||||||
private readonly locationName = el('p', { class: 'panel__name' });
|
private readonly locationName = el('p', { class: 'panel__name' });
|
||||||
private readonly itemsHeading = el('h3', { class: 'panel__section-title' });
|
private readonly itemsHeading = el('h3', { class: 'panel__section-title' });
|
||||||
private readonly itemsEmpty = el('p', { class: 'panel__empty' });
|
private readonly itemsEmpty = el('p', { class: 'panel__empty' });
|
||||||
@@ -46,7 +48,7 @@ export class GameScreen {
|
|||||||
private readonly positionsEmpty = el('p', { class: 'panel__empty' });
|
private readonly positionsEmpty = el('p', { class: 'panel__empty' });
|
||||||
private readonly positionsList = el('ul', { class: 'panel__list' });
|
private readonly positionsList = el('ul', { class: 'panel__list' });
|
||||||
|
|
||||||
private readonly people = new PeoplePanel();
|
private readonly people = new PeoplePanel({ onSelect: () => this.inspect('person') });
|
||||||
|
|
||||||
private readonly treeButtons = new Map<string, HTMLButtonElement>();
|
private readonly treeButtons = new Map<string, HTMLButtonElement>();
|
||||||
private nodes: readonly MapSnapshotNode[] = [];
|
private nodes: readonly MapSnapshotNode[] = [];
|
||||||
@@ -55,6 +57,7 @@ export class GameScreen {
|
|||||||
private running = false;
|
private running = false;
|
||||||
private lastGameTime: Date | null = null;
|
private lastGameTime: Date | null = null;
|
||||||
private lastSpeedIndex = 0;
|
private lastSpeedIndex = 0;
|
||||||
|
private inspected: 'location' | 'person' = 'location';
|
||||||
|
|
||||||
constructor(options: GameScreenOptions) {
|
constructor(options: GameScreenOptions) {
|
||||||
this.speedButtons = CLOCK_SPEEDS.map((_, index) =>
|
this.speedButtons = CLOCK_SPEEDS.map((_, index) =>
|
||||||
@@ -84,41 +87,33 @@ export class GameScreen {
|
|||||||
),
|
),
|
||||||
el(
|
el(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'shell' },
|
{ class: 'manager' },
|
||||||
el(
|
el(
|
||||||
'div',
|
'section',
|
||||||
{ class: 'manager' },
|
{ class: 'panel' },
|
||||||
el(
|
el('div', { class: 'panel__tabs' }, this.mapTab, this.peopleTab),
|
||||||
'section',
|
this.mapBody,
|
||||||
{ class: 'panel' },
|
this.peopleBody,
|
||||||
this.mapTitle,
|
|
||||||
el('div', { class: 'panel__body' }, this.tree),
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
'section',
|
|
||||||
{ class: 'panel' },
|
|
||||||
this.eventsTitle,
|
|
||||||
el('div', { class: 'panel__body' }, this.eventsEmpty),
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
'section',
|
|
||||||
{ class: 'panel' },
|
|
||||||
this.locationTitle,
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{ class: 'panel__body' },
|
|
||||||
this.locationName,
|
|
||||||
el('div', { class: 'panel__section' }, this.itemsHeading, this.itemsEmpty, this.itemsList, this.pupilSlotsLine),
|
|
||||||
el('div', { class: 'panel__section' }, this.charactersHeading, this.charactersEmpty),
|
|
||||||
el('div', { class: 'panel__section' }, this.activitiesHeading, this.activitiesEmpty),
|
|
||||||
el('div', { class: 'panel__section' }, this.positionsHeading, this.positionsEmpty, this.positionsList),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
this.people.element,
|
el('section', { class: 'panel' }, this.inspectTitle, this.locationBody, this.people.cardElement),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.mapBody.append(this.tree);
|
||||||
|
this.peopleBody.append(this.people.listElement);
|
||||||
|
this.locationBody.append(
|
||||||
|
this.locationName,
|
||||||
|
el('div', { class: 'panel__section' }, this.itemsHeading, this.itemsEmpty, this.itemsList, this.pupilSlotsLine),
|
||||||
|
el('div', { class: 'panel__section' }, this.charactersHeading, this.charactersEmpty),
|
||||||
|
el('div', { class: 'panel__section' }, this.activitiesHeading, this.activitiesEmpty),
|
||||||
|
el('div', { class: 'panel__section' }, this.positionsHeading, this.positionsEmpty, this.positionsList),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.mapTab.addEventListener('click', () => this.showTab('map'));
|
||||||
|
this.peopleTab.addEventListener('click', () => this.showTab('people'));
|
||||||
|
this.showTab('map');
|
||||||
|
this.inspect('location');
|
||||||
|
|
||||||
this.localize();
|
this.localize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +123,9 @@ export class GameScreen {
|
|||||||
|
|
||||||
localize(): void {
|
localize(): void {
|
||||||
this.backButton.textContent = t('backToMenu');
|
this.backButton.textContent = t('backToMenu');
|
||||||
this.mapTitle.textContent = t('mapTitle');
|
this.mapTab.textContent = t('mapTitle');
|
||||||
this.eventsTitle.textContent = t('eventsTitle');
|
this.peopleTab.textContent = t('peopleTitle');
|
||||||
this.eventsEmpty.textContent = t('eventsEmpty');
|
this.paintInspectTitle();
|
||||||
this.locationTitle.textContent = t('locationName');
|
|
||||||
this.itemsHeading.textContent = t('locationItems');
|
this.itemsHeading.textContent = t('locationItems');
|
||||||
this.itemsEmpty.textContent = t('itemsEmpty');
|
this.itemsEmpty.textContent = t('itemsEmpty');
|
||||||
this.charactersHeading.textContent = t('locationCharacters');
|
this.charactersHeading.textContent = t('locationCharacters');
|
||||||
@@ -160,6 +154,8 @@ export class GameScreen {
|
|||||||
this.rebuildTree();
|
this.rebuildTree();
|
||||||
this.applyClock(new Date(school.gameTime), school.running, school.speedIndex);
|
this.applyClock(new Date(school.gameTime), school.running, school.speedIndex);
|
||||||
this.people.show(school.id);
|
this.people.show(school.id);
|
||||||
|
this.showTab('map');
|
||||||
|
this.inspect('location');
|
||||||
}
|
}
|
||||||
|
|
||||||
applyMap(schoolId: number, nodes: readonly MapSnapshotNode[]): void {
|
applyMap(schoolId: number, nodes: readonly MapSnapshotNode[]): void {
|
||||||
@@ -211,9 +207,32 @@ export class GameScreen {
|
|||||||
|
|
||||||
private select(id: string): void {
|
private select(id: string): void {
|
||||||
this.selectedId = id;
|
this.selectedId = id;
|
||||||
|
this.inspect('location');
|
||||||
this.paintSelection();
|
this.paintSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showTab(tab: 'map' | 'people'): void {
|
||||||
|
this.mapTab.classList.toggle('panel__tab--active', tab === 'map');
|
||||||
|
this.peopleTab.classList.toggle('panel__tab--active', tab === 'people');
|
||||||
|
this.mapBody.hidden = tab !== 'map';
|
||||||
|
this.peopleBody.hidden = tab !== 'people';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The middle panel follows the last thing picked, whichever list it came from. Switching tabs
|
||||||
|
* on the left does not change it — the map tab is often just a way to find the next room.
|
||||||
|
*/
|
||||||
|
private inspect(what: 'location' | 'person'): void {
|
||||||
|
this.inspected = what;
|
||||||
|
this.locationBody.hidden = what !== 'location';
|
||||||
|
this.people.cardElement.hidden = what !== 'person';
|
||||||
|
this.paintInspectTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private paintInspectTitle(): void {
|
||||||
|
this.inspectTitle.textContent = this.inspected === 'person' ? t('personTitle') : t('locationName');
|
||||||
|
}
|
||||||
|
|
||||||
private paintSelection(): void {
|
private paintSelection(): void {
|
||||||
for (const [id, button] of this.treeButtons) {
|
for (const [id, button] of this.treeButtons) {
|
||||||
button.classList.toggle('tree__button--active', id === this.selectedId);
|
button.classList.toggle('tree__button--active', id === this.selectedId);
|
||||||
|
|||||||
@@ -24,14 +24,22 @@ const COLUMNS: readonly { sort: PersonSort; label: MessageKey }[] = [
|
|||||||
{ sort: 'age', label: 'peopleColAge' },
|
{ sort: 'age', label: 'peopleColAge' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
interface PeoplePanelOptions {
|
||||||
|
/** Somebody was picked, so the inspector has to stop showing a location. */
|
||||||
|
readonly onSelect: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bottom row of the manager shell: filters, a page of people, and one open card.
|
* The people list and the card of whoever is picked. They live in two different panels — the list
|
||||||
* Fetches over HTTP; never ticks locally.
|
* on the left next to the map tree, the card in the middle inspector — so this owns two elements
|
||||||
|
* rather than one. Fetches over HTTP; never ticks locally.
|
||||||
*/
|
*/
|
||||||
export class PeoplePanel {
|
export class PeoplePanel {
|
||||||
readonly element: HTMLElement;
|
/** Filters, the table and the pager. Goes under the "people" tab of the left panel. */
|
||||||
|
readonly listElement: HTMLElement;
|
||||||
|
|
||||||
private readonly title = el('h2', { class: 'panel__title' });
|
/** The open card. Goes into the inspector in the middle. */
|
||||||
|
readonly cardElement: HTMLElement;
|
||||||
private readonly roleSelect = el('select', { class: 'input people__input' });
|
private readonly roleSelect = el('select', { class: 'input people__input' });
|
||||||
private readonly yearSelect = el('select', { class: 'input people__input' });
|
private readonly yearSelect = el('select', { class: 'input people__input' });
|
||||||
private readonly letterSelect = el('select', { class: 'input people__input' });
|
private readonly letterSelect = el('select', { class: 'input people__input' });
|
||||||
@@ -53,7 +61,7 @@ export class PeoplePanel {
|
|||||||
private readonly pagerLabel = el('span', { class: 'people__pager-label' });
|
private readonly pagerLabel = el('span', { class: 'people__pager-label' });
|
||||||
private readonly prevButton = el('button', { class: 'button button--small', type: 'button' });
|
private readonly prevButton = el('button', { class: 'button button--small', type: 'button' });
|
||||||
private readonly nextButton = el('button', { class: 'button button--small', type: 'button' });
|
private readonly nextButton = el('button', { class: 'button button--small', type: 'button' });
|
||||||
private readonly card = el('aside', { class: 'people__card' });
|
private readonly card = el('aside', { class: 'panel__body people__card' });
|
||||||
|
|
||||||
private schoolId: number | null = null;
|
private schoolId: number | null = null;
|
||||||
private sort: PersonSort = 'surname';
|
private sort: PersonSort = 'surname';
|
||||||
@@ -63,7 +71,7 @@ export class PeoplePanel {
|
|||||||
private token = 0;
|
private token = 0;
|
||||||
private cardToken = 0;
|
private cardToken = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor(private readonly options: PeoplePanelOptions) {
|
||||||
this.ageMinInput.min = '0';
|
this.ageMinInput.min = '0';
|
||||||
this.ageMaxInput.min = '0';
|
this.ageMaxInput.min = '0';
|
||||||
this.table.append(this.thead, this.tbody);
|
this.table.append(this.thead, this.tbody);
|
||||||
@@ -86,43 +94,34 @@ export class PeoplePanel {
|
|||||||
void this.reload();
|
void this.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.element = el(
|
this.listElement = el(
|
||||||
'section',
|
'div',
|
||||||
{ class: 'panel panel--people' },
|
{ class: 'people' },
|
||||||
this.title,
|
|
||||||
el(
|
el(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'panel__body people' },
|
{ class: 'people__toolbar' },
|
||||||
el(
|
field(this.roleLabel, this.roleSelect),
|
||||||
'div',
|
field(this.yearLabel, this.yearSelect),
|
||||||
{ class: 'people__toolbar' },
|
field(this.letterLabel, this.letterSelect),
|
||||||
field(this.roleLabel, this.roleSelect),
|
field(this.positionLabel, this.positionSelect),
|
||||||
field(this.yearLabel, this.yearSelect),
|
field(this.sexLabel, this.sexSelect),
|
||||||
field(this.letterLabel, this.letterSelect),
|
field(this.ageFromLabel, this.ageMinInput),
|
||||||
field(this.positionLabel, this.positionSelect),
|
field(this.ageToLabel, this.ageMaxInput),
|
||||||
field(this.sexLabel, this.sexSelect),
|
),
|
||||||
field(this.ageFromLabel, this.ageMinInput),
|
el(
|
||||||
field(this.ageToLabel, this.ageMaxInput),
|
'div',
|
||||||
),
|
{ class: 'people__list' },
|
||||||
el(
|
el('div', { class: 'people__table-wrap' }, this.table, this.empty),
|
||||||
'div',
|
el('div', { class: 'people__pager' }, this.prevButton, this.pagerLabel, this.nextButton),
|
||||||
{ class: 'people__main' },
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{ class: 'people__list' },
|
|
||||||
el('div', { class: 'people__table-wrap' }, this.table, this.empty),
|
|
||||||
el('div', { class: 'people__pager' }, this.prevButton, this.pagerLabel, this.nextButton),
|
|
||||||
),
|
|
||||||
this.card,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.cardElement = this.card;
|
||||||
|
|
||||||
this.localize();
|
this.localize();
|
||||||
}
|
}
|
||||||
|
|
||||||
localize(): void {
|
localize(): void {
|
||||||
this.title.textContent = t('peopleTitle');
|
|
||||||
this.roleLabel.textContent = t('peopleRole');
|
this.roleLabel.textContent = t('peopleRole');
|
||||||
this.yearLabel.textContent = t('peopleYear');
|
this.yearLabel.textContent = t('peopleYear');
|
||||||
this.letterLabel.textContent = t('peopleLetter');
|
this.letterLabel.textContent = t('peopleLetter');
|
||||||
@@ -296,6 +295,7 @@ export class PeoplePanel {
|
|||||||
row.addEventListener('click', () => {
|
row.addEventListener('click', () => {
|
||||||
this.selectedId = person.id;
|
this.selectedId = person.id;
|
||||||
this.highlightSelection();
|
this.highlightSelection();
|
||||||
|
this.options.onSelect();
|
||||||
void this.openCard(person.id);
|
void this.openCard(person.id);
|
||||||
});
|
});
|
||||||
row.append(
|
row.append(
|
||||||
@@ -327,6 +327,9 @@ export class PeoplePanel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also covers the links inside a card: opening a relative is picking somebody too.
|
||||||
|
this.options.onSelect();
|
||||||
|
|
||||||
const token = ++this.cardToken;
|
const token = ++this.cardToken;
|
||||||
try {
|
try {
|
||||||
const card = await fetchPerson(schoolId, personId, getLocale());
|
const card = await fetchPerson(schoolId, personId, getLocale());
|
||||||
|
|||||||
Reference in New Issue
Block a user