🏡 index : ~doyle/chartered.git

author Jordan Doyle <jordan@doyle.la> 2022-09-10 4:03:17.0 +01:00:00
committer Jordan Doyle <jordan@doyle.la> 2022-09-10 4:03:17.0 +01:00:00
commit
b0e20816a518b240b78b5676430e3df465aa502e [patch]
tree
e91e6e91f3be91ee3e0b75ef8810a8677a2377dd
parent
804e9d25fe8917ab36a608bd6d5feedda722bc2e
download
b0e20816a518b240b78b5676430e3df465aa502e.tar.gz

Add skeleton loading to most common pages



Diff

 chartered-frontend/src/app.pcss                                                   |  12 ++++++++++++
 chartered-frontend/src/components/FeaturedCrate.svelte                            |  35 +++++++++++++++++++++++++++--------
 chartered-frontend/src/routes/(authed)/+page.svelte                               |  31 ++++++++++++++++++++++---------
 chartered-frontend/src/routes/(authed)/ssh-keys/+page.svelte                      |  13 ++++++++-----
 chartered-frontend/src/routes/(authed)/ssh-keys/SingleSshKey.svelte               |  49 +++++++++++++++++++++++++++++++++++++++++--------
 chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte         |  30 +++++++++++++++++++++++++++---
 chartered-frontend/src/routes/(authed)/organisations/list/+page.svelte            |  30 +++++++++++++++++++++++++++---
 chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 8 files changed, 244 insertions(+), 88 deletions(-)

diff --git a/chartered-frontend/src/app.pcss b/chartered-frontend/src/app.pcss
index 590601d..eaf9167 100644
--- a/chartered-frontend/src/app.pcss
+++ a/chartered-frontend/src/app.pcss
@@ -55,8 +55,20 @@
    .btn-blue-outline {
        @apply w-fit mt-3 text-blue-700 dark:text-inherit hover:text-white border border-blue-700 hover:bg-blue-700 dark:bg-transparent focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:border-blue-600 dark:hover:bg-blue-600 focus:outline-none dark:focus:ring-blue-800 transition duration-150 ease-out;
    }

    .btn-skeleton-outline {
        @apply w-fit mt-3 border border-slate-700 bg-transparent font-medium rounded-lg text-sm px-5 py-2.5 pointer-events-none;
    }
}

.text-highlight {
    @apply text-blue-700 dark:text-blue-600;
}

.skeleton {
    @apply h-2 bg-slate-700 rounded animate-pulse;
}

.skeleton-highlight {
    @apply h-2 bg-blue-700 rounded animate-pulse;
}
diff --git a/chartered-frontend/src/components/FeaturedCrate.svelte b/chartered-frontend/src/components/FeaturedCrate.svelte
index 4076305..9b7599e 100644
--- a/chartered-frontend/src/components/FeaturedCrate.svelte
+++ a/chartered-frontend/src/components/FeaturedCrate.svelte
@@ -5,19 +5,34 @@
    /**
     * The crate to show in the card
     */
    export let crate: Crate;
    export let crate: Crate | null;
</script>

<a href={`/crates/${crate.organisation}/${crate.name}`} class="card flex items-center mb-3">
    <div class="flex-grow">
        <div class="font-semibold">
            {crate.organisation}/<span class="text-highlight">{crate.name}</span>
{#if crate}
    <a href={`/crates/${crate.organisation}/${crate.name}`} class="card flex items-center mb-3">
        <div class="flex-grow">
            <div class="font-semibold">
                {crate.organisation}/<span class="text-highlight">{crate.name}</span>
            </div>

            <div class="text-xs flex items-center space-x-1">
                <slot />
            </div>
        </div>

        <div class="text-xs flex items-center space-x-1">
            <slot />
        <Icon name="chevron-right" strokeWidth="3px" />
    </a>
{:else}
    <div class="card flex items-center mb-3">
        <div class="flex-grow">
            <div class="flex items-end pb-2 h-6">
                <div style={`width: ${Math.random() * 4 + 4}rem`} class="skeleton" />
                <div style={`width: ${Math.random() * 4 + 4}rem`} class="ml-2 skeleton-highlight" />
            </div>

            <div class="text-xs flex items-center space-x-1">
                <slot />
            </div>
        </div>
    </div>

    <Icon name="chevron-right" strokeWidth="3px" />
</a>
{/if}
diff --git a/chartered-frontend/src/routes/(authed)/+page.svelte b/chartered-frontend/src/routes/(authed)/+page.svelte
index 65c64a1..939c1c3 100644
--- a/chartered-frontend/src/routes/(authed)/+page.svelte
+++ a/chartered-frontend/src/routes/(authed)/+page.svelte
@@ -1,9 +1,8 @@
<script type="typescript">
    import Icon from '../../components/Icon.svelte';
    import rustLogo from '../../img/rust.svg';
    import { request } from '../../stores/auth';
    import RelativeTime from '../../components/RelativeTime.svelte';
    import Spinner from '../../components/Spinner.svelte';
    import type { MostDownloaded, RecentlyCreated, RecentlyUpdated } from '../../types/featured_crate';
    import FeaturedCrate from '../../components/FeaturedCrate.svelte';
    import ErrorAlert from '../../components/ErrorAlert.svelte';
@@ -39,9 +38,14 @@
            <h3 class="text-3xl mb-2">Newly created</h3>

            {#await recentlyCreatedPromise}
                <div class="relative h-12">
                    <Spinner />
                </div>
                {#each [1, 2, 3, 4, 5] as _}
                    <FeaturedCrate crate={null}>
                        <div class="my-0.5 flex items-center space-x-1">
                            <Icon name="calendar" />
                            <div class="skeleton w-16" />
                        </div>
                    </FeaturedCrate>
                {/each}
            {:then recentlyCreated}
                {#each recentlyCreated.crates as crate}
                    <FeaturedCrate {crate}>
@@ -58,9 +62,11 @@
            <h3 class="text-3xl mb-2">Recently updated</h3>

            {#await recentlyUpdatedPromise}
                <div class="relative h-12">
                    <Spinner />
                </div>
                {#each [1, 2, 3, 4, 5] as _}
                    <FeaturedCrate crate={null}>
                        <div class="skeleton w-9 my-1" />
                    </FeaturedCrate>
                {/each}
            {:then recentlyUpdated}
                {#each recentlyUpdated.versions as crate}
                    <FeaturedCrate {crate}>
@@ -76,9 +82,14 @@
            <h3 class="text-3xl mb-2">Most downloaded</h3>

            {#await mostDownloadedPromise}
                <div class="relative h-12">
                    <Spinner />
                </div>
                {#each [1, 2, 3, 4, 5] as _}
                    <FeaturedCrate crate={null}>
                        <div class="my-0.5 flex items-center space-x-1">
                            <Icon name="download" />
                            <div class="skeleton w-8" />
                        </div>
                    </FeaturedCrate>
                {/each}
            {:then mostDownloaded}
                {#each mostDownloaded.crates as crate}
                    <FeaturedCrate {crate}>
diff --git a/chartered-frontend/src/routes/(authed)/ssh-keys/+page.svelte b/chartered-frontend/src/routes/(authed)/ssh-keys/+page.svelte
index d97546f..5a0b8eb 100644
--- a/chartered-frontend/src/routes/(authed)/ssh-keys/+page.svelte
+++ a/chartered-frontend/src/routes/(authed)/ssh-keys/+page.svelte
@@ -1,6 +1,5 @@
<script type="typescript">
    import { request } from '../../../stores/auth';
    import Spinner from '../../../components/Spinner.svelte';
    import ErrorAlert from '../../../components/ErrorAlert.svelte';
    import SingleSshKey from './SingleSshKey.svelte';
    import type { SshKeys, SshKey } from '../../../types/ssh_keys';
@@ -45,8 +44,12 @@

<main class="container mx-auto p-10 pt-0">
    {#await sshKeysPromise}
        <div class="relative h-4">
            <Spinner />
        <div class="card mb-4 p-2">
            <div class="overflow-scroll">
                <div class="w-fit min-w-full">
                    <SingleSshKey sshKey={null} />
                </div>
            </div>
        </div>
    {:then sshKeys}
        <div class:hidden={sshKeys.keys.length === 0} class="card mb-4 p-2">
@@ -60,11 +63,11 @@
                </div>
            </div>
        </div>

        <CreateKeyForm on:complete={reloadSshKeys} />
    {:catch e}
        <ErrorAlert showClose={false}>{e}</ErrorAlert>
    {/await}

    <CreateKeyForm on:complete={reloadSshKeys} />
</main>

{#if deleting}
diff --git a/chartered-frontend/src/routes/(authed)/ssh-keys/SingleSshKey.svelte b/chartered-frontend/src/routes/(authed)/ssh-keys/SingleSshKey.svelte
index cb3f1e1..f975639 100644
--- a/chartered-frontend/src/routes/(authed)/ssh-keys/SingleSshKey.svelte
+++ a/chartered-frontend/src/routes/(authed)/ssh-keys/SingleSshKey.svelte
@@ -7,7 +7,7 @@
    /**
     * The SSH key to draw up some information about
     */
    export let sshKey: SshKey;
    export let sshKey: SshKey | null;

    // build the event dispatcher for alerting the main view that the user wants to
    // delete the current key
@@ -16,21 +16,44 @@

<div class="p-2 flex items-center">
    <div class="flex-grow">
        <h3 class="text-lg">{sshKey.name}</h3>
        <h3 class="text-lg">
            {#if sshKey}
                {sshKey.name}
            {:else}
                <div class="skeleton w-24 mt-3" />
            {/if}
        </h3>

        <code class="text-xs">{sshKey.fingerprint}</code>
        {#if sshKey}
            <code class="text-xs">
                {sshKey.fingerprint}
            </code>
        {:else}
            <div class="flex">
                {#each [...Array(32).keys()] as _}
                    <div class="skeleton w-4 mt-4 mr-1.5" />
                {/each}
            </div>
        {/if}

        <div class="text-xs pt-0.5 pb-1">
            <span>Added <RelativeTime time={sshKey.created_at} /></span>

            <span class="ml-2">
                Last used
                {#if sshKey.last_used_at}
                    <RelativeTime time={sshKey.last_used_at} />
                {:else}
                    never
                {/if}
            </span>
            {#if sshKey}
                <span>Added <RelativeTime time={sshKey.created_at} /></span>

                <span class="ml-2">
                    Last used
                    {#if sshKey.last_used_at}
                        <RelativeTime time={sshKey.last_used_at} />
                    {:else}
                        never
                    {/if}
                </span>
            {:else}
                <div class="flex mt-3 mb-1">
                    <div class="skeleton w-32" />
                    <div class="skeleton w-24 ml-2" />
                </div>
            {/if}
        </div>
    </div>

diff --git a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte b/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte
index 3bfc3ae..a3d8d5f 100644
--- a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte
+++ a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte
@@ -1,7 +1,6 @@
<script type="typescript">
    import { page } from '$app/stores';
    import { request } from '../../../../stores/auth';
    import Spinner from '../../../../components/Spinner.svelte';
    import ErrorAlert from '../../../../components/ErrorAlert.svelte';
    import Icon from '../../../../components/Icon.svelte';
    import type { OrganisationDetail } from '../../../../types/organisations';
@@ -70,8 +69,13 @@

            <h2>
                {#await organisationPromise}
                    <div class="relative h-4 w-4">
                        <Spinner />
                    <div class="h-6">
                        <div class="skeleton inline-block mr-2 w-24" />
                        <div class="skeleton inline-block mr-2 w-8" />
                        <div class="skeleton inline-block mr-2 w-16" />
                        <div class="skeleton inline-block mr-2 w-12" />
                        <div class="skeleton inline-block mr-2 w-9" />
                        <div class="skeleton inline-block w-10" />
                    </div>
                {:then organisation}
                    {#if organisation.description}
@@ -110,8 +114,24 @@

    <div class="mt-4">
        {#await organisationPromise}
            <div class="relative h-14">
                <Spinner />
            <div class="grid gap-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
                {#each [1, 2, 3] as _}
                    <div class="card">
                        <div class="card-header flex items-center my-4">
                            <div class="skeleton mr-2 w-24" />
                            <div class="skeleton-highlight w-16" />
                        </div>

                        <div class="card-body">
                            <div class="skeleton inline-block mr-2 w-24" />
                            <div class="skeleton inline-block mr-2 w-8" />
                            <div class="skeleton inline-block mr-2 w-16" />
                            <div class="skeleton inline-block mr-2 w-12" />
                            <div class="skeleton inline-block mr-2 w-9" />
                            <div class="skeleton inline-block w-10" />
                        </div>
                    </div>
                {/each}
            </div>
        {:then organisation}
            {#if currentTab === Tab.CRATES}
diff --git a/chartered-frontend/src/routes/(authed)/organisations/list/+page.svelte b/chartered-frontend/src/routes/(authed)/organisations/list/+page.svelte
index 1754939..41484f9 100644
--- a/chartered-frontend/src/routes/(authed)/organisations/list/+page.svelte
+++ a/chartered-frontend/src/routes/(authed)/organisations/list/+page.svelte
@@ -1,5 +1,4 @@
<script type="typescript">
    import Spinner from '../../../../components/Spinner.svelte';
    import { request } from '../../../../stores/auth';
    import type { OrganisationList } from '../../../../types/organisations';
    import ErrorAlert from '../../../../components/ErrorAlert.svelte';
@@ -26,8 +25,29 @@

<main class="container mx-auto p-10 pt-0">
    {#await organisationsPromise}
        <div class="relative h-4">
            <Spinner />
        <div class="mb-4 grid md:grid-cols-2 lg:grid-cols-4 gap-2">
            {#each [1, 2, 3] as _}
                <div class="card flex space-x-2 items-center">
                    <div class="flex-grow h-full">
                        <div class="card-header">
                            <div class="skeleton-highlight w-32" />
                        </div>

                        <div class="card-body">
                            <div class="skeleton inline-block mr-2 w-24" />
                            <div class="skeleton inline-block mr-2 w-8" />
                            <div class="skeleton inline-block mr-2 w-16" />
                            <div class="skeleton inline-block mr-2 w-12" />
                            <div class="skeleton inline-block mr-2 w-9" />
                            <div class="skeleton inline-block w-10" />
                        </div>
                    </div>

                    <div class="min-w-[48px]">
                        <img alt="Placeholder" class="rounded-[50%]" src="http://placekitten.com/48/48" />
                    </div>
                </div>
            {/each}
        </div>
    {:then organisations}
        <div
@@ -60,9 +80,9 @@
                one.
            </div>
        {/if}

        <a href="/organisations/create" class="inline-flex items-center btn-blue-outline"> + Create </a>
    {:catch e}
        <ErrorAlert showClose={false}>{e}</ErrorAlert>
    {/await}

    <a href="/organisations/create" class="inline-flex items-center btn-blue-outline"> + Create </a>
</main>
diff --git a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte b/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte
index 216565a..216be13 100644
--- a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte
+++ a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte
@@ -57,7 +57,36 @@
                >
            </h1>

            {#await cratePromise then crate}
            {#await cratePromise}
                <div class="h-6">
                    <div class="skeleton inline-block mr-2 w-12" />
                    <div class="skeleton inline-block mr-2 w-24" />
                    <div class="skeleton inline-block mr-2 w-16" />
                    <div class="skeleton inline-block mr-2 w-32" />
                    <div class="skeleton inline-block mr-2 w-12" />
                    <div class="skeleton inline-block w-10" />
                </div>

                <div class="space-x-2">
                    <div class="card-header-button btn-skeleton-outline">
                        &nbsp;
                        <div class="skeleton inline-block w-10" />
                        &nbsp;
                    </div>

                    <div class="card-header-button btn-skeleton-outline">
                        &nbsp;
                        <div class="skeleton inline-block w-10" />
                        &nbsp;
                    </div>

                    <div class="card-header-button btn-skeleton-outline">
                        &nbsp;
                        <div class="skeleton inline-block w-10" />
                        &nbsp;
                    </div>
                </div>
            {:then crate}
                <h2>
                    {#if crate.description}
                        {crate.description}
@@ -94,57 +123,80 @@
</header>

<main class="container mx-auto p-10 pt-0 grid grid-cols-12 gap-6 relative">
    {#await cratePromise}
        <Spinner />
    {:then crate}
        <div class="card col-span-full lg:col-span-9 p-0">
            <div class="border-b border-gray-200 dark:border-gray-700">
                <ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
                    {#each allTabs as tab}
                        <li class="mr-2">
                            <button
                                on:click={() => (currentTab = tab.id)}
                                class:!border-blue-500={currentTab === tab.id}
                                class:text-blue-500={currentTab === tab.id}
                                aria-current={currentTab === tab.id ? 'page' : false}
                                class="inline-flex items-center space-x-2 p-4 rounded-t-lg border-b-2 border-transparent"
                            >
                                <Icon name={tab.icon} /> <span>{tab.name}</span>
                            </button>
                        </li>
                    {/each}
                </ul>
            </div>
    <div class="card col-span-full lg:col-span-9 p-0">
        <div class="border-b border-gray-200 dark:border-gray-700">
            <ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
                {#each allTabs as tab}
                    <li class="mr-2">
                        <button
                            on:click={() => (currentTab = tab.id)}
                            class:!border-blue-500={currentTab === tab.id}
                            class:text-blue-500={currentTab === tab.id}
                            aria-current={currentTab === tab.id ? 'page' : false}
                            class="inline-flex items-center space-x-2 p-4 rounded-t-lg border-b-2 border-transparent"
                        >
                            <Icon name={tab.icon} /> <span>{tab.name}</span>
                        </button>
                    </li>
                {/each}
            </ul>
        </div>

            {#if currentTab === Tab.README}
                <article
                    class="mt-8 px-6 pb-6 prose dark:prose-invert text-inherit max-w-full prose-headings:text-inherit hover:prose-a:text-blue-600 prose-a:text-blue-500 prose-code:p-1 prose-code:bg-slate-100 dark:prose-code:bg-slate-700 prose-code:rounded-lg prose-pre:bg-slate-100 dark:prose-pre:bg-slate-700 leading-6 before:prose-code:content-none after:prose-code:content-none prose-code:text-pink-400 prose-code:font-normal prose-strong:text-inherit prose-img:inline prose-img:my-0"
                >
        {#if currentTab === Tab.README}
            <article
                class="mt-8 px-6 pb-6 prose dark:prose-invert text-inherit max-w-full prose-headings:text-inherit hover:prose-a:text-blue-600 prose-a:text-blue-500 prose-code:p-1 prose-code:bg-slate-100 dark:prose-code:bg-slate-700 prose-code:rounded-lg prose-pre:bg-slate-100 dark:prose-pre:bg-slate-700 leading-6 before:prose-code:content-none after:prose-code:content-none prose-code:text-pink-400 prose-code:font-normal prose-strong:text-inherit prose-img:inline prose-img:my-0"
            >
                {#await cratePromise}
                    <div class="skeleton inline-block mr-2 w-24" />
                    <br /><br />
                    {#each [...Array(200).keys()] as _}
                        <div
                            style={`width: ${Math.max(Math.random() * 24, 4)}rem`}
                            class={`skeleton inline-block mr-2`}
                        />
                    {/each}
                {:then crate}
                    <SvelteMarkdown source={crate.readme} />
                </article>
            {:else if currentTab === Tab.MEMBERS}
                <MemberTab />
            {:else if currentTab === Tab.VERSIONS}
                <div class="divide-y divide-gray-200 dark:divide-gray-700">
                {/await}
            </article>
        {:else if currentTab === Tab.MEMBERS}
            <MemberTab />
        {:else if currentTab === Tab.VERSIONS}
            <div class="divide-y divide-gray-200 dark:divide-gray-700">
                {#await cratePromise}
                    <div class="relative h-20"><Spinner /></div>
                {:then crate}
                    {#each crate.versions as version}
                        <VersionTab {version} class="p-6" />
                    {/each}
                </div>
            {/if}
        </div>
                {/await}
            </div>
        {/if}
    </div>

        <div class="col-span-full lg:col-span-3">
            <div class="card p-0">
                <h1 class="text-xl p-3 border-b border-gray-200 dark:border-gray-700 font-medium">Dependencies</h1>
    <div class="col-span-full lg:col-span-3">
        <div class="card p-0">
            <h1 class="text-xl p-3 border-b border-gray-200 dark:border-gray-700 font-medium">Dependencies</h1>

                <div class="divide-y divide-gray-200 dark:divide-gray-700">
            <div class="divide-y divide-gray-200 dark:divide-gray-700">
                {#await cratePromise}
                    {#each [...Array(Math.floor(Math.random() * 8 + 5)).keys()] as _}
                        <div class="flex items-center py-5">
                            <div
                                style={`width: ${Math.max(Math.random() * 12, 4)}rem`}
                                class={`skeleton inline-block ml-3 mr-2`}
                            />
                            <div class={`skeleton inline-block mr-3 w-12`} />
                        </div>
                    {/each}
                {:then crate}
                    {#each crate.versions[0].deps as dependency}
                        <Dependency {dependency} class="p-3" />
                    {/each}
                </div>
                {/await}
            </div>
        </div>
    {/await}
    </div>
</main>

<style lang="postcss">