Skip to content

Instantly share code, notes, and snippets.

@fpassaniti
Created May 22, 2020 08:44
Show Gist options
  • Select an option

  • Save fpassaniti/73cba539f829c705bc49370fc13d1bf1 to your computer and use it in GitHub Desktop.

Select an option

Save fpassaniti/73cba539f829c705bc49370fc13d1bf1 to your computer and use it in GitHub Desktop.
Template listing generator
<div ng-app="ods-widgets">
<div class="container"
ng-init="domainid = 'discovery';
datasetid = 'oeuvres-de-johannes-vermeer';
filters = ['technique','collection','genre'];
view = 'cards';
fieldsList = ['titre','collection','genre','format','date'];
fieldLink = 'wikipedia';
fieldLinkLabel = 'Lire l\'article';
cardTitle = 'titre';
fieldPhoto = 'image';
imagePosition = 'left';
itemsPerRow = '2';
kpis = [
{
'title': 'Taille moyenne',
'function': 'AVG',
'expression': 'surface',
'precision': 2,
'unit': 'm2',
'faicon': 'fa-square-o'
},
{
'title': 'Nombre d\'oeuvre référencées',
'function': 'COUNT'
}
];
DO_NOT_MODIFY_BELOW;
ctxfields = {}
">
<!-- ### GENERAL SETTINGS ### -->
<!-- domainid : (Domain ID) : Must contain the ID of the domain where the dataset is published.
ex: 'discovery'
-->
<!-- datasetid (Dataset ID) : Must contain the ID of the dataset
ex: 'oeuvres-de-johannes-vermeer'
-->
<!-- ### FILTERS SETTINGS ### -->
<!-- filters (Filters) : List of field IDs to generate the filters pannel.
NB: the field must be a facet in the dataset
NB: alphanumerical sort is applied in the filter view
ex: ['technique','collection','genre']
-->
<!-- ### LIST VIEW SETTINGS ### -->
<!-- view (List view type) : Type of the view to list results, can be 'table' or 'cards'
-->
<!-- fieldsList (List configuration) : Set the list of field IDs
ex: ['title','category','genre','date']
-->
<!-- fieldLink (Link to an external resource) : If available, the field ID of some external resource as a web URL
ex: 'link'
-->
<!-- fieldLinkLabel (The label of that link) : Label of the link button
ex: 'Read more here'
-->
<!-- Specificly to the 'cards' view mode, set a title and a background image if any -->
<!-- cardTitle (Title of the card) : Field id of the card title
ex: 'title'
-->
<!-- fieldPhoto (Field id of the image field if any)
ex: 'image'
-->
<!-- imagePosition (Image position) : Image position in the card, can be 'top' or 'left'
ex: 'left'
-->
<!-- itemsPerRow (Number of columns) : Modify the columns layout. The division by 12 must be a whole number, ie it can be 1, 2, 3, 4, 6 or 12. But 6 and 12 will generaly be two norrow
ex: '3'
-->
<!-- ### KPIS SETTINGS ### -->
<!-- KPIS settings is a list of object that describes each KPI
List of available keys are :
- title (Name of the KPI) ex: 'Average # of citizens'
- function (function of the aggregation) ex: 'SUM'
- expression (field id that contains numerical values to aggregate) ex: 'population'
- precision (Decimal precision of the KPI) ex: 2
- unit (KPI unit) ex: 'citizens'
- faicon (FontAwesome icon id) ex: 'fa-square-o'
title, function, expression are MANDATORY
the others are optionnal
ex:
kpis = [
{
'title': 'Taille moyenne',
'function': 'AVG',
'expression': 'surface',
'precision': 2,
'unit': 'm2',
'faicon': 'fa-square-o'
},
{
'title': 'Nombre d\'oeuvre référencées',
'function': 'COUNT'
}
];
-->
<!-- MUST READ
A common error is forget to protect commas with a leading backslash, as commas are used to declare values of variable it will break the settings
wrongVariable = 'I'll be freed from commas'
correctVariable = 'I\'ll be freed from commas'
-->
<!-- DO NOT MODIFY -->
<!-- Technical fields, do not modify please -->
<h1 class="page-title">
Oeuvres de Johannes Vermeer
</h1>
<p class="page-subtitle">
Johannes ou Jan Van der Meer, dit Vermeer ou Vermeer de Delft, baptisé à Delft le 31 octobre 1632, et inhumé dans cette même ville le 15 décembre 1675, est un peintre baroque néerlandais (Provinces-Unies).
<br/>
Découvrez une sélection de ses oeuvres, misent en avant avec la plateforme Opendatasoft.
<br/>
<a href="https://discovery.opendatasoft.com/explore/dataset/oeuvres-de-johannes-vermeer/images/"
target="_blanck">Accéder au jeu de données source</a>
</p>
<ods-dataset-context context="ctx"
ctx-domain="{{ domainid }}"
ctx-dataset="{{ datasetid }}">
<span ng-repeat="field in ctx.dataset.fields">
{{ ctxfields[field.name] = field.label; '' }}
</span>
<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 -->
<div class="filter-list"
ng-init="dropdown.open = '';
select = {}">
<div ng-repeat="filter in filters">
{{ ctx.parameters['disjunctive.' + filter] = true; '' }}
<div ods-facet-results="categories"
ods-facet-results-facet-name="{{ filter }}"
ods-facet-results-context="ctx"
ods-facet-results-sort="alphanum">
<div class="dropdown"
ng-if="categories">
<button ng-click="dropdown.open = (dropdown.open == filter ? '' : filter);"
ng-class="{'dropdown-button-active': select[filter],
'dropdown-button-open': dropdown.open == filter}"
id="dropdown-button"
class="dropdown-button"
aria-haspopup="true"
aria-expanded="{{ dropdown.open == filter }}">
{{ (!select[filter] ? ctxfields[filter] : select[filter] | capitalize) }}
</button>
<div class="dropdown-menu"a
ng-class="{'dropdown-visible' : dropdown.open == filter }"
aria-labelledby="dropdown-button">
<div class="dropdown-title">
{{ ctxfields[filter] }}
</div>
<ul class="dropdown-items">
<li class="dropdown-item">
<label class="dropdown-label">
<input ng-model="select[filter]"
ng-value="Tous"
type="radio"
class="dropdown-input" />
Tous
</label>
</li>
<li ng-repeat="category in categories"
class="dropdown-item">
<label class="dropdown-label"
title="{{ category.path | capitalize }}">
<input ng-model="select[filter]"
ng-value="category.path"
class="dropdown-input"
type="radio" />
{{ category.path | capitalize }}
</label>
</li>
</ul>
{{ ctx.parameters['refine.' + filter] = (select[filter]=='Tous'?undefined:select[filter]); ''}}
</div>
<div class="dropdown-backdrop"
ng-click="dropdown.open = ''"
ng-show="dropdown.open != ''"></div>
</div>
</div>
</div>
</div>
</div>
<!-- KPIs -->
<section class="kpis-container row row-equal-height">
<div class="{{ 'col-md-' + (12/itemsPerRow) }} margin-bottom-20"
ng-repeat="kpi in kpis">
<!-- KPI box component -->
<div class="kpi-card"
ods-aggregation="agg"
ods-aggregation-context="ctx"
ods-aggregation-function="{{ kpi.function }}"
ods-aggregation-expression="{{ kpi.expression }}">
<i class="kpi-icon fa {{ kpi.faicon || 'fa-gitlab' }}" aria-hidden="true"></i>
<h2 class="kpi-title">
{{ agg | number : (kpi.precision || 0) }}
<span ng-if="kpi.unit" class="kpi-unit">{{ kpi.unit }}</span>
</h2>
<p class="kpi-description">
{{ kpi.title }}
</p>
</div>
</div>
</section>
<!-- TABLE -->
<section ng-if="view == 'table'"
class="content-card">
<div class="table-module">
<table class="table-basic"
ods-results="items"
ods-results-context="ctx"
ods-results-max="20">
<thead>
<tr>
<th ng-repeat="field in fieldsList">{{ ctxfields[field] }}</th>
<th ng-if="fieldLink"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td ng-repeat="field in fieldsList"
style="max-width: calc(100vh / {{ fieldsList.length }});"
title="{{ item.fields[field] }}">
{{ item.fields[field] }}
</td>
<td ng-if="fieldLink">
<a href="{{ item.fields[fieldLink] }}"
tilte="{{ fieldLinkLabel }}"
target="_blanck"
class="table-dropdown-button">
<i class="fa fa-external-link"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- CARDS -->
<section ng-if="view == 'cards'">
<div class="row row-equal-height"
ods-results="items"
ods-results-context="ctx"
ods-results-max="{{ 8 * itemsPerRow }}">
<div ng-repeat="item in items"
class="{{ 'col-md-' + (12/itemsPerRow) }} margin-bottom-20">
<div class="content-card"
ng-class="{'content-card-horizontal': imagePosition === 'left' }">
<div class="content-card-img"
ng-if="item.fields[fieldPhoto]"
style="{{ 'background-image: url(https://' + domainid + '.opendatasoft.com/explore/dataset/' + datasetid + '/files/' + item.fields[fieldPhoto].id + '/300/);' }}">
</div>
<div class="content-card-body">
<h2 class="content-card-title text-center">
{{ item.fields[cardTitle] }}
</h2>
<div class="content-card-fields">
<dl>
<dt ng-repeat-start="field in fieldsList">{{ ctxfields[field] }}</dt>
<dd ng-repeat-end>{{ item.fields[field] }}</dd>
</dl>
</div>
<div ng-if="fieldLink" class="text-center">
<a href="{{ item.fields[fieldLink] }}"
target="_blanck"
class="content-card-button">
{{ fieldLinkLabel }}
</a>
</div>
</div>
</div>
</div>
</div>
</section>
</ods-dataset-context>
</div>
</div>
/* Codepen specific */
html {
--links: #0088CC;
--page-background: #FFFFFF;
--header-links: #FFFFFF;
--titles: #1E0C33;
--section-titles: #FFFFFF;
--highlight: #EC643C;
--footer-links: #0088CC;
--boxes-border: #E5E5E5;
--boxes-background: #FFFFFF;
--header-background: #1E0C33;
--footer-background: #FFFFFF;
--text: #333333;
--section-titles-background: #1E0C33;
}
body {
margin: 4rem 0;
background-color: hsla(225, 10%, 98%, 1);
}
/* 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)
}
/* Dropdown menu with pill styling
========================================================================== */
.filter-list {
display: flex;
flex-wrap: wrap;
}
.dropdown {
display: inline-block;
margin: 13px 0 0 0;
position: relative;
}
/* Button */
.dropdown-button {
font-size: 1rem;
color: var(--text);
border: 1px solid #cbd2db;
border-radius: 2rem;
background: #FFFFFF;
padding: .37rem 1rem;
margin-right: 6px;
transition: all .2s;
}
.dropdown-button:hover,
.dropdown-button:focus {
color: var(--links);
border-color: var(--links);
}
.dropdown-button-open {
border-color: var(--links);
box-shadow: 0 0 0 3px rgba(20, 46, 123, .2);
}
.dropdown-button-active {
color: var(--links);
border-color: var(--links);
background-color: rgba(20, 46, 123, 0.1);
}
/* Dropdown styling */
.dropdown-menu {
background-color: #FFFFFF;
border: 1px solid #dee5ef;
border-radius: 4px;
box-shadow: 0px 2px 4px rgba(0,0,0,0.15);
max-width: 350px;
overflow-x: auto;
visibility: hidden;
opacity: 0;
position: absolute;
top: 0;
z-index: 11;
white-space: nowrap;
transition: visibility 0s, opacity 0.1s ease, top 0.1s ease;
}
.dropdown-visible {
opacity: 1;
visibility: visible;
top: 38px;
}
/* Dropdown items */
.dropdown-menu {
padding: 26px 0;
}
.dropdown-title {
font-size: 1.3rem;
color: var(--text);
font-weight: normal;
margin-top: 0;
margin-bottom: 0;
padding: 0 26px;
}
.dropdown-items {
list-style: none;
padding: 0 26px;
margin: 0;
display: flex;
flex-direction: column;
max-height: 180px;
overflow-y: auto;
}
.dropdown-item {
font-size: 1rem;
display: block;
margin-top: 13px;
}
.dropdown-item:hover {
text-decoration: none;
}
.dropdown-input {
margin-right: 4px;
}
.dropdown-label {
display: block;
margin-bottom: 0;
cursor: pointer;
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
padding-left: 2px;
}
/* Backdrop */
.dropdown-backdrop {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
cursor: auto;
z-index: 10;
}
/* 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-horizontal {
display: flex;
}
.content-card-horizontal .content-card-img {
height: auto;
flex: 0 0 25%;
width: 25%;
border-radius: 4px 0 0 4px;
}
.content-card-img {
display: block;
height: 110px;
background-position: center;
background-size: cover;
}
.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%;
}
/* Table Module Basic
========================================================================== */
.table-module {
height: 1000px;
overflow-y: auto;
}
.table-basic {
display: table;
border-collapse: collapse;
width: 100%;
white-space: nowrap;
background-color: #FFFFFF;
margin-bottom: 20px;
}
.table-basic thead th {
color: var(--titles);
background-color: #f6f8fb;
font-weight: 500;
padding: 13px 3px;
position: sticky;
top: 0;
z-index: 1;
}
.table-basic thead th:first-child,
.table-basic tbody td:first-child {
padding-left: 13px;
}
.table-basic tr td,
.table-basic tbody th {
font-weight: normal;
border-top: 1px solid #dee5ef;
}
.table-basic tr td {
padding: 13px 3px;
}
.table-basic td {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.table-dropdown-button {
width: 28px;
height: 28px;
padding: 0;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
background: white;
border: 1px solid transparent;
border-radius: 4px;
margin-left: auto;
}
.table-basic tr:hover .table-dropdown-button {
border-color: var(--highlight);
text-decoration: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet" />
<link href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4124551/ods.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment