forked from MapComplete/MapComplete
		
	Style: bring index page (and legacy subtle button) in line with the new style
This commit is contained in:
		
							parent
							
								
									8ed0a32d15
								
							
						
					
					
						commit
						64e791dbfb
					
				
					 13 changed files with 126 additions and 203 deletions
				
			
		| 
						 | 
				
			
			@ -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"),
 | 
			
		||||
            ])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<script lang="ts" context="module">
 | 
			
		||||
<script context="module" lang="ts">
 | 
			
		||||
    export interface Theme {
 | 
			
		||||
        id: string
 | 
			
		||||
        icon: string
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { UIEventSource } from "../../Logic/UIEventSource"
 | 
			
		||||
    import {UIEventSource} from "../../Logic/UIEventSource"
 | 
			
		||||
    import Svg from "../../Svg"
 | 
			
		||||
    import SubtleButton from "../Base/SubtleButton.svelte"
 | 
			
		||||
    import ToSvelte from "../Base/ToSvelte.svelte"
 | 
			
		||||
| 
						 | 
				
			
			@ -24,41 +24,13 @@
 | 
			
		|||
    const t = Translations.t.general.morescreen
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<span>
 | 
			
		||||
<div class="w-full">
 | 
			
		||||
    <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>
 | 
			
		||||
    <div class="flex justify-center">
 | 
			
		||||
 | 
			
		||||
        <button on:click={() => search.setData("")}>
 | 
			
		||||
            <ToSvelte construct={Svg.search_disable_svg().SetClass("w-6 mr-2")}/>
 | 
			
		||||
            <Tr slot="message" t={t.noSearch}/>
 | 
			
		||||
        </button>
 | 
			
		||||
</span>
 | 
			
		||||
 | 
			
		||||
<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>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,13 +13,13 @@
 | 
			
		|||
  <span>
 | 
			
		||||
    {t.hookMore.toString()}
 | 
			
		||||
  </span>
 | 
			
		||||
  <div class="w-full">
 | 
			
		||||
    
 | 
			
		||||
  <SubtleLink href="./professional.html">
 | 
			
		||||
    <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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
  import { OsmConnection } from "../../Logic/Osm/OsmConnection"
 | 
			
		||||
  import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
 | 
			
		||||
    import {OsmConnection} from "../../Logic/Osm/OsmConnection"
 | 
			
		||||
    import {Store, Stores, UIEventSource} from "../../Logic/UIEventSource"
 | 
			
		||||
    import type Loc from "../../Models/Loc"
 | 
			
		||||
  import { Utils } from "../../Utils"
 | 
			
		||||
    import {Utils} from "../../Utils"
 | 
			
		||||
    import ThemesList from "./ThemesList.svelte"
 | 
			
		||||
    import Translations from "../i18n/Translations"
 | 
			
		||||
    import UserRelatedState from "../../Logic/State/UserRelatedState"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,16 +22,18 @@
 | 
			
		|||
    $: console.log("Custom themes are", customThemes)
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<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>
 | 
			
		||||
    </ThemesList>
 | 
			
		||||
{/if}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								Utils.ts
									
										
									
									
									
								
							
							
						
						
									
										48
									
								
								Utils.ts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			@ -992,7 +992,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
 | 
			
		|||
            url,
 | 
			
		||||
            headers
 | 
			
		||||
        )
 | 
			
		||||
        Utils._download_cache.set(url, { promise, timestamp: new Date().getTime() })
 | 
			
		||||
        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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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%;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue