Merge pull request #10525 from colinux/stats-dark
Pages stats au DSFR, déclinées en thème sombre et adaptées aux mobiles
This commit is contained in:
commit
d7f953f08c
7 changed files with 186 additions and 292 deletions
|
@ -1,162 +1,13 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
$dark-grey: #333333;
|
||||
$light-grey: #999999;
|
||||
|
||||
$default-space: 15px;
|
||||
|
||||
$new-h1-margin-bottom: 4 * $default-space;
|
||||
$new-h2-margin-bottom: 3 * $default-space;
|
||||
|
||||
.new-h1,
|
||||
.new-h2 {
|
||||
color: $dark-grey;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.new-h1 {
|
||||
margin-bottom: 3.75rem;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.new-h2 {
|
||||
margin-bottom: $new-h2-margin-bottom;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
$statistiques-padding-top: $default-space * 2;
|
||||
|
||||
.statistiques {
|
||||
width: 1040px;
|
||||
margin: 0 auto;
|
||||
padding-top: $statistiques-padding-top;
|
||||
}
|
||||
|
||||
.stat-cards {
|
||||
.stat-card:nth-of-type(even) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
$stat-card-margin-bottom: 3 * $default-space;
|
||||
|
||||
.stat-card {
|
||||
padding: 15px;
|
||||
margin-bottom: $stat-card-margin-bottom;
|
||||
border-radius: 5px;
|
||||
box-shadow: none;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
$stat-card-half-horizontal-spacing: 4 * $default-space;
|
||||
|
||||
.stat-card-half {
|
||||
width: calc((100% - #{$stat-card-half-horizontal-spacing}) / 2);
|
||||
margin-right: $stat-card-half-horizontal-spacing;
|
||||
}
|
||||
|
||||
.stat-card-title {
|
||||
color: $dark-grey;
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.stat-card-details {
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
$segmented-control-margin-top: $default-space;
|
||||
|
||||
.segmented-control {
|
||||
border-radius: 36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
font-size: 0;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
margin-top: $segmented-control-margin-top;
|
||||
}
|
||||
|
||||
$segmented-control-item-horizontal-padding: $default-space;
|
||||
$segmented-control-item-border-radius: 2 * $default-space;
|
||||
|
||||
.segmented-control-item {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
border: 2px solid $blue-france-700;
|
||||
margin-right: -2px;
|
||||
padding-top: var(--li-bottom);
|
||||
padding-left: $segmented-control-item-horizontal-padding;
|
||||
padding-right: $segmented-control-item-horizontal-padding;
|
||||
color: $blue-france-700;
|
||||
|
||||
&:first-of-type {
|
||||
border-radius: $segmented-control-item-border-radius 0px 0px $segmented-control-item-border-radius;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-radius: 0px $segmented-control-item-border-radius $segmented-control-item-border-radius 0px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $blue-france-500;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.segmented-control-item-active {
|
||||
background-color: $blue-france-700;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
margin-top: 36px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
$big-number-card-padding: 2 * $segmented-control-item-border-radius;
|
||||
|
||||
.big-number-card {
|
||||
padding: $big-number-card-padding $segmented-control-item-horizontal-padding;
|
||||
}
|
||||
|
||||
.big-number-card-title {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 20px;
|
||||
color: $light-grey;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.long-title {
|
||||
margin-left: -30px;
|
||||
margin-right: -30px;
|
||||
}
|
||||
}
|
||||
|
||||
.big-number-card-number {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 80px;
|
||||
line-height: 1em;
|
||||
font-size: 4.5rem;
|
||||
line-height: 1.5em;
|
||||
font-weight: bold;
|
||||
color: $blue-france-500;
|
||||
color: var(--text-title-blue-france);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.big-number-card-detail {
|
||||
display: block;
|
||||
margin-top: $default-padding;
|
||||
text-align: center;
|
||||
color: $blue-france-500;
|
||||
}
|
||||
|
|
|
@ -1,44 +1,43 @@
|
|||
import { Controller } from '@hotwired/stimulus';
|
||||
import { toggle, delegate } from '@utils';
|
||||
import Highcharts from 'highcharts';
|
||||
import Chartkick from 'chartkick';
|
||||
|
||||
export class ChartkickController extends Controller {
|
||||
async connect() {
|
||||
delegate('click', '[data-toggle-chart]', (event) =>
|
||||
toggleChart(event as MouseEvent)
|
||||
);
|
||||
}
|
||||
}
|
||||
import Highcharts from 'highcharts';
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
Chartkick.use(Highcharts);
|
||||
function reflow(nextChartId?: string) {
|
||||
nextChartId && Chartkick.charts[nextChartId]?.getChartObject()?.reflow();
|
||||
}
|
||||
|
||||
function toggleChart(event: MouseEvent) {
|
||||
const nextSelectorItem = event.target as HTMLButtonElement,
|
||||
chartClass = nextSelectorItem.dataset.toggleChart,
|
||||
nextChart = chartClass
|
||||
? document.querySelector<HTMLDivElement>(chartClass)
|
||||
: undefined,
|
||||
nextChartId = nextChart?.children[0]?.id,
|
||||
currentSelectorItem = nextSelectorItem.parentElement?.querySelector(
|
||||
'.segmented-control-item-active'
|
||||
),
|
||||
currentChart =
|
||||
nextSelectorItem.parentElement?.parentElement?.querySelector<HTMLDivElement>(
|
||||
'.chart:not(.hidden)'
|
||||
export default class ChartkickController extends Controller {
|
||||
static targets = ['chart'];
|
||||
|
||||
declare readonly chartTargets: HTMLElement[];
|
||||
|
||||
toggleChart(event: Event) {
|
||||
const target = event.currentTarget as HTMLInputElement;
|
||||
const chartClass = target.dataset.toggleChart;
|
||||
|
||||
invariant(chartClass, 'Missing data-toggle-chart attribute');
|
||||
|
||||
const nextChart = document.querySelector(chartClass);
|
||||
const currentChart = this.chartTargets.find(
|
||||
(chart) => !chart.classList.contains('hidden')
|
||||
);
|
||||
|
||||
// Change the current selector and the next selector states
|
||||
currentSelectorItem?.classList.toggle('segmented-control-item-active');
|
||||
nextSelectorItem.classList.toggle('segmented-control-item-active');
|
||||
if (currentChart) {
|
||||
currentChart.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Hide the currently shown chart and show the new one
|
||||
currentChart && toggle(currentChart);
|
||||
nextChart && toggle(nextChart);
|
||||
if (nextChart) {
|
||||
nextChart.classList.remove('hidden');
|
||||
const nextChartId = nextChart.children[0]?.id;
|
||||
this.reflow(nextChartId);
|
||||
}
|
||||
}
|
||||
|
||||
// Reflow needed, see https://github.com/highcharts/highcharts/issues/1979
|
||||
reflow(nextChartId);
|
||||
reflow(chartId: string) {
|
||||
if (chartId) {
|
||||
const chart = Chartkick.charts[chartId];
|
||||
if (chart) {
|
||||
chart.getChartObject()?.reflow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
@import '@gouvfr/dsfr/dist/component/modal/modal.css';
|
||||
@import '@gouvfr/dsfr/dist/component/navigation/navigation.css';
|
||||
@import '@gouvfr/dsfr/dist/component/notice/notice.css';
|
||||
@import '@gouvfr/dsfr/dist/component/segmented/segmented.css';
|
||||
@import '@gouvfr/dsfr/dist/component/table/table.css';
|
||||
@import '@gouvfr/dsfr/dist/component/tile/tile.css';
|
||||
@import '@gouvfr/dsfr/dist/component/tag/tag.css';
|
||||
|
|
|
@ -1,45 +1,56 @@
|
|||
.statistiques{ 'data-controller': 'chartkick' }
|
||||
%h1.new-h1= title
|
||||
.stat-cards
|
||||
.fr-container.fr-my-4w
|
||||
%h1= title
|
||||
.fr-grid-row.fr-grid-row--gutters
|
||||
- if @usual_traitement_time.present?
|
||||
.stat-card.big-number-card
|
||||
%span.big-number-card-title= t('.usual_processing_time')
|
||||
.fr-col-xs-12
|
||||
.fr-callout
|
||||
%h2.fr-callout__title= t('.usual_processing_time')
|
||||
= render Procedure::EstimatedDelayComponent.new(procedure: @procedure)
|
||||
|
||||
.stat-cards
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title= t('.processing_time')
|
||||
.stat-card-details= t('.since_procedure_creation')
|
||||
.chart-container
|
||||
.chart
|
||||
- colors = %w(#C3D9FF #0069CC #1C7EC9) # from _colors.scss
|
||||
= column_chart @usual_traitement_time_by_month, ytitle: t('.nb_days'), legend: "bottom", label: t('.processing_time_graph_description')
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout{ data: { controller: 'chartkick' } }
|
||||
%h2.fr-callout__title= t('.processing_time')
|
||||
%p.fr-callout__text.fr-text--md= t('.since_procedure_creation')
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title= t('.status_evolution')
|
||||
.stat-card-details= t('.status_evolution_details')
|
||||
.chart-container
|
||||
.chart
|
||||
= area_chart @dossiers_funnel, ytitle: t('.dossiers_count'), label: t('.dossiers_count')
|
||||
.fr-mt-4w
|
||||
.chart-procedures-chart{ data: { 'chartkick-target': 'chart' } }
|
||||
= column_chart @usual_traitement_time_by_month,
|
||||
library: Chartkick.options[:default_library_config],
|
||||
ytitle: t('.nb_days'), legend: "bottom", label: t('.processing_time_graph_description')
|
||||
|
||||
.stat-cards
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title= t('.acceptance_rate')
|
||||
.stat-card-details= t('.acceptance_rate_details')
|
||||
.chart-container
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout
|
||||
%h2.fr-callout__title= t('.status_evolution')
|
||||
%p.fr-callout__text.fr-text--md= t('.status_evolution_details')
|
||||
|
||||
.fr-mt-4w
|
||||
.chart
|
||||
= area_chart @dossiers_funnel,
|
||||
library: Chartkick.options[:default_library_config],
|
||||
ytitle: t('.dossiers_count'), label: t('.dossiers_count')
|
||||
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout
|
||||
%h2.fr-callout__title= t('.acceptance_rate')
|
||||
%p.fr-callout__text.fr-text--md= t('.acceptance_rate_details')
|
||||
|
||||
.fr-mt-4w
|
||||
.chart
|
||||
= pie_chart @termines_states,
|
||||
library: Chartkick.options[:default_library_config],
|
||||
code: true,
|
||||
colors: %w(#387EC3 #AE2C2B #FAD859),
|
||||
colors: ["var(--background-flat-success)", "var(--background-flat-error)", "#FAD859" ],
|
||||
label: t('.rate'),
|
||||
suffix: '%',
|
||||
library: { plotOptions: { pie: { dataLabels: { enabled: true, format: '{point.name} : {point.percentage: .1f}%' } } } }
|
||||
suffix: '%'
|
||||
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout
|
||||
%h2.fr-callout__title= t('.weekly_distribution')
|
||||
%p.fr-callout__text.fr-text--md= t('.weekly_distribution_details')
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title= t('.weekly_distribution')
|
||||
.stat-card-details= t('.weekly_distribution_details')
|
||||
.chart-container
|
||||
.fr-mt-4w
|
||||
.chart
|
||||
= line_chart @termines_by_week, colors: ["#387EC3", "#AE2C2B", "#FAD859"], ytitle: t('.dossiers_count')
|
||||
.clearfix
|
||||
= line_chart @termines_by_week,
|
||||
library: Chartkick.options[:default_library_config],
|
||||
colors: ["var(--background-flat-success)", "var(--background-flat-error)", "#FAD859" ],
|
||||
ytitle: t('.dossiers_count')
|
||||
|
|
|
@ -2,71 +2,75 @@
|
|||
- content_for :footer do
|
||||
= render partial: "root/footer"
|
||||
|
||||
.statistiques{ 'data-controller': 'chartkick' }
|
||||
%h1.new-h1 Statistiques
|
||||
.fr-container.fr-my-4w
|
||||
%h1 Statistiques d’utilisation de la plateforme
|
||||
|
||||
.stat-cards
|
||||
.stat-card.stat-card-half.big-number-card.pull-left
|
||||
%span.big-number-card-title.long-title TOTAL DÉMARCHES DÉMAT. OU EN COURS DE DÉMAT.
|
||||
%span.big-number-card-number
|
||||
= number_with_delimiter(@procedures_numbers[:total])
|
||||
%span.big-number-card-detail
|
||||
.fr-grid-row.fr-grid-row--gutters
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout{ data: { controller: 'chartkick' } }
|
||||
%h2.fr-callout__title Démarches dématérialisées (total)
|
||||
%p.fr-callout__text.big-number-card-number.fr-mb-2w
|
||||
%span.big-number-card-number= number_with_delimiter(@procedures_numbers[:total])
|
||||
%p.fr-callout__text.fr-text--md.text-center
|
||||
#{number_with_delimiter(@procedures_numbers[:last_30_days_count])} (#{@procedures_numbers[:evolution]} %) sur les 30 derniers jours
|
||||
%span.big-number-card-detail
|
||||
%br
|
||||
= link_to "Voir carte de déploiement", carte_path
|
||||
|
||||
.stat-card.stat-card-half.big-number-card.pull-left
|
||||
%span.big-number-card-title TOTAL DOSSIERS DÉPOSÉS
|
||||
%span.big-number-card-number
|
||||
%fieldset.fr-segmented.fr-segmented--sm.pull-right.fr-mt-2w.fr-my-1w
|
||||
.fr-segmented__elements
|
||||
.fr-segmented__element
|
||||
%input{ value: "1", checked: true, type: "radio", id: "segmented-procedures-1", name: "segmented-procedures", data: { action: 'chartkick#toggleChart', 'toggle-chart': '.monthly-procedures-chart' } }
|
||||
%label.fr-label{ for: "segmented-procedures-1" }
|
||||
Par mois
|
||||
.fr-segmented__element
|
||||
%input{ value: "2", type: "radio", id: "segmented-procedures-2", name: "segmented-procedures", data: { action: 'chartkick#toggleChart', 'toggle-chart': '.cumulative-procedures-chart' } }
|
||||
%label.fr-label{ for: "segmented-procedures-2" }
|
||||
Cumul
|
||||
|
||||
.fr-mt-4w
|
||||
.chart.monthly-procedures-chart{ data: { 'chartkick-target': 'chart' } }
|
||||
= column_chart @procedures_in_the_last_4_months, library: Chartkick.options[:default_library_config]
|
||||
.chart.cumulative-procedures-chart.hidden{ data: { 'chartkick-target': 'chart' } }
|
||||
= area_chart @procedures_cumulative, library: Chartkick.options[:default_library_config]
|
||||
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout{ data: { controller: 'chartkick' } }
|
||||
%h2.fr-callout__title Dossiers déposés (total)
|
||||
%p.fr-callout__text.big-number-card-number.fr-mb-2w
|
||||
= number_with_delimiter(@dossiers_numbers[:total])
|
||||
%span.big-number-card-detail
|
||||
%p.fr-callout__text.fr-text--md.text-center
|
||||
#{number_with_delimiter(@dossiers_numbers[:last_30_days_count])} (#{@dossiers_numbers[:evolution]} %) sur les 30 derniers jours
|
||||
%span.big-number-card-detail
|
||||
%br
|
||||
= link_to "Voir carte de déploiement", carte_path(map_filter: { kind: :nb_dossiers })
|
||||
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%ul.segmented-control.pull-right
|
||||
%li.segmented-control-item.segmented-control-item-active{ data: { 'toggle-chart': '.monthly-procedures-chart' } }
|
||||
%fieldset.fr-segmented.fr-segmented--sm.pull-right.fr-mt-2w.fr-my-1w
|
||||
.fr-segmented__elements
|
||||
.fr-segmented__element
|
||||
%input{ value: "1", checked: true, type: "radio", id: "segmented-dossiers-1", name: "segmented-dossiers", data: { action: 'chartkick#toggleChart', 'toggle-chart': '.monthly-dossiers-chart' } }
|
||||
%label.fr-label{ for: "segmented-dossiers-1" }
|
||||
Par mois
|
||||
%li.segmented-control-item{ data: { 'toggle-chart': '.cumulative-procedures-chart' } }
|
||||
.fr-segmented__element
|
||||
%input{ value: "2", type: "radio", id: "segmented-dossiers-2", name: "segmented-dossiers", data: { action: 'chartkick#toggleChart', 'toggle-chart': '.cumulative-dossiers-chart' } }
|
||||
%label.fr-label{ for: "segmented-dossiers-2" }
|
||||
Cumul
|
||||
%span.stat-card-title.pull-left Démarches dématérialisées
|
||||
.clearfix
|
||||
|
||||
.chart-container
|
||||
.chart.monthly-procedures-chart
|
||||
= column_chart @procedures_in_the_last_4_months
|
||||
.chart.cumulative-procedures-chart.hidden
|
||||
= area_chart @procedures_cumulative
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%ul.segmented-control.pull-right
|
||||
%li.segmented-control-item.segmented-control-item-active{ data: { 'toggle-chart': '.monthly-dossiers-chart' } }
|
||||
Par mois
|
||||
%li.segmented-control-item{ data: { 'toggle-chart': '.cumulative-dossiers-chart' } }
|
||||
Cumul
|
||||
%span.stat-card-title.pull-left Dossiers déposés
|
||||
.clearfix
|
||||
.fr-mt-4w
|
||||
.chart.monthly-dossiers-chart{ data: { 'chartkick-target': 'chart' } }
|
||||
= column_chart @dossiers_in_the_last_4_months, library: Chartkick.options[:default_library_config]
|
||||
.chart.cumulative-dossiers-chart.hidden{ data: { 'chartkick-target': 'chart' } }
|
||||
= area_chart @dossiers_cumulative, library: Chartkick.options[:default_library_config]
|
||||
|
||||
.chart-container
|
||||
.chart.monthly-dossiers-chart
|
||||
= column_chart @dossiers_in_the_last_4_months
|
||||
.chart.cumulative-dossiers-chart.hidden
|
||||
= area_chart @dossiers_cumulative
|
||||
.fr-col-xs-12.fr-col-sm-12.fr-col-lg-6
|
||||
.fr-callout
|
||||
%h2.fr-callout__title Répartition des dossiers
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title
|
||||
Répartition des dossiers
|
||||
|
||||
.chart-container
|
||||
.fr-mt-4w
|
||||
.chart
|
||||
= pie_chart @dossiers_states_for_pie,
|
||||
= pie_chart @dossiers_states_for_pie, library: Chartkick.options[:default_library_config],
|
||||
colors: ["#000091", "#7F7FC8", "#9A9AFF", "#00006D"]
|
||||
|
||||
.clearfix
|
||||
|
||||
- if super_admin_signed_in?
|
||||
%h2.new-h2 Téléchargement
|
||||
%h2.fr-h4 Téléchargement
|
||||
|
||||
= link_to "Télécharger les statistiques (CSV)", stats_download_path(format: :csv), class: 'fr-btn fr-btn-primary mb-4'
|
||||
= link_to "Télécharger les statistiques (CSV)", stats_download_path(format: :csv), class: 'fr-btn fr-btn-primary fr-mb-4w'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#contact-form
|
||||
.container
|
||||
%h1.new-h1
|
||||
%h1
|
||||
= t('.contact_team')
|
||||
|
||||
.description
|
||||
|
|
|
@ -1,6 +1,34 @@
|
|||
Chartkick.options = {
|
||||
content_for: :charts_js,
|
||||
colors: ["#000091"],
|
||||
colors: ["var(--background-action-high-blue-france)"],
|
||||
thousands: ' ',
|
||||
decimal: ','
|
||||
decimal: ',',
|
||||
default_library_config: {
|
||||
chart: { backgroundColor: 'var(--background-contrast-grey)' },
|
||||
xAxis: {
|
||||
lineColor: 'var(--border-action-high-grey)',
|
||||
labels: { style: { color: "var(--text-default-grey)" } }
|
||||
},
|
||||
yAxis: {
|
||||
gridLineColor: 'var(--border-plain-grey)',
|
||||
lineColor: 'var(--border-action-high-grey)',
|
||||
labels: { style: { color: "var(--text-default-grey)" } }
|
||||
},
|
||||
legend: {
|
||||
itemStyle: {
|
||||
color: "var(--text-default-grey)"
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
dataLabels: {
|
||||
color: "var(--text-default-grey)",
|
||||
enabled: true, format: '{point.name} : {point.percentage: .1f}%',
|
||||
style: {
|
||||
textOutline: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue