| @@ -15,7 +15,7 @@ export type IAppBasicProps = { | |||
| hoverTip?: string | |||
| textStyle?: { main?: string; extra?: string } | |||
| isExtraInLine?: boolean | |||
| mode?: 'expand' | 'collapse' | |||
| mode?: string | |||
| } | |||
| const ApiSvg = <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| @@ -56,7 +56,7 @@ const ICON_MAP = { | |||
| notion: <AppIcon innerIcon={NotionSvg} className='!border-[0.5px] !border-indigo-100 !bg-white' />, | |||
| } | |||
| export default function AppBasic({ icon, icon_background, name, type, hoverTip, textStyle, mode = 'expand', iconType = 'app', isExtraInLine }: IAppBasicProps) { | |||
| export default function AppBasic({ icon, icon_background, name, type, hoverTip, textStyle, mode = 'expand', iconType = 'app' }: IAppBasicProps) { | |||
| return ( | |||
| <div className="flex items-start"> | |||
| {icon && icon_background && iconType === 'app' && ( | |||
| @@ -1,8 +1,12 @@ | |||
| import React from 'react' | |||
| import React, { useCallback, useState } from 'react' | |||
| import NavLink from './navLink' | |||
| import type { NavIcon } from './navLink' | |||
| import AppBasic from './basic' | |||
| import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' | |||
| import { | |||
| AlignLeft01, | |||
| AlignRight01, | |||
| } from '@/app/components/base/icons/src/vender/line/layout' | |||
| export type IAppDetailNavProps = { | |||
| iconType?: 'app' | 'dataset' | 'notion' | |||
| @@ -20,23 +24,77 @@ export type IAppDetailNavProps = { | |||
| } | |||
| const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => { | |||
| const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand' | |||
| const media = useBreakpoints() | |||
| const isMobile = media === MediaType.mobile | |||
| const mode = isMobile ? 'collapse' : 'expand' | |||
| const [modeState, setModeState] = useState(isMobile ? mode : localeMode) | |||
| const expand = modeState === 'expand' | |||
| const handleToggle = useCallback(() => { | |||
| setModeState((prev) => { | |||
| const next = prev === 'expand' ? 'collapse' : 'expand' | |||
| localStorage.setItem('app-detail-collapse-or-expand', next) | |||
| return next | |||
| }) | |||
| }, []) | |||
| return ( | |||
| <div className="flex flex-col sm:w-56 w-16 overflow-y-auto bg-white border-r border-gray-200 shrink-0 mobile:h-screen"> | |||
| <div className="flex flex-shrink-0 p-4"> | |||
| <AppBasic mode={mode} iconType={iconType} icon={icon} icon_background={icon_background} name={title} type={desc} /> | |||
| <div | |||
| className={` | |||
| shrink-0 flex flex-col bg-white border-r border-gray-200 transition-all | |||
| ${expand ? 'w-[216px]' : 'w-14'} | |||
| `} | |||
| > | |||
| <div | |||
| className={` | |||
| shrink-0 | |||
| ${expand ? 'p-4' : 'p-2'} | |||
| `} | |||
| > | |||
| <AppBasic | |||
| mode={modeState} | |||
| iconType={iconType} | |||
| icon={icon} | |||
| icon_background={icon_background} | |||
| name={title} | |||
| type={desc} | |||
| /> | |||
| </div> | |||
| <nav className="flex-1 p-4 space-y-1 bg-white"> | |||
| <nav | |||
| className={` | |||
| grow space-y-1 bg-white | |||
| ${expand ? 'p-4' : 'px-2.5 py-4'} | |||
| `} | |||
| > | |||
| {navigation.map((item, index) => { | |||
| return ( | |||
| <NavLink key={index} mode={mode} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} /> | |||
| <NavLink key={index} mode={modeState} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} /> | |||
| ) | |||
| })} | |||
| {extraInfo ?? null} | |||
| </nav> | |||
| { | |||
| !isMobile && ( | |||
| <div | |||
| className={` | |||
| shrink-0 py-3 | |||
| ${expand ? 'px-6' : 'px-4'} | |||
| `} | |||
| > | |||
| <div | |||
| className='flex items-center justify-center w-6 h-6 text-gray-500 cursor-pointer' | |||
| onClick={handleToggle} | |||
| > | |||
| { | |||
| expand | |||
| ? <AlignLeft01 className='w-[14px] h-[14px]' /> | |||
| : <AlignRight01 className='w-[14px] h-[14px]' /> | |||
| } | |||
| </div> | |||
| </div> | |||
| ) | |||
| } | |||
| </div> | |||
| ) | |||
| } | |||
| @@ -18,7 +18,7 @@ export type NavLinkProps = { | |||
| selected: NavIcon | |||
| normal: NavIcon | |||
| } | |||
| mode?: 'expand' | 'collapse' | |||
| mode?: string | |||
| } | |||
| export default function NavLink({ | |||
| @@ -45,13 +45,15 @@ export default function NavLink({ | |||
| href={href} | |||
| className={classNames( | |||
| isActive ? 'bg-primary-50 text-primary-600 font-semibold' : 'text-gray-700 hover:bg-gray-100 hover:text-gray-700', | |||
| 'group flex items-center rounded-md px-2 py-2 text-sm font-normal', | |||
| 'group flex items-center h-9 rounded-md py-2 text-sm font-normal', | |||
| mode === 'expand' ? 'px-3' : 'px-2.5', | |||
| )} | |||
| > | |||
| <NavIcon | |||
| className={classNames( | |||
| 'mr-2 h-4 w-4 flex-shrink-0', | |||
| 'h-4 w-4 flex-shrink-0', | |||
| isActive ? 'text-primary-600' : 'text-gray-700', | |||
| mode === 'expand' ? 'mr-2' : 'mr-0', | |||
| )} | |||
| aria-hidden="true" | |||
| /> | |||
| @@ -0,0 +1,5 @@ | |||
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <g id="align-left-01"> | |||
| <path id="Icon" d="M3 3V21M21 12H7M7 12L14 19M7 12L14 5" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </g> | |||
| </svg> | |||
| @@ -0,0 +1,5 @@ | |||
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <g id="align-right-01"> | |||
| <path id="Icon" d="M21 21V3M3 12H17M17 12L10 5M17 12L10 19" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </g> | |||
| </svg> | |||
| @@ -0,0 +1,39 @@ | |||
| { | |||
| "icon": { | |||
| "type": "element", | |||
| "isRootNode": true, | |||
| "name": "svg", | |||
| "attributes": { | |||
| "width": "24", | |||
| "height": "24", | |||
| "viewBox": "0 0 24 24", | |||
| "fill": "none", | |||
| "xmlns": "http://www.w3.org/2000/svg" | |||
| }, | |||
| "children": [ | |||
| { | |||
| "type": "element", | |||
| "name": "g", | |||
| "attributes": { | |||
| "id": "align-left-01" | |||
| }, | |||
| "children": [ | |||
| { | |||
| "type": "element", | |||
| "name": "path", | |||
| "attributes": { | |||
| "id": "Icon", | |||
| "d": "M3 3V21M21 12H7M7 12L14 19M7 12L14 5", | |||
| "stroke": "currentColor", | |||
| "stroke-width": "2", | |||
| "stroke-linecap": "round", | |||
| "stroke-linejoin": "round" | |||
| }, | |||
| "children": [] | |||
| } | |||
| ] | |||
| } | |||
| ] | |||
| }, | |||
| "name": "AlignLeft01" | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| // GENERATE BY script | |||
| // DON NOT EDIT IT MANUALLY | |||
| import * as React from 'react' | |||
| import data from './AlignLeft01.json' | |||
| import IconBase from '@/app/components/base/icons/IconBase' | |||
| import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' | |||
| const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>(( | |||
| props, | |||
| ref, | |||
| ) => <IconBase {...props} ref={ref} data={data as IconData} />) | |||
| Icon.displayName = 'AlignLeft01' | |||
| export default Icon | |||
| @@ -0,0 +1,39 @@ | |||
| { | |||
| "icon": { | |||
| "type": "element", | |||
| "isRootNode": true, | |||
| "name": "svg", | |||
| "attributes": { | |||
| "width": "24", | |||
| "height": "24", | |||
| "viewBox": "0 0 24 24", | |||
| "fill": "none", | |||
| "xmlns": "http://www.w3.org/2000/svg" | |||
| }, | |||
| "children": [ | |||
| { | |||
| "type": "element", | |||
| "name": "g", | |||
| "attributes": { | |||
| "id": "align-right-01" | |||
| }, | |||
| "children": [ | |||
| { | |||
| "type": "element", | |||
| "name": "path", | |||
| "attributes": { | |||
| "id": "Icon", | |||
| "d": "M21 21V3M3 12H17M17 12L10 5M17 12L10 19", | |||
| "stroke": "currentColor", | |||
| "stroke-width": "2", | |||
| "stroke-linecap": "round", | |||
| "stroke-linejoin": "round" | |||
| }, | |||
| "children": [] | |||
| } | |||
| ] | |||
| } | |||
| ] | |||
| }, | |||
| "name": "AlignRight01" | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| // GENERATE BY script | |||
| // DON NOT EDIT IT MANUALLY | |||
| import * as React from 'react' | |||
| import data from './AlignRight01.json' | |||
| import IconBase from '@/app/components/base/icons/IconBase' | |||
| import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' | |||
| const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>(( | |||
| props, | |||
| ref, | |||
| ) => <IconBase {...props} ref={ref} data={data as IconData} />) | |||
| Icon.displayName = 'AlignRight01' | |||
| export default Icon | |||
| @@ -1 +1,3 @@ | |||
| export { default as AlignLeft01 } from './AlignLeft01' | |||
| export { default as AlignRight01 } from './AlignRight01' | |||
| export { default as Grid01 } from './Grid01' | |||