Use fancy menu for presets
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled

This commit is contained in:
Misode
2025-01-28 01:14:35 +01:00
parent 111855f3ea
commit 59642b2ff5
7 changed files with 38 additions and 41 deletions

View File

@@ -4,10 +4,12 @@ import { useFocus } from '../hooks/index.js'
interface Props {
placeholder?: string
relative?: boolean
class?: string
getResults: (search: string, close: () => void) => ComponentChildren
children: ComponentChildren
}
export function FancyMenu({ placeholder, getResults, children }: Props) {
export function FancyMenu({ placeholder, relative, class: clazz, getResults, children }: Props) {
const [active, setActive] = useFocus()
const [search, setSearch] = useState('')
const inputRef = useRef<HTMLInputElement>(null)
@@ -51,13 +53,13 @@ export function FancyMenu({ placeholder, getResults, children }: Props) {
}
}, [setActive, inputRef])
return <div class="px-1 relative">
return <div class={`px-1 ${relative ? 'relative' : ''}`}>
<div onClick={open}>
{children}
</div>
<div class={`fancy-menu absolute flex flex-col gap-2 p-2 rounded-lg drop-shadow-xl ${active ? '' : 'hidden'}`} onKeyDown={handleKeyDown}>
<div class={`fancy-menu absolute flex flex-col gap-2 p-2 rounded-lg drop-shadow-xl ${clazz} ${active ? '' : 'hidden'}`} onKeyDown={handleKeyDown}>
<input ref={inputRef} type="text" class="py-1 px-2 w-full rounded" value={search} placeholder={placeholder} onInput={(e) => setSearch((e.target as HTMLInputElement).value)} onClick={(e) => e.stopPropagation()} />
{active && <div ref={resultsRef} class="overflow-y-auto overscroll-none flex flex-col pr-2 h-96 max-h-max min-w-max">
{active && <div ref={resultsRef} class="fancy-menu-results overflow-y-auto overscroll-none flex flex-col pr-2 h-96 max-h-max w-max max-w-full">
{results}
</div>}
</div>

View File

@@ -82,7 +82,7 @@ function GeneratorTitle({ title, gen }: GeneratorTitleProps) {
return [<span class="note">{locale('generators.no_results')}</span>]
}
return results.map(g =>
<Link class="gen-result flex items-center cursor-pointer no-underline rounded p-1" href={cleanUrl(g.url)} onClick={close}>
<Link class="flex items-center cursor-pointer no-underline rounded p-1" href={cleanUrl(g.url)} onClick={close}>
{locale(`generator.${g.id}`)}
{Object.keys(Icons).includes(g.id) ? Icons[g.id as keyof typeof Icons] : undefined}
<div class="m-auto"></div>

View File

@@ -1,24 +0,0 @@
import { useMemo, useState } from 'preact/hooks'
import { Btn, BtnInput } from '../index.js'
interface Props {
values?: string[],
onSelect?: (value: string) => unknown,
searchPlaceholder?: string,
noResults?: string,
}
export function SearchList({ values, onSelect, searchPlaceholder, noResults }: Props) {
const [search, setSearch] = useState('')
const results = useMemo(() => {
const terms = search.trim().split(' ')
return values?.filter(v => terms.every(t => v.includes(t))) ?? []
}, [values, search])
return <>
<BtnInput icon="search" large value={search} onChange={setSearch} doSelect={1} placeholder={searchPlaceholder ?? 'Search'} />
<div class="result-list">
{results.map(v => <Btn key={v} label={v} onClick={() => onSelect?.(v)} />)}
{results.length === 0 && <Btn label={noResults ?? 'No results'}/>}
</div>
</>
}

View File

@@ -1,3 +1,2 @@
export * from './Checkbox.js'
export * from './Input.js'
export * from './SearchList.js'

View File

@@ -13,7 +13,8 @@ import { checkVersion, fetchDependencyMcdoc, fetchPreset, fetchRegistries, getSn
import { DEPENDENCY_URI } from '../../services/Spyglass.js'
import { Store } from '../../Store.js'
import { cleanUrl, genPath } from '../../Utils.js'
import { Ad, Btn, BtnMenu, ErrorPanel, FileCreation, FileView, Footer, HasPreview, Octicon, PreviewPanel, ProjectPanel, SearchList, SourcePanel, TextInput, VersionSwitcher } from '../index.js'
import { FancyMenu } from '../FancyMenu.jsx'
import { Ad, Btn, BtnMenu, ErrorPanel, FileCreation, FileView, Footer, HasPreview, Octicon, PreviewPanel, ProjectPanel, SourcePanel, TextInput, VersionSwitcher } from '../index.js'
import { getRootDefault } from './McdocHelpers.js'
export const SHARE_KEY = 'share'
@@ -199,6 +200,23 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) {
return entries.map(e => e.startsWith('minecraft:') ? e.slice(10) : e)
}, [version, gen.id])
const getPresets = useCallback((search: string, close: () => void) => {
if (presets === undefined) {
return <span class="w-80 note">{locale('loading')}</span>
}
if (!presets || presets.length === 0) {
return <span class="w-80 note">{locale('presets.no_results')}</span>
}
const terms = search.trim().split(' ')
const results = presets?.filter(v => terms.every(t => v.includes(t))).slice(0, 100) ?? []
if (results.length === 0) {
return <span class="w-80 note">{locale('presets.no_results_for_query')}</span>
}
return results.map(r => <button class="w-80 flex items-center cursor-pointer no-underline rounded p-1" onClick={() => {selectPreset(r); close()}}>
{r}
</button>)
}, [presets])
const selectPreset = (id: string) => {
Analytics.loadPreset(gen.id, id)
setSharedSnippetId(undefined, true)
@@ -372,9 +390,9 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) {
{Octicon.mortar_board}
<span>{locale('wiki')}</span>
</a>}
<BtnMenu icon="archive" label={locale('presets')} relative={false}>
<SearchList searchPlaceholder={locale('search')} noResults={locale('no_presets')} values={presets} onSelect={selectPreset}/>
</BtnMenu>
<FancyMenu placeholder={locale('search')} getResults={getPresets} relative={false} class="right-0 mt-2">
<Btn icon="archive" label={locale('presets')} />
</FancyMenu>
<VersionSwitcher value={version} onChange={selectVersion} allowed={allowedVersions} />
<BtnMenu icon="kebab_horizontal" tooltip={locale('more')}>
<Btn icon="history" label={locale('reset_default')} onClick={reset} />

View File

@@ -184,7 +184,6 @@
"move_down": "Move down",
"move_up": "Move up",
"no_file_chosen": "No file chosen",
"no_presets": "No presets",
"normalize": "Normalize",
"not_found.description": "The page you were looking for does not exist.",
"output_settings": "Output settings",
@@ -196,6 +195,8 @@
"partner.ohthetreesyoullgrow": "Oh The Trees You'll Grow",
"partner.sky_aesthetics": "Sky Aesthetics",
"presets": "Presets",
"presets.no_results": "No presets",
"presets.no_results_for_query": "No presets for this query",
"preview": "Visualize",
"preview.auto_scroll": "Auto scroll",
"preview.biome": "Biome",

View File

@@ -226,6 +226,7 @@ nav li .btn svg {
}
.fancy-menu {
max-width: calc(100vw - 32px);
background-color: var(--background-2);
color: var(--text-2);
}
@@ -234,11 +235,11 @@ nav li .btn svg {
background-color: var(--background-1);
}
.gen-result {
.fancy-menu-results > * {
outline-offset: -2px;
}
.gen-result svg {
.fancy-menu-results > * svg {
width: 16px;
height: 16px;
fill: var(--nav);
@@ -247,13 +248,13 @@ nav li .btn svg {
transition: margin 0.2s;
}
.gen-result:focus-visible,
.gen-result:hover {
.fancy-menu-results > *:focus-visible,
.fancy-menu-results > *:hover {
background-color: var(--background-3);
}
.gen-result:focus-visible svg,
.gen-result:hover svg {
.fancy-menu-results > *:focus-visible svg,
.fancy-menu-results > *:hover svg {
margin-left: 14px;
margin-right: 0px;
}