diff --git a/app/client/src/assets/icons/ads/two-line-hamburger.svg b/app/client/src/assets/icons/ads/two-line-hamburger.svg
new file mode 100644
index 0000000000..b613452efc
--- /dev/null
+++ b/app/client/src/assets/icons/ads/two-line-hamburger.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/client/src/components/ads/Icon.tsx b/app/client/src/components/ads/Icon.tsx
index 2f5197f0e1..af35937949 100644
--- a/app/client/src/components/ads/Icon.tsx
+++ b/app/client/src/components/ads/Icon.tsx
@@ -143,6 +143,7 @@ import EditBoxLineIcon from "remixicon-react/EditBoxLineIcon";
import StarLineIcon from "remixicon-react/StarLineIcon";
import StarFillIcon from "remixicon-react/StarFillIcon";
import Settings2LineIcon from "remixicon-react/Settings2LineIcon";
+import HamburgerIcon from "remixicon-react/MenuLineIcon";
import MagicLineIcon from "remixicon-react/MagicLineIcon";
export enum IconSize {
@@ -356,6 +357,7 @@ const ICON_LOOKUP = {
warning: ,
widget: ,
workspace: ,
+ hamburger: ,
};
export const IconCollection = Object.keys(ICON_LOOKUP);
diff --git a/app/client/src/components/ads/SearchInput.tsx b/app/client/src/components/ads/SearchInput.tsx
index a52b0561c3..44a3f1d6dc 100644
--- a/app/client/src/components/ads/SearchInput.tsx
+++ b/app/client/src/components/ads/SearchInput.tsx
@@ -18,14 +18,16 @@ export enum SearchVariant {
}
export type TextInputProps = CommonComponentProps & {
+ border?: boolean;
placeholder?: string;
fill?: boolean;
defaultValue?: string;
variant?: SearchVariant;
+ width?: string;
onChange?: (value: string) => void;
};
-const SearchInputWrapper = styled.div`
+const SearchInputWrapper = styled.div<{ border?: boolean }>`
& > div {
border: none;
@@ -45,6 +47,16 @@ const SearchInputWrapper = styled.div`
& input {
padding: 0 8px;
}
+
+ ${({ border }) =>
+ border &&
+ `
+ border: 1.2px solid var(--appsmith-search-input-mobile-border-color);
+
+ &:active, &:focus, &:hover {
+ border-color: var(--appsmith-search-input-focus-mobile-border-color);
+ }
+ `}
}
`;
@@ -82,7 +94,7 @@ const SearchInput = forwardRef(
return props.onChange && props.onChange("");
}, [props]);
return (
-
+
) : null
}
- width="228px"
+ width={props.width ? props.width : "228px"}
/>
);
diff --git a/app/client/src/constants/AppConstants.ts b/app/client/src/constants/AppConstants.ts
index e75a8c8fe9..1065e1ab5a 100644
--- a/app/client/src/constants/AppConstants.ts
+++ b/app/client/src/constants/AppConstants.ts
@@ -32,3 +32,8 @@ export const getPersistentAppStore = (appId: string, branch?: string) => {
};
export const TOOLTIP_HOVER_ON_DELAY = 1000;
+
+export const MOBILE_MAX_WIDTH = 767;
+export const TABLET_MIN_WIDTH = 768;
+export const TABLET_MAX_WIDTH = 991;
+export const DESKTOP_MIN_WIDTH = 992;
diff --git a/app/client/src/constants/Colors.tsx b/app/client/src/constants/Colors.tsx
index 00bead750a..8b2c1d78c3 100644
--- a/app/client/src/constants/Colors.tsx
+++ b/app/client/src/constants/Colors.tsx
@@ -86,6 +86,7 @@ export const Colors = {
LIGHT_GREY2: "#C4C4C4",
Gallery: "#F0F0F0",
GALLERY_1: "#EBEBEB",
+ GALLERY_2: "#EDEDED",
Galliano: "#E0B30E",
ROYAL_BLUE: "#457AE6",
ALTO2: "#E0DEDE",
diff --git a/app/client/src/pages/Applications/ApplicationCard.tsx b/app/client/src/pages/Applications/ApplicationCard.tsx
index 09bff99d18..7e76ff99af 100644
--- a/app/client/src/pages/Applications/ApplicationCard.tsx
+++ b/app/client/src/pages/Applications/ApplicationCard.tsx
@@ -21,7 +21,7 @@ import {
getApplicationIcon,
getRandomPaletteColor,
} from "utils/AppsmithUtils";
-import { omit } from "lodash";
+import { noop, omit } from "lodash";
import Text, { TextType } from "components/ads/Text";
import Button, { Category, Size, IconPositions } from "components/ads/Button";
import Icon, { IconSize } from "components/ads/Icon";
@@ -161,6 +161,7 @@ const Wrapper = styled(
props: ICardProps & {
hasReadPermission?: boolean;
backgroundColor: string;
+ isMobile?: boolean;
},
) => ,
)`
@@ -191,6 +192,13 @@ const Wrapper = styled(
}
}
}
+
+ ${({ isMobile }) =>
+ isMobile &&
+ `
+ width: 100% !important;
+ height: 126px !important;
+ `}
`;
const ApplicationImage = styled.div`
@@ -283,6 +291,7 @@ type ApplicationCardProps = {
delete?: (applicationId: string) => void;
update?: (id: string, data: UpdateApplicationPayload) => void;
enableImportExport?: boolean;
+ isMobile?: boolean;
};
const EditButton = styled(Button)`
@@ -391,9 +400,10 @@ function GitConnectedBadge() {
);
}
-const Container = styled.div`
+const Container = styled.div<{ isMobile?: boolean }>`
position: relative;
overflow: visible;
+ ${({ isMobile }) => isMobile && `width: 100%;`}
`;
export function ApplicationCard(props: ApplicationCardProps) {
@@ -703,8 +713,15 @@ export function ApplicationCard(props: ApplicationCardProps) {
return editedBy + " edited " + editedOn;
};
+ const LaunchAppInMobile = () => {
+ window.location.href = viewApplicationURL;
+ };
+
return (
-
+
@@ -746,7 +764,7 @@ export function ApplicationCard(props: ApplicationCardProps) {
appNameText
)}
- {showOverlay && (
+ {showOverlay && !props.isMobile && (
@@ -781,7 +799,7 @@ export function ApplicationCard(props: ApplicationCardProps) {
{editedByText()}
- {!!moreActionItems.length && ContextMenu}
+ {!!moreActionItems.length && !props.isMobile && ContextMenu}
{showGitBadge && }
diff --git a/app/client/src/pages/Applications/index.tsx b/app/client/src/pages/Applications/index.tsx
index fd84040843..f99073bf06 100644
--- a/app/client/src/pages/Applications/index.tsx
+++ b/app/client/src/pages/Applications/index.tsx
@@ -95,31 +95,40 @@ import getFeatureFlags from "utils/featureFlags";
import { setIsImportAppViaGitModalOpen } from "actions/gitSyncActions";
import SharedUserList from "pages/common/SharedUserList";
import { getOnboardingOrganisations } from "selectors/onboardingSelectors";
+import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
+import { Indices } from "constants/Layers";
import { getAppsmithConfigs } from "@appsmith/configs";
import AnalyticsUtil from "utils/AnalyticsUtil";
-const OrgDropDown = styled.div`
+const OrgDropDown = styled.div<{ isMobile?: boolean }>`
display: flex;
- padding: ${(props) => props.theme.spaces[4]}px
- ${(props) => props.theme.spaces[4]}px;
+ padding: ${(props) => (props.isMobile ? `10px 16px` : `10px 10px`)};
font-size: ${(props) => props.theme.fontSizes[1]}px;
justify-content: space-between;
align-items: center;
+ ${({ isMobile }) =>
+ isMobile &&
+ `
+ position: sticky;
+ top: 0;
+ background-color: #fff;
+ z-index: ${Indices.Layer8};
+ `}
`;
-const ApplicationCardsWrapper = styled.div`
+const ApplicationCardsWrapper = styled.div<{ isMobile?: boolean }>`
display: flex;
flex-wrap: wrap;
- gap: 20px;
+ gap: ${({ isMobile }) => (isMobile ? 12 : 20)}px;
font-size: ${(props) => props.theme.fontSizes[4]}px;
- padding: 10px;
+ padding: ${({ isMobile }) => (isMobile ? `10px 16px` : `10px`)};
`;
-const OrgSection = styled.div`
- margin-bottom: 40px;
+const OrgSection = styled.div<{ isMobile?: boolean }>`
+ margin-bottom: ${({ isMobile }) => (isMobile ? `8` : `40`)}px;
`;
-const PaddingWrapper = styled.div`
+const PaddingWrapper = styled.div<{ isMobile?: boolean }>`
display: flex;
align-items: baseline;
justify-content: center;
@@ -184,6 +193,12 @@ const PaddingWrapper = styled.div`
height: ${(props) => props.theme.card.minHeight - 15}px;
}
}
+
+ ${({ isMobile }) =>
+ isMobile &&
+ `
+ width: 100% !important;
+ `}
`;
const LeftPaneWrapper = styled.div`
@@ -198,7 +213,7 @@ const LeftPaneWrapper = styled.div`
top: ${(props) => props.theme.homePage.header}px;
box-shadow: 1px 0px 0px #ededed;
`;
-const ApplicationContainer = styled.div`
+const ApplicationContainer = styled.div<{ isMobile?: boolean }>`
height: calc(100vh - ${(props) => props.theme.homePage.search.height - 40}px);
overflow: auto;
padding-right: ${(props) => props.theme.homePage.leftPane.rightMargin}px;
@@ -215,6 +230,13 @@ const ApplicationContainer = styled.div`
props.theme.homePage.leftPane.leftPadding}px
);
scroll-behavior: smooth;
+ ${({ isMobile }) =>
+ isMobile &&
+ `
+ margin-left: 0;
+ width: 100%;
+ padding: 0;
+ `}
`;
const ItemWrapper = styled.div`
@@ -401,6 +423,7 @@ function LeftPane() {
const isFetchingApplications = useSelector(getIsFetchingApplications);
const { appVersion } = getAppsmithConfigs();
const howMuchTimeBefore = howMuchTimeBeforeText(appVersion.releaseDate);
+ const isMobile = useIsMobileDevice();
let userOrgs;
if (!isFetchingApplications) {
userOrgs = fetchedUserOrgs;
@@ -411,6 +434,8 @@ function LeftPane() {
const location = useLocation();
const urlHash = location.hash.slice(1);
+ if (isMobile) return null;
+
return (
`
+ max-width: ${({ isMobile }) => (isMobile ? 220 : 500)}px;
${truncateTextUsingEllipsis}
`;
@@ -541,6 +566,7 @@ function ApplicationsSection(props: any) {
const userOrgs = useSelector(getUserApplicationsOrgsList);
const creatingApplicationMap = useSelector(getIsCreatingApplication);
const currentUser = useSelector(getCurrentUser);
+ const isMobile = useIsMobileDevice();
const deleteApplication = (applicationId: string) => {
if (applicationId && applicationId.length > 0) {
dispatch({
@@ -612,6 +638,7 @@ function ApplicationsSection(props: any) {
>
{orgName}
@@ -674,8 +701,12 @@ function ApplicationsSection(props: any) {
PERMISSION_TYPE.MANAGE_ORGANIZATION,
);
return (
-
-
+
+
{(currentUser || isFetchingApplications) &&
OrgMenuTarget({
orgName: organization.name,
@@ -708,25 +739,28 @@ function ApplicationsSection(props: any) {
!isFetchingApplications && (
-
- }
- />
+ {!isMobile && (
+
+ }
+ />
+ )}
{isPermitted(
organization.userPermissions,
PERMISSION_TYPE.CREATE_APPLICATION,
) &&
+ !isMobile &&
!isFetchingApplications &&
applications.length !== 0 && (
)}
- {(currentUser || isFetchingApplications) && (
+ {(currentUser || isFetchingApplications) && !isMobile && (
-
+
{applications.map((application: any) => {
return (
-
+
@@ -924,32 +959,34 @@ function ApplicationsSection(props: any) {
There’s nothing inside this organization
{/* below component is duplicate. This is because of cypress test were failing */}
-
@@ -960,7 +997,10 @@ function ApplicationsSection(props: any) {
}
return (
-
+
{organizationsListComponent}
{getFeatureFlags().GIT_IMPORT && }
diff --git a/app/client/src/pages/common/MobileSidebar.tsx b/app/client/src/pages/common/MobileSidebar.tsx
new file mode 100644
index 0000000000..adef944183
--- /dev/null
+++ b/app/client/src/pages/common/MobileSidebar.tsx
@@ -0,0 +1,165 @@
+import React from "react";
+import styled from "styled-components";
+import { Colors } from "constants/Colors";
+import ProfileImage from "pages/common/ProfileImage";
+import MenuItem from "components/ads/MenuItem";
+import { ADMIN_SETTINGS_CATEGORY_DEFAULT_URL } from "constants/routes";
+import {
+ getOnSelectAction,
+ DropdownOnSelectActions,
+} from "./CustomizedDropdown/dropdownHelpers";
+import { ReduxActionTypes } from "constants/ReduxActionConstants";
+import { useSelector } from "react-redux";
+import { getCurrentUser } from "selectors/usersSelectors";
+import {
+ createMessage,
+ ADMIN_SETTINGS,
+ DOCUMENTATION,
+} from "@appsmith/constants/messages";
+import { getAppsmithConfigs } from "@appsmith/configs";
+import { howMuchTimeBeforeText } from "utils/helpers";
+
+type MobileSideBarProps = {
+ name: string;
+ isOpen: boolean;
+ userName?: string;
+ photoId?: string;
+};
+
+const MainContainer = styled.div<{ isOpen: boolean }>`
+ position: absolute;
+ top: 49px; /* height of mobile header */
+ left: ${({ isOpen }) => (isOpen ? `0` : `-100vw`)};
+ width: 100vw;
+ height: calc(100vh - 49px);
+ background-color: ${Colors.WHITE};
+ transition: left 0.6s ease;
+ padding: 16px;
+`;
+
+const Section = styled.div`
+ padding: 20px 0;
+ border-bottom: 1px solid ${Colors.MERCURY};
+
+ & > h4 {
+ color: ${Colors.BLACK};
+ font-size: 13px;
+ font-weight: 600;
+ margin-left: 4px;
+ }
+`;
+
+const ProfileSection = styled(Section)`
+ display: flex;
+ align-items: center;
+`;
+
+const UserNameSection = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ margin-left: 12px;
+`;
+
+const Name = styled.span`
+ font-weight: 600;
+ color: ${Colors.BLACK};
+ font-size: 16px;
+`;
+
+const Email = styled.span`
+ font-size: 14px;
+ color: ${Colors.GREY_8};
+`;
+
+const StyledMenuItem = styled(MenuItem)`
+ svg {
+ width: 16px;
+ height: 16px;
+ fill: ${Colors.DARK_GRAY};
+ }
+
+ .cs-text {
+ color: ${Colors.BLACK};
+ font-size: 16px;
+ }
+`;
+
+const LeftPaneVersionData = styled.div`
+ display: flex;
+ justify-content: space-between;
+ color: #121826;
+ font-size: 8px;
+ width: 92%;
+ margin-top: 8px;
+`;
+
+export default function MobileSideBar(props: MobileSideBarProps) {
+ const user = useSelector(getCurrentUser);
+ const { appVersion } = getAppsmithConfigs();
+ const howMuchTimeBefore = howMuchTimeBeforeText(appVersion.releaseDate);
+
+ return (
+
+
+
+
+ {props.name}
+ {props.userName}
+
+
+
+ ACCOUNT
+ {user?.isSuperUser && user?.isConfigurable && (
+ {
+ getOnSelectAction(DropdownOnSelectActions.REDIRECT, {
+ path: ADMIN_SETTINGS_CATEGORY_DEFAULT_URL,
+ });
+ }}
+ text={createMessage(ADMIN_SETTINGS)}
+ />
+ )}
+
+ getOnSelectAction(DropdownOnSelectActions.DISPATCH, {
+ type: ReduxActionTypes.LOGOUT_USER_INIT,
+ })
+ }
+ text="Sign Out"
+ />
+
+
+ {
+ window.open("https://discord.gg/rBTTVJp", "_blank");
+ }}
+ text={"Join our Discord"}
+ />
+ {
+ window.open("https://docs.appsmith.com/", "_blank");
+ }}
+ text={createMessage(DOCUMENTATION)}
+ />
+
+
+ Appsmith {appVersion.id}
+ {howMuchTimeBefore !== "" && (
+ Released {howMuchTimeBefore} ago
+ )}
+
+
+ );
+}
diff --git a/app/client/src/pages/common/PageHeader.tsx b/app/client/src/pages/common/PageHeader.tsx
index 1ee14b9680..78a053b763 100644
--- a/app/client/src/pages/common/PageHeader.tsx
+++ b/app/client/src/pages/common/PageHeader.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { connect } from "react-redux";
import { getCurrentUser } from "selectors/usersSelectors";
@@ -12,9 +12,16 @@ import Button from "components/editorComponents/Button";
import history from "utils/history";
import ProfileDropdown from "./ProfileDropdown";
import Bell from "notifications/Bell";
+import { Colors } from "constants/Colors";
+import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
+import { ReactComponent as TwoLineHamburger } from "assets/icons/ads/two-line-hamburger.svg";
+import MobileSideBar from "./MobileSidebar";
+import { Indices } from "constants/Layers";
+import Icon, { IconSize } from "components/ads/Icon";
const StyledPageHeader = styled(StyledHeader)<{
hideShadow?: boolean;
+ isMobile?: boolean;
showSeparator?: boolean;
}>`
background: white;
@@ -23,10 +30,18 @@ const StyledPageHeader = styled(StyledHeader)<{
flex-direction: row;
position: fixed;
top: 0;
- z-index: 10;
+ z-index: ${Indices.Layer9};
box-shadow: ${(props) =>
- props.hideShadow ? `none` : `0px 4px 4px rgba(0, 0, 0, 0.05)`};
- ${(props) => props.showSeparator && sideBorder}
+ props.hideShadow && !props.isMobile
+ ? `none`
+ : `0px 4px 4px rgba(0, 0, 0, 0.05)`};
+ ${(props) => props.showSeparator && !props.isMobile && sideBorder}
+ ${({ isMobile }) =>
+ isMobile &&
+ `
+ padding: 0 12px;
+ padding-left: 10px;
+ `}
`;
const HeaderSection = styled.div`
@@ -49,12 +64,19 @@ const sideBorder = css`
left: ${(props) => props.theme.homePage.sidebar}px;
width: 1px;
height: 100%;
- background-color: #ededed;
+ background-color: ${Colors.GALLERY_2};
}
`;
const StyledDropDownContainer = styled.div``;
+const StyledTwoLineHamburger = styled(TwoLineHamburger)`
+ fill: ${Colors.BLACK};
+ width: 22px;
+ height: 22px;
+ cursor: pointer;
+`;
+
type PageHeaderProps = {
user?: User;
hideShadow?: boolean;
@@ -65,6 +87,8 @@ export function PageHeader(props: PageHeaderProps) {
const { user } = props;
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
+ const isMobile = useIsMobileDevice();
+ const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
let loginUrl = AUTH_LOGIN_URL;
if (queryParams.has("redirectUrl")) {
loginUrl += `?redirectUrl
@@ -74,6 +98,7 @@ export function PageHeader(props: PageHeaderProps) {
return (
@@ -81,7 +106,7 @@ export function PageHeader(props: PageHeaderProps) {
- {user && (
+ {user && !isMobile && (
<>
{user.username !== ANONYMOUS_USERNAME && }
@@ -103,6 +128,24 @@ export function PageHeader(props: PageHeaderProps) {
>
)}
+ {isMobile && !isMobileSidebarOpen && (
+ setIsMobileSidebarOpen(true)} />
+ )}
+ {isMobile && isMobileSidebarOpen && (
+ setIsMobileSidebarOpen(false)}
+ size={IconSize.XXXXL}
+ />
+ )}
+ {isMobile && (
+
+ )}
);
}
diff --git a/app/client/src/pages/common/SharedUserList.tsx b/app/client/src/pages/common/SharedUserList.tsx
index 5d6a191fff..ff5dc007fc 100644
--- a/app/client/src/pages/common/SharedUserList.tsx
+++ b/app/client/src/pages/common/SharedUserList.tsx
@@ -8,10 +8,11 @@ import ProfileImage from "./ProfileImage";
import ScrollIndicator from "components/ads/ScrollIndicator";
import { OrgUser } from "constants/orgConstants";
import { getUserApplicationsOrgsList } from "selectors/applicationSelectors";
+import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
-const UserImageContainer = styled.div`
+const UserImageContainer = styled.div<{ isMobile?: boolean }>`
display: flex;
- margin-right: 24px;
+ margin-right: ${({ isMobile }) => (isMobile ? 0 : 24)}px;
.org-share-user-icons {
cursor: default;
@@ -67,6 +68,7 @@ export default function SharedUserList(props: any) {
const currentUser = useSelector(getCurrentUser);
const scrollWrapperRef = React.createRef();
const userOrgs = useSelector(getUserApplicationsOrgsList);
+ const isMobile = useIsMobileDevice();
const allUsers = useMemo(() => {
const org: any = userOrgs.find((organizationObject: any) => {
const { organization } = organizationObject;
@@ -77,7 +79,7 @@ export default function SharedUserList(props: any) {
return userRoles || [];
}, [userOrgs]);
return (
-
+
{allUsers.slice(0, 5).map((el: OrgUser) => (
`
+ width: ${({ isMobile }) => (isMobile ? `100%` : `250px`)};
display: flex;
justify-content: space-between;
- position: fixed;
+ position: ${({ isMobile }) => (isMobile ? `relative` : `fixed`)};
background: ${(props) => props.theme.colors.homepageBackground};
top: 2px;
- left: ${(props) => props.theme.homePage.sidebar + 24}px;
- z-index: ${Indices.Layer9};
+ left: ${(props) =>
+ props.isMobile ? 0 : props.theme.homePage.sidebar + 24}px;
+ z-index: ${({ isMobile }) => (isMobile ? Indices.Layer8 : Indices.Layer9)};
+ ${({ isMobile }) => isMobile && `padding: 12px 16px;`}
`;
const SearchContainer = styled.div`
flex-grow: 1;
@@ -52,6 +57,7 @@ type SubHeaderProps = {
export function ApplicationsSubHeader(props: SubHeaderProps) {
const isFetchingApplications = useSelector(getIsFetchingApplications);
+ const isMobile = useIsMobileDevice();
const query =
props.search &&
props.search.queryFn &&
@@ -61,17 +67,19 @@ export function ApplicationsSubHeader(props: SubHeaderProps) {
);
return (
-
+
{props.search && (
)}
diff --git a/app/client/src/theme/colors.css b/app/client/src/theme/colors.css
index 2a5c428c9e..e44d09b0a8 100644
--- a/app/client/src/theme/colors.css
+++ b/app/client/src/theme/colors.css
@@ -22,6 +22,7 @@
--appsmith-color-black-200 : #E7E7E7;
--appsmith-color-black-100 : #F1F1F1;
--appsmith-color-black-50 : #F8F8F8;
+ --appsmith-color-black-0 : #FFFFFF;
/* green */
--appsmith-color-green-500 : #03B364;
diff --git a/app/client/src/theme/defaultTheme.css b/app/client/src/theme/defaultTheme.css
index 7c255ae2f2..efe41fc9f3 100644
--- a/app/client/src/theme/defaultTheme.css
+++ b/app/client/src/theme/defaultTheme.css
@@ -6,4 +6,8 @@
/* input */
--appsmith-input-focus-border-color: var(--appsmith-color-black-900);
+ /* search input */
+ --appsmith-search-input-focus-mobile-border-color: var(--appsmith-color-black-900);
+ --appsmith-search-input-mobile-border-color: var(--appsmith-color-black-400);
+
}
diff --git a/app/client/src/utils/hooks/useDeviceDetect.ts b/app/client/src/utils/hooks/useDeviceDetect.ts
new file mode 100644
index 0000000000..33eb8a7019
--- /dev/null
+++ b/app/client/src/utils/hooks/useDeviceDetect.ts
@@ -0,0 +1,24 @@
+import { useMediaQuery } from "react-responsive";
+import {
+ MOBILE_MAX_WIDTH,
+ TABLET_MIN_WIDTH,
+ TABLET_MAX_WIDTH,
+ DESKTOP_MIN_WIDTH,
+} from "constants/AppConstants";
+
+export function useIsMobileDevice() {
+ return useMediaQuery({ maxWidth: MOBILE_MAX_WIDTH });
+}
+
+export function useIsTabletDevice() {
+ return useMediaQuery({
+ minWidth: TABLET_MIN_WIDTH,
+ maxWidth: TABLET_MAX_WIDTH,
+ });
+}
+
+export function useIsDesktopDevice() {
+ return useMediaQuery({
+ minWidth: DESKTOP_MIN_WIDTH,
+ });
+}