Improve homepage (#245)

* Improve how generators are listed on home

* Add some icons for generators

* Remove debug

* Refactor cachedFetch and use generated changelogs

* Add limit to how many changes are shown by default

* Add more generator icons

* Refactor cards

* Fix generator icons for light theme

* Add more worldgen icons

* Add remaining generator icons

* Refactor navigation and badges style

* Group on homepage for guides and tools

* Fix header button style

* Add versions and technical changelog to homepage

* Make it clear that not all changes could be documented
This commit is contained in:
Misode
2022-07-01 23:48:38 +02:00
committed by GitHub
parent 29031bb375
commit d0bae089d1
40 changed files with 791 additions and 460 deletions

View File

@@ -1,21 +0,0 @@
import { Footer, ToolCard } from '../components/index.js'
import config from '../Config.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { cleanUrl } from '../Utils.js'
interface Props {
category: string,
path?: string,
}
export function Category({ category }: Props) {
const { locale } = useLocale()
useTitle(locale('title.generator_category', locale(category)))
return <main>
<div class="container">
{config.generators.filter(g => g.category === category).map(g =>
<ToolCard title={locale(g.id)} link={cleanUrl(g.url)} />
)}
</div>
<Footer donate={false} />
</main>
}

View File

@@ -1,7 +1,7 @@
import { Ad, ChangelogList, ErrorPanel, Footer } from '../components/index.js'
import { BtnLink, ChangelogList, ErrorPanel, Footer } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { useAsync } from '../hooks/index.js'
import { getChangelogs } from '../services/index.js'
import { fetchChangelogs } from '../services/index.js'
interface Props {
path?: string,
@@ -10,13 +10,14 @@ export function Changelog({}: Props) {
const { locale } = useLocale()
useTitle(locale('title.changelog'))
const { value: changelogs, error } = useAsync(getChangelogs, [])
const { value: changes, error } = useAsync(fetchChangelogs, [])
return <main>
<Ad type="text" id="changelog" />
{error && <ErrorPanel error={error} />}
<div class="container changelog">
<ChangelogList changes={changelogs} defaultOrder="desc" />
<ChangelogList changes={changes} defaultOrder="desc" limit={100} navigation={(
<BtnLink link="/versions/" icon="three_bars" label={locale('versions.all')} />
)} />
</div>
<Footer />
</main>

View File

@@ -49,6 +49,8 @@ export function Generator({}: Props) {
setError(`This generator is not available in versions above ${gen.maxVersion}`)
}
useEffect(() => Store.visitGenerator(gen.id), [gen.id])
const [currentPreset, setCurrentPreset] = useSearchParam('preset')
const [sharedSnippetId, setSharedSnippetId] = useSearchParam(SHARE_KEY)
const ignoreChange = useRef(false)

View File

@@ -0,0 +1,17 @@
import { Footer, GeneratorList } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
interface Props {
path?: string
}
export function Generators({}: Props) {
const { locale } = useLocale()
useTitle(locale('title.generators'))
return <main>
<div class="container">
<GeneratorList predicate={gen => !gen.partner} />
</div>
<Footer />
</main>
}

View File

@@ -3,7 +3,7 @@ import json from 'highlight.js/lib/languages/json'
import { marked } from 'marked'
import { route } from 'preact-router'
import { useCallback, useEffect, useMemo, useState } from 'preact/hooks'
import { Ad, Btn, ChangelogTag, Footer, Giscus, Octicon, VersionSwitcher } from '../components/index.js'
import { Ad, Badge, Btn, Footer, Giscus, Icons, Octicon, VersionSwitcher } from '../components/index.js'
import config from '../Config.js'
import { useLocale, useTitle, useVersion } from '../contexts/index.js'
import { useActiveTimeout, useAsync, useHash } from '../hooks/index.js'
@@ -176,14 +176,19 @@ export function Guide({ id }: Props) {
<div class="navigation">
<a class="btn btn-link" href="/guides/">
{Octicon.arrow_left}
{locale('guides.all')}
<span>{locale('guides.all')}</span>
</a>
<a class="btn btn-link" href="/worldgen/">
{Icons.worldgen}
<span>{locale('worldgen')}</span>
</a>
<div class="navigation-divider" />
<Btn icon={shareActive ? 'check' : 'link'} label={locale('share')} onClick={onShare} active={shareActive} tooltip={locale(shareActive ? 'copied' : 'copy_share')} class="guide-share" />
{allowedVersions && <VersionSwitcher value={guideVersion} allowed={allowedVersions} onChange={changeVersion} />}
</div>
{(frontMatter?.tags && frontMatter.tags.length > 0) && <div class="guide-tags">
{(frontMatter?.tags && frontMatter.tags.length > 0) && <div class="badges-list">
{frontMatter.tags.map((tag: string) =>
<ChangelogTag label={tag} active onClick={() => onClickTag(tag)} />
<Badge label={tag} active onClick={() => onClickTag(tag)} />
)}
</div>}
{html && <>

View File

@@ -1,16 +1,8 @@
import { useMemo, useState } from 'preact/hooks'
import { ChangelogTag, Footer, GuideCard, TextInput, VersionSwitcher } from '../components/index.js'
import { Badge, Footer, GuideCard, TextInput, VersionSwitcher } from '../components/index.js'
import { useLocale, useTitle, useVersion } from '../contexts/index.js'
import { useTags } from '../hooks/index.js'
interface Guide {
id: string,
title: string,
versions?: string[],
tags?: string[],
}
declare var __GUIDES__: Guide[]
import { getGuides } from '../services/Guides.js'
interface Props {
path?: string
@@ -26,8 +18,8 @@ export function Guides({}: Props) {
const [versionFilter, setVersionFiler] = useState(false)
const versionedGuides = useMemo(() => {
if (versionFilter === false) return __GUIDES__
return __GUIDES__.filter(guide => {
if (versionFilter === false) return getGuides()
return getGuides().filter(guide => {
return guide.versions?.includes(version)
})
}, [version, versionFilter])
@@ -49,21 +41,23 @@ export function Guides({}: Props) {
}, [versionedGuides, search, activeTags])
return <main>
<div class="container">
<div class="changelog-query">
<TextInput class="btn btn-input changelog-search" placeholder={locale('guides.search')} value={search} onChange={setSearch} />
<div class="container guides">
<div class="navigation">
<TextInput class="btn btn-input query-search" placeholder={locale('guides.search')} value={search} onChange={setSearch} />
<VersionSwitcher value={versionFilter ? version : undefined} onChange={v => {changeVersion(v); setVersionFiler(true)}} hasAny onAny={() => setVersionFiler(false)} />
</div>
{activeTags.length > 0 && <div class="changelog-tags">
{activeTags.map(tag => <ChangelogTag label={tag} onClick={() => toggleTag(tag)} />)}
{activeTags.length > 0 && <div class="badges-list">
{activeTags.map(tag => <Badge label={tag} onClick={() => toggleTag(tag)} />)}
</div>}
{versionedGuides.length === 0 ? <>
<span class="note">{locale('guides.no_results.version')}</span>
</> : filteredGuides.length === 0 ? <>
<span class="note">{locale('guides.no_results.query')}</span>
</> : filteredGuides.map(g =>
<GuideCard title={g.title} link={`/guides/${g.id}/`} tags={g.tags ?? []} versions={g.versions ?? []} activeTags={activeTags} toggleTag={toggleTag} />
)}
<div class="result-list">
{versionedGuides.length === 0 ? <>
<span class="note">{locale('guides.no_results.version')}</span>
</> : filteredGuides.length === 0 ? <>
<span class="note">{locale('guides.no_results.query')}</span>
</> : filteredGuides.map(g =>
<GuideCard id={g.id} activeTags={activeTags} toggleTag={toggleTag} />
)}
</div>
</div>
<Footer />
</main>

View File

@@ -1,7 +1,12 @@
import { Footer, Giscus, ToolCard } from '../components/index.js'
import config from '../Config.js'
import { useMemo } from 'preact/hooks'
import { ChangelogEntry, Footer, GeneratorCard, Giscus, GuideCard, ToolCard, ToolGroup } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { cleanUrl } from '../Utils.js'
import { useAsync } from '../hooks/useAsync.js'
import { fetchChangelogs, fetchVersions } from '../services/DataFetcher.js'
import { Store } from '../Store.js'
const MIN_FAVORITES = 2
const MAX_FAVORITES = 5
interface Props {
path?: string,
@@ -9,33 +14,63 @@ interface Props {
export function Home({}: Props) {
const { locale } = useLocale()
useTitle(locale('title.home'))
const favorites = useMemo(() => {
const history: string[] = []
for (const id of Store.getGeneratorHistory().reverse()) {
if (!history.includes(id)) {
history.push(id)
}
}
return history.slice(0, MAX_FAVORITES)
}, [])
const { value: versions } = useAsync(fetchVersions, [])
const release = useMemo(() => versions?.find(v => v.type === 'release'), [versions])
const { value: changes } = useAsync(fetchChangelogs, [])
const latestChanges = useMemo(() => changes?.sort((a, b) => b.order - a.order).slice(0, 2), [changes])
return <main>
<div class="container home">
<ToolCard title="Data packs">
{config.generators.filter(g => !g.category).map(g =>
<ToolCard title={locale(g.id)} link={cleanUrl(g.url)} />
)}
<ToolCard title={locale('tags')} link="/tags/" />
<ToolCard title={locale('worldgen')} link="/worldgen/" />
</ToolCard>
<ToolCard title="Resource packs">
{config.generators.filter(g => g.category === 'assets').map(g =>
<ToolCard title={locale(g.id)} link={cleanUrl(g.url)} />
)}
</ToolCard>
<ToolCard title="Partners" link="/partners/" />
<ToolCard title="Report Inspector" icon="report"
link="https://misode.github.io/report/"
desc="Analyse your performance reports" />
<ToolCard title="Minecraft Sounds" icon="sounds"
link="/sounds/"
desc="Browse through and mix all the vanilla sounds" />
<ToolCard title="Data Pack Upgrader"
link="https://misode.github.io/upgrader/"
desc="Convert your data packs from 1.16 to 1.17 to 1.18" />
<ToolCard title="Technical Changelog" link="/changelog/" />
<ToolCard title="Minecraft Versions" link="/versions/" />
<ToolCard title="Data Pack Guides" link="/guides/" />
<div class="container">
<div class="card-group">
<ToolGroup title={locale('generators.popular')} link="/generators/">
<GeneratorCard minimal id="loot_table" />
<GeneratorCard minimal id="advancement" />
<GeneratorCard minimal id="predicate" />
<ToolCard title={locale('worldgen')} link="/worldgen/" titleIcon="worldgen" />
<ToolCard title={locale('generators.all')} link="/generators/" titleIcon="arrow_right" />
</ToolGroup>
{favorites.length >= MIN_FAVORITES && <ToolGroup title={locale('generators.recent')}>
{favorites.map(f => <GeneratorCard minimal id={f} />)}
</ToolGroup>}
<ToolGroup title={locale('guides')} link="/guides/" titleIcon="arrow_right">
<GuideCard id="adding-custom-structures" />
<GuideCard id="noise-router" />
</ToolGroup>
<ToolGroup title={locale('tools')}>
<ToolCard title="Report Inspector" icon="report"
link="https://misode.github.io/report/"
desc="Analyse your performance reports" />
<ToolCard title="Minecraft Sounds" icon="sounds"
link="/sounds/"
desc="Browse through and mix all the vanilla sounds" />
<ToolCard title="Data Pack Upgrader"
link="https://misode.github.io/upgrader/"
desc="Convert your data packs from 1.16 to 1.19" />
</ToolGroup>
<ToolGroup title={locale('versions.minecraft_versions')} link="/versions/" titleIcon="arrow_right">
{(versions?.[0] && release) && <>
{versions[0].id !== release.id && (
<ToolCard title={versions[0].name} link={`/versions/?id=${versions[0].id}`} desc={locale('versions.latest_snapshot')} />
)}
<ToolCard title={release.name} link={`/versions/?id=${release.id}`} desc={locale('versions.latest_release')} />
</>}
</ToolGroup>
<ToolGroup title={locale('changelog')} link="/changelog/" titleIcon="git_commit">
{latestChanges?.map(change => <ChangelogEntry change={change} />)}
</ToolGroup>
</div>
<Giscus />
<Footer />
</div>

View File

@@ -1,15 +1,8 @@
import { Footer, ToolCard } from '../components/index.js'
import config from '../Config.js'
import { Footer, GeneratorList } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { cleanUrl } from '../Utils.js'
const partners = [...new Set(config.generators
.filter(g => g.partner !== undefined)
.map(g => g.partner as string)
)]
interface Props {
path?: string,
path?: string
}
export function Partners({}: Props) {
const { locale } = useLocale()
@@ -17,11 +10,7 @@ export function Partners({}: Props) {
return <main>
<div class="container">
{partners.map(p => <ToolCard title={locale(`partner.${p}`)}>
{config.generators.filter(g => g.partner === p).map(g =>
<ToolCard title={locale(`partner.${p}.${g.id}`)} link={cleanUrl(g.url)} />
)}
</ToolCard>)}
<GeneratorList predicate={gen => gen.partner !== undefined} />
</div>
<Footer donate={false} />
</main>

View File

@@ -1,4 +1,4 @@
import { Ad, BtnLink, ErrorPanel, Footer, VersionDetail, VersionList } from '../components/index.js'
import { BtnLink, ErrorPanel, Footer, VersionDetail, VersionList } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { useAsync, useSearchParam } from '../hooks/index.js'
import type { VersionMeta } from '../services/index.js'
@@ -9,7 +9,6 @@ interface Props {
}
export function Versions({}: Props) {
const { locale } = useLocale()
useTitle(locale('title.versions'))
const { value: versions, error } = useAsync(fetchVersions, [])
@@ -25,7 +24,6 @@ export function Versions({}: Props) {
const previousVersion = selected && getOffsetVersion(versions ?? [], selected, 1)
return <main>
<Ad type="text" id="versions" />
{error && <ErrorPanel error={error} />}
<div class="container">
{selectedId ? <>
@@ -37,7 +35,11 @@ export function Versions({}: Props) {
icon="arrow_right" label={locale('versions.next')} swapped />
</div>
<VersionDetail id={selectedId} version={selected} />
</> : <VersionList versions={versions ?? []} link={id => `/versions/?id=${id}`} />}
</> : <>
<VersionList versions={versions} link={id => `/versions/?id=${id}`} navigation={(
<BtnLink link="/changelog" icon="git_commit" label={locale('versions.technical_changes')} />
)} />
</>}
</div>
<Footer donate={false} />
</main>

View File

@@ -0,0 +1,30 @@
import { Footer, GeneratorCard, GeneratorList, GuideCard, ToolGroup } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
interface Props {
path?: string
}
export function Worldgen({}: Props) {
const { locale } = useLocale()
useTitle(locale('title.worldgen'))
return <main>
<div class="container worldgen">
<div class="card-group">
<ToolGroup title={locale('popular_generators')}>
<GeneratorCard minimal id="dimension" />
<GeneratorCard minimal id="worldgen/biome" />
<GeneratorCard minimal id="worldgen/noise_settings" />
<GeneratorCard minimal id="worldgen/configured_feature" />
<GeneratorCard minimal id="worldgen/placed_feature" />
</ToolGroup>
<ToolGroup title={locale('guides')} link="/guides/?tags=worldgen" titleIcon="arrow_right">
<GuideCard id="adding-custom-structures" />
<GuideCard id="placed-features" />
</ToolGroup>
</div>
<GeneratorList predicate={gen => gen.tags?.includes('worldgen')} />
</div>
<Footer />
</main>
}

View File

@@ -1,9 +1,10 @@
export * from './Category.js'
export * from './Changelog.js'
export * from './Generator.js'
export * from './Generators.jsx'
export * from './Guide.js'
export * from './Guides.js'
export * from './Home.js'
export * from './Partners.js'
export * from './Sounds.js'
export * from './Versions.js'
export * from './Worldgen.jsx'