Remove sidebar menus in favor of lil' popovers (#3046)

* Convert user menu to a popover from a sidebar

* Move the user menu over to the left menu cluster

* Replace project sidebar with popover-style menu

* Styling tweaks, give export button a proper tooltip when disabled

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Filter orphan breaks, tweak space to remove mouse gaps

* Unify with and without avatar image code

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

* Prepare to move UserSidebarMenu over to right

* Revert AppHeader tweaks

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

* Fix typo in README

* Fix export E2E tests that relied on button text

* Missed the data-testid we used to have on the data-testid we had on the settings button

* Dang I missed another testId

* Update snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-07-18 14:29:15 -04:00
committed by GitHub
parent fe512611ac
commit 01076c3aed
28 changed files with 414 additions and 253 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -471,8 +471,10 @@ export const doExport = async (
page: Page page: Page
): Promise<Paths> => { ): Promise<Paths> => {
await page.getByRole('button', { name: APP_NAME }).click() await page.getByRole('button', { name: APP_NAME }).click()
await expect(page.getByRole('button', { name: 'Export Part' })).toBeVisible() await expect(
await page.getByRole('button', { name: 'Export Part' }).click() page.getByRole('button', { name: 'Export', exact: false })
).toBeVisible()
await page.getByRole('button', { name: 'Export', exact: false }).click()
await expect(page.getByTestId('command-bar')).toBeVisible() await expect(page.getByTestId('command-bar')).toBeVisible()
// Go through export via command bar // Go through export via command bar

View File

@ -77,7 +77,7 @@ describe('ZMA authorized user flows', () => {
const menuButton = await $('[data-testid="user-sidebar-toggle"]') const menuButton = await $('[data-testid="user-sidebar-toggle"]')
await click(menuButton) await click(menuButton)
const settingsButton = await $('[data-testid="settings-button"]') const settingsButton = await $('[data-testid="user-settings"]')
await click(settingsButton) await click(settingsButton)
const projectDirInput = await $('[data-testid="project-directory-input"]') const projectDirInput = await $('[data-testid="project-directory-input"]')

108
src-tauri/Cargo.lock generated
View File

@ -332,7 +332,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -367,7 +367,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -407,7 +407,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -550,7 +550,7 @@ dependencies = [
"proc-macro-crate 3.1.0", "proc-macro-crate 3.1.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"syn_derive", "syn_derive",
] ]
@ -823,7 +823,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1073,7 +1073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1083,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1107,7 +1107,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim 0.10.0",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1118,7 +1118,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1179,7 +1179,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"synstructure", "synstructure",
] ]
@ -1216,7 +1216,7 @@ dependencies = [
"regex", "regex",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1227,7 +1227,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1288,7 +1288,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1320,7 +1320,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1427,7 +1427,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1588,7 +1588,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1704,7 +1704,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -1980,7 +1980,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -2008,7 +2008,7 @@ dependencies = [
"inflections", "inflections",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -2083,7 +2083,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -3377,7 +3377,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.8.3", "regex-syntax 0.8.3",
"structmeta", "structmeta",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -3496,7 +3496,7 @@ dependencies = [
"phf_shared 0.11.2", "phf_shared 0.11.2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -3564,7 +3564,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4438,7 +4438,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde_derive_internals", "serde_derive_internals",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4558,7 +4558,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4569,7 +4569,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4602,7 +4602,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4623,7 +4623,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4665,7 +4665,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4933,7 +4933,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive", "structmeta-derive",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4944,7 +4944,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4966,7 +4966,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -4999,9 +4999,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.70" version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -5017,7 +5017,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -5034,7 +5034,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -5251,7 +5251,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"syn 2.0.70", "syn 2.0.71",
"tauri-utils", "tauri-utils",
"thiserror", "thiserror",
"time", "time",
@ -5269,7 +5269,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"tauri-codegen", "tauri-codegen",
"tauri-utils", "tauri-utils",
] ]
@ -5627,22 +5627,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.61" version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.61" version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -5740,7 +5740,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -5940,7 +5940,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -5969,7 +5969,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -6099,7 +6099,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"termcolor", "termcolor",
] ]
@ -6316,7 +6316,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -6415,7 +6415,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6449,7 +6449,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6590,7 +6590,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -6696,7 +6696,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -6707,7 +6707,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]
@ -7159,7 +7159,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.70", "syn 2.0.71",
] ]
[[package]] [[package]]

View File

@ -49,9 +49,9 @@ export const AppHeader = ({
<> <>
<CommandBarOpenButton /> <CommandBarOpenButton />
<RefreshButton /> <RefreshButton />
<UserSidebarMenu user={user} />
</> </>
)} )}
<UserSidebarMenu user={user} />
</div> </div>
</header> </header>
) )

View File

@ -311,6 +311,16 @@ const CustomIconMap = {
/> />
</svg> </svg>
), ),
link: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.5864 4.46513C11.9532 3.09829 14.1693 3.09829 15.5361 4.46513C16.903 5.83196 16.903 8.04804 15.5361 9.41488L13.5364 11.4147C13.5839 10.9639 13.5635 10.5074 13.4752 10.0616L14.829 8.70777C15.8053 7.73146 15.8053 6.14855 14.829 5.17224C13.8527 4.19592 12.2698 4.19592 11.2935 5.17224L9.17217 7.29356C8.19586 8.26987 8.19586 9.85278 9.17217 10.8291C9.53458 11.1915 9.98056 11.4194 10.4481 11.5127C10.3749 11.6902 10.2662 11.8565 10.122 12.0007L9.76392 12.3587C9.28973 12.1899 8.84465 11.9158 8.46507 11.5362C7.09823 10.1694 7.09823 7.95328 8.46507 6.58645L10.5864 4.46513ZM4.46507 10.5864L6.46488 8.58663C6.41734 9.03738 6.43772 9.49394 6.52601 9.93972L5.17217 11.2935C4.19586 12.2699 4.19586 13.8528 5.17217 14.8291C6.14849 15.8054 7.7314 15.8054 8.70771 14.8291L10.829 12.7078C11.8053 11.7315 11.8053 10.1485 10.829 9.17223C10.4666 8.80983 10.0207 8.58195 9.55314 8.48859C9.62635 8.31113 9.73506 8.14487 9.87926 8.00066L10.2373 7.64262C10.7115 7.81138 11.1566 8.08555 11.5361 8.46512C12.903 9.83196 12.903 12.048 11.5361 13.4149L9.41481 15.5362C8.04798 16.903 5.8319 16.903 4.46507 15.5362C3.09823 14.1694 3.09823 11.9533 4.46507 10.5864Z"
fill="currentColor"
/>
</svg>
),
'make-variable': ( 'make-variable': (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path

View File

@ -1,10 +1,10 @@
import { Popover, Transition } from '@headlessui/react' import { Popover, Transition } from '@headlessui/react'
import { ActionButton } from './ActionButton' import { ActionButton, ActionButtonProps } from './ActionButton'
import { type IndexLoaderData } from 'lib/types' import { type IndexLoaderData } from 'lib/types'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { isTauri } from '../lib/isTauri' import { isTauri } from '../lib/isTauri'
import { Link } from 'react-router-dom' import { Link, useLocation, useNavigate } from 'react-router-dom'
import { Fragment } from 'react' import { Fragment, useMemo } from 'react'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
import { Logo } from './Logo' import { Logo } from './Logo'
import { APP_NAME } from 'lib/constants' import { APP_NAME } from 'lib/constants'
@ -12,6 +12,9 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
import { CustomIcon } from './CustomIcon' import { CustomIcon } from './CustomIcon'
import { useLspContext } from './LspProvider' import { useLspContext } from './LspProvider'
import { engineCommandManager } from 'lib/singletons' import { engineCommandManager } from 'lib/singletons'
import usePlatform from 'hooks/usePlatform'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import Tooltip from './Tooltip'
const ProjectSidebarMenu = ({ const ProjectSidebarMenu = ({
project, project,
@ -80,6 +83,10 @@ function ProjectMenuPopover({
project?: IndexLoaderData['project'] project?: IndexLoaderData['project']
file?: IndexLoaderData['file'] file?: IndexLoaderData['file']
}) { }) {
const platform = usePlatform()
const location = useLocation()
const navigate = useNavigate()
const filePath = useAbsoluteFilePath()
const { commandBarState, commandBarSend } = useCommandsContext() const { commandBarState, commandBarSend } = useCommandsContext()
const { onProjectClose } = useLspContext() const { onProjectClose } = useLspContext()
const exportCommandInfo = { name: 'Export', groupId: 'modeling' } const exportCommandInfo = { name: 'Export', groupId: 'modeling' }
@ -90,13 +97,82 @@ function ProjectMenuPopover({
) )
) )
// We filter this memoized list so that no orphan "break" elements are rendered.
const projectMenuItems = useMemo<(ActionButtonProps | 'break')[]>(
() =>
[
{
id: 'settings',
Element: 'button',
children: (
<>
<span className="flex-1">Project settings</span>
<kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${
isTauri() ? '' : '⬆'
},`}</kbd>
</>
),
onClick: () => {
const targetPath = location.pathname.includes(paths.FILE)
? filePath + paths.SETTINGS
: paths.HOME + paths.SETTINGS
navigate(targetPath + '?tab=project')
},
},
'break',
{
id: 'export',
Element: 'button',
children: (
<>
<span>Export current part</span>
{!findCommand(exportCommandInfo) && (
<Tooltip position="right" className="!max-w-none min-w-fit">
Awaiting engine connection
</Tooltip>
)}
</>
),
disabled: !findCommand(exportCommandInfo),
onClick: () =>
commandBarSend({
type: 'Find and select command',
data: exportCommandInfo,
}),
},
'break',
{
id: 'go-home',
Element: 'button',
children: 'Go to Home',
className: !isTauri() ? 'hidden' : '',
onClick: () => {
onProjectClose(file || null, project?.path || null, true)
// Clear the scene and end the session.
engineCommandManager.endSession()
},
},
].filter(
(props) =>
props === 'break' ||
(typeof props !== 'string' && !props.className?.includes('hidden'))
) as (ActionButtonProps | 'break')[],
[
platform,
findCommand,
commandBarSend,
engineCommandManager,
onProjectClose,
isTauri,
]
)
return ( return (
<Popover className="relative"> <Popover className="relative">
<Popover.Button <Popover.Button
className="rounded-sm h-9 mr-auto max-h-min min-w-max border-0 py-1 pl-0 pr-2 flex items-center focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary dark:hover:bg-chalkboard-90" className="gap-1 rounded-sm h-9 mr-auto max-h-min min-w-max border-0 py-1 px-2 flex items-center focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary dark:hover:bg-chalkboard-90"
data-testid="project-sidebar-toggle" data-testid="project-sidebar-toggle"
> >
<CustomIcon name="three-dots" className="w-5 h-5 rotate-90" />
<div className="flex flex-col items-start py-0.5"> <div className="flex flex-col items-start py-0.5">
<span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"> <span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block">
{isTauri() && file?.name {isTauri() && file?.name
@ -109,68 +185,53 @@ function ProjectMenuPopover({
</span> </span>
)} )}
</div> </div>
<CustomIcon
name="caretDown"
className="w-4 h-4 text-chalkboard-70 dark:text-chalkboard-40 ui-open:rotate-180"
/>
</Popover.Button> </Popover.Button>
<Transition
enter="duration-200 ease-out"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="duration-100 ease-in"
leaveFrom="opacity-100"
leaveTo="opacity-0"
as={Fragment}
>
<Popover.Overlay className="fixed inset-0 z-20 bg-chalkboard-110/50" />
</Transition>
<Transition <Transition
enter="duration-100 ease-out" enter="duration-100 ease-out"
enterFrom="opacity-0 -translate-x-1/4" enterFrom="opacity-0 -translate-y-2"
enterTo="opacity-100 translate-x-0" enterTo="opacity-100 translate-y-0"
leave="duration-75 ease-in"
leaveFrom="opacity-100 translate-x-0"
leaveTo="opacity-0 -translate-x-4"
as={Fragment} as={Fragment}
> >
<Popover.Panel <Popover.Panel
className="fixed inset-0 right-auto z-30 grid w-64 h-screen max-h-screen grid-cols-1 border rounded-r-md shadow-md bg-chalkboard-10 dark:bg-chalkboard-100 border-chalkboard-40 dark:border-chalkboard-80" className={`z-10 absolute top-full left-0 mt-1 pb-1 w-48 bg-chalkboard-10 dark:bg-chalkboard-90
style={{ gridTemplateRows: 'auto 1fr auto' }} border border-solid border-chalkboard-20 dark:border-chalkboard-90 rounded
shadow-lg`}
> >
{({ close }) => ( {({ close }) => (
<> <ul className="relative flex flex-col items-stretch content-stretch p-0.5">
<div className="flex flex-col gap-2 p-4"> {projectMenuItems.map((props, index) => {
<ActionButton if (props === 'break') {
Element="button" return index !== projectMenuItems.length - 1 ? (
iconStart={{ icon: 'exportFile', className: 'p-1' }} <li key={`break-${index}`} className="contents">
className="border-transparent dark:border-transparent" <hr className="border-chalkboard-20 dark:border-chalkboard-80" />
disabled={!findCommand(exportCommandInfo)} </li>
onClick={() => ) : null
commandBarSend({
type: 'Find and select command',
data: exportCommandInfo,
})
} }
>
Export Part const { id, className, children, ...rest } = props
</ActionButton> return (
{isTauri() && ( <li key={id} className="contents">
<ActionButton <ActionButton
Element="button" {...rest}
onClick={() => { className={
onProjectClose(file || null, project?.path || null, true) 'relative !font-sans flex items-center gap-2 rounded-sm py-1.5 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left ' +
// Clear the scene and end the session. className
engineCommandManager.endSession() }
onMouseUp={() => {
close()
}} }}
iconStart={{
icon: 'arrowLeft',
className: 'p-1',
}}
className="border-transparent dark:border-transparent"
> >
Go to Home {children}
</ActionButton> </ActionButton>
)} </li>
</div> )
</> })}
</ul>
)} )}
</Popover.Panel> </Popover.Panel>
</Transition> </Transition>

View File

@ -8,7 +8,9 @@
--_delay: 200ms; --_delay: 200ms;
--_triangle-width: 8px; --_triangle-width: 8px;
--_triangle-height: 12px; --_triangle-height: 12px;
--_p-inline: calc(50% + calc(var(--isRTL) * var(--_triangle-width) / 2)); --_p-inline-arrow-alignment: calc(
50% + calc(var(--isRTL) * var(--_triangle-width) / 2)
);
--_p-block: 4px; --_p-block: 4px;
--_bg: var(--chalkboard-10); --_bg: var(--chalkboard-10);
--_shadow-alpha: 8%; --_shadow-alpha: 8%;
@ -33,7 +35,7 @@
font-weight: normal; font-weight: normal;
line-height: initial; line-height: initial;
letter-spacing: 0; letter-spacing: 0;
padding: var(--_p-block) var(--_p-inline); padding: var(--_p-block) calc(2 * var(--_p-block));
margin: 0; margin: 0;
border-radius: 3px; border-radius: 3px;
background: var(--_bg); background: var(--_bg);
@ -119,7 +121,7 @@
} }
.tooltip.top-right { .tooltip.top-right {
inset-inline-end: var(--_p-inline); inset-inline-end: var(--_p-inline-arrow-alignment);
inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-height)); inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-height));
} }
@ -130,7 +132,7 @@
} }
.tooltip.right { .tooltip.right {
inset-inline-start: calc(100% + var(--_p-inline) + var(--_triangle-height)); inset-inline-start: calc(100% + var(--_triangle-height));
inset-block-end: 50%; inset-block-end: 50%;
--_y: 50%; --_y: 50%;
} }
@ -142,7 +144,7 @@
} }
.tooltip.bottom-right { .tooltip.bottom-right {
inset-inline-end: var(--_p-inline); inset-inline-end: var(--_p-inline-arrow-alignment);
inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-height)); inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-height));
} }
@ -165,7 +167,7 @@
} }
.tooltip.bottom-left { .tooltip.bottom-left {
inset-inline-start: var(--_p-inline); inset-inline-start: var(--_p-inline-arrow-alignment);
inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-height)); inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-height));
} }
@ -176,7 +178,9 @@
} }
.tooltip.left { .tooltip.left {
inset-inline-end: calc(100% + var(--_p-inline) + var(--_triangle-height)); inset-inline-end: calc(
100% + var(--_p-inline-arrow-alignment) + var(--_triangle-height)
);
inset-block-end: 50%; inset-block-end: 50%;
--_y: 50%; --_y: 50%;
} }
@ -188,7 +192,7 @@
} }
.tooltip.top-left { .tooltip.top-left {
inset-inline-start: var(--_p-inline); inset-inline-start: var(--_p-inline-arrow-alignment);
inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-height)); inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-height));
} }

View File

@ -25,11 +25,11 @@ export function UnitsMenu() {
border border-solid border-chalkboard-10 dark:border-chalkboard-90 rounded border border-solid border-chalkboard-10 dark:border-chalkboard-90 rounded
shadow-lg`} shadow-lg`}
> >
<ul className="relative flex flex-col gap-0.5 items-stretch content-stretch"> <ul className="relative flex flex-col items-stretch content-stretch p-0.5">
{baseUnitsUnion.map((unit) => ( {baseUnitsUnion.map((unit) => (
<li key={unit} className="contents"> <li key={unit} className="contents">
<button <button
className="flex items-center gap-2 py-1 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left" className="flex items-center gap-2 m-0 py-1.5 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left"
onClick={() => { onClick={() => {
settings.send({ settings.send({
type: 'set.modeling.defaultUnit', type: 'set.modeling.defaultUnit',

View File

@ -1,18 +1,20 @@
import { Popover, Transition } from '@headlessui/react' import { Popover, Transition } from '@headlessui/react'
import { ActionButton } from './ActionButton' import { ActionButton, ActionButtonProps } from './ActionButton'
import { faBug, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'
import { faGithub } from '@fortawesome/free-brands-svg-icons'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { Fragment, useState } from 'react' import { Fragment, useMemo, useState } from 'react'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
import usePlatform from 'hooks/usePlatform'
import { isTauri } from 'lib/isTauri'
import { CustomIcon } from './CustomIcon'
type User = Models['User_type'] type User = Models['User_type']
const UserSidebarMenu = ({ user }: { user?: User }) => { const UserSidebarMenu = ({ user }: { user?: User }) => {
const platform = usePlatform()
const location = useLocation() const location = useLocation()
const filePath = useAbsoluteFilePath() const filePath = useAbsoluteFilePath()
const displayedName = getDisplayName(user) const displayedName = getDisplayName(user)
@ -20,6 +22,128 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
const navigate = useNavigate() const navigate = useNavigate()
const send = useSettingsAuthContext()?.auth?.send const send = useSettingsAuthContext()?.auth?.send
// We filter this memoized list so that no orphan "break" elements are rendered.
const userMenuItems = useMemo<(ActionButtonProps | 'break')[]>(
() =>
[
{
id: 'settings',
Element: 'button',
children: (
<>
<span className="flex-1">User settings</span>
<kbd className="hotkey">{`${platform === 'macos' ? '⌘' : 'Ctrl'}${
isTauri() ? '' : '⬆'
},`}</kbd>
</>
),
'data-testid': 'user-settings',
onClick: () => {
const targetPath = location.pathname.includes(paths.FILE)
? filePath + paths.SETTINGS
: paths.HOME + paths.SETTINGS
navigate(targetPath + '?tab=user')
},
},
{
id: 'keybindings',
Element: 'button',
children: 'Keyboard shortcuts',
onClick: () => {
const targetPath = location.pathname.includes(paths.FILE)
? filePath + paths.SETTINGS
: paths.HOME + paths.SETTINGS
navigate(targetPath + '?tab=keybindings')
},
},
{
id: 'account',
Element: 'externalLink',
to: 'https://zoo.dev/account',
children: (
<>
<span className="flex-1">Manage account</span>
<CustomIcon
name="link"
className="w-3 h-3 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
),
},
'break',
{
id: 'request-feature',
Element: 'externalLink',
to: 'https://github.com/KittyCAD/modeling-app/discussions',
children: (
<>
<span className="flex-1">Request a feature</span>
<CustomIcon
name="link"
className="w-3 h-3 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
),
},
{
id: 'report-bug',
Element: 'externalLink',
to: 'https://github.com/KittyCAD/modeling-app/issues/new/choose',
children: (
<>
<span className="flex-1">Report a bug</span>
<CustomIcon
name="link"
className="w-3 h-3 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
),
},
{
id: 'community',
Element: 'externalLink',
to: 'https://discord.gg/JQEpHR7Nt2',
children: (
<>
<span className="flex-1">Ask the community</span>
<CustomIcon
name="link"
className="w-3 h-3 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
),
},
{
id: 'release-notes',
Element: 'externalLink',
to: 'https://github.com/KittyCAD/modeling-app/releases',
children: (
<>
<span className="flex-1">Release notes</span>
<CustomIcon
name="link"
className="w-3 h-3 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
),
},
'break',
{
id: 'sign-out',
Element: 'button',
'data-testid': 'user-sidebar-sign-out',
children: 'Sign out',
onClick: () => send('Log out'),
className: '', // Just making TS's filter type coercion happy 😠
},
].filter(
(props) =>
props === 'break' ||
(typeof props !== 'string' && !props.className?.includes('hidden'))
) as (ActionButtonProps | 'break')[],
[platform, location, filePath, navigate, send]
)
// This image host goes down sometimes. We will instead rewrite the // This image host goes down sometimes. We will instead rewrite the
// resource to be a local one. // resource to be a local one.
if (user?.image === 'https://placekitten.com/200/200') { if (user?.image === 'https://placekitten.com/200/200') {
@ -43,76 +167,52 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
return ( return (
<Popover className="relative"> <Popover className="relative">
{user?.image && !imageLoadFailed ? (
<Popover.Button <Popover.Button
className="relative border-0 rounded-full w-fit min-w-max p-0 group" className="relative group border-0 w-fit min-w-max p-0 rounded-l-full focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary"
data-testid="user-sidebar-toggle" data-testid="user-sidebar-toggle"
> >
<div className="flex items-center">
<div className="rounded-full border overflow-hidden"> <div className="rounded-full border overflow-hidden">
{user?.image && !imageLoadFailed ? (
<img <img
src={user?.image || ''} src={user?.image || ''}
alt={user?.name || ''} alt={user?.name || ''}
className="h-8 w-8 rounded-full" className="h-7 w-7 rounded-full"
referrerPolicy="no-referrer" referrerPolicy="no-referrer"
onError={() => setImageLoadFailed(true)} onError={() => setImageLoadFailed(true)}
/> />
) : (
<CustomIcon
name="person"
className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40 bg-chalkboard-20 dark:bg-chalkboard-80"
/>
)}
</div> </div>
<Tooltip position="bottom-right" delay={1000}> <CustomIcon
name="caretDown"
className="w-4 h-4 text-chalkboard-70 dark:text-chalkboard-40 ui-open:rotate-180"
/>
</div>
<Tooltip position="bottom-right" delay={1000} hoverOnly>
User menu User menu
</Tooltip> </Tooltip>
</Popover.Button> </Popover.Button>
) : (
<ActionButton
Element={Popover.Button}
iconStart={{ icon: 'menu' }}
className="border-transparent !px-0"
data-testid="user-sidebar-toggle"
>
<Tooltip position="bottom-right" delay={1000}>
User menu
</Tooltip>
</ActionButton>
)}
<Transition
enter="duration-200 ease-out"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="duration-100 ease-in"
leaveFrom="opacity-100"
leaveTo="opacity-0"
as={Fragment}
>
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
</Transition>
<Transition <Transition
enter="duration-100 ease-out" enter="duration-100 ease-out"
enterFrom="opacity-0 translate-x-1/4" enterFrom="opacity-0 -translate-y-2"
enterTo="opacity-100 translate-x-0" enterTo="opacity-100 translate-y-0"
leave="duration-75 ease-in"
leaveFrom="opacity-100 translate-x-0"
leaveTo="opacity-0 translate-x-4"
as={Fragment} as={Fragment}
> >
<Popover.Panel className="fixed inset-0 left-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-90 border border-chalkboard-30 dark:border-chalkboard-80 shadow-md rounded-l-md overflow-hidden"> <Popover.Panel
className={`z-10 absolute top-full right-0 mt-1 pb-1 w-48 bg-chalkboard-10 dark:bg-chalkboard-90
border border-solid border-chalkboard-20 dark:border-chalkboard-90 rounded
shadow-lg`}
>
{({ close }) => ( {({ close }) => (
<> <>
{user && ( {user && (
<div className="flex items-center gap-4 px-4 py-3 bg-chalkboard-20/50 dark:bg-chalkboard-80/50 border-b border-b-chalkboard-30 dark:border-b-chalkboard-80"> <div className="flex flex-col gap-1 px-2.5 py-3 bg-chalkboard-20 dark:bg-chalkboard-80/50">
{user.image && !imageLoadFailed && ( <p className="m-0 text-mono text-xs" data-testid="username">
<div className="rounded-full shadow-inner overflow-hidden">
<img
src={user.image}
alt={user.name || ''}
className="h-8 w-8"
referrerPolicy="no-referrer"
onError={() => setImageLoadFailed(true)}
/>
</div>
)}
<div>
<p className="m-0 text-mono" data-testid="username">
{displayedName || ''} {displayedName || ''}
</p> </p>
{displayedName !== user.email && ( {displayedName !== user.email && (
@ -124,58 +224,33 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
</p> </p>
)} )}
</div> </div>
</div>
)} )}
<div className="p-4 flex flex-col gap-2"> <ul className="relative flex flex-col items-stretch content-stretch p-0.5">
{userMenuItems.map((props, index) => {
if (props === 'break') {
return index !== userMenuItems.length - 1 ? (
<li key={`break-${index}`} className="contents">
<hr className="border-chalkboard-20 dark:border-chalkboard-80" />
</li>
) : null
}
const { id, children, ...rest } = props
return (
<li key={id} className="contents">
<ActionButton <ActionButton
Element="button" {...rest}
iconStart={{ icon: 'settings' }} className="!font-sans flex items-center gap-2 rounded-sm py-1.5 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left"
className="border-transparent dark:border-transparent hover:bg-transparent" onMouseUp={() => {
onClick={() => {
// since /settings is a nested route the sidebar doesn't close
// automatically when navigating to it
close() close()
const targetPath = location.pathname.includes(paths.FILE)
? filePath + paths.SETTINGS
: paths.HOME + paths.SETTINGS
navigate(targetPath)
}} }}
data-testid="settings-button"
> >
Settings {children}
</ActionButton> </ActionButton>
<ActionButton </li>
Element="externalLink" )
to="https://github.com/KittyCAD/modeling-app/discussions" })}
iconStart={{ icon: faGithub, className: 'p-1', size: 'sm' }} </ul>
className="border-transparent dark:border-transparent"
>
Request a feature
</ActionButton>
<ActionButton
Element="externalLink"
to="https://github.com/KittyCAD/modeling-app/issues/new/choose"
iconStart={{ icon: faBug, className: 'p-1', size: 'sm' }}
className="border-transparent dark:border-transparent"
>
Report a bug
</ActionButton>
<ActionButton
Element="button"
onClick={() => send('Log out')}
iconStart={{
icon: faSignOutAlt,
className: 'p-1',
bgClassName: '!bg-transparent',
size: 'sm',
iconClassName: '!text-destroy-70',
}}
className="border-transparent dark:border-transparent hover:border-destroy-40 dark:hover:border-destroy-60 hover:bg-destroy-10/20 dark:hover:bg-destroy-80/20"
data-testid="user-sidebar-sign-out"
>
Sign out
</ActionButton>
</div>
</> </>
)} )}
</Popover.Panel> </Popover.Panel>

View File

@ -260,8 +260,17 @@ code {
@layer components { @layer components {
kbd.hotkey { kbd.hotkey {
@apply font-mono text-xs inline-block px-1 py-0.5 rounded-sm; @apply font-mono text-xs inline-block px-0.5 py-[2px] rounded;
/* This is the only place in our code where layout is impacted by theme.
* We may not want that later, if hotkeys are possibly visible
* while switching theme, but more padding feels better in dark mode.
*/
@apply dark:px-1;
@apply text-chalkboard-70 dark:text-chalkboard-40;
@apply bg-chalkboard-20 dark:bg-chalkboard-90; @apply bg-chalkboard-20 dark:bg-chalkboard-90;
@apply border border-t-0 border-b-2 border-chalkboard-30 dark:border-chalkboard-80;
} }
} }