summaryrefslogtreecommitdiff
path: root/resources/views
diff options
context:
space:
mode:
authorRico Sonntag <mail@ricosonntag.de>2019-01-30 13:24:27 +0100
committerGreg Roach <fisharebest@gmail.com>2019-01-30 12:24:27 +0000
commit8add1155cb77caede54752196ff44696d1346431 (patch)
tree9f3d128bc9153d53d02d9b69d20c26fc2766c779 /resources/views
parentc3d1646f7eb0095bcea8d11a6368142b853c1949 (diff)
downloadwebtrees-8add1155cb77caede54752196ff44696d1346431.tar.gz
webtrees-8add1155cb77caede54752196ff44696d1346431.tar.bz2
webtrees-8add1155cb77caede54752196ff44696d1346431.zip
2059 (#2156)
* 2059 - Split other charts into separate views * 2059 - Added some basic bootstrap markup * 2059 - Moved distribution chart out of places table * 2059 - Moved HTML of other statistics (places list) into templates * 2059 - Removed tables, use cards instead * 2059 - Started adding chart.js charts * 2059: Moved template into sub directory * 2059: Refactor family statistics * 2059 - Started splitting places lists * 2059 - Refactor individual statistics * 2059: Moved HTML into templates * 2059: Handle list/nolist of top-10 oldest * 2059 - Use separate templates for lists * 2059: Use templates * 2059 - Minor enhancements * 2059: Moved distribution chart into own class * 2059: Splitted Stats into separate modules * 2059: Use repository pattern to hide complexity and structure methods * 2059: Use illuminate db * 2059: Google charts * 2059: Squash classes * 2059: Use PHPs number formatter to format century ordinal suffix * 2059: Place repository * 2059: Use repositories * 2059: Use illuminate db * 2059: Simplify event repository methods * 2059: Use @inheritDoc to avoid duplicate (or not updated) doc blocks * 2059: PlaceRepository - Use illuminate database * 2059: SexRepository * 2059: Removed not used percentage calculations * 2059: Consolidate classes * 2059: Event dates * 2059: Use constants * 2059: Refactoring Stats * 2059: Rename repo * 2059: Refactor media repository * 2059: Removed Chart.js stuff, doing this in a later update * 2059: Reduce code complexity * 2059: Moved age calculation to separate method * 2059: Fixes after rebase * 2059: Removed obsolete method parameters * 2059: Use view to render hitcounter * 2059: Update phpdoc * 2059: Removed debug output * 2059: Use consts * 2059: Fixed method parameter type hints * 2059: Add missing const types * 2059: Simplify method * 2059: Refactor google charts * 2059: Fixed rebase issues
Diffstat (limited to 'resources/views')
-rw-r--r--resources/views/modules/statistics-chart/families.phtml154
-rw-r--r--resources/views/modules/statistics-chart/individuals.phtml144
-rw-r--r--resources/views/modules/statistics-chart/other.phtml95
-rw-r--r--resources/views/statistics/families/age-difference.phtml55
-rw-r--r--resources/views/statistics/families/birth-age.phtml61
-rw-r--r--resources/views/statistics/families/children.phtml59
-rw-r--r--resources/views/statistics/families/marriage-age.phtml71
-rw-r--r--resources/views/statistics/families/marriage-length.phtml37
-rw-r--r--resources/views/statistics/families/top10-list-age.phtml28
-rw-r--r--resources/views/statistics/families/top10-list-grand.phtml21
-rw-r--r--resources/views/statistics/families/top10-list-spouses.phtml18
-rw-r--r--resources/views/statistics/families/top10-list.phtml21
-rw-r--r--resources/views/statistics/families/top10-nolist-age.phtml24
-rw-r--r--resources/views/statistics/families/top10-nolist-grand.phtml15
-rw-r--r--resources/views/statistics/families/top10-nolist-spouses.phtml13
-rw-r--r--resources/views/statistics/families/top10-nolist.phtml15
-rw-r--r--resources/views/statistics/families/total-records.phtml112
-rw-r--r--resources/views/statistics/hit-count.phtml8
-rw-r--r--resources/views/statistics/individuals/greatest-age.phtml33
-rw-r--r--resources/views/statistics/individuals/lifespan.phtml52
-rw-r--r--resources/views/statistics/individuals/names.phtml63
-rw-r--r--resources/views/statistics/individuals/oldest-living.phtml33
-rw-r--r--resources/views/statistics/individuals/top10-list.phtml18
-rw-r--r--resources/views/statistics/individuals/top10-nolist.phtml13
-rw-r--r--resources/views/statistics/individuals/total-events.phtml111
-rw-r--r--resources/views/statistics/individuals/total-records.phtml77
-rw-r--r--resources/views/statistics/other/chart-distribution.phtml31
-rw-r--r--resources/views/statistics/other/chart-google.phtml1
-rw-r--r--resources/views/statistics/other/chart-objects.phtml23
-rw-r--r--resources/views/statistics/other/chart-sources.phtml39
-rw-r--r--resources/views/statistics/other/places.phtml53
-rw-r--r--resources/views/statistics/other/top10-list.phtml19
-rw-r--r--resources/views/statistics/other/total-events.phtml38
-rw-r--r--resources/views/statistics/other/total-records.phtml52
34 files changed, 1247 insertions, 360 deletions
diff --git a/resources/views/modules/statistics-chart/families.phtml b/resources/views/modules/statistics-chart/families.phtml
index 9097fa3bd7..dbbab97f21 100644
--- a/resources/views/modules/statistics-chart/families.phtml
+++ b/resources/views/modules/statistics-chart/families.phtml
@@ -1,144 +1,12 @@
-<?php use Fisharebest\Webtrees\I18N; ?>
+<?php
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
-<h3>
- <?= I18N::translate('Total families: %s', $stats->totalFamilies()) ?>
-</h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Total marriages') ?></td>
- <td><?= I18N::translate('Total divorces') ?></td>
- </tr>
- <tr>
- <td><?= $stats->totalMarriages() ?></td>
- <td><?= $stats->totalDivorces() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Marriages by century') ?></td>
- <td><?= I18N::translate('Divorces by century') ?></td>
- </tr>
- <tr>
- <td><?= $stats->statsMarr() ?></td>
- <td><?= $stats->statsDiv() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Earliest marriage') ?></td>
- <td><?= I18N::translate('Earliest divorce') ?></td>
- </tr>
- <tr>
- <td><?= $stats->firstMarriage() ?></td>
- <td><?= $stats->firstDivorce() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Latest marriage') ?></td>
- <td><?= I18N::translate('Latest divorce') ?></td>
- </tr>
- <tr>
- <td><?= $stats->lastMarriage() ?></td>
- <td><?= $stats->lastDivorce() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Length of marriage') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Longest marriage'), ' - ', $stats->topAgeOfMarriage() ?></td>
- <td><?= I18N::translate('Shortest marriage'), ' - ', $stats->minAgeOfMarriage() ?></td>
- </tr>
- <tr>
- <td><?= $stats->topAgeOfMarriageFamily() ?></td>
- <td><?= $stats->minAgeOfMarriageFamily() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Age in year of marriage') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Youngest male'), ' - ', $stats->youngestMarriageMaleAge(true) ?></td>
- <td><?= I18N::translate('Youngest female'), ' - ', $stats->youngestMarriageFemaleAge(true) ?></td>
- </tr>
- <tr>
- <td><?= $stats->youngestMarriageMale() ?></td>
- <td><?= $stats->youngestMarriageFemale() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Oldest male'), ' - ', $stats->oldestMarriageMaleAge(true) ?></td>
- <td><?= I18N::translate('Oldest female'), ' - ', $stats->oldestMarriageFemaleAge(true) ?></td>
- </tr>
- <tr>
- <td><?= $stats->oldestMarriageMale() ?></td>
- <td><?= $stats->oldestMarriageFemale() ?></td>
- </tr>
- <tr>
- <td colspan="2"><?= $stats->statsMarrAge() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Age at birth of child') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Youngest father'), ' - ', $stats->youngestFatherAge(true) ?></td>
- <td><?= I18N::translate('Youngest mother'), ' - ', $stats->youngestMotherAge(true) ?></td>
- </tr>
- <tr>
- <td><?= $stats->youngestFather() ?></td>
- <td><?= $stats->youngestMother() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Oldest father'), ' - ', $stats->oldestFatherAge(true) ?></td>
- <td><?= I18N::translate('Oldest mother'), ' - ', $stats->oldestMotherAge(true) ?></td>
- </tr>
- <tr>
- <td><?= $stats->oldestFather() ?></td>
- <td><?= $stats->oldestMother() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Children in family') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Average number of children per family') ?></td>
- <td><?= I18N::translate('Number of families without children') ?></td>
- </tr>
- <tr>
- <td><?= $stats->averageChildren() ?></td>
- <td><?= $stats->noChildrenFamilies() ?></td>
- </tr>
- <tr>
- <td><?= $stats->statsChildren() ?></td>
- <td><?= $stats->chartNoChildrenFamilies() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Largest families') ?></td>
- <td><?= I18N::translate('Largest number of grandchildren') ?></td>
- </tr>
- <tr>
- <td><?= $stats->topTenLargestFamilyList() ?></td>
- <td><?= $stats->topTenLargestGrandFamilyList() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Age difference') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Age between siblings') ?></td>
- <td><?= I18N::translate('Greatest age between siblings') ?></td>
- </tr>
- <tr>
- <td><?= $stats->topAgeBetweenSiblingsList() ?></td>
- <td><?= $stats->topAgeBetweenSiblingsFullName() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Age between husband and wife') ?></td>
- <td><?= I18N::translate('Age between wife and husband') ?></td>
- </tr>
- <tr>
- <td><?= $stats->ageBetweenSpousesMFList() ?></td>
- <td><?= $stats->ageBetweenSpousesFMList() ?></td>
- </tr>
-</table>
+<div class="container pt-3">
+ <?= view('statistics/families/total-records', ['stats' => $stats]) ?>
+ <?= view('statistics/families/marriage-length', ['stats' => $stats]) ?>
+ <?= view('statistics/families/marriage-age', ['stats' => $stats]) ?>
+ <?= view('statistics/families/birth-age', ['stats' => $stats]) ?>
+ <?= view('statistics/families/children', ['stats' => $stats]) ?>
+ <?= view('statistics/families/age-difference', ['stats' => $stats]) ?>
+</div>
diff --git a/resources/views/modules/statistics-chart/individuals.phtml b/resources/views/modules/statistics-chart/individuals.phtml
index 7980441272..9fadb3c699 100644
--- a/resources/views/modules/statistics-chart/individuals.phtml
+++ b/resources/views/modules/statistics-chart/individuals.phtml
@@ -1,136 +1,14 @@
<?php use Fisharebest\Webtrees\I18N; ?>
-<h3>
- <?= I18N::translate('Total individuals: %s', $stats->totalIndividuals()) ?>
-</h3>
+<?php
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
-<table class="table table-sm table-bordered">
- <thead>
- <tr>
- <th><?= I18N::translate('Total males') ?></th>
- <th><?= I18N::translate('Total females') ?></th>
- <th><?= I18N::translate('Total living') ?></th>
- <th><?= I18N::translate('Total dead') ?></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><?= $stats->totalSexMales() ?></td>
- <td><?= $stats->totalSexFemales() ?></td>
- <td><?= $stats->totalLiving() ?></td>
- <td><?= $stats->totalDeceased() ?></td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <td colspan="2"><?= $stats->chartSex() ?></td>
- <td colspan="2"><?= $stats->chartMortality() ?></td>
- </tr>
- </tfoot>
-</table>
-
-<h3><?= I18N::translate('Events') ?></h3>
-
-<table class="table table-sm table-bordered">
- <tbody>
- <tr>
- <th><?= I18N::translate('Total births') ?></th>
- <th><?= I18N::translate('Total deaths') ?></th>
- </tr>
- <tr>
- <td><?= $stats->totalBirths() ?></td>
- <td><?= $stats->totalDeaths() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Births by century') ?></td>
- <td><?= I18N::translate('Deaths by century') ?></td>
- </tr>
- <tr>
- <td><?= $stats->statsBirth() ?></td>
- <td><?= $stats->statsDeath() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Earliest birth') ?></td>
- <td><?= I18N::translate('Earliest death') ?></td>
- </tr>
- <tr>
- <td><?= $stats->firstBirth() ?></td>
- <td><?= $stats->firstDeath() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Latest birth') ?></td>
- <td><?= I18N::translate('Latest death') ?></td>
- </tr>
- <tr>
- <td><?= $stats->lastBirth() ?></td>
- <td><?= $stats->lastDeath() ?></td>
- </tr>
- </tbody>
-</table>
-
-<h3><?= I18N::translate('Lifespan') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Average age at death') ?></td>
- <td><?= I18N::translate('Males') ?></td>
- <td><?= I18N::translate('Females') ?></td>
- </tr>
- <tr>
- <td><?= $stats->averageLifespan(true) ?></td>
- <td><?= $stats->averageLifespanMale(true) ?></td>
- <td><?= $stats->averageLifespanFemale(true) ?></td>
- </tr>
- <tr>
- <td colspan="3"><?= $stats->statsAge() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Greatest age at death') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Males') ?></td>
- <td><?= I18N::translate('Females') ?></td>
- </tr>
- <tr>
- <td><?= $stats->topTenOldestMaleList() ?></td>
- <td><?= $stats->topTenOldestFemaleList() ?></td>
- </tr>
-</table>
-
-<?php if ($show_oldest_living) : ?>
- <h3><?= I18N::translate('Oldest living individuals') ?></h3>
-
- <table>
- <tr>
- <td><?= I18N::translate('Males') ?></td>
- <td><?= I18N::translate('Females') ?></td>
- </tr>
- <tr>
- <td><?= $stats->topTenOldestMaleListAlive() ?></td>
- <td><?= $stats->topTenOldestFemaleListAlive() ?></td>
- </tr>
- </table>
-<?php endif ?>
-
-<h3><?= I18N::translate('Names') ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Total surnames') ?></td>
- <td><?= I18N::translate('Total given names') ?></td>
- </tr>
- <tr>
- <td><?= $stats->totalSurnames() ?></td>
- <td><?= $stats->totalGivennames() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Top surnames') ?></td>
- <td><?= I18N::translate('Top given names') ?></td>
- </tr>
- <tr>
- <td><?= $stats->chartCommonSurnames() ?></td>
- <td><?= $stats->chartCommonGiven() ?></td>
- </tr>
-</table>
+<div class="container pt-3">
+ <?= view('statistics/individuals/total-records', ['stats' => $stats]) ?>
+ <?= view('statistics/individuals/total-events', ['stats' => $stats]) ?>
+ <?= view('statistics/individuals/lifespan', ['stats' => $stats]) ?>
+ <?= view('statistics/individuals/greatest-age', ['stats' => $stats]) ?>
+ <?= view('statistics/individuals/oldest-living', ['stats' => $stats]) ?>
+ <?= view('statistics/individuals/names', ['stats' => $stats]) ?>
+</div>
diff --git a/resources/views/modules/statistics-chart/other.phtml b/resources/views/modules/statistics-chart/other.phtml
index d30979de96..d6e374e4a0 100644
--- a/resources/views/modules/statistics-chart/other.phtml
+++ b/resources/views/modules/statistics-chart/other.phtml
@@ -1,85 +1,12 @@
-<?php use Fisharebest\Webtrees\I18N; ?>
+<?php
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
-<h3>
- <?= I18N::translate('Records') ?>: <?= $stats->totalRecords() ?>
-</h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Media objects') ?></td>
- <td><?= I18N::translate('Sources') ?></td>
- <td><?= I18N::translate('Notes') ?></td>
- <td><?= I18N::translate('Repositories') ?></td>
- </tr>
- <tr>
- <td><?= $stats->totalMedia() ?></td>
- <td><?= $stats->totalSources() ?></td>
- <td><?= $stats->totalNotes() ?></td>
- <td><?= $stats->totalRepositories() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Total events'), ': ', $stats->totalEvents() ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('First event'), ' - ', $stats->firstEventType() ?></td>
- <td><?= I18N::translate('Last event'), ' - ', $stats->lastEventType() ?></td>
- </tr>
- <tr>
- <td><?= $stats->firstEvent() ?></td>
- <td><?= $stats->lastEvent() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Media objects'), ': ', $stats->totalMedia() ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Media objects') ?></td>
- </tr>
- <tr>
- <td><?= $stats->chartMedia() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Sources'), ': ', $stats->totalSources() ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Individuals with sources') ?></td>
- <td><?= I18N::translate('Families with sources') ?></td>
- </tr>
- <tr>
- <td><?= $stats->totalIndisWithSources() ?></td>
- <td><?= $stats->totalFamsWithSources() ?></td>
- </tr>
- <tr>
- <td><?= $stats->chartIndisWithSources() ?></td>
- <td><?= $stats->chartFamsWithSources() ?></td>
- </tr>
-</table>
-
-<h3><?= I18N::translate('Places'), ': ', $stats->totalPlaces() ?></h3>
-
-<table>
- <tr>
- <td><?= I18N::translate('Birth places') ?></td>
- <td><?= I18N::translate('Death places') ?></td>
- </tr>
- <tr>
- <td><?= $stats->commonBirthPlacesList() ?></td>
- <td><?= $stats->commonDeathPlacesList() ?></td>
- </tr>
- <tr>
- <td><?= I18N::translate('Marriage places') ?></td>
- <td><?= I18N::translate('Events in countries') ?></td>
- </tr>
- <tr>
- <td><?= $stats->commonMarriagePlacesList() ?></td>
- <td><?= $stats->commonCountriesList() ?></td>
- </tr>
- <tr>
- <td colspan="2"><?= $stats->chartDistribution() ?></td>
- </tr>
-</table>
+<div class="container pt-3">
+ <?= view('statistics/other/total-records', ['stats' => $stats]) ?>
+ <?= view('statistics/other/total-events', ['stats' => $stats]) ?>
+ <?= view('statistics/other/chart-objects', ['stats' => $stats]) ?>
+ <?= view('statistics/other/chart-sources', ['stats' => $stats]) ?>
+ <?= view('statistics/other/places', ['stats' => $stats]) ?>
+ <?= $stats->chartDistribution() ?>
+</div>
diff --git a/resources/views/statistics/families/age-difference.phtml b/resources/views/statistics/families/age-difference.phtml
new file mode 100644
index 0000000000..246770cb3e
--- /dev/null
+++ b/resources/views/statistics/families/age-difference.phtml
@@ -0,0 +1,55 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Age difference') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Age between siblings') ?>
+ </h5>
+ <?= $stats->topAgeBetweenSiblingsList() ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Greatest age between siblings') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->topAgeBetweenSiblingsFullName() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Age between husband and wife') ?>
+ </h5>
+ <?= $stats->ageBetweenSpousesMFList() ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Age between wife and husband') ?>
+ </h5>
+ <?= $stats->ageBetweenSpousesFMList() ?>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/families/birth-age.phtml b/resources/views/statistics/families/birth-age.phtml
new file mode 100644
index 0000000000..4635120b3f
--- /dev/null
+++ b/resources/views/statistics/families/birth-age.phtml
@@ -0,0 +1,61 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Age at birth of child') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Youngest father'), ' - ', $stats->youngestFatherAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->youngestFather() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Youngest mother'), ' - ', $stats->youngestMotherAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->youngestMother() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Oldest father'), ' - ', $stats->oldestFatherAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->oldestFather() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Oldest mother'), ' - ', $stats->oldestMotherAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->oldestMother() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/families/children.phtml b/resources/views/statistics/families/children.phtml
new file mode 100644
index 0000000000..f45f62405e
--- /dev/null
+++ b/resources/views/statistics/families/children.phtml
@@ -0,0 +1,59 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Children in family') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Average number of children per family') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->averageChildren() ?></span>
+ </h5>
+ <div class="card-body text-center">
+ <?= $stats->statsChildren() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Number of families without children') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->noChildrenFamilies() ?></span>
+ </h5>
+ <div class="card-body text-center">
+ <?= $stats->chartNoChildrenFamilies() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Largest families') ?>
+ </h5>
+ <?= $stats->topTenLargestFamilyList(); ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Largest number of grandchildren') ?>
+ </h5>
+ <?= $stats->topTenLargestGrandFamilyList(); ?>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/families/marriage-age.phtml b/resources/views/statistics/families/marriage-age.phtml
new file mode 100644
index 0000000000..fa8d52dbee
--- /dev/null
+++ b/resources/views/statistics/families/marriage-age.phtml
@@ -0,0 +1,71 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Age in year of marriage') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Youngest male'), ' - ', $stats->youngestMarriageMaleAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->youngestMarriageMale() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Youngest female'), ' - ', $stats->youngestMarriageFemaleAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->youngestMarriageFemale() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Oldest male'), ' - ', $stats->oldestMarriageMaleAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->oldestMarriageMale() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Oldest female'), ' - ', $stats->oldestMarriageFemaleAge('1') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->oldestMarriageFemale() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-lg-12 col-md-12 mb-3">
+ <div class="card m-0">
+ <div class="card-body text-center">
+ <?= $stats->statsMarrAge() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/families/marriage-length.phtml b/resources/views/statistics/families/marriage-length.phtml
new file mode 100644
index 0000000000..82813995d3
--- /dev/null
+++ b/resources/views/statistics/families/marriage-length.phtml
@@ -0,0 +1,37 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Length of marriage') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Longest marriage'), ' - ', $stats->topAgeOfMarriage() ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->topAgeOfMarriageFamily() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Shortest marriage'), ' - ', $stats->minAgeOfMarriage() ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->minAgeOfMarriageFamily() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/families/top10-list-age.phtml b/resources/views/statistics/families/top10-list-age.phtml
new file mode 100644
index 0000000000..9728c2422f
--- /dev/null
+++ b/resources/views/statistics/families/top10-list-age.phtml
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Individual;
+
+/* @var array $records */
+/* @var Family $family */
+/* @var Individual $child1 */
+/* @var Individual $child2 */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $child1 = $record['child1']; ?>
+ <?php $child2 = $record['child2']; ?>
+ <?php $family = $record['family']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <span>
+ <a href="<?= e($child2->url()) ?>"><?= $child2->getFullName() ?></a> <?= I18N::translate('and') ?> <a href="<?= e($child1->url()) ?>"><?= $child1->getFullName() ?></a>
+ <br>
+ <a href="<?= e($family->url()) ?>">[<?= I18N::translate('View this family') ?>]</a>
+ </span>
+ <span class="badge badge-secondary badge-pill ml-3"><?= $record['age'] ?></span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/families/top10-list-grand.phtml b/resources/views/statistics/families/top10-list-grand.phtml
new file mode 100644
index 0000000000..bb2c1c2f64
--- /dev/null
+++ b/resources/views/statistics/families/top10-list-grand.phtml
@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a>
+ <span class="badge badge-secondary badge-pill ml-3">
+ <?= I18N::plural('%s grandchild', '%s grandchildren', $record['count'], I18N::number($record['count'])) ?>
+ </span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/families/top10-list-spouses.phtml b/resources/views/statistics/families/top10-list-spouses.phtml
new file mode 100644
index 0000000000..3575f0eb8a
--- /dev/null
+++ b/resources/views/statistics/families/top10-list-spouses.phtml
@@ -0,0 +1,18 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a>
+ <span class="badge badge-secondary badge-pill ml-3"><?= $record['age'] ?></span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/families/top10-list.phtml b/resources/views/statistics/families/top10-list.phtml
new file mode 100644
index 0000000000..18e1fd470a
--- /dev/null
+++ b/resources/views/statistics/families/top10-list.phtml
@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a>
+ <span class="badge badge-secondary badge-pill ml-3">
+ <?= I18N::plural('%s child', '%s children', $record['count'], I18N::number($record['count'])) ?>
+ </span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/families/top10-nolist-age.phtml b/resources/views/statistics/families/top10-nolist-age.phtml
new file mode 100644
index 0000000000..13e008cad3
--- /dev/null
+++ b/resources/views/statistics/families/top10-nolist-age.phtml
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Individual;
+
+/* @var array $record */
+/* @var Family $family */
+/* @var Individual $child1 */
+/* @var Individual $child2 */
+?>
+
+<?php $child1 = $record['child1']; ?>
+<?php $child2 = $record['child2']; ?>
+<?php $family = $record['family']; ?>
+
+<?= $child2->formatList() ?>
+<br>
+<?= I18N::translate('and') ?>
+<br>
+<?= $child1->formatList() ?>
+<br>
+<a href="<?= e($family->url()) ?>">[<?= I18N::translate('View this family') ?>]</a>
diff --git a/resources/views/statistics/families/top10-nolist-grand.phtml b/resources/views/statistics/families/top10-nolist-grand.phtml
new file mode 100644
index 0000000000..6c58c6b868
--- /dev/null
+++ b/resources/views/statistics/families/top10-nolist-grand.phtml
@@ -0,0 +1,15 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a>
+ - <?= I18N::plural('%s grandchild', '%s grandchildren', $record['count'], I18N::number($record['count'])) ?>
+<?php endforeach; ?>
diff --git a/resources/views/statistics/families/top10-nolist-spouses.phtml b/resources/views/statistics/families/top10-nolist-spouses.phtml
new file mode 100644
index 0000000000..50a09aac07
--- /dev/null
+++ b/resources/views/statistics/families/top10-nolist-spouses.phtml
@@ -0,0 +1,13 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a> (<?= $record['age'] ?>)
+<?php endforeach; ?>
diff --git a/resources/views/statistics/families/top10-nolist.phtml b/resources/views/statistics/families/top10-nolist.phtml
new file mode 100644
index 0000000000..a60d371fec
--- /dev/null
+++ b/resources/views/statistics/families/top10-nolist.phtml
@@ -0,0 +1,15 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\I18N;
+
+/* @var array $records */
+/* @var Family $family */
+?>
+
+<?php foreach ($records as $record): ?>
+ <?php $family = $record['family']; ?>
+ <a href="<?= e($family->url()) ?>"><?= $family->getFullName() ?></a>
+ - <?= I18N::plural('%s child', '%s children', $record['count'], I18N::number($record['count'])) ?>
+<?php endforeach; ?>
diff --git a/resources/views/statistics/families/total-records.phtml b/resources/views/statistics/families/total-records.phtml
new file mode 100644
index 0000000000..e9b67e2806
--- /dev/null
+++ b/resources/views/statistics/families/total-records.phtml
@@ -0,0 +1,112 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Total families') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalFamilies() ?></span>
+</h4>
+
+<div class="mb-3">
+ <div class="row">
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total marriages') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalMarriages() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Marriages by century') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->statsMarr() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Earliest marriage') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->firstMarriage() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Latest marriage') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->lastMarriage() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total divorces') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalDivorces() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Divorces by century') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->statsDiv() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Earliest divorce') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->firstDivorce() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Latest divorce') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->lastDivorce() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/hit-count.phtml b/resources/views/statistics/hit-count.phtml
new file mode 100644
index 0000000000..cc015b6b7e
--- /dev/null
+++ b/resources/views/statistics/hit-count.phtml
@@ -0,0 +1,8 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+?>
+<span class="odometer">
+ <?= I18N::digits($count); ?>
+</span>
diff --git a/resources/views/statistics/individuals/greatest-age.phtml b/resources/views/statistics/individuals/greatest-age.phtml
new file mode 100644
index 0000000000..caaa6b0014
--- /dev/null
+++ b/resources/views/statistics/individuals/greatest-age.phtml
@@ -0,0 +1,33 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Greatest age at death') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Males') ?>
+ </h5>
+ <?= $stats->topTenOldestMaleList() ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Females') ?>
+ </h5>
+ <?= $stats->topTenOldestFemaleList() ?>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/individuals/lifespan.phtml b/resources/views/statistics/individuals/lifespan.phtml
new file mode 100644
index 0000000000..637ce7c2df
--- /dev/null
+++ b/resources/views/statistics/individuals/lifespan.phtml
@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Lifespan') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Average age at death') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->averageLifespan(true) ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Males') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->averageLifespanMale(true) ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Females') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->averageLifespanFemale(true) ?></span>
+ </h5>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="col-12 mb-3">
+ <div class="card m-0">
+ <div class="card-body text-center">
+ <?= $stats->statsAge() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/individuals/names.phtml b/resources/views/statistics/individuals/names.phtml
new file mode 100644
index 0000000000..bc00056b9a
--- /dev/null
+++ b/resources/views/statistics/individuals/names.phtml
@@ -0,0 +1,63 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Names') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="row">
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total surnames') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalSurnames() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Top surnames') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->chartCommonSurnames() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total given names') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalGivennames() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Top given names') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->chartCommonGiven() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/individuals/oldest-living.phtml b/resources/views/statistics/individuals/oldest-living.phtml
new file mode 100644
index 0000000000..288f6f934c
--- /dev/null
+++ b/resources/views/statistics/individuals/oldest-living.phtml
@@ -0,0 +1,33 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Oldest living individuals') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Males') ?>
+ </h5>
+ <?= $stats->topTenOldestMaleListAlive() ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Females') ?>
+ </h5>
+ <?= $stats->topTenOldestFemaleListAlive() ?>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/individuals/top10-list.phtml b/resources/views/statistics/individuals/top10-list.phtml
new file mode 100644
index 0000000000..c1a1d32330
--- /dev/null
+++ b/resources/views/statistics/individuals/top10-list.phtml
@@ -0,0 +1,18 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Individual;
+
+/* @var array $records */
+/* @var Individual $person */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $person = $record['person']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <a href="<?= e($person->url()) ?>"><?= $person->getFullName() ?></a>
+ <span class="badge badge-secondary badge-pill ml-3"><?= $record['age'] ?></span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/individuals/top10-nolist.phtml b/resources/views/statistics/individuals/top10-nolist.phtml
new file mode 100644
index 0000000000..e3e52d9a91
--- /dev/null
+++ b/resources/views/statistics/individuals/top10-nolist.phtml
@@ -0,0 +1,13 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\Individual;
+
+/* @var array $records */
+/* @var Individual $person */
+?>
+
+<?php foreach ($records as $record): ?>
+ <?php $person = $record['person']; ?>
+ <a href="<?= e($person->url()) ?>"><?= $person->getFullName() ?></a> (<?= $record['age'] ?>)
+<?php endforeach; ?>
diff --git a/resources/views/statistics/individuals/total-events.phtml b/resources/views/statistics/individuals/total-events.phtml
new file mode 100644
index 0000000000..c3e27cd0e8
--- /dev/null
+++ b/resources/views/statistics/individuals/total-events.phtml
@@ -0,0 +1,111 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Events') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="row">
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total births') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalBirths() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Births by century') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->statsBirth() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Earliest birth') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->firstBirth() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Latest birth') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->lastBirth() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total deaths') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalDeaths() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Deaths by century') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->statsDeath() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Earliest death') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->firstDeath() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Latest death') ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->lastDeath() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/individuals/total-records.phtml b/resources/views/statistics/individuals/total-records.phtml
new file mode 100644
index 0000000000..a28777ca23
--- /dev/null
+++ b/resources/views/statistics/individuals/total-records.phtml
@@ -0,0 +1,77 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Total individuals') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalIndividuals() ?></span>
+</h4>
+
+<div class="mb-3">
+ <div class="row">
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total males') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalSexMales() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total females') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalSexFemales() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <div class="card-body">
+ <?= $stats->chartSex() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6">
+ <div class="card-deck">
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total living') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalLiving() ?></span>
+ </h5>
+ </div>
+ </div>
+ <div class="mb-3 col-lg-12 col-md-6">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Total dead') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalDeceased() ?></span>
+ </h5>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-deck">
+ <div class="mb-3 col-12">
+ <div class="card m-0">
+ <div class="card-body">
+ <?= $stats->chartMortality() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/chart-distribution.phtml b/resources/views/statistics/other/chart-distribution.phtml
new file mode 100644
index 0000000000..fe75a0e30f
--- /dev/null
+++ b/resources/views/statistics/other/chart-distribution.phtml
@@ -0,0 +1,31 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= $chart_title ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 mb-3">
+ <div class="card m-0">
+ <div class="card-body">
+ <div id="google_charts" class="text-center">
+ <img src="<?= $chart_url ?>" alt="<?= $chart_title ?>" title="<?= $chart_title ?>" class="gchart" />
+ <br>
+ <table class="center">
+ <tr>
+ <td bgcolor="#<?= $chart_color2 ?>" width="12"></td><td><?= I18N::translate('Highest population') ?></td>
+ <td bgcolor="#<?= $chart_color3 ?>" width="12"></td><td><?= I18N::translate('Lowest population') ?></td>
+ <td bgcolor="#<?= $chart_color1 ?>" width="12"></td><td><?= I18N::translate('Nobody at all') ?></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/chart-google.phtml b/resources/views/statistics/other/chart-google.phtml
new file mode 100644
index 0000000000..5172f56d28
--- /dev/null
+++ b/resources/views/statistics/other/chart-google.phtml
@@ -0,0 +1 @@
+<img src="<?= $chart_url ?>" width="<?= $sizes[0] ?>" height="<?= $sizes[1] ?>" alt="<?= $chart_title ?>" title="<?= $chart_title ?>" />
diff --git a/resources/views/statistics/other/chart-objects.phtml b/resources/views/statistics/other/chart-objects.phtml
new file mode 100644
index 0000000000..df65296172
--- /dev/null
+++ b/resources/views/statistics/other/chart-objects.phtml
@@ -0,0 +1,23 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Media objects') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <div class="card-body">
+ <?= $stats->chartMedia() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/chart-sources.phtml b/resources/views/statistics/other/chart-sources.phtml
new file mode 100644
index 0000000000..720c1a119c
--- /dev/null
+++ b/resources/views/statistics/other/chart-sources.phtml
@@ -0,0 +1,39 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Sources') ?>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Individuals with sources') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalIndisWithSources() ?></span>
+ </h5>
+ <div class="card-body">
+ <?= $stats->chartIndisWithSources() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Families with sources') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalFamsWithSources() ?></span>
+ </h5>
+ <div class="card-body">
+ <?= $stats->chartFamsWithSources() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/places.phtml b/resources/views/statistics/other/places.phtml
new file mode 100644
index 0000000000..ef4a037fcb
--- /dev/null
+++ b/resources/views/statistics/other/places.phtml
@@ -0,0 +1,53 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Place;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Places') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalPlaces() ?></span>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Birth places') ?>
+ </h5>
+ <?= $stats->commonBirthPlacesList(); ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Death places') ?>
+ </h5>
+ <?= $stats->commonDeathPlacesList(); ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Marriage places') ?>
+ </h5>
+ <?= $stats->commonMarriagePlacesList(); ?>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Events in countries') ?>
+ </h5>
+ <?= $stats->commonCountriesList(); ?>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/top10-list.phtml b/resources/views/statistics/other/top10-list.phtml
new file mode 100644
index 0000000000..27d3638f1c
--- /dev/null
+++ b/resources/views/statistics/other/top10-list.phtml
@@ -0,0 +1,19 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Place;
+
+/* @var array $records */
+/* @var Place $place */
+?>
+
+<ul class="list-group list-group-flush">
+ <?php foreach ($records as $record): ?>
+ <?php $place = $record['place']; ?>
+ <li class="list-group-item d-flex justify-content-between align-items-center">
+ <a href="<?= e($place->url()) ?>"><?= $place->fullName() ?></a>
+ <span class="badge badge-secondary badge-pill ml-3"><?= I18N::number($record['count']) ?></span>
+ </li>
+ <?php endforeach; ?>
+</ul>
diff --git a/resources/views/statistics/other/total-events.phtml b/resources/views/statistics/other/total-events.phtml
new file mode 100644
index 0000000000..776f1857f7
--- /dev/null
+++ b/resources/views/statistics/other/total-events.phtml
@@ -0,0 +1,38 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Total events') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalEvents() ?></span>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('First event'), ' - ', $stats->firstEventType() ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->firstEvent() ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-12 col-md-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header">
+ <?= I18N::translate('Last event'), ' - ', $stats->lastEventType() ?>
+ </h5>
+ <div class="card-body">
+ <?= $stats->lastEvent() ?>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/resources/views/statistics/other/total-records.phtml b/resources/views/statistics/other/total-records.phtml
new file mode 100644
index 0000000000..4c90246412
--- /dev/null
+++ b/resources/views/statistics/other/total-records.phtml
@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+
+use Fisharebest\Webtrees\I18N;
+
+/** @var \Fisharebest\Webtrees\Stats $stats */
+?>
+
+<h4 class="border-bottom p-2 mb-4">
+ <?= I18N::translate('Records') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalRecords() ?></span>
+</h4>
+
+<div class="mb-3">
+ <div class="card-deck">
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Media objects') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalMedia() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Sources') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalSources() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Notes') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalNotes() ?></span>
+ </h5>
+ </div>
+ </div>
+
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card m-0">
+ <h5 class="card-header border-bottom-0">
+ <?= I18N::translate('Repositories') ?>
+ <span class="badge badge-secondary badge-pill float-right"><?= $stats->totalRepositories() ?></span>
+ </h5>
+ </div>
+ </div>
+ </div>
+</div>