@geogirafe/lib-geoportal 1.2.0-dev.2853894139 → 1.2.0-dev.2857838548

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -247,6 +247,7 @@
247
247
  "geoadminch_other": "Andere",
248
248
  "geoadminch_parcel": "Parzellen",
249
249
  "geoadminch_zipcode": "PLZ",
250
+ "GeoGirafe is a flexible application to build online geoportals.": "GeoGirafe ist eine flexible Applikation um Online-Geoportale zu erstellen.",
250
251
  "GeoJSON": "GeoJSON",
251
252
  "Geolocation browser error": "Ihr Browser unterstützt keine Geolokalisierung",
252
253
  "Geolocation error": "Geolocation-Fehler",
@@ -249,6 +249,7 @@
249
249
  "geoadminch_other": "Other",
250
250
  "geoadminch_parcel": "Parcels",
251
251
  "geoadminch_zipcode": "ZIP codes",
252
+ "GeoGirafe is a flexible application to build online geoportals.": "GeoGirafe is a flexible application to build online geoportals.",
252
253
  "GeoJSON": "GeoJSON",
253
254
  "Geolocation browser error": "Your browser does not support geolocation",
254
255
  "Geolocation error": "Geolocation error",
@@ -247,6 +247,7 @@
247
247
  "geoadminch_other": "Autres",
248
248
  "geoadminch_parcel": "Parcelles",
249
249
  "geoadminch_zipcode": "Codes postaux",
250
+ "GeoGirafe is a flexible application to build online geoportals.": "GeoGirafe est une application flexible permettant de créer des géoportails en ligne.",
250
251
  "GeoJSON": "GeoJSON",
251
252
  "Geolocation browser error": "Votre navigateur ne supporte pas la géolocalisation",
252
253
  "Geolocation error": "Erreur de géolocalisation",
@@ -247,6 +247,7 @@
247
247
  "geoadminch_other": "Altri",
248
248
  "geoadminch_parcel": "Parcelle",
249
249
  "geoadminch_zipcode": "Codici postali",
250
+ "GeoGirafe is a flexible application to build online geoportals.": "GeoGirafe è un'applicazione flessibile per creare geoportali online.",
250
251
  "GeoJSON": "GeoJSON",
251
252
  "Geolocation browser error": "Il tuo browser non supporta la geolocalizzazione",
252
253
  "Geolocation error": "Errore di geolocalizzazione",
@@ -8,10 +8,10 @@ export default class OauthComponent extends GirafeHTMLElement {
8
8
  return uHtml `<style>
9
9
  .hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-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-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.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)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
10
10
  </style><style>
11
- .container{border-right:var(--app-standard-border);flex-direction:row;align-items:center;display:flex}.name{text-align:left;flex-direction:column;display:flex}.avatar-initials{background-color:var(--app-color-grey);color:#000;border-radius:50%;justify-content:center;align-items:center;width:2rem;height:2rem;font-weight:700;display:flex}.gg-icon-button.logged-in{flex-direction:row;gap:.5rem;padding:.5rem}
11
+ .container{border-right:var(--app-standard-border);flex-direction:row;align-items:center;display:flex}.name{text-align:left;flex-direction:column;display:flex}.avatar-initials{background-color:var(--app-color-grey);color:#000;border-radius:50%;justify-content:center;align-items:center;width:2rem;height:2rem;font-weight:700;display:flex}.gg-icon-button.logged-in{flex-direction:row;gap:.5rem;padding:.5rem}@media (width<=991px){#login-btn>span,.logged-in>.name{display:none}#login-btn>img{padding-right:.5rem}}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button logged-in" onclick="${() => this.onLogoutClick()}"><span class="avatar-initials">${this.getInitials()}</span><div class="name"><span class="${this.getFullName() ? '' : 'hidden'}">${this.getFullName()}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
14
+ <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button id="login-btn" class="gg-icon-button gg-medium-withtext" aria-label="Login" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button logged-in" onclick="${() => this.onLogoutClick()}"><span class="avatar-initials">${this.getInitials()}</span><div class="name"><span class="${this.getFullName() ? '' : 'hidden'}">${this.getFullName()}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
15
15
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
16
16
  };
17
17
  constructor(name = 'oauth') {
@@ -29,3 +29,13 @@
29
29
  gap: 0.5rem;
30
30
  padding: 0.5rem;
31
31
  }
32
+
33
+ @media (max-width: 991px) {
34
+ #login-btn > span,
35
+ .logged-in > .name {
36
+ display: none;
37
+ }
38
+ #login-btn > img {
39
+ padding-right: 0.5rem;
40
+ }
41
+ }
@@ -11,7 +11,7 @@ export default class MobileOauthComponent extends OauthComponent {
11
11
  .container{filter:drop-shadow(0 4px 7px #0004382c);background-color:#fff;border-radius:8px;flex-direction:column;padding:1em;display:flex}.container:active{background-color:#c6ceda}.container>button{background:0 0;border:none;flex-direction:column;flex:1;justify-content:center;align-items:center;display:flex}.container>button>img{opacity:.7;width:25%;padding-bottom:1em}.container>button>span{color:#3f68a7;flex:1;justify-content:center;align-items:center;font-size:1.2em;font-weight:600;display:flex}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button logged-in" onclick="${() => this.onLogoutClick()}"><span class="avatar-initials">${this.getInitials()}</span><div class="name"><span class="${this.getFullName() ? '' : 'hidden'}">${this.getFullName()}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
14
+ <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button id="login-btn" class="gg-icon-button gg-medium-withtext" aria-label="Login" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button logged-in" onclick="${() => this.onLogoutClick()}"><span class="avatar-initials">${this.getInitials()}</span><div class="name"><span class="${this.getFullName() ? '' : 'hidden'}">${this.getFullName()}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
15
15
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
16
16
  };
17
17
  constructor() {
@@ -0,0 +1,15 @@
1
+ import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
2
+ import GirafeConfig from '../../tools/configuration/girafeconfig.js';
3
+ declare class HeaderComponent extends GirafeHTMLElement {
4
+ protected templateUrl: string | null;
5
+ protected styleUrls: string[] | null;
6
+ template: () => import("uhtml").Hole;
7
+ constructor();
8
+ get config(): GirafeConfig;
9
+ get logoSource(): string;
10
+ get logoAltText(): string;
11
+ private setHtmlMetaData;
12
+ registerEvents(): void;
13
+ protected connectedCallback(): void;
14
+ }
15
+ export default HeaderComponent;
@@ -0,0 +1,67 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html as uHtml } from 'uhtml';
8
+ // SPDX-License-Identifier: Apache-2.0
9
+ import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
10
+ import { UsedInTemplateOnly } from '../../decorators.js';
11
+ class HeaderComponent extends GirafeHTMLElement {
12
+ templateUrl = null;
13
+ styleUrls = null;
14
+ template = () => {
15
+ return uHtml `<style>
16
+ #header{box-sizing:border-box;align-items:center;gap:1rem;height:100%;padding:.15rem 1rem;display:flex}#logo{filter:none;width:auto;height:100%;max-height:100%;display:block}#app-title{color:var(--text-color);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-width:0;font-size:1.3rem;font-weight:700;display:-webkit-box;overflow:hidden}@media (width<=991px){#app-title{display:none}}
17
+ </style>
18
+ <style>${this.customStyle}</style>
19
+ <div id="header">${this.config.branding.logo !== '' ? uHtml ` <img id="logo" alt="${this.logoAltText}" src="${this.logoSource}"> ` : ''} ${this.config.branding.showAppTitleInHeader ? uHtml `<div id="app-title" i18n="${this.config.branding.appTitle}">${this.config.branding.appTitle}</div>` : ''}</div>
20
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
21
+ };
22
+ constructor() {
23
+ super('header');
24
+ }
25
+ get config() {
26
+ return this.context.configManager.Config;
27
+ }
28
+ get logoSource() {
29
+ if (this.state.interface.darkFrontendMode) {
30
+ return this.config.branding.logoDarkMode;
31
+ }
32
+ return this.config.branding.logo;
33
+ }
34
+ get logoAltText() {
35
+ return `${this.config.branding.appTitle.toLowerCase().replaceAll(' ', '-')}-logo`;
36
+ }
37
+ setHtmlMetaData() {
38
+ const title = this.context.i18nManager.getTranslation(this.config.branding.appTitle);
39
+ const description = this.context.i18nManager.getTranslation(this.config.branding.description);
40
+ document.title = title;
41
+ document.querySelector('meta[name="description"]')?.setAttribute('content', description);
42
+ }
43
+ registerEvents() {
44
+ this.subscribe('language', () => this.setHtmlMetaData());
45
+ if (!this.state.interface.isMobile) {
46
+ this.subscribe('interface.darkFrontendMode', () => this.refreshRender());
47
+ }
48
+ }
49
+ connectedCallback() {
50
+ super.connectedCallback();
51
+ this.setHtmlMetaData();
52
+ this.render();
53
+ super.girafeTranslate();
54
+ if (this.state.interface.isMobile) {
55
+ // Header shouldn't be visible on mobile
56
+ this.hide();
57
+ }
58
+ this.registerEvents();
59
+ }
60
+ }
61
+ __decorate([
62
+ UsedInTemplateOnly()
63
+ ], HeaderComponent.prototype, "logoSource", null);
64
+ __decorate([
65
+ UsedInTemplateOnly()
66
+ ], HeaderComponent.prototype, "logoAltText", null);
67
+ export default HeaderComponent;
@@ -0,0 +1,38 @@
1
+ /* SPDX-License-Identifier: Apache-2.0 */
2
+ #header {
3
+ height: 100%;
4
+ display: flex;
5
+ gap: 1rem;
6
+ padding: 0.15rem 1rem;
7
+ box-sizing: border-box;
8
+ align-items: center;
9
+ }
10
+
11
+ #logo {
12
+ width: auto;
13
+ height: 100%;
14
+ max-height: 100%;
15
+ display: block;
16
+ filter: none;
17
+ }
18
+
19
+ #app-title {
20
+ font-size: 1.3rem;
21
+ font-weight: bold;
22
+ color: var(--text-color);
23
+ min-width: 0;
24
+ /* Will limit word wrapping to two lines */
25
+ display: -webkit-box;
26
+ -webkit-box-orient: vertical;
27
+ -webkit-line-clamp: 2;
28
+ overflow: hidden;
29
+ }
30
+
31
+ /*
32
+ Don't show app title on small screens
33
+ */
34
+ @media (max-width: 991px) {
35
+ #app-title {
36
+ display: none;
37
+ }
38
+ }
@@ -24,6 +24,7 @@ export { default as ExternalLayersComponent } from './extlayers/component.js';
24
24
  export { default as FeedbackButtonComponent } from './feedbackbutton/component.js';
25
25
  export { default as GeolocationMobile } from './geolocation-mobile/component.js';
26
26
  export { default as GetDirectionsArtifact } from './getdirections/component.js';
27
+ export { default as HeaderComponent } from './header/component.js';
27
28
  export { default as HelpComponent } from './help/component.js';
28
29
  export { default as InfoboxComponent } from './infobox/component.js';
29
30
  export { default as InfoWindowComponent } from './infowindow/component.js';
@@ -23,6 +23,7 @@ export { default as ExternalLayersComponent } from './extlayers/component.js';
23
23
  export { default as FeedbackButtonComponent } from './feedbackbutton/component.js';
24
24
  export { default as GeolocationMobile } from './geolocation-mobile/component.js';
25
25
  export { default as GetDirectionsArtifact } from './getdirections/component.js';
26
+ export { default as HeaderComponent } from './header/component.js';
26
27
  export { default as HelpComponent } from './help/component.js';
27
28
  export { default as InfoboxComponent } from './infobox/component.js';
28
29
  export { default as InfoWindowComponent } from './infowindow/component.js';
@@ -19,7 +19,12 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
19
19
  }
20
20
  connectedCallback() {
21
21
  super.connectedCallback();
22
- this.render();
22
+ if (this.context.configManager.Config.branding.prototypeBanner) {
23
+ this.render();
24
+ }
25
+ else {
26
+ this.hide();
27
+ }
23
28
  }
24
29
  }
25
30
  export default PrototypeBannerComponent;
@@ -10,7 +10,7 @@ class MobileThemeElementComponent extends GirafeHTMLElement {
10
10
  return uHtml `<style>
11
11
  .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)}
12
12
  </style><style>
13
- header{align-items:center;gap:1rem;font-size:1.5rem;display:flex}
13
+ header{align-items:center;gap:1rem;font-size:1.5rem;display:flex}header>img{max-width:50%}header>span{overflow-wrap:anywhere}
14
14
  </style>
15
15
  <style>${this.customStyle}</style>
16
16
  <header><button onclick="${() => this.state.themes.lastSelectedTheme = null}" class="gg-icon-button gg-small"><img alt="Back button" src="icons/arrow_left.svg"></button> <img alt="Theme icon" src="${this.theme?.icon}"> <span i18n="${this.theme?.name}"></span></header><div class="children">${(this.theme?.children ?? []).map(layer => (layer instanceof _GroupLayer) ? uHtmlFor(layer, layer.treeItemId) `<girafe-group groupid="${layer.treeItemId}"></girafe-group>` : uHtmlFor(layer, layer.treeItemId) `<girafe-layer layerid="${layer.treeItemId}"></girafe-layer>`)}</div>
@@ -5,3 +5,11 @@ header {
5
5
  gap: 1rem;
6
6
  font-size: 1.5rem;
7
7
  }
8
+
9
+ header > img {
10
+ max-width: 50%;
11
+ }
12
+
13
+ header > span {
14
+ overflow-wrap: anywhere;
15
+ }
@@ -11,7 +11,7 @@ export default class MobileThemeComponent extends GirafeHTMLElement {
11
11
  return uHtml `<style>
12
12
  .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)}
13
13
  </style><style>
14
- 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}
14
+ 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;white-space:normal;overflow-wrap:anywhere;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}
15
15
  </style>
16
16
  <style>${this.customStyle}</style>
17
17
  <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>
@@ -23,6 +23,8 @@ header {
23
23
  text-align: left;
24
24
  border: none;
25
25
  font-size: 0.8rem;
26
+ white-space: normal;
27
+ overflow-wrap: anywhere;
26
28
  }
27
29
 
28
30
  .item img {
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geogirafe.org"
7
7
  },
8
- "version": "1.2.0-dev.2853894139",
8
+ "version": "1.2.0-dev.2857838548",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
package/styles/iframe.css CHANGED
@@ -10,14 +10,15 @@ body {
10
10
  overflow: hidden;
11
11
  }
12
12
 
13
- .logo {
13
+ girafe-header {
14
+ height: 2.25rem;
14
15
  position: absolute;
15
- top: 0.2rem;
16
- left: 1rem;
16
+ top: 0.5rem;
17
+ left: 0.5rem;
17
18
  z-index: 10;
18
- width: 8rem;
19
- background-color: #fff;
19
+ background-color: var(--bkg-color);
20
20
  opacity: 0.5;
21
+ border-radius: 4px;
21
22
  }
22
23
 
23
24
  #content {
package/styles/index.css CHANGED
@@ -39,10 +39,8 @@ girafe-theme-select {
39
39
  border-right: var(--app-standard-border);
40
40
  }
41
41
 
42
- .logo {
43
- margin: 0.2rem 1rem;
44
- height: var(--app-standard-height);
45
- opacity: 0.8;
42
+ girafe-header {
43
+ height: 100%;
46
44
  }
47
45
 
48
46
  girafe-search {
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <meta name="description" content="GeoGirafe is an flexible application to build online geoportals." />
7
+ <meta name="description" content="GeoGirafe is a flexible application to build online geoportals." />
8
8
 
9
9
  <meta name="configs" content="main" />
10
10
  <link rel="config-main-url" href="config.json" />
@@ -107,7 +107,7 @@
107
107
  <span lang="en">Loading...</span>
108
108
  </div>
109
109
  <girafe-app>
110
- <img class="logo" alt="geogirafe-logo" src="images/logo/horizontal_black.svg" />
110
+ <girafe-header></girafe-header>
111
111
 
112
112
  <div id="content">
113
113
  <div id="main">
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <meta name="description" content="GeoGirafe is an flexible application to build online geoportals." />
7
+ <meta name="description" content="GeoGirafe is a flexible application to build online geoportals." />
8
8
 
9
9
  <!--
10
10
  If redirect-url meta tag is present, a redirect will happen when the detected device is an iPhone or Android.
@@ -114,7 +114,7 @@
114
114
  <girafe-app>
115
115
  <header>
116
116
  <girafe-theme-select data-tour="theme-selection"></girafe-theme-select>
117
- <img class="logo" alt="geogirafe-logo" src="images/logo/horizontal_black.svg" />
117
+ <girafe-header></girafe-header>
118
118
  <div class="header-center-align">
119
119
  <girafe-search id="search" plugin="config:search">
120
120
  <!-- <div slot="search-tooltip">
@@ -3,7 +3,7 @@
3
3
  <html lang="en">
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
- <meta name="description" content="GeoGirafe is an flexible application to build online geoportals." />
6
+ <meta name="description" content="GeoGirafe is a flexible application to build online geoportals." />
7
7
  <meta
8
8
  name="viewport"
9
9
  content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
@@ -80,6 +80,7 @@
80
80
  <span lang="en">Loading...</span>
81
81
  </div>
82
82
  <girafe-app>
83
+ <girafe-header></girafe-header>
83
84
  <div class="bottom-button-container-mobile">
84
85
  <girafe-align-north-button-mobile></girafe-align-north-button-mobile>
85
86
 
@@ -1 +1 @@
1
- {"version":"1.2.0-dev.2853894139", "build":"2853894139", "date":"16/09/2026"}
1
+ {"version":"1.2.0-dev.2857838548", "build":"2857838548", "date":"17/09/2026"}
@@ -29,6 +29,7 @@ import MobileSelectedLayerElementComponent from '../../components/themes-mobile/
29
29
  import GetDirectionsArtifact from '../../components/getdirections/component.js';
30
30
  import MenuMobileShareButton from '../../components/menu-buttons-mobile/MenuMobileShareButton.js';
31
31
  import ShareMobileComponent from '../../components/share-mobile/component.js';
32
+ import HeaderComponent from '../../components/header/component.js';
32
33
  export default class GeoGirafeAppMobile extends GeoGirafeApp {
33
34
  initializeInterface() {
34
35
  if (window.cordova) {
@@ -54,6 +55,7 @@ export default class GeoGirafeAppMobile extends GeoGirafeApp {
54
55
  customElements.define('girafe-map', DeprecatedMapComponent);
55
56
  customElements.define('girafe-search', MobileSearchComponent);
56
57
  customElements.define('girafe-offline', OfflineComponent);
58
+ customElements.define('girafe-header', HeaderComponent);
57
59
  customElements.define('girafe-theme-select', MobileThemeComponent);
58
60
  customElements.define('girafe-display-selector-button-mobile', DisplaySelectorButtonMobile);
59
61
  customElements.define('girafe-display-menu-button-mobile', DisplayMenuButtonMobile);
@@ -58,6 +58,7 @@ import FeedbackButtonComponent from '../../components/feedbackbutton/component.j
58
58
  import AddBookmarkComponent from '../../components/addbookmark/component.js';
59
59
  import DrawingToolbarComponent from '../../components/drawing-toolbar/component.js';
60
60
  import SearchFilterComponent from '../../components/search-filter/component.js';
61
+ import HeaderComponent from '../../components/header/component.js';
61
62
  export default class GeoGirafeApp {
62
63
  readyPromise;
63
64
  resolveReady;
@@ -108,6 +109,7 @@ export default class GeoGirafeApp {
108
109
  defineCoreComponents() {
109
110
  customElements.define('girafe-about', AboutComponent);
110
111
  customElements.define('girafe-advanced-filter', AdvancedFilterComponent);
112
+ customElements.define('girafe-header', HeaderComponent);
111
113
  customElements.define('girafe-basemap', BasemapComponent);
112
114
  customElements.define('girafe-coordinate', CoordinateComponent);
113
115
  customElements.define('girafe-contact', ContactComponent);
@@ -289,6 +289,14 @@ declare class GirafeConfig {
289
289
  permalink?: {
290
290
  sanitizeConfig?: SanitizeConfig;
291
291
  };
292
+ branding: {
293
+ logo: string;
294
+ logoDarkMode: string;
295
+ appTitle: string;
296
+ showAppTitleInHeader: boolean;
297
+ description: string;
298
+ prototypeBanner: boolean;
299
+ };
292
300
  extendedConfig?: Record<string, object>;
293
301
  static readonly DEFAULT_LOCALE = "en-US";
294
302
  /**
@@ -332,5 +340,6 @@ declare class GirafeConfig {
332
340
  private initApiConfig;
333
341
  private initConfigFiltering;
334
342
  private initPermalinkConfig;
343
+ private initBrandingConfig;
335
344
  }
336
345
  export default GirafeConfig;
@@ -39,6 +39,7 @@ class GirafeConfig {
39
39
  feedback;
40
40
  filtering;
41
41
  permalink;
42
+ branding;
42
43
  // The extended configuration can be used by third-party components or extensions
43
44
  // to add custom attributes to the GirafeConfig.
44
45
  extendedConfig;
@@ -81,6 +82,7 @@ class GirafeConfig {
81
82
  this.api = this.initApiConfig(config);
82
83
  this.filtering = this.initConfigFiltering(config);
83
84
  this.permalink = this.initPermalinkConfig(config);
85
+ this.branding = this.initBrandingConfig(config);
84
86
  try {
85
87
  this.search = this.initConfigSearch(config);
86
88
  }
@@ -510,5 +512,17 @@ class GirafeConfig {
510
512
  sanitizeConfig: defaultPermalinkSanitizeConfig
511
513
  });
512
514
  }
515
+ initBrandingConfig(config) {
516
+ // Logos, title and description fall back to GeoGirafe defaults if not specified
517
+ return {
518
+ logo: config.branding?.logo ?? 'images/logo/horizontal_black.svg',
519
+ logoDarkMode: config.branding?.logoDarkMode ?? config.branding?.logo ?? 'images/logo/horizontal_white.svg',
520
+ appTitle: config.branding?.appTitle ?? 'GeoGirafe',
521
+ showAppTitleInHeader: config.branding?.showAppTitleInHeader ?? false,
522
+ description: config.branding?.description ?? 'GeoGirafe is a flexible application to build online geoportals.',
523
+ // The prototype banner is shown by default
524
+ prototypeBanner: config.branding?.prototypeBanner ?? true
525
+ };
526
+ }
513
527
  }
514
528
  export default GirafeConfig;