Commit a1a1b70c authored by Jean-Baptiste Nizet's avatar Jean-Baptiste Nizet Committed by Exbrayat Cédric
Browse files

feat: implement styling

parent 8bbe24fb
...@@ -11,7 +11,7 @@ Its unique argument (institute) is an InstituteVO ...@@ -11,7 +11,7 @@ Its unique argument (institute) is an InstituteVO
<th:block th:fragment="institute(institute)"> <th:block th:fragment="institute(institute)">
<div class="text-center py-2" th:if="${institute.logo}"> <div class="text-center py-2" th:if="${institute.logo}">
<img th:src="${institute.logo}" th:alt="${institute.instituteName}"/> <img class="img-fluid" th:src="${institute.logo}" th:alt="${institute.instituteName}"/>
</div> </div>
<div th:replace="fragments/row::text-row(label='Code', text=${institute.instituteCode})"></div> <div th:replace="fragments/row::text-row(label='Code', text=${institute.instituteCode})"></div>
<div th:replace="fragments/row::text-row(label='Acronym', text=${institute.acronym})"></div> <div th:replace="fragments/row::text-row(label='Acronym', text=${institute.acronym})"></div>
......
...@@ -10,7 +10,7 @@ to display ...@@ -10,7 +10,7 @@ to display
--> -->
<div th:fragment="map" id="map-container" class="d-none"> <div th:fragment="map" id="map-container" class="d-none">
<div id="map" class="border rounded"></div> <div id="map" class="border rounded"></div>
<div class="map-legend mt-1"> <div class="map-legend mt-1 small">
<img th:src="@{/assets/images/marker-icon-red.png}" id="red"/> <img th:src="@{/assets/images/marker-icon-red.png}" id="red"/>
<label for="red" class="me-2">Origin site</label> <label for="red" class="me-2">Origin site</label>
<img th:src="@{/assets/images/marker-icon-blue.png}" id="blue"/> <img th:src="@{/assets/images/marker-icon-blue.png}" id="blue"/>
......
...@@ -19,7 +19,7 @@ into a block with the condition: ...@@ -19,7 +19,7 @@ into a block with the condition:
</th:block> </th:block>
--> -->
<div th:fragment="row(label, content)" class="row py-2"> <div th:fragment="row(label, content)" class="row f-row">
<div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div> <div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div>
<div class="col"> <div class="col">
<th:block th:replace="${content}" /> <th:block th:replace="${content}" />
...@@ -40,7 +40,7 @@ into a block with the condition: ...@@ -40,7 +40,7 @@ into a block with the condition:
<div th:replace="fragments/row::text-row(label='Some label', text=${someTextExpression})"></div> <div th:replace="fragments/row::text-row(label='Some label', text=${someTextExpression})"></div>
</th:block> </th:block>
--> -->
<div th:fragment="text-row(label, text)" th:unless="${#strings.isEmpty(text)}" class="row py-2"> <div th:fragment="text-row(label, text)" th:unless="${#strings.isEmpty(text)}" class="row f-row">
<div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div> <div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div>
<div class="col" th:text="${text}"></div> <div class="col" th:text="${text}"></div>
</div> </div>
......
...@@ -16,7 +16,7 @@ The entityType argument is a string, which is used in the message ...@@ -16,7 +16,7 @@ The entityType argument is a string, which is used in the message
<th:block th:if="${source != null}"> <th:block th:if="${source != null}">
<div th:replace="fragments/row::row(label='Source', content=~{::.source})"> <div th:replace="fragments/row::row(label='Source', content=~{::.source})">
<a class="source" target="_blank" th:href="${source.url}"> <a class="source" target="_blank" th:href="${source.url}">
<img style="max-height: 60px;" th:src="${source.image}" th:alt="${source.name} + ' logo'" /> <img class="img-fluid" style="max-height: 60px;" th:src="${source.image}" th:alt="${source.name} + ' logo'" />
</a> </a>
</div> </div>
</th:block> </th:block>
......
...@@ -9,12 +9,11 @@ Reusable fragment displaying a cross references section, with its title. ...@@ -9,12 +9,11 @@ Reusable fragment displaying a cross references section, with its title.
The unique argument (crossReferences) is a List<XRefDocumentVO> The unique argument (crossReferences) is a List<XRefDocumentVO>
--> -->
<div th:fragment="xrefs(crossReferences)" th:if="${!#lists.isEmpty(crossReferences)}"> <div class="f-card" th:fragment="xrefs(crossReferences)" th:if="${!#lists.isEmpty(crossReferences)}">
<h2>Cross references</h2> <h2>Cross references</h2>
<div class="f-card-body">
<div class="table-responsive scroll-big-table table-card-body"> <div class="scroll-table-container scroll-table-container-big">
<div class="card"> <table class="table table-sm table-striped table-sticky table-responsive-sm">
<table class="table table-sm table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col">Name</th> <th scope="col">Name</th>
...@@ -28,13 +27,12 @@ The unique argument (crossReferences) is a List<XRefDocumentVO> ...@@ -28,13 +27,12 @@ The unique argument (crossReferences) is a List<XRefDocumentVO>
<td><a th:href="${crossRef.url}" target="_blank" th:text="${crossRef.name}"></a></td> <td><a th:href="${crossRef.url}" target="_blank" th:text="${crossRef.name}"></a></td>
<td th:text="${crossRef.databaseName}"></td> <td th:text="${crossRef.databaseName}"></td>
<td th:text="${crossRef.entryType}"></td> <td th:text="${crossRef.entryType}"></td>
<td th:text="${#strings.abbreviate(crossRef.description, 120)}"></td> <td style="min-width: 30rem;" th:text="${#strings.abbreviate(crossRef.description, 120)}"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
</body> </body>
......
...@@ -12,18 +12,17 @@ ...@@ -12,18 +12,17 @@
</head> </head>
<body> <body>
<div class="container"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<header> <div class="container">
Common header <span class="navbar-brand py-0">
</header> <img th:src="@{/assets/images/logo.png}" style="height: 40px"/>
</span>
</div>
</nav>
<div class="container mt-3">
<div th:replace="${content}"> <div th:replace="${content}">
<p>Layout content</p> <p>Layout content</p>
</div> </div>
<footer>
common footer
</footer>
</div> </div>
<script type="text/javascript" th:src="@{/assets/script.js}"></script> <script type="text/javascript" th:src="@{/assets/script.js}"></script>
<script type="text/javascript" th:replace="${script}"></script> <script type="text/javascript" th:replace="${script}"></script>
......
...@@ -15,48 +15,55 @@ ...@@ -15,48 +15,55 @@
<div th:replace="fragments/map::map"></div> <div th:replace="fragments/map::map"></div>
<th:block th:if="${model.site.uri != null && !model.site.uri.startsWith('urn:')}"> <div class="f-card mt-4">
<div th:replace="fragments/row::text-row(label='Permanent unique identifier', text=${model.site.uri})"></div> <h2>Details</h2>
</th:block> <div class="f-card-body">
<th:block th:if="${model.site.uri != null && !model.site.uri.startsWith('urn:')}">
<div th:replace="fragments/row::text-row(label='Permanent unique identifier', text=${model.site.uri})"></div>
</th:block>
<div th:replace="fragments/source::source(source=${model.source}, url=${model.site.url}, entityType='site')"></div> <div th:replace="fragments/source::source(source=${model.source}, url=${model.site.url}, entityType='site')"></div>
<div th:replace="fragments/row::text-row(label='Abbreviation', text=${model.site.abbreviation})"></div> <div th:replace="fragments/row::text-row(label='Abbreviation', text=${model.site.abbreviation})"></div>
<div th:replace="fragments/row::text-row(label='Type', text=${model.site.locationType})"></div> <div th:replace="fragments/row::text-row(label='Type', text=${model.site.locationType})"></div>
<div th:replace="fragments/row::text-row(label='Status', text=${model.siteStatus})"></div> <div th:replace="fragments/row::text-row(label='Status', text=${model.siteStatus})"></div>
<div th:replace="fragments/row::text-row(label='Institution/Landowner', text=${model.site.instituteName})"></div> <div th:replace="fragments/row::text-row(label='Institution/Landowner', text=${model.site.instituteName})"></div>
<div th:replace="fragments/row::text-row(label='Institution address', text=${model.site.instituteAddress})"></div> <div th:replace="fragments/row::text-row(label='Institution address', text=${model.site.instituteAddress})"></div>
<div th:replace="fragments/row::text-row(label='Coordinates precision', text=${model.coordinatesPrecision})"></div> <div th:replace="fragments/row::text-row(label='Coordinates precision', text=${model.coordinatesPrecision})"></div>
<th:block th:if="${model.site.latitude}"> <th:block th:if="${model.site.latitude}">
<div th:replace="fragments/row::text-row(label='Latitude', text=${#coordinates.formatLatitude(model.site.latitude)})"></div> <div th:replace="fragments/row::text-row(label='Latitude', text=${#coordinates.formatLatitude(model.site.latitude)})"></div>
</th:block> </th:block>
<th:block th:if="${model.site.longitude}"> <th:block th:if="${model.site.longitude}">
<div th:replace="fragments/row::text-row(label='Longitude', text=${#coordinates.formatLongitude(model.site.longitude)})"></div> <div th:replace="fragments/row::text-row(label='Longitude', text=${#coordinates.formatLongitude(model.site.longitude)})"></div>
</th:block> </th:block>
<div th:replace="fragments/row::text-row(label='Geographical location', text=${model.geographicalLocation})"></div> <div th:replace="fragments/row::text-row(label='Geographical location', text=${model.geographicalLocation})"></div>
<th:block th:if="${model.site.countryName != null && model.geographicalLocation == null}"> <th:block th:if="${model.site.countryName != null && model.geographicalLocation == null}">
<div th:replace="fragments/row::text-row(label='Country name', text=${model.site.countryName})"></div> <div th:replace="fragments/row::text-row(label='Country name', text=${model.site.countryName})"></div>
</th:block> </th:block>
<th:block th:if="${model.site.countryCode != null && model.geographicalLocation == null}"> <th:block th:if="${model.site.countryCode != null && model.geographicalLocation == null}">
<div th:replace="fragments/row::text-row(label='Country code', text=${model.site.countryName})"></div> <div th:replace="fragments/row::text-row(label='Country code', text=${model.site.countryName})"></div>
</th:block> </th:block>
<div th:replace="fragments/row::text-row(label='Altitude', text=${model.site.altitude})"></div> <div th:replace="fragments/row::text-row(label='Altitude', text=${model.site.altitude})"></div>
<div th:replace="fragments/row::text-row(label='Slope', text=${model.slope})"></div> <div th:replace="fragments/row::text-row(label='Slope', text=${model.slope})"></div>
<div th:replace="fragments/row::text-row(label='Exposure', text=${model.exposure})"></div> <div th:replace="fragments/row::text-row(label='Exposure', text=${model.exposure})"></div>
<div th:replace="fragments/row::text-row(label='Topography', text=${model.topography})"></div> <div th:replace="fragments/row::text-row(label='Topography', text=${model.topography})"></div>
<div th:replace="fragments/row::text-row(label='Environment type', text=${model.environmentType})"></div> <div th:replace="fragments/row::text-row(label='Environment type', text=${model.environmentType})"></div>
<div th:replace="fragments/row::text-row(label='Distance to city', text=${model.distanceToCity})"></div> <div th:replace="fragments/row::text-row(label='Distance to city', text=${model.distanceToCity})"></div>
<div th:replace="fragments/row::text-row(label='Direction from city', text=${model.directionFromCity})"></div> <div th:replace="fragments/row::text-row(label='Direction from city', text=${model.directionFromCity})"></div>
<div th:replace="fragments/row::text-row(label='Comment', text=${model.comment})"></div> <div th:replace="fragments/row::text-row(label='Comment', text=${model.comment})"></div>
</div>
</div>
<th:block th:unless="${#lists.isEmpty(model.additionalInfoProperties)}"> <div class="f-card" th:unless="${#lists.isEmpty(model.additionalInfoProperties)}">
<h2>Additional info</h2> <h2>Additional info</h2>
<th:block th:each="prop : ${model.additionalInfoProperties}"> <div class="f-card-body">
<div th:replace="fragments/row::text-row(label=${prop.key}, text=${prop.value})"></div> <th:block th:each="prop : ${model.additionalInfoProperties}">
</th:block> <div th:replace="fragments/row::text-row(label=${prop.key}, text=${prop.value})"></div>
</th:block> </th:block>
</div>
</div>
<div th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"></div> <div th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"></div>
</main> </main>
......
...@@ -15,51 +15,53 @@ ...@@ -15,51 +15,53 @@
<div th:replace="fragments/map::map"></div> <div th:replace="fragments/map::map"></div>
<h2>Identification</h2> <div class="f-card mt-4">
<h2>Identification</h2>
<div th:replace="fragments/row::text-row(label='Name', text=${model.study.studyName})"></div> <div class="f-card-body">
<div th:replace="fragments/row::text-row(label='Identifier', text=${model.study.studyDbId})"></div> <div th:replace="fragments/row::text-row(label='Name', text=${model.study.studyName})"></div>
<div th:replace="fragments/row::text-row(label='Identifier', text=${model.study.studyDbId})"></div>
<div th:replace="fragments/source::source(source=${model.source}, url=${model.study.url}, entityType='study')"></div>
<div th:replace="fragments/source::source(source=${model.source}, url=${model.study.url}, entityType='study')"></div>
<div th:replace="fragments/row::text-row(label='Project name', text=${model.study.programName})"></div>
<div th:replace="fragments/row::text-row(label='Description', text=${model.study.studyDescription})"></div> <div th:replace="fragments/row::text-row(label='Project name', text=${model.study.programName})"></div>
<th:block th:if="${model.study.active != null}"> <div th:replace="fragments/row::text-row(label='Description', text=${model.study.studyDescription})"></div>
<div th:replace="fragments/row::text-row(label='Active', text=${model.study.active ? 'Yes' : 'No'})"></div> <th:block th:if="${model.study.active != null}">
</th:block> <div th:replace="fragments/row::text-row(label='Active', text=${model.study.active ? 'Yes' : 'No'})"></div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.study.seasons)}">
<div th:replace="fragments/row::text-row(label='Seasons', text=${#strings.listJoin(model.study.seasons, ',')})"></div> <th:block th:unless="${#lists.isEmpty(model.study.seasons)}">
</th:block> <div th:replace="fragments/row::text-row(label='Seasons', text=${#strings.listJoin(model.study.seasons, ',')})"></div>
<th:block th:if="${model.study.startDate != null && model.study.endDate != null}"> </th:block>
<div th:replace="fragments/row::text-row(label='Date', text=${'From ' + #dates.format(model.study.startDate, 'yyyy-MM-dd') + ' to ' + #dates.format(model.study.endDate, 'yyyy-MM-dd') })"></div> <th:block th:if="${model.study.startDate != null && model.study.endDate != null}">
</th:block> <div th:replace="fragments/row::text-row(label='Date', text=${'From ' + #dates.format(model.study.startDate, 'yyyy-MM-dd') + ' to ' + #dates.format(model.study.endDate, 'yyyy-MM-dd') })"></div>
<th:block th:if="${model.study.startDate != null && model.study.endDate == null}"> </th:block>
<div th:replace="fragments/row::text-row(label='Date', text=${'Started on ' + #dates.format(model.study.startDate, 'yyyy-MM-dd')})"></div> <th:block th:if="${model.study.startDate != null && model.study.endDate == null}">
</th:block> <div th:replace="fragments/row::text-row(label='Date', text=${'Started on ' + #dates.format(model.study.startDate, 'yyyy-MM-dd')})"></div>
</th:block>
<th:block th:if="${model.study.locationDbId}">
<div th:replace="fragments/row::row(label='Location name', content=~{::#location})"> <th:block th:if="${model.study.locationDbId}">
<a id="location" th:href="@{/sites/{siteId}(siteId=${model.study.locationDbId})}" th:text="${model.study.locationName}"></a> <div th:replace="fragments/row::row(label='Location name', content=~{::#location})">
<a id="location" th:href="@{/sites/{siteId}(siteId=${model.study.locationDbId})}" th:text="${model.study.locationName}"></a>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.study.dataLinks)}">
<div th:replace="fragments/row::row(label='Data files', content=~{::#data-files})">
<ul id="data-files" class="list-unstyled">
<li th:each="dataLink : ${model.study.dataLinks}">
<a target="_blank" th:href="${dataLink.url}" th:text="${dataLink.name}"></a>
</li>
</ul>
</div>
</th:block>
</div> </div>
</th:block> </div>
<th:block th:unless="${#lists.isEmpty(model.study.dataLinks)}">
<div th:replace="fragments/row::row(label='Data files', content=~{::#data-files})">
<ul id="data-files" class="list-unstyled">
<li th:each="dataLink : ${model.study.dataLinks}">
<a target="_blank" th:href="${dataLink.url}" th:text="${dataLink.name}"></a>
</li>
</ul>
</div>
</th:block>
<th:block th:unles="${#lists.isEmpty(model.germplasms)}"> <div class="f-card" th:unles="${#lists.isEmpty(model.germplasms)}">
<h2>Genotype</h2> <h2>Genotype</h2>
<div class="f-card-body">
<div class="table-responsive scroll-table table-card-body"> <div class="scroll-table-container scroll-table-container-big">
<div class="card"> <table class="table table-sm table-striped table-sticky table-responsive-sm">
<table class="table table-sm table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col">Accession number</th> <th scope="col">Accession number</th>
...@@ -79,13 +81,13 @@ ...@@ -79,13 +81,13 @@
</table> </table>
</div> </div>
</div> </div>
</th:block> </div>
<th:block th:unless="${#lists.isEmpty(model.variables)}"> <div class="f-card" th:unless="${#lists.isEmpty(model.variables)}">
<h2>Variables</h2> <h2>Variables</h2>
<div class="table-responsive scroll-table table-card-body"> <div class="f-card-body">
<div class="card"> <div class="scroll-table-container">
<table class="table table-sm table-striped"> <table class="table table-sm table-striped table-sticky table-responsive-sm">
<thead> <thead>
<tr> <tr>
<th scope="col">Variable ID</th> <th scope="col">Variable ID</th>
...@@ -110,13 +112,13 @@ ...@@ -110,13 +112,13 @@
</table> </table>
</div> </div>
</div> </div>
</th:block> </div>
<th:block th:unless="${#lists.isEmpty(model.trials)}"> <div class="f-card" th:unless="${#lists.isEmpty(model.trials)}">
<h2>Data Set</h2> <h2>Data Set</h2>
<div class="table-responsive scroll-big-table table-card-body"> <div class="f-card-body">
<div class="card"> <div class="scroll-table-container scroll-table-container-big">
<table class="table table-sm table-striped"> <table class="table table-sm table-striped table-sticky table-responsive-sm">
<thead> <thead>
<tr> <tr>
<th scope="col">Name</th> <th scope="col">Name</th>
...@@ -144,13 +146,13 @@ ...@@ -144,13 +146,13 @@
</table> </table>
</div> </div>
</div> </div>
</th:block> </div>
<th:block th:unless="${#lists.isEmpty(model.study.contacts)}"> <div class="f-card" th:unless="${#lists.isEmpty(model.study.contacts)}">
<h2>Contact</h2> <h2>Contact</h2>
<div class="table-responsive scroll-table table-card-body"> <div class="f-card-body">
<div class="card"> <div class="scroll-table-container">
<table class="table table-sm table-striped"> <table class="table table-sm table-striped table-sticky table-responsive-sm">
<thead> <thead>
<tr> <tr>
<th scope="col">Role</th> <th scope="col">Role</th>
...@@ -170,23 +172,23 @@ ...@@ -170,23 +172,23 @@
</table> </table>
</div> </div>
</div> </div>
</th:block> </div>
<th:block th:unless="${#lists.isEmpty(model.additionalInfoProperties)}"> <div class="f-card" th:unless="${#lists.isEmpty(model.additionalInfoProperties)}">
<h2>Additional information</h2> <h2>Additional information</h2>
<div class="table-responsive scroll-table table-card-body"> <div class="f-card-body">
<div class="card"> <div class="scroll-table-container">
<table class="table table-sm table-striped"> <table class="table table-sm">
<tbody> <tbody>
<tr th:each="row : ${model.additionalInfoProperties}"> <tr th:each="row : ${model.additionalInfoProperties}">
<td style="width: 50%;" th:text="${row.key}"></td> <th class="label" style="width: 33.33%" th:text="${row.key}" scope="row"></th>
<td th:text="${row.value}"></td> <td th:text="${row.value}"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</th:block> </div>
<div th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"></div> <div th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"></div>
</main> </main>
......
$headings-color: #0f6191;
$border-color: #0f6e9f;
$link-color: #0f6fa1;
$link-decoration: none;
$link-hover-decoration: underline;
$enable-shadows: true;
$table-border-color: #dee2e6;
$table-group-separator-color: $table-border-color;
@import 'custom-bootstrap'; @import 'custom-bootstrap';
@import '~leaflet/dist/leaflet.css'; @import '~leaflet/dist/leaflet.css';
@import '~leaflet.markercluster/dist/MarkerCluster.css'; @import '~leaflet.markercluster/dist/MarkerCluster.css';
@import '~leaflet.markercluster/dist/MarkerCluster.Default.css'; @import '~leaflet.markercluster/dist/MarkerCluster.Default.css';
.label { a[role=button] {
font-weight: 500; color: $link-color !important;
}
.f-row {
border-top: 1px solid $gray-300;
padding: 0.5rem 0;
.label {
font-weight: 700;
}
}
.f-card {
border: 1px solid $border-color;
border-radius: 0.25rem;
margin: 0.5rem 0;
h2 {
font-size: $h4-font-size;
padding: 0.5rem 1rem;
background-image: repeating-linear-gradient(#0f96cd, #0f6191, #0f76a5);
color: $white;
}
.f-card-body {
padding: 0.25rem 1rem;
.f-row:first-of-type {
border-top: 0;
}
}
} }
.popover { .popover {
max-width: min(80vw, 600px); max-width: min(80vw, 500px);
}
.popover-header {
font-weight: 700;
} }
#map { #map {
...@@ -19,3 +58,34 @@ ...@@ -19,3 +58,34 @@
height: 1.5rem; height: 1.5rem;
} }
.content-overflow {
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
&.content-overflow-big {
max-height: 275px;
}
}
.scroll-table-container {
max-height: 200px;
overflow-y: auto;
padding-top: 0;
&.scroll-table-container-big {
max-height: 500px;
}
}
.table-sticky {
width: 100%;
thead th {
position: sticky;
position: -webkit-sticky;
top: 0;
background-color: white;
border-top-width: 0;
th {
padding-top: 0;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment