@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
109 lines (108 loc) • 7.72 kB
JavaScript
import { htmlFor as uHtmlFor } from 'uhtml/keyed';
import { html as uHtml } from 'uhtml';
// SPDX-License-Identifier: Apache-2.0
import GirafeHTMLElement from '../../../base/GirafeHTMLElement.js';
import GroupLayer from '../../../models/layers/grouplayer.js';
import Layer from '../../../models/layers/layer.js';
export default class MobileThemeComponent extends GirafeHTMLElement {
templateUrl = null;
styleUrls = null;
template = () => {
return uHtml `<style>
.hidden{display:none}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}button,input,select,textarea{font:inherit}.gg-icon-button,.gg-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-button{text-align:left}.gg-small{flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 2.5);margin:0}.gg-small span{margin-left:.5rem;font-size:1rem}.girafe-button-big{filter:drop-shadow(0 0 8px #0000004d);background-color:var(--bkg-color);width:3.5rem;height:3.5rem;color:var(--text-color);border:none;border-radius:4rem;flex-direction:column;align-items:center;padding:.5rem;display:flex}.girafe-button-big img{width:95%;height:auto;padding:5%;overflow:hidden}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color)}
</style><style>
header{background:#fff;margin:0;position:sticky;top:-5px}.container{scrollbar-width:thin;width:100%}.tiles{grid-template-columns:repeat(3,1fr);align-items:start;gap:.5rem;display:grid}.item{text-align:left;background:0 0;border:none;font-size:.8rem}.item img{border:solid 2px var(--bkg-color);border-radius:5px;width:100%;margin:0}.item.active img{border:solid 2px var(--text-color);border-radius:5px;width:100%;margin:0}h3{text-align:center;font-variant:small-caps;background-color:var(--text-color);color:var(--bkg-color);padding:1rem;font-size:1rem}.counter{float:right}
</style>
<style>${this.customStyle}</style>
<div class="${this.state.interface.swipeupPanelContent === 'selector' ? '' : 'hidden'}"><header class="gg-tabs"><button class="${this.activeTab === 'themes' ? 'gg-tab active' : 'gg-tab'}" i18n="Themes" onclick="${() => this.changeTab('themes')}"></button> <button class="${this.activeTab === 'selected' ? 'gg-tab active' : 'gg-tab'}" onclick="${() => this.changeTab('selected')}"><span i18n="My selection"></span> <span id="counter" class="counter"></span></button> <button id="basemap-button" class="${this.activeTab === 'basemaps' ? 'gg-tab active' : 'gg-tab'}" i18n="Basemaps" onclick="${() => this.changeTab('basemaps')}"></button></header><div class="${this.activeTab === 'themes' ? 'container' : 'hidden'}"><div class="${this.state.themes.lastSelectedTheme !== null ? 'hidden' : 'tiles'}">${Object.values(this.state.themes._allThemes).map((theme) => uHtmlFor(theme, theme.id) ` <button onclick="${() => this.changeTheme(theme)}" class="item"><img alt="Theme icon" src="${theme.icon}"> <span i18n="${theme.name}"></span></button> `)}</div><div class="${this.state.themes.lastSelectedTheme === null ? 'hidden' : 'layers'}"><girafe-theme themeid="${this.state.themes.lastSelectedTheme?.id}"></girafe-theme></div></div><div class="${this.activeTab === 'selected' ? 'container' : 'hidden'}"><div class="layers">${Array.from(this.activeLayersByGroup.keys()).map(group => uHtmlFor(group, group.treeItemId) `<h3 i18n="${group.name}">${group.name}</h3><div class="children">${this.activeLayersByGroup.get(group).map(layer => uHtmlFor(layer, layer.treeItemId) `<girafe-layer-selected layerid="${layer.treeItemId}"></girafe-layer-selected>`)}</div>`)}</div></div><div class="${this.activeTab === 'basemaps' ? 'container' : 'hidden'}"><div class="tiles">${Object.values(this.state.basemaps).map(basemap => uHtmlFor(basemap, basemap.id) ` <button onclick="${() => this.changeBasemap(basemap)}" class="${this.state.activeBasemaps.length > 0 && this.state.activeBasemaps[0] === basemap ? 'item active' : 'item'}"><img alt="Basemap thumbnail" src="${basemap.thumbnail}"> <span i18n="${basemap.name}"></span></button> `)}</div></div></div>
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
};
activeTab = 'themes';
activeLayersByGroup = new Map();
constructor() {
super('themes-select');
}
registerEvents() {
this.subscribe('interface.swipeupPanelContent', () => {
this.refreshRender();
});
this.subscribe('themes.lastSelectedTheme', () => {
this.refreshRender();
});
this.subscribe('themes.isLoaded', (_, isLoaded) => {
if (isLoaded) {
this.refreshRender();
}
});
this.subscribe(/layers\.layersList\..*\.activeState/, () => {
this.setActiveLayersByGroups();
});
}
setActiveLayersByGroups() {
const activeLayers = this.context.layerManager.getFlattenedLayerTree(this.state.layers.layersList).filter((l) => {
return l instanceof Layer && l.active;
});
const activeLayersByGroups = new Map();
for (const layer of activeLayers) {
let parent = layer.parent;
while (parent.parent instanceof GroupLayer) {
// Get the top parent
parent = parent.parent;
}
let children;
if (activeLayersByGroups.has(parent)) {
children = activeLayersByGroups.get(parent);
}
else {
children = [];
activeLayersByGroups.set(parent, children);
}
children.push(layer);
}
this.activeLayersByGroup = activeLayersByGroups;
// Do not call refreshRender here, because if the user delesect a layer, we want to keep it visible
// until he switch tab. This will allow him to reselect it if he wants
const counter = this.shadow.getElementById('counter');
if (counter) {
counter.innerHTML = `(${activeLayers.length})`;
}
}
changeTab(tab) {
this.activeTab = tab;
this.refreshRender();
}
changeBasemap(basemap) {
this.state.projection = basemap.projection ?? this.context.configManager.Config.map.srid;
this.state.activeBasemaps = [basemap];
this.refreshRender();
}
// TODO REG : Merge with method onThemeChanged from the desktop component
changeTheme(theme) {
this.state.themes.lastSelectedTheme = theme;
if (theme.disclaimer) {
this.state.infobox.elements.push({
id: theme.treeItemId,
text: theme.disclaimer,
type: 'info'
});
}
if (theme.location != null || theme.zoom != null) {
const view = this.context.mapManager.getMap().getView();
view.animate({
center: theme.location ?? view.getCenter(),
zoom: theme.zoom ?? view.getZoom(),
duration: 1000
});
}
this.refreshRender();
}
connectedCallback() {
super.connectedCallback();
this.render();
if (!this.context.configManager.Config.basemaps.show) {
this.context.stateManager.state.interface.basemapComponentVisible = false;
this.shadow.getElementById('basemap-button').style.display = 'none';
}
this.registerEvents();
}
}