mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-24 07:37:10 +00:00
Add skeleton loading indicators
This commit is contained in:
37
src/app/components/generator/FileView.tsx
Normal file
37
src/app/components/generator/FileView.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { DocAndNode } from '@spyglassmc/core'
|
||||
import { JsonFileNode } from '@spyglassmc/json'
|
||||
import { useErrorBoundary } from 'preact/hooks'
|
||||
import { useDocAndNode, useSpyglass } from '../../contexts/Spyglass.jsx'
|
||||
import { message } from '../../Utils.js'
|
||||
import { ErrorPanel } from '../ErrorPanel.jsx'
|
||||
import { JsonFileView } from './JsonFileView.jsx'
|
||||
|
||||
type FileViewProps = {
|
||||
docAndNode: DocAndNode | undefined,
|
||||
}
|
||||
export function FileView({ docAndNode: original }: FileViewProps) {
|
||||
const { serviceLoading } = useSpyglass()
|
||||
|
||||
const [error, errorRetry] = useErrorBoundary()
|
||||
if (error) {
|
||||
return <ErrorPanel error={`Error viewing the file: ${message(error)}`} onDismiss={errorRetry} />
|
||||
}
|
||||
|
||||
const docAndNode = useDocAndNode(original)
|
||||
if (!docAndNode || serviceLoading) {
|
||||
return <div class="file-view flex flex-col gap-1">
|
||||
<div class="skeleton rounded-md h-[34px] w-[200px]"></div>
|
||||
<div class="skeleton rounded-md h-[34px] w-[240px]"></div>
|
||||
<div class="skeleton rounded-md h-[34px] w-[190px] ml-[18px]"></div>
|
||||
<div class="skeleton rounded-md h-[34px] w-[130px] ml-[18px]"></div>
|
||||
<div class="skeleton rounded-md h-[34px] w-[290px]"></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
const fileNode = docAndNode?.node.children[0]
|
||||
if (JsonFileNode.is(fileNode)) {
|
||||
return <JsonFileView docAndNode={docAndNode} node={fileNode.children[0]} />
|
||||
}
|
||||
|
||||
return <ErrorPanel error={`Cannot view file ${docAndNode.doc.uri}`} />
|
||||
}
|
||||
@@ -2,35 +2,19 @@ import type { DocAndNode, Range } from '@spyglassmc/core'
|
||||
import { dissectUri } from '@spyglassmc/java-edition/lib/binder/index.js'
|
||||
import type { JsonNode } from '@spyglassmc/json'
|
||||
import { JsonFileNode } from '@spyglassmc/json'
|
||||
import { useCallback, useErrorBoundary, useMemo } from 'preact/hooks'
|
||||
import { useLocale } from '../../contexts/index.js'
|
||||
import { useDocAndNode, useSpyglass } from '../../contexts/Spyglass.jsx'
|
||||
import { useCallback, useMemo } from 'preact/hooks'
|
||||
import { useSpyglass } from '../../contexts/Spyglass.jsx'
|
||||
import { getRootType, simplifyType } from './McdocHelpers.js'
|
||||
import type { McdocContext } from './McdocRenderer.jsx'
|
||||
import { McdocRoot } from './McdocRenderer.jsx'
|
||||
|
||||
type TreePanelProps = {
|
||||
type JsonFileViewProps = {
|
||||
docAndNode: DocAndNode,
|
||||
onError: (message: string) => unknown,
|
||||
node: JsonNode,
|
||||
}
|
||||
export function Tree({ docAndNode: original, onError }: TreePanelProps) {
|
||||
const { lang } = useLocale()
|
||||
export function JsonFileView({ docAndNode, node }: JsonFileViewProps) {
|
||||
const { service } = useSpyglass()
|
||||
|
||||
if (lang === 'none') return <></>
|
||||
|
||||
const docAndNode = useDocAndNode(original)
|
||||
const fileChild = docAndNode.node.children[0]
|
||||
if (!JsonFileNode.is(fileChild)) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const [error] = useErrorBoundary(e => {
|
||||
onError(`Error rendering the tree: ${e.message}`)
|
||||
console.error(e)
|
||||
})
|
||||
if (error) return <></>
|
||||
|
||||
const makeEdit = useCallback((edit: (range: Range) => JsonNode | undefined) => {
|
||||
if (!service) {
|
||||
return
|
||||
@@ -62,15 +46,15 @@ export function Tree({ docAndNode: original, onError }: TreePanelProps) {
|
||||
}, [docAndNode, service, makeEdit])
|
||||
|
||||
const resourceType = useMemo(() => {
|
||||
if (original.doc.uri.endsWith('/pack.mcmeta')) {
|
||||
if (docAndNode.doc.uri.endsWith('/pack.mcmeta')) {
|
||||
return 'pack_mcmeta'
|
||||
}
|
||||
if (ctx === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const res = dissectUri(original.doc.uri, ctx)
|
||||
const res = dissectUri(docAndNode.doc.uri, ctx)
|
||||
return res?.category
|
||||
}, [original, ctx])
|
||||
}, [docAndNode, ctx])
|
||||
|
||||
const mcdocType = useMemo(() => {
|
||||
if (!ctx || !resourceType) {
|
||||
@@ -81,8 +65,8 @@ export function Tree({ docAndNode: original, onError }: TreePanelProps) {
|
||||
return type
|
||||
}, [resourceType, ctx])
|
||||
|
||||
return <div class="tree node-root" data-category={getCategory(resourceType)}>
|
||||
{(ctx && mcdocType) && <McdocRoot type={mcdocType} node={fileChild.children[0]} ctx={ctx} />}
|
||||
return <div class="file-view tree node-root" data-category={getCategory(resourceType)}>
|
||||
{(ctx && mcdocType) && <McdocRoot type={mcdocType} node={node} ctx={ctx} />}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -144,9 +144,15 @@ export function ProjectPanel() {
|
||||
{project.name !== DRAFT_PROJECT.name && <Btn icon="trashcan" label={locale('project.delete')} onClick={onDeleteProject} />}
|
||||
</BtnMenu>
|
||||
</div>
|
||||
<div class="file-view">
|
||||
<div class="project-files">
|
||||
{entries === undefined
|
||||
? <></>
|
||||
? <div class="p-2 flex flex-col gap-2">
|
||||
<div class="skeleton-2 rounded h-4 w-24"></div>
|
||||
<div class="skeleton-2 rounded h-4 w-32 ml-4"></div>
|
||||
<div class="skeleton-2 rounded h-4 w-24 ml-8"></div>
|
||||
<div class="skeleton-2 rounded h-4 w-36 ml-8"></div>
|
||||
<div class="skeleton-2 rounded h-4 w-28"></div>
|
||||
</div>
|
||||
: entries.length === 0
|
||||
? <span>{locale('project.no_files')}</span>
|
||||
: <TreeView entries={entries} split={path => path.split('/')} group={FolderEntry} leaf={FileEntry} />}
|
||||
|
||||
@@ -13,7 +13,7 @@ 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, Footer, HasPreview, Octicon, PreviewPanel, ProjectPanel, SearchList, SourcePanel, TextInput, Tree, VersionSwitcher } from '../index.js'
|
||||
import { Ad, Btn, BtnMenu, ErrorPanel, FileCreation, FileView, Footer, HasPreview, Octicon, PreviewPanel, ProjectPanel, SearchList, SourcePanel, TextInput, VersionSwitcher } from '../index.js'
|
||||
import { getRootDefault } from './McdocHelpers.js'
|
||||
|
||||
export const SHARE_KEY = 'share'
|
||||
@@ -59,7 +59,7 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) {
|
||||
const [sharedSnippetId, setSharedSnippetId] = useSearchParam(SHARE_KEY)
|
||||
const ignoreChange = useRef(false)
|
||||
|
||||
const { value: docAndNode } = useAsync(async () => {
|
||||
const { value: docAndNode, loading: docLoading } = useAsync(async () => {
|
||||
let text: string | undefined = undefined
|
||||
if (currentPreset && sharedSnippetId) {
|
||||
setSharedSnippetId(undefined)
|
||||
@@ -386,7 +386,7 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) {
|
||||
</BtnMenu>
|
||||
</div>
|
||||
{error && <ErrorPanel error={error} onDismiss={() => setError(null)} />}
|
||||
{docAndNode && <Tree docAndNode={docAndNode} onError={setError} />}
|
||||
<FileView docAndNode={docLoading ? undefined : docAndNode} />
|
||||
<Footer donate={!gen.tags?.includes('partners')} />
|
||||
</main>
|
||||
<div class="popup-actions right-actions" style={`--offset: -${8 + actionsShown * 50}px;`}>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
export * from './FileCreation.js'
|
||||
export * from './FileRenaming.js'
|
||||
export * from './FileView.jsx'
|
||||
export * from './GeneratorCard.jsx'
|
||||
export * from './GeneratorList.jsx'
|
||||
export * from './JsonFileView.jsx'
|
||||
export * from './PreviewPanel.js'
|
||||
export * from './ProjectCreation.js'
|
||||
export * from './ProjectDeletion.js'
|
||||
export * from './ProjectPanel.js'
|
||||
export * from './SourcePanel.js'
|
||||
export * from './Tree.js'
|
||||
|
||||
Reference in New Issue
Block a user