Listing page
This template is an alternative to the automated Listing Generator. It offers more customization possibilities to advanced users who would like to add or remove items to this template, or reuse some blocks on another page.
This ressource integrates the following widgets:
ods-select
to create the filters on text fields. Resource available hereods-date-range-slider
to create the date selector. Resource available hereods-aggregation
to create KPI. Resource available hereods-results
to list the content of the records from the dataset. Resource available here
Dataset in use: rappel-conso
(See it on userclub domain)
Fields in use:
nature_juridique_du_rappel | categorie_de_produit | distributeurs | date_de_publication_de_la_fiche | noms_des_modeles_ou_references | motif_du_rappel | risques_encourus_par_le_consommateur | nom_de_la_marque_du_produit | lien_vers_l_affichette_pdf |
---|---|---|---|---|---|---|---|---|
Volontaire | Alimentation | Magasins BIO et détaillants, pharmacies et sites internet | 2021-04-01 | MORINGA MADIA BIO | Présence possible d’oxyde d’éthylène. | Autres contaminants chimiques | MADIA BIO | http://rappel.conso.gouv.fr/affichettePDF/123/Interne |
Volontaire | Bébés-Enfants (hors alimentaire) | Voir liste magasins. | 2021-04-01 | Jeu de bowling, référence 167924 | Rappel préventif : Risque de détachement de la partie supérieure des quilles pouvant occasionner un étouffement. | Arrêt respiratoire | BeToys | http://rappel.conso.gouv.fr/affichettePDF/130/Interne |
Imposé par l’administration | Alimentation | Silva alimentation | 2021-04-01 | Thé minceur Emagrecimento Dom duarte | Plantes dangereuses pour la santé | Additifs et arômes dépassement des seuils de sécurité Présence de substance interdite | Dom Duarte | http://rappel.conso.gouv.fr/affichettePDF/193/Interne |
Imposé par l’administration | Alimentation | Leclerc Geispolsheim, Leclerc express Illkirch et Leclerc express Holtzheim | 2021-04-01 | Pains et fougasses maison (cf liste) | Risque de présence éventuelle de corps étrangers | Inertes (verre, métal, plastique, papier, textile…) | Sans marque | http://rappel.conso.gouv.fr/affichettePDF/247/Interne |
<div class="container">
<ods-dataset-context context="ctx,ctxdate" ctx-domain="userclub.opendatasoft.com" ctx-dataset="rappel-conso"
ctxdate-domain="userclub.opendatasoft.com" ctxdate-dataset="rappel-conso"
ctx-parameters="{'sort':'date_de_publication_de_la_fiche','disjunctive.nature_juridique_du_rappel':'true','disjunctive.distributeurs':'true','disjunctive.categorie_de_produit':'true'}">
<h1 class="page-title">Rappel conso</h1>
<p class="page-subtitle">
Le jeu de données du site rappel-conso comprend la liste des fiches de rappels publiées sur le site
rappel-conso.
</p>
<div class="content-card search-module-container">
<!-- SEARCH -->
<div class="search-module">
<i class="fa fa-search search-module-icon" aria-hidden="true"></i>
<input placeholder="Rechercher" ng-model="ctx.parameters['q']"
ng-model-options="{ updateOn: 'keyup', debounce: { 'default': 300, 'blur': 0 }}"
class="search-module-input" type="text" />
<button class="search-module-clear" ng-if="ctx.parameters['q']"
ng-click="ctx.parameters['q'] = undefined">
<i class="fa fa-times-circle" aria-hidden="true"></i>
</button>
</div>
<!-- FILTERS Search & Select -->
<div class="filter-list" ng-init="dropdown.open = ''">
<div ods-facet-results="naturejuridique" ods-facet-results-facet-name="nature_juridique_du_rappel"
ods-facet-results-context="ctx" ods-facet-results-sort="alphanum">
<ods-select ng-if="naturejuridique"
selected-values="ctx.parameters['refine.nature_juridique_du_rappel']" multiple="false"
options="naturejuridique" label-modifier="name" value-modifier="name"
placeholder="Sélectionnez une nature juridique"></ods-select>
</div>
<div ods-facet-results="categorie" ods-facet-results-facet-name="categorie_de_produit"
ods-facet-results-context="ctx" ods-facet-results-sort="alphanum">
<ods-select ng-if="categorie" selected-values="ctx.parameters['refine.categorie_de_produit']"
multiple="true" options="categorie" label-modifier="name" value-modifier="name"
placeholder="Sélectionnez une catégorie"></ods-select>
</div>
<div ods-facet-results="distributeurs" ods-facet-results-facet-name="distributeurs"
ods-facet-results-context="ctx" ods-facet-results-sort="alphanum">
<ods-select ng-if="distributeurs" selected-values="ctx.parameters['refine.distributeurs']"
multiple="true" options="distributeurs" label-modifier="name" value-modifier="name"
placeholder="Sélectionnez un distributeur"></ods-select>
</div>
<div class="clear-filters"
ng-show="ctx.parameters['refine.categorie_de_produit'].length >0 || ctx.parameters['refine.distributeurs'].length >0 || ctx.parameters['refine.nature_juridique_du_rappel'].length >0">
<div class="clear-filters-button" role="button" ng-click="ctx.parameters['refine.categorie_de_produit'] = undefined;
ctx.parameters['refine.distributeurs'] = undefined;
ctx.parameters['refine.nature_juridique_du_rappel'] = undefined">
Supprimer tous les filtres
<i class="fa fa-times-circle" aria-hidden="true"></i>
</div>
</div>
</div>
<!-- FILTERS date -->
<div class="filter-date"
ng-init="bounds = {'min':undefined, 'max':undefined, 'minselection':undefined, 'maxselection':undefined}">
<!--
Get the date range
If the day or month is on 1 digit (ie. < 10), it is right justified with a 0 padding.
dateminmax[0] is the first date (oldest)
dateminmax[dateminmax.results.length-1] is the last date (newest / biggest)
-->
<span ods-analysis="dateminmax" ods-analysis-context="ctxdate"
ods-analysis-x-year="date_de_publication_de_la_fiche.year"
ods-analysis-x-month="date_de_publication_de_la_fiche.month"
ods-analysis-x-day="date_de_publication_de_la_fiche.day" ods-analysis-serie-c="COUNT()"
ods-analysis-sort="x.date_de_publication_de_la_fiche.year,x.date_de_publication_de_la_fiche.month,x.date_de_publication_de_la_fiche.day">
<span ng-if="dateminmax.results && dateminmax.results.length > 0">
{{ bounds['min'] = dateminmax.results[0].x.year + '-' + (10 >
dateminmax.results[0].x.month?'0':'') + dateminmax.results[0].x.month + '-' +
(10 > dateminmax.results[0].x.day?'0':'') + dateminmax.results[0].x.day;
bounds['max'] = dateminmax.results[dateminmax.results.length-1].x.year + '-' +
(10 > dateminmax.results[dateminmax.results.length-1].x.month?'0':'') +
dateminmax.results[dateminmax.results.length-1].x.month + '-' + (10 >
dateminmax.results[dateminmax.results.length-1].x.day?'0':'') +
dateminmax.results[dateminmax.results.length-1].x.day; ''}}
</span>
</span>
<ods-date-range-slider ng-if="bounds.min && bounds.max" context="ctx" initial-from="{{ bounds.min }}"
initial-to="{{ bounds.max }}" start-bound="bounds.min" end-bound="bounds.max"
date-field="date_de_publication_de_la_fiche" precision="day" from="bounds.minselection"
to="bounds.maxselection">
</ods-date-range-slider>
<!-- Resetting the range by setting widget "from" and "to" to the min/max bounds computed with ods-analysis -->
<div ng-if="bounds.min && bounds.max" class="filter-date-button" ng-class="{'filter-date-button-disabled':
bounds.minselection == bounds.min &&
bounds.maxselection == bounds.max}"
ng-click="bounds.minselection = bounds.min; bounds.maxselection = bounds.max">
Toute la période <i class="fa fa-arrows-h" aria-hidden="true"></i>
</div>
</div>
</div>
<!-- KPIs -->
<section class="kpis-container row row-equal-height">
<div class="col-md-4 margin-bottom-20">
<!-- KPI box component -->
<div class="kpi-card" ods-aggregation="total" ods-aggregation-context="ctx"
ods-aggregation-function="COUNT">
<i class="kpi-icon fa fa-calendar" aria-hidden="true"></i>
<p class="kpi-title">{{ (total || 0) | number : 0 }}</p>
<p class="kpi-description">Nombre de rappels</p>
</div>
</div>
</section>
<!-- CARDS -->
<section>
<div class="row row-equal-height" ods-results="items" ods-results-context="ctx" ods-results-max="12">
<div ng-repeat="item in items" class="col-md-6 margin-bottom-20">
<div class="content-card">
<div class="content-card-img"
style="{{'background-image: url(https://userclub.opendatasoft.com/explore/dataset/rappel-conso/files/' + item.fields.lien_vers_la_liste_des_images.id + '/300/);' }}">
</div>
<div class="content-card-body">
<h2 class="content-card-title text-center">
{{ item.fields.noms_des_modeles_ou_references }}
</h2>
<div class="content-card-fields">
<dl>
<dt>Motif du rappel</dt>
<dd>{{item.fields.motif_du_rappel}}</dd>
<dt>Risques</dt>
<dd>{{item.fields.risques_encourus_par_le_consommateur}}</dd>
<dt>Marque</dt>
<dd>{{item.fields.nom_de_la_marque_du_produit}}</dd>
<dt>Catégorie</dt>
<dd>{{item.fields.categorie_de_produit}}</dd>
<dt>Distributeur</dt>
<dd>{{item.fields.distributeurs}}</dd>
<dt>Nature juridique du rappel</dt>
<dd>{{item.fields.nature_juridique_du_rappel}}</dd>
<dt>Date de publication de la fiche</dt>
<dd>
{{item.fields.date_de_publication_de_la_fiche | moment : 'DD/MM/YYYY'}}
</dd>
</dl>
</div>
<div class="text-center">
<a href="{{item.fields.lien_vers_l_affichette_pdf}}" target="_blank"
class="content-card-button">
Lien vers l'affichette
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<a href="https://userclub.opendatasoft.com/explore/dataset/rappel-conso/" target="_blank"
class="margin-bottom-20">Voir les données</a>
</ods-dataset-context>
</div>
/* General Layout
========================================================================== */
:root {
--secondary-color: black;
}
main {
margin: 6rem 0 3em 0;
}
@media screen and (min-width: 992px) {
.row-equal-height {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-bottom: 20px;
}
/* Fix for early content wrapping in Safari*/
.row-equal-height:before,
.row-equal-height:after {
content: normal;
}
}
.page-title {
font-size: 3rem;
font-weight: bold;
margin-top: 0;
margin-bottom: 1rem;
}
.page-subtitle {
font-size: 1.2rem;
line-height: 2;
margin-top: 0;
margin-bottom: 3rem;
}
.margin-bottom-20 {
margin-bottom: 20px;
}
/* Search Module
========================================================================== */
.search-module-container {
padding: 26px;
margin-bottom: 20px;
}
.search-module {
display: flex;
align-items: stretch;
border-bottom: 1px solid #dee5ef;
margin-bottom: 13px;
transition: all .2s;
}
.search-module:hover,
.search-module:focus-within {
border-bottom-color: var(--links);
}
.search-module-icon {
color: #898d92;
margin-right: 8px;
align-self: center;
}
.search-module-input {
background-color: transparent;
width: 100%;
outline: none;
border: none;
padding: 12px 0;
transition: all .2s;
color: var(--text);
}
.search-module-input::placeholder {
transition: all .2s;
}
.search-module-clear {
color: #898d92;
font-size: 1rem;
background: transparent;
border: none;
margin: 0;
outline: none;
padding: 0 0 0 12px;
transition: all .2s;
}
.search-module-clear:hover {
opacity: .65;
}
.search-module:hover .search-module-icon,
.search-module:focus-within .search-module-icon,
.search-module:hover .search-module-input::placeholder,
.search-module:focus-within .search-module-input::placeholder {
color: var(--links)
}
/* Filters
========================================================================== */
.filter-list {
display: flex;
flex-wrap: wrap;
position: relative;
}
.filter-list>* {
margin: 0 0 10px;
width: 100%;
}
.odswidget-select .odswidget-select-dropdown.open .odswidget-select-dropdown-menu {
width: 100%
}
.clear-filters {
display: flex;
align-items: center;
justify-content: center;
}
.clear-filters-button:hover {
opacity: 0.65;
}
.odswidget-select,
.odswidget-select .odswidget-select-dropdown {
width: 100%;
}
@media screen and (min-width: 500px) {
.filter-list>* {
margin: 0 10px 10px 0;
width: inherit;
}
.odswidget-select .odswidget-select-dropdown.open .odswidget-select-dropdown-menu {
width: max-content;
min-width: 240px;
}
}
/*********** Filter date ************/
.filter-date {
display: flex;
flex-direction: column;
align-items: center;
margin: 13px 26px 32px 26px;
}
.odswidget-date-range-slider {
width: 100%;
}
.filter-date-button {
margin-left: 0;
margin-top: 13px;
white-space: nowrap;
text-decoration: underline;
}
.filter-date-button:not(.filter-date-button-disabled):hover {
opacity: 0.65;
}
.filter-date-button-disabled {
opacity: 0.5;
pointer-event: none;
text-decoration: none;
}
@media screen and (min-width: 500px) {
.filter-date {
flex-direction: row;
}
.filter-date-button {
margin-left: 50px;
margin-top: 0;
}
}
/* date range slider style override */
.odswidget-date-range-slider .irs--flat .irs-from,
.odswidget-date-range-slider .irs--flat .irs-single,
.odswidget-date-range-slider .irs--flat .irs-to {
color: var(--text);
border: 1px solid #cbd2db;
border-radius: 2rem;
background: #FFFFFF;
}
.odswidget-date-range-slider .irs--flat .irs-from:before,
.odswidget-date-range-slider .irs--flat .irs-single:before,
.odswidget-date-range-slider .irs--flat .irs-to:before {
border-top-color: var(--text);
}
.odswidget-date-range-slider .irs--flat .irs-bar {
background-color: var(--highlight);
}
.odswidget-date-range-slider .irs--flat .irs-handle>i:first-child {
background-color: var(--highlight);
}
.odswidget-date-range-slider .irs--flat .irs-handle.state_hover>i:first-child,
.odswidget-date-range-slider .irs--flat .irs-handle:hover>i:first-child {
background-color: var(--text);
}
/* Content Card
========================================================================== */
.content-card {
background-color: var(--boxes-background);
border-radius: 4px;
height: 100%;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.13);
}
.content-card-img {
display: block;
height: 110px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
.content-card-body {
padding: 26px;
flex: 1 1 auto;
}
.content-card-title {
color: var(--titles);
font-size: 1.2rem;
line-height: 1.5;
font-weight: normal;
margin-top: 0;
margin-bottom: 13px;
max-width: 100%;
}
.content-card-description {
color: var(--text);
font-size: 1rem;
line-height: 1.5;
font-weight: normal;
margin-top: 0;
margin-bottom: 26px;
max-width: 100%;
}
.content-card-fields dt {
font-size: 0.8rem;
opacity: 0.8;
}
.content-card-fields dd {
margin-left: 0;
}
.content-card-icon {
color: var(--highlight);
font-size: 2rem;
margin-bottom: 13px;
max-width: 100%;
}
.content-card-link {
color: var(--links);
font-weight: bold;
transition: all .2s;
opacity: 1;
max-width: 100%;
}
.content-card-link:hover {
opacity: .7;
text-decoration: none;
}
.content-card-button {
color: var(--highlight);
border: 1px solid var(--highlight);
background: transparent;
display: inline-block;
text-align: center;
font-size: .867rem;
border-radius: 4px;
padding: .5rem 1.15rem;
text-decoration: none;
transition: all .2s;
}
.content-card-button:hover {
background-color: var(--highlight);
color: #FFFFFF;
text-decoration: none;
}
/* KPI Card
========================================================================== */
@media screen and (min-width: 992px) {
.kpis-container {
display: flex;
justify-content: center;
}
}
.kpi-card {
background-color: var(--boxes-background);
height: 100%;
padding: 39px;
border-radius: 4px;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.13);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
text-align: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
text-align: center;
}
.kpi-icon {
color: var(--highlight);
color: var(--secondary-color);
font-size: 4rem;
margin-top: 0;
margin-bottom: 13px;
max-width: 100%;
}
.kpi-title {
font-weight: normal;
color: var(--highlight);
font-size: 3.2rem;
margin-top: 0;
margin-bottom: 13px;
max-width: 100%;
}
.kpi-unit {
font-size: 0.8em;
color: var(--secondary-color);
}
.kpi-description {
color: var(--text);
font-size: 1rem;
line-height: 1.5;
font-weight: normal;
margin-top: 0;
margin-bottom: 0;
max-width: 100%;
}
/** Specific override for custom views **/
@media screen and (min-width: 1408px) {
.ods-dataset-visualization .ods-tabs__pane .container:not(.is-max-desktop):not(.is-max-widescreen) {
max-width: 100%;
}
}
@media screen and (min-width: 1216px) {
.ods-dataset-visualization .ods-tabs__pane .container:not(.is-max-desktop) {
max-width: 100%;
}
}
@media screen and (min-width: 1024px) {
.ods-dataset-visualization .ods-tabs__pane .container {
max-width: 100%;
}
}