diff --git a/Models/Constants.ts b/Models/Constants.ts index e60afebba..3d42ad533 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -40,6 +40,7 @@ export default class Constants { addNewPointWithUnreadMessagesUnlock: 500, minZoomLevelToAddNewPoints: (Constants.isRetina() ? 18 : 19), + importHelperUnlock: 5000 }; /** * Used by 'PendingChangesUploader', which waits this amount of seconds to upload changes. diff --git a/UI/BigComponents/BackToIndex.ts b/UI/BigComponents/BackToIndex.ts new file mode 100644 index 000000000..9edd54c59 --- /dev/null +++ b/UI/BigComponents/BackToIndex.ts @@ -0,0 +1,20 @@ +import {SubtleButton} from "../Base/SubtleButton"; +import Combine from "../Base/Combine"; +import Svg from "../../Svg"; +import Translations from "../i18n/Translations"; +import BaseUIElement from "../BaseUIElement"; + +export default class BackToIndex extends SubtleButton { + + constructor(message? : string | BaseUIElement) { + super( + Svg.back_svg().SetStyle("height: 1.5rem;"), + message ?? Translations.t.general.backToMapcomplete, + { + url: "./index.html" + } + ) + } + + +} \ No newline at end of file diff --git a/UI/BigComponents/MoreScreen.ts b/UI/BigComponents/MoreScreen.ts index 711824300..e8ddc957c 100644 --- a/UI/BigComponents/MoreScreen.ts +++ b/UI/BigComponents/MoreScreen.ts @@ -110,7 +110,7 @@ export default class MoreScreen extends Combine { ]), {url: linkText, newTab: false}); } - private static CreateProffessionalSerivesButton() { + public static CreateProffessionalSerivesButton() { const t = Translations.t.professional.indexPage; return new Combine([ new Title(t.hook, 4), diff --git a/UI/ImportHelperGui.ts b/UI/ImportHelperGui.ts new file mode 100644 index 000000000..d3d768ec2 --- /dev/null +++ b/UI/ImportHelperGui.ts @@ -0,0 +1,60 @@ +import {FixedUiElement} from "./Base/FixedUiElement"; +import {LoginToggle} from "./Popup/LoginButton"; +import {OsmConnection} from "../Logic/Osm/OsmConnection"; +import UserRelatedState from "../Logic/State/UserRelatedState"; +import Combine from "./Base/Combine"; +import BackToIndex from "./BigComponents/BackToIndex"; +import BaseUIElement from "./BaseUIElement"; +import TableOfContents from "./Base/TableOfContents"; +import LanguagePicker from "./LanguagePicker"; +import Translations from "./i18n/Translations"; +import Constants from "../Models/Constants"; +import Toggle from "./Input/Toggle"; +import MoreScreen from "./BigComponents/MoreScreen"; +import Title from "./Base/Title"; + +export default class ImportHelperGui extends LoginToggle{ + + constructor() { + const t = Translations.t.importHelper; + + const state = new UserRelatedState(undefined) + + const leftContents: BaseUIElement[] = [ + new BackToIndex().SetClass("block pl-4"), + LanguagePicker.CreateLanguagePicker(Translations.t.importHelper.title.SupportedLanguages())?.SetClass("mt-4 self-end flex-col"), + ].map(el => el?.SetClass("pl-4")) + + const leftBar = new Combine([ + new Combine(leftContents).SetClass("sticky top-4 m-4") + ]).SetClass("block w-full md:w-2/6 lg:w-1/6") + + + super( + + new Toggle( + new Combine([ + leftBar, + new Combine([ + new Title(t.title,1), + t.description + ]).SetClass("flex flex-col m-8") + ]).SetClass("block md:flex") + + , + new Combine([ + t.lockNotice.Subs(Constants.userJourney), + MoreScreen.CreateProffessionalSerivesButton() + ]) + + , + state.osmConnection.userDetails.map(ud => ud.csCount >= Constants.userJourney.importHelperUnlock)), + + "Login needed...", + state) + } + +} + + +new ImportHelperGui().AttachTo("main") \ No newline at end of file diff --git a/UI/ProfessionalGui.ts b/UI/ProfessionalGui.ts index e6f4476ef..d9a83cd7e 100644 --- a/UI/ProfessionalGui.ts +++ b/UI/ProfessionalGui.ts @@ -6,9 +6,8 @@ import Toggleable, {Accordeon} from "./Base/Toggleable"; import List from "./Base/List"; import BaseUIElement from "./BaseUIElement"; import LanguagePicker from "./LanguagePicker"; -import {SubtleButton} from "./Base/SubtleButton"; -import Svg from "../Svg"; import TableOfContents from "./Base/TableOfContents"; +import BackToIndex from "./BigComponents/BackToIndex"; class Snippet extends Toggleable { constructor(translations, ...extraContent: BaseUIElement[]) { @@ -40,7 +39,7 @@ class SnippetContent extends Combine { } } -export default class ProfessionalGui { +class ProfessionalGui { constructor() { @@ -93,16 +92,8 @@ export default class ProfessionalGui { ]).SetClass("flex flex-col pb-12 m-3 lg:w-3/4 lg:ml-10 link-underline") - const backToIndex = new Combine([new SubtleButton( - Svg.back_svg().SetStyle("height: 1.5rem;"), - t.backToMapcomplete, - { - url: "./index.html" - } - )]).SetClass("block") - const leftContents: BaseUIElement[] = [ - backToIndex, + new BackToIndex().SetClass("block"), new TableOfContents(content, { noTopLevel: true, maxDepth: 2 @@ -110,6 +101,7 @@ export default class ProfessionalGui { LanguagePicker.CreateLanguagePicker(Translations.t.professional.title.SupportedLanguages())?.SetClass("mt-4 self-end flex-col"), ].map(el => el?.SetClass("pl-4")) + const leftBar = new Combine([ new Combine(leftContents).SetClass("sticky top-4 m-4") ]).SetClass("block w-full md:w-2/6 lg:w-1/6") diff --git a/automaton.html b/automaton.html index 4735380b2..d4c9ffb3e 100644 --- a/automaton.html +++ b/automaton.html @@ -1,5 +1,4 @@ -
diff --git a/index.html b/index.html index d7a2734e8..6f4f08b31 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,4 @@ - diff --git a/langs/en.json b/langs/en.json index 51d452ab8..1d197fa5a 100644 --- a/langs/en.json +++ b/langs/en.json @@ -70,6 +70,7 @@ "readMessages": "You have unread messages. Read these before deleting a point - someone might have feedback" }, "general": { + "backToMapcomplete": "Back to the theme overview", "loading": "Loading...", "pdf": { "generatedWith": "Generated with MapComplete.osm.be", @@ -332,8 +333,7 @@ "surveillance": "As you are reading the privacy policy, you probably care about privacy - so do we! We even made a theme showing surveillance cameras. Feel free to map them all!" }, "professional": { - "backToMapcomplete": "Back to the theme overview", - "indexPage": { + "indexPage": { "hook": "Need professional support?", "hookMore": "We can help with setting up surveys, data imports and OpenStreetMap-consultancy", "button": "Discover our services" @@ -463,5 +463,10 @@ "layerName": "Possible {title}", "description": "A layer which imports entries for {title}", "popupTitle": "Possible {title}" + }, + "importHelper": { + "title": "Import helper", + "description": "The import helper converts an external dataset to notes", + "lockNotice": "This page is locked. You need {importHelperUnlock} changesets before you can access here." } } diff --git a/langs/layers/fr.json b/langs/layers/fr.json index cf500c06a..f5fed3035 100644 --- a/langs/layers/fr.json +++ b/langs/layers/fr.json @@ -1,4 +1,29 @@ { + "address": { + "description": "Adresses", + "name": "Adresses connues d’OpenStreetMap", + "tagRenderings": { + "fixme": { + "question": "Précisez ce qui devrait être corrigé ici" + }, + "housenumber": { + "mappings": { + "0": { + "then": "Ce bâtiment n’a pas de numéro" + } + }, + "question": "Quel est le numéro de ce bâtiment ?", + "render": "Son numéro est le {addr:housenumber}" + }, + "street": { + "question": "Dans quelle rue est située l’adresse ?", + "render": "Le nom de la voie est {addr:street}" + } + }, + "title": { + "render": "Adresse connue" + } + }, "ambulancestation": { "description": "Une station d’ambulance est un lieu où sont stockés les véhicules d’urgence ainsi que de l’équipement médical.", "name": "Couche des ambulances", @@ -122,10 +147,12 @@ } }, "barrier": { + "description": "Obstacles à vélo, tels que des potelets ou des barrières", + "name": "Barrières", "presets": { "0": { - "title": "Bollard", - "description": "Un potelet sur le chemin" + "description": "Un potelet sur le chemin", + "title": "Bollard" }, "1": { "description": "Barrières cyclables, ralentissant les cyclistes", @@ -153,9 +180,34 @@ }, "question": "Quel est le type de bollard (borne) ?" }, + "Cycle barrier type": { + "mappings": { + "0": { + "then": "Simple, deux barrières côte à côte " + }, + "1": { + "then": "Double, deux barrières successives" + }, + "2": { + "then": "Triple, trois barrières successives " + }, + "3": { + "then": "Poire, l’espace en hauteur est plus faible qu’au sol " + } + }, + "question": "Quel est ce type de barrière cyclable ?" + }, "MaxWidth": { - "render": "Largeur maximale: {maxwidth:physical} m", - "question": "Quelle est la largeur du passage ?" + "question": "Quelle est la largeur du passage ?", + "render": "Largeur maximale: {maxwidth:physical} m" + }, + "Overlap (cyclebarrier)": { + "question": "Quel est le chevauchement des barrières ?", + "render": "Chevauchement : {overlap} m" + }, + "Space between barrier (cyclebarrier)": { + "question": "Combien d’espace sépare deux barrières successives ?", + "render": "Espace entre deux barrières successives : {width:separation} m" }, "Width of opening (cyclebarrier)": { "render": "Largeur de l'ouverture : {width:opening} m" @@ -169,31 +221,6 @@ "then": "Un cycliste ne peut pas franchir ceci." } } - }, - "Cycle barrier type": { - "mappings": { - "0": { - "then": "Simple, deux barrières côte à côte " - }, - "2": { - "then": "Triple, trois barrières successives " - }, - "3": { - "then": "Poire, l’espace en hauteur est plus faible qu’au sol " - }, - "1": { - "then": "Double, deux barrières successives" - } - }, - "question": "Quel est ce type de barrière cyclable ?" - }, - "Overlap (cyclebarrier)": { - "question": "Quel est le chevauchement des barrières ?", - "render": "Chevauchement : {overlap} m" - }, - "Space between barrier (cyclebarrier)": { - "question": "Combien d’espace sépare deux barrières successives ?", - "render": "Espace entre deux barrières successives : {width:separation} m" } }, "title": { @@ -206,9 +233,7 @@ } }, "render": "Barrière" - }, - "description": "Obstacles à vélo, tels que des potelets ou des barrières", - "name": "Barrières" + } }, "bench": { "name": "Bancs", @@ -979,6 +1004,54 @@ } } }, + "crossings": { + "description": "Traversée pour piétons et cyclistes", + "name": "Traversée", + "presets": { + "0": { + "description": "Traversée pour piétons et/ou cyclistes", + "title": "Traversée" + }, + "1": { + "description": "Feu de signalisation sur la voie", + "title": "Feu de signalisation" + } + }, + "title": { + "mappings": { + "0": { + "then": "Feu de signalisation" + }, + "1": { + "then": "Traversée avec feu de signalisation" + } + }, + "render": "Traversée" + } + }, + "cycleways_and_roads": { + "name": "Pistes cyclables et routes", + "title": { + "mappings": { + "0": { + "then": "Piste cyclable" + }, + "1": { + "then": "Voie partagée" + }, + "2": { + "then": "Bande cyclable" + }, + "3": { + "then": "Piste cyclable séparée de la route" + }, + "4": { + "then": "Vélorue" + } + }, + "render": "Pistes cyclables" + } + }, "defibrillator": { "name": "Défibrillateurs", "presets": { @@ -2168,6 +2241,12 @@ "render": "Toilettes" } }, + "trail": { + "name": "Sentiers", + "title": { + "render": "Sentier" + } + }, "tree_node": { "name": "Arbre", "presets": { @@ -2311,57 +2390,6 @@ "render": "Point de vue" } }, - "cycleways_and_roads": { - "name": "Pistes cyclables et routes", - "title": { - "mappings": { - "3": { - "then": "Piste cyclable séparée de la route" - }, - "2": { - "then": "Bande cyclable" - }, - "4": { - "then": "Vélorue" - }, - "0": { - "then": "Piste cyclable" - }, - "1": { - "then": "Voie partagée" - } - }, - "render": "Pistes cyclables" - } - }, - "watermill": { - "name": "Moulin à eau" - }, - "crossings": { - "presets": { - "0": { - "description": "Traversée pour piétons et/ou cyclistes", - "title": "Traversée" - }, - "1": { - "description": "Feu de signalisation sur la voie", - "title": "Feu de signalisation" - } - }, - "description": "Traversée pour piétons et cyclistes", - "title": { - "mappings": { - "0": { - "then": "Feu de signalisation" - }, - "1": { - "then": "Traversée avec feu de signalisation" - } - }, - "render": "Traversée" - }, - "name": "Traversée" - }, "visitor_information_centre": { "title": { "mappings": { @@ -2372,35 +2400,7 @@ "render": "{name}" } }, - "address": { - "description": "Adresses", - "name": "Adresses connues d’OpenStreetMap", - "tagRenderings": { - "fixme": { - "question": "Précisez ce qui devrait être corrigé ici" - }, - "housenumber": { - "mappings": { - "0": { - "then": "Ce bâtiment n’a pas de numéro" - } - }, - "question": "Quel est le numéro de ce bâtiment ?", - "render": "Son numéro est le {addr:housenumber}" - }, - "street": { - "question": "Dans quelle rue est située l’adresse ?", - "render": "Le nom de la voie est {addr:street}" - } - }, - "title": { - "render": "Adresse connue" - } - }, - "trail": { - "name": "Sentiers", - "title": { - "render": "Sentier" - } + "watermill": { + "name": "Moulin à eau" } -} +} \ No newline at end of file diff --git a/langs/shared-questions/fr.json b/langs/shared-questions/fr.json index a75cde800..aeb372cb3 100644 --- a/langs/shared-questions/fr.json +++ b/langs/shared-questions/fr.json @@ -61,17 +61,17 @@ }, "service:electricity": { "mappings": { + "0": { + "then": "Il y a suffisamment de prises disponibles pour les client·e·s en intérieur souhaitant recharger leurs appareils" + }, + "1": { + "then": "Il y a peu de prises disponibles pour les client·e·s en intérieur souhaitant recharger leurs appareils" + }, "2": { "then": "Il n'y a pas de prises disponibles à l'intérieur pour les clients, mais la recharge est peut-être possible sur demande auprès des employés" }, "3": { "then": "Il n'y a pas de prises secteur disponibles pour les clients assis à l'intérieur" - }, - "1": { - "then": "Il y a peu de prises disponibles pour les client·e·s en intérieur souhaitant recharger leurs appareils" - }, - "0": { - "then": "Il y a suffisamment de prises disponibles pour les client·e·s en intérieur souhaitant recharger leurs appareils" } }, "question": "Des prises sont elles à disposition des client·e·s en intérieur ?" @@ -113,4 +113,4 @@ "question": "Quel est l’élément Wikipédia correspondant ?" } } -} +} \ No newline at end of file diff --git a/notfound.ts b/notfound.ts index 12146ef4d..632c57348 100644 --- a/notfound.ts +++ b/notfound.ts @@ -1,11 +1,6 @@ import {FixedUiElement} from "./UI/Base/FixedUiElement"; import Combine from "./UI/Base/Combine"; -import {SubtleButton} from "./UI/Base/SubtleButton"; -import Svg from "./Svg"; +import BackToIndex from "./UI/BigComponents/BackToIndex"; new Combine([new FixedUiElement("This page is not found"), -new SubtleButton(Svg.back_svg(), "Back to index", { - url: "./index.html", - newTab: false -}) -]).AttachTo("maindiv") \ No newline at end of file +new BackToIndex()]).AttachTo("maindiv") \ No newline at end of file diff --git a/package.json b/package.json index 759fe910d..8593cc1fe 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "prepare-deploy": "./scripts/build.sh", "gittag": "ts-node scripts/printVersion.ts | bash", "lint": "tslint --project . -c tslint.json '**.ts' ", - "clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|theme\\).html\" | xargs rm) && (ls | grep \"^index_[a-zA-Z_]\\+\\.ts$\" | xargs rm) && (ls | grep \".*.webmanifest$\" | xargs rm)", + "clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|import_helper\\|theme\\).html\" | xargs rm) && (ls | grep \"^index_[a-zA-Z_]\\+\\.ts$\" | xargs rm) && (ls | grep \".*.webmanifest$\" | xargs rm)", "generate:dependency-graph": "node_modules/.bin/depcruise --exclude \"^node_modules\" --output-type dot Logic/State/MapState.ts > dependencies.dot && dot dependencies.dot -T svg -o dependencies.svg && rm dependencies.dot", "bicycle_rental": "ts-node ./scripts/extractBikeRental.ts" },