forked from github/plane
style: mobile responsive ui
This commit is contained in:
parent
13389d1b2b
commit
86604c6f13
@ -30,7 +30,7 @@ export const EmailForgotPasswordForm: FC<IEmailForgotPasswordForm> = (props) =>
|
||||
});
|
||||
|
||||
return (
|
||||
<form className="space-y-4 mt-10 w-full sm:w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<form className="space-y-4 mt-10 w-[80vw] max-w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="space-y-1">
|
||||
<Controller
|
||||
control={control}
|
||||
|
@ -36,7 +36,7 @@ export const EmailSignUpForm: React.FC<Props> = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="space-y-4 mt-10 w-full sm:w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<form className="space-y-4 mt-10 w-[80vw] max-w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="space-y-1">
|
||||
<Controller
|
||||
control={control}
|
||||
|
@ -54,7 +54,11 @@ export const GoogleLoginButton: FC<IGoogleLoginButton> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<Script src="https://accounts.google.com/gsi/client" async defer onLoad={loadScript} />
|
||||
<div className="overflow-hidden rounded w-full" id="googleSignInButton" ref={googleSignInButton} />
|
||||
<div
|
||||
className="overflow-hidden rounded max-w-[360px] w-[80vw]"
|
||||
id="googleSignInButton"
|
||||
ref={googleSignInButton}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ export const EmptyState: React.FC<Props> = ({
|
||||
secondaryButton,
|
||||
disabled = false,
|
||||
}) => (
|
||||
<div className={`flex items-center justify-center h-full w-full`}>
|
||||
<div className={`flex items-center justify-center h-full px-5 lg:px-40 w-full`}>
|
||||
<div className="text-center flex flex-col items-center w-full">
|
||||
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} />
|
||||
<h6 className="text-xl font-semibold mt-6 sm:mt-8 mb-3">{title}</h6>
|
||||
|
@ -51,7 +51,7 @@ export const ProductUpdatesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative overflow-hidden rounded-lg bg-custom-background-100 border border-custom-border-100 shadow-custom-shadow-rg] min-w-[100%] sm:min-w-[50%] sm:max-w-[50%]">
|
||||
<Dialog.Panel className="relative overflow-hidden rounded-lg bg-custom-background-100 border border-custom-border-100 shadow-custom-shadow-rg] min-w-[100%] max-w-[80vw] sm:min-w-[50%] sm:max-w-[50%]">
|
||||
<div className="flex flex-col p-4 max-h-[90vh] w-full">
|
||||
<Dialog.Title as="h3" className="flex items-center justify-between text-lg font-semibold">
|
||||
<span>Product Updates</span>
|
||||
|
@ -137,7 +137,7 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 p-5 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 p-5 text-left shadow-xl transition-all w-[90vw] sm:w-full sm:max-w-2xl">
|
||||
<CycleForm
|
||||
handleFormSubmit={handleFormSubmit}
|
||||
handleClose={handleClose}
|
||||
|
@ -3,6 +3,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import useSWR from "swr";
|
||||
import { Menu } from "lucide-react";
|
||||
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
@ -17,7 +18,6 @@ import { List, PlusIcon, Sheet } from "lucide-react";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TStaticViewTypes } from "types";
|
||||
// constants
|
||||
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
||||
|
||||
const GLOBAL_VIEW_LAYOUTS = [
|
||||
{ key: "list", title: "List", link: "/workspace-views", icon: List },
|
||||
{ key: "spreadsheet", title: "Spreadsheet", link: "/workspace-views/all-issues", icon: Sheet },
|
||||
@ -42,6 +42,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
||||
workspaceFilter: workspaceFilterStore,
|
||||
workspace: workspaceStore,
|
||||
project: projectStore,
|
||||
theme: themStore,
|
||||
} = useMobxStore();
|
||||
|
||||
const storedFilters = globalViewId ? globalViewFiltersStore.storedFilters[globalViewId.toString()] : undefined;
|
||||
@ -99,7 +100,15 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
||||
<>
|
||||
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
|
||||
<div className="relative w-full flex items-center z-10 justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="grid md:hidden h-7 w-7 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => {
|
||||
themStore.setShowSidebarOnMobile(true);
|
||||
}}
|
||||
>
|
||||
<Menu className="h-4 w-4 " fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
|
@ -100,7 +100,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
||||
/>
|
||||
<div className="relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
{/* <div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
@ -108,7 +108,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
||||
>
|
||||
<ArrowLeft fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
</div> */}
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -6,12 +6,14 @@ import { Breadcrumbs, Button } from "@plane/ui";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import { Menu } from "lucide-react";
|
||||
|
||||
export const ProjectsHeader = observer(() => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
// store
|
||||
const { project: projectStore } = useMobxStore();
|
||||
const { project: projectStore, theme: themStore } = useMobxStore();
|
||||
|
||||
const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : [];
|
||||
|
||||
@ -19,7 +21,16 @@ export const ProjectsHeader = observer(() => {
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="flex items-center gap-2 sm:flex-grow sm:w-full whitespace-nowrap overflow-ellipsis">
|
||||
<button
|
||||
className="grid md:hidden h-7 w-7 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => {
|
||||
themStore.setShowSidebarOnMobile(true);
|
||||
}}
|
||||
>
|
||||
<Menu className="h-4 w-4 " fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
@ -35,7 +46,7 @@ export const ProjectsHeader = observer(() => {
|
||||
<div className="flex w-full gap-1 items-center justify-start text-custom-text-400 rounded-md px-2.5 py-1.5 border border-custom-border-200 bg-custom-background-100">
|
||||
<Search className="h-3.5 w-3.5" />
|
||||
<input
|
||||
className="min-w-[234px] w-full border-none bg-transparent text-sm focus:outline-none"
|
||||
className="sm:min-w-[150px] lg:min-w-[234px] w-full border-none bg-transparent text-sm focus:outline-none"
|
||||
value={projectStore.searchQuery}
|
||||
onChange={(e) => projectStore.setSearchQuery(e.target.value)}
|
||||
placeholder="Search"
|
||||
@ -51,7 +62,7 @@ export const ProjectsHeader = observer(() => {
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
Add Project
|
||||
<span className="hidden md:block">Add Project</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@ export const WorkspaceAnalyticsHeader = () => {
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
{/* <div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
@ -20,7 +20,7 @@ export const WorkspaceAnalyticsHeader = () => {
|
||||
>
|
||||
<ArrowLeft fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
</div> */}
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -212,13 +212,13 @@ export const SignInView = observer(() => {
|
||||
<>
|
||||
{enableEmailPassword && <EmailPasswordForm onSubmit={handlePasswordSignIn} />}
|
||||
{data?.magic_login && (
|
||||
<div className="flex flex-col divide-y divide-custom-border-200">
|
||||
<div className="flex flex-col divide-y divide-custom-border-200 max-w-[360px] mx-auto w-[80vw]">
|
||||
<div className="pb-7">
|
||||
<EmailCodeForm handleSignIn={handleEmailCodeSignIn} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col items-center justify-center gap-4 pt-7 sm:w-[360px] mx-auto overflow-hidden">
|
||||
<div className="flex flex-col items-center justify-center gap-4 pt-7 max-w-[360px] w-[80vw] mx-auto overflow-hidden">
|
||||
{data?.google && <GoogleLoginButton clientId={data?.google} handleSignIn={handleGoogleSignIn} />}
|
||||
{data?.github && <GithubLoginButton clientId={data?.github} handleSignIn={handleGitHubSignIn} />}
|
||||
</div>
|
||||
|
@ -167,7 +167,7 @@ export const CreateUpdatePageModal: React.FC<Props> = (props) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 w-[90vw] sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<PageForm
|
||||
handleFormSubmit={handleFormSubmit}
|
||||
handleClose={handleClose}
|
||||
|
@ -86,7 +86,7 @@ export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 w-[90vw] sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<ProjectViewForm
|
||||
data={data}
|
||||
handleClose={handleClose}
|
||||
|
@ -126,7 +126,7 @@ export const CreateUpdateWorkspaceViewModal: React.FC<Props> = observer((props)
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 w-[90vw] sm:w-full sm:max-w-2xl sm:p-6">
|
||||
<WorkspaceViewForm
|
||||
handleFormSubmit={handleFormSubmit}
|
||||
handleClose={handleClose}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FC } from "react";
|
||||
import { FC, useEffect } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// components
|
||||
import {
|
||||
@ -10,6 +10,8 @@ import {
|
||||
import { ProjectSidebarList } from "components/project";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { Menu } from "lucide-react";
|
||||
import router from "next/router";
|
||||
|
||||
export interface IAppSidebar {}
|
||||
|
||||
@ -17,15 +19,42 @@ export const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
// store
|
||||
const { theme: themStore } = useMobxStore();
|
||||
|
||||
useEffect(() => {
|
||||
router.events.on("routeChangeStart", () => {
|
||||
themStore.setShowSidebarOnMobile(false);
|
||||
});
|
||||
return () => {
|
||||
router.events.off("routeChangeStart", () => {
|
||||
themStore.setShowSidebarOnMobile(false);
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="app-sidebar"
|
||||
className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 duration-300 ${
|
||||
className={`absolute max-w-[300px] top-0 left-0 md:relative inset-y-0 md:flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 md:translate-x-0 duration-300 ${
|
||||
themStore?.sidebarCollapsed ? "" : "md:w-[280px]"
|
||||
} ${themStore?.sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`}
|
||||
} ${themStore?.sidebarCollapsed ? "left-0" : "-left-full md:left-0"}
|
||||
${themStore.showSidebarOnMobile ? "" : "transition-transform translate-x-[-300px] ease-linear"}
|
||||
`}
|
||||
>
|
||||
<div className="flex h-full w-full flex-1 flex-col">
|
||||
<div className="flex items-center ">
|
||||
<div className="pt-4 pl-4 md:hidden">
|
||||
<button
|
||||
className="grid h-7 w-7 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => {
|
||||
themStore.setShowSidebarOnMobile(false);
|
||||
}}
|
||||
>
|
||||
<Menu className="h-4 w-4 " fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<WorkspaceSidebarDropdown />
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceSidebarQuickAction />
|
||||
<WorkspaceSidebarMenu />
|
||||
<ProjectSidebarList />
|
||||
|
@ -106,7 +106,7 @@ const ResetPasswordPage: NextPageWithLayout = () => {
|
||||
<div className="grid place-items-center h-full w-full overflow-y-auto py-5 px-7">
|
||||
<div className="w-full">
|
||||
<h1 className="text-center text-2xl sm:text-2.5xl font-semibold text-custom-text-100">Reset your password</h1>
|
||||
<form className="space-y-4 mt-10 w-full sm:w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<form className="space-y-4 mt-10 w-[80vw] max-w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="space-y-1">
|
||||
<Controller
|
||||
control={control}
|
||||
|
@ -6,13 +6,16 @@ import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
export interface IThemeStore {
|
||||
theme: string | null;
|
||||
sidebarCollapsed: boolean | undefined;
|
||||
showSidebarOnMobile: boolean;
|
||||
|
||||
toggleSidebar: (collapsed?: boolean) => void;
|
||||
setShowSidebarOnMobile: (show: boolean) => void;
|
||||
setTheme: (theme: any) => void;
|
||||
}
|
||||
|
||||
class ThemeStore implements IThemeStore {
|
||||
sidebarCollapsed: boolean | undefined = undefined;
|
||||
showSidebarOnMobile: boolean = false;
|
||||
theme: string | null = null;
|
||||
// root store
|
||||
rootStore;
|
||||
@ -21,9 +24,11 @@ class ThemeStore implements IThemeStore {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
sidebarCollapsed: observable.ref,
|
||||
showSidebarOnMobile: observable.ref,
|
||||
theme: observable.ref,
|
||||
// action
|
||||
toggleSidebar: action,
|
||||
setShowSidebarOnMobile: action,
|
||||
setTheme: action,
|
||||
// computed
|
||||
});
|
||||
@ -40,6 +45,10 @@ class ThemeStore implements IThemeStore {
|
||||
localStorage.setItem("app_sidebar_collapsed", this.sidebarCollapsed.toString());
|
||||
};
|
||||
|
||||
setShowSidebarOnMobile = (show: boolean) => {
|
||||
this.showSidebarOnMobile = show;
|
||||
};
|
||||
|
||||
setTheme = async (_theme: { theme: any }) => {
|
||||
try {
|
||||
const currentTheme: string = _theme?.theme?.theme?.toString();
|
||||
|
Loading…
Reference in New Issue
Block a user