diff --git a/src/lib/components/bottom-nav-settings.svelte b/src/lib/components/bottom-nav-settings.svelte index 5b5f73b61c..e0a4b0579b 100644 --- a/src/lib/components/bottom-nav-settings.svelte +++ b/src/lib/components/bottom-nav-settings.svelte @@ -28,8 +28,14 @@ class="flex h-full flex-col justify-start gap-6 overflow-auto px-4 py-8" data-theme="dark" > - - +
+

Timezone

+ +
+
+

{translate('common.theme')}

+ +

- + {translate('common.user-profile')} {/if} diff --git a/src/lib/components/dark-mode-menu.svelte b/src/lib/components/dark-mode-menu.svelte index e928cdef21..128f171cb7 100644 --- a/src/lib/components/dark-mode-menu.svelte +++ b/src/lib/components/dark-mode-menu.svelte @@ -1,12 +1,7 @@ - - + setDarkModePreference('system')} + active={$useDarkModePreference === 'system'} + size="xs" + > + + + setDarkModePreference(false)} + active={$useDarkModePreference === false} + size="xs" + > + + + setDarkModePreference(true)} + active={$useDarkModePreference === true} + size="xs" > - {#if !hideLabel}{menuButtonText}{/if} - - - - setDarkModePreference(true)} - selected={$useDarkModePreference === true} - data-testid="night-mode" - > - - Night - - setDarkModePreference(false)} - selected={$useDarkModePreference === false} - data-testid="day-mode" - > - - Day - - setDarkModePreference('system')} - selected={$useDarkModePreference === 'system'} - data-testid="system-mode" - > - - System Default - - - + + + diff --git a/src/lib/components/timezone-select.svelte b/src/lib/components/timezone-select.svelte index 2be623ba84..51c2b42944 100644 --- a/src/lib/components/timezone-select.svelte +++ b/src/lib/components/timezone-select.svelte @@ -75,7 +75,7 @@ }); - + + import { MediaQuery } from 'svelte/reactivity'; + import { type ClassNameValue, twMerge as merge } from 'tailwind-merge'; - import DarkModeMenu from '$lib/components/dark-mode-menu.svelte'; import DataEncoderStatus from '$lib/components/data-encoder-status.svelte'; import TimezoneSelect from '$lib/components/timezone-select.svelte'; import { translate } from '$lib/i18n/translate'; - let screenWidth: number; - let className: ClassNameValue = ''; export { className as class }; - export let onThemeChange: (prefersDarkMode: boolean) => void = () => {}; + + const md = new MediaQuery('min-width:768px'); - - +{#if md.current} + +{/if} diff --git a/src/lib/holocene/menu/menu-item.svelte b/src/lib/holocene/menu/menu-item.svelte index c99861aaf1..c28aa52b4f 100644 --- a/src/lib/holocene/menu/menu-item.svelte +++ b/src/lib/holocene/menu/menu-item.svelte @@ -128,11 +128,11 @@ 'menu-item', 'm-1 px-3 py-2', 'flex items-center gap-2', + centered ? 'justify-center' : 'justify-between', className, )} class:disabled class:hoverable - class:justify-center={centered} aria-hidden={disabled ? 'true' : 'false'} aria-disabled={disabled} tabindex={disabled ? -1 : 0} @@ -142,7 +142,12 @@ on:keydown|stopPropagation={handleKeydown} {...$$restProps} > - +
+ +
+ {#if newTab} + + {/if} {:else}
  • .menu-item { - @apply cursor-pointer border border-transparent text-sm font-medium focus-visible:border-inverse focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/70 dark:focus-visible:border-interactive; + @apply cursor-pointer border border-transparent text-sm focus-visible:border-inverse focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/70 dark:focus-visible:border-interactive; &.hoverable { @apply hover:surface-interactive-secondary focus-visible:surface-interactive-secondary; diff --git a/src/lib/holocene/toggle-button/toggle-buttons.svelte b/src/lib/holocene/toggle-button/toggle-buttons.svelte index 08e1d9ce53..a6dd2de741 100644 --- a/src/lib/holocene/toggle-button/toggle-buttons.svelte +++ b/src/lib/holocene/toggle-button/toggle-buttons.svelte @@ -1,8 +1,19 @@ -
    - +
    + {@render children()}
    diff --git a/src/lib/holocene/user-menu.svelte b/src/lib/holocene/user-menu.svelte index 88fdb30818..12c763396a 100644 --- a/src/lib/holocene/user-menu.svelte +++ b/src/lib/holocene/user-menu.svelte @@ -1,4 +1,5 @@ -{#if $authUser.accessToken} - - + + + {#if $authUser.accessToken} {$authUser?.profile {/if}
    - - + {:else} + {translate('common.user-profile')} + {/if} + + + {#if $authUser.accessToken}
    @@ -53,6 +68,39 @@ {translate('common.log-out')}
    -
    - -{/if} + + {:else} + Anonymous Tardigrade + + {/if} + + {translate('common.theme')} + + + + + {translate('common.slack-community')} + + + {translate('common.community-forum')} + + + {translate('common.change-log')} + +
    + diff --git a/src/lib/i18n/locales/en/common.ts b/src/lib/i18n/locales/en/common.ts index 318bb2109e..bf2590b382 100644 --- a/src/lib/i18n/locales/en/common.ts +++ b/src/lib/i18n/locales/en/common.ts @@ -214,4 +214,8 @@ export const Strings = { 'Unable to complete operation after {{attempts}} attempts.', 'retry-support-message': 'Please refresh the page or contact support if the problem persists.', + theme: 'Theme', + 'slack-community': 'Slack Community', + 'community-forum': 'Community Forum', + 'change-log': 'Change Log', } as const; diff --git a/static/ziggy-full-face.png b/static/ziggy-full-face.png new file mode 100644 index 0000000000..72220fa410 Binary files /dev/null and b/static/ziggy-full-face.png differ diff --git a/tests/integration/dark-mode.desktop.spec.ts b/tests/integration/dark-mode.desktop.spec.ts index d0514ff9d6..a4c730fa2b 100644 --- a/tests/integration/dark-mode.desktop.spec.ts +++ b/tests/integration/dark-mode.desktop.spec.ts @@ -9,43 +9,31 @@ test.describe('Dark Mode Dropdown', () => { test.beforeEach(async ({ page }) => { await mockWorkflowsApis(page); await page.goto('/'); + await page.getByTestId('user-menu-trigger').click(); + const menuButton = page.getByTestId('dark-mode-toggle-buttons'); + await expect(menuButton).toBeVisible(); }); test('user can select System Default option via dropdown menu', async ({ page, }) => { - const menuButton = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(menuButton).toBeVisible(); - - await menuButton.click(); - await page.getByRole('menuitem', { name: 'System Default' }).click(); - await expect(menuButton).toHaveAccessibleName('System Default'); + const systemModeButton = page.getByTestId('system-mode'); + await expect(systemModeButton).toHaveAccessibleName('System Default'); + await systemModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, 'system'); }); test('user can select Night option via dropdown menu', async ({ page }) => { - const menuButton = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(menuButton).toBeVisible(); - - await menuButton.click(); - await page.getByTestId('night-mode').click(); - await expect(menuButton).toHaveAccessibleName('Night'); + const nightModeButton = page.getByTestId('night-mode'); + await expect(nightModeButton).toHaveAccessibleName('Night'); + await nightModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, true); }); test('user can select Day option via dropdown menu', async ({ page }) => { - const menuButton = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(menuButton).toBeVisible(); - - await menuButton.click(); - await page.getByTestId('day-mode').click(); - await expect(menuButton).toHaveAccessibleName('Day'); + const dayModeButton = page.getByTestId('day-mode'); + await expect(dayModeButton).toHaveAccessibleName('Day'); + await dayModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, false); }); }); diff --git a/tests/integration/dark-mode.mobile.spec.ts b/tests/integration/dark-mode.mobile.spec.ts index 10e1933178..b0085511ca 100644 --- a/tests/integration/dark-mode.mobile.spec.ts +++ b/tests/integration/dark-mode.mobile.spec.ts @@ -16,38 +16,23 @@ test.describe('Dark Mode Dropdown on Mobile', () => { test('user can select System Default option via dropdown menu', async ({ page, }) => { - const button = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(button).toBeVisible(); - - await button.click(); - await page.getByRole('menuitem', { name: 'System Default' }).click(); - await expect(button).toHaveAccessibleName('System Default'); + const systemModeButton = page.getByTestId('system-mode'); + await expect(systemModeButton).toHaveAccessibleName('System Default'); + await systemModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, 'system'); }); test('user can select Night option via dropdown menu', async ({ page }) => { - const button = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(button).toBeVisible(); - - await button.click(); - await page.getByRole('menuitem', { name: 'Night' }).click(); - await expect(button).toHaveAccessibleName('Night'); + const nightModeButton = page.getByTestId('night-mode'); + await expect(nightModeButton).toHaveAccessibleName('Night'); + await nightModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, true); }); test('user can select Day option via dropdown menu', async ({ page }) => { - const button = page - .getByTestId('dark-mode-menu-button') - .locator('visible=true'); - await expect(button).toBeVisible(); - - await button.click(); - await page.getByRole('menuitem', { name: 'Day' }).click(); - await expect(button).toHaveAccessibleName('Day'); + const dayModeButton = page.getByTestId('day-mode'); + await expect(dayModeButton).toHaveAccessibleName('Day'); + await dayModeButton.click(); await expect(page).toHaveLocalStorageItem(localStorageKey, false); }); });