Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • geocontrib/geocontrib-frontend
  • ext_matthieu/geocontrib-frontend
  • fnecas/geocontrib-frontend
  • MatthieuE/geocontrib-frontend
4 results
Show changes
Showing
with 1323 additions and 41433 deletions
src/assets/img/multiline.png

11.2 KiB

src/assets/img/multimarker.png

12.8 KiB

src/assets/img/multipolygon.png

9.69 KiB

src/assets/img/polygon.png

8.26 KiB | W: 0px | H: 0px

src/assets/img/polygon.png

4.03 KiB | W: 0px | H: 0px

src/assets/img/polygon.png
src/assets/img/polygon.png
src/assets/img/polygon.png
src/assets/img/polygon.png
  • 2-up
  • Swipe
  • Onion skin
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import flip from '@turf/flip';
import axios from '@/axios-client.js';
import 'leaflet.vectorgrid';
let map;
let dictLayersToLeaflet = {};
var layerMVT;
let statusList = [
{
name: 'Brouillon',
value: 'draft',
},
{
name: 'Publié',
value: 'published',
},
{
name: 'Archivé',
value: 'archived',
},
{
name: 'En attente de publication',
value: 'pending',
},
];
L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({
onAdd: function (map) {
// Triggered when the layer is added to a map.
// Register a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onAdd.call(this, map);
map.on('click', this.getFeatureInfo, this);
},
onRemove: function (map) {
// Triggered when the layer is removed from a map.
// Unregister a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onRemove.call(this, map);
map.off('click', this.getFeatureInfo, this);
},
getFeatureInfo: function (evt) {
if (this.wmsParams.basemapId != undefined) {
const queryableLayerSelected = document.getElementById(`queryable-layers-selector-${this.wmsParams.basemapId}`).getElementsByClassName('selected')[0].textContent;
if (queryableLayerSelected.trim() === this.wmsParams.title.trim()) {
// Make an AJAX request to the server and hope for the best
var params = this.getFeatureInfoUrl(evt.latlng);
var showResults = L.Util.bind(this.showGetFeatureInfo, this);
axios.get(
window.proxy_url,
{
params: params,
}
).then(response => {
let data = response.data;
var err = typeof data === 'object' ? null : data;
if (data.features || err) {
showResults(err, evt.latlng, data);
}
})
.catch(error => {
throw (error);
}
);
}
}
},
getFeatureInfoUrl: function (latlng) {
// Construct a GetFeatureInfo request URL given a point
var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom());
var size = this._map.getSize(),
params = {
url: this._url,
request: 'GetFeatureInfo',
service: 'WMS',
// srs: this.wmsParams.srs,
srs: 'EPSG:4326',
// styles: this.wmsParams.styles,
// transparent: this.wmsParams.transparent,
version: this.wmsParams.version,
// format: this.wmsParams.format,
bbox: this._map.getBounds().toBBoxString(),
height: size.y,
width: size.x,
layers: this.wmsParams.layers,
query_layers: this.wmsParams.layers,
info_format: 'application/json'
};
params[params.version === '1.3.0' ? 'i' : 'x'] = Math.floor(point.x);
params[params.version === '1.3.0' ? 'j' : 'y'] = Math.floor(point.y);
return params;
},
showGetFeatureInfo: function (err, latlng, data) {
let content;
if (err) {
content = `
<h4>${this.options.title}</h4>
<p>Données de la couche inaccessibles</p>
`;
L.popup({ maxWidth: 800 })
.setLatLng(latlng)
.setContent(content)
.openOn(this._map);
} else {
// Otherwise show the content in a popup
let contentLines = [];
let contentTitle;
if (data.features.length > 0) {
Object.entries(data.features[0].properties).forEach(entry => {
const [key, value] = entry;
if (key !== 'bbox') {
contentLines.push(`<div>${key}: ${value}</div>`);
}
});
contentTitle = `<h4>${this.options.title}</h4>`;
content = contentTitle.concat(contentLines.join(''));
L.popup({ maxWidth: 800 })
.setLatLng(latlng)
.setContent(content)
.openOn(this._map);
}
}
}
});
L.tileLayer.betterWms = function (url, options) {
return new L.TileLayer.BetterWMS(url, options);
};
const mapUtil = {
getMap: () => {
return map;
},
createMap: function (el, options) {
const {
lat,
lng,
mapDefaultViewCenter,
mapDefaultViewZoom,
zoom,
zoomControl = true,
} = options;
map = L.map(el, {
maxZoom: 18,
minZoom: 1,
zoomControl: false,
}).setView(
[
lat ? lat : mapDefaultViewCenter[0],
lng ? lng : mapDefaultViewCenter[1],
],
!zoom ? mapDefaultViewZoom : zoom
);
map.setMaxBounds( [[-90,-180], [90,180]] );
if (zoomControl) {
L.control
.zoom({
zoomInTitle: 'Zoomer',
zoomOutTitle: 'Dézoomer',
position: 'topright',
})
.addTo(map);
}
L.control.scale().addTo(map);
return map;
},
addGeocoders: function (configuration) {
let geocoder;
const geocoderLabel = configuration.SELECTED_GEOCODER.PROVIDER;
if (geocoderLabel && L.Control.Geocoder) {
const LIMIT_RESULTS = 5;
if (
geocoderLabel === configuration.GEOCODER_PROVIDERS.ADDOK
) {
geocoder = L.Control.Geocoder.addok({ limit: LIMIT_RESULTS });
} else if (
geocoderLabel === configuration.GEOCODER_PROVIDERS.PHOTON
) {
geocoder = L.Control.Geocoder.photon();
} else if (
geocoderLabel === configuration.GEOCODER_PROVIDERS.NOMINATIM
) {
geocoder = L.Control.Geocoder.nominatim();
}
L.Control.geocoder({
placeholder: 'Chercher une adresse...',
geocoder: geocoder,
}).addTo(map);
}
},
addLayers: function (layers, serviceMap, optionsMap, schemaType) {
if (layers) { //* if admin has defined basemaps for this project
layers.forEach((layer) => {
if (layer) {
let options = layer.options;
if (options) {
options.noWrap = true;
options.opacity = layer.opacity;
if (layer.schema_type === 'wms') {
let leafletLayer;
if (layer.queryable) {
options.title = layer.title;
leafletLayer = L.tileLayer
.betterWms(layer.service, options)
.addTo(map);
} else {
leafletLayer = L.tileLayer
.wms(layer.service, options)
.addTo(map);
}
dictLayersToLeaflet[layer.id] = leafletLayer._leaflet_id;
} else if (layer.schema_type === 'tms') {
const leafletLayer = L.tileLayer(layer.service, options).addTo(map);
dictLayersToLeaflet[layer.id] = leafletLayer._leaflet_id;
}
}
}
});
} else { //* else when no basemaps defined
optionsMap.noWrap = true;
if (schemaType === 'wms') {
L.tileLayer
.wms(serviceMap, optionsMap)
.addTo(map);
} else {
L.tileLayer(serviceMap, optionsMap).addTo(map);
}
}
},
// Remove the base layers (not the features)
removeLayers: function () {
map.eachLayer((leafLetlayer) => {
if (
Object.values(dictLayersToLeaflet).includes(leafLetlayer._leaflet_id)
) {
map.removeLayer(leafLetlayer);
}
});
dictLayersToLeaflet = {};
},
updateOpacity(layerId, opacity) {
const internalLeafletLayerId = dictLayersToLeaflet[layerId];
map.eachLayer((layer) => {
if (layer._leaflet_id === internalLeafletLayerId) {
layer.setOpacity(opacity);
}
});
},
updateOrder(layers) {
// First remove existing layers undefined
layers = layers.filter(function (x) {
return x !== undefined;
});
// First remove existing layers
map.eachLayer((leafLetlayer) => {
layers.forEach((layerOptions) => {
if (dictLayersToLeaflet[layerOptions.id] === leafLetlayer._leaflet_id) {
map.removeLayer(leafLetlayer);
}
});
});
dictLayersToLeaflet = {};
// Redraw the layers
this.addLayers(layers);
},
retrieveFeatureColor: function (featureType, properties) {
const colorsStyle = featureType.colors_style;
if (featureType && colorsStyle && colorsStyle.custom_field_name) {
const currentValue = properties[colorsStyle.custom_field_name];
const colorStyle = colorsStyle.colors[currentValue];
return colorStyle ? colorStyle : featureType.color;
}
return featureType.color;
},
addVectorTileLayer: function (url, project_slug, featureTypes, form_filters) {
layerMVT = L.vectorGrid.protobuf(url, {
noWrap:true,
vectorTileLayerStyles: {
default: (properties) => {
const featureType = featureTypes.find((x) => x.slug.split('-')[0] === '' + properties.feature_type_id);
const color = this.retrieveFeatureColor(featureType, properties);
const colorValue =
color.value && color.value.length ?
color.value : typeof color === 'string' && color.length ?
color : '#000000';
const hiddenStyle = ({
radius: 0,
fillOpacity: 0.5,
weight: 0,
fill: false,
color: featureType.color,
});
const defaultStyle = {
radius: 4,
fillOpacity: 0.5,
weight: 3,
fill: true,
color: colorValue,
};
// Filtre sur le feature type
if (form_filters && form_filters.type.selected) {
if (featureType.title !== form_filters.type.selected) {
return hiddenStyle;
}
}
// Filtre sur le statut
if (form_filters && form_filters.status.selected.value) {
if (properties.status !== form_filters.status.selected.value) {
return hiddenStyle;
}
}
// Filtre sur le titre
if (form_filters && form_filters.title) {
if (!properties.title.toLowerCase().includes(form_filters.title.toLowerCase())) {
return hiddenStyle;
}
}
return defaultStyle;
},
},
// subdomains: "0123",
// key: 'abcdefghi01234567890',
interactive: true,
maxNativeZoom: 18,
getFeatureId: function (f) {
return f.properties.id;
}
});
layerMVT.on('click', (e) => { // The .on method attaches an event handler
const popupContent = this._createContentPopup(e.layer, featureTypes, project_slug);
L.popup()
.setContent(popupContent)
.setLatLng(e.latlng)
.openOn(map);
});
layerMVT.addTo(map);
window.layerMVT = layerMVT;
},
addFeatures: function (features, filter, addToMap = true, featureTypes, project_slug) {
const featureGroup = new L.FeatureGroup();
features.forEach((feature) => {
const featureProperties = feature.properties ? feature.properties : feature;
const featureType = featureTypes
.find((ft) => ft.slug === (featureProperties.feature_type.slug || featureProperties.feature_type));
let filters = [];
if (filter) {
const typeCheck = filter.featureType && featureProperties.feature_type.slug === filter.featureType;
const statusCheck = filter.featureStatus && featureProperties.status.value === filter.featureStatus;
const titleCheck = filter.featureTitle && featureProperties.title.includes(filter.featureTitle);
filters = [typeCheck, statusCheck, titleCheck];
}
if (
!filter ||
!Object.values(filter).some(val => val) ||
Object.values(filter).some(val => val) &&
filters.length && filters.every(val => val !== false)
) {
const geomJSON = flip(feature.geometry || feature.geom);
const popupContent = this._createContentPopup(feature, featureTypes, project_slug);
// Look for a custom field
let customField;
let customFieldOption;
if (
featureType.customfield_set &&
Object.keys(featureProperties).some(el => featureType.customfield_set.map(e => e.name).includes(el))
) {
customField = Object.keys(featureProperties)
.filter(el => featureType.customfield_set.map(e => e.name).includes(el));
customFieldOption = featureProperties[customField[0]];
}
let color = '#000000';
if (feature.overideColor) {
color = feature.overideColor;
} else {
color = this.retrieveFeatureColor(featureType, featureProperties) || featureProperties.color;
if (color.value && color.value.length) {
color = color.value;
}
}
if (geomJSON.type === 'Point') {
if (
customFieldOption &&
featureType.colors_style &&
featureType.colors_style.value &&
featureType.colors_style.value.icons &&
!!Object.keys(featureType.colors_style.value.icons).length
) {
if (
featureType.colors_style.value.icons[customFieldOption] &&
featureType.colors_style.value.icons[customFieldOption] !== 'circle'
) {
const iconHTML = `
<i
class="fas fa-${featureType.colors_style.value.icons[customFieldOption]} fa-lg"
style="color: ${color}"
></i>
`;
const customMapIcon = L.divIcon({
html: iconHTML,
iconSize: [20, 20],
className: 'myDivIcon',
});
L.marker(geomJSON.coordinates, {
icon: customMapIcon,
color: color,
zIndexOffset: 100
})
.bindPopup(popupContent)
.addTo(featureGroup);
} else {
L.circleMarker(geomJSON.coordinates, {
color: color,
radius: 4,
fillOpacity: 0.5,
weight: 3,
})
.bindPopup(popupContent)
.addTo(featureGroup);
}
} else {
if (featureType.icon && featureType.icon !== 'circle') {
const iconHTML = `
<i
class="fas fa-${featureType.icon} fa-lg"
style="color: ${color}"
></i>
`;
const customMapIcon = L.divIcon({
html: iconHTML,
iconSize: [20, 20],
className: 'myDivIcon',
});
L.marker(geomJSON.coordinates, {
icon: customMapIcon,
color: color,
zIndexOffset: 100
})
.bindPopup(popupContent)
.addTo(featureGroup);
} else {
L.circleMarker(geomJSON.coordinates, {
color: color,
radius: 4,
fillOpacity: 0.5,
weight: 3,
})
.bindPopup(popupContent)
.addTo(featureGroup);
}
}
} else if (geomJSON.type === 'LineString') {
L.polyline(geomJSON.coordinates, {
color: color,
weight: 3,
})
.bindPopup(popupContent)
.addTo(featureGroup);
} else if (geomJSON.type === 'Polygon') {
L.polygon(geomJSON.coordinates, {
color: color,
weight: 3,
fillOpacity: 0.5,
})
.bindPopup(popupContent)
.addTo(featureGroup);
}
}
});
if (map && addToMap) {
map.addLayer(featureGroup);
}
return featureGroup;
},
addMapEventListener: function (eventName, callback) {
map.on(eventName, callback);
},
_createContentPopup: function (feature, featureTypes, project_slug) {
const formatDate = (current_datetime) => {
let formatted_date = current_datetime.getFullYear() + '-' + ('0' + (current_datetime.getMonth() + 1)).slice(-2) + '-' + ('0' + current_datetime.getDate()).slice(-2) + ' ' +
('0' + current_datetime.getHours()).slice(-2) + ':' + ('0' + current_datetime.getMinutes()).slice(-2);
return formatted_date;
};
let feature_type = feature.properties ? feature.properties.feature_type : feature.feature_type;
let feature_url = feature.feature_url;
let status = feature.status;
let feature_type_url = feature.feature_type_url;
let date_maj = feature.updated_on;
if (feature.properties) {
status = feature.properties.status;
date_maj = feature.properties.updated_on ? formatDate(new Date(feature.properties.updated_on)) : '<i>indisponible</i>';
feature_type_url = feature.properties.feature_type_url;
feature_url = feature.properties.feature_url;
}
if (featureTypes && feature.properties) { // => VectorTile
feature_type = feature.properties.feature_type_id ?
featureTypes.find((x) => x.slug.split('-')[0] === '' + feature.properties.feature_type_id) :
featureTypes.find((f_type) => f_type.slug === feature.properties.feature_type); //* geojson
status = statusList.find((x) => x.value === feature.properties.status).name;
if (feature_type) feature_type_url = '/geocontrib/projet/' + project_slug + '/type-signalement/' + feature_type.slug + '/';
feature_url = feature_type_url + 'signalement/' + feature.properties.feature_id + '/';
} else {
status = feature.properties ? feature.properties.status.label : feature.status.label;
}
//* adapt link url for shared-project restricted navigation
if (window.location.pathname.includes('projet-partage')) {
feature_url = feature_url.replace('projet', 'projet-partage');
feature_type_url = feature_type_url.replace('projet', 'projet-partage');
}
let author = '';
const creator = feature.properties ? feature.properties.creator : feature.creator;
if (creator) {
author = creator.full_name
? `<div>
Auteur : ${creator.first_name} ${creator.last_name}
</div>`
: creator.username ? `<div>Auteur: ${creator.username}</div>` : '';
}
let title = feature.properties ? feature.properties.title : feature.title;
if (feature_url) {
title = `<a href="${feature_url}">${title}</a>`;
} else {
title = `<span>${title|| '<i>indisponible</i>'}</span>`;
}
if (feature_type_url) {
`<a href="${feature_type_url}"> ${feature_type.title || '<i>indisponible</i>'} </a>`;
}
return `
<h4>
<${feature_url ? 'a href="' + feature_url + '"' : 'span'}>${title || '<i>indisponible</i>'}</${feature_url ? 'a' : 'span'}>
</h4>
<div>
Statut : ${status || '<i>indisponible</i>'}
</div>
<div>
Type : <${feature_type_url ? 'a href="'+ feature_type_url + '"' : 'span'}> ${feature_type.title || '<i>indisponible</i>'} </${feature_type_url ? 'a' : 'span'}>
</div>
<div>
Dernière mise à jour : ${date_maj || '<i>indisponible</i>'}
</div>
${author}
`;
},
};
export { mapUtil };
......@@ -2,33 +2,127 @@ export function fileConvertSize(aSize){
aSize = Math.abs(parseInt(aSize, 10));
const def = [[1, 'octets', 0], [1024, 'ko', 0], [1024*1024, 'Mo', 1], [1024*1024*1024, 'Go', 2], [1024*1024*1024*1024, 'To', 2]];
for (let i=0; i<def.length; i++) {
if (aSize<def[i][0]) return (aSize/def[i-1][0]).toFixed(def[i-1][2]) + ' ' + def[i-1][1];
if (aSize<def[i][0]) {
return (aSize/def[i-1][0]).toFixed(def[i-1][2]) + ' ' + def[i-1][1];
}
}
}
export function fileConvertSizeToMo(aSize){
console.log(aSize);
aSize = Math.abs(parseInt(aSize, 10));
const def = [1024*1024, 'Mo', 1];
return (aSize/def[0]).toFixed(def[2]);
}
export function csvToJson(csv) {
let result = [];
/**
* Determines the likely field delimiter in a CSV string by analyzing the first few lines.
* The function counts the occurrences of common delimiters such as commas, semicolons, and tabs.
* The most frequently and consistently occurring delimiter across the sampled lines is chosen as the likely delimiter.
*
* @param {string} text - The CSV string to analyze for determining the delimiter.
* @returns {string|false} The most likely delimiter character if one can be determined, or false if none is found.
*/
export function determineDelimiter(text) {
const lines = text.split('\n').slice(0, 5); // Analyze the first 5 lines
const delimiters = [',', ';', '\t']; // List of possible delimiters
let delimiterCounts = new Map(delimiters.map(d => [d, 0])); // Initialize a map to count delimiter occurrences
const allLines = csv.split('\n');
const headers = allLines[0].split(',');
const [, ...lines] = allLines;
// Count the occurrences of each delimiter in each line
lines.forEach(line => {
delimiters.forEach(delimiter => {
const count = line.split(delimiter).length - 1; // Count the occurrences of the delimiter in the line
delimiterCounts.set(delimiter, delimiterCounts.get(delimiter) + count); // Update the count in the map
});
});
for (const line of lines) {
let obj = {};
const currentLine = line.split(',');
let mostCommonDelimiter = '';
let maxCount = 0;
for (let i = 0; i < headers.length; i++) {
obj[headers[i]] = currentLine[i];
// Determine the most common delimiter
delimiterCounts.forEach((count, delimiter) => {
if (count > maxCount) {
mostCommonDelimiter = delimiter; // Set the most common delimiter found so far
maxCount = count; // Update the maximum count found so far
}
});
return mostCommonDelimiter || false; // Return the most common delimiter or false if none is found
}
/**
* Parses a CSV string into an array of rows, where each row is an array of fields.
* The function correctly handles multiline fields enclosed in double quotes, removes
* carriage return characters (\r) at the end of lines, and allows for different field
* delimiters.
*
* @param {string} text - The CSV string to be parsed.
* @param {string} delimiter - The field delimiter character (default is comma ',').
* @returns {Array<Array<string>>} An array of rows, each row being an array of fields.
*/
export function parseCSV(text, delimiter = ',') {
let rows = []; // This will hold the parsed rows
let row = []; // Temporary array to hold the fields of the current row
let field = ''; // Temporary string to hold the current field
let inQuotes = false; // Boolean to track whether we are inside quotes
for (let i = 0; i < text.length; i++) {
const char = text[i]; // Current character
if (char === '"' && text[i - 1] !== '\\') {
inQuotes = !inQuotes; // Toggle the inQuotes flag if not escaped
} else if (char === delimiter && !inQuotes) {
// If the current character is the delimiter and we are not inside quotes,
// add the field to the row and reset the field variable
row.push(field.replace(/\r$/, '')); // Remove trailing carriage return
field = '';
} else if (char === '\n' && !inQuotes) {
// If the current character is a newline and we are not inside quotes,
// add the field to the row, add the row to the list of rows,
// and reset the field and row variables
row.push(field.replace(/\r$/, '')); // Remove trailing carriage return
rows.push(row);
row = [];
field = '';
} else {
// If the current character is part of a field, add it to the field variable
field += char;
}
}
// After the loop, check if there's a remaining field or row to be added
if (field) {
row.push(field.replace(/\r$/, '')); // Remove trailing carriage return
rows.push(row);
}
return rows; // Return the parsed rows
}
result.push(obj);
/**
* Checks if the values in 'lon' and 'lat' columns are decimal numbers in the provided CSV data.
*
* @param {Array<string>} headers - The array of headers from the CSV file.
* @param {Array<Array<string>>} data - The CSV data as an array of rows, each row being an array of field values.
* @returns {boolean} True if 'lon' and 'lat' are found and their values are decimal numbers, false otherwise.
*/
export function checkLonLatValues(headers, data) {
const lonIndex = headers.indexOf('lon');
const latIndex = headers.indexOf('lat');
// Check if both 'lon' and 'lat' headers are found
if (lonIndex === -1 || latIndex === -1) {
return false;
}
return JSON.parse(JSON.stringify(result));
// Function to check if a string is a decimal number
const isDecimal = (str) => !isNaN(str) && str.includes('.');
for (const row of data) {
// Check if 'lon' and 'lat' values are decimal numbers
if (!isDecimal(row[lonIndex]) || !isDecimal(row[latIndex])) {
return false;
}
}
return true;
}
import L from 'leaflet';
export var Symbolizer = L.Class.extend({
// 🍂method initialize(feature: GeoJSON, pxPerExtent: Number)
// Initializes a new Line Symbolizer given a GeoJSON feature and the
// pixel-to-coordinate-units ratio. Internal use only.
// 🍂method render(renderer, style)
// Renders this symbolizer in the given tiled renderer, with the given
// `L.Path` options. Internal use only.
render: function(renderer, style) {
this._renderer = renderer;
this.options = style;
renderer._initPath(this);
renderer._updateStyle(this);
},
// 🍂method render(renderer, style)
// Updates the `L.Path` options used to style this symbolizer, and re-renders it.
// Internal use only.
updateStyle: function(renderer, style) {
this.options = style;
renderer._updateStyle(this);
},
_getPixelBounds: function() {
var parts = this._parts;
var bounds = L.bounds([]);
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
for (var j = 0; j < part.length; j++) {
bounds.extend(part[j]);
}
}
var w = this._clickTolerance(),
p = new L.Point(w, w);
bounds.min._subtract(p);
bounds.max._add(p);
return bounds;
},
_clickTolerance: L.Path.prototype._clickTolerance,
});
export var PolyBase = {
_makeFeatureParts: function(feat, pxPerExtent) {
var rings = feat.geometry;
var coord;
this._parts = [];
for (var i = 0; i < rings.length; i++) {
var ring = rings[i];
var part = [];
for (var j = 0; j < ring.length; j++) {
coord = ring[j];
// Protobuf vector tiles return {x: , y:}
// Geojson-vt returns [,]
part.push(L.point(coord).scaleBy(pxPerExtent));
}
this._parts.push(part);
}
},
makeInteractive: function() {
this._pxBounds = this._getPixelBounds();
}
};
export var LineSymbolizer = L.Polyline.extend({
includes: [Symbolizer.prototype, PolyBase],
initialize: function(feature, pxPerExtent) {
this.properties = feature.properties;
this._makeFeatureParts(feature, pxPerExtent);
},
render: function(renderer, style) {
style.fill = false;
Symbolizer.prototype.render.call(this, renderer, style);
this._updatePath();
},
updateStyle: function(renderer, style) {
style.fill = false;
Symbolizer.prototype.updateStyle.call(this, renderer, style);
},
});
export var FillSymbolizer = L.Polygon.extend({
includes: [Symbolizer.prototype, PolyBase],
initialize: function(feature, pxPerExtent) {
this.properties = feature.properties;
this._makeFeatureParts(feature, pxPerExtent);
},
render: function(renderer, style) {
Symbolizer.prototype.render.call(this, renderer, style);
this._updatePath();
}
});
export var PointSymbolizer = L.CircleMarker.extend({
includes: Symbolizer.prototype,
statics: {
iconCache: {}
},
initialize: function(feature, pxPerExtent) {
this.properties = feature.properties;
this._makeFeatureParts(feature, pxPerExtent);
},
render: function(renderer, style) {
Symbolizer.prototype.render.call(this, renderer, style);
this._radius = style.radius || L.CircleMarker.prototype.options.radius;
this._updatePath();
},
_makeFeatureParts: function(feat, pxPerExtent) {
var coord = feat.geometry[0];
if (typeof coord[0] === 'object' && 'x' in coord[0]) {
// Protobuf vector tiles return [{x: , y:}]
this._point = L.point(coord[0]).scaleBy(pxPerExtent);
this._empty = L.Util.falseFn;
} else {
// Geojson-vt returns [,]
this._point = L.point(coord).scaleBy(pxPerExtent);
this._empty = L.Util.falseFn;
}
},
makeInteractive: function() {
this._updateBounds();
},
updateStyle: function(renderer, style) {
this._radius = style.radius || this._radius;
this._updateBounds();
return Symbolizer.prototype.updateStyle.call(this, renderer, style);
},
_updateBounds: function() {
var icon = this.options.icon;
if (icon) {
var size = L.point(icon.options.iconSize),
anchor = icon.options.iconAnchor ||
size && size.divideBy(2, true),
p = this._point.subtract(anchor);
this._pxBounds = new L.Bounds(p, p.add(icon.options.iconSize));
} else {
L.CircleMarker.prototype._updateBounds.call(this);
}
},
_updatePath: function() {
if (this.options.icon) {
this._renderer._updateIcon(this);
} else {
L.CircleMarker.prototype._updatePath.call(this);
}
},
_getImage: function () {
if (this.options.icon) {
var url = this.options.icon.options.iconUrl,
img = PointSymbolizer.iconCache[url];
if (!img) {
var icon = this.options.icon;
img = PointSymbolizer.iconCache[url] = icon.createIcon();
}
return img;
} else {
return null;
}
},
_containsPoint: function(p) {
var icon = this.options.icon;
if (icon) {
return this._pxBounds.contains(p);
} else {
return L.CircleMarker.prototype._containsPoint.call(this, p);
}
}
});
L.VectorGrid.prototype._createLayer=function(feat, pxPerExtent) {
var layer;
switch (feat.type) {
case 1:
layer = new PointSymbolizer(feat, pxPerExtent);
// [YB 2019-10-23: prevent leaflet from treating these canvas points as real markers]
layer.getLatLng = null;
break;
case 2:
layer = new LineSymbolizer(feat, pxPerExtent);
break;
case 3:
layer = new FillSymbolizer(feat, pxPerExtent);
break;
}
if (this.options.interactive) {
layer.addEventParent(this);
}
return layer;
};
\ No newline at end of file
/* required styles */
/* For input, we add the strong #map selector to avoid conflicts with semantic-ui */
#map .leaflet-control-geocoder {
border-radius: 4px;
background: white;
min-width: 26px;
min-height: 26px;
}
.leaflet-touch .leaflet-control-geocoder {
min-width: 30px;
min-height: 30px;
}
.leaflet-control-geocoder a,
.leaflet-control-geocoder .leaflet-control-geocoder-icon {
border-bottom: none;
display: inline-block;
}
.leaflet-control-geocoder .leaflet-control-geocoder-alternatives a {
width: inherit;
height: inherit;
line-height: inherit;
}
.leaflet-control-geocoder a:hover,
.leaflet-control-geocoder .leaflet-control-geocoder-icon:hover {
border-bottom: none;
display: inline-block;
}
.leaflet-control-geocoder-form {
display: none;
vertical-align: middle;
}
.leaflet-control-geocoder-expanded .leaflet-control-geocoder-form {
display: inline-block;
}
#map .leaflet-control-geocoder-form input {
font-size: 120%;
border: 0;
background-color: transparent;
width: 246px;
}
.leaflet-control-geocoder-icon {
border-radius: 4px;
width: 26px;
height: 26px;
border: none;
background-color: white;
background-image: url(./images/geocoder.svg);
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.leaflet-touch .leaflet-control-geocoder-icon {
width: 30px;
height: 30px;
}
.leaflet-control-geocoder-throbber .leaflet-control-geocoder-icon {
background-image: url(./images/throbber.gif);
}
.leaflet-control-geocoder-form-no-error {
display: none;
}
#map .leaflet-control-geocoder-form input:focus {
outline: none;
}
.leaflet-control-geocoder-form button {
display: none;
}
.leaflet-control-geocoder-error {
margin-top: 8px;
margin-left: 8px;
display: block;
color: #444;
}
.leaflet-control-geocoder-alternatives {
display: block;
width: 272px;
list-style: none;
padding: 0;
margin: 0;
}
.leaflet-control-geocoder-alternatives-minimized {
display: none;
height: 0;
}
.leaflet-control-geocoder-alternatives li {
white-space: nowrap;
display: block;
overflow: hidden;
padding: 5px 8px;
text-overflow: ellipsis;
border-bottom: 1px solid #ccc;
cursor: pointer;
}
.leaflet-control-geocoder-alternatives li a,
.leaflet-control-geocoder-alternatives li a:hover {
width: inherit;
height: inherit;
line-height: inherit;
background: inherit;
border-radius: inherit;
text-align: left;
}
.leaflet-control-geocoder-alternatives li:last-child {
border-bottom: none;
}
.leaflet-control-geocoder-alternatives li:hover,
.leaflet-control-geocoder-selected {
background-color: #f5f5f5;
}
/* Custom style */
.leaflet-control-geocoder-icon {
border-radius: 4px;
width: 35px;
height: 35px;
}
#map .leaflet-control-geocoder-form input {
height: 35px;
}
.leaflet-control-geocoder-alternatives li:first-of-type {
border-top: 1px solid #ccc;
}
.leaflet-control-geocoder-address-item {
font-weight: 600;
}
.leaflet-control-geocoder-address-detail {
font-size: 12px;
font-weight: normal;
}
.leaflet-control-geocoder-address-context {
color: #666;
font-size: 12px;
font-weight: lighter;
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
\ No newline at end of file
Source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -10,6 +10,7 @@
*/
 
@import url('https://fonts.googleapis.com/css?family=Roboto Condensed:400,700,400italic,700italic&subset=latin');
/*!
* # Semantic UI 2.4.2 - Reset
* http://github.com/semantic-org/semantic-ui/
......@@ -271,7 +272,7 @@ body {
overflow-x: hidden;
min-width: 320px;
background: #fff;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 14px;
line-height: 1.4285em;
color: #252525;
......@@ -279,7 +280,7 @@ body {
}
 
h1, h2, h3, h4, h5 {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
line-height: 1.28571429em;
margin: calc(2rem - .14285714em) 0 1rem;
font-weight: 700;
......@@ -420,7 +421,7 @@ body .ui.inverted::-webkit-scrollbar-thumb:hover {
vertical-align: baseline;
background: #e0e1e2 none;
color: rgba(0, 0, 0, .6);
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
margin: 0 .25em 0 0;
padding: .78571429em 1.5em .78571429em;
text-transform: none;
......@@ -2924,7 +2925,7 @@ body .ui.inverted::-webkit-scrollbar-thumb:hover {
}
 
.ui.teal.button, .ui.teal.buttons .button {
background-color: #00b5ad;
background-color: var(--primary-color, #00b5ad);
color: #fff;
text-shadow: none;
background-image: none
......@@ -2936,60 +2937,68 @@ body .ui.inverted::-webkit-scrollbar-thumb:hover {
}
 
.ui.teal.button:hover, .ui.teal.buttons .button:hover {
background-color: #009c95;
background-color: var(--primary-highlight-color, #009c95)
;
color: #fff;
text-shadow: none
}
 
.ui.teal.button:focus, .ui.teal.buttons .button:focus {
background-color: #008c86;
background-color: var(--primary-highlight-color, #008c86);
color: #fff;
text-shadow: none
}
 
.ui.teal.button:active, .ui.teal.buttons .button:active {
background-color: #00827c;
background: var(--primary-highlight-color, #00827c);
color: #fff;
text-shadow: none
}
 
.ui.teal.active.button, .ui.teal.button .active.button:active, .ui.teal.buttons .active.button, .ui.teal.buttons .active.button:active {
background-color: #009c95;
background-color: var(--primary-highlight-color, #009c95)
;
color: #fff;
text-shadow: none
}
 
.ui.basic.teal.button, .ui.basic.teal.buttons .button {
-webkit-box-shadow: 0 0 0 1px #00b5ad inset!important;
box-shadow: 0 0 0 1px #00b5ad inset!important;
color: #00b5ad!important
-webkit-box-shadow: 0 0 0 1px var(--primary-color, #00b5ad) inset!important;
box-shadow: 0 0 0 1px var(--primary-color, #00b5ad) inset!important;
color: var(--primary-color, #00b5ad)!important
}
 
.ui.basic.teal.button:hover, .ui.basic.teal.buttons .button:hover {
background: 0 0!important;
-webkit-box-shadow: 0 0 0 1px #009c95 inset!important;
box-shadow: 0 0 0 1px #009c95 inset!important;
color: #009c95!important
-webkit-box-shadow: 0 0 0 1px var(--primary-highlight-color, #009c95)
inset!important;
box-shadow: 0 0 0 1px var(--primary-highlight-color, #009c95)
inset!important;
color: var(--primary-highlight-color, #009c95)
!important
}
 
.ui.basic.teal.button:focus, .ui.basic.teal.buttons .button:focus {
background: 0 0!important;
-webkit-box-shadow: 0 0 0 1px #008c86 inset!important;
box-shadow: 0 0 0 1px #008c86 inset!important;
color: #009c95!important
-webkit-box-shadow: 0 0 0 1px var(--primary-highlight-color, #008c86) inset!important;
box-shadow: 0 0 0 1px var(--primary-highlight-color, #008c86) inset!important;
color: var(--primary-highlight-color, #009c95)
!important
}
 
.ui.basic.teal.active.button, .ui.basic.teal.buttons .active.button {
background: 0 0!important;
-webkit-box-shadow: 0 0 0 1px #009c95 inset!important;
box-shadow: 0 0 0 1px #009c95 inset!important;
color: #00827c!important
-webkit-box-shadow: 0 0 0 1px var(--primary-highlight-color, #009c95)
inset!important;
box-shadow: 0 0 0 1px var(--primary-highlight-color, #009c95)
inset!important;
color: var(--primary-highlight-color, #00827c)!important
}
 
.ui.basic.teal.button:active, .ui.basic.teal.buttons .button:active {
-webkit-box-shadow: 0 0 0 1px #00827c inset!important;
box-shadow: 0 0 0 1px #00827c inset!important;
color: #00827c!important
-webkit-box-shadow: 0 0 0 1px var(--primary-highlight-color, #00827c) inset!important;
box-shadow: 0 0 0 1px var(--primary-highlight-color, #00827c) inset!important;
color: var(--primary-highlight-color, #00827c)!important
}
 
.ui.buttons:not(.vertical)>.basic.teal.button:not(:first-child) {
......@@ -3905,7 +3914,7 @@ body .ui.inverted::-webkit-scrollbar-thumb:hover {
}
 
.ui.text.container {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
max-width: 700px!important;
line-height: 1.5
}
......@@ -5146,7 +5155,7 @@ i.flag.zimbabwe:before, i.flag.zw:before {
border: none;
margin: calc(2rem - .14285714em) 0 1rem;
padding: 0 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-weight: 700;
line-height: 1.28571429em;
text-transform: none;
......@@ -5516,15 +5525,16 @@ a.ui.inverted.green.header:hover {
}
 
.ui.teal.header {
color: #00b5ad!important
color: var(--primary-color, #00b5ad)!important
}
 
a.ui.teal.header:hover {
color: #009c95!important
color: var(--primary-highlight-color, #009c95)
!important
}
 
.ui.teal.dividing.header {
border-bottom: 2px solid #00b5ad
border-bottom: 2px solid var(--primary-color, #00b5ad)
}
 
.ui.inverted.teal.header {
......@@ -6027,7 +6037,7 @@ i.inverted.bordered.green.icon, i.inverted.circular.green.icon {
}
 
i.teal.icon {
color: #00b5ad!important
color: var(--primary-color, #00b5ad)!important
}
 
i.inverted.teal.icon {
......@@ -6035,7 +6045,7 @@ i.inverted.teal.icon {
}
 
i.inverted.bordered.teal.icon, i.inverted.circular.teal.icon {
background-color: #00b5ad!important;
background-color: var(--primary-color, #00b5ad)!important;
color: #fff!important
}
 
......@@ -11654,7 +11664,7 @@ img.ui.image {
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
text-align: left;
line-height: 1.21428571em;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
padding: .67857143em 1em;
background: #fff;
border: 1px solid rgba(34, 36, 38, .15);
......@@ -12658,14 +12668,16 @@ a.ui.active.label:hover, a.ui.labels .active.label:hover {
}
 
.ui.teal.label, .ui.teal.labels .label {
background-color: #00b5ad!important;
border-color: #00b5ad!important;
background-color: var(--primary-color, #00b5ad)!important;
border-color: var(--primary-color, #00b5ad)!important;
color: #fff!important
}
 
.ui.teal.labels .label:hover, a.ui.teal.label:hover {
background-color: #009c95!important;
border-color: #009c95!important;
background-color: var(--primary-highlight-color, #009c95)
!important;
border-color: var(--primary-highlight-color, #009c95)
!important;
color: #fff!important
}
 
......@@ -12674,19 +12686,21 @@ a.ui.active.label:hover, a.ui.labels .active.label:hover {
}
 
.ui.teal.ribbon.label {
border-color: #00827c!important
border-color: var(--primary-highlight-color, #00827c)!important
}
 
.ui.basic.teal.label {
background: none #fff!important;
color: #00b5ad!important;
border-color: #00b5ad!important
color: var(--primary-color, #00b5ad)!important;
border-color: var(--primary-color, #00b5ad)!important
}
 
.ui.basic.teal.labels a.label:hover, a.ui.basic.teal.label:hover {
background-color: #fff!important;
color: #009c95!important;
border-color: #009c95!important
color: var(--primary-highlight-color, #009c95)
!important;
border-color: var(--primary-highlight-color, #009c95)
!important
}
 
.ui.blue.label, .ui.blue.labels .label {
......@@ -13236,7 +13250,7 @@ a.ui.basic.label:hover {
.ui.list .list>.item .header, .ui.list>.item .header {
display: block;
margin: 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-weight: 700;
color: #252525
}
......@@ -15298,11 +15312,11 @@ ol.ui.list li[value]:before {
}
 
.ui.teal.segment:not(.inverted) {
border-top: 2px solid #00b5ad!important
border-top: 2px solid var(--primary-color, #00b5ad)!important
}
 
.ui.inverted.teal.segment {
background-color: #00b5ad!important;
background-color: var(--primary-color, #00b5ad)!important;
color: #fff!important
}
 
......@@ -15627,7 +15641,7 @@ ol.ui.list li[value]:before {
}
 
.ui.steps .step .title {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1.14285714em;
font-weight: 700
}
......@@ -16174,7 +16188,7 @@ ol.ui.list li[value]:before {
}
 
.ui.form input:not([type]), .ui.form input[type=date], .ui.form input[type=datetime-local], .ui.form input[type=email], .ui.form input[type=file], .ui.form input[type=number], .ui.form input[type=password], .ui.form input[type=search], .ui.form input[type=tel], .ui.form input[type=text], .ui.form input[type=time], .ui.form input[type=url] {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
margin: 0;
outline: 0;
-webkit-appearance: none;
......@@ -17827,7 +17841,7 @@ ol.ui.list li[value]:before {
}
 
.ui.grid>.row>.teal.column, .ui.grid>.teal.column, .ui.grid>.teal.row {
background-color: #00b5ad!important;
background-color: var(--primary-color, #00b5ad)!important;
color: #fff
}
 
......@@ -18237,7 +18251,7 @@ ol.ui.list li[value]:before {
display: -ms-flexbox;
display: flex;
margin: 1rem 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
background: #fff;
font-weight: 400;
border: 1px solid rgba(34, 36, 38, .15);
......@@ -19355,8 +19369,8 @@ ol.ui.list li[value]:before {
}
 
.ui.menu .teal.active.item, .ui.teal.menu .active.item {
border-color: #00b5ad!important;
color: #00b5ad!important
border-color: var(--primary-color, #00b5ad)!important;
color: var(--primary-color, #00b5ad)!important
}
 
.ui.blue.menu .active.item, .ui.menu .blue.active.item {
......@@ -19391,13 +19405,13 @@ ol.ui.list li[value]:before {
 
.ui.inverted.menu {
border: 0 solid transparent;
background: #373636;
background: var(--primary-color, #373636);
-webkit-box-shadow: none;
box-shadow: none
}
 
.ui.inverted.menu .item, .ui.inverted.menu .item>a:not(.ui) {
background: 0 0;
background: var(--primary-color, 0 0);
color: rgba(255, 255, 255, .9)
}
 
......@@ -19429,7 +19443,7 @@ ol.ui.list li[value]:before {
}
 
.ui.inverted.menu .dropdown.item:hover, .ui.inverted.menu .link.item:hover, .ui.inverted.menu a.item:hover, .ui.link.inverted.menu .item:hover {
background: rgba(255, 255, 255, .08);
background: var(--primary-highlight-color, rgba(255, 255, 255, 0.08));
color: #fff
}
 
......@@ -19439,12 +19453,12 @@ ol.ui.list li[value]:before {
}
 
.ui.inverted.menu .link.item:active, .ui.inverted.menu a.item:active {
background: #757575;
background: var(--primary-color, #757575);
color: #fff
}
 
.ui.inverted.menu .active.item {
background: #757575;
background: var(--primary-highlight-color, rgba(255, 255, 255, 0.08));
color: #fff!important
}
 
......@@ -19462,7 +19476,7 @@ ol.ui.list li[value]:before {
}
 
.ui.inverted.menu .active.item:hover {
background: #757575;
background: var(--primary-highlight-color, #757575);
color: #fff!important
}
 
......@@ -19545,7 +19559,7 @@ ol.ui.list li[value]:before {
}
 
.ui.inverted.menu .teal.active.item, .ui.inverted.teal.menu {
background-color: #00b5ad
background-color: var(--primary-color, #00b5ad)
}
 
.ui.inverted.teal.menu .item:before {
......@@ -20019,10 +20033,10 @@ ol.ui.list li[value]:before {
padding: 1em 1.5em;
line-height: 1.4285em;
color: #252525;
-webkit-transition: opacity .5s ease, color .5s ease, background .5s ease, -webkit-box-shadow .5s ease;
transition: opacity .5s ease, color .5s ease, background .5s ease, -webkit-box-shadow .5s ease;
transition: opacity .5s ease, color .5s ease, background .5s ease, box-shadow .5s ease;
transition: opacity .5s ease, color .5s ease, background .5s ease, box-shadow .5s ease, -webkit-box-shadow .5s ease;
-webkit-transition: padding .5s ease, max-height .5s ease, opacity .5s ease, color .5s ease, background .5s ease, -webkit-box-shadow .5s ease;
transition: padding .5s ease, max-height .5s ease, opacity .5s ease, color .5s ease, background .5s ease, -webkit-box-shadow .5s ease;
transition: padding .5s ease, max-height .5s ease, opacity .5s ease, color .5s ease, background .5s ease, box-shadow .5s ease;
transition: padding .5s ease, max-height .5s ease, opacity .5s ease, color .5s ease, background .5s ease, box-shadow .5s ease, -webkit-box-shadow .5s ease;
border-radius: .07142857rem;
-webkit-box-shadow: 0 0 0 1px rgba(34, 36, 38, .22) inset, 0 0 0 0 transparent;
box-shadow: 0 0 0 1px rgba(34, 36, 38, .22) inset, 0 0 0 0 transparent
......@@ -20038,7 +20052,7 @@ ol.ui.list li[value]:before {
 
.ui.message .header {
display: block;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-weight: 700;
margin: -.14285714em 0 0 0
}
......@@ -21016,11 +21030,11 @@ ol.ui.list li[value]:before {
}
 
.ui.teal.table {
border-top: .2em solid #00b5ad
border-top: .2em solid var(--primary-color, #00b5ad)
}
 
.ui.inverted.teal.table {
background-color: #00b5ad!important;
background-color: var(--primary-color, #00b5ad)!important;
color: #fff!important
}
 
......@@ -21766,7 +21780,7 @@ ol.ui.list li[value]:before {
.ui.card>.content>.header, .ui.cards>.card>.content>.header {
display: block;
margin: '';
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
color: rgba(0, 0, 0, .85)
}
 
......@@ -22039,13 +22053,15 @@ ol.ui.list li[value]:before {
}
 
.ui.cards>.teal.card, .ui.teal.card, .ui.teal.cards>.card {
-webkit-box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 #00b5ad, 0 1px 3px 0 #d4d4d5;
box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 #00b5ad, 0 1px 3px 0 #d4d4d5
-webkit-box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 var(--primary-color, #00b5ad), 0 1px 3px 0 #d4d4d5;
box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 var(--primary-color, #00b5ad), 0 1px 3px 0 #d4d4d5
}
 
.ui.cards>.teal.card:hover, .ui.teal.card:hover, .ui.teal.cards>.card:hover {
-webkit-box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 #009c95, 0 1px 3px 0 #bcbdbd;
box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 #009c95, 0 1px 3px 0 #bcbdbd
-webkit-box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 var(--primary-highlight-color, #009c95)
, 0 1px 3px 0 #bcbdbd;
box-shadow: 0 0 0 1px #d4d4d5, 0 2px 0 0 var(--primary-highlight-color, #009c95)
, 0 1px 3px 0 #bcbdbd
}
 
.ui.blue.card, .ui.blue.cards>.card, .ui.cards>.blue.card {
......@@ -22994,7 +23010,7 @@ ol.ui.list li[value]:before {
.ui.items>.item>.content>.header {
display: inline-block;
margin: -.21425em 0 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-weight: 700;
color: rgba(0, 0, 0, .85)
}
......@@ -23341,7 +23357,7 @@ ol.ui.list li[value]:before {
}
 
.ui.statistic>.value, .ui.statistics .statistic>.value {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 4rem;
font-weight: 400;
line-height: 1em;
......@@ -23351,7 +23367,7 @@ ol.ui.list li[value]:before {
}
 
.ui.statistic>.label, .ui.statistics .statistic>.label {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1em;
font-weight: 700;
color: #252525;
......@@ -23550,7 +23566,7 @@ ol.ui.list li[value]:before {
}
 
.ui.statistics .teal.statistic>.value, .ui.teal.statistic>.value, .ui.teal.statistics .statistic>.value {
color: #00b5ad
color: var(--primary-color, #00b5ad)
}
 
.ui.blue.statistic>.value, .ui.blue.statistics .statistic>.value, .ui.statistics .blue.statistic>.value {
......@@ -23744,7 +23760,7 @@ ol.ui.list li[value]:before {
 
.ui.accordion .title:not(.ui) {
padding: .5em 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1em;
color: #252525
}
......@@ -24305,7 +24321,7 @@ ol.ui.list li[value]:before {
}
 
.ui.toggle.checkbox input:checked~.box:before, .ui.toggle.checkbox input:checked~label:before {
background-color: #ee2e24!important
background-color: #2185d0!important
}
 
.ui.toggle.checkbox input:checked~.box:after, .ui.toggle.checkbox input:checked~label:after {
......@@ -24319,7 +24335,7 @@ ol.ui.list li[value]:before {
}
 
.ui.toggle.checkbox input:focus:checked~.box:before, .ui.toggle.checkbox input:focus:checked~label:before {
background-color: #e90c00!important
background-color: #0d71bb!important
}
 
.ui.fitted.checkbox .box, .ui.fitted.checkbox label {
......@@ -24605,7 +24621,7 @@ body.dimmable>.dimmer {
.ui.dropdown>.dropdown.icon {
position: relative;
width: auto;
font-size: .85714286em;
font-size: .9em;
margin: 0 0 0 1em
}
 
......@@ -24823,9 +24839,9 @@ select.ui.dropdown {
z-index: 3;
margin: -.78571429em;
padding: .91666667em;
opacity: .8;
-webkit-transition: opacity .5s ease;
transition: opacity .5s ease
color: #999;
-webkit-transition: transform .2s ease;
transition: transform .2s ease
}
 
.ui.compact.selection.dropdown {
......@@ -24942,7 +24958,7 @@ select.ui.dropdown {
}
 
.ui.active.selection.dropdown>.dropdown.icon, .ui.visible.selection.dropdown>.dropdown.icon {
opacity: '';
transform: rotate(180deg);
z-index: 3
}
 
......@@ -25976,7 +25992,7 @@ select.ui.dropdown {
 
.ui.modal>.header {
display: block;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
background: #fff;
margin: 0;
padding: 1.25rem 1.5rem;
......@@ -26593,7 +26609,7 @@ a.ui.nag {
 
.ui.popup>.header {
padding: 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1.14285714em;
line-height: 1.2;
font-weight: 700
......@@ -27564,7 +27580,7 @@ a.ui.nag {
}
 
.ui.teal.progress .bar {
background-color: #00b5ad
background-color: var(--primary-color, #00b5ad)
}
 
.ui.teal.inverted.progress .bar {
......@@ -27957,7 +27973,7 @@ a.ui.nag {
 
.ui.search>.results .result .title {
margin: -.14285714em 0 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-weight: 700;
font-size: 1em;
color: rgba(0, 0, 0, .85)
......@@ -27979,7 +27995,7 @@ a.ui.nag {
}
 
.ui.search>.results>.message .header {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1rem;
font-weight: 700;
color: #252525
......@@ -28143,7 +28159,7 @@ a.ui.nag {
width: 100px;
white-space: nowrap;
background: 0 0;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif);
font-size: 1em;
padding: .4em 1em;
font-weight: 700;
......
/* ---------------------------------- */
/* HEADER */
/* APP */
/* ---------------------------------- */
header {
background: #373636;
body {
height: 100%;
width: 100%;
margin: 0;
}
#app {
position: relative;
min-height: 100vh;
/* keep the space for loader, before page contents are injected */
display: flex;
/* used to fix height on sticky header and footer */
flex-direction: column;
/* used to fix height on sticky header and footer */
}
#app-header {
position: sticky;
top: 0;
z-index: 1;
background: var(--header-color, #373636);
.ui.inverted.menu {
background: var(--header-color, #373636);
}
.item {
background: var(--header-color, #373636);
}
}
#app-content {
overflow: auto;
flex: 1 0 auto;
/* used to fix height on sticky header and footer */
min-height: 61px;
/* value by default of the header, defined here to be sync with anchor below, in order to keep the page stuck to top */
position: relative;
/* for anchor below */
}
#scroll-top-anchor {
position: absolute;
top: -61px;
visibility: hidden;
}
.page-content {
max-width: 1200px;
padding: 0 2em;
margin: 2em auto;
}
#map {
width: 100%;
height: 100%;
min-height: 250px;
touch-action: none;
/* workaround for modifying feature on mobile */
}
#app-footer {
overflow: hidden;
background-color: #464646;
text-align: center;
flex-shrink: 0;
/* used to fix height on sticky header and footer */
position: sticky;
bottom: 0;
z-index: 1000;
}
#app-footer .ui.text.menu {
min-height: 30px !important;
}
main {
padding: 2em 0em;
#app-footer .ui.text.menu .item {
color: #ffffff;
padding: 5px 14px;
}
#app-footer .ui.text.menu a.item:hover {
color: var(--primary-color, #008c86);
}
#app-footer .ui.text.menu .item:not(:first-child) {
border-left: 1px solid rgba(34, 36, 38, .15);
}
/* ---------------------------------- */
/* UTILS */
/* UTILS */
/* ---------------------------------- */
.inline {
display: inline;
}
.no-margin {
margin: 0 !important;
}
......@@ -19,42 +106,67 @@ main {
.margin-top {
margin-top: 1rem;
}
/* ---------------------------------- */
/* UTILS */
/* ---------------------------------- */
.margin-bottom {
margin-bottom: 1rem;
}
.tiny-margin {
margin: 0.1rem 0 0.1rem 0.1rem !important;
}
.tiny-margin-left {
margin-left: 0.1rem !important;
}
.ellipsis {
text-overflow: ellipsis;
overflow: hidden;
}
.nowrap {
white-space: nowrap;
}
.important-flex {
display: flex !important;
}
.pointer:hover {
cursor: pointer;
cursor: pointer !important;
}
.dimmer-anchor {
position: relative;
}
.full-width {
width: 100%;
}
/* ---------------------------------- */
/* MAIN */
/* MAIN */
/* ---------------------------------- */
.button-hover-orange:hover {
background: #fbbd08 !important;
}
.button-hover-green:hover {
background: #5bba21 !important;
}
.button-hover-red:hover {
background: #ee2e24 !important;
}
.ui.button.button-hover-red:hover, .ui.button.button-hover-red:hover i.icon,
.ui.button.button-hover-green:hover, .ui.button.button-hover-green:hover i.icon {
.ui.button.button-hover-red:hover,
.ui.button.button-hover-red:hover i.icon,
.ui.button.button-hover-green:hover,
.ui.button.button-hover-green:hover i.icon {
color: #fff !important;
}
.ui.button.button-hover-red:hover i.icon,
.ui.button.button-hover-green:hover i.icon {
transition: all 0.5s ease !important;
......@@ -65,7 +177,7 @@ main {
}
.ui.horizontal.divider {
color: #1ab2b6!important;
color: var(--primary-color, #008c86) !important;
padding-top: 1.5em;
}
......@@ -73,7 +185,7 @@ main {
display: none;
}
.ui.dropdown .menu > .header {
.ui.dropdown .menu>.header {
font-size: 1em;
text-transform: none;
}
......@@ -83,27 +195,33 @@ main {
overflow: auto;
}
.ui.dropdown .menu.text-wrap > .item {
.ui.dropdown .menu.text-wrap>.item {
white-space: normal;
word-wrap: normal;
}
.ui.checkbox.disabled > input {
.ui.checkbox.disabled>input {
cursor: default !important;
}
/* Add basemap view */
#form-layers .ui.buttons{
margin-bottom: 1rem;
#form-layers button.button:not(:last-of-type) {
margin-right: 0.5em !important;
}
#form-layers .errorlist{
#form-layers .errorlist {
list-style: none;
padding-left: 0;
color: #9f3a38;
}
#form-layers .infoslist {
list-style: none;
padding-left: 0;
color: #38989f;
}
/* Fix semantic ui overflow when is too long */
.layer-item .form div.text {
width: 100%
......@@ -119,9 +237,9 @@ main {
}
/* Thicker borders for each basemap segment */
#form-layers [data-segments=basemap_set-SEGMENTS] > .ui.segment {
#form-layers [data-segments=basemap_set-SEGMENTS]>.ui.segment {
margin-bottom: 3rem;
border: 1px solid rgba(34,36,38,.30);
border: 1px solid rgba(34, 36, 38, .30);
}
......@@ -139,65 +257,49 @@ main {
opacity: 0.9;
}
/* */
/* ---------------------------------- */
/* LEAFLET DRAW TOOLBAR */
/* LEAFLET DRAW TOOLBAR */
/* ---------------------------------- */
.leaflet-draw-toolbar a.leaflet-draw-draw-circlemarker,
.leaflet-draw-toolbar a.leaflet-draw-draw-polyline,
.leaflet-draw-toolbar a.leaflet-draw-draw-polygon {
background-color: #FFA19E;
}
/* ---------------------------------- */
/* LEAFLET*/
/* ---------------------------------- */
.leaflet-container {
background: #FFF;
background-color: #FFA19E;
}
/* ---------------------------------- */
/* FOOTER */
/* ---------------------------------- */
footer {
background-color: #464646;
text-align: center;
}
footer .ui.text.menu .item {
color: #ffffff;
padding: 5px 14px;
}
footer .ui.text.menu a.item:hover {
color: #1ab2b6;
}
footer .ui.text.menu .item:not(:first-child) {
border-left: 1px solid rgba(34,36,38,.15);
}
/* ---------------------------------- */
/* ERROR LIST */
/* ERROR LIST */
/* ---------------------------------- */
.errorlist {
margin-top: 1rem;
padding: 0;
}
.errorlist > li {
.infoslist {
margin-top: 0.1rem;
padding: 0;
}
.errorlist>li {
list-style: none;
color: rgb(177, 55, 55);
border: thin solid rgb(197, 157, 157);
border: thin solid rgb(197, 157, 157);
border-radius: 3px;
background-color: rgb(250, 241, 242);
padding: 1rem;
padding: 0.5rem 1rem;
}
.infoslist>li {
list-style: none;
color: #38989f;
border-radius: 3px;
padding: 0;
text-align: right;
}
/* ---------------------------------- */
/* PAGINATION */
/* PAGINATION */
/* ---------------------------------- */
.custom-pagination {
......@@ -207,12 +309,13 @@ footer .ui.text.menu .item:not(:first-child) {
font-size: 1.2em;
}
.custom-pagination > .page-item > .page-link {
.custom-pagination>.page-item>.page-link {
border: none;
font-weight: 400;
color: #008080;
}
.custom-pagination > .page-item.active > .page-link {
.custom-pagination>.page-item.active>.page-link {
color: #008080;
background-color: transparent;
font-weight: bolder;
......@@ -220,18 +323,20 @@ footer .ui.text.menu .item:not(:first-child) {
padding: 0.325em 0.75em;
pointer-events: none;
}
.custom-pagination > .page-item.disabled > .page-link {
.custom-pagination>.page-item.disabled>.page-link {
opacity: 0.5;
pointer-events: none;
}
.custom-pagination > div > .page-item > .page-link {
.custom-pagination>div>.page-item>.page-link {
border: none;
font-weight: 400;
color: #008080;
padding: 0.325em 0.75em;
}
.custom-pagination > div > .page-item.active > .page-link {
.custom-pagination>div>.page-item.active>.page-link {
color: #008080;
background-color: transparent;
font-weight: bolder;
......@@ -240,28 +345,32 @@ footer .ui.text.menu .item:not(:first-child) {
padding: 0.325em 0.75em;
pointer-events: none;
}
.custom-pagination > div > .page-item.disabled > .page-link {
.custom-pagination>div>.page-item.disabled>.page-link {
opacity: 0.5;
padding: 0.325em 0.75em;
pointer-events: none;
}
/* ---------------------------------- */
/* MULTISELECT */
/* MULTISELECT */
/* ---------------------------------- */
.multiselect {
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif) !important;
}
.multiselect__tags {
border: 1px solid #ced4da;
border-radius: 0 !important;
font-family: 'Roboto Condensed', Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
font-family: var(--font-family, 'Roboto Condensed', 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif) !important;
font-size: 1rem !important;
}
.multiselect__tags > .multiselect__input {
.multiselect__tags>.multiselect__input {
border: none !important;
font-size: 1rem !important;
overflow: hidden;
text-overflow: ellipsis;
}
.multiselect__placeholder {
......@@ -270,7 +379,10 @@ footer .ui.text.menu .item:not(:first-child) {
padding-top: 0;
}
.multiselect__single, .multiselect__tags, .multiselect__content, .multiselect__option {
.multiselect__single,
.multiselect__tags,
.multiselect__content,
.multiselect__option {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
......@@ -282,6 +394,11 @@ footer .ui.text.menu .item:not(:first-child) {
.multiselect__select {
z-index: 1 !important;
}
.multiselect__content-wrapper {
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15);
}
.multiselect__clear {
position: absolute;
right: 1px;
......@@ -291,7 +408,10 @@ footer .ui.text.menu .item:not(:first-child) {
cursor: pointer;
z-index: 9;
background-color: #fff;
padding: 0 4px;
text-align: center;
}
.multiselect__spinner {
z-index: 2 !important;
background-color: #fff;
......@@ -299,10 +419,11 @@ footer .ui.text.menu .item:not(:first-child) {
top: 2px;
}
.menu.projects > .item > .multiselect {
.menu.projects>.item>.multiselect {
min-height: 0px !important;
}
.menu.projects > .item > .multiselect > .multiselect__tags {
.menu.projects>.item>.multiselect>.multiselect__tags {
min-height: 0px !important;
}
......@@ -310,11 +431,28 @@ footer .ui.text.menu .item:not(:first-child) {
background: #fff !important;
color: #35495e !important;
}
.multiselect__option--highlight {
background: #f3f3f3 !important;
color: #35495e !important;
}
.multiselect__option--selected.multiselect__option--highlight {
background: #f3f3f3 !important;
color: #35495e !important;
}
.multiselect__clear i.icon {
font-size: .75em;
color: #999;
margin: 0;
}
/* ---------------------------------- */
/* OVERRIDE SEMANTIC STYLES */
/* ---------------------------------- */
.ui.page.dimmer {
/* keep the dimmer above the dropdown (z-index 1001: above the map)*/
z-index: 1002;
}
\ No newline at end of file
/* OPENLAYERS */
.ol-zoom{
right: 5px !important;
left:unset !important;
}
.ol-popup {
position: absolute;
background-color: white;
padding: 15px 5px 15px 15px;
border-radius: 10px;
bottom: 12px;
left: -120px;
width: 240px;
line-height: 1.4;
-webkit-box-shadow: 0 3px 14px rgba(0,0,0,.4);
box-shadow: 0 3px 14px rgba(0,0,0,.4);
}
.ol-popup #popup-content {
line-height: 1.3;
font-size: .95em;
}
.ol-popup #popup-content h4 {
margin-right: 15px;
margin-bottom: .5em;
color: #cacaca;
}
.ol-popup #popup-content h4,
.ol-popup #popup-content div {
text-overflow: ellipsis;
overflow: hidden;
}
.ol-popup #popup-content div {
color: #434343;
}
.ol-popup #popup-content .fields {
max-height: 200px;
overflow-y: scroll;
overflow-x: hidden;
padding-right: 10px;
display: block; /* overide .ui.form.fields rule conflict in featureEdit page */
margin: 0; /* overide .ui.form.fields rule conflict in featureEdit page */
}
.ol-popup #popup-content .divider {
margin-bottom: 0;
}
.ol-popup #popup-content #customFields h5 {
max-height: 20;
margin: .5em 0;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 50%;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 50%;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 4px;
right: 0;
width: 24px;
height: 24px;
font: 18px/24px Tahoma,Verdana,sans-serif;
color: #757575;
}
.ol-popup-closer:after {
content: "×";
}
.ol-scale-line {
left: 2em;
background: hsla(0,0%,100%,.5);
padding: 0;
}
.ol-scale-line-inner {
color: #333;
font-size: 0.9em;
text-align: left;
padding-left: 0.5em;
border: 2px solid #777;
border-top: none;
}
.ol-control {
border: 2px solid rgba(0,0,0,.2);
background-clip: padding-box;
padding: 0;
}
.ol-control button {
background-color: #fff;
color: #000;
height: 30px;
width: 30px;
font: 700 18px Lucida Console,Monaco,monospace;
margin: 0;
}
.ol-control button:hover {
cursor: pointer;
background-color: #ebebeb;
}
.ol-control button:focus {
background-color: #ebebeb;
}
/* hide the popup before the map get loaded */
.map-container > #popup.ol-popup {
display: none;
}
.ol-full-screen {
top: calc(1em + 60px);
right: 5px !important;
}
/* Geolocation button */
div.geolocation-container {
position: absolute;
right: 6px;
z-index: 9;
border: 2px solid rgba(0,0,0,.2);
background-clip: padding-box;
padding: 0;
border-radius: 4px;
}
button.button-geolocation {
border: none;
padding: 0;
margin: 0;
text-align: center;
background-color: #fff;
color: rgb(39, 39, 39);
width: 30px;
height: 30px;
font: 700 18px Lucida Console,Monaco,monospace;
border-radius: 2px;
line-height: 1.15;
cursor: pointer;
}
button.button-geolocation:hover {
background-color: #ebebeb;
}
button.button-geolocation.tracking {
background-color: rgba(255, 145, 0, 0.904);
color: #fff;
}
button.button-geolocation i {
margin: 0;
vertical-align: top; /* strangely top is the only value that center at middle */
background-image: url(../img/geolocation-icon.png);
background-size: cover;
width: 25px;
height: 25px;
}
\ No newline at end of file
......@@ -13,8 +13,7 @@
border: 1px solid grey;
top: 0;
position: absolute;
/* Under this value, the map hide the sidebar */
z-index: 400;
z-index: 9;
}
.sidebar-layers {
......@@ -62,7 +61,7 @@
.sidebar-container.expanded .layers-icon svg path,
.sidebar-container.closing .layers-icon svg path {
fill: #00b5ad;
fill: var(--primary-color, #00b5ad);
}
@keyframes open-sidebar {
......@@ -132,7 +131,7 @@
}
.layers-icon:hover svg path {
fill: #00b5ad;
fill: var(--primary-color, #00b5ad);
}
.basemaps-title {
......@@ -144,7 +143,6 @@
}
/* Layer item */
.layer-item {
padding-bottom: 0.5rem;
}
......@@ -164,6 +162,7 @@
.range-container {
display: flex;
min-width: 15em; /* give space for the bubble since adding a min-width to keep its shape */
}
.range-output-bubble {
......@@ -172,6 +171,8 @@
padding: 4px 7px;
border-radius: 40px;
background-color: #2c3e50;
min-width: 2em;
text-align: center;
}
/* Overrides default padding of semantic-ui accordion */
......
......@@ -32,4 +32,4 @@ axios.interceptors.response.use(function (response) {
return Promise.reject(error);
});
export default axios;
\ No newline at end of file
export default axios;
<template>
<div
id="user-activity"
class="ui stackable cards"
>
<!-- EVENTS -->
<div class="red card">
<div class="content">
<div class="center aligned header">
Mes dernières notifications reçues
</div>
<div class="center aligned description">
<div class="ui relaxed list">
<div
v-for="item in events"
:key="item.id"
class="item"
>
<div :class="['content', { 'ellipsis nowrap': item.related_feature.title }]">
{{ getNotificationName(item.event_type, item.object_type) }}
<div
v-if="item.object_type === 'project'"
>
<router-link
v-if="item.project_title"
:to="{
name: 'project_detail',
params: { slug: item.project_slug },
}"
>
{{ item.project_title }}
</router-link>
<span
v-else
class="meta"
><del>{{ item.project_slug }}</del>&nbsp;(supprimé)</span>
</div>
<div v-else>
<FeatureFetchOffsetRoute
v-if="item.related_feature.deletion_on === 'None'"
:feature-id="item.feature_id"
:properties="{
feature_type: {
slug: item.feature_type_slug
},
title: item.related_feature.title,
...item
}"
/>
<span
v-else
class="meta"
><del>{{ item.data.feature_title || item.feature_id }}</del>&nbsp;(supprimé)</span>
</div>
<div class="description">
<em>[ {{ item.created_on }}
<span v-if="user">
, par {{ item.display_user }}
</span>
]</em>
</div>
</div>
</div>
<em
v-if="!events || events.length === 0"
>Aucune notification pour le moment.</em>
</div>
</div>
</div>
</div>
<!-- FEATURES -->
<div class="orange card">
<div class="content">
<div class="center aligned header">
Mes derniers signalements
</div>
<div class="center aligned description">
<div class="ui relaxed list">
<div
v-for="item in features"
:key="item.id"
class="item"
>
<div class="content">
<div>
<FeatureFetchOffsetRoute
v-if="item.related_feature.deletion_on === 'None'"
:feature-id="item.feature_id"
:properties="{
feature_type: {
slug: item.feature_type_slug
},
title: item.related_feature.title,
...item
}"
/>
<span
v-else
class="meta"
>
<del>{{ item.data.feature_title || item.feature_id }}</del>&nbsp;(supprimé)
</span>
</div>
<div class="description">
<em>[ {{ item.created_on }}
<span v-if="user">
, par {{ item.display_user }}
</span>
]</em>
</div>
</div>
</div>
<em
v-if="!features || features.length === 0"
>Aucun signalement pour le moment.</em>
</div>
</div>
</div>
</div>
<!-- COMMENTS -->
<div class="yellow card">
<div class="content">
<div class="center aligned header">
Mes derniers commentaires
</div>
<div class="center aligned description">
<div class="ui relaxed list">
<div
v-for="item in comments"
:key="item.id"
class="item"
>
<div class="content">
<div>
<FeatureFetchOffsetRoute
v-if="item.related_feature.deletion_on === 'None'"
:feature-id="item.feature_id"
:properties="{
feature_type: {
slug: item.feature_type_slug
},
title: quoteComment(item.data.comment),
...item
}"
/>
<span
v-else
class="meta"
>
<del>{{ item.data.comment }}</del>&nbsp;(supprimé)
</span>
</div>
<div class="description">
<em>[ {{ item.created_on }}
<span v-if="user">
, par {{ item.display_user }}
</span>
]</em>
</div>
</div>
</div>
<em
v-if="!comments || comments.length === 0"
>Aucun commentaire pour le moment.</em>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import miscAPI from '@/services/misc-api';
import FeatureFetchOffsetRoute from '@/components/Feature/FeatureFetchOffsetRoute';
export default {
name: 'UserActivity',
components: {
FeatureFetchOffsetRoute,
},
data() {
return {
events: [],
features: [],
comments: [],
};
},
computed: {
...mapState([
'user',
]),
isSharedProject() {
return this.$route.path.includes('projet-partage');
},
},
created(){
this.getEvents();
// unset project to avoid interfering with generating query in feature links
this.$store.commit('projects/SET_PROJECT', null);
},
methods: {
getEvents(){
miscAPI.getUserEvents(this.$route.params.slug)
.then((data)=>{
this.events = data.events;
this.features = data.features;
this.comments = data.comments;
});
},
getNotificationName(eventType, objectType) {
if (eventType === 'create') {
if (objectType === 'feature') {
return 'Signalement créé';
} else if (objectType === 'comment') {
return 'Commentaire créé';
} else if (objectType === 'attachment') {
return 'Pièce jointe ajoutée';
} else if (objectType === 'project') {
return 'Projet créé';
}
} else if (eventType === 'update') {
if (objectType === 'feature') {
return 'Signalement mis à jour';
} else if (objectType === 'project') {
return 'Projet mis à jour';
}
} else if (eventType === 'delete') {
if (objectType === 'feature') {
return 'Signalement supprimé';
} else if (objectType === 'project') {
return 'Projet mis à jour';
} else {
return 'Événement inconnu';
}
}
},
quoteComment(comment) {
return `"${comment}"`;
},
}
};
</script>
<style scoped lang="less">
#user-activity {
flex-flow: column;
margin: 1em 0;
.card {
margin: .875em 0;
}
}
</style>
<template>
<div>
<h4 class="ui horizontal divider header">
PROFIL
</h4>
<div class="ui divided list">
<div class="item">
<div class="right floated content">
<div class="description">
<span v-if="user.username">{{ user.username }} </span>
</div>
</div>
<div class="content">
Nom d'utilisateur
</div>
</div>
<div class="item">
<div class="right floated content">
<div class="description">
{{ userFullname }}
</div>
</div>
<div class="content">
Nom complet
</div>
</div>
<div class="item">
<div class="right floated content">
<div class="description">
{{ user.email }}
</div>
</div>
<div class="content">
Adresse e-mail
</div>
</div>
<div class="item">
<div class="right floated content">
<div class="description">
{{ user.is_superuser ? "Oui" : "Non" }}
</div>
</div>
<div class="content">
Administrateur
</div>
</div>
</div>
<div
v-if="qrcode"
class="qrcode"
>
<img
:src="qrcode"
alt="qrcode"
>
<p>
Ce QR code vous permet de vous connecter à l'application mobile GéoContrib (bientôt disponible)
</p>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import QRCode from 'qrcode';
export default {
name: 'UserProfile',
data() {
return {
qrcode: null
};
},
computed: {
...mapState([
'configuration',
'user',
'userToken'
]),
userFullname() {
if (this.user.first_name || this.user.last_name) {
return `${this.user.first_name} ${this.user.last_name}`;
}
return null;
},
},
created() {
this.GET_USER_TOKEN()
.then(async () => {
try {
const qrcodeData = {
url: `${this.configuration.VUE_APP_DJANGO_BASE}/geocontrib/`,
token: this.userToken
};
this.qrcode = await QRCode.toDataURL(JSON.stringify(qrcodeData));
} catch (err) {
console.error(err);
}
})
.catch((err) => {
console.error(err);
});
},
methods: {
...mapActions([
'GET_USER_TOKEN'
])
}
};
</script>
<style scoped lang="less">
.qrcode {
img {
display: block;
margin: auto;
width: 12rem;
}
p {
font-size: 0.8rem;
font-style: italic;
text-align: center;
}
}
</style>
<template>
<div>
<h4 class="ui horizontal divider header">
MES PROJETS
</h4>
<div class="ui divided items">
<div
:class="['ui inverted dimmer', { active: projectsLoading }]"
>
<div class="ui text loader">
Récupération des projets en cours...
</div>
</div>
<div
v-for="project in projectsArray"
:key="project.slug"
class="item"
>
<div
v-if="user_permissions[project.slug].can_view_project"
class="item-content-wrapper"
>
<div class="ui tiny image">
<img
v-if="project.thumbnail"
class="ui small image"
alt="Thumbnail projet"
:src="
project.thumbnail.includes('default')
? require('@/assets/img/default.png')
: DJANGO_BASE_URL + project.thumbnail + refreshId()
"
height="200"
>
</div>
<div class="middle aligned content">
<router-link
:to="{
name: 'project_detail',
params: { slug: project.slug },
}"
class="header"
>
{{ project.title }}
</router-link>
<div class="description">
<p>{{ project.description }}</p>
</div>
<div class="meta top">
<span
class="right floated"
>
<strong>Projet {{ project.moderation ? "" : "non" }} modéré</strong>
</span>
<span>
Niveau d'autorisation requis : {{ project.access_level_pub_feature }}
</span><br>
<span>
Mon niveau d'autorisation :
<span v-if="USER_LEVEL_PROJECTS && project">
{{ USER_LEVEL_PROJECTS[project.slug] }}
</span>
<span v-if="user && user.is_administrator">
{{ "+ Gestionnaire métier" }}
</span>
</span>
</div>
<div class="meta">
<span
class="right floated"
:data-tooltip="`Projet créé le ${project.created_on}`"
>
<i
class="calendar icon"
aria-hidden="true"
/>
&nbsp;{{ project.created_on }}
</span>
<span data-tooltip="Membres">
{{ project.nb_contributors }}&nbsp;
<i
class="user icon"
aria-hidden="true"
/>
</span>
<span data-tooltip="Signalements publiés">
{{ project.nb_published_features }}&nbsp;
<i
class="map marker icon"
aria-hidden="true"
/>
</span>
<span data-tooltip="Commentaires">
{{ project.nb_published_features_comments }}&nbsp;
<i
class="comment icon"
aria-hidden="true"
/>
</span>
</div>
</div>
</div>
</div>
<!-- PAGINATION -->
<Pagination
v-if="count"
:nb-pages="Math.ceil(count/10)"
@page-update="changePage"
/>
</div>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex';
import Pagination from '@/components/Pagination.vue';
export default {
name: 'UserProjectList',
components: {
Pagination,
},
data() {
return {
projectsLoading: true,
};
},
computed: {
...mapState([
'user',
'USER_LEVEL_PROJECTS',
'user_permissions',
]),
// todo : filter projects to user
...mapState('projects', [
'projects',
'count',
]),
DJANGO_BASE_URL() {
return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
},
isSharedProject() {
return this.$route.path.includes('projet-partage');
},
availableProjects() {
if (this.isSharedProject) {
return this.projects.filter((el) => el.slug === this.$route.params.slug);
}
return this.projects;
},
projectsArray() { //* if only one project, only project object is returned
return Array.isArray(this.projects) ? this.projects : [this.projects];
}
},
created(){
this.SET_PROJECTS([]); //* empty previous project to avoid undefined user_permissions[project.slug]
this.getData();
},
methods: {
...mapMutations('projects', [
'SET_CURRENT_PAGE',
'SET_PROJECTS',
]),
...mapActions('projects', [
'GET_PROJECTS',
]),
refreshId() {
const crypto = window.crypto || window.msCrypto;
var array = new Uint32Array(1);
return '?ver=' + crypto.getRandomValues(array); // Compliant for security-sensitive use cases
},
getData(page) {
this.loading = true;
this.GET_PROJECTS({ ismyaccount: true, projectSlug: this.$route.params.slug, page })
.then(() => this.projectsLoading = false)
.catch(() => this.projectsLoading = false);
},
changePage(e) {
this.getData(e);
},
}
};
</script>
<style lang="less" scoped>
.ui.divided.items {
.item {
.item-content-wrapper {
width: 100%;
margin: 0;
padding: 1em 0;
display: flex;
.middle.aligned.content {
.header {
font-size: 1.28571429em;
font-weight: 600;
color: rgb(31, 31, 31)
}
}
}
}
> .item:nth-child(2) {
border: none !important;
}
}
.description {
p {
text-align: justify;
}
}
@media only screen and (min-width: 767px) {
.item-content-wrapper {
align-items: flex-start;
.middle.aligned.content {
width: 100%;
padding: 0 0 0 1.5em;
.meta.top {
span {
line-height: 1.2em;
}
}
}
}
}
@media only screen and (max-width: 767px) {
.item-content-wrapper {
flex-direction: column;
align-items: center;
.middle.aligned.content {
width: 80%;
padding: 1.5em 0 0;
.meta.top {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
.right.floated {
float: none !important;
margin-left: 0 !important;
margin-bottom: 0.5em;
}
span {
margin: 0.15em 0;
}
}
}
}
}
</style>
<template>
<div id="app-footer">
<div class="ui compact text menu">
<router-link
:to="{name: 'mentions'}"
class="item"
>
Mentions légales
</router-link>
<router-link
:to="{name: 'aide'}"
class="item"
>
Aide
</router-link>
<p class="item">
Version {{ PACKAGE_VERSION }}
</p>
</div>
</div>
</template>
<script>
export default {
name: 'AppFooter',
computed: {
PACKAGE_VERSION: () => process.env.PACKAGE_VERSION || '0',
}
};
</script>