diff --git a/packages/suite-desktop-core/e2e/support/bridge.ts b/packages/suite-desktop-core/e2e/support/bridge.ts
index e5ecd31ac5e..09c0e6372c0 100644
--- a/packages/suite-desktop-core/e2e/support/bridge.ts
+++ b/packages/suite-desktop-core/e2e/support/bridge.ts
@@ -14,12 +14,12 @@ export const expectBridgeToBeStopped = async (request: APIRequestContext) => {
}).rejects.toThrow('ECONNREFUSED');
};
-// We wait for `@welcome/title` or `@dashboard/graph` since
+// We wait for `@welcome-layout/body` or `@dashboard/graph` since
// one or the other will be display depending on the state of the app
// due to previously run tests. And both means the same for the porpoise of this test.
// Bridge should be ready to check `/status` endpoint.
export const waitForAppToBeInitialized = async (suite: any) =>
await Promise.race([
- expect(suite.window.getByTestId('@welcome/title')).toBeVisible(),
+ expect(suite.window.getByTestId('@welcome-layout/body')).toBeVisible(),
expect(suite.window.getByTestId('@dashboard/graph')).toBeVisible(),
]);
diff --git a/packages/suite-desktop-core/e2e/support/pageActions/onboarding/onboardingActions.ts b/packages/suite-desktop-core/e2e/support/pageActions/onboarding/onboardingActions.ts
index 32acc39d604..fd389ffbc94 100644
--- a/packages/suite-desktop-core/e2e/support/pageActions/onboarding/onboardingActions.ts
+++ b/packages/suite-desktop-core/e2e/support/pageActions/onboarding/onboardingActions.ts
@@ -18,7 +18,7 @@ export class OnboardingActions {
readonly pin: PinActions;
readonly tutorial: TutorialActions;
- readonly welcomeTitle: Locator;
+ readonly welcomeBody: Locator;
readonly onboardingContinueButton: Locator;
readonly onboardingViewOnlySkipButton: Locator;
readonly onboardingViewOnlyEnableButton: Locator;
@@ -52,7 +52,7 @@ export class OnboardingActions {
this.tutorial = new TutorialActions(page);
this.pin = new PinActions(page);
- this.welcomeTitle = this.page.getByTestId('@welcome/title');
+ this.welcomeBody = this.page.getByTestId('@welcome-layout/body');
this.onboardingContinueButton = this.page.getByTestId('@onboarding/exit-app-button');
this.onboardingViewOnlySkipButton = this.page.getByTestId('@onboarding/viewOnly/skip');
this.onboardingViewOnlyEnableButton = this.page.getByTestId('@onboarding/viewOnly/enable');
@@ -83,7 +83,7 @@ export class OnboardingActions {
@step()
async verifySuiteIsLoaded() {
- await expect(this.welcomeTitle, 'expect Suite to load in under 30s').toBeVisible({
+ await expect(this.welcomeBody, 'expect Suite to load in under 30s').toBeVisible({
timeout: 30_000,
});
}
diff --git a/packages/suite-desktop-core/e2e/support/pageActions/settings/settingsActions.ts b/packages/suite-desktop-core/e2e/support/pageActions/settings/settingsActions.ts
index dede25fbd70..a1dc69ede77 100644
--- a/packages/suite-desktop-core/e2e/support/pageActions/settings/settingsActions.ts
+++ b/packages/suite-desktop-core/e2e/support/pageActions/settings/settingsActions.ts
@@ -88,7 +88,7 @@ export class SettingsActions {
'@settings/early-access-confirm-button',
);
this.earlyAccessSkipButton = this.page.getByTestId('@settings/early-access-skip-button');
- this.settingsCloseButton = this.page.getByTestId('@settings/menu/close');
+ this.settingsCloseButton = this.page.getByTestId('@suite/menu/suite-start');
this.modal = this.page.getByTestId('@modal');
this.modalCloseButton = this.page.getByTestId('@modal/close-button');
this.deviceLabelInput = this.page.getByTestId('@settings/device/label-input');
diff --git a/packages/suite-desktop-core/e2e/tests/bridge-tor/spawn-tor.test.ts b/packages/suite-desktop-core/e2e/tests/bridge-tor/spawn-tor.test.ts
index 478451e62c6..57bbb9dd35a 100644
--- a/packages/suite-desktop-core/e2e/tests/bridge-tor/spawn-tor.test.ts
+++ b/packages/suite-desktop-core/e2e/tests/bridge-tor/spawn-tor.test.ts
@@ -55,7 +55,7 @@ test.describe.skip('Tor loading screen', { tag: ['@group=suite', '@desktopOnly']
state: 'visible',
});
- await suite.window.waitForSelector('[data-testid="@welcome/title"]', { timeout });
+ await suite.window.waitForSelector('[data-testid="@welcome-layout/body"]', { timeout });
suite.electronApp.close();
});
@@ -83,7 +83,7 @@ test.describe.skip('Tor loading screen', { tag: ['@group=suite', '@desktopOnly']
state: 'visible',
});
- await suite.window.waitForSelector('[data-testid="@welcome/title"]', { timeout });
+ await suite.window.waitForSelector('[data-testid="@welcome-layout/body"]', { timeout });
networkAnalyzer.stop();
const requests = networkAnalyzer.getRequests();
requests.forEach(request => {
diff --git a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx
index f7d1f250f87..ea3325a720a 100644
--- a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx
+++ b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx
@@ -1,6 +1,7 @@
import * as envUtils from '@trezor/env-utils';
import { DeepPartial } from '@trezor/type-utils';
+import { desktopUpdateInitialState } from 'src/reducers/suite/desktopUpdateReducer';
import { configureStore } from 'src/support/tests/configureStore';
import { findByTestId, renderWithProviders } from 'src/support/tests/hooksHelper';
@@ -85,7 +86,9 @@ const getInitialState = ({ suite, router, device }: any = {}) => ({
discovery: [],
accountSearch: {},
settings: {},
+ blockchain: {},
},
+ desktopUpdate: desktopUpdateInitialState,
router: {
app: 'suite-index',
loaded: true,
diff --git a/packages/suite/src/components/suite/layouts/LoggedOutLayout.tsx b/packages/suite/src/components/suite/layouts/LoggedOutLayout.tsx
index 395c2b57125..3b21b9938a3 100644
--- a/packages/suite/src/components/suite/layouts/LoggedOutLayout.tsx
+++ b/packages/suite/src/components/suite/layouts/LoggedOutLayout.tsx
@@ -1,6 +1,6 @@
import { ReactNode, useRef, useState } from 'react';
-import { ElevationContext, ElevationUp, NewModal } from '@trezor/components';
+import { ElevationContext, ElevationDown, ElevationUp, NewModal } from '@trezor/components';
import { GuideButton, GuideRouter } from 'src/components/guide';
import { useLayoutSize } from 'src/hooks/suite';
@@ -10,7 +10,6 @@ import { LayoutContext, LayoutContextPayload } from 'src/support/suite/LayoutCon
import { ModalContextProvider } from 'src/support/suite/ModalContext';
import { Metadata } from '../Metadata';
-import { TrafficLightOffset } from '../TrafficLightOffset';
import {
AppWrapper,
Body,
@@ -19,6 +18,7 @@ import {
PageWrapper,
Wrapper,
} from './SuiteLayout/SuiteLayout';
+import { LoggedOutSidebar } from './WelcomeLayout/WelcomeLayout';
import { ModalSwitcher } from '../modals/ModalSwitcher/ModalSwitcher';
interface LoggedOutLayout {
@@ -36,38 +36,39 @@ export const LoggedOutLayout = ({ children }: LoggedOutLayout) => {
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
- {layoutHeader}
-
- {children}
-
-
-
-
-
+
+
+
+
+
+
+
+ {layoutHeader}
+
+ {children}
+
+
+
+
+
- {!isMobileLayout && }
-
-
-
-
-
-
+ {!isMobileLayout && }
+
+
+
+
+
);
};
diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/PageHeader/PageNames/SettingsName.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/PageHeader/PageNames/SettingsName.tsx
index e71d7dbe36d..dd59a2be9ba 100644
--- a/packages/suite/src/components/suite/layouts/SuiteLayout/PageHeader/PageNames/SettingsName.tsx
+++ b/packages/suite/src/components/suite/layouts/SuiteLayout/PageHeader/PageNames/SettingsName.tsx
@@ -2,15 +2,13 @@ import { useState } from 'react';
import styled from 'styled-components';
-import { IconButton } from '@trezor/components';
import { desktopApi } from '@trezor/suite-desktop-api';
import { spacingsPx } from '@trezor/theme';
-import { goto } from 'src/actions/suite/routerActions';
import { setDebugMode } from 'src/actions/suite/suiteActions';
import { Translation } from 'src/components/suite';
import { useDispatch, useSelector } from 'src/hooks/suite';
-import { selectIsDebugModeActive, selectIsLoggedOut } from 'src/reducers/suite/suiteReducer';
+import { selectIsDebugModeActive } from 'src/reducers/suite/suiteReducer';
import { HeaderHeading } from './BasicName';
@@ -22,7 +20,6 @@ const Container = styled.div`
export const SettingsName = () => {
const isDebugModeActive = useSelector(selectIsDebugModeActive);
- const isLoggedOut = useSelector(selectIsLoggedOut);
// show debug menu item after 5 clicks on "Settings" heading
const [clickCounter, setClickCounter] = useState(0);
@@ -51,20 +48,8 @@ export const SettingsName = () => {
}
};
- const handleBackClick = () => dispatch(goto('suite-start'));
-
return (
- {isLoggedOut && (
-
- )}
-
diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Navigation.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Navigation.tsx
index a5a565a1724..fe34cd63076 100644
--- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Navigation.tsx
+++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Navigation.tsx
@@ -2,13 +2,14 @@ import { FC } from 'react';
import styled from 'styled-components';
+import { Route } from '@suite-common/suite-types';
import { spacingsPx } from '@trezor/theme';
import { NavigationItem, NavigationItemProps } from './NavigationItem';
import { NotificationDropdown } from './NotificationDropdown';
import { useResponsiveContext } from '../../../../../support/suite/ResponsiveContext';
-const Nav = styled.nav<{ $isSidebarCollapsed: boolean }>`
+export const Nav = styled.nav<{ $isSidebarCollapsed: boolean }>`
display: flex;
flex-direction: column;
gap: ${spacingsPx.xxs};
@@ -18,6 +19,13 @@ const Nav = styled.nav<{ $isSidebarCollapsed: boolean }>`
${({ $isSidebarCollapsed }) => $isSidebarCollapsed && `align-items: center;`}
`;
+export const SETTINGS_ROUTES: Route['name'][] = [
+ 'settings-index',
+ 'settings-device',
+ 'settings-coins',
+ 'settings-debug',
+] as const;
+
const navItems: Array }> = [
{
nameId: 'TR_DASHBOARD',
@@ -34,7 +42,7 @@ const navItems: Array ({
tabIndex: 0,
@@ -77,6 +75,7 @@ const Container = styled(NavigationItemBase)<{
export interface NavigationItemProps {
nameId: TranslationKey;
icon: IconName;
+ expanded?: boolean;
routes?: Route['name'][];
goToRoute?: Route['name'];
preserveParams?: boolean;
@@ -98,10 +97,11 @@ type TitleProps = {
const Title = ({ nameId, values }: TitleProps) => ;
-const NavItem = (props: NavigationItemProps) => {
+export const NavItem = (props: NavigationItemProps) => {
const {
nameId,
icon,
+ expanded,
routes,
goToRoute,
isActive,
@@ -144,39 +144,34 @@ const NavItem = (props: NavigationItemProps) => {
$isRounded={isRounded}
$typographyStyle={typographyStyle}
>
-
-
-
-
-
-
- {itemsCount && (
-
- {itemsCount}
+ }
+ isActive={!expanded}
+ placement="right"
+ hasArrow
+ >
+
+
+ {expanded && (
+ <>
+
+
- )}
-
+
+ {itemsCount && (
+
+ {itemsCount}
+
+ )}
+ >
+ )}
);
};
export const NavigationItem = (props: NavigationItemProps) => {
- const { nameId, values } = props;
+ const { isSidebarCollapsed } = useResponsiveContext();
- return (
- <>
-
- }
- placement="right"
- hasArrow
- >
-
-
-
-
-
-
- >
- );
+ return ;
};
diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx
index f58457f17f7..68abe1966d2 100644
--- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx
+++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx
@@ -7,7 +7,6 @@ import { DebugAndExperimental } from './DebugAndExperimental';
import { HideBalances } from './HideBalances';
import { Tor } from './Tor';
import { UpdateStatusActionBarIcon } from './Update/UpdateStatusActionBarIcon';
-import { useResponsiveContext } from '../../../../../../support/suite/ResponsiveContext';
const ActionsContainer = styled.div<{ $isSidebarCollapsed: boolean }>`
display: flex;
@@ -25,21 +24,21 @@ const ActionsContainer = styled.div<{ $isSidebarCollapsed: boolean }>`
`;
type QuickActionsProps = {
- showUpdateBannerNotification: boolean;
+ isSidebarCollapsed: boolean;
+ showUpdateBannerNotification?: boolean;
};
-export const QuickActions = ({ showUpdateBannerNotification }: QuickActionsProps) => {
- const { isSidebarCollapsed } = useResponsiveContext();
-
- return (
-
-
-
-
-
-
-
- );
-};
+export const QuickActions = ({
+ isSidebarCollapsed,
+ showUpdateBannerNotification,
+}: QuickActionsProps) => (
+
+
+
+
+
+
+
+);
diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx
index abff6d072dc..1f21b56f91d 100644
--- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx
+++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx
@@ -37,6 +37,8 @@ const Content = styled.div`
flex-direction: column;
`;
+export const SIDEBAR_MIN_WIDTH = 84;
+
export const Sidebar = () => {
const [closedNotificationDevice, setClosedNotificationDevice] = useState(false);
const [closedNotificationSuite, setClosedNotificationSuite] = useState(false);
@@ -75,7 +77,7 @@ export const Sidebar = () => {
{
)}
diff --git a/packages/suite/src/components/suite/layouts/WelcomeLayout/WelcomeLayout.tsx b/packages/suite/src/components/suite/layouts/WelcomeLayout/WelcomeLayout.tsx
index 615d66272d1..2116db2c6c0 100644
--- a/packages/suite/src/components/suite/layouts/WelcomeLayout/WelcomeLayout.tsx
+++ b/packages/suite/src/components/suite/layouts/WelcomeLayout/WelcomeLayout.tsx
@@ -1,68 +1,39 @@
import { ReactNode } from 'react';
-import { AnimatePresence, motion } from 'framer-motion';
import styled from 'styled-components';
import { selectBannerMessage } from '@suite-common/message-system';
import {
- Button,
Column,
- ElevationContext,
ElevationDown,
ElevationUp,
Row,
useElevation,
variables,
} from '@trezor/components';
-import { isWeb } from '@trezor/env-utils';
-import { TrezorLogo } from '@trezor/product-components';
-import { useOnce } from '@trezor/react-utils';
-import { Elevation, mapElevationToBackground, spacings, spacingsPx } from '@trezor/theme';
-import { SUITE_URL, TREZOR_URL } from '@trezor/urls';
+import {
+ Elevation,
+ mapElevationToBackground,
+ mapElevationToBorder,
+ spacings,
+ spacingsPx,
+} from '@trezor/theme';
import { GuideButton, GuideRouter } from 'src/components/guide';
-import { Translation } from 'src/components/suite';
// importing directly, otherwise unit tests fail, seems to be a styled-components issue
import { MessageSystemBanner } from 'src/components/suite/banners';
import { MAX_ONBOARDING_WIDTH } from 'src/constants/suite/layout';
-import { useGuide } from 'src/hooks/guide';
import { useSelector } from 'src/hooks/suite';
-import { NavSettings } from './NavSettings';
import { TrafficLightOffset } from '../../TrafficLightOffset';
-
-const Expander = styled.div`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- flex: 1;
- margin-top: 96px;
-`;
+import { Nav, SETTINGS_ROUTES } from '../SuiteLayout/Sidebar/Navigation';
+import { NavItem } from '../SuiteLayout/Sidebar/NavigationItem';
+import { QuickActions } from '../SuiteLayout/Sidebar/QuickActions/QuickActions';
+import { SIDEBAR_MIN_WIDTH } from '../SuiteLayout/Sidebar/Sidebar';
const WelcomeWrapper = styled.div<{ $elevation: Elevation }>`
background-color: ${mapElevationToBackground};
height: 100%;
-
- @media (max-width: ${variables.SCREEN_SIZE.MD}) {
- display: none;
- }
-`;
-
-const MotionWelcome = styled(motion.div)`
- height: 100%;
- overflow: hidden;
- min-width: 380px;
- max-width: 660px;
-`;
-
-const LinksContainer = styled.div`
- bottom: 0;
- display: flex;
- margin: ${spacingsPx.xl};
- align-items: center;
- flex-flow: row wrap;
- gap: ${spacingsPx.md};
`;
const Content = styled.div<{ $elevation: Elevation }>`
@@ -80,11 +51,6 @@ const Content = styled.div<{ $elevation: Elevation }>`
}
`;
-const SettingsWrapper = styled.div`
- position: absolute;
- align-self: flex-end;
-`;
-
const ChildrenWrapper = styled.div`
display: flex;
flex: 1;
@@ -99,65 +65,42 @@ interface WelcomeLayoutProps {
children: ReactNode;
}
-const Left = () => {
- const { elevation } = useElevation();
-
- const { isGuideOpen, isGuideOnTop } = useGuide();
+const WelcomeNavColumn = styled.div<{ $elevation: Elevation; $minWidth: number }>`
+ border-right: solid 1px ${mapElevationToBorder};
+ min-width: ${({ $minWidth }) => $minWidth}px;
+ height: 100%;
+`;
- // do not animate welcome bar on initial load
- const isFirstRender = useOnce(true, false);
+export const LoggedOutSidebar = () => {
+ const { elevation } = useElevation();
return (
-
- {(!isGuideOpen || isGuideOnTop) && (
-
-
-
-
-
-
-
-
- {isWeb() && (
-
- )}
-
-
-
-
-
- )}
-
+
+
+
+
+
+
+
+
+
+
);
};
@@ -167,10 +110,6 @@ const Right = ({ children }: { children: ReactNode }) => {
return (
-
-
-
-
{children}
@@ -184,25 +123,23 @@ export const WelcomeLayout = ({ children }: WelcomeLayoutProps) => {
const bannerMessage = useSelector(selectBannerMessage);
return (
-
-
-
- {bannerMessage && (
-
- )}
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-
+
+
+ {bannerMessage && (
+
+ )}
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
);
};
diff --git a/packages/suite/src/reducers/suite/desktopUpdateReducer.ts b/packages/suite/src/reducers/suite/desktopUpdateReducer.ts
index eb465b0c20b..64a9edbd3d4 100644
--- a/packages/suite/src/reducers/suite/desktopUpdateReducer.ts
+++ b/packages/suite/src/reducers/suite/desktopUpdateReducer.ts
@@ -46,6 +46,8 @@ const initialState: DesktopUpdateState = {
justUpdatedInteractedWith: false,
};
+export const desktopUpdateInitialState = initialState;
+
const desktopUpdateReducer = (
state: DesktopUpdateState = initialState,
action: Action,