diff --git a/package.json b/package.json index 5ff3e109b..d0383e0ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.44.13", + "version": "0.44.14", "repository": "https://github.com/pietervdvn/MapComplete", "description": "A small website to edit OSM easily", "bugs": "https://github.com/pietervdvn/MapComplete/issues", diff --git a/src/UI/Popup/LoginButton.ts b/src/UI/Popup/LoginButton.ts deleted file mode 100644 index 846a5f4f1..000000000 --- a/src/UI/Popup/LoginButton.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { SubtleButton } from "../Base/SubtleButton" -import BaseUIElement from "../BaseUIElement" -import { OsmConnection, OsmServiceState } from "../../Logic/Osm/OsmConnection" -import { VariableUiElement } from "../Base/VariableUIElement" -import Loading from "../Base/Loading" -import Translations from "../i18n/Translations" -import { ImmutableStore, Store } from "../../Logic/UIEventSource" -import Combine from "../Base/Combine" -import { Translation } from "../i18n/Translation" -import SvelteUIElement from "../Base/SvelteUIElement" -import Login from "../../assets/svg/Login.svelte" -import Invalid from "../../assets/svg/Invalid.svelte" - -class LoginButton extends SubtleButton { - constructor( - text: BaseUIElement | string, - state: { - osmConnection?: OsmConnection - }, - icon?: BaseUIElement | string - ) { - super(icon ?? new SvelteUIElement(Login), text) - this.onClick(() => { - state.osmConnection?.AttemptLogin() - }) - } -} - -export class LoginToggle extends VariableUiElement { - /** - * Constructs an element which shows 'el' if the user is logged in - * If not logged in, 'text' is shown on the button which invites to login. - * - * If logging in is not possible for some reason, an appropriate error message is shown - * - * State contains the 'osmConnection' to work with - * @param el: Element to show when logged in - * @param text: To show on the login button. Default: nothing - * @param state: if no osmConnection is given, assumes test situation and will show 'el' as if logged in - */ - constructor( - el: BaseUIElement, - text: BaseUIElement | string, - state: { - readonly osmConnection?: OsmConnection - readonly featureSwitchUserbadge?: Store - } - ) { - const loading = new Loading("Trying to log in...") - const login = text === undefined ? undefined : new LoginButton(text, state) - const t = Translations.t.general - const offlineModes: Partial> = { - offline: t.loginFailedOfflineMode, - unreachable: t.loginFailedUnreachableMode, - readonly: t.loginFailedReadonlyMode, - } - - super( - state.osmConnection?.loadingStatus?.map( - (osmConnectionState) => { - if (state.featureSwitchUserbadge?.data == false) { - // All features to login with are disabled - return undefined - } - - const apiState = state.osmConnection?.apiIsOnline?.data ?? "online" - const apiTranslation = offlineModes[apiState] - if (apiTranslation !== undefined) { - return new Combine([ - new SvelteUIElement(Invalid).SetClass("w-8 h-8 m-2 shrink-0"), - apiTranslation, - ]).SetClass("flex items-center alert max-w-64") - } - - if (osmConnectionState === "loading") { - return loading - } - if (osmConnectionState === "not-attempted") { - return login - } - if (osmConnectionState === "logged-in") { - return el - } - - // Fallback - return new LoginButton( - Translations.t.general.loginFailed, - state, - new SvelteUIElement(Invalid) - ) - }, - [state.featureSwitchUserbadge, state.osmConnection?.apiIsOnline] - ) ?? new ImmutableStore(el) - ) - } -} diff --git a/src/UI/Popup/Notes/CloseNoteButton.svelte b/src/UI/Popup/Notes/CloseNoteButton.svelte new file mode 100644 index 000000000..31fe64ab5 --- /dev/null +++ b/src/UI/Popup/Notes/CloseNoteButton.svelte @@ -0,0 +1,54 @@ + + + +
+ +
+ + + {#if $isClosed} + + {:else if minzoom <= $curZoom} + + {:else if zoomMoreMessage} + {zoomMoreMessage} + {/if} + +
diff --git a/src/UI/Popup/Notes/CloseNoteButton.ts b/src/UI/Popup/Notes/CloseNoteButton.ts deleted file mode 100644 index 657f0f97f..000000000 --- a/src/UI/Popup/Notes/CloseNoteButton.ts +++ /dev/null @@ -1,106 +0,0 @@ -import BaseUIElement from "../../BaseUIElement" -import Translations from "../../i18n/Translations" -import { Utils } from "../../../Utils" -import Img from "../../Base/Img" -import { SubtleButton } from "../../Base/SubtleButton" -import Toggle from "../../Input/Toggle" -import { LoginToggle } from ".././LoginButton" -import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization" -import { UIEventSource } from "../../../Logic/UIEventSource" -import Constants from "../../../Models/Constants" -import SvelteUIElement from "../../Base/SvelteUIElement" -import Checkmark from "../../../assets/svg/Checkmark.svelte" -import NoteCommentElement from "./NoteCommentElement" -import Icon from "../../Map/Icon.svelte" - -export class CloseNoteButton implements SpecialVisualization { - public readonly funcName = "close_note" - public readonly needsUrls = [Constants.osmAuthConfig.url] - public readonly docs = - "Button to close a note. A predefined text can be defined to close the note with. If the note is already closed, will show a small text." - public readonly args = [ - { - name: "text", - doc: "Text to show on this button", - required: true, - }, - { - name: "icon", - doc: "Icon to show", - defaultValue: "checkmark.svg", - }, - { - name: "idkey", - doc: "The property name where the ID of the note to close can be found", - defaultValue: "id", - }, - { - name: "comment", - doc: "Text to add onto the note when closing", - }, - { - name: "minZoom", - doc: "If set, only show the closenote button if zoomed in enough", - }, - { - name: "zoomButton", - doc: "Text to show if not zoomed in enough", - }, - ] - - public constr( - state: SpecialVisualizationState, - tags: UIEventSource>, - args: string[] - ): BaseUIElement { - const t = Translations.t.notes - - const params: { - text: string - icon: string - idkey: string - comment: string - minZoom: string - zoomButton: string - } = Utils.ParseVisArgs(this.args, args) - - let icon: BaseUIElement = new SvelteUIElement(Icon, { - icon: params.icon ?? "checkmark.svg", - }) - let textToShow = t.closeNote - if ((params.text ?? "") !== "") { - textToShow = Translations.T(args[0]) - } - - let closeButton: BaseUIElement = new SubtleButton(icon, textToShow) - const isClosed = tags.map((tags) => (tags["closed_at"] ?? "") !== "") - closeButton.onClick(() => { - const id = tags.data[args[2] ?? "id"] - const text = args[3] - state.osmConnection.closeNote(id, text)?.then((_) => { - NoteCommentElement.addCommentTo(text, tags, state) - tags.data["closed_at"] = new Date().toISOString() - tags.ping() - }) - }) - - if ((params.minZoom ?? "") !== "" && !isNaN(Number(params.minZoom))) { - closeButton = new Toggle( - closeButton, - params.zoomButton ?? "", - state.mapProperties.zoom.map((zoom) => zoom >= Number(params.minZoom)) - ) - } - - return new LoginToggle( - new Toggle( - t.isClosed.SetClass("thanks"), - closeButton, - - isClosed - ), - t.loginToClose, - state - ) - } -} diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index b004f966c..bdfad68b7 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -2,11 +2,7 @@ import Combine from "./Base/Combine" import { FixedUiElement } from "./Base/FixedUiElement" import BaseUIElement from "./BaseUIElement" import Title from "./Base/Title" -import { - RenderingSpecification, - SpecialVisualization, - SpecialVisualizationState -} from "./SpecialVisualization" +import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization" import { HistogramViz } from "./Popup/HistogramViz" import MinimapViz from "./Popup/MinimapViz.svelte" import { ShareLinkViz } from "./Popup/ShareLinkViz" @@ -15,7 +11,6 @@ import { MultiApplyViz } from "./Popup/MultiApplyViz" import { AddNoteCommentViz } from "./Popup/Notes/AddNoteCommentViz" import { PlantNetDetectionViz } from "./Popup/PlantNetDetectionViz" import TagApplyButton from "./Popup/TagApplyButton" -import { CloseNoteButton } from "./Popup/Notes/CloseNoteButton" import { MapillaryLinkVis } from "./Popup/MapillaryLinkVis" import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource" import AllTagsPanel from "./Popup/AllTagsPanel.svelte" @@ -99,6 +94,7 @@ import Trash from "@babeard/svelte-heroicons/mini/Trash" import NothingKnown from "./Popup/NothingKnown.svelte" import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch" import { And } from "../Logic/Tags/And" +import CloseNoteButton from "./Popup/Notes/CloseNoteButton.svelte" class NearbyImageVis implements SpecialVisualization { // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests @@ -215,6 +211,66 @@ class StealViz implements SpecialVisualization { } } +class CloseNoteViz implements SpecialVisualization { + public readonly funcName = "close_note" + public readonly needsUrls = [Constants.osmAuthConfig.url] + public readonly docs = + "Button to close a note. A predefined text can be defined to close the note with. If the note is already closed, will show a small text." + public readonly args = [ + { + name: "text", + doc: "Text to show on this button", + required: true, + }, + { + name: "icon", + doc: "Icon to show", + defaultValue: "checkmark.svg", + }, + { + name: "idkey", + doc: "The property name where the ID of the note to close can be found", + defaultValue: "id", + }, + { + name: "comment", + doc: "Text to add onto the note when closing", + }, + { + name: "minZoom", + doc: "If set, only show the closenote button if zoomed in enough", + }, + { + name: "zoomButton", + doc: "Text to show if not zoomed in enough", + }, + ] + + public constr(state: SpecialVisualizationState, tags: UIEventSource>, args: string[], feature: Feature, layer: LayerConfig): SvelteUIElement { + + const { + text, + icon, + idkey, + comment, + minZoom, + zoomButton + } = Utils.ParseVisArgs(this.args, args) + + + return new SvelteUIElement(CloseNoteButton, { + state, + tags, + icon, + idkey, + message: comment, + text: Translations.T(text), + minzoom: minZoom, + zoomMoreMessage: zoomButton + }) + } +} + /** * Thin wrapper around QuestionBox.svelte to include it into the special Visualisations */ @@ -525,7 +581,7 @@ export default class SpecialVisualizations { }) } }, - new CloseNoteButton(), + new CloseNoteViz(), new PlantNetDetectionViz(), new TagApplyButton(), @@ -533,7 +589,6 @@ export default class SpecialVisualizations { new PointImportButtonViz(), new WayImportButtonViz(), new ConflateImportButtonViz(), - new NearbyImageVis(), { @@ -1938,7 +1993,7 @@ export default class SpecialVisualizations { mostShadowed = undefined break } - }else if(!prTags.shadows(mostShadowedTags)) { + } else if (!prTags.shadows(mostShadowedTags)) { // The new contender does not win, but it might defeat the current contender mostShadowed = undefined break diff --git a/src/Utils.ts b/src/Utils.ts index 43661e9ed..6740452e7 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -170,10 +170,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be /** * Parses the arguments for special visualisations */ - public static ParseVisArgs( + public static ParseVisArgs>( specs: { name: string; defaultValue?: string }[], args: string[] - ): Record { + ): T { const parsed: Record = {} if (args.length > specs.length) { throw ( @@ -193,7 +193,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be parsed[spec.name] = arg } - return parsed + return parsed } static EncodeXmlValue(str) {