diff --git a/src/app/App.tsx b/src/app/App.tsx index 72093387..dcfb2a69 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -4,7 +4,7 @@ import '../styles/global.css' import '../styles/nodes.css' import { Analytics } from './Analytics.js' import { Header } from './components/index.js' -import { Category, Changelog, Generator, Guide, Guides, Home, Partners, Sounds, Versions } from './pages/index.js' +import { Changelog, Generator, Generators, Guide, Guides, Home, Partners, Sounds, Versions, Worldgen } from './pages/index.js' import { cleanUrl } from './Utils.js' export function App() { @@ -18,14 +18,13 @@ export function App() {
- - - + + - + diff --git a/src/app/Config.ts b/src/app/Config.ts index 7816ba4c..cfc60d8f 100644 --- a/src/app/Config.ts +++ b/src/app/Config.ts @@ -1,27 +1,34 @@ import config from '../config.json' -interface Config { - languages: Array<{ - code: string, - name: string, - schemas?: boolean, - }>, - versions: Array<{ - id: string, - pack_format: number, - ref?: string, - dynamic?: boolean, - }>, - generators: Array<{ - id: string, - url: string, - schema: string, - path?: string, - category?: string, - partner?: string, - minVersion?: string, - maxVersion?: string, - }>, +export interface ConfigLanguage { + code: string, + name: string, + schemas?: boolean, +} + +export interface ConfigVersion { + id: string, + pack_format: number, + ref?: string, + dynamic?: boolean, +} + +export interface ConfigGenerator { + id: string, + url: string, + schema: string, + path?: string, + noPath?: boolean, + tags?: string[], + partner?: string, + minVersion?: string, + maxVersion?: string, +} + +export interface Config { + languages: ConfigLanguage[], + versions: ConfigVersion[], + generators: ConfigGenerator[], } export default config as Config diff --git a/src/app/Store.ts b/src/app/Store.ts index aa69b1e7..975abc2b 100644 --- a/src/app/Store.ts +++ b/src/app/Store.ts @@ -16,6 +16,7 @@ export namespace Store { export const ID_PROJECT_PANEL_OPEN = 'misode_project_panel_open' export const ID_OPEN_PROJECT = 'misode_open_project' export const ID_TREE_VIEW_MODE = 'misode_tree_view_mode' + export const ID_GENERATOR_HISTORY = 'misode_generator_history' export function getLanguage() { return localStorage.getItem(ID_LANGUAGE) ?? 'en' @@ -84,6 +85,10 @@ export namespace Store { return localStorage.getItem(ID_TREE_VIEW_MODE) ?? 'resources' } + export function getGeneratorHistory(): string[] { + return JSON.parse(localStorage.getItem(ID_GENERATOR_HISTORY) ?? '[]') + } + export function setLanguage(language: string | undefined) { if (language) localStorage.setItem(ID_LANGUAGE, language) } @@ -145,4 +150,10 @@ export namespace Store { export function setTreeViewMode(mode: string | undefined) { if (mode) localStorage.setItem(ID_TREE_VIEW_MODE, mode) } + + export function visitGenerator(id: string) { + const history = getGeneratorHistory() + history.push(id) + localStorage.setItem(ID_GENERATOR_HISTORY, JSON.stringify(history.slice(-50))) + } } diff --git a/src/app/components/Badge.tsx b/src/app/components/Badge.tsx new file mode 100644 index 00000000..c70b1db4 --- /dev/null +++ b/src/app/components/Badge.tsx @@ -0,0 +1,15 @@ +import { hashString } from '../Utils.js' +import { Octicon } from './index.js' + +interface Props { + label: string, + active?: boolean, + onClick?: (e: MouseEvent) => unknown, +} +export function Badge({ label, active, onClick }: Props) { + const color = label === 'breaking' ? 5 : hashString(label) % 360 + return
+ {label === 'breaking' && Octicon.alert} + {label} +
+} diff --git a/src/app/components/Card.tsx b/src/app/components/Card.tsx new file mode 100644 index 00000000..13ffc4ac --- /dev/null +++ b/src/app/components/Card.tsx @@ -0,0 +1,21 @@ +import type { ComponentChildren } from 'preact' + +interface Props { + title?: ComponentChildren, + link?: string, + overlay?: ComponentChildren, + children?: ComponentChildren, +} +export function Card({ title, overlay, link, children }: Props) { + const content = <> + {overlay && {overlay}} +
+ {title &&

{title}

} + {children} +
+ + + return link === undefined + ?
{content}
+ : {content} +} diff --git a/src/app/components/GuideCard.tsx b/src/app/components/GuideCard.tsx index ac9e13f8..4eaf0010 100644 --- a/src/app/components/GuideCard.tsx +++ b/src/app/components/GuideCard.tsx @@ -1,25 +1,25 @@ -import { ChangelogTag } from './index.js' +import { useMemo } from 'preact/hooks' +import { getGuide } from '../services/Guides.js' +import { Card } from './Card.jsx' +import { Badge } from './index.js' interface Props { - title: string, - link: string, - versions: string[], - tags: string[], + id: string, activeTags?: string[], toggleTag?: (tag: string) => unknown, } -export function GuideCard({ title, link, versions, tags, activeTags, toggleTag }: Props) { +export function GuideCard({ id, activeTags, toggleTag }: Props) { + const { title, versions, tags } = useMemo(() => getGuide(id), [id]) + const onToggleTag = (tag: string) => (e: MouseEvent) => { if (toggleTag) toggleTag(tag) e.preventDefault() e.stopImmediatePropagation() } - return - {versions.join(' • ')} -

{title}

-
- {tags.sort().map(tag => )} + return +
+ {tags?.sort().map(tag => )}
-
+ } diff --git a/src/app/components/Header.tsx b/src/app/components/Header.tsx index a325f6f7..fa395515 100644 --- a/src/app/components/Header.tsx +++ b/src/app/components/Header.tsx @@ -26,7 +26,7 @@ export function Header() {

{title}

{gen && {config.generators - .filter(g => g.category === gen?.category && checkVersion(version, g.minVersion)) + .filter(g => g.tags?.[0] === gen?.tags?.[0] && checkVersion(version, g.minVersion)) .map(g => route(cleanUrl(g.url))} /> )} diff --git a/src/app/components/Icons.tsx b/src/app/components/Icons.tsx index eecc5478..23cdfa96 100644 --- a/src/app/components/Icons.tsx +++ b/src/app/components/Icons.tsx @@ -1,5 +1,43 @@ +const TAG = +const STRUCTURE = + export const Icons = { home: , report: , sounds: , + advancement: , + block_definition: , + chat_type: , + dimension: , + dimension_type: , + item_modifier: , + loot_table: , + model: , + pack_mcmeta: , + predicate: , + recipe: , + 'tag/block': TAG, + 'tag/entity_type': TAG, + 'tag/fluid': TAG, + 'tag/game_event': TAG, + 'tag/item': TAG, + 'tag/worldgen/biome': TAG, + text_component: , + world: , + worldgen: , + 'worldgen/biome': , + 'worldgen/configured_carver': , + 'worldgen/configured_feature': , + 'worldgen/configured_structure_feature': STRUCTURE, + 'worldgen/configured_surface_builder': , + 'worldgen/density_function': , + 'worldgen/flat_level_generator_preset': , + 'worldgen/noise': , + 'worldgen/noise_settings': , + 'worldgen/placed_feature': , + 'worldgen/processor_list': , + 'worldgen/structure': STRUCTURE, + 'worldgen/structure_set': , + 'worldgen/template_pool': , + 'worldgen/world_preset': , } diff --git a/src/app/components/Octicon.tsx b/src/app/components/Octicon.tsx index 123b35f1..df0918f9 100644 --- a/src/app/components/Octicon.tsx +++ b/src/app/components/Octicon.tsx @@ -22,6 +22,7 @@ export const Octicon = { file_directory: , file_zip: , gear: , + git_commit: , globe: , heart: , history: , diff --git a/src/app/components/ToolCard.tsx b/src/app/components/ToolCard.tsx index 7e16869c..6b246470 100644 --- a/src/app/components/ToolCard.tsx +++ b/src/app/components/ToolCard.tsx @@ -1,27 +1,32 @@ -import type { ComponentChildren } from 'preact' import { Icons } from './Icons.js' +import { Octicon } from './Octicon.jsx' -type ToolCardProps = { +interface Props { title: string, - desc?: string, - link?: string, + titleIcon?: keyof typeof Octicon | keyof typeof Icons, + link: string, icon?: keyof typeof Icons, - children?: ComponentChildren, + desc?: string, } -export function ToolCard({ title, desc, link, icon, children }: ToolCardProps) { - const content = <> -
+export function ToolCard({ title, desc, link, icon, titleIcon }: Props) { + if (icon || desc) { + return {icon && Icons[icon]}
-

{title}

+

{desc}

-
- {children &&
- {children} -
} - - return link - ?
{content} - :
{content}
+ + } + + return + + +} + +function ToolHead({ title, titleIcon }: Pick) { + return

+ {title} + {titleIcon && (titleIcon in Octicon ? (Octicon as any)[titleIcon] : (Icons as any)[titleIcon])} +

} diff --git a/src/app/components/ToolGroup.tsx b/src/app/components/ToolGroup.tsx new file mode 100644 index 00000000..051e5ca1 --- /dev/null +++ b/src/app/components/ToolGroup.tsx @@ -0,0 +1,22 @@ +import type { ComponentChildren } from 'preact' +import type { Icons } from './Icons.jsx' +import type { Octicon } from './Octicon.jsx' +import { ToolCard } from './ToolCard.jsx' + +interface Props { + title: string, + titleIcon?: keyof typeof Octicon | keyof typeof Icons, + link?: string, + children?: ComponentChildren, +} +export function ToolGroup({ title, titleIcon, link, children }: Props) { + return
+ {link === undefined + ?

{title}

+ : + } + {children &&
+ {children} +
} +
+} diff --git a/src/app/components/generator/GeneratorCard.tsx b/src/app/components/generator/GeneratorCard.tsx new file mode 100644 index 00000000..5c113133 --- /dev/null +++ b/src/app/components/generator/GeneratorCard.tsx @@ -0,0 +1,51 @@ +import { useMemo } from 'preact/hooks' +import type { ConfigGenerator } from '../../Config.js' +import config from '../../Config.js' +import { useLocale } from '../../contexts/Locale.jsx' +import type { VersionId } from '../../services/Schemas.js' +import { checkVersion } from '../../services/Schemas.js' +import { cleanUrl } from '../../Utils.js' +import { Badge, Card, Icons, ToolCard } from '../index.js' + +interface Props { + id: string, + minimal?: boolean, +} +export function GeneratorCard({ id, minimal }: Props) { + const { locale } = useLocale() + + const gen = useMemo(() => { + const gen = config.generators.find(g => g.id === id) + if (gen === undefined) { + return { id, schema: id, url: id } + } + return gen + }, [id]) + + const title = locale(gen.partner ? `partner.${gen.partner}.${gen.id}` : gen.id) + + const icon = Object.keys(Icons).includes(id) ? id as keyof typeof Icons : undefined + + if (minimal) { + return + } + + const versions = useMemo(() => { + if (!gen) return [] + return config.versions + .filter(v => checkVersion(v.id, gen.minVersion, gen.maxVersion)) + .map(v => v.id as VersionId) + }, [gen]) + + const tags = useMemo(() => { + if (gen.tags?.includes('assets')) return ['resource-pack'] + return [] + }, [gen]) + + return {title}{icon && Icons[icon]}} overlay={gen.partner ? locale(`partner.${gen.partner}`) : versions.join(' • ')} link={cleanUrl(gen.url)}> + {!gen.noPath &&

/{gen.path ?? gen.id}

} + {tags.length > 0 &&
+ {tags.sort().map(tag => )} +
} +
+} diff --git a/src/app/components/generator/GeneratorList.tsx b/src/app/components/generator/GeneratorList.tsx new file mode 100644 index 00000000..bad4a48f --- /dev/null +++ b/src/app/components/generator/GeneratorList.tsx @@ -0,0 +1,54 @@ +import { useMemo, useState } from 'preact/hooks' +import type { ConfigGenerator } from '../../Config.js' +import config from '../../Config.js' +import { useLocale, useVersion } from '../../contexts/index.js' +import { checkVersion } from '../../services/Schemas.js' +import { GeneratorCard, TextInput, VersionSwitcher } from '../index.js' + +interface Props { + path?: string, + predicate?: (gen: ConfigGenerator) => boolean | undefined, +} +export function GeneratorList({ predicate }: Props) { + const { locale } = useLocale() + const { version, changeVersion } = useVersion() + + const [search, setSearch] = useState('') + + const [versionFilter, setVersionFiler] = useState(true) + + const versionedGenerators = useMemo(() => { + return config.generators.filter(gen => { + if (predicate === undefined || !predicate(gen)) return false + if (versionFilter === false) return true + return checkVersion(version, gen.minVersion, gen.maxVersion) + }) + }, [version, versionFilter]) + + const filteredGenerators = useMemo(() => { + const query = search.split(' ').map(q => q.trim().toLowerCase()).filter(q => q.length > 0) + return versionedGenerators.filter(gen => { + const content = `${gen.id} ${gen.tags?.join(' ') ?? ''} ${gen.path ?? ''} ${gen.partner ?? ''} ${locale(gen.id).toLowerCase()}` + return query.every(q => { + if (q.startsWith('!')) { + return q.length === 1 || !content.includes(q.slice(1)) + } + return content.includes(q) + }) + }) + }, [versionedGenerators, search, locale]) + + return
+ + {filteredGenerators.length === 0 ? <> + {locale('generators.no_results')} + :
+ {filteredGenerators.map(gen => + + )} +
} +
+} diff --git a/src/app/components/generator/index.ts b/src/app/components/generator/index.ts index bba18e8a..5587369e 100644 --- a/src/app/components/generator/index.ts +++ b/src/app/components/generator/index.ts @@ -1,5 +1,7 @@ export * from './FileCreation.js' export * from './FileRenaming.js' +export * from './GeneratorCard.jsx' +export * from './GeneratorList.jsx' export * from './PreviewPanel.js' export * from './ProjectCreation.js' export * from './ProjectDeletion.js' diff --git a/src/app/components/index.ts b/src/app/components/index.ts index b4e499ab..b202bd81 100644 --- a/src/app/components/index.ts +++ b/src/app/components/index.ts @@ -3,13 +3,14 @@ export * from './Btn.js' export * from './BtnInput.js' export * from './BtnLink.js' export * from './BtnMenu.js' +export * from './Card.jsx' export * from './ErrorPanel.js' export * from './FileUpload.js' export * from './Footer.js' export * from './forms/index.js' export * from './generator/index.js' export * from './Giscus.js' -export * from './GuideCard.js' +export * from './GuideCard.jsx' export * from './Header.js' export * from './Icons.js' export * from './Modal.js' @@ -17,6 +18,7 @@ export * from './Octicon.js' export * from './previews/index.js' export * from './sounds/index.js' export * from './ToolCard.js' +export * from './ToolGroup.jsx' export * from './TreeView.js' export * from './versions/index.js' export * from './VersionSwitcher.js' diff --git a/src/app/components/versions/ChangelogEntry.tsx b/src/app/components/versions/ChangelogEntry.tsx index c02d4808..5537b801 100644 --- a/src/app/components/versions/ChangelogEntry.tsx +++ b/src/app/components/versions/ChangelogEntry.tsx @@ -1,6 +1,7 @@ import { marked } from 'marked' import type { Change } from '../../services/index.js' -import { ChangelogTag } from './index.js' +import { Card } from '../Card.jsx' +import { Badge } from './index.js' type Props = { change: Change, @@ -8,14 +9,13 @@ type Props = { toggleTag?: (tag: string) => unknown, } export function ChangelogEntry({ change, activeTags, toggleTag }: Props) { - return
- -
- {change.tags.map(tag => toggleTag(tag) : undefined} active={activeTags?.includes(tag)} />)} + return + {change.version} + {change.group} + }> +
+ {change.tags.map(tag => toggleTag(tag) : undefined} active={activeTags?.includes(tag)} />)}
-
+
} diff --git a/src/app/components/versions/ChangelogList.tsx b/src/app/components/versions/ChangelogList.tsx index 43d43599..83cf7248 100644 --- a/src/app/components/versions/ChangelogList.tsx +++ b/src/app/components/versions/ChangelogList.tsx @@ -1,18 +1,21 @@ +import type { ComponentChildren } from 'preact' import { useMemo, useState } from 'preact/hooks' import { useLocale } from '../../contexts/index.js' import { useSearchParam, useTags } from '../../hooks/index.js' import type { Change } from '../../services/index.js' +import { Badge } from '../Badge.jsx' import { Btn, TextInput } from '../index.js' import { ChangelogEntry } from './ChangelogEntry.js' -import { ChangelogTag } from './ChangelogTag.js' const SEARCH_KEY = 'search' interface Props { changes: Change[] | undefined, defaultOrder: 'asc' | 'desc', + limit?: number, + navigation?: ComponentChildren, } -export function ChangelogList({ changes, defaultOrder }: Props) { +export function ChangelogList({ changes, defaultOrder, limit, navigation }: Props) { const { locale } = useLocale() const [search, setSearch] = useSearchParam(SEARCH_KEY) @@ -25,7 +28,7 @@ export function ChangelogList({ changes, defaultOrder }: Props) { if (!tags.every(tag => change.tags.includes(tag))) { return false } - const content = change.tags.join(' ') + ' ' + change.content.toLowerCase() + const content = `${change.group} ${change.version} ${change.tags.join(' ')} ${change.content.toLowerCase()}` return query.every(q => { if (q.startsWith('!')) { return q.length === 1 || !content.includes(q.slice(1)) @@ -41,22 +44,35 @@ export function ChangelogList({ changes, defaultOrder }: Props) { return filteredChangelogs?.sort((a, b) => sort ? b.order - a.order : a.order - b.order) }, [filteredChangelogs, sort]) + const [limitActive, setLimitActive] = useState(true) + + const limitedChangelogs = useMemo(() => { + if (!limitActive || (limit ?? -1) < 0) return sortedChangelogs + return sortedChangelogs?.slice(0, limit) + }, [sortedChangelogs, limitActive, limit, sort /* why is this necessary??? */]) + + const hiddenChanges = (sortedChangelogs?.length ?? 0) - (limitedChangelogs?.length ?? 0) + return <> -
- + {navigation} + setSearch(v, true)} /> setSort(!sort)} />
- {tags.length > 0 &&
- {tags.map(tag => toggleTag(tag)} />)} + {tags.length > 0 &&
+ {tags.map(tag => toggleTag(tag)} />)}
} -
- {sortedChangelogs === undefined +
+ {limitedChangelogs === undefined ? {locale('loading')} - : sortedChangelogs.length === 0 + : limitedChangelogs.length === 0 ? {locale('changelog.no_results')} - : sortedChangelogs.map(change => + : limitedChangelogs.map(change => )} + {hiddenChanges > 0 && ( + setLimitActive(false)}/> + )}
} diff --git a/src/app/components/versions/ChangelogTag.tsx b/src/app/components/versions/ChangelogTag.tsx deleted file mode 100644 index cd2abfec..00000000 --- a/src/app/components/versions/ChangelogTag.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { hashString } from '../../Utils.js' -import { Octicon } from '../index.js' - -type TagProps = { - label: string, - active?: boolean, - onClick?: (e: MouseEvent) => unknown, -} -export function ChangelogTag({ label, active, onClick }: TagProps) { - const color = label === 'breaking' ? 5 : hashString(label) % 360 - return
- {label === 'breaking' && Octicon.alert} - {label} -
-} diff --git a/src/app/components/versions/VersionDetail.tsx b/src/app/components/versions/VersionDetail.tsx index d5c8496b..ce65412b 100644 --- a/src/app/components/versions/VersionDetail.tsx +++ b/src/app/components/versions/VersionDetail.tsx @@ -1,7 +1,8 @@ -import { useEffect, useMemo, useState } from 'preact/hooks' +import { useMemo, useState } from 'preact/hooks' import { useLocale } from '../../contexts/index.js' -import type { Change, VersionMeta } from '../../services/index.js' -import { getArticleLink, getChangelogs } from '../../services/index.js' +import { useAsync } from '../../hooks/useAsync.js' +import type { VersionMeta } from '../../services/index.js' +import { fetchChangelogs, getArticleLink } from '../../services/index.js' import { Giscus } from '../Giscus.js' import { Octicon } from '../Octicon.js' import { ChangelogList } from './ChangelogList.js' @@ -18,18 +19,11 @@ export function VersionDetail({ id, version }: Props) { const [tab, setTab] = useState('changelog') - const [changelogs, setChangelogs] = useState(undefined) - useEffect(() => { - getChangelogs() - .then(changelogs => setChangelogs( - changelogs.map(c => ({ ...c, tags: c.tags.filter(t => t !== c.group) })) - )) - .catch(e => console.error(e)) - }, []) + const { value: changes } = useAsync(fetchChangelogs, []) const filteredChangelogs = useMemo(() => - changelogs?.filter(c => c.version === id || c.group === id), - [id, changelogs]) + changes?.filter(c => c.version === id || c.group === id), + [id, changes]) const articleLink = version && getArticleLink(version.id) diff --git a/src/app/components/versions/VersionList.tsx b/src/app/components/versions/VersionList.tsx index fd81425f..a4ab898f 100644 --- a/src/app/components/versions/VersionList.tsx +++ b/src/app/components/versions/VersionList.tsx @@ -1,39 +1,43 @@ -import { useMemo, useState } from 'preact/hooks' +import type { ComponentChildren } from 'preact' +import { useMemo } from 'preact/hooks' import { useLocale } from '../../contexts/index.js' -import { useSearchParam } from '../../hooks/index.js' +import { useLocalStorage, useSearchParam } from '../../hooks/index.js' import type { VersionMeta } from '../../services/index.js' import { Checkbox, TextInput } from '../index.js' import { VersionEntry } from './VersionEntry.js' +const INCLUDE_SNAPSHOTS = 'misode_include_snapshots' const SEARCH_KEY = 'search' interface Props { - versions: VersionMeta[] - link?: (id: string) => string + versions?: VersionMeta[], + link?: (id: string) => string, + navigation?: ComponentChildren, } -export function VersionList({ versions, link }: Props) { +export function VersionList({ versions, link, navigation }: Props) { const { locale } = useLocale() - const [snapshots, setSnapshots] = useState(true) + const [snapshots, setSnapshots] = useLocalStorage(INCLUDE_SNAPSHOTS, true, v => v === 'true', b => `${b}`) const [search, setSearch] = useSearchParam(SEARCH_KEY) - const filteredVersions = useMemo(() => versions.filter(v => { + const filteredVersions = useMemo(() => versions?.filter(v => { if (v.type === 'snapshot' && !snapshots) return false return v.id.includes(search ?? '') }), [versions, snapshots, search]) - return <> -
- + {navigation} +
- {filteredVersions.map(v => )} - {filteredVersions.length === 0 && - {locale('versions.no_results')} - } + {filteredVersions === undefined + ? {locale('loading')} + : filteredVersions.length === 0 + ? {locale('versions.no_results')} + : filteredVersions.map(v => )}
} diff --git a/src/app/components/versions/index.ts b/src/app/components/versions/index.ts index 6735f6b3..22b66a7f 100644 --- a/src/app/components/versions/index.ts +++ b/src/app/components/versions/index.ts @@ -1,6 +1,6 @@ +export * from '../Badge.jsx' export * from './ChangelogEntry.js' export * from './ChangelogList.js' -export * from './ChangelogTag.js' export * from './VersionDetail.js' export * from './VersionEntry.js' export * from './VersionList.js' diff --git a/src/app/hooks/useLocalStorage.ts b/src/app/hooks/useLocalStorage.ts index de60b5d1..b66fb81c 100644 --- a/src/app/hooks/useLocalStorage.ts +++ b/src/app/hooks/useLocalStorage.ts @@ -2,7 +2,7 @@ import { useCallback, useState } from 'preact/hooks' type Result = [T, (value: T | null | undefined) => void] -export function useLocalStorage(key: string, defaultValue: T): Result +export function useLocalStorage(key: string, defaultValue: string): Result export function useLocalStorage(key: string, defaultValue: T, parse: (s: string) => T, stringify: (e: T) => string): Result export function useLocalStorage(key: string, defaultValue: T, parse?: (s: string) => T, stringify?: (e: T) => string): Result { const getter = useCallback(() => { diff --git a/src/app/pages/Category.tsx b/src/app/pages/Category.tsx deleted file mode 100644 index b4d38c60..00000000 --- a/src/app/pages/Category.tsx +++ /dev/null @@ -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
-
- {config.generators.filter(g => g.category === category).map(g => - - )} -
-
-
-} diff --git a/src/app/pages/Changelog.tsx b/src/app/pages/Changelog.tsx index 9b21d069..a74c4cac 100644 --- a/src/app/pages/Changelog.tsx +++ b/src/app/pages/Changelog.tsx @@ -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
- {error && }
- + + )} />
diff --git a/src/app/pages/Generator.tsx b/src/app/pages/Generator.tsx index eaec9c98..36402a28 100644 --- a/src/app/pages/Generator.tsx +++ b/src/app/pages/Generator.tsx @@ -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) diff --git a/src/app/pages/Generators.tsx b/src/app/pages/Generators.tsx new file mode 100644 index 00000000..9cf6598d --- /dev/null +++ b/src/app/pages/Generators.tsx @@ -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
+
+ !gen.partner} /> +
+
+
+} diff --git a/src/app/pages/Guide.tsx b/src/app/pages/Guide.tsx index 991bcbd7..1c01b77e 100644 --- a/src/app/pages/Guide.tsx +++ b/src/app/pages/Guide.tsx @@ -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) {