diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index 6bef61478..2514d1a9b 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -858,6 +858,10 @@ video { margin-bottom: 0.75rem; } +.mr-4 { + margin-right: 1rem; +} + .ml-3 { margin-left: 0.75rem; } @@ -886,10 +890,6 @@ video { margin-bottom: 6rem; } -.mr-4 { - margin-right: 1rem; -} - .mt-2 { margin-top: 0.5rem; } @@ -1038,6 +1038,10 @@ video { height: 6rem; } +.h-8 { + height: 2rem; +} + .h-full { height: 100%; } @@ -1050,10 +1054,6 @@ video { height: 3rem; } -.h-8 { - height: 2rem; -} - .h-1\/2 { height: 50%; } @@ -1122,6 +1122,14 @@ video { width: 100%; } +.w-8 { + width: 2rem; +} + +.w-1\/2 { + width: 50%; +} + .w-24 { width: 6rem; } @@ -1138,10 +1146,6 @@ video { width: 3rem; } -.w-8 { - width: 2rem; -} - .w-0 { width: 0px; } @@ -1163,10 +1167,6 @@ video { width: min-content; } -.w-1\/2 { - width: 50%; -} - .w-max { width: -webkit-max-content; width: max-content; @@ -1400,6 +1400,10 @@ video { border-bottom-left-radius: 0.25rem; } +.border-4 { + border-width: 4px; +} + .border { border-width: 1px; } @@ -1408,10 +1412,6 @@ video { border-width: 2px; } -.border-4 { - border-width: 4px; -} - .border-l-4 { border-left-width: 4px; } @@ -1420,16 +1420,16 @@ video { border-bottom-width: 1px; } -.border-gray-500 { - --tw-border-opacity: 1; - border-color: rgba(107, 114, 128, var(--tw-border-opacity)); -} - .border-black { --tw-border-opacity: 1; border-color: rgba(0, 0, 0, var(--tw-border-opacity)); } +.border-gray-500 { + --tw-border-opacity: 1; + border-color: rgba(107, 114, 128, var(--tw-border-opacity)); +} + .border-gray-400 { --tw-border-opacity: 1; border-color: rgba(156, 163, 175, var(--tw-border-opacity)); @@ -1508,14 +1508,14 @@ video { padding: 0.75rem; } -.p-4 { - padding: 1rem; -} - .p-1 { padding: 0.25rem; } +.p-4 { + padding: 1rem; +} + .p-2 { padding: 0.5rem; } @@ -1528,11 +1528,20 @@ video { padding: 0.125rem; } +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + .px-0 { padding-left: 0px; padding-right: 0px; } +.pr-2 { + padding-right: 0.5rem; +} + .pb-12 { padding-bottom: 3rem; } @@ -1601,10 +1610,6 @@ video { padding-top: 0.125rem; } -.pr-2 { - padding-right: 0.5rem; -} - .pl-6 { padding-left: 1.5rem; } @@ -1668,10 +1673,6 @@ video { font-weight: 600; } -.font-medium { - font-weight: 500; -} - .uppercase { text-transform: uppercase; } @@ -1701,10 +1702,6 @@ video { --tw-ordinal: ordinal; } -.leading-6 { - line-height: 1.5rem; -} - .tracking-tight { letter-spacing: -0.025em; } @@ -2507,16 +2504,6 @@ input { color: var(--unsubtle-detail-color-contrast); } -.group:hover .group-hover\:text-blue-800 { - --tw-text-opacity: 1; - color: rgba(30, 64, 175, var(--tw-text-opacity)); -} - -.group:hover .group-hover\:text-blue-900 { - --tw-text-opacity: 1; - color: rgba(30, 58, 138, var(--tw-text-opacity)); -} - @media (min-width: 640px) { .sm\:mx-auto { margin-left: auto; diff --git a/test.ts b/test.ts index 885ca13c3..916a46654 100644 --- a/test.ts +++ b/test.ts @@ -1,51 +1,216 @@ -import {UIEventSource} from "./Logic/UIEventSource"; -import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion"; -import TagRenderingConfig from "./Models/ThemeConfig/TagRenderingConfig"; -import {RadioButton} from "./UI/Input/RadioButton"; -import {FixedInputElement} from "./UI/Input/FixedInputElement"; +import * as shops from "./assets/generated/layers/shops.json" +import Combine from "./UI/Base/Combine"; +import Img from "./UI/Base/Img"; +import BaseUIElement from "./UI/BaseUIElement"; +import Svg from "./Svg"; +import {TextField} from "./UI/Input/TextField"; +import {Store, UIEventSource} from "./Logic/UIEventSource"; import {VariableUiElement} from "./UI/Base/VariableUIElement"; -import ValidatedTextField from "./UI/Input/ValidatedTextField"; -import VariableInputElement from "./UI/Input/VariableInputElement"; +import Locale from "./UI/i18n/Locale"; +import LanguagePicker from "./UI/LanguagePicker"; +import {InputElement} from "./UI/Input/InputElement"; +import {UIElement} from "./UI/UIElement"; +import Translations from "./UI/i18n/Translations"; +import TagRenderingConfig, {Mapping} from "./Models/ThemeConfig/TagRenderingConfig"; +import {MappingConfigJson} from "./Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; +import {FixedUiElement} from "./UI/Base/FixedUiElement"; +import {TagsFilter} from "./Logic/Tags/TagsFilter"; -const config = new TagRenderingConfig({ - question: "What is the name?", - render: "The name is {name}", - freeform: { - key: 'name', - inline:true - }, - mappings:[ - { - if:"noname=yes", - then: "This feature has no name" +const mappingsRaw: MappingConfigJson[] = shops.tagRenderings.find(tr => tr.id == "shop_types").mappings +const mappings = mappingsRaw.map((m, i) => TagRenderingConfig.ExtractMapping(m, i, "test", "test")) + + +export class SelfHidingToggle extends UIElement implements InputElement { + private readonly _shown: BaseUIElement; + private readonly _searchTerms: Record; + private readonly _search: Store; + + private readonly _selected: UIEventSource + + public constructor( + shown: string | BaseUIElement, + mainTerm: Record, + search: Store, + searchTerms?: Record, + selected: UIEventSource = new UIEventSource(false) + ) { + super(); + this._shown = Translations.W(shown); + this._search = search; + this._searchTerms = {}; + for (const lng in searchTerms ?? []) { + if (lng === "_context") { + continue + } + this._searchTerms[lng] = searchTerms[lng].map(t => t.trim().toLowerCase()) } - ] -}) - -const tags = new UIEventSource({ - name: "current feature name" -}) - -/*new TagRenderingQuestion( - tags, config, undefined).AttachTo("maindiv")*/ -const options = new UIEventSource([]) -const rb = - new VariableInputElement( - options.map(options => { - console.trace("Construction an input element for", options) - return new RadioButton( - [ - ...options.map(o => new FixedInputElement(o,o)), - new FixedInputElement("abc", "abc"), - ValidatedTextField.ForType().ConstructInputElement() - ]) + for (const lng in mainTerm) { + if (lng === "_context") { + continue + } + this._searchTerms[lng] = [mainTerm[lng]].concat(this._searchTerms[lng] ?? []) } - - ) - + this._selected = selected; + } + + + GetValue(): UIEventSource { + return this._selected + } + + IsValid(t: boolean): boolean { + return true; + } + + protected InnerRender(): string | BaseUIElement { + let el: BaseUIElement = this._shown; + const selected = this._selected; + const search = this._search; + const terms = this._searchTerms; + const applySearch = () => { + const s = search.data?.trim()?.toLowerCase() + if (s === undefined || s.length === 0 || selected.data) { + el.RemoveClass("hidden") + return; + } + + if (terms[Locale.language.data].some(t => t.toLowerCase().indexOf(s) >= 0)) { + el.RemoveClass("hidden"); + return; + } + + el.SetClass("hidden") + } + search.addCallbackAndRun(_ => { + applySearch() + }) + Locale.language.addCallback(_ => { + applySearch() + }) + + selected.addCallbackAndRun(selected => { + if (selected) { + el.SetClass("border-4") + el.RemoveClass("border") + el.SetStyle("margin: calc( 0.25rem )") + } else { + el.SetStyle("margin: calc( 0.25rem + 3px )") + el.SetClass("border") + el.RemoveClass("border-4") + } + applySearch() + }) + + el.onClick(() => selected.setData(!selected.data)) + + return el.SetClass("border border-black rounded-full p-1 px-4") + } +} + + +class SearchablePresets extends Combine implements InputElement { + private selectedElements: UIEventSource; + + constructor( + values: { show: BaseUIElement, value: T, mainTerm: Record, searchTerms?: Record }[], + mode: "select-one" | "select-many", + selectedElements: UIEventSource = new UIEventSource([])) { + + const search = new TextField({}) + + const searchBar = new Combine([Svg.search_svg().SetClass("w-8"), search.SetClass("mr-4 w-full")]) + .SetClass("flex rounded-full border-2 border-black items-center my-2 w-1/2") + + const searchValue = search.GetValue().map(s => s?.trim()?.toLowerCase()) + + + values = values.map(v => { + + const vIsSelected = new UIEventSource(false); + + selectedElements.addCallbackAndRunD(selectedElements => { + vIsSelected.setData(selectedElements.some(t => t === v.value)) + }) + + vIsSelected.addCallback(selected => { + if (selected) { + if (mode === "select-one") { + selectedElements.setData([v.value]) + } else if (!selectedElements.data.some(t => t === v.value)) { + selectedElements.data.push(v.value); + selectedElements.ping() + } + }else{ + for (let i = 0; i < selectedElements.data.length; i++) { + const t = selectedElements.data[i] + if(t == v.value){ + selectedElements.data.splice(i, 1) + selectedElements.ping() + break; + } + } + } + }) + + return { + ...v, + show: new SelfHidingToggle(v.show, v.mainTerm, searchValue, v.searchTerms, vIsSelected) + }; + }) + + super([ + searchBar, + new VariableUiElement(Locale.language.map(lng => { + values.sort((a, b) => a.mainTerm[lng] < b.mainTerm[lng] ? -1 : 1) + return new Combine(values.map(e => e.show)) + .SetClass("flex flex-wrap w-full") + })) + + ]) + this.selectedElements = selectedElements; + + } + + public GetValue(): UIEventSource { + return this.selectedElements; + } + + IsValid(t: T[]): boolean { + return true; + } + + +} + + +function fromMapping(m: Mapping): { show: BaseUIElement, value: TagsFilter, mainTerm: Record, searchTerms?: Record } { + const el: BaseUIElement = m.then + let icon: BaseUIElement + if (m.icon !== undefined) { + icon = new Img(m.icon).SetClass("h-8 w-8 pr-2") + } else { + icon = new FixedUiElement("").SetClass("h-8 w-1") + } + const show = new Combine([ + icon, + el.SetClass("block-ruby") + ]).SetClass("flex items-center") + + return {show, mainTerm: m.then.translations, searchTerms: m.searchTerms, value: m.if}; + +} + +const sp = new SearchablePresets( + mappings.map(m => fromMapping(m)), + "select-one" ) -rb.AttachTo("maindiv") -rb.GetValue().addCallbackAndRun(v => console.log("Current value is",v)) -new VariableUiElement(rb.GetValue()).AttachTo("extradiv") -window.setTimeout(() => {options.setData(["xyz","foo","bar"])},10000) \ No newline at end of file +sp.AttachTo("maindiv") + +const lp = new LanguagePicker(["en", "nl"], "") + +new Combine([ + new VariableUiElement(sp.GetValue().map(tf => new FixedUiElement("Selected tags: " + tf.map(tf => tf.asHumanString(false, false, {})).join(", ")))), + lp +]).SetClass("flex flex-col") + .AttachTo("extradiv") \ No newline at end of file