diff --git a/apps/common/components/MobileNavbar.tsx b/apps/common/components/MobileNavbar.tsx
new file mode 100644
index 000000000..1ea2a01f1
--- /dev/null
+++ b/apps/common/components/MobileNavbar.tsx
@@ -0,0 +1,72 @@
+import Link from 'next/link';
+import {usePathname} from 'next/navigation';
+import {cl} from '@builtbymom/web3/utils';
+import {IconDiscord} from '@common/icons/IconDiscord';
+import {IconParagraph} from '@common/icons/IconParagraph';
+import {IconTwitter} from '@common/icons/IconTwitter';
+import {iconsDict, LANDING_SIDEBAR_LINKS, MENU_TABS} from '@common/utils/constants';
+
+import type {ReactElement} from 'react';
+
+export function MobileNavbar({onClose}: {onClose: VoidFunction}): ReactElement {
+ const pathName = usePathname();
+
+ const currentTab = pathName?.startsWith('/apps/') ? pathName?.split('/')[2] : 'apps';
+
+ return (
+
+
+ {MENU_TABS.map(tab => (
+
+
+ {iconsDict[tab.route as keyof typeof iconsDict]}
+
+
{tab.title}
+
+ ))}
+
+
+
+
+ {LANDING_SIDEBAR_LINKS.slice(0, 5).map(link => (
+
+ {link.title}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/common/components/MobileTopNav.tsx b/apps/common/components/MobileTopNav.tsx
new file mode 100644
index 000000000..bc46c9745
--- /dev/null
+++ b/apps/common/components/MobileTopNav.tsx
@@ -0,0 +1,79 @@
+import {type ReactElement, useCallback} from 'react';
+import {useRouter} from 'next/router';
+import {useSearch} from '@common/contexts/useSearch';
+import {IconBurgerPlain} from '@common/icons/IconBurgerPlain';
+import {IconCross} from '@common/icons/IconCross';
+import {IconSearch} from '@common/icons/IconSearch';
+import {LogoYearn} from '@common/icons/LogoYearn';
+
+import {SearchBar} from './SearchBar';
+
+export function MobileTopNav({
+ isSearchOpen,
+ isNavbarOpen,
+ set_isSearchOpen,
+ set_isNavbarOpen
+}: {
+ isSearchOpen: boolean;
+ isNavbarOpen: boolean;
+ set_isSearchOpen: React.Dispatch
>;
+ set_isNavbarOpen: React.Dispatch>;
+}): ReactElement {
+ const {configuration, dispatch} = useSearch();
+ const router = useRouter();
+
+ const onSearchClick = useCallback(() => {
+ if (!configuration.searchValue) {
+ router.push('/apps');
+ return;
+ }
+ router.push(`/apps/search/${encodeURIComponent(configuration.searchValue)}`);
+ }, [configuration.searchValue, router]);
+
+ return (
+
+
+
+
+
+
+
+
+
+ {isSearchOpen && (
+
+ dispatch({searchValue: value})}
+ searchPlaceholder={'Search App'}
+ onSearchClick={onSearchClick}
+ shouldSearchByClick
+ />
+
+ )}
+
+ );
+}
diff --git a/apps/common/components/ModalMobileMenu.tsx b/apps/common/components/ModalMobileMenu.tsx
new file mode 100644
index 000000000..0c4a8fdfa
--- /dev/null
+++ b/apps/common/components/ModalMobileMenu.tsx
@@ -0,0 +1,152 @@
+'use client';
+import React, {Fragment, useMemo} from 'react';
+import Link from 'next/link';
+import {Dialog, Transition, TransitionChild} from '@headlessui/react';
+import {IconArrow} from '@common/icons/IconArrow';
+import {IconClose} from '@common/icons/IconClose';
+import {IconDiscord} from '@common/icons/IconDiscord';
+import {IconParagraph} from '@common/icons/IconParagraph';
+import {IconTwitter} from '@common/icons/IconTwitter';
+import {LogoYearn} from '@common/icons/LogoYearn';
+
+import type {ReactElement, ReactNode} from 'react';
+import type {Chain} from 'viem';
+import type {TMenu} from '@yearn-finance/web-lib/components/Header';
+
+export function FooterNav(): ReactElement {
+ const menu = useMemo((): TMenu[] => {
+ const HOME_MENU = {path: '/apps', label: 'Apps'};
+
+ return [
+ HOME_MENU,
+ {
+ path: 'https://gov.yearn.fi/',
+ label: 'Governance',
+ target: '_blank'
+ },
+ {path: 'https://blog.yearn.fi/', label: 'Blog', target: '_blank'},
+ {path: 'https://docs.yearn.fi/', label: 'Docs', target: '_blank'},
+ {path: 'https://discord.gg/yearn', label: 'Support', target: '_blank'}
+ ];
+ }, []);
+
+ return (
+
+
+ {menu.map(link => (
+
+ {link.label}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+type TModalMobileMenu = {
+ isOpen: boolean;
+ shouldUseWallets: boolean;
+ shouldUseNetworks: boolean;
+ onClose: () => void;
+ children: ReactNode;
+ supportedNetworks: Chain[];
+};
+
+export type TModal = {
+ isOpen: boolean;
+ onClose: () => void;
+ children: ReactNode;
+} & React.ComponentPropsWithoutRef<'div'>;
+
+export function ModalMobileMenu(props: TModalMobileMenu): ReactElement {
+ const {isOpen, onClose} = props;
+
+ return (
+
+
+
+ );
+}
diff --git a/apps/common/components/Pagination.tsx b/apps/common/components/Pagination.tsx
index 1f0b0a1da..922b0b9b7 100644
--- a/apps/common/components/Pagination.tsx
+++ b/apps/common/components/Pagination.tsx
@@ -25,7 +25,7 @@ export function Pagination(props: TProps): ReactElement {
role={'button'}
href={'#'}
className={
- 'border-gray-300 text-gray-700 hover:bg-gray-50 relative inline-flex items-center rounded-md border px-4 py-2 text-sm font-medium'
+ 'hover:bg-gray-50 relative inline-flex items-center rounded-md border border-gray-300 px-4 py-2 text-sm font-medium text-gray-500'
}>
{'Previous'}
@@ -33,7 +33,7 @@ export function Pagination(props: TProps): ReactElement {
role={'button'}
href={'#'}
className={
- 'border-gray-300 text-gray-700 hover:bg-gray-50 relative ml-3 inline-flex items-center rounded-md border px-4 py-2 text-sm font-medium'
+ 'hover:bg-gray-50 relative ml-3 inline-flex items-center rounded-md border border-gray-300 px-4 py-2 text-sm font-medium text-gray-500'
}>
{'Next'}
diff --git a/apps/common/components/PromoPoster.tsx b/apps/common/components/PromoPoster.tsx
new file mode 100644
index 000000000..e4a474ffc
--- /dev/null
+++ b/apps/common/components/PromoPoster.tsx
@@ -0,0 +1,31 @@
+import Link from 'next/link';
+import {IconShare} from '@common/icons/IconShare';
+
+import type {ReactElement} from 'react';
+
+export function PromoPoster(): ReactElement {
+ return (
+
+
+ {'earn with'}
+
{'yearn'}
+
+
+
+
+
+
+
+
+ {
+ 'Yearn is a decentralized suite of products helping individuals, DAOs, and other protocols earn yield on their digital assets.'
+ }
+
+
+
+ );
+}
diff --git a/apps/common/components/SearchBar.tsx b/apps/common/components/SearchBar.tsx
index c1dad29b8..4bc3e61f9 100644
--- a/apps/common/components/SearchBar.tsx
+++ b/apps/common/components/SearchBar.tsx
@@ -1,4 +1,6 @@
import {cl} from '@builtbymom/web3/utils';
+import {IconEnter} from '@common/icons/IconEnter';
+import {IconSearch} from '@common/icons/IconSearch';
import type {ChangeEvent, ReactElement} from 'react';
@@ -9,6 +11,8 @@ type TSearchBar = {
className?: string;
iconClassName?: string;
inputClassName?: string;
+ shouldSearchByClick?: boolean;
+ onSearchClick?: () => void;
};
export function SearchBar(props: TSearchBar): ReactElement {
@@ -25,7 +29,7 @@ export function SearchBar(props: TSearchBar): ReactElement {
suppressHydrationWarning
className={cl(
props.inputClassName,
- 'h-10 w-full overflow-x-scroll border-none bg-transparent px-0 py-2 text-base outline-none scrollbar-none placeholder:text-neutral-400'
+ 'h-10 w-full overflow-x-scroll border-none bg-transparent pl-2 px-0 py-2 text-base outline-none scrollbar-none placeholder:text-neutral-400'
)}
type={'text'}
placeholder={props.searchPlaceholder}
@@ -33,23 +37,24 @@ export function SearchBar(props: TSearchBar): ReactElement {
onChange={(e: ChangeEvent): void => {
props.onSearch(e.target.value);
}}
+ onKeyDown={e => {
+ if (!props.shouldSearchByClick) return;
+ if (e.key === 'Enter') {
+ return props.onSearchClick?.();
+ }
+ }}
/>
-
-
+
props.onSearchClick?.()}
+ className={cl(props.iconClassName, 'absolute right-0 text-neutral-400')}>
+ {props.shouldSearchByClick && props.searchValue ? (
+
+
+
+ ) : (
+
+ )}
diff --git a/apps/common/components/Sidebar.tsx b/apps/common/components/Sidebar.tsx
new file mode 100644
index 000000000..26d5afa9e
--- /dev/null
+++ b/apps/common/components/Sidebar.tsx
@@ -0,0 +1,97 @@
+import {type ReactElement, useCallback} from 'react';
+import Link from 'next/link';
+import {usePathname} from 'next/navigation';
+import {useRouter} from 'next/router';
+import {cl} from '@builtbymom/web3/utils';
+import {useSearch} from '@common/contexts/useSearch';
+import {LogoYearn} from '@common/icons/LogoYearn';
+import {iconsDict, LANDING_SIDEBAR_LINKS} from '@common/utils/constants';
+
+import {PromoPoster} from './PromoPoster';
+import {SearchBar} from './SearchBar';
+
+type TSidebarProps = {
+ tabs: {route: string; title: string; isAcitve?: boolean}[];
+};
+
+export function Sidebar(props: TSidebarProps): ReactElement {
+ const pathName = usePathname();
+ const router = useRouter();
+ const {configuration, dispatch} = useSearch();
+
+ const currentTab = pathName?.startsWith('/apps/') ? pathName?.split('/')[2] : 'apps';
+
+ const onSearchClick = useCallback(() => {
+ if (!configuration.searchValue) {
+ router.push('/apps');
+ return;
+ }
+ router.push(`/apps/search/${encodeURIComponent(configuration.searchValue)}`);
+ }, [configuration.searchValue, router]);
+
+ return (
+