Style: bring index page (and legacy subtle button) in line with the new style

This commit is contained in:
Pieter Vander Vennet 2023-05-22 01:37:02 +02:00
parent 8ed0a32d15
commit 64e791dbfb
13 changed files with 126 additions and 203 deletions

View file

@ -27,7 +27,7 @@ export default class AllThemesGui {
new LoginToggle(undefined, Translations.t.index.logIn, {
osmConnection,
featureSwitchUserbadge: new ImmutableStore(true),
}),
}).SetClass("flex justify-center w-full"),
Translations.t.general.aboutMapComplete.intro.SetClass("link-underline"),
new FixedUiElement("v" + Constants.vNumber).SetClass("block"),
])

View file

@ -4,13 +4,15 @@ import { UIElement } from "../UIElement"
import { VariableUiElement } from "./VariableUIElement"
import Lazy from "./Lazy"
import Loading from "./Loading"
import SubtleButtonSvelte from "./SubtleButton.svelte"
import SvelteUIElement from "./SvelteUIElement"
import SubtleLink from "./SubtleLink.svelte";
import Translations from "../i18n/Translations";
import Combine from "./Combine";
import Img from "./Img";
/**
* @deprecated
*/
export class SubtleButton extends UIElement {
private readonly imageUrl: string | BaseUIElement
private readonly message: string | BaseUIElement
@ -42,7 +44,7 @@ export class SubtleButton extends UIElement {
return new SvelteUIElement(SubtleLink, {href: this.options.url, newTab: this.options.newTab})
}
const classes = "block flex p-3 my-2 bg-subtle rounded-lg hover:shadow-xl hover:bg-unsubtle transition-colors transition-shadow link-no-underline";
const classes = "button";
const message = Translations.W(this.message)?.SetClass("block overflow-ellipsis no-images flex-shrink");
let img;
const imgClasses = "block justify-center flex-none mr-4 " + (this.options?.imgSize ?? "h-11 w-11")

View file

@ -32,7 +32,7 @@
</script>
<a
class={(options.extraClasses??"") + 'flex hover:shadow-xl transition-[color,background-color,box-shadow] hover:bg-unsubtle cursor-pointer'}
class={(options.extraClasses??"") + ' button text-ellipsis'}
{href}
target={(newTab ? "_blank" : undefined) }
>
@ -48,16 +48,3 @@
<slot/>
</a>
<style lang="scss">
span,
a {
@apply flex p-3 my-2 py-4 rounded-lg shrink-0;
@apply items-center w-full no-underline;
@apply bg-subtle text-black;
:global(span) {
@apply block text-ellipsis;
}
}
</style>

View file

@ -13,9 +13,9 @@
export let onMainScreen: boolean = true
const prefix = "mapcomplete-hidden-theme-"
const hiddenThemes: LayoutInformation[] = themeOverview.filter(
const hiddenThemes: LayoutInformation[] = (themeOverview["default"] ?? themeOverview)?.filter(
(layout) => layout.hideFromOverview
)
) ?? []
const userPreferences = state.osmConnection.preferencesHandler.preferences
const t = Translations.t.general.morescreen
@ -45,3 +45,4 @@
</p>
</svelte:fragment>
</ThemesList>

View file

@ -1,17 +1,13 @@
import Svg from "../../Svg"
import Combine from "../Base/Combine"
import { SubtleButton } from "../Base/SubtleButton"
import Translations from "../i18n/Translations"
import BaseUIElement from "../BaseUIElement"
import LayoutConfig, { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
import LayoutConfig, {LayoutInformation} from "../../Models/ThemeConfig/LayoutConfig"
import {ImmutableStore, Store, UIEventSource} from "../../Logic/UIEventSource"
import Loc from "../../Models/Loc"
import UserRelatedState from "../../Logic/State/UserRelatedState"
import { Utils } from "../../Utils"
import Title from "../Base/Title"
import {Utils} from "../../Utils"
import themeOverview from "../../assets/generated/theme_overview.json"
import { Translation } from "../i18n/Translation"
import { TextField } from "../Input/TextField"
import {TextField} from "../Input/TextField"
import Locale from "../i18n/Locale"
import SvelteUIElement from "../Base/SvelteUIElement"
import ThemesList from "./ThemesList.svelte"

View file

@ -1,64 +1,36 @@
<script lang="ts" context="module">
export interface Theme {
id: string
icon: string
title: any
shortDescription: any
definition?: any
mustHaveLanguage?: boolean
hideFromOverview: boolean
keywords?: any[]
}
<script context="module" lang="ts">
export interface Theme {
id: string
icon: string
title: any
shortDescription: any
definition?: any
mustHaveLanguage?: boolean
hideFromOverview: boolean
keywords?: any[]
}
</script>
<script lang="ts">
import { UIEventSource } from "../../Logic/UIEventSource"
import Svg from "../../Svg"
import SubtleButton from "../Base/SubtleButton.svelte"
import ToSvelte from "../Base/ToSvelte.svelte"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte";
import {UIEventSource} from "../../Logic/UIEventSource"
import Svg from "../../Svg"
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>
export let search: UIEventSource<string>
const t = Translations.t.general.morescreen
const t = Translations.t.general.morescreen
</script>
<span>
<h5>{t.noMatchingThemes.toString()}</h5>
<button
on:click={() => {
search.setData("")
}}
>
<SubtleButton>
<span slot="image">
<ToSvelte construct={Svg.search_disable_svg().SetClass("w-6 mr-2")} />
</span>
<Tr t={t.noSearch} slot="message"/>
</SubtleButton>
</button>
</span>
<div class="w-full">
<h5>{t.noMatchingThemes.toString()}</h5>
<div class="flex justify-center">
<style lang="scss">
span {
@apply flex flex-col items-center w-full;
h5 {
@apply w-max font-bold;
}
// SubtleButton
button {
@apply h-12;
span {
@apply w-max;
:global(img) {
@apply h-6;
}
}
}
}
</style>
<button on:click={() => search.setData("")}>
<ToSvelte construct={Svg.search_disable_svg().SetClass("w-6 mr-2")}/>
<Tr slot="message" t={t.noSearch}/>
</button>
</div>
</div>

View file

@ -13,13 +13,13 @@
<span>
{t.hookMore.toString()}
</span>
<div class="w-full">
<SubtleLink href="./professional.html">
<Tr slot="message" t={t.button} />
<div class="w-full">
<Tr slot="message" t={t.button} />
</div>
</SubtleLink>
</div>
</div>
<style lang="scss">
div {
@apply flex flex-col border border-gray-300 p-2 rounded-lg;
}
</style>

View file

@ -86,7 +86,7 @@
<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">
<span class="subtle max-h-12 truncate text-ellipsis">
<Tr t={description}/>
</span>
</span>

View file

@ -21,7 +21,7 @@
$: filteredThemes = themes.filter((theme) => MoreScreen.MatchesLayout(theme, $search))
</script>
<section>
<section class="w-full">
<slot name="title" />
{#if onMainScreen}
<div class="md:grid md:grid-flow-row md:grid-cols-2 lg:grid-cols-3 gap-4">
@ -51,13 +51,7 @@
</div>
{/if}
{#if filteredThemes.length == 0}
{#if filteredThemes.length === 0}
<NoThemeResultButton {search} />
{/if}
</section>
<style lang="scss">
section {
@apply flex flex-col;
}
</style>

View file

@ -1,37 +1,39 @@
<script lang="ts">
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
import type Loc from "../../Models/Loc"
import { Utils } from "../../Utils"
import ThemesList from "./ThemesList.svelte"
import Translations from "../i18n/Translations"
import UserRelatedState from "../../Logic/State/UserRelatedState"
import {OsmConnection} from "../../Logic/Osm/OsmConnection"
import {Store, Stores, UIEventSource} from "../../Logic/UIEventSource"
import type Loc from "../../Models/Loc"
import {Utils} from "../../Utils"
import ThemesList from "./ThemesList.svelte"
import Translations from "../i18n/Translations"
import UserRelatedState from "../../Logic/State/UserRelatedState"
export let search: UIEventSource<string>
export let state: UserRelatedState & {
osmConnection: OsmConnection
locationControl?: UIEventSource<Loc>
}
export let onMainScreen: boolean = true
export let search: UIEventSource<string>
export let state: UserRelatedState & {
osmConnection: OsmConnection
locationControl?: UIEventSource<Loc>
}
export let onMainScreen: boolean = true
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)
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
{search}
{state}
{onMainScreen}
themes={customThemes}
isCustom={true}
hideThemes={false}
>
<svelte:fragment slot="title">
<!-- TODO: Change string to exclude html -->
{@html t.customThemeIntro.toString()}
</svelte:fragment>
</ThemesList>
{#if customThemes.length > 0}
<ThemesList
{search}
{state}
{onMainScreen}
themes={customThemes}
isCustom={true}
hideThemes={false}
>
<svelte:fragment slot="title">
<!-- TODO: Change string to exclude html -->
{@html t.customThemeIntro.toString()}
</svelte:fragment>
</ThemesList>
{/if}

View file

@ -704,10 +704,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
if (Array.isArray(leaf)) {
for (let i = 0; i < (<any[]>leaf).length; i++) {
const l = (<any[]>leaf)[i]
collectedList.push({ leaf: l, path: [...travelledPath, "" + i] })
collectedList.push({leaf: l, path: [...travelledPath, "" + i]})
}
} else {
collectedList.push({ leaf, path: travelledPath })
collectedList.push({leaf, path: travelledPath})
}
return collectedList
}
@ -785,7 +785,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
})
}
const cp = { ...json }
const cp = {...json}
for (const key in json) {
cp[key] = Utils.WalkJson(json[key], f, isLeaf, [...path, key])
}
@ -915,11 +915,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
const xhr = new XMLHttpRequest()
xhr.onload = () => {
if (xhr.status == 200) {
resolve({ content: xhr.response })
resolve({content: xhr.response})
} else if (xhr.status === 302) {
resolve({ redirect: xhr.getResponseHeader("location") })
resolve({redirect: xhr.getResponseHeader("location")})
} else if (xhr.status === 509 || xhr.status === 429) {
resolve({ error: "rate limited", url, statuscode: xhr.status })
resolve({error: "rate limited", url, statuscode: xhr.status})
} else {
resolve({
error: "other error: " + xhr.statusText,
@ -989,10 +989,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
const promise =
/*NO AWAIT as we work with the promise directly */ Utils.downloadJsonAdvanced(
url,
headers
)
Utils._download_cache.set(url, { promise, timestamp: new Date().getTime() })
url,
headers
)
Utils._download_cache.set(url, {promise, timestamp: new Date().getTime()})
return await promise
}
@ -1011,11 +1011,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
const injected = Utils.injectedDownloads[url]
if (injected !== undefined) {
console.log("Using injected resource for test for URL", url)
return new Promise((resolve, _) => resolve({ content: injected }))
return new Promise((resolve, _) => resolve({content: injected}))
}
const result = await Utils.downloadAdvanced(
url,
Utils.Merge({ accept: "application/json" }, headers ?? {})
Utils.Merge({accept: "application/json"}, headers ?? {})
)
if (result["error"] !== undefined) {
return <{ error: string; url: string; statuscode?: number }>result
@ -1023,12 +1023,12 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
const data = result["content"]
try {
if (typeof data === "string") {
return { content: JSON.parse(data) }
return {content: JSON.parse(data)}
}
return { content: data }
return {content: data}
} catch (e) {
console.error("Could not parse ", data, "due to", e, "\n", e.stack)
return { error: "malformed", url }
return {error: "malformed", url}
}
}
@ -1052,7 +1052,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
const element = document.createElement("a")
let file
if (typeof contents === "string") {
file = new Blob([contents], { type: options?.mimetype ?? "text/plain" })
file = new Blob([contents], {type: options?.mimetype ?? "text/plain"})
} else {
file = contents
}
@ -1169,7 +1169,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
if (typeof window === "undefined") {
return "https://mapcomplete.osm.be"
}
const path = (window.location.protocol+ window.location.host + window.location.pathname) .split("/")
const path = (window.location.protocol + "//" + window.location.host + window.location.pathname).split("/")
path.pop()
path.push("index.html")
return path.join("/")
@ -1318,7 +1318,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
if (match == undefined) {
return undefined
}
return { r: Number(match[1]), g: Number(match[2]), b: Number(match[3]) }
return {r: Number(match[1]), g: Number(match[2]), b: Number(match[3])}
}
if (!hex.startsWith("#")) {
@ -1366,7 +1366,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
d.setUTCMinutes(0)
}
public static scrollIntoView(element: HTMLBaseElement){
public static scrollIntoView(element: HTMLBaseElement) {
console.log("Scrolling into view:", element)
// Is the element completely in the view?
const parentRect = Utils.findParentWithScrolling(
@ -1384,6 +1384,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
console.log("Actually scrolling...")
element.scrollIntoView({behavior: "smooth", block: "nearest"})
}
public static findParentWithScrolling(element: HTMLBaseElement): HTMLBaseElement {
// Check if the element itself has scrolling
if (element.scrollHeight > element.clientHeight) {
@ -1396,7 +1397,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
// If the element has a parent, repeat the process for the parent element
return Utils.findParentWithScrolling(<HTMLBaseElement> element.parentElement)
return Utils.findParentWithScrolling(<HTMLBaseElement>element.parentElement)
}
/**
@ -1428,12 +1429,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
return true
}
private static colorDiff(
c0: { r: number; g: number; b: number },
c1: { r: number; g: number; b: number }
) {
return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) + Math.abs(c0.b - c1.b)
}
static SameObject(a: any, b: any) {
if (a === b) {
@ -1463,4 +1458,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
return false
}
private static colorDiff(
c0: { r: number; g: number; b: number },
c1: { r: number; g: number; b: number }
) {
return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) + Math.abs(c0.b - c1.b)
}
}

View file

@ -397,6 +397,8 @@ select:hover {
.subtle {
/* For all information that is not important for 99% of the users */
color: #999;
font-size: medium;
font-weight: normal;
}
.link-underline .subtle a {

View file

@ -800,11 +800,6 @@ video {
margin-right: 0.25rem;
}
.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.my-4 {
margin-top: 1rem;
margin-bottom: 1rem;
@ -815,6 +810,11 @@ video {
margin-right: 1rem;
}
.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.mx-10 {
margin-left: 2.5rem;
margin-right: 2.5rem;
@ -1137,11 +1137,6 @@ video {
width: 50%;
}
.w-max {
width: -webkit-max-content;
width: max-content;
}
.w-96 {
width: 24rem;
}
@ -1150,6 +1145,11 @@ video {
width: 2.5rem;
}
.w-max {
width: -webkit-max-content;
width: max-content;
}
.w-48 {
width: 12rem;
}
@ -1493,11 +1493,6 @@ video {
background-color: rgb(248 113 113 / var(--tw-bg-opacity));
}
.bg-subtle {
--tw-bg-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@ -1553,10 +1548,6 @@ video {
padding: 0px;
}
.p-3 {
padding: 0.75rem;
}
.p-8 {
padding: 2rem;
}
@ -1571,11 +1562,6 @@ video {
padding-right: 1rem;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
@ -1848,18 +1834,6 @@ video {
transition-duration: 150ms;
}
.transition-shadow {
transition-property: box-shadow;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition-\[color\2c background-color\2c box-shadow\] {
transition-property: color,background-color,box-shadow;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
@ -2246,6 +2220,8 @@ select:hover {
.subtle {
/* For all information that is not important for 99% of the users */
color: #999;
font-size: medium;
font-weight: normal;
}
.link-underline .subtle a {
@ -2432,11 +2408,6 @@ a.link-underline {
overflow-y: hidden;
}
.hover\:bg-unsubtle:hover {
--tw-bg-opacity: 1;
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
}
.hover\:bg-indigo-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(199 210 254 / var(--tw-bg-opacity));
@ -2451,12 +2422,6 @@ a.link-underline {
opacity: 1;
}
.hover\:shadow-xl:hover {
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
@media (max-width: 480px) {
.max-\[480px\]\:w-full {
width: 100%;