forked from MapComplete/MapComplete
Refactoring: overhaul of the visual style with CSS
This commit is contained in:
parent
a1f5032232
commit
7f1e8d3f9c
37 changed files with 1280 additions and 741 deletions
|
@ -3,36 +3,30 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource"
|
||||
import Constants from "../../Models/Constants"
|
||||
import Svg from "../../Svg"
|
||||
import SubtleButton from "../Base/SubtleButton.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import SubtleLink from "../Base/SubtleLink.svelte";
|
||||
import Tr from "../Base/Tr.svelte";
|
||||
|
||||
export let userDetails: UIEventSource<UserDetails>
|
||||
const t = Translations.t.general.morescreen
|
||||
|
||||
console.log($userDetails.csCount < 50)
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if $userDetails.csCount < Constants.userJourney.themeGeneratorReadOnlyUnlock}
|
||||
<SubtleButton
|
||||
options={{
|
||||
url: "https://github.com/pietervdvn/MapComplete/issues",
|
||||
newTab: true,
|
||||
}}
|
||||
<SubtleLink
|
||||
url="https://github.com/pietervdvn/MapComplete/issues"
|
||||
newTab={true}
|
||||
>
|
||||
<span slot="message">{t.requestATheme.toString()}</span>
|
||||
</SubtleButton>
|
||||
<Tr t={t.requestATheme}/>
|
||||
</SubtleLink>
|
||||
{:else}
|
||||
<SubtleButton
|
||||
options={{
|
||||
url: "https://pietervdvn.github.io/mc/legacy/070/customGenerator.html",
|
||||
}}
|
||||
>
|
||||
<span slot="image">
|
||||
<ToSvelte construct={Svg.pencil_svg().SetClass("h-11 w-11 mx-4 bg-red")}/>
|
||||
</span>
|
||||
<span slot="message">{t.createYourOwnTheme.toString()}</span>
|
||||
</SubtleButton>
|
||||
<SubtleLink href="https://pietervdvn.github.io/mc/legacy/070/customGenerator.html">
|
||||
<span slot="image">
|
||||
<ToSvelte construct={Svg.pencil_svg().SetClass("h-11 w-11 mx-4 bg-red")}/>
|
||||
</span>
|
||||
<Tr t={t.createYourOwnTheme}/>
|
||||
</SubtleLink>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -109,51 +109,6 @@ export default class MoreScreen extends Combine {
|
|||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a button linking to the given theme
|
||||
* @private
|
||||
*/
|
||||
public static createLinkButton(
|
||||
state: {
|
||||
locationControl?: UIEventSource<Loc>
|
||||
layoutToUse?: LayoutConfig
|
||||
},
|
||||
layout: {
|
||||
id: string
|
||||
icon: string
|
||||
title: any
|
||||
shortDescription: any
|
||||
definition?: any
|
||||
mustHaveLanguage?: boolean
|
||||
},
|
||||
isCustom: boolean = false
|
||||
): BaseUIElement {
|
||||
const url = MoreScreen.createUrlFor(layout, isCustom, state)
|
||||
let content = new Combine([
|
||||
new Translation(
|
||||
layout.title,
|
||||
!isCustom && !layout.mustHaveLanguage ? "themes:" + layout.id + ".title" : undefined
|
||||
),
|
||||
new Translation(layout.shortDescription)?.SetClass("subtle") ?? "",
|
||||
]).SetClass("overflow-hidden flex flex-col")
|
||||
|
||||
if (state.layoutToUse === undefined) {
|
||||
// Currently on the index screen: we style the buttons equally large
|
||||
content = new Combine([content]).SetClass("flex flex-col justify-center h-24")
|
||||
}
|
||||
|
||||
return new SubtleButton(layout.icon, content, { url, newTab: false })
|
||||
}
|
||||
|
||||
public static CreateProffessionalSerivesButton() {
|
||||
const t = Translations.t.professional.indexPage
|
||||
return new Combine([
|
||||
new Title(t.hook, 4),
|
||||
t.hookMore,
|
||||
new SubtleButton(undefined, t.button, { url: "./professional.html" }),
|
||||
]).SetClass("flex flex-col border border-gray-300 p-2 rounded-lg")
|
||||
}
|
||||
|
||||
public static MatchesLayout(
|
||||
layout: {
|
||||
id: string
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import SubtleButton from "../Base/SubtleButton.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte";
|
||||
|
||||
export let search: UIEventSource<string>
|
||||
|
||||
|
@ -30,14 +31,12 @@
|
|||
search.setData("")
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<SubtleButton>
|
||||
<span slot="image">
|
||||
<ToSvelte construct={Svg.search_disable_svg().SetClass("w-6 mr-2")} />
|
||||
</span>
|
||||
<span slot="message">{t.noSearch.toString()}</span>
|
||||
<Tr t={t.noSearch} slot="message"/>
|
||||
</SubtleButton>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script lang="ts">
|
||||
import SubtleButton from "../Base/SubtleButton.svelte"
|
||||
import Title from "../Base/Title"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import SubtleLink from "../Base/SubtleLink.svelte";
|
||||
import Tr from "../Base/Tr.svelte";
|
||||
|
||||
const t = Translations.t.professional.indexPage
|
||||
</script>
|
||||
|
@ -12,9 +13,9 @@
|
|||
<span>
|
||||
{t.hookMore.toString()}
|
||||
</span>
|
||||
<SubtleButton options={{ url: "./professional.html" }}>
|
||||
<span slot="message">{t.button.toString()}</span>
|
||||
</SubtleButton>
|
||||
<SubtleLink href="./professional.html">
|
||||
<Tr slot="message" t={t.button} />
|
||||
</SubtleLink>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,114 +1,94 @@
|
|||
<script lang="ts">
|
||||
import SubtleButton from "../Base/SubtleButton.svelte"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import * as personal from "../../assets/themes/personal/personal.json"
|
||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import UserDetails, { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Constants from "../../Models/Constants"
|
||||
import type Loc from "../../Models/Loc"
|
||||
import type { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import {Translation} from "../i18n/Translation"
|
||||
import * as personal from "../../assets/themes/personal/personal.json"
|
||||
import {ImmutableStore, Store, UIEventSource} from "../../Logic/UIEventSource"
|
||||
import UserDetails, {OsmConnection} from "../../Logic/Osm/OsmConnection"
|
||||
import Constants from "../../Models/Constants"
|
||||
import type Loc from "../../Models/Loc"
|
||||
import type {LayoutInformation} from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import SubtleLink from "../Base/SubtleLink.svelte";
|
||||
|
||||
export let theme: LayoutInformation
|
||||
export let isCustom: boolean = false
|
||||
export let userDetails: UIEventSource<UserDetails>
|
||||
export let state: { osmConnection: OsmConnection; locationControl?: UIEventSource<Loc> }
|
||||
export let theme: LayoutInformation
|
||||
export let isCustom: boolean = false
|
||||
export let userDetails: UIEventSource<UserDetails>
|
||||
export let state: { osmConnection: OsmConnection; locationControl?: UIEventSource<Loc> }
|
||||
|
||||
$: title = new Translation(
|
||||
theme.title,
|
||||
!isCustom && !theme.mustHaveLanguage ? "themes:" + theme.id + ".title" : undefined
|
||||
)
|
||||
$: description = new Translation(theme.shortDescription)
|
||||
|
||||
// TODO: Improve this function
|
||||
function createUrl(
|
||||
layout: { id: string; definition?: string },
|
||||
isCustom: boolean,
|
||||
state?: { locationControl?: UIEventSource<{ lat; lon; zoom }>; layoutToUse?: { id } }
|
||||
): Store<string> {
|
||||
if (layout === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (layout.id === undefined) {
|
||||
console.error("ID is undefined for layout", layout)
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (layout.id === state?.layoutToUse?.id) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const currentLocation = state?.locationControl
|
||||
|
||||
let path = window.location.pathname
|
||||
// Path starts with a '/' and contains everything, e.g. '/dir/dir/page.html'
|
||||
path = path.substr(0, path.lastIndexOf("/"))
|
||||
// Path will now contain '/dir/dir', or empty string in case of nothing
|
||||
if (path === "") {
|
||||
path = "."
|
||||
}
|
||||
|
||||
let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1" || location.port === "1234") {
|
||||
// Redirect to 'theme.html?layout=* instead of 'layout.html'. This is probably a debug run, where the routing does not work
|
||||
linkPrefix = `${path}/theme.html?layout=${layout.id}&`
|
||||
}
|
||||
|
||||
if (isCustom) {
|
||||
linkPrefix = `${path}/theme.html?userlayout=${layout.id}&`
|
||||
}
|
||||
|
||||
let hash = ""
|
||||
if (layout.definition !== undefined) {
|
||||
hash = "#" + btoa(JSON.stringify(layout.definition))
|
||||
}
|
||||
|
||||
return (
|
||||
currentLocation?.map((currentLocation) => {
|
||||
const params = [
|
||||
["z", currentLocation?.zoom],
|
||||
["lat", currentLocation?.lat],
|
||||
["lon", currentLocation?.lon],
|
||||
]
|
||||
.filter((part) => part[1] !== undefined)
|
||||
.map((part) => part[0] + "=" + part[1])
|
||||
.join("&")
|
||||
return `${linkPrefix}${params}${hash}`
|
||||
}) ?? new ImmutableStore<string>(`${linkPrefix}`)
|
||||
$: title = new Translation(
|
||||
theme.title,
|
||||
!isCustom && !theme.mustHaveLanguage ? "themes:" + theme.id + ".title" : undefined
|
||||
)
|
||||
}
|
||||
$: description = new Translation(theme.shortDescription)
|
||||
|
||||
// TODO: Improve this function
|
||||
function createUrl(
|
||||
layout: { id: string; definition?: string },
|
||||
isCustom: boolean,
|
||||
state?: { locationControl?: UIEventSource<{ lat; lon; zoom }>; layoutToUse?: { id } }
|
||||
): Store<string> {
|
||||
if (layout === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (layout.id === undefined) {
|
||||
console.error("ID is undefined for layout", layout)
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (layout.id === state?.layoutToUse?.id) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const currentLocation = state?.locationControl
|
||||
|
||||
let path = window.location.pathname
|
||||
// Path starts with a '/' and contains everything, e.g. '/dir/dir/page.html'
|
||||
path = path.substr(0, path.lastIndexOf("/"))
|
||||
// Path will now contain '/dir/dir', or empty string in case of nothing
|
||||
if (path === "") {
|
||||
path = "."
|
||||
}
|
||||
|
||||
let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1" || location.port === "1234") {
|
||||
// Redirect to 'theme.html?layout=* instead of 'layout.html'. This is probably a debug run, where the routing does not work
|
||||
linkPrefix = `${path}/theme.html?layout=${layout.id}&`
|
||||
}
|
||||
|
||||
if (isCustom) {
|
||||
linkPrefix = `${path}/theme.html?userlayout=${layout.id}&`
|
||||
}
|
||||
|
||||
let hash = ""
|
||||
if (layout.definition !== undefined) {
|
||||
hash = "#" + btoa(JSON.stringify(layout.definition))
|
||||
}
|
||||
|
||||
return (
|
||||
currentLocation?.map((currentLocation) => {
|
||||
const params = [
|
||||
["z", currentLocation?.zoom],
|
||||
["lat", currentLocation?.lat],
|
||||
["lon", currentLocation?.lon],
|
||||
]
|
||||
.filter((part) => part[1] !== undefined)
|
||||
.map((part) => part[0] + "=" + part[1])
|
||||
.join("&")
|
||||
return `${linkPrefix}${params}${hash}`
|
||||
}) ?? new ImmutableStore<string>(`${linkPrefix}`)
|
||||
)
|
||||
}
|
||||
|
||||
let href = createUrl(theme, isCustom, state)
|
||||
</script>
|
||||
|
||||
{#if theme.id !== personal.id || $userDetails.csCount > Constants.userJourney.personalLayoutUnlock}
|
||||
<div>
|
||||
<SubtleButton options={{ url: createUrl(theme, isCustom, state) }}>
|
||||
<img slot="image" src={theme.icon} class="block h-11 w-11 bg-red mx-4" alt="" />
|
||||
<span slot="message" class="message">
|
||||
<span>
|
||||
<Tr t={title}></Tr>
|
||||
<span class="subtle">
|
||||
<Tr t={description}></Tr>
|
||||
<SubtleLink href={ $href }>
|
||||
<img slot="image" src={theme.icon} class="block h-11 w-11 bg-red mx-4" alt=""/>
|
||||
<span class="flex flex-col text-ellipsis overflow-hidden">
|
||||
<Tr t={title}/>
|
||||
<span class="subtle max-h-12">
|
||||
<Tr t={description}/>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</SubtleButton>
|
||||
</div>
|
||||
</SubtleLink>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
div {
|
||||
@apply h-32 min-h-[8rem] max-h-32 text-ellipsis overflow-hidden;
|
||||
|
||||
span.message {
|
||||
@apply flex flex-col justify-center h-24;
|
||||
|
||||
& > span {
|
||||
@apply flex flex-col overflow-hidden;
|
||||
|
||||
span:nth-child(2) {
|
||||
@apply text-[#999];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
const t = Translations.t.general
|
||||
const currentIds: Store<string[]> = state.installedUserThemes
|
||||
const stableIds = Stores.ListStabilized<string>(currentIds)
|
||||
let customThemes
|
||||
$: customThemes = Utils.NoNull($stableIds.map((id) => state.GetUnofficialTheme(id)))
|
||||
$: console.log("Custom themes are", customThemes)
|
||||
</script>
|
||||
|
||||
<ThemesList
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue