forked from MapComplete/MapComplete
		
	Fix search behaviour of theme index, fix #1385
This commit is contained in:
		
							parent
							
								
									aa6902a25c
								
							
						
					
					
						commit
						102fe2c5e8
					
				
					 2 changed files with 90 additions and 104 deletions
				
			
		| 
						 | 
					@ -1,17 +1,17 @@
 | 
				
			||||||
import Svg from "../../Svg"
 | 
					import Svg from "../../Svg"
 | 
				
			||||||
import Combine from "../Base/Combine"
 | 
					import Combine from "../Base/Combine"
 | 
				
			||||||
import { SubtleButton } from "../Base/SubtleButton"
 | 
					import {SubtleButton} from "../Base/SubtleButton"
 | 
				
			||||||
import Translations from "../i18n/Translations"
 | 
					import Translations from "../i18n/Translations"
 | 
				
			||||||
import BaseUIElement from "../BaseUIElement"
 | 
					import BaseUIElement from "../BaseUIElement"
 | 
				
			||||||
import LayoutConfig, { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
 | 
					import LayoutConfig, {LayoutInformation} from "../../Models/ThemeConfig/LayoutConfig"
 | 
				
			||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
 | 
					import {ImmutableStore, Store, UIEventSource} from "../../Logic/UIEventSource"
 | 
				
			||||||
import Loc from "../../Models/Loc"
 | 
					import Loc from "../../Models/Loc"
 | 
				
			||||||
import UserRelatedState from "../../Logic/State/UserRelatedState"
 | 
					import UserRelatedState from "../../Logic/State/UserRelatedState"
 | 
				
			||||||
import { Utils } from "../../Utils"
 | 
					import {Utils} from "../../Utils"
 | 
				
			||||||
import Title from "../Base/Title"
 | 
					import Title from "../Base/Title"
 | 
				
			||||||
import themeOverview from "../../assets/generated/theme_overview.json"
 | 
					import themeOverview from "../../assets/generated/theme_overview.json"
 | 
				
			||||||
import { Translation } from "../i18n/Translation"
 | 
					import {Translation} from "../i18n/Translation"
 | 
				
			||||||
import { TextField } from "../Input/TextField"
 | 
					import {TextField} from "../Input/TextField"
 | 
				
			||||||
import Locale from "../i18n/Locale"
 | 
					import Locale from "../i18n/Locale"
 | 
				
			||||||
import SvelteUIElement from "../Base/SvelteUIElement"
 | 
					import SvelteUIElement from "../Base/SvelteUIElement"
 | 
				
			||||||
import ThemesList from "./ThemesList.svelte"
 | 
					import ThemesList from "./ThemesList.svelte"
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
            searchTerm = searchTerm.toLowerCase()
 | 
					            searchTerm = searchTerm.toLowerCase()
 | 
				
			||||||
            if (searchTerm === "personal") {
 | 
					            if (searchTerm === "personal") {
 | 
				
			||||||
                window.location.href = MoreScreen.createUrlFor(
 | 
					                window.location.href = MoreScreen.createUrlFor(
 | 
				
			||||||
                    { id: "personal" },
 | 
					                    {id: "personal"},
 | 
				
			||||||
                    false,
 | 
					                    false,
 | 
				
			||||||
                    state
 | 
					                    state
 | 
				
			||||||
                ).data
 | 
					                ).data
 | 
				
			||||||
| 
						 | 
					@ -59,13 +59,13 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
                (th) =>
 | 
					                (th) =>
 | 
				
			||||||
                    th.hideFromOverview == false &&
 | 
					                    th.hideFromOverview == false &&
 | 
				
			||||||
                    th.id !== "personal" &&
 | 
					                    th.id !== "personal" &&
 | 
				
			||||||
                    MoreScreen.MatchesLayoutFunc(th)(searchTerm)
 | 
					                    MoreScreen.MatchesLayout(th, searchTerm)
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            if (publicTheme !== undefined) {
 | 
					            if (publicTheme !== undefined) {
 | 
				
			||||||
                window.location.href = MoreScreen.createUrlFor(publicTheme, false, state).data
 | 
					                window.location.href = MoreScreen.createUrlFor(publicTheme, false, state).data
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const hiddenTheme = MoreScreen.officialThemes.find(
 | 
					            const hiddenTheme = MoreScreen.officialThemes.find(
 | 
				
			||||||
                (th) => th.id !== "personal" && MoreScreen.MatchesLayoutFunc(th)(searchTerm)
 | 
					                (th) => th.id !== "personal" && MoreScreen.MatchesLayout(th, searchTerm)
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            if (hiddenTheme !== undefined) {
 | 
					            if (hiddenTheme !== undefined) {
 | 
				
			||||||
                window.location.href = MoreScreen.createUrlFor(hiddenTheme, false, state).data
 | 
					                window.location.href = MoreScreen.createUrlFor(hiddenTheme, false, state).data
 | 
				
			||||||
| 
						 | 
					@ -109,6 +109,85 @@ 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
 | 
				
			||||||
 | 
					        title: any
 | 
				
			||||||
 | 
					        shortDescription: any
 | 
				
			||||||
 | 
					        keywords?: any[]
 | 
				
			||||||
 | 
					    }, search: string): boolean {
 | 
				
			||||||
 | 
					        if(search === undefined){
 | 
				
			||||||
 | 
					            return true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        search = search.toLocaleLowerCase()
 | 
				
			||||||
 | 
					        if (search.length > 3 && layout.id.toLowerCase().indexOf(search) >= 0) {
 | 
				
			||||||
 | 
					            return true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(layout.id === "personal"){
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const entitiesToSearch = [
 | 
				
			||||||
 | 
					            layout.shortDescription,
 | 
				
			||||||
 | 
					            layout.title,
 | 
				
			||||||
 | 
					            ...(layout.keywords ?? []),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        for (const entity of entitiesToSearch) {
 | 
				
			||||||
 | 
					            if (entity === undefined) {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const term = entity["*"] ?? entity[Locale.language.data]
 | 
				
			||||||
 | 
					            if (term?.toLowerCase()?.indexOf(search) >= 0) {
 | 
				
			||||||
 | 
					                return true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static createUrlFor(
 | 
					    private static createUrlFor(
 | 
				
			||||||
        layout: { id: string; definition?: string },
 | 
					        layout: { id: string; definition?: string },
 | 
				
			||||||
        isCustom: boolean,
 | 
					        isCustom: boolean,
 | 
				
			||||||
| 
						 | 
					@ -164,79 +243,4 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
            }) ?? new ImmutableStore<string>(`${linkPrefix}`)
 | 
					            }) ?? new ImmutableStore<string>(`${linkPrefix}`)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 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")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static MatchesLayoutFunc(layout: {
 | 
					 | 
				
			||||||
        id: string
 | 
					 | 
				
			||||||
        title: any
 | 
					 | 
				
			||||||
        shortDescription: any
 | 
					 | 
				
			||||||
        keywords?: any[]
 | 
					 | 
				
			||||||
    }): (search: string) => boolean {
 | 
					 | 
				
			||||||
        return (search: string) => {
 | 
					 | 
				
			||||||
            search = search.toLocaleLowerCase()
 | 
					 | 
				
			||||||
            if (layout.id.toLowerCase().indexOf(search) >= 0) {
 | 
					 | 
				
			||||||
                return true
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            const entitiesToSearch = [
 | 
					 | 
				
			||||||
                layout.shortDescription,
 | 
					 | 
				
			||||||
                layout.title,
 | 
					 | 
				
			||||||
                ...(layout.keywords ?? []),
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
            for (const entity of entitiesToSearch) {
 | 
					 | 
				
			||||||
                if (entity === undefined) {
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const term = entity["*"] ?? entity[Locale.language.data]
 | 
					 | 
				
			||||||
                if (term?.toLowerCase()?.indexOf(search) >= 0) {
 | 
					 | 
				
			||||||
                    return true
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
  import ProfessionalServicesButton from "./ProfessionalServicesButton.svelte"
 | 
					  import ProfessionalServicesButton from "./ProfessionalServicesButton.svelte"
 | 
				
			||||||
  import ThemeButton from "./ThemeButton.svelte"
 | 
					  import ThemeButton from "./ThemeButton.svelte"
 | 
				
			||||||
  import { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
 | 
					  import { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
 | 
				
			||||||
 | 
					  import MoreScreen from "./MoreScreen";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let search: UIEventSource<string>
 | 
					  export let search: UIEventSource<string>
 | 
				
			||||||
  export let themes: LayoutInformation[]
 | 
					  export let themes: LayoutInformation[]
 | 
				
			||||||
| 
						 | 
					@ -18,26 +19,7 @@
 | 
				
			||||||
  export let hideThemes: boolean = true
 | 
					  export let hideThemes: boolean = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Filter theme based on search value
 | 
					  // Filter theme based on search value
 | 
				
			||||||
  $: filteredThemes = themes.filter((theme) => {
 | 
					  $: filteredThemes = themes.filter((theme) => MoreScreen.MatchesLayout(theme, $search))
 | 
				
			||||||
    if ($search === undefined || $search === "") return true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const srch = $search.toLocaleLowerCase()
 | 
					 | 
				
			||||||
    if (theme.id.toLowerCase().indexOf(srch) >= 0) {
 | 
					 | 
				
			||||||
      return true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const entitiesToSearch = [theme.shortDescription, theme.title, ...(theme.keywords ?? [])]
 | 
					 | 
				
			||||||
    for (const entity of entitiesToSearch) {
 | 
					 | 
				
			||||||
      if (entity === undefined) {
 | 
					 | 
				
			||||||
        continue
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const term = entity["*"] ?? entity[Locale.language.data]
 | 
					 | 
				
			||||||
      if (term?.toLowerCase()?.indexOf(search) >= 0) {
 | 
					 | 
				
			||||||
        return true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return false
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<section>
 | 
					<section>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue