Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sidebar layout #92

Merged
merged 40 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3c4e35e
Change "dashboard" to "view" so pages can share sidebar layout
franknoirot Jan 5, 2024
0d380d6
Rename nav to sidebar, apply only to `/view/*`
franknoirot Jan 5, 2024
01777f7
Group layouts without changing URLs:
franknoirot Jan 5, 2024
ae9f48f
Move generations to sidebar
franknoirot Jan 5, 2024
e970208
Merge branch 'main' into sidebar-layout
franknoirot Jan 5, 2024
b4463a8
New GenerationList, simple sorted list of links
franknoirot Jan 5, 2024
f0fedc1
Some polish on the sidebar
franknoirot Jan 5, 2024
6de7786
Add icons, start polishing view page
franknoirot Jan 7, 2024
835a678
Make error version of view page
franknoirot Jan 8, 2024
e8b1ff4
Persist generations to localStorage
franknoirot Jan 8, 2024
ebab987
Change "This Week" to "Past 7 Days"
franknoirot Jan 8, 2024
b3d88f1
Invalidate threlte renderer on navigation or resize
franknoirot Jan 8, 2024
d8608b5
Add links to billing and github issues
franknoirot Jan 8, 2024
9826e54
Fix broken conditional for failed submissions
franknoirot Jan 8, 2024
dd8fbae
UX polish
franknoirot Jan 8, 2024
910a29f
Add mobile styling, sidebar
franknoirot Jan 8, 2024
cb00c22
Make prompt text box auto-resize, other polish
franknoirot Jan 8, 2024
1068971
preserve query params through homepage redirect
franknoirot Jan 8, 2024
e36ee08
UX polish, colors and submit on enter for textarea
franknoirot Jan 9, 2024
22f8c50
Polish error styling on view page
franknoirot Jan 9, 2024
fc4f2e5
Polish dashboard, separate out components
franknoirot Jan 9, 2024
1b52ab3
Fix linting errors
franknoirot Jan 9, 2024
546ed86
Make some 3D lights move with camera
franknoirot Jan 9, 2024
0ff5270
Add screen read labels to feedback buttons
franknoirot Jan 9, 2024
d041b7f
Polish model color and resizing
franknoirot Jan 9, 2024
0f5e4ed
Tablet polish and copy tweak
franknoirot Jan 9, 2024
0884d9c
Add storage version key, remove @square/svelte-store
franknoirot Jan 9, 2024
4975ade
Remove logs, misc UX polish
franknoirot Jan 9, 2024
dd21755
Fix new prompt button dark mode hover
franknoirot Jan 9, 2024
50732d0
Trim prompt text
franknoirot Jan 9, 2024
e2ce848
Add first integration test
franknoirot Jan 9, 2024
04c2200
Fix unit tests for time buckets
franknoirot Jan 9, 2024
22bbb95
Try adding GitHub CI action
franknoirot Jan 9, 2024
c10b95f
Switch to only do unit tests in CI for now
franknoirot Jan 9, 2024
b4b3e2e
Remove Playwright steps
franknoirot Jan 9, 2024
06dd1fa
Fixes found after user testing
franknoirot Jan 9, 2024
5908b32
Make polling work better
franknoirot Jan 10, 2024
93aed37
Clean up home page responsive styles
franknoirot Jan 10, 2024
57fe851
@jessfraz feedback
franknoirot Jan 10, 2024
f102f9f
Fix endless refresh after model completion
franknoirot Jan 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
VITE_API_BASE_URL=https://api.dev.zoo.dev
VITE_SITE_BASE_URL=https://dev.zoo.dev
PLAYWRIGHT_SESSION_COOKIE=''
22 changes: 22 additions & 0 deletions .github/workflows/unitTests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Unit Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
main:
timeout-minutes: 10
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn
- name: Run integration tests
run: yarn test:unit run
env:
CI: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*


# playwright artifacts
test-results
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.5.0
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ CookieDate.setFullYear(CookieDate.getFullYear() + 10)
document.cookie =
'__Secure-next-auth.session-token=YOUR_TOKEN;Secure;expires=' + CookieDate.toUTCString() + ';'
```

### Running Playwright E2E tests locally

In order to run our Playwright testing suite locally, please set the `PLAYWRIGHT_SESSION_COOKIE` variable within `.env.development` to a token from a logged in local development session. You can retrieve it by:

1. logging in to the project locally using the method outlined above
2. opening the Application tab in your browser developer tools
3. copying out the value of the cookie titled `__Secure-next-auth.session-token` with the domain of `localhost`

Now you should be able to run the `yarn test:integration` and `yarn test` commands successfully.
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "npm run test:integration && npm run test:unit",
"test": "npm run test:integration && npm run test:unit run",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
Expand All @@ -20,12 +20,14 @@
"@sveltejs/kit": "^1.20.4",
"@testing-library/jest-dom": "^6.2.0",
"@testing-library/svelte": "^4.0.5",
"@types/object.groupby": "^1.0.3",
"@types/testing-library__jest-dom": "^6.0.0",
"@types/three": "^0.157.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitest/ui": "^1.1.2",
"autoprefixer": "^10.4.16",
"dotenv": "^16.3.1",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
Expand All @@ -49,6 +51,10 @@
"@kittycad/lib": "^0.0.48",
"@threlte/core": "^6.1.0",
"@threlte/extras": "^7.3.0",
"@types/core-js": "^2.5.8",
"core-js-pure": "^3.35.0",
"object.groupby": "^1.0.1",
"svelte-autosize": "^1.1.0",
"three": "^0.157.0"
}
}
36 changes: 33 additions & 3 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
import type { PlaywrightTestConfig } from '@playwright/test'
import { AUTH_COOKIE_NAME } from './src/lib/cookies'
import dotenv from 'dotenv'
import path from 'path'

dotenv.config({ path: path.resolve(path.dirname('.'), '.env.development') })
const expiration = new Date()
expiration.setFullYear(expiration.getFullYear() + 1)

const config: PlaywrightTestConfig = {
use: {
baseURL: 'https://localhost:3000',
storageState: {
cookies: [
{
name: AUTH_COOKIE_NAME,
value: process.env.PLAYWRIGHT_SESSION_COOKIE ?? '',
domain: 'localhost',
path: '/',
expires: expiration.getTime() / 1000,
httpOnly: true,
secure: true,
sameSite: 'None'
}
],
origins: [
{
origin: 'https://localhost:3000',
localStorage: []
}
]
}
},
webServer: {
command: 'npm run build && npm run preview',
port: 4173
command: 'yarn dev',
port: 3000
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
testMatch: /(.+\.)?(playwright)\.[jt]s/
}

export default config
103 changes: 70 additions & 33 deletions src/components/AccountMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { Models } from '@kittycad/lib'
import { paths } from '$lib/paths'
import Person from './Icons/Person.svelte'
import ArrowRight from './Icons/ArrowRight.svelte'

export let user: Models['User_type']
let open = false
Expand All @@ -11,6 +12,14 @@
((user?.name && user.name.length > 0) ||
(user?.first_name && user.first_name.length > 0) ||
(user?.email && user.email.length > 0))
let displayName =
user?.first_name && user.first_name.length > 0
? (user.first_name + (user.last_name ? ' ' + user.last_name : '')).trim()
: user?.name && user.name.length > 0
? user.name
: user?.email && user.email.length > 0
? user.email
: 'Unnamed User'

function dismiss(e: KeyboardEvent) {
if (e.key === 'Escape') {
Expand All @@ -19,55 +28,74 @@
}
</script>

<div class={'relative flex justify-center items-center ' + (open ? 'open' : '')}>
<div class={'relative flex ' + (open ? 'open' : '')}>
<button
class={'toggle grid place-content-center border border-solid hover:border-green overflow-hidden bg-currentColor w-8 h-8 md:w-12 md:h-12 ' +
(shouldDisplayInitial || shouldDisplayImage ? 'rounded-full' : 'rounded')}
class="flex flex-auto items-center gap-2"
on:click={() => {
open = !open
}}
on:keydown={dismiss}
>
<img
src={user.image}
alt="Avatar"
class="object-fill"
style={`display: ${shouldDisplayImage ? 'block' : 'none'}`}
referrerpolicy="no-referrer"
/>
{#if shouldDisplayInitial}
<span
class="w-5 h-5 font-bold text-xl leading-[1] pt-0.5 text-center text-chalkboard-10 dark:text-chalkboard-120"
data-testid="initial"
>
{user.name?.[0] || user.first_name?.[0] || user.email?.[0]}
</span>
{:else if !shouldDisplayImage}
<Person
data-testid="person-icon"
class="w-full text-chalkboard-10 dark:text-chalkboard-120"
<div
class={'toggle grid place-content-center border border-solid hover:border-green overflow-hidden bg-currentColor w-8 h-8 md:w-12 md:h-12 ' +
(shouldDisplayInitial || shouldDisplayImage ? 'rounded-full' : 'rounded')}
>
<img
src={user?.image}
alt="Avatar"
class="object-fill"
style={`display: ${shouldDisplayImage ? 'block' : 'none'}`}
referrerpolicy="no-referrer"
/>
{/if}
<span class="sr-only">Open menu</span>
{#if shouldDisplayInitial}
<span
class="uppercase w-5 h-5 font-bold text-xl leading-[1] pt-0.5 text-center text-chalkboard-10 dark:text-chalkboard-120"
data-testid="initial"
>
{user.name?.[0] || user.first_name?.[0] || user.email?.[0]}
</span>
{:else if !shouldDisplayImage}
<Person
data-testid="person-icon"
class="w-full text-chalkboard-10 dark:text-chalkboard-120"
/>
{/if}
</div>
<span class="mt-0.5 font-mono">{displayName}</span>
</button>
<dialog class="menu">
<menu class="contents">
<div class="p-4 pb-2">
<p class="font-mono">
{user?.first_name
? user.first_name + (user.last_name ? user.last_name : '')
? user.first_name + (user.last_name ? ' ' + user.last_name : '')
: user?.name || 'Unnamed User'}
</p>
<p class="font-mono text-sm text-chalkboard-70 dark:text-chalkboard-40">
{user?.email || '[email protected]'}
</p>
</div>
<a
data-sveltekit-reload
href={paths.SIGN_OUT}
class="text-sm font-mono uppercase tracking-[1px] hover:bg-green hover:text-chalkboard-120 text-center px-4 py-2 border-t"
href={paths.ZOO_BILLING}
class="menu-button"
on:keydown={dismiss}
target="_blank"
rel="noopener noreferrer"
>
<span>Billing Info</span>
<ArrowRight class="w-5 h-5 inline-block origin-center -rotate-45 ml-1" />
</a>
<a
href={paths.GITHUB_NEW_ISSUE}
class="menu-button"
on:keydown={dismiss}
target="_blank"
rel="noopener noreferrer"
>
<span>Report UI Issue</span>
<ArrowRight class="w-5 h-5 inline-block origin-center -rotate-45 ml-1" />
</a>
<a data-sveltekit-reload href={paths.SIGN_OUT} class="menu-button" on:keydown={dismiss}>
Sign Out
</a>
</menu>
Expand All @@ -76,33 +104,42 @@

<style lang="postcss">
.menu {
@apply absolute top-full -right-4;
@apply z-10 mt-1 mr-0;
@apply absolute bottom-full left-0;
@apply z-10 mb-2;
@apply text-chalkboard-120 dark:text-chalkboard-10;
@apply bg-white dark:bg-chalkboard-90;
@apply border-solid border-2 border-chalkboard-100;
@apply border border-chalkboard-100 dark:border-chalkboard-20;
@apply flex flex-col gap-5;
@apply w-screen text-right;
@apply flex flex-col;
@apply w-screen;
max-inline-size: min(90vw, 250px);
min-inline-size: 150px;
@apply shadow-md;
/* These will transition in */
pointer-events: none;
opacity: 0;
translate: 1px 10px;
translate: -1px 10px;
transition: transform 0.2s ease-out, opacity 0.1s ease-out;
}

.open .menu {
pointer-events: auto;
opacity: 1;
translate: 1px 0px;
translate: -1px 0px;
}

.open .toggle::after {
content: '';
@apply fixed inset-0 z-0 bg-chalkboard-110/20;
@apply pointer-events-auto;
}

.menu-button {
@apply uppercase tracking-[1px] hover:bg-green hover:text-chalkboard-120;
@apply flex gap-2 justify-center items-center text-sm font-mono text-center px-4 py-2 border-t;
}

.menu-button span {
@apply pt-0.5;
}
</style>
22 changes: 16 additions & 6 deletions src/components/DownloadButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@
import type { ConvertResponse } from '../routes/api/convert/[output_format]/+server'
import { toKebabCase } from '$lib/toKebabCase'
import LoadingIndicator from './LoadingIndicator.svelte'
import { onNavigate } from '$app/navigation'
import { tick } from 'svelte'

export let prompt: string = ''
export let outputs: PromptResponse['outputs']
export let className: string = ''
let link: HTMLAnchorElement
let currentOutput: CADFormat = 'gltf'
let outputData = outputs ? outputs[`source.${currentOutput}`] : ''
let status: 'loading' | 'ready' | 'failed' = 'ready'

onNavigate(() => {
currentOutput = 'gltf'
})

$: currentMimeType = CADMIMETypes[currentOutput]
$: dataUrl = `data:${currentMimeType};base64,${outputData}`
$: fileName = `${toKebabCase(prompt)}.${currentOutput}`
Expand All @@ -36,20 +43,23 @@
return
}

// TODO: handle asynchronous case where the conversion is not yet complete

outputs[`source.${currentOutput}`] = responseData.outputs[`source.${currentOutput}`]
outputData = outputs[`source.${currentOutput}`]
}
status = outputData ? 'ready' : 'failed'

if (outputData) {
await tick()
link.click()
}
}
</script>

<div class={`split-button ${status}${status === 'loading' ? ' shimmer ' : ' '}${className}`}>
{#if status == 'ready'}
<a href={dataUrl} download={fileName} class="mt-1">Download</a>
<a href={dataUrl} download={fileName} class="mt-1" bind:this={link}>Download</a>
{:else if status == 'loading'}
<button disabled class="mt-1">Loading&nbsp;</button>
<button disabled class="mt-1">Converting&nbsp;</button>
{:else}
<button disabled class="mt-1">Failed</button>
{/if}
Expand Down Expand Up @@ -77,8 +87,8 @@

<style lang="postcss">
.split-button {
@apply inline-flex justify-center items-center px-2 py-1 gap-4 relative;
@apply font-mono uppercase text-sm tracking-[1px] text-chalkboard-120 bg-green hover:hue-rotate-15;
@apply inline-flex md:flex-col lg:flex-row justify-center items-center px-2 py-4 md:py-1 gap-4 relative;
@apply font-mono uppercase md:text-sm tracking-[1px] text-chalkboard-120 bg-green hover:hue-rotate-15;
}

.split-button:global(.loading),
Expand Down
Loading