Lots of styling tweaks, add filter links between layers

This commit is contained in:
pietervdvn 2022-02-01 04:14:54 +01:00
parent 5cefc4d25f
commit c15f3d2036
28 changed files with 263 additions and 217 deletions

View file

@ -17,6 +17,7 @@ import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource";
import {LocalStorageSource} from "../Web/LocalStorageSource"; import {LocalStorageSource} from "../Web/LocalStorageSource";
import {GeoOperations} from "../GeoOperations"; import {GeoOperations} from "../GeoOperations";
import TitleHandler from "../Actors/TitleHandler"; import TitleHandler from "../Actors/TitleHandler";
import {BBox} from "../BBox";
/** /**
* Contains all the leaflet-map related state * Contains all the leaflet-map related state
@ -73,7 +74,7 @@ export default class MapState extends UserRelatedState {
/** /**
* WHich layers are enabled in the current theme * Which layers are enabled in the current theme and what filters are applied onto them
*/ */
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers"); public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers");
/** /**
@ -169,11 +170,10 @@ export default class MapState extends UserRelatedState {
]; ];
} }
console.warn("Locking the bounds to ", layout.lockLocation); console.warn("Locking the bounds to ", layout.lockLocation);
this.leafletMap.addCallbackAndRunD(map => { this.mainMapObject.installBounds(
// @ts-ignore new BBox(layout.lockLocation),
map.setMaxBounds(layout.lockLocation); this.featureSwitchIsTesting.data
map.setMinZoom(layout.startZoom); )
})
} }
} }
@ -377,6 +377,24 @@ export default class MapState extends UserRelatedState {
flayers.push(flayer); flayers.push(flayer);
} }
for (const layer of layoutToUse.layers) {
if(layer.filterIsSameAs === undefined){
continue
}
const toReuse = flayers.find(l => l.layerDef.id === layer.filterIsSameAs)
if(toReuse === undefined){
throw "Error in layer "+layer.id+": it defines that it should be use the filters of "+layer.filterIsSameAs+", but this layer was not loaded"
}
console.warn("Linking filter and isDisplayed-states of "+layer.id+" and "+layer.filterIsSameAs)
const selfLayer = flayers.findIndex(l => l.layerDef.id === layer.id)
flayers[selfLayer] = {
isDisplayed: toReuse.isDisplayed,
layerDef: layer,
appliedFilters: toReuse.appliedFilters
};
}
return new UIEventSource<FilteredLayer[]>(flayers); return new UIEventSource<FilteredLayer[]>(flayers);
} }

View file

@ -237,7 +237,7 @@ export interface LayerConfigJson {
/** /**
* All the extra questions for filtering * All the extra questions for filtering
*/ */
filter?: (FilterConfigJson) [], filter?: (FilterConfigJson) [] | {sameAs: string},
/** /**
* This block defines under what circumstances the delete dialog is shown for objects of this layer. * This block defines under what circumstances the delete dialog is shown for objects of this layer.

View file

@ -232,7 +232,7 @@ export interface LayoutConfigJson {
/** /**
* If set to true, the basemap will not scroll outside of the area visible on initial zoom. * If set to true, the basemap will not scroll outside of the area visible on initial zoom.
* If set to [[lat0, lon0], [lat1, lon1]], the map will not scroll outside of those bounds. * If set to [[lon, lat], [lon, lat]], the map will not scroll outside of those bounds.
* Off by default, which will enable panning to the entire world * Off by default, which will enable panning to the entire world
*/ */
lockLocation?: boolean | [[number, number], [number, number]] | number[][]; lockLocation?: boolean | [[number, number], [number, number]] | number[][];

View file

@ -24,6 +24,7 @@ import Link from "../../UI/Base/Link";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import Table from "../../UI/Base/Table"; import Table from "../../UI/Base/Table";
import FilterConfigJson from "./Json/FilterConfigJson";
export default class LayerConfig extends WithContextLoader { export default class LayerConfig extends WithContextLoader {
@ -58,7 +59,8 @@ export default class LayerConfig extends WithContextLoader {
public readonly tagRenderings: TagRenderingConfig[]; public readonly tagRenderings: TagRenderingConfig[];
public readonly filters: FilterConfig[]; public readonly filters: FilterConfig[];
public readonly filterIsSameAs: string;
constructor( constructor(
json: LayerConfigJson, json: LayerConfigJson,
context?: string, context?: string,
@ -243,9 +245,14 @@ export default class LayerConfig extends WithContextLoader {
this.tagRenderings = (Utils.NoNull(json.tagRenderings) ?? []).map((tr, i) => new TagRenderingConfig(<TagRenderingConfigJson>tr, this.id + ".tagRenderings[" + i + "]")) this.tagRenderings = (Utils.NoNull(json.tagRenderings) ?? []).map((tr, i) => new TagRenderingConfig(<TagRenderingConfigJson>tr, this.id + ".tagRenderings[" + i + "]"))
this.filters = (json.filter ?? []).map((option, i) => { if(json.filter !== undefined && json.filter !== null && json.filter["sameAs"] !== undefined){
return new FilterConfig(option, `${context}.filter-[${i}]`) this.filterIsSameAs = json.filter["sameAs"]
}); this.filters = []
}else{
this.filters = (<FilterConfigJson[]>json.filter ?? []).map((option, i) => {
return new FilterConfig(option, `${context}.filter-[${i}]`)
});
}
{ {
const duplicateIds = Utils.Dupiclates(this.filters.map(f => f.id)) const duplicateIds = Utils.Dupiclates(this.filters.map(f => f.id))
@ -302,8 +309,7 @@ export default class LayerConfig extends WithContextLoader {
return undefined return undefined
} }
const baseTags = TagUtils.changeAsProperties(this.source.osmTags.asChange({id: "node/-1"})) const baseTags = TagUtils.changeAsProperties(this.source.osmTags.asChange({id: "node/-1"}))
return mapRendering.GenerateLeafletStyle(new UIEventSource(baseTags), false, return mapRendering.GetSimpleIcon(new UIEventSource(baseTags))
{noSize: true, includeBadges: false}).html
} }
public GenerateDocumentation(usedInThemes: string[], layerIsNeededBy: Map<string, string[]>, dependencies: { public GenerateDocumentation(usedInThemes: string[], layerIsNeededBy: Map<string, string[]>, dependencies: {

View file

@ -66,7 +66,7 @@ export default class LayoutConfig {
this.maintainer = json.maintainer; this.maintainer = json.maintainer;
this.credits = json.credits; this.credits = json.credits;
this.version = json.version; this.version = json.version;
this.language = Array.from(Object.keys(json.title)); this.language = json.mustHaveLanguage ?? Array.from(Object.keys(json.title));
{ {
if (typeof json.title === "string") { if (typeof json.title === "string") {

View file

@ -150,8 +150,8 @@ export default class PointRenderingConfig extends WithContextLoader {
tags: UIEventSource<any>, tags: UIEventSource<any>,
clickable: boolean, clickable: boolean,
options?: { options?: {
noSize: false | boolean, noSize?: false | boolean,
includeBadges: true | boolean includeBadges?: true | boolean
} }
): ):
{ {

View file

@ -53,14 +53,15 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
public installBounds(factor: number | BBox, showRange?: boolean) { public installBounds(factor: number | BBox, showRange?: boolean) {
this.leafletMap.addCallbackD(leaflet => { this.leafletMap.addCallbackD(leaflet => {
let bounds; let bounds : {getEast(), getNorth(), getWest(), getSouth()};
if (typeof factor === "number") { if (typeof factor === "number") {
bounds = leaflet.getBounds().pad(factor) const lbounds = leaflet.getBounds().pad(factor)
leaflet.setMaxBounds(bounds) leaflet.setMaxBounds(lbounds)
bounds = lbounds;
} else { } else {
// @ts-ignore // @ts-ignore
leaflet.setMaxBounds(factor.toLeaflet()) leaflet.setMaxBounds(factor.toLeaflet())
bounds = leaflet.getBounds() bounds = factor
} }
if (showRange) { if (showRange) {

View file

@ -6,6 +6,7 @@ import {UIEventSource} from "../../Logic/UIEventSource";
import Hash from "../../Logic/Web/Hash"; import Hash from "../../Logic/Web/Hash";
import BaseUIElement from "../BaseUIElement"; import BaseUIElement from "../BaseUIElement";
import Img from "./Img"; import Img from "./Img";
import Title from "./Title";
/** /**
* *
@ -101,7 +102,8 @@ export default class ScrollableFullScreen extends UIElement {
Hash.hash.setData(undefined) Hash.hash.setData(undefined)
}) })
title.SetClass("block text-l sm:text-xl md:text-2xl w-full font-bold p-0 max-h-20vh overflow-y-auto self-center") title = new Title(title, 2)
title.SetClass("text-l sm:text-xl md:text-2xl w-full p-0 max-h-20vh overflow-y-auto self-center")
return new Combine([ return new Combine([
new Combine([ new Combine([
new Combine([returnToTheMap, title]) new Combine([returnToTheMap, title])

View file

@ -21,7 +21,7 @@ export class SubtleButton extends UIElement {
} }
protected InnerRender(): string | BaseUIElement { protected InnerRender(): string | BaseUIElement {
const classes = "block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200 link-no-underline"; const classes = "block flex p-3 my-2 bg-subtle rounded-lg hover:shadow-xl hover:bg-unsubtle transition-colors transition-shadow link-no-underline";
const message = Translations.W(this.message); const message = Translations.W(this.message);
let img; let img;
if ((this.imageUrl ?? "") === "") { if ((this.imageUrl ?? "") === "") {

View file

@ -185,7 +185,7 @@ export default class CopyrightPanel extends Combine {
...iconAttributions ...iconAttributions
].map(e => e?.SetClass("mt-4"))); ].map(e => e?.SetClass("mt-4")));
this.SetClass("flex flex-col link-underline overflow-hidden") this.SetClass("flex flex-col link-underline overflow-hidden")
this.SetStyle("max-width: calc(100vw - 3em); width: 40rem; margin-left: 0.75rem; margin-right: 0.5rem") this.SetStyle("max-width:100%; width: 40rem; margin-left: 0.75rem; margin-right: 0.5rem")
} }
private static CodeContributors(): BaseUIElement { private static CodeContributors(): BaseUIElement {

View file

@ -115,17 +115,16 @@ export default class FilterView extends VariableUiElement {
) )
const style = const toggleClasses = "layer-toggle flex flex-wrap items-center pt-2 pb-1 px-0";
"display:flex;align-items:center;padding:0.5rem 0;"; const layerIcon = layer.defaultIcon()?.SetClass("flex-shrink-0 w-8 h-8 ml-2")
const layerIcon = layer.defaultIcon()?.SetClass("w-8 h-8 ml-2 shrink-0") const layerIconUnchecked = layer.defaultIcon()?.SetClass("flex-shrink-0 opacity-50 w-8 h-8 ml-2")
const layerIconUnchecked = layer.defaultIcon()?.SetClass("opacity-50 w-8 h-8 ml-2")
const layerChecked = new Combine([icon, layerIcon, styledNameChecked, zoomStatus]) const layerChecked = new Combine([icon, layerIcon, styledNameChecked, zoomStatus])
.SetStyle(style) .SetClass(toggleClasses)
.onClick(() => filteredLayer.isDisplayed.setData(false)); .onClick(() => filteredLayer.isDisplayed.setData(false));
const layerNotChecked = new Combine([iconUnselected, layerIconUnchecked, styledNameUnChecked]) const layerNotChecked = new Combine([iconUnselected, layerIconUnchecked, styledNameUnChecked])
.SetStyle(style) .SetClass(toggleClasses)
.onClick(() => filteredLayer.isDisplayed.setData(true)); .onClick(() => filteredLayer.isDisplayed.setData(true));
@ -152,7 +151,7 @@ export default class FilterView extends VariableUiElement {
const [ui, actualTags] = FilterView.createFilter(filter) const [ui, actualTags] = FilterView.createFilter(filter)
ui.SetClass("mt-3") ui.SetClass("mt-1")
toShow.push(ui) toShow.push(ui)
actualTags.addCallback(tagsToFilterFor => { actualTags.addCallback(tagsToFilterFor => {
flayer.appliedFilters.data.set(filter.id, tagsToFilterFor) flayer.appliedFilters.data.set(filter.id, tagsToFilterFor)
@ -165,7 +164,7 @@ export default class FilterView extends VariableUiElement {
} }
return new Combine(toShow) return new Combine(toShow)
.SetClass("flex flex-col p-2 ml-0 pl-12 bg-gray-200 pt-0 border-b-2 border-detail mb-4") .SetClass("flex flex-col p-2 ml-12 pl-1 pt-0 border-b-2 border-detail mb-4")
} }

View file

@ -35,9 +35,7 @@ export default class LeftControls extends Combine {
return defaultIcon; return defaultIcon;
} }
const tags = {...feature.properties, button: "yes"} const tags = {...feature.properties, button: "yes"}
const elem = currentViewFL.layerDef.mapRendering[0]?.GenerateLeafletStyle(new UIEventSource(tags), false, { const elem = currentViewFL.layerDef.mapRendering[0]?.GetSimpleIcon(new UIEventSource(tags));
noSize: true
})?.html
if (elem === undefined) { if (elem === undefined) {
return defaultIcon return defaultIcon
} }

View file

@ -75,7 +75,7 @@ export class ImageUploadFlow extends Toggle {
const label = new Combine([ const label = new Combine([
Svg.camera_plus_ui().SetClass("block w-12 h-12 p-1 text-4xl "), Svg.camera_plus_ui().SetClass("block w-12 h-12 p-1 text-4xl "),
labelContent labelContent
]).SetClass("p-2 border-4 border-black rounded-full font-bold h-full align-middle w-full flex justify-center") ]).SetClass("p-2 border-4 border-detail rounded-full font-bold h-full align-middle w-full flex justify-center")
const fileSelector = new FileSelectorButton(label) const fileSelector = new FileSelectorButton(label)
fileSelector.GetValue().addCallback(filelist => { fileSelector.GetValue().addCallback(filelist => {

View file

@ -62,7 +62,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
layerConfig: LayerConfig, layerConfig: LayerConfig,
state: {}): BaseUIElement { state: {}): BaseUIElement {
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI"), state) const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI"), state)
.SetClass("break-words font-bold sm:p-0.5 md:p-1 sm:p-1.5 md:p-2"); .SetClass("break-words font-bold sm:p-0.5 md:p-1 sm:p-1.5 md:p-2 text-2xl");
const titleIcons = new Combine( const titleIcons = new Combine(
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon, state, layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon, state,
"block w-8 h-8 max-h-8 align-baseline box-content sm:p-0.5 w-10",) "block w-8 h-8 max-h-8 align-baseline box-content sm:p-0.5 w-10",)

View file

@ -111,9 +111,8 @@ export default class TagRenderingQuestion extends Combine {
const saveButton = new Combine([ const saveButton = new Combine([
options.saveButtonConstr(inputElement.GetValue()), options.saveButtonConstr(inputElement.GetValue()),
new Toggle(Translations.t.general.testing.SetClass("alert"), undefined, state.featureSwitchIsTesting)
]) ])
let bottomTags: BaseUIElement; let bottomTags: BaseUIElement;
if (options.bottomText !== undefined) { if (options.bottomText !== undefined) {
bottomTags = options.bottomText(inputElement.GetValue()) bottomTags = options.bottomText(inputElement.GetValue())
@ -142,7 +141,9 @@ export default class TagRenderingQuestion extends Combine {
inputElement, inputElement,
options.cancelButton, options.cancelButton,
saveButton, saveButton,
bottomTags]) bottomTags,
new Toggle(Translations.t.general.testing.SetClass("alert"), undefined, state.featureSwitchIsTesting)
])
this.SetClass("question disable-links") this.SetClass("question disable-links")

View file

@ -36,7 +36,7 @@ export class SubstitutedTranslation extends VariableUiElement {
super( super(
Locale.language.map(language => { Locale.language.map(language => {
let txt = translation.textFor(language); let txt = translation?.textFor(language);
if (txt === undefined) { if (txt === undefined) {
return undefined return undefined
} }

View file

@ -35,7 +35,7 @@ export class Translation extends BaseUIElement {
get txt(): string { get txt(): string {
return this.textFor(Translation.forcedLanguage ?? Locale.language.data) return this.textFor(Translation.forcedLanguage ?? Locale.language.data)
} }
static ExtractAllTranslationsFrom(object: any, context = ""): { context: string, tr: Translation }[] { static ExtractAllTranslationsFrom(object: any, context = ""): { context: string, tr: Translation }[] {
const allTranslations: { context: string, tr: Translation }[] = [] const allTranslations: { context: string, tr: Translation }[] = []

View file

@ -305,6 +305,12 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
if (!source.hasOwnProperty(key)) { if (!source.hasOwnProperty(key)) {
continue continue
} }
if (key.startsWith("=")) {
const trimmedKey = key.substr(1);
target[trimmedKey] = source[key]
continue
}
if (key.startsWith("+") || key.endsWith("+")) { if (key.startsWith("+") || key.endsWith("+")) {
const trimmedKey = key.replace("+", ""); const trimmedKey = key.replace("+", "");
const sourceV = source[key]; const sourceV = source[key];

View file

@ -8,7 +8,7 @@
}, },
"mapRendering": [ "mapRendering": [
{ {
"icon": "crosshair:#00f", "icon": "crosshair:var(--catch-detail-color)",
"iconSize": "40,40,center", "iconSize": "40,40,center",
"location": [ "location": [
"point", "point",

View file

@ -151,8 +151,9 @@
] ]
}, },
"then": { "then": {
"nl": "<img src=\"./assets/layers/nature_reserve/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door Natuurpunt" "nl": "Dit gebied wordt beheerd door Natuurpunt"
} },
"icon": "./assets/layers/nature_reserve/Natuurpunt.jpg"
}, },
{ {
"if": { "if": {
@ -161,8 +162,9 @@
] ]
}, },
"then": { "then": {
"nl": "<img src=\"./assets/layers/nature_reserve/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door {operator}" "nl": "Dit gebied wordt beheerd door {operator}"
}, },
"icon": "./assets/layers/nature_reserve/Natuurpunt.jpg",
"hideInAnswer": true "hideInAnswer": true
}, },
{ {
@ -172,8 +174,9 @@
] ]
}, },
"then": { "then": {
"nl": "<img src=\"./assets/layers/nature_reserve/ANB.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door het Agentschap Natuur en Bos" "nl": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos"
} },
"icon": "./assets/layers/nature_reserve/ANB.jpg"
} }
], ],
"id": "Operator tag" "id": "Operator tag"

View file

@ -1,9 +1,11 @@
:root { :root {
--subtle-detail-color: #007759; --subtle-detail-color: #007759;
--subtle-detail-color-contrast: #ffffff; --subtle-detail-color-contrast: #ffffff;
--subtle-detail-color-light-contrast: lightgrey; --subtle-detail-color-light-contrast: white;
--catch-detail-color: #0fff00; --unsubtle-detail-color: #b34f26;
--unsubtle-detail-color-contrast: #ffffff;
--catch-detail-color: #FE6F32;
--catch-detail-color-contrast: #ffffff; --catch-detail-color-contrast: #ffffff;
--alert-color: #fee4d1; --alert-color: #fee4d1;
--background-color: white; --background-color: white;
@ -31,7 +33,21 @@ body {
font-family: 'Open Sans Regular', sans-serif; font-family: 'Open Sans Regular', sans-serif;
} }
h1 h2 h3 h4 { .layer-toggle .alert {
background: unset !important;
padding: 0 !important;
}
.layer-toggle svg path {
fill: var(--foreground-color) !important;
}
.layer-toggle .alert::before {
content: " - "
}
h1, h2, h3, h4 {
font-family: 'Amaranth', sans-serif; font-family: 'Amaranth', sans-serif;
} }
@ -43,4 +59,4 @@ h1 h2 h3 h4 {
.tab-non-active svg path { .tab-non-active svg path {
fill: white !important; fill: white !important;
stroke: white !important; stroke: white !important;
} }

View file

@ -30,6 +30,7 @@
"startLat": 51.20875, "startLat": 51.20875,
"startLon": 3.22435, "startLon": 3.22435,
"startZoom": 15, "startZoom": 15,
"lockLocation": [[2.1,50.40],[ 6.4,51.54]],
"widenFactor": 2, "widenFactor": 2,
"socialImage": "", "socialImage": "",
"defaultBackgroundId": "CartoDB.Positron", "defaultBackgroundId": "CartoDB.Positron",
@ -64,7 +65,10 @@
"render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg" "render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg"
} }
} }
] ],
"=filter": {
"sameAs": "nature_reserve_centerpoints"
}
} }
}, },
{ {
@ -183,7 +187,12 @@
"source": { "source": {
"geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", "geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 12, "geoJsonZoomLevel": 12,
"isOsmCache": true "isOsmCache": true,
"osmTags": {
"+and": [
"operator~.*[nN]atuurpunt.*"
]
}
}, },
"mapRendering": [ "mapRendering": [
{ {
@ -313,7 +322,7 @@
} }
}, },
{ {
"builtin": "gps_location_history", "builtin": "gps_track",
"override": { "override": {
"name": null "name": null
} }

View file

@ -896,12 +896,12 @@ video {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
.mt-3 { .ml-12 {
margin-top: 0.75rem; margin-left: 3rem;
} }
.ml-0 { .mt-3 {
margin-left: 0px; margin-top: 0.75rem;
} }
.mb-10 { .mb-10 {
@ -1437,11 +1437,6 @@ video {
background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); background-color: rgba(255, 255, 255, var(--tw-bg-opacity));
} }
.bg-blue-100 {
--tw-bg-opacity: 1;
background-color: rgba(219, 234, 254, var(--tw-bg-opacity));
}
.bg-gray-400 { .bg-gray-400 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgba(156, 163, 175, var(--tw-bg-opacity)); background-color: rgba(156, 163, 175, var(--tw-bg-opacity));
@ -1452,16 +1447,16 @@ video {
background-color: rgba(224, 231, 255, var(--tw-bg-opacity)); background-color: rgba(224, 231, 255, var(--tw-bg-opacity));
} }
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgba(229, 231, 235, var(--tw-bg-opacity));
}
.bg-black { .bg-black {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgba(0, 0, 0, var(--tw-bg-opacity)); background-color: rgba(0, 0, 0, var(--tw-bg-opacity));
} }
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgba(229, 231, 235, var(--tw-bg-opacity));
}
.bg-gray-100 { .bg-gray-100 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgba(243, 244, 246, var(--tw-bg-opacity)); background-color: rgba(243, 244, 246, var(--tw-bg-opacity));
@ -1514,6 +1509,11 @@ video {
padding: 2rem; padding: 2rem;
} }
.px-0 {
padding-left: 0px;
padding-right: 0px;
}
.pb-12 { .pb-12 {
padding-bottom: 3rem; padding-bottom: 3rem;
} }
@ -1546,8 +1546,8 @@ video {
padding-right: 0.25rem; padding-right: 0.25rem;
} }
.pl-12 { .pt-2 {
padding-left: 3rem; padding-top: 0.5rem;
} }
.pt-0 { .pt-0 {
@ -1590,10 +1590,6 @@ video {
padding-left: 1.5rem; padding-left: 1.5rem;
} }
.pt-2 {
padding-top: 0.5rem;
}
.text-center { .text-center {
text-align: center; text-align: center;
} }
@ -1783,6 +1779,12 @@ video {
transition-duration: 150ms; transition-duration: 150ms;
} }
.transition-shadow {
transition-property: box-shadow;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition-opacity { .transition-opacity {
transition-property: opacity; transition-property: opacity;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@ -1805,101 +1807,17 @@ video {
z-index: 10001 z-index: 10001
} }
.btn { .bg-subtle {
display: inline-flex; background-color: var(--subtle-detail-color);
justify-content: center; color: var(--subtle-detail-color-contrast);
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
border-width: 1px;
border-color: transparent;
--tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
border-radius: 1.5rem;
--tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
--tw-ring-opacity: 1;
--tw-ring-color: rgba(191, 219, 254, var(--tw-ring-opacity));
}
.btn:hover {
--tw-ring-opacity: 1;
--tw-ring-color: rgba(147, 197, 253, var(--tw-ring-opacity));
}
.btn {
margin-top: 0.25rem;
margin-right: 0.25rem;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
--tw-text-opacity: 1;
color: rgba(255, 255, 255, var(--tw-text-opacity));
--tw-bg-opacity: 1;
background-color: rgba(37, 99, 235, var(--tw-bg-opacity));
}
.btn:hover {
--tw-bg-opacity: 1;
background-color: rgba(29, 78, 216, var(--tw-bg-opacity));
}
.btn:focus {
outline: 2px solid transparent;
outline-offset: 2px;
--tw-ring-opacity: 1;
--tw-ring-color: rgba(29, 78, 216, var(--tw-ring-opacity));
}
.btn-secondary {
--tw-bg-opacity: 1;
background-color: rgba(75, 85, 99, var(--tw-bg-opacity));
}
.btn-secondary:hover {
--tw-bg-opacity: 1;
background-color: rgba(55, 65, 81, var(--tw-bg-opacity));
}
.btn-disabled {
--tw-bg-opacity: 1;
background-color: rgba(107, 114, 128, var(--tw-bg-opacity));
}
.btn-disabled:hover {
--tw-bg-opacity: 1;
background-color: rgba(107, 114, 128, var(--tw-bg-opacity));
}
.btn-disabled {
--tw-text-opacity: 1;
color: rgba(209, 213, 219, var(--tw-text-opacity));
--tw-ring-opacity: 1;
--tw-ring-color: rgba(229, 231, 235, var(--tw-ring-opacity));
}
.btn-disabled:hover {
--tw-ring-opacity: 1;
--tw-ring-color: rgba(229, 231, 235, var(--tw-ring-opacity));
}
.btn-disabled:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgba(229, 231, 235, var(--tw-ring-opacity));
}
.btn-disabled {
cursor: default;
} }
:root { :root {
--subtle-detail-color: #e5f5ff; --subtle-detail-color: #DBEAFE;
--subtle-detail-color-contrast: black; --subtle-detail-color-contrast: black;
--subtle-detail-color-light-contrast: lightgrey; --subtle-detail-color-light-contrast: lightgrey;
--unsubtle-detail-color: #BFDBFE;
--unsubtle-detail-color-contrast: black;
--catch-detail-color: #3a3aeb; --catch-detail-color: #3a3aeb;
--catch-detail-color-contrast: white; --catch-detail-color-contrast: white;
--alert-color: #fee4d1; --alert-color: #fee4d1;
@ -1967,16 +1885,45 @@ a {
color: var(--foreground-color); color: var(--foreground-color);
} }
btn { .btn {
margin-top: 0.25rem; margin-top: 0.5rem;
margin-right: 0.25rem; margin-right: 0.5rem;
font-size: 0.875rem;
line-height: 1.25rem; line-height: 1.25rem;
font-weight: 500;
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: var(--catch-detail-color-contrast); color: var(--catch-detail-color-contrast);
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: var(--catch-detail-color); background-color: var(--catch-detail-color);
display: inline-flex;
border-radius: 1.5rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
font-size: large;
font-weight: bold;
/*-- invisible border: rendered on hover*/
border: 3px solid var(--unsubtle-detail-color);
}
.btn:hover {
border: 3px solid var(--catch-detail-color);
}
.btn-secondary {
background-color: var(--unsubtle-detail-color);
}
.btn-secondary:hover {
background-color: var(--catch-detail-color);
}
.btn-disabled {
filter: saturate(0.3);
cursor: default;
}
.btn-disabled:hover {
border: 3px solid var(--unsubtle-detail-color);
} }
.h-min { .h-min {
@ -2000,9 +1947,8 @@ btn {
} }
.link-underline a { .link-underline a {
-webkit-text-decoration: underline 1px #0078a855; -webkit-text-decoration: underline 1px var(--foreground-color);
text-decoration: underline 1px #0078a855; text-decoration: underline 1px var(--foreground-color);
color: #0078A8;
} }
.link-no-underline a { .link-no-underline a {
@ -2083,6 +2029,7 @@ li::marker {
} }
.leaflet-container { .leaflet-container {
font: unset !important;
background-color: var(--background-color) !important; background-color: var(--background-color) !important;
} }
@ -2134,6 +2081,7 @@ li::marker {
.alert { .alert {
background-color: var(--alert-color); background-color: var(--alert-color);
color: var(--foreground-color);
font-weight: bold; font-weight: bold;
border-radius: 1em; border-radius: 1em;
margin: 0.25em; margin: 0.25em;
@ -2326,6 +2274,10 @@ li::marker {
/***************** Info box (box containing features and questions ******************/ /***************** Info box (box containing features and questions ******************/
input {
color: var(--foreground-color)
}
.leaflet-popup-content { .leaflet-popup-content {
width: 45em !important; width: 45em !important;
margin: 0.25rem !important; margin: 0.25rem !important;
@ -2383,11 +2335,6 @@ li::marker {
background-color: #f2f2f2; background-color: #f2f2f2;
} }
.hover\:bg-blue-200:hover {
--tw-bg-opacity: 1;
background-color: rgba(191, 219, 254, var(--tw-bg-opacity));
}
.hover\:bg-indigo-200:hover { .hover\:bg-indigo-200:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgba(199, 210, 254, var(--tw-bg-opacity)); background-color: rgba(199, 210, 254, var(--tw-bg-opacity));
@ -2407,6 +2354,11 @@ li::marker {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
} }
.hover\:bg-unsubtle:hover {
background-color: var(--unsubtle-detail-color);
color: var(--unsubtle-detail-color-contrast);
}
.group:hover .group-hover\:text-blue-800 { .group:hover .group-hover\:text-blue-800 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgba(30, 64, 175, var(--tw-text-opacity)); color: rgba(30, 64, 175, var(--tw-text-opacity));

View file

@ -24,38 +24,33 @@
.w-160 { .w-160 {
width: 40rem; width: 40rem;
} }
.bg-subtle {
background-color: var(--subtle-detail-color);
color: var(--subtle-detail-color-contrast);
}
.bg-unsubtle {
background-color: var(--unsubtle-detail-color);
color: var(--unsubtle-detail-color-contrast);
}
.bg-catch {
background-color: var(--catch-detail-color);
color: var(--catch-detail-color-contrast);
}
} }
.btn {
@apply inline-flex justify-center;
@apply py-2 px-4;
@apply border border-transparent shadow-sm;
@apply shadow-sm rounded-3xl;
@apply ring-2 ring-blue-200 hover:ring-blue-300;
@apply mt-1 mr-1;
@apply text-sm font-medium text-white;
@apply bg-blue-600 hover:bg-blue-700;
@apply focus:outline-none focus:ring-blue-700;
}
.btn-secondary {
@apply bg-gray-600 hover:bg-gray-700;
}
.btn-disabled {
@apply bg-gray-500 hover:bg-gray-500;
@apply text-gray-300;
@apply ring-gray-200 hover:ring-gray-200 focus:ring-gray-200;
@apply cursor-default;
}
} }
:root { :root {
--subtle-detail-color: #e5f5ff; --subtle-detail-color: #DBEAFE;
--subtle-detail-color-contrast: black; --subtle-detail-color-contrast: black;
--subtle-detail-color-light-contrast: lightgrey; --subtle-detail-color-light-contrast: lightgrey;
--unsubtle-detail-color: #BFDBFE;
--unsubtle-detail-color-contrast: black;
--catch-detail-color: #3a3aeb; --catch-detail-color: #3a3aeb;
--catch-detail-color-contrast: white; --catch-detail-color-contrast: white;
--alert-color: #fee4d1; --alert-color: #fee4d1;
@ -123,16 +118,45 @@ a {
color: var(--foreground-color); color: var(--foreground-color);
} }
btn { .btn {
margin-top: 0.25rem; margin-top: 0.5rem;
margin-right: 0.25rem; margin-right: 0.5rem;
font-size: 0.875rem;
line-height: 1.25rem; line-height: 1.25rem;
font-weight: 500;
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: var(--catch-detail-color-contrast); color: var(--catch-detail-color-contrast);
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: var(--catch-detail-color); background-color: var(--catch-detail-color);
display: inline-flex;
border-radius: 1.5rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
font-size: large;
font-weight: bold;
/*-- invisible border: rendered on hover*/
border: 3px solid var(--unsubtle-detail-color);
}
.btn:hover {
border: 3px solid var(--catch-detail-color);
}
.btn-secondary {
background-color: var(--unsubtle-detail-color);
}
.btn-secondary:hover {
background-color: var(--catch-detail-color);
}
.btn-disabled {
filter: saturate(0.3);
cursor: default;
}
.btn-disabled:hover {
border: 3px solid var(--unsubtle-detail-color);
} }
.h-min { .h-min {
@ -153,8 +177,7 @@ btn {
} }
.link-underline a { .link-underline a {
text-decoration: underline 1px #0078a855;; text-decoration: underline 1px var(--foreground-color);
color: #0078A8;
} }
.link-no-underline a { .link-no-underline a {
@ -239,6 +262,7 @@ li::marker {
} }
.leaflet-container { .leaflet-container {
font: unset !important;
background-color: var(--background-color) !important; background-color: var(--background-color) !important;
} }
@ -292,6 +316,7 @@ li::marker {
.alert { .alert {
background-color: var(--alert-color); background-color: var(--alert-color);
color: var(--foreground-color);
font-weight: bold; font-weight: bold;
border-radius: 1em; border-radius: 1em;
margin: 0.25em; margin: 0.25em;
@ -434,6 +459,9 @@ li::marker {
/***************** Info box (box containing features and questions ******************/ /***************** Info box (box containing features and questions ******************/
input {
color: var(--foreground-color)
}
.leaflet-popup-content { .leaflet-popup-content {
width: 45em !important; width: 45em !important;
@ -489,6 +517,7 @@ li::marker {
overflow-y: hidden; overflow-y: hidden;
} }
.zebra-table tr:nth-child(even) { .zebra-table tr:nth-child(even) {
background-color: #f2f2f2; background-color: #f2f2f2;
} }

View file

@ -2,6 +2,7 @@
"name": "index", "name": "index",
"short_name": "MapComplete", "short_name": "MapComplete",
"start_url": "index.html", "start_url": "index.html",
"lang": "en",
"display": "standalone", "display": "standalone",
"background_color": "#fff", "background_color": "#fff",
"description": "A thematic map viewer and editor based on OpenStreetMap", "description": "A thematic map viewer and editor based on OpenStreetMap",

View file

@ -3240,13 +3240,13 @@
"Operator tag": { "Operator tag": {
"mappings": { "mappings": {
"0": { "0": {
"then": "<img src=\"./assets/layers/nature_reserve/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door Natuurpunt" "then": "Dit gebied wordt beheerd door Natuurpunt"
}, },
"1": { "1": {
"then": "<img src=\"./assets/layers/nature_reserve/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door {operator}" "then": "Dit gebied wordt beheerd door {operator}"
}, },
"2": { "2": {
"then": "<img src=\"./assets/layers/nature_reserve/ANB.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door het Agentschap Natuur en Bos" "then": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos"
} }
}, },
"question": "Wie beheert dit gebied?", "question": "Wie beheert dit gebied?",

View file

@ -7,12 +7,9 @@
"homepage": "https://mapcomplete.osm.be", "homepage": "https://mapcomplete.osm.be",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"increase-memory": "export NODE_OPTIONS=--max_old_space_size=8364", "start": "npm run generate:layeroverview && npm run ",
"start": "npm run start:prepare && npm-run-all --parallel start:parallel:*", "strt": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve *.html UI/** Logic/** assets/*.json assets/svg/* assets/generated/* assets/layers/*/*.svg assets/layers/*/*.jpg assets/layers/*/*.png assets/layers/*/*.css assets/tagRenderings/*.json assets/themes/*/*.svg assets/themes/*/*.ttf assets/themes/*/*/*.ttf aassets/themes/*/*.otf assets/themes/*/*/*.otf ssets/themes/*/*.css assets/themes/*/*.jpg assets/themes/*/*.png vendor/* vendor/*/*",
"strt": "npm run start:prepare && npm run start:parallel:parcel", "watch:css": "tailwindcss -i index.css -o css/index-tailwind-output.css --watch",
"start:prepare": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory",
"start:parallel:parcel": "parcel serve *.html UI/** Logic/** assets/*.json assets/svg/* assets/generated/* assets/layers/*/*.svg assets/layers/*/*.jpg assets/layers/*/*.png assets/layers/*/*.css assets/tagRenderings/*.json assets/themes/*/*.svg assets/themes/*/*.ttf assets/themes/*/*/*.ttf aassets/themes/*/*.otf assets/themes/*/*/*.otf ssets/themes/*/*.css assets/themes/*/*.jpg assets/themes/*/*.png vendor/* vendor/*/*",
"start:parallel:tailwindcli": "tailwindcss -i index.css -o css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i index.css -o css/index-tailwind-output.css", "generate:css": "tailwindcss -i index.css -o css/index-tailwind-output.css",
"test": "ts-node test/TestAll.ts", "test": "ts-node test/TestAll.ts",
"init": "npm ci && npm run generate && npm run generate:editor-layer-index && npm run generate:layouts && npm run clean", "init": "npm ci && npm run generate && npm run generate:editor-layer-index && npm run generate:layouts && npm run clean",

View file

@ -195,8 +195,16 @@ if (!existsSync(generatedDir)) {
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"] const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"]
// @ts-ignore // @ts-ignore
const all: LayoutConfigJson[] = all_known_layouts.themes; const all: LayoutConfigJson[] = all_known_layouts.themes;
const args = process.argv
const theme = args[2]
if(theme !== undefined){
console.warn("Only generating layout "+theme)
}
for (const i in all) { for (const i in all) {
const layoutConfigJson: LayoutConfigJson = all[i] const layoutConfigJson: LayoutConfigJson = all[i]
if(theme !== undefined && layoutConfigJson.id !== theme){
continue
}
const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts") const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts")
const layoutName = layout.id const layoutName = layout.id
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) { if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {