Skip to content

Commit

Permalink
Surface real API errors to user, add submission success message and c…
Browse files Browse the repository at this point in the history
…ooldown, misc. UI polish (#78)

* Try moving fetches out of serverless functions

* Fix linting, add loud error if fetch fails

* Client-side render dashboard and individual pages

Signed-off-by: Frank Noirot <[email protected]>

* Add icon components

* Make logo in nav link to Zoo site

* Show plain error so it's more clear what went wrong
+ border and icon polish

* Show success message, put a cooldown timer on submission, scroll results into view
+ some UI polish

* misc UI polish

* Fix typography-caused padding in ML-ephant badge

* Sign-in button typography tweak

---------

Signed-off-by: Frank Noirot <[email protected]>
  • Loading branch information
franknoirot authored Dec 22, 2023
1 parent a7e034a commit 6e16fe3
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 43 deletions.
10 changes: 5 additions & 5 deletions src/components/DownloadButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@

<div class={`split-button ${status}${status === 'loading' ? ' shimmer ' : ' '}${className}`}>
{#if status == 'ready'}
<a href={dataUrl} download={fileName}>Download</a>
<a href={dataUrl} download={fileName} class="mt-1">Download</a>
{:else if status == 'loading'}
<button disabled>Loading&nbsp;</button>
<button disabled class="mt-1">Loading&nbsp;</button>
{:else}
<button disabled>Failed</button>
<button disabled class="mt-1">Failed</button>
{/if}

<div class="relative">
Expand Down Expand Up @@ -91,11 +91,11 @@
}
select {
@apply bg-green text-chalkboard-120 border-0;
@apply bg-green text-chalkboard-120;
@apply uppercase text-sm font-mono;
@apply shadow-inner;
@apply pl-2 pr-3 py-1 rounded-sm;
@apply border-transparent hover:border-chalkboard-120 border-solid border;
@apply brightness-95 border border-transparent hover:border-chalkboard-120 hover:brightness-100;
}
.shimmer {
Expand Down
2 changes: 1 addition & 1 deletion src/components/GenerationList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
export let additionalGenerations: Models['TextToCad_type'][] = []
$: combinedGenerations = [...additionalGenerations, ...$generations]
const RENDER_THRESHOLD = 0.05
const RENDER_THRESHOLD = -0.1
let PAGE_SIZE = 2
let isFetching = false
let error: string | null = null
Expand Down
37 changes: 22 additions & 15 deletions src/components/GenerationListItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { createEventDispatcher } from 'svelte'
import type { GenerationEvents } from '$lib/types'
import DownloadButton from './DownloadButton.svelte'
import ArrowRight from './Icons/ArrowRight.svelte'
const dispatch = createEventDispatcher<GenerationEvents>()
export let data: PromptResponse
Expand Down Expand Up @@ -54,7 +55,9 @@

<div>
<div class="grid md:grid-cols-2 lg:grid-cols-3 border items-stretch">
<h3 class="font-normal font-mono lg:col-span-2 px-2 py-6 lg:px-4 lg:py-16 border-r box-border">
<h3
class="font-normal font-mono lg:col-span-2 px-2 py-6 lg:px-4 lg:py-16 md:border-r box-border"
>
<span class="block text-sm uppercase text-chalkboard-70 dark:text-chalkboard-40"
>Your Prompt</span
>
Expand All @@ -71,28 +74,27 @@
</div>
{:else if data.status === 'failed' || error}
<div
class="failed dark:dark relative overflow-hidden min-h-[33vh] border-t flex items-center justify-center p-2"
class="failed dark:dark relative overflow-hidden min-h-[33vh] border-t md:border-t-0 flex items-center justify-center p-4"
>
<p class="font-mono text-xs text-destroy-50">
{error?.status
{data?.error
? data.error
: error?.status
? `Error ${error.status}: ${error.message}`
: 'CAD model generation failed, try again later'}
{data?.error?.match(/4\d\d/)?.length
? 'The prompt must clearly describe a CAD model.'
: 'CAD model generation failed, try again later'}
</p>
</div>
{:else}
<div
class="shimmer-skeleton relative overflow-hidden min-h-[33vh] border-t flex items-center justify-center"
class="shimmer-skeleton relative overflow-hidden min-h-[33vh] border-t md:border-t-0 flex items-center justify-center"
>
<p class="font-mono text-sm text-green">Generating...</p>
</div>
{/if}
</div>
<div class="grid md:grid-cols-2 lg:grid-cols-3 border border-t-0 items-stretch">
<dl
class="m-0 px-2 md:px-4 py-1 lg:col-span-2 flex flex-col md:flex-row md:items-center order-1 md:order-none justify-between text-xs font-mono text-chalkboard-70 dark:text-chalkboard-40 border-r"
class="m-0 px-2 md:px-4 py-1 lg:col-span-2 flex flex-col md:flex-row md:items-center order-1 md:order-none justify-between text-xs font-mono text-chalkboard-70 dark:text-chalkboard-40 md:border-r"
>
<div class="flex gap-2">
<dt>Submitted</dt>
Expand All @@ -107,14 +109,16 @@
</dl>
{#if data.outputs && data.status === 'completed'}
<ul class="m-0 p-0 flex flex-col md:flex-row items-stretch">
<DownloadButton className="link flex-auto" outputs={data.outputs} prompt={data.prompt} />
<li class="contents">
<a
href={`view/${data.id}`}
class="link font-mono uppercase text-sm tracking-[1px] flex-auto md:border-r reverse hover:text-chalkboard-120 hover:!bg-green border-chalkboard-70 dark:border-chalkboard-40"
>View</a
class="link font-mono uppercase text-sm tracking-[1px] flex-auto md:border-l reverse hover:text-chalkboard-120 hover:!bg-green border-chalkboard-70 dark:border-chalkboard-40"
>
<span class="mt-1">View</span>
<ArrowRight class="w-4 h-4 ml-2" />
</a>
</li>
<DownloadButton className="link flex-auto" outputs={data.outputs} prompt={data.prompt} />
</ul>
{:else if data.error}
<button
Expand All @@ -128,12 +132,15 @@

<style lang="postcss">
.failed {
--_rim-color: theme('colors.destroy.10');
background: radial-gradient(circle at center, transparent 80%, var(--_rim-color));
@apply bg-destroy-10/20;
@apply text-destroy-80;
@apply border-chalkboard-70;
}
@media (prefers-color-scheme: dark) {
.failed {
--_rim-color: theme('colors.destroy.80' / 25%);
@apply bg-destroy-80/10;
@apply text-destroy-10;
@apply border-chalkboard-40;
}
}
Expand All @@ -155,7 +162,7 @@
.link {
@apply text-center flex items-center justify-center;
@apply px-2 py-1;
@apply px-2 py-4;
@apply hover:bg-chalkboard-20 dark:hover:bg-chalkboard-90;
}
.link:global(.reverse) {
Expand Down
8 changes: 8 additions & 0 deletions src/components/Icons/ArrowLeft.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<svg {...$$restProps} viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2.29285 10L2.6464 9.64645L6.1464 6.14645L6.85351 6.85356L4.20706 9.50001L17 9.50001V10.5L4.20706 10.5L6.85351 13.1465L6.1464 13.8536L2.6464 10.3536L2.29285 10Z"
fill="currentColor"
/>
</svg>
8 changes: 8 additions & 0 deletions src/components/Icons/ArrowRight.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<svg {...$$restProps} viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.7071 10L17.3536 10.3536L13.8536 13.8536L13.1464 13.1465L15.7929 10.5H3V9.50001H15.7929L13.1464 6.85356L13.8536 6.14645L17.3536 9.64645L17.7071 10Z"
fill="currentColor"
/>
</svg>
8 changes: 4 additions & 4 deletions src/components/Nav.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</script>

<nav class="nav">
<a href={user ? paths.DASHBOARD : paths.HOME}>
<a href={paths.ZOO_SITE} rel="noopener noreferrer" target="_blank">
<Logo className="h-6 lg:h-8 hover:text-green" />
</a>
{#if user}
Expand All @@ -22,12 +22,12 @@
<style lang="postcss">
.nav {
@apply bg-white dark:bg-chalkboard-120;
@apply mx-5 lg:mx-auto mt-2 lg:mt-4 max-w-5xl;
@apply mx-2 md:mx-5 lg:mx-auto mt-2 lg:mt-4 max-w-5xl;
@apply sticky z-10 top-0 flex justify-between items-center;
@apply border px-2 md:px-4 py-1 z-20;
@apply border px-2 py-1 z-20;
}
.sign-in {
@apply font-mono uppercase tracking-[1px] px-2 py-1 hover:bg-green hover:text-chalkboard-120;
@apply font-mono text-sm uppercase tracking-[1px] px-2 pt-1 pb-0.5 hover:bg-green hover:text-chalkboard-120;
}
</style>
3 changes: 2 additions & 1 deletion src/lib/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export const paths = {
import.meta.env.VITE_SITE_BASE_URL + '/signin/?callbackUrl=' + encodeURIComponent(callbackUrl),
HOME: '/',
DASHBOARD: '/dashboard',
SIGN_OUT: `/?${SIGN_OUT_PARAM}=true`
SIGN_OUT: `/?${SIGN_OUT_PARAM}=true`,
ZOO_SITE: 'https://zoo.dev'
} as const
2 changes: 1 addition & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
</script>

<Nav user={data ? data.user : undefined} />
<main class="mx-5 lg:mx-auto max-w-5xl">
<main class="mx-2 md:mx-5 lg:mx-auto max-w-5xl">
<slot />
</main>
2 changes: 1 addition & 1 deletion src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
href="https://zoo.dev/machine-learning-api"
target="_blank"
rel="noopener noreferrer"
class="bg-chalkboard-120 rounded-sm dark:bg-transparent"
class="bg-chalkboard-120 rounded-sm dark:bg-transparent pt-0.5"
><LogoMLephant
className="h-[0.8em] text-green mx-[0.5ch] inline-block align-baseline"
/><span class="sr-only">ML-ephant</span></a
Expand Down
39 changes: 29 additions & 10 deletions src/routes/dashboard/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
const getExammplePrompts = () => [...EXAMPLE_PROMPTS].sort(() => Math.random() - 0.5).slice(0, 3)
let examplePrompts = getExammplePrompts()
let error: string | null = null
let showSuccessMessage: boolean = false
let isCoolingDown = false
let listSection = null as HTMLDivElement | null
const submitPrompt = async (prompt: string) => {
const OUTPUT_FORMAT: Models['FileExportFormat_type'] = 'gltf'
Expand Down Expand Up @@ -41,6 +44,12 @@
await submitPrompt(prompt)
const form = e.target as HTMLFormElement
form.reset()
showSuccessMessage = true
isCoolingDown = true
setTimeout(() => {
isCoolingDown = false
}, 3000)
listSection?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
}
const retryPrompt = (e: CustomEvent<GenerationEvents['retryprompt']>) => {
Expand All @@ -50,11 +59,11 @@
}
</script>

<section class="mx-auto max-w-2xl my-48">
<h1 class="text-5xl mb-2">
<section class="mx-auto max-w-2xl my-16 md:my-24 lg:my-48">
<h1 class="text-4xl md:text-5xl mb-2">
Text-to-<span class="text-green">CAD</span>
</h1>
<form on:submit={submitForm} class="flex w-full text-lg" bind:this={form}>
<form on:submit={submitForm} class="flex text-lg" bind:this={form}>
<label class="flex-1">
<span class="sr-only">Enter a text-to-CAD prompt:</span>
<input
Expand All @@ -64,22 +73,29 @@
required
spellcheck="false"
type="text"
class="w-full px-4 py-1 border"
class="w-full px-4 py-1 border border-r-0 focus:outline-none focus:bg-green/20 focus:placeholder-shown:bg-green/10"
bind:this={input}
on:input={() => {
showSuccessMessage = false
error = null
}}
/>
</label>
<button type="submit" class="submit">Submit</button>
<button type="submit" class="submit" disabled={isCoolingDown}>Submit</button>
</form>
{#if error}
<p class="text-red mt-2">{error}</p>
{:else if showSuccessMessage}
<p class="border border-t-0 border-chalkboard-70 dark:border-chalkboard-40 p-2 bg-green/40">
Prompt submitted!
</p>
{/if}
<div class="prompt-buttons">
<span class="font-mono pt-1 text-xs uppercase text-chalkboard-70 dark:text-chalkboard-40"
>Example prompts:</span
>
{#each examplePrompts as prompt (prompt)}
<button
class="submit"
on:click={() => {
if (input) {
input.value = prompt
Expand All @@ -92,26 +108,29 @@
</div>
</section>
{#if Boolean(data.user)}
<GenerationList additionalGenerations={promptedGenerations} on:retryprompt={retryPrompt} />
<div bind:this={listSection}>
<GenerationList additionalGenerations={promptedGenerations} on:retryprompt={retryPrompt} />
</div>
{/if}

<style lang="postcss">
.submit {
@apply px-4 lg:px-6 py-1 border border-l-0;
@apply px-4 lg:px-6 pt-1 pb-0.5 border;
@apply font-mono uppercase tracking-[1px] text-sm;
@apply border-chalkboard-100 dark:border-chalkboard-20;
@apply bg-green text-chalkboard-120 hover:hue-rotate-15;
@apply hover:bg-green/50;
}
.prompt-buttons {
@apply flex flex-wrap gap-2 mt-4;
}
.prompt-buttons button {
@apply text-xs rounded-full border pt-0.5 pb-0 px-3;
@apply text-sm rounded-full border pt-0.5 pb-0 px-3;
@apply bg-transparent hover:bg-green/50;
@apply text-chalkboard-70 dark:text-chalkboard-50 hover:text-chalkboard-120 dark:hover:text-chalkboard-10;
@apply border-chalkboard-30 dark:border-chalkboard-70;
@apply hover:border-chalkboard-120 dark:hover:border-chalkboard-10;
@apply hover:bg-green/20 text-chalkboard-120 hover:hue-rotate-15;
}
</style>
10 changes: 5 additions & 5 deletions src/routes/view/[modelId]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ModelFeedback from 'components/ModelFeedback.svelte'
import DownloadButton from 'components/DownloadButton.svelte'
import type { Models } from '@kittycad/lib'
import ArrowLeft from 'components/Icons/ArrowLeft.svelte'
export let data: Models['TextToCad_type']
Expand All @@ -15,11 +16,10 @@
>UI</span
>
</p>
<a
href="/"
class="block w-fit text-xs px-2 py-1 mb-4 hover:bg-chalkboard-20 dark:hover:bg-chalkboard-90"
>⬅ Back to home</a
>
<a href="/" class="w-fit flex gap-2 text-sm px-2 py-1 mb-4 hover:bg-green/40"
><ArrowLeft class="w-5 h-5" />
<span class="pb-0.5">Back to dashboard</span>
</a>
<div class="mb-24">
<div class="grid md:grid-cols-3 lg:grid-cols-4 border items-stretch">
<h1
Expand Down

0 comments on commit 6e16fe3

Please sign in to comment.