diff --git a/langs/en.json b/langs/en.json index 220bc4806..7b0c0f97c 100644 --- a/langs/en.json +++ b/langs/en.json @@ -216,6 +216,7 @@ "panoramaxHelp": "Panoramax is an online service which gathers street-level pictures and offers them under a free license. Contributors are allowed to use these pictures to improve OpenStreetMap", "panoramaxLicenseCCBYSA": "Your pictures are published under CC-BY-SA - everyone can reuse your image if they mention your name", "seeOnMapillary": "See this image on Mapillary", + "themeBy": "Theme maintained by {author}", "title": "Copyright and attribution", "translatedBy": "MapComplete has been translated by {contributors} and {hiddenCount} more contributors" @@ -941,4 +942,4 @@ "startsWithQ": "A wikidata identifier starts with Q and is followed by a number" } } -} \ No newline at end of file +} diff --git a/src/Logic/ImageProviders/Mapillary.ts b/src/Logic/ImageProviders/Mapillary.ts index b66adf984..c9cb2a6a8 100644 --- a/src/Logic/ImageProviders/Mapillary.ts +++ b/src/Logic/ImageProviders/Mapillary.ts @@ -1,10 +1,9 @@ import ImageProvider, { PanoramaView, ProvidedImage } from "./ImageProvider" -import BaseUIElement from "../../UI/BaseUIElement" import { Utils } from "../../Utils" import { LicenseInfo } from "./LicenseInfo" import Constants from "../../Models/Constants" import SvelteUIElement from "../../UI/Base/SvelteUIElement" -import MapillaryIcon from "./MapillaryIcon.svelte" +import { default as MapillaryIcon } from "./Mapillary.svelte" import { Feature, Point } from "geojson" import { Store, UIEventSource } from "../UIEventSource" import { ServerSourceInfo } from "../../Models/SourceOverview" @@ -139,19 +138,8 @@ export class Mapillary extends ImageProvider { })) } - SourceIcon( - img: { id: string; url: string }, - location?: { - lon: number - lat: number - } - ): BaseUIElement { - let url: string = undefined - const id = img.id - if (id) { - url = Mapillary.createLink(location, 16, "" + id) - } - return new SvelteUIElement(MapillaryIcon, { url }) + SourceIcon(): SvelteUIElement { + return new SvelteUIElement(MapillaryIcon) } async ExtractUrls(key: string, value: string): Promise { diff --git a/src/Logic/ImageProviders/MapillaryIcon.svelte b/src/Logic/ImageProviders/MapillaryIcon.svelte deleted file mode 100644 index 8932e33e9..000000000 --- a/src/Logic/ImageProviders/MapillaryIcon.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - -{#if url} - - - -{:else} - -{/if} diff --git a/src/Logic/ImageProviders/Panoramax.ts b/src/Logic/ImageProviders/Panoramax.ts index a4c827b73..fde47448c 100644 --- a/src/Logic/ImageProviders/Panoramax.ts +++ b/src/Logic/ImageProviders/Panoramax.ts @@ -9,7 +9,6 @@ import Constants from "../../Models/Constants" import { Store, Stores, UIEventSource } from "../UIEventSource" import SvelteUIElement from "../../UI/Base/SvelteUIElement" import Panoramax_bw from "../../assets/svg/Panoramax_bw.svelte" -import Link from "../../UI/Base/Link" import { Feature, Point } from "geojson" import { AddImageOptions } from "panoramax-js/dist/Panoramax" import { ServerSourceInfo } from "../../Models/SourceOverview" @@ -40,23 +39,8 @@ export default class PanoramaxImageProvider extends ImageProvider { { data: Promise<{ data: ImageData; url: string }>; time: Date } > = {} - public SourceIcon( - img?: { id: string; url: string }, - location?: { - lon: number - lat: number - } - ): BaseUIElement { - const host = "https://" + new URL(img.url).host - const p = new Panoramax(host) - return new Link( - new SvelteUIElement(Panoramax_bw), - p.createViewLink({ - imageId: img?.id, - location, - }), - true - ) + public SourceIcon(): SvelteUIElement { + return new SvelteUIElement(Panoramax_bw) } visitUrl( diff --git a/src/Logic/ImageProviders/WikidataImageProvider.ts b/src/Logic/ImageProviders/WikidataImageProvider.ts index 34c9e38f6..66fdeb690 100644 --- a/src/Logic/ImageProviders/WikidataImageProvider.ts +++ b/src/Logic/ImageProviders/WikidataImageProvider.ts @@ -3,7 +3,7 @@ import BaseUIElement from "../../UI/BaseUIElement" import { WikimediaImageProvider } from "./WikimediaImageProvider" import Wikidata from "../Web/Wikidata" import SvelteUIElement from "../../UI/Base/SvelteUIElement" -import * as Wikidata_icon from "../../assets/svg/Wikidata.svelte" +import Wikidata_icon from "../../assets/svg/Wikidata.svelte" import { Utils } from "../../Utils" import { Feature, Point } from "geojson" import { ServerSourceInfo } from "../../Models/SourceOverview" diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index e715ce20f..2695928c1 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -12,7 +12,6 @@ import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import usersettings from "../../../public/assets/generated/layers/usersettings.json" import Locale from "../../UI/i18n/Locale" -import LinkToWeblate from "../../UI/Base/LinkToWeblate" import FeatureSwitchState from "./FeatureSwitchState" import Constants from "../../Models/Constants" import { QueryParameters } from "../Web/QueryParameters" @@ -20,6 +19,7 @@ import { ThemeMetaTagging } from "./UserSettingsMetaTagging" import Showdown from "showdown" import { LocalStorageSource } from "../Web/LocalStorageSource" import { GeocodeResult } from "../Search/GeocodingProvider" +import Translations from "../../UI/i18n/Translations" class RoundRobinStore { private readonly _store: UIEventSource @@ -562,7 +562,7 @@ export default class UserRelatedState { hasMissingTheme ? { id: "theme:" + layout.id, - link: LinkToWeblate.hrefToWeblateZen( + link: Translations.hrefToWeblateZen( language, "themes", layout.id @@ -571,7 +571,7 @@ export default class UserRelatedState { : undefined, ...missingLayers.map((id) => ({ id: "layer:" + id, - link: LinkToWeblate.hrefToWeblateZen(language, "layers", id), + link: Translations.hrefToWeblateZen(language, "layers", id), })), ]) const untranslated_count = untranslated.length diff --git a/src/UI/Base/Img.ts b/src/UI/Base/Img.ts deleted file mode 100644 index d244d5329..000000000 --- a/src/UI/Base/Img.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Utils } from "../../Utils" -import BaseUIElement from "../BaseUIElement" - -/** - * @deprecated - */ -export default class Img extends BaseUIElement { - private readonly _src: string - private readonly _rawSvg: boolean - private readonly _options: { readonly fallbackImage?: string } - - /** @deprecated - */ - constructor( - src: string, - rawSvg = false, - options?: { - fallbackImage?: string - } - ) { - super() - if (src === undefined || src === "undefined") { - throw "Undefined src for image" - } - this._src = src - this._rawSvg = rawSvg - this._options = options - } - - static AsData(source: string) { - if (Utils.runningFromConsole) { - return source - } - try { - return `data:image/svg+xml;base64,${btoa(source)}` - } catch (e) { - console.error("Cannot create an image for", source.slice(0, 100)) - console.trace("Cannot create an image for the given source string due to ", e) - return "" - } - } - - static AsImageElement(source: string, css_class: string = "", style = ""): string { - return `` - } - - AsMarkdown(): string { - if (this._rawSvg === true) { - console.warn("Converting raw svgs to markdown is not supported") - return undefined - } - let src = this._src - if (this._src.startsWith("./")) { - src = "https://mapcomplete.org/" + src - } - return "![](" + src + ")" - } - - protected InnerConstructElement(): HTMLElement { - if (this._rawSvg) { - const e = document.createElement("div") - e.innerHTML = this._src - return e - } - - const el = document.createElement("img") - el.src = this._src - el.onload = () => { - el.style.opacity = "1" - } - el.onerror = () => { - if (this._options?.fallbackImage) { - if (el.src === this._options.fallbackImage) { - // Sigh... nothing to be done anymore - return - } - el.src = this._options.fallbackImage - } - } - return el - } -} diff --git a/src/UI/Base/Lazy.ts b/src/UI/Base/Lazy.ts deleted file mode 100644 index c575e5a4e..000000000 --- a/src/UI/Base/Lazy.ts +++ /dev/null @@ -1,15 +0,0 @@ -import BaseUIElement from "../BaseUIElement" - -export default class Lazy extends BaseUIElement { - private readonly _f: () => BaseUIElement - - constructor(f: () => BaseUIElement) { - super() - this._f = f - } - - protected InnerConstructElement(): HTMLElement { - // The caching of the BaseUIElement will guarantee that _f will only be called once - return this._f().ConstructElement() - } -} diff --git a/src/UI/Base/LinkToWeblate.ts b/src/UI/Base/LinkToWeblate.ts deleted file mode 100644 index 273ae3d32..000000000 --- a/src/UI/Base/LinkToWeblate.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { VariableUiElement } from "./VariableUIElement" -import Locale from "../i18n/Locale" -import Link from "./Link" -import SvelteUIElement from "./SvelteUIElement" -import Translate from "../../assets/svg/Translate.svelte" -import Constants from "../../Models/Constants" - -/** - * The little 'translate'-icon next to every icon + some static helper functions - */ -export default class LinkToWeblate extends VariableUiElement { - constructor(context: string, availableTranslations: object) { - super( - Locale.language.map( - (ln) => { - if (Locale.showLinkToWeblate.data === false) { - return undefined - } - if (availableTranslations["*"] !== undefined) { - return undefined - } - if (context === undefined || context.indexOf(":") < 0) { - return undefined - } - const icon = new SvelteUIElement(Translate).SetClass( - "rounded-full inline-block w-3 h-3 ml-1 weblate-link self-center" - ) - if (availableTranslations[ln] === undefined) { - icon.SetClass("bg-red-400") - } - return new Link(icon, LinkToWeblate.hrefToWeblate(ln, context), true).SetClass( - "weblate-link" - ) - }, - [Locale.showLinkToWeblate] - ) - ) - this.SetClass("enable-links") - const self = this - Locale.showLinkOnMobile.addCallbackAndRunD((showOnMobile) => { - if (showOnMobile) { - self.RemoveClass("hidden-on-mobile") - } else { - self.SetClass("hidden-on-mobile") - } - }) - } - - /** - * Creates the url to Hosted weblate - * - * LinkToWeblate.hrefToWeblate("nl", "category:some.context") // => "https://translate.mapcomplete.org/translate/mapcomplete/category/nl/?offset=1&q=context%3A%3D%22some.context%22" - */ - public static hrefToWeblate(language: string, contextKey: string): string { - if (contextKey === undefined || contextKey.indexOf(":") < 0) { - return undefined - } - const [category, ...rest] = contextKey.split(":") - const key = rest.join(":") - - const baseUrl = Constants.weblate + "translate/mapcomplete/" - return baseUrl + category + "/" + language + "/?offset=1&q=context%3A%3D%22" + key + "%22" - } - - public static hrefToWeblateZen( - language: string, - category: "core" | "themes" | "layers" | "shared-questions" | "glossary" | string, - searchKey: string - ): string { - const baseUrl = Constants.weblate + "zen/mapcomplete/" - // ?offset=1&q=+state%3A%3Ctranslated+context%3Acampersite&sort_by=-priority%2Cposition&checksum= - return ( - baseUrl + - category + - "/" + - language + - "?offset=1&q=+state%3A%3Ctranslated+context%3A" + - encodeURIComponent(searchKey) + - "&sort_by=-priority%2Cposition&checksum=" - ) - } -} diff --git a/src/UI/Base/WeblateLink.svelte b/src/UI/Base/WeblateLink.svelte index 4f5a149d3..413ee3b59 100644 --- a/src/UI/Base/WeblateLink.svelte +++ b/src/UI/Base/WeblateLink.svelte @@ -1,8 +1,8 @@ {#if $license !== undefined} @@ -25,9 +26,15 @@ class="no-images bg-black-transparent flex items-center rounded-lg p-0.5 px-3 text-sm text-white" > {#if icon !== undefined} -
- -
+ {#if openOriginal} + + + + {:else} +
+ +
+ {/if} {/if}
diff --git a/src/UI/UIElement.ts b/src/UI/UIElement.ts deleted file mode 100644 index 39990260b..000000000 --- a/src/UI/UIElement.ts +++ /dev/null @@ -1,30 +0,0 @@ -import BaseUIElement from "./BaseUIElement" - -/** - * @deprecated - */ -export abstract class UIElement extends BaseUIElement { - /** - * Should be overridden for specific HTML functionality - */ - protected InnerConstructElement(): HTMLElement { - // Uses the old fashioned way to construct an element using 'InnerRender' - const innerRender = this.InnerRender() - if (innerRender === undefined || innerRender === "") { - return undefined - } - const el = document.createElement("span") - if (typeof innerRender === "string") { - el.innerHTML = innerRender - } else { - const subElement = innerRender.ConstructElement() - if (subElement === undefined) { - return undefined - } - el.appendChild(subElement) - } - return el - } - - protected abstract InnerRender(): string | BaseUIElement -} diff --git a/src/UI/i18n/Translation.ts b/src/UI/i18n/Translation.ts index 9fc07ffec..6b1d30f67 100644 --- a/src/UI/i18n/Translation.ts +++ b/src/UI/i18n/Translation.ts @@ -1,7 +1,6 @@ import Locale from "./Locale" import { Utils } from "../../Utils" import BaseUIElement from "../BaseUIElement" -import LinkToWeblate from "../Base/LinkToWeblate" import { Store } from "../../Logic/UIEventSource" export class Translation extends BaseUIElement { @@ -209,22 +208,7 @@ export class Translation extends BaseUIElement { } }) - if (this.context === undefined || this.context?.indexOf(":") < 0) { - return el - } - - const wrapper = document.createElement("span") - wrapper.appendChild(el) - Locale.showLinkToWeblate.addCallbackAndRun((doShow) => { - if (!doShow) { - return - } - const linkToWeblate = new LinkToWeblate(this.context, this.translations) - wrapper.appendChild(linkToWeblate.ConstructElement()) - return true - }) - - return wrapper + return el } public SupportedLanguages(): string[] { diff --git a/src/UI/i18n/Translations.ts b/src/UI/i18n/Translations.ts index ea95dc47c..98a53715c 100644 --- a/src/UI/i18n/Translations.ts +++ b/src/UI/i18n/Translations.ts @@ -6,6 +6,7 @@ import LanguageUtils from "../../Utils/LanguageUtils" import { Store } from "../../Logic/UIEventSource" import Locale from "./Locale" import { Utils } from "../../Utils" +import Constants from "../../Models/Constants" export default class Translations { static readonly t: Readonly = CompiledTranslations.t @@ -169,4 +170,38 @@ export default class Translations { return true } + + /** + * Creates the url to Hosted weblate + * + * LinkToWeblate.hrefToWeblate("nl", "category:some.context") // => "https://translate.mapcomplete.org/translate/mapcomplete/category/nl/?offset=1&q=context%3A%3D%22some.context%22" + */ + public static hrefToWeblate(language: string, contextKey: string): string { + if (contextKey === undefined || contextKey.indexOf(":") < 0) { + return undefined + } + const [category, ...rest] = contextKey.split(":") + const key = rest.join(":") + + const baseUrl = Constants.weblate + "translate/mapcomplete/" + return baseUrl + category + "/" + language + "/?offset=1&q=context%3A%3D%22" + key + "%22" + } + + public static hrefToWeblateZen( + language: string, + category: "core" | "themes" | "layers" | "shared-questions" | "glossary" | string, + searchKey: string + ): string { + const baseUrl = Constants.weblate + "zen/mapcomplete/" + // ?offset=1&q=+state%3A%3Ctranslated+context%3Acampersite&sort_by=-priority%2Cposition&checksum= + return ( + baseUrl + + category + + "/" + + language + + "?offset=1&q=+state%3A%3Ctranslated+context%3A" + + encodeURIComponent(searchKey) + + "&sort_by=-priority%2Cposition&checksum=" + ) + } }