mirror of
https://github.com/penxio/penx.git
synced 2026-04-19 03:03:06 -04:00
feat: improve mobile ui
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import { DndProvider } from 'react-dnd'
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend'
|
||||
import { Redirect, Route } from 'react-router-dom'
|
||||
import { DarkMode } from '@aparajita/capacitor-dark-mode'
|
||||
import { SafeArea } from '@capacitor-community/safe-area'
|
||||
@@ -30,6 +28,11 @@ import '@ionic/react/css/text-alignment.css'
|
||||
import '@ionic/react/css/text-transformation.css'
|
||||
import '@ionic/react/css/flex-utils.css'
|
||||
import '@ionic/react/css/display.css'
|
||||
//
|
||||
import 'react-grid-layout/css/styles.css'
|
||||
import 'react-resizable/css/styles.css'
|
||||
import 'react-datepicker/dist/react-datepicker.css'
|
||||
import '@glideapps/glide-data-grid/dist/index.css'
|
||||
/**
|
||||
* Ionic Dark Mode
|
||||
* -----------------------------------------------------
|
||||
@@ -142,26 +145,25 @@ const App: React.FC = () => {
|
||||
|
||||
return (
|
||||
<IonApp>
|
||||
<div id="portal" className="fixed left-0 top-0 z-[100000000]" />
|
||||
<LinguiClientProvider initialLocale={'en'} initialMessages={{}}>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<DashboardProviders>
|
||||
<IonReactRouter>
|
||||
<IonSplitPane contentId="main">
|
||||
<Menu />
|
||||
<IonRouterOutlet id="main">
|
||||
<Route path="/" exact={true}>
|
||||
<Redirect to="/folder/area" />
|
||||
</Route>
|
||||
<Route path="/folder/:name" exact={true}>
|
||||
<NavProvider nav={nav.current!}>
|
||||
<IonNav ref={nav} root={() => <PageHome />}></IonNav>
|
||||
</NavProvider>
|
||||
</Route>
|
||||
</IonRouterOutlet>
|
||||
</IonSplitPane>
|
||||
</IonReactRouter>
|
||||
</DashboardProviders>
|
||||
</DndProvider>
|
||||
<DashboardProviders>
|
||||
<IonReactRouter>
|
||||
<IonSplitPane contentId="main">
|
||||
<Menu />
|
||||
<IonRouterOutlet id="main">
|
||||
<Route path="/" exact={true}>
|
||||
<Redirect to="/folder/area" />
|
||||
</Route>
|
||||
<Route path="/folder/:name" exact={true}>
|
||||
<NavProvider nav={nav.current!}>
|
||||
<IonNav ref={nav} root={() => <PageHome />}></IonNav>
|
||||
</NavProvider>
|
||||
</Route>
|
||||
</IonRouterOutlet>
|
||||
</IonSplitPane>
|
||||
</IonReactRouter>
|
||||
</DashboardProviders>
|
||||
</LinguiClientProvider>
|
||||
</IonApp>
|
||||
)
|
||||
|
||||
@@ -51,7 +51,21 @@ export const AreaList: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="mb-2 mt-2 px-3 text-xl font-bold">My areas</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="mb-2 mt-2 px-3 text-xl font-bold">My areas</div>
|
||||
<IonMenuToggle>
|
||||
<MenuItem
|
||||
className="flex cursor-pointer items-center gap-2"
|
||||
onClick={async () => {
|
||||
setIsOpen(true)
|
||||
// menuController.close()
|
||||
menuController.close('main')
|
||||
}}
|
||||
>
|
||||
<PlusIcon size={24} />
|
||||
</MenuItem>
|
||||
</IonMenuToggle>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
{areas.map((item) => (
|
||||
@@ -81,22 +95,6 @@ export const AreaList: React.FC = () => {
|
||||
</MenuItem>
|
||||
</IonMenuToggle>
|
||||
))}
|
||||
|
||||
<IonMenuToggle>
|
||||
<MenuItem
|
||||
className="flex cursor-pointer items-center gap-2"
|
||||
onClick={async () => {
|
||||
setIsOpen(true)
|
||||
// menuController.close()
|
||||
// menuController.close('main')
|
||||
}}
|
||||
>
|
||||
<PlusIcon size={24} />
|
||||
<div>
|
||||
<Trans id="Create area"></Trans>
|
||||
</div>
|
||||
</MenuItem>
|
||||
</IonMenuToggle>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useHomeTab } from '@/hooks/useHomeTab'
|
||||
import { IonFooter, IonToolbar } from '@ionic/react'
|
||||
import { PlusIcon } from 'lucide-react'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import { cn } from '@penx/utils'
|
||||
|
||||
interface Props {
|
||||
onAdd: () => void
|
||||
@@ -13,63 +12,27 @@ export const Footer = ({ onAdd }: Props) => {
|
||||
const { setType } = useHomeTab()
|
||||
|
||||
return (
|
||||
<IonFooter>
|
||||
<IonFooter
|
||||
style={{
|
||||
boxShadow: '0 0 0 rgba(0, 0, 0, 0)',
|
||||
}}
|
||||
>
|
||||
<IonToolbar
|
||||
className="toolbar px-3"
|
||||
style={{
|
||||
'--border-width': 0,
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3 rounded-full px-3">
|
||||
<div className="flex items-center justify-center gap-3 rounded-full px-3 pb-4">
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className={cn('size-8 rounded-full')}
|
||||
onClick={async () => {
|
||||
setType('HOME')
|
||||
}}
|
||||
>
|
||||
<span className="icon-[solar--home-2-linear] size-6"></span>
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className={cn('size-8 rounded-full')}
|
||||
onClick={async () => {
|
||||
setType('NOTE')
|
||||
}}
|
||||
>
|
||||
<span className="icon-[solar--notes-linear] size-6"></span>
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="text-background bg-foreground size-9 rounded-full"
|
||||
className="text-background shadow-popover size-14 rounded-full"
|
||||
onClick={async () => {
|
||||
onAdd()
|
||||
}}
|
||||
>
|
||||
<PlusIcon size={24} />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className={cn('size-8 rounded-full')}
|
||||
onClick={async () => {
|
||||
setType('TASK')
|
||||
}}
|
||||
>
|
||||
<span className="icon-[solar--check-square-linear] size-6"></span>
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className={cn('size-8 rounded-full')}
|
||||
onClick={async () => {
|
||||
setType('PROFILE')
|
||||
}}
|
||||
>
|
||||
<span className="icon-[solar--user-linear] size-6"></span>
|
||||
<PlusIcon size={28} className="text-foreground" />
|
||||
</Button>
|
||||
</div>
|
||||
</IonToolbar>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import { IonContent, IonMenu } from '@ionic/react'
|
||||
import { AreaWidgets } from '@penx/components/area-widgets/AreaWidgets'
|
||||
import { useMobileMenu } from '@penx/hooks/useMobileMenu'
|
||||
import { useSession } from '@penx/session'
|
||||
import { store } from '@penx/store'
|
||||
import { cn } from '@penx/utils'
|
||||
import { AreaList } from './AreaList'
|
||||
import { MobileModeToggle } from './MobileModeToggle'
|
||||
@@ -8,12 +12,22 @@ import { MobileModeToggle } from './MobileModeToggle'
|
||||
const platform = Capacitor.getPlatform()
|
||||
|
||||
const Menu: React.FC = () => {
|
||||
const { setMenu } = useMobileMenu()
|
||||
const { isLoading } = useSession()
|
||||
const menu = useRef<HTMLIonMenuElement>(null)
|
||||
|
||||
if (isLoading) return null
|
||||
useEffect(() => {
|
||||
setMenu(menu)
|
||||
}, [menu])
|
||||
|
||||
return (
|
||||
<IonMenu contentId="main" type="overlay">
|
||||
<IonMenu
|
||||
ref={menu}
|
||||
id="menu"
|
||||
menuId="myMenu"
|
||||
contentId="main"
|
||||
type="overlay"
|
||||
>
|
||||
<IonContent className="ion-padding safe-area drawer-menu h-full">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -23,6 +37,7 @@ const Menu: React.FC = () => {
|
||||
>
|
||||
<div className="flex-1">
|
||||
<AreaList />
|
||||
<AreaWidgets />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<MobileModeToggle />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { DndProvider } from 'react-dnd'
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend'
|
||||
import { CreationMenu } from '@/components/CreationMenu'
|
||||
import { MobileCreation } from '@/components/MobileCreation'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
@@ -59,7 +61,9 @@ export const PageCreation = ({
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent className="ion-padding">
|
||||
<MobileCreation creationId={creationId} />
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<MobileCreation creationId={creationId} />
|
||||
</DndProvider>
|
||||
</IonContent>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
} from 'motion/react'
|
||||
import { EditWidgetButton } from '@penx/components/area-widgets/EditWidget/EditWidgetButton'
|
||||
import { AreaDialog } from '@penx/components/AreaDialog'
|
||||
import { PanelList } from '@penx/components/DashboardLayout/PanelList'
|
||||
import { QuickInput } from '@penx/components/QuickInput'
|
||||
import { appEmitter } from '@penx/emitter'
|
||||
import { useArea } from '@penx/hooks/useArea'
|
||||
@@ -44,6 +45,7 @@ import { ICreationNode } from '@penx/model-type'
|
||||
import { useSession } from '@penx/session'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import { Separator } from '@penx/uikit/separator'
|
||||
import { SidebarProvider } from '@penx/uikit/ui/sidebar'
|
||||
import { cn } from '@penx/utils'
|
||||
import { PageCreation } from './PageCreation'
|
||||
|
||||
@@ -188,7 +190,7 @@ const PageHome: React.FC = ({ nav }: any) => {
|
||||
|
||||
<IonButtons slot="end" className="">
|
||||
<SearchButton />
|
||||
<EditWidgetButton />
|
||||
{/* <EditWidgetButton /> */}
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
@@ -201,17 +203,20 @@ const PageHome: React.FC = ({ nav }: any) => {
|
||||
</IonHeader> */}
|
||||
|
||||
<div
|
||||
className="text-foreground relative flex min-h-full flex-col px-1"
|
||||
className="text-foreground z-1 relative flex min-h-full flex-col px-1"
|
||||
style={
|
||||
{
|
||||
'--background': 'oklch(1 0 0)',
|
||||
} as any
|
||||
}
|
||||
>
|
||||
{type === 'HOME' && <MobileHome />}
|
||||
{type === 'TASK' && <MobileTask />}
|
||||
{type === 'PROFILE' &&
|
||||
(session ? <ProfileContent /> : <LoginContent />)}
|
||||
<SidebarProvider>
|
||||
<PanelList />
|
||||
</SidebarProvider>
|
||||
{/* {type === 'HOME' && <MobileHome />} */}
|
||||
{/* {type === 'TASK' && <MobileTask />} */}
|
||||
{/* {type === 'PROFILE' &&
|
||||
(session ? <ProfileContent /> : <LoginContent />)} */}
|
||||
</div>
|
||||
</IonContent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useStructs } from '@penx/hooks/useStructs'
|
||||
import { ICreationNode } from '@penx/model-type'
|
||||
import { store } from '@penx/store'
|
||||
import { trpc } from '@penx/trpc-client'
|
||||
import { StructType, Panel } from '@penx/types'
|
||||
import { Panel, StructType } from '@penx/types'
|
||||
import { Checkbox } from '@penx/uikit/checkbox'
|
||||
import { Separator } from '@penx/uikit/separator'
|
||||
import { cn } from '@penx/utils'
|
||||
@@ -111,7 +111,7 @@ export function Creation({ panel, className, ref }: Props) {
|
||||
<div
|
||||
className={cn(
|
||||
'creation-container relative z-0 min-h-[100vh] flex-1 flex-col overflow-y-auto overflow-x-hidden px-0 pb-40 md:px-8',
|
||||
isMobileApp && 'pt-0',
|
||||
isMobileApp && 'px-3 pt-0',
|
||||
className,
|
||||
)}
|
||||
onClick={(e: any) => {
|
||||
@@ -187,7 +187,7 @@ export function Creation({ panel, className, ref }: Props) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center justify-between bg-">
|
||||
<div className="flex items-center gap-1">
|
||||
<ChangeType creation={creation} />
|
||||
<div className="text-foreground/60 text-lg">•</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ export const PropList = ({ onUpdateProps }: Props) => {
|
||||
const { structs } = useStructs()
|
||||
const struct = structs.find((m) => m.id === creation.structId)!
|
||||
|
||||
if (!struct.columns.length) return null
|
||||
if (struct.columns.length < 2) return null
|
||||
return (
|
||||
<div className="mt-4 flex flex-col gap-1">
|
||||
{struct.columns.map((column, i) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { isMobileApp } from '@penx/constants'
|
||||
import { SidebarTrigger } from '@penx/uikit/sidebar'
|
||||
|
||||
export function PanelHeaderWrapper({
|
||||
@@ -10,6 +11,7 @@ export function PanelHeaderWrapper({
|
||||
children: ReactNode
|
||||
index: number
|
||||
}) {
|
||||
if (isMobileApp!) return null
|
||||
if (index === 0)
|
||||
return (
|
||||
<div className="flex h-10 shrink-0 items-center gap-1 pl-2 pr-1">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { isMobileApp } from '@penx/constants'
|
||||
import { Panel, PanelType } from '@penx/types'
|
||||
import { ResizableHandle, ResizablePanel } from '@penx/uikit/resizable'
|
||||
import { cn } from '@penx/utils'
|
||||
@@ -60,7 +61,7 @@ export function PanelItem({
|
||||
|
||||
{panel.type === PanelType.WIDGET && (
|
||||
<>
|
||||
<PanelWidgetHeader index={index} panel={panel} />
|
||||
{!isMobileApp && <PanelWidgetHeader index={index} panel={panel} />}
|
||||
<PanelWidget index={index} panel={panel} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
usePanelCreationContext,
|
||||
} from '@penx/components/PanelCreationProvider'
|
||||
import { PublishDialog } from '@penx/components/PublishDialog'
|
||||
import { BUILTIN_PAGE_SLUGS, ROOT_DOMAIN } from '@penx/constants'
|
||||
import { BUILTIN_PAGE_SLUGS, isMobileApp, ROOT_DOMAIN } from '@penx/constants'
|
||||
import { CreationStatus } from '@penx/db/client'
|
||||
import { getSiteDomain } from '@penx/libs/getSiteDomain'
|
||||
import { Panel } from '@penx/types'
|
||||
@@ -45,6 +45,7 @@ export function Content({ panel, index }: Props) {
|
||||
<ClosePanelButton panel={panel} />
|
||||
</div>
|
||||
</PanelHeaderWrapper>
|
||||
|
||||
<Creation panel={panel} className="" />
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ import { toast } from 'sonner'
|
||||
import { useLocalStorage, useWindowSize } from 'usehooks-ts'
|
||||
import { useAddCreation } from '@penx/hooks/useAddCreation'
|
||||
import { store } from '@penx/store'
|
||||
import { StructType, PanelType } from '@penx/types'
|
||||
import { PanelType, StructType } from '@penx/types'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import { Checkbox } from '@penx/uikit/checkbox'
|
||||
import { Textarea } from '@penx/uikit/textarea'
|
||||
@@ -81,6 +81,7 @@ export function QuickInput({
|
||||
addCreation({
|
||||
type: StructType.NOTE,
|
||||
content: JSON.stringify(slateValue),
|
||||
isAddPanel: false,
|
||||
})
|
||||
afterSubmit?.()
|
||||
setInput('')
|
||||
|
||||
@@ -31,17 +31,15 @@ import {
|
||||
TooltipTrigger,
|
||||
} from '@penx/uikit/tooltip'
|
||||
import { useLoginDialog } from '@penx/widgets/LoginDialog/useLoginDialog'
|
||||
import { AddCreationButton } from '../AddCreationButton'
|
||||
import { AreaWidgets } from '../area-widgets'
|
||||
import { AreasPopover } from '../AreasPopover/AreasPopover'
|
||||
import { ProfileButton } from '../ProfileButton'
|
||||
import { ImportPostEntry } from './ImportPostEntry'
|
||||
import { QuickSearchTrigger } from './QuickSearchTrigger'
|
||||
import { VisitSiteButton } from './VisitSiteButton'
|
||||
import { AddCreationButton } from '../AddCreationButton'
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
const { session } = useSession()
|
||||
const { setIsOpen } = useLoginDialog()
|
||||
return (
|
||||
<Sidebar variant="inset" {...props}>
|
||||
<SidebarHeader className="m-0 p-0 pb-1">
|
||||
@@ -50,7 +48,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
<AreasPopover />
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
<div className='flex items-center justify-between mb-1 gap-1'>
|
||||
<div className="mb-1 flex items-center justify-between gap-1">
|
||||
<QuickSearchTrigger />
|
||||
{!isMobileApp && <AddCreationButton></AddCreationButton>}
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,8 @@ export function AreaWidgets({}: Props) {
|
||||
<div className="space-y-2">
|
||||
{isMobileApp && <MobileWidgetList />}
|
||||
{!isMobileApp && <WidgetList />}
|
||||
{!isMobileApp && <AddWidgetButton />}
|
||||
{/* {!isMobileApp && } */}
|
||||
<AddWidgetButton />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -17,10 +17,11 @@ import { useArea } from '@penx/hooks/useArea'
|
||||
import { updateCreationProps } from '@penx/hooks/useCreation'
|
||||
import { creationIdAtom, useCreationId } from '@penx/hooks/useCreationId'
|
||||
import { useCreationStruct } from '@penx/hooks/useCreationStruct'
|
||||
import { mobileMenuAtom, useMobileMenu } from '@penx/hooks/useMobileMenu'
|
||||
import { usePanels } from '@penx/hooks/usePanels'
|
||||
import { ICreationNode } from '@penx/model-type'
|
||||
import { store } from '@penx/store'
|
||||
import { StructType, PanelType, SiteCreation } from '@penx/types'
|
||||
import { PanelType, SiteCreation, StructType } from '@penx/types'
|
||||
import { Checkbox } from '@penx/uikit/checkbox'
|
||||
import {
|
||||
ContextMenu,
|
||||
@@ -41,6 +42,7 @@ export function CreationItem({ creation, className }: CreationItemProps) {
|
||||
const { isCreationInPanels } = usePanels()
|
||||
const { isAll, setVisible } = useIsAllContext()
|
||||
const struct = useCreationStruct(creation)
|
||||
const { close } = useMobileMenu()
|
||||
|
||||
const getTitleFromContent = () => {
|
||||
try {
|
||||
@@ -63,10 +65,11 @@ export function CreationItem({ creation, className }: CreationItemProps) {
|
||||
)}
|
||||
onClick={() => {
|
||||
if (isMobileApp) {
|
||||
appEmitter.emit('ROUTE_TO_CREATION', creation)
|
||||
store.set(creationIdAtom, creation.id)
|
||||
// appEmitter.emit('ROUTE_TO_CREATION', creation)
|
||||
// store.set(creationIdAtom, creation.id)
|
||||
close()
|
||||
setVisible?.(false)
|
||||
return
|
||||
// return
|
||||
}
|
||||
|
||||
store.panels.updateMainPanel({
|
||||
|
||||
@@ -7,11 +7,13 @@ import { AnimatePresence, motion } from 'motion/react'
|
||||
import { Drawer } from 'vaul'
|
||||
import { isMobileApp, WidgetType } from '@penx/constants'
|
||||
import { useArea } from '@penx/hooks/useArea'
|
||||
import { useMobileMenu } from '@penx/hooks/useMobileMenu'
|
||||
import { useStructs } from '@penx/hooks/useStructs'
|
||||
import { store } from '@penx/store'
|
||||
import { Widget } from '@penx/types'
|
||||
import { PanelType, Widget } from '@penx/types'
|
||||
import { ContextMenu, ContextMenuTrigger } from '@penx/uikit/context-menu'
|
||||
import { DialogDescription, DialogTitle } from '@penx/uikit/dialog'
|
||||
import { uniqueId } from '@penx/unique-id'
|
||||
import { cn } from '@penx/utils'
|
||||
import { WidgetIcon } from '@penx/widgets/WidgetIcon'
|
||||
import { WidgetName } from '@penx/widgets/WidgetName'
|
||||
@@ -65,6 +67,7 @@ export const WidgetItem = forwardRef<HTMLDivElement, Props>(
|
||||
const { area } = useArea()
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [struct, setStruct] = useState(null as any)
|
||||
const { close } = useMobileMenu()
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!dragOverlay) {
|
||||
@@ -176,7 +179,16 @@ export const WidgetItem = forwardRef<HTMLDivElement, Props>(
|
||||
{widget.type === WidgetType.ALL_STRUCTS ? (
|
||||
<StructList
|
||||
onSelect={(struct) => {
|
||||
setVisible(!visible)
|
||||
if (isMobileApp) {
|
||||
close()
|
||||
store.panels.openWidgetPanel({
|
||||
id: uniqueId(),
|
||||
type: PanelType.WIDGET,
|
||||
structId: struct.id,
|
||||
})
|
||||
} else {
|
||||
setVisible(!visible)
|
||||
}
|
||||
setStruct(struct)
|
||||
}}
|
||||
/>
|
||||
|
||||
15
packages/hooks/src/useMobileMenu.ts
Normal file
15
packages/hooks/src/useMobileMenu.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { atom, useAtom, useAtomValue } from 'jotai'
|
||||
|
||||
export const mobileMenuAtom = atom<any>({} as any)
|
||||
|
||||
export function useMobileMenu() {
|
||||
const [menu, setMenu] = useAtom(mobileMenuAtom)
|
||||
return {
|
||||
close: () => {
|
||||
return menu.current?.close()
|
||||
},
|
||||
open: () => menu.current?.open(),
|
||||
menu,
|
||||
setMenu,
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ function DropdownMenuContent({
|
||||
data-slot="dropdown-menu-content"
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) border-foreground/10 z-50 min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border p-1 shadow-md',
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) shadow-popover z-50 min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md p-1',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user