mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 19:30:38 +08:00
Preload blobs in project source browser
This commit is contained in:
+26
-3
@@ -4,6 +4,7 @@
|
||||
export let center = false;
|
||||
export let fadeIn = false;
|
||||
export let margins = false;
|
||||
export let condensed = false;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -34,6 +35,11 @@
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.spinner.condensed > div {
|
||||
-webkit-animation: sk-bouncedelay-condensed 0.7s infinite linear both;
|
||||
animation: sk-bouncedelay-condensed 0.7s infinite linear both;
|
||||
}
|
||||
|
||||
.spinner.small > div {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
@@ -53,6 +59,21 @@
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay-condensed {
|
||||
0%, 100% { -webkit-transform: scale(0.2) }
|
||||
50% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay-condensed {
|
||||
0%, 100% {
|
||||
-webkit-transform: scale(0.2);
|
||||
transform: scale(0.2);
|
||||
} 50% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
@@ -85,8 +106,10 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="spinner" class:fade-in={fadeIn} class:small class:center class:margins>
|
||||
<div class="spinner" class:fade-in={fadeIn} class:small class:center class:margins class:condensed>
|
||||
<div class="bounce1" style="background-color: var(--color-{color})"></div>
|
||||
<div class="bounce2" style="background-color: var(--color-{color})"></div>
|
||||
<div class="bounce3" style="background-color: var(--color-{color})"></div>
|
||||
{#if !condensed}
|
||||
<div class="bounce2" style="background-color: var(--color-{color})"></div>
|
||||
<div class="bounce3" style="background-color: var(--color-{color})"></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -11,13 +11,49 @@
|
||||
import Blob from './Blob.svelte';
|
||||
import Readme from './Readme.svelte';
|
||||
|
||||
enum Status {
|
||||
Idle,
|
||||
Loading,
|
||||
Loaded,
|
||||
}
|
||||
|
||||
type State =
|
||||
{ status: Status.Idle }
|
||||
| { status: Status.Loading; path: string }
|
||||
| { status: Status.Loaded; path: string; blob: proj.Blob };
|
||||
|
||||
export let urn: string;
|
||||
export let commit: string;
|
||||
export let config: Config;
|
||||
export let path: string;
|
||||
export let org = "";
|
||||
|
||||
const onSelect = ({ detail: path }: { detail: string }) => {
|
||||
// When the component is loaded the first time, the blob is yet to be loaded.
|
||||
let state: State = { status: Status.Idle };
|
||||
|
||||
const loadBlob = async (path: string): Promise<proj.Blob> => {
|
||||
if (state.status == Status.Loaded && state.path === path) {
|
||||
return state.blob;
|
||||
}
|
||||
|
||||
const isMarkdownPath = utils.isMarkdownPath(path);
|
||||
const promise = path === "/"
|
||||
? proj.getReadme(urn, commit, config)
|
||||
: proj.getBlob(urn, commit, path, { highlight: !isMarkdownPath }, config);
|
||||
|
||||
state = { status: Status.Loading, path };
|
||||
state = { status: Status.Loaded, path, blob: await promise };
|
||||
|
||||
return state.blob;
|
||||
};
|
||||
|
||||
const onSelect = async ({ detail: path }: { detail: string }) => {
|
||||
// Ensure we don't spend any time in a "loading" state. This means
|
||||
// the loading spinner won't be shown, and instead the blob will be
|
||||
// displayed once loaded.
|
||||
const blob = await loadBlob(path);
|
||||
getBlob = new Promise(resolve => resolve(blob));
|
||||
|
||||
navigate(proj.path({ urn, org, commit, path }));
|
||||
};
|
||||
|
||||
@@ -25,11 +61,11 @@
|
||||
return proj.getTree(urn, commit, path, config);
|
||||
};
|
||||
|
||||
$: isMarkdownPath = utils.isMarkdownPath(path);
|
||||
$: getBlob = path === "/"
|
||||
? proj.getReadme(urn, commit, config)
|
||||
: proj.getBlob(urn, commit, path, { highlight: !isMarkdownPath }, config);
|
||||
// This is reactive to respond to path changes that don't originate from this
|
||||
// component, eg. when using the browser's "back" button.
|
||||
$: getBlob = loadBlob(path);
|
||||
$: getAnchor = org ? Org.getAnchor(org, urn, config) : null;
|
||||
$: loading = state.status == Status.Loading ? state.path : null;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -167,7 +203,7 @@
|
||||
{#if tree.entries.length}
|
||||
<div class="column-left">
|
||||
<div class="source-tree">
|
||||
<Tree {tree} {path} {fetchTree} on:select={onSelect} />
|
||||
<Tree {tree} {path} {fetchTree} {loading} on:select={onSelect} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-right">
|
||||
|
||||
@@ -4,26 +4,14 @@
|
||||
import type { Config } from '@app/config';
|
||||
|
||||
export let config: Config;
|
||||
|
||||
const joinPaths = (path: string, glob: string): string => {
|
||||
return glob.length > 0 ? [path, glob].join("/") : path;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Route path="/projects/:urn/head/:path/*" let:params>
|
||||
<View {config} urn={params.urn} path={joinPaths(params.path, params['*'])} />
|
||||
<Route path="/projects/:urn/head/*" let:params>
|
||||
<View {config} urn={params.urn} path={params['*'] || "/"} />
|
||||
</Route>
|
||||
|
||||
<Route path="/projects/:urn/:commit/:path/*" let:params>
|
||||
<View {config} urn={params.urn} commit={params.commit} path={joinPaths(params.path, params['*'])} />
|
||||
</Route>
|
||||
|
||||
<Route path="/projects/:urn/:commit" let:params>
|
||||
<View {config} urn={params.urn} commit={params.commit} path="/" />
|
||||
</Route>
|
||||
|
||||
<Route path="/projects/:urn/head" let:params>
|
||||
<View {config} urn={params.urn} path="/" />
|
||||
<Route path="/projects/:urn/:commit/*" let:params>
|
||||
<View {config} urn={params.urn} commit={params.commit} path={params['*'] || "/"} />
|
||||
</Route>
|
||||
|
||||
<Route path="/projects/:urn" let:params>
|
||||
@@ -32,20 +20,12 @@
|
||||
|
||||
<!-- With an Org context -->
|
||||
|
||||
<Route path="/orgs/:org/projects/:urn/head/:path/*" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} path={joinPaths(params.path, params['*'])} />
|
||||
<Route path="/orgs/:org/projects/:urn/head/*" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} path={params['*'] || "/"} />
|
||||
</Route>
|
||||
|
||||
<Route path="/orgs/:org/projects/:urn/:commit/:path/*" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} commit={params.commit} path={joinPaths(params.path, params['*'])} />
|
||||
</Route>
|
||||
|
||||
<Route path="/orgs/:org/projects/:urn/:commit" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} commit={params.commit} path="/" />
|
||||
</Route>
|
||||
|
||||
<Route path="/orgs/:org/projects/:urn/head" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} path="/" />
|
||||
<Route path="/orgs/:org/projects/:urn/:commit/*" let:params>
|
||||
<View {config} org={params.org} urn={params.urn} commit={params.commit} path={params["*"] || "/"} />
|
||||
</Route>
|
||||
|
||||
<Route path="/orgs/:org/projects/:urn" let:params>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
export let fetchTree: (path: string) => Promise<Tree>;
|
||||
export let path: string;
|
||||
export let tree: Tree;
|
||||
export let loading: string | null = null;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const onSelect = ({ detail: path }: { detail: string }): void => {
|
||||
@@ -29,7 +30,7 @@
|
||||
{:else}
|
||||
<File
|
||||
active={entry.path === path}
|
||||
loading={false}
|
||||
loading={entry.path === loading}
|
||||
name={entry.info.name}
|
||||
on:click={() => onSelect({ detail: entry.path })}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
border-radius: 0.25rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: space-between;
|
||||
line-height: 1.5em;
|
||||
margin: 0.125rem 0;
|
||||
padding: 0.25rem;
|
||||
@@ -44,12 +44,10 @@
|
||||
</style>
|
||||
|
||||
<div class="file" class:active on:click>
|
||||
{#if loading}
|
||||
<div class="spinner">
|
||||
<Loading small />
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Nothing -->
|
||||
{/if}
|
||||
<span class="name">{name}</span>
|
||||
<div class="spinner">
|
||||
{#if loading}
|
||||
<Loading small condensed />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user