Copyright panel: port to svelte, generate licenses detects 'mostly white' icons now, fix #2041

This commit is contained in:
Pieter Vander Vennet 2024-07-23 17:59:06 +02:00
parent f2d2240896
commit 2aa77b7b47
9 changed files with 331 additions and 245 deletions

View file

@ -0,0 +1,188 @@
<script lang="ts">
import type { SpecialVisualizationState } from "../SpecialVisualization"
import Translations from "../i18n/Translations"
import contributors from "../../assets/contributors.json"
import translators from "../../assets/translators.json"
import { Translation, TypedTranslation } from "../i18n/Translation"
import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
import Tr from "../Base/Tr.svelte"
import IconCopyrightPanel from "./IconCopyrightPanel.svelte"
import licenses from "../../assets/generated/license_info.json"
import type SmallLicense from "../../Models/smallLicense"
import Constants from "../../Models/Constants"
import ContributorCount from "../../Logic/ContributorCount"
import BaseUIElement from "../BaseUIElement"
import Github from "../../assets/svg/Github.svelte"
import { DatabaseIcon, TranslateIcon } from "@rgossiaux/svelte-heroicons/solid"
import Osm_logo from "../../assets/svg/Osm_logo.svelte"
import Generic_map from "../../assets/svg/Generic_map.svelte"
import { PencilIcon, UserGroupIcon, UsersIcon } from "@babeard/svelte-heroicons/solid"
import Loading from "../Base/Loading.svelte"
import Marker from "../Map/Marker.svelte"
export let state: SpecialVisualizationState
const t = Translations.t.general.attribution
const layoutToUse = state.layout
const iconAttributions: string[] = layoutToUse.getUsedImages()
let maintainer: Translation = undefined
if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") {
maintainer = t.themeBy.Subs({ author: layoutToUse.credits })
}
const bgMapAttribution = state.mapProperties.rasterLayer.mapD((layer) => {
const props = layer.properties
const attrUrl = props.attribution?.url
const attrText = props.attribution?.text
let bgAttr: BaseUIElement | string = undefined
if (attrText && attrUrl) {
bgAttr =
"<a href='" +
attrUrl +
"' target='_blank' rel='noopener'>" +
attrText +
"</a>"
} else if (attrUrl) {
bgAttr = attrUrl
} else {
bgAttr = attrText
}
if (bgAttr) {
return Translations.t.general.attribution.attributionBackgroundLayerWithCopyright.Subs(
{
name: props.name,
copyright: bgAttr
}
)
}
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(
props
)
})
const allLicenses = {}
for (const key in licenses) {
const license: SmallLicense = licenses[key]
allLicenses[license.path] = license
}
function calculateDataContributions(contributions: Map<string, number>): Translation {
if (contributions === undefined) {
return undefined
}
const sorted = Array.from(contributions, ([name, value]) => ({
name,
value
})).filter((x) => x.name !== undefined && x.name !== "undefined")
if (sorted.length === 0) {
return undefined
}
sorted.sort((a, b) => b.value - a.value)
let hiddenCount = 0
if (sorted.length > 10) {
hiddenCount = sorted.length - 10
sorted.splice(10, sorted.length - 10)
}
const links = sorted.map(
(kv) =>
`<a href="https://openstreetmap.org/user/${kv.name}" target="_blank">${kv.name}</a>`
)
const contribs = links.join(", ")
if (hiddenCount <= 0) {
return t.mapContributionsBy.Subs({
contributors: contribs
})
} else {
return t.mapContributionsByAndHidden.Subs({
contributors: contribs,
hiddenCount: hiddenCount
})
}
}
const datacontributions = new ContributorCount(state).Contributors.map(counts => calculateDataContributions(counts))
function codeContributors(contributors,
translation: TypedTranslation<{ contributors; hiddenCount }>): Translation {
const total = contributors.contributors.length
let filtered = [...contributors.contributors]
filtered.splice(10, total - 10)
let contribsStr = filtered.map((c) => c.contributor).join(", ")
if (contribsStr === "") {
// Hmm, something went wrong loading the contributors list. Lets show nothing
return undefined
}
return translation.Subs({
contributors: contribsStr,
hiddenCount: total - 10
})
}
</script>
<div class="flex flex-col gap-y-4 link-underline">
<h3>
<Tr t={t.attributionTitle} />
</h3>
<div class="flex items-center gap-x-2">
<Osm_logo class="w-8 h-8 shrink-0" />
<Tr t={t.attributionContent} />
</div>
{#if $bgMapAttribution !== undefined}
<div class="flex items-center gap-x-2">
<Generic_map class="w-8 h-8 shrink-0" />
<Tr t={$bgMapAttribution} />
</div>
{/if}
<div class="flex items-center gap-x-2">
<Marker icons={state.layout.icon} size="h-8 w-8 shrink-0" />
<Tr t={maintainer} />
</div>
<div class="flex items-center gap-x-2">
<UserGroupIcon class="w-8 h-8 shrink-0" />
{#if $datacontributions !== undefined}
<Tr t={$datacontributions} />
{:else}
<Loading />
{/if}
</div>
<div class="flex items-center gap-x-2">
<Github class="w-8 h-8 shrink-0" />
<Tr t={codeContributors(contributors, t.codeContributionsBy)} />
</div>
<div class="flex items-center gap-x-2">
<TranslateIcon class="w-8 h-8 shrink-0" />
<Tr t={codeContributors(translators, t.translatedBy)} />
</div>
<AccordionSingle>
<div slot="header">
<Tr t={t.iconAttribution.title} />
</div>
{#each iconAttributions as iconAttribution}
<IconCopyrightPanel iconPath={iconAttribution} license={allLicenses[iconAttribution]} />
{/each}
</AccordionSingle>
<div class="self-end">
MapComplete {Constants.vNumber}
</div>
</div>