@topthink/common 1.1.18 → 1.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/types/index.d.ts +1 -10
- package/types/layout/sider.d.ts +2 -2
- package/types/utils/get-menu-data.d.ts +9 -1
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteral.js","../src/components/footer.tsx","../src/utils/get-menu-data.ts","../src/layout/sider.tsx","../src/pages/login.tsx","../src/pages/logout.tsx","../src/utils/create-application.tsx","../src/components/user-provider.tsx","../src/components/header.tsx","../src/images/logo.svg","../src/components/access.tsx","../src/components/content.tsx"],"sourcesContent":["export default function _taggedTemplateLiteral(strings, raw) {\n if (!raw) {\n raw = strings.slice(0);\n }\n\n return Object.freeze(Object.defineProperties(strings, {\n raw: {\n value: Object.freeze(raw)\n }\n }));\n}","import { styled } from '@topthink/components';\r\n\r\nconst FooterWrapper = styled.footer`\r\n\r\n`;\r\n\r\nexport default function Footer() {\r\n return <FooterWrapper>\r\n <div className='container'>\r\n\r\n </div>\r\n </FooterWrapper>;\r\n}\r\n","import type { RouteObject } from 'react-router';\r\n\r\nexport interface MenuData {\r\n path: string;\r\n title: string;\r\n icon?: string;\r\n children: MenuData[];\r\n}\r\n\r\nconst formatRelativePath = (\r\n routes: RouteObject[],\r\n parent: string = '/',\r\n): MenuData[] => {\r\n\r\n const menus: MenuData[] = [];\r\n\r\n for (const route of routes) {\r\n\r\n if (route.meta?.hideInMenu) {\r\n continue;\r\n }\r\n\r\n const title = route.meta?.title;\r\n if (!title) {\r\n continue;\r\n }\r\n\r\n let path = route.path || '';\r\n\r\n path = `${parent}/${path}`;\r\n\r\n path = path.replace(/\\/+/, '/').replace(/\\/$/, '');\r\n\r\n const icon = route.meta?.icon;\r\n\r\n const menu: MenuData = {\r\n title,\r\n icon,\r\n path,\r\n children: []\r\n };\r\n\r\n if (!route.meta?.hideChildrenInMenu) {\r\n if (route.children && route.children.length > 0) {\r\n menu.children = formatRelativePath(route.children, path);\r\n }\r\n }\r\n\r\n menus.push(menu);\r\n }\r\n\r\n return menus;\r\n};\r\n\r\nexport default function getMenuData(routes: RouteObject[], base: string = '/'): MenuData[] {\r\n return formatRelativePath(routes, base);\r\n}\r\n","import RcMenu, { MenuItem, SubMenu } from 'rc-menu';\r\nimport Footer from '../components/footer';\r\nimport { Link, useLocation, useRoutes } from 'react-router-dom';\r\nimport { useEffect, useMemo, useState } from 'react';\r\nimport type { RouteObject } from 'react-router';\r\nimport getMenuData, { MenuData } from '../utils/get-menu-data';\r\nimport type { CSSMotionProps } from 'rc-motion';\r\nimport { styled } from '@topthink/components';\r\n\r\ninterface Props {\r\n title: string;\r\n routes: RouteObject[];\r\n basename: string;\r\n}\r\n\r\nconst renderMenuItems = (items: MenuData[]) => {\r\n return items.map((item) => {\r\n\r\n const title = <>\r\n {item.icon && <i className={`bi bi-${item.icon}`} />}\r\n {item.title}\r\n </>;\r\n\r\n if (item.children.length > 0) {\r\n return <SubMenu title={title} key={item.path}>\r\n {renderMenuItems(item.children)}\r\n </SubMenu>;\r\n } else {\r\n return <MenuItem key={item.path}>\r\n <Link to={item.path}>\r\n {title}\r\n </Link>\r\n </MenuItem>;\r\n }\r\n });\r\n};\r\n\r\nconst collapseNode = () => {\r\n return { height: 0 };\r\n};\r\nconst expandNode = (node: HTMLElement) => {\r\n return { height: node.scrollHeight };\r\n};\r\n\r\nconst motion: CSSMotionProps = {\r\n motionName: 'rc-menu-collapse',\r\n motionAppear: true,\r\n onAppearStart: collapseNode,\r\n onAppearActive: expandNode,\r\n onEnterStart: collapseNode,\r\n onEnterActive: expandNode,\r\n onLeaveStart: expandNode,\r\n onLeaveActive: collapseNode,\r\n};\r\n\r\n\r\nexport default function SiderLayout({ routes, basename, title }: Props) {\r\n\r\n const children = useRoutes(routes);\r\n\r\n const menu = useMemo(() => getMenuData(routes, basename), [routes, basename]);\r\n\r\n const { pathname } = useLocation();\r\n\r\n const selectedKeys = useMemo(() => {\r\n const keys: string[] = [];\r\n const parts = pathname.split('/');\r\n parts.reduce<string[]>((pre, curr) => {\r\n if (pre.length > 1) {\r\n keys.push(pre.join('/'));\r\n }\r\n return [...pre, curr];\r\n }, []);\r\n keys.push(pathname);\r\n return keys;\r\n }, [pathname]);\r\n\r\n const [openKeys, setOpenKeys] = useState<string[]>([]);\r\n\r\n useEffect(() => {\r\n setOpenKeys(selectedKeys.slice(0, -1));\r\n }, [selectedKeys]);\r\n\r\n const onOpenChange = (openKeys: string[]) => {\r\n const currentKey = openKeys[openKeys.length - 1];\r\n setOpenKeys(openKeys.filter(key => currentKey.startsWith(key)));\r\n };\r\n\r\n return <Container>\r\n <Sidebar>\r\n <Header>{title}</Header>\r\n <Menu\r\n mode='inline'\r\n motion={motion}\r\n openKeys={openKeys}\r\n onOpenChange={onOpenChange}\r\n selectedKeys={selectedKeys}\r\n >\r\n {renderMenuItems(menu)}\r\n </Menu>\r\n </Sidebar>\r\n <Content>\r\n <Main>{children}</Main>\r\n <Footer />\r\n </Content>\r\n </Container>;\r\n}\r\n\r\nconst Container = styled.div`\r\n display: flex;\r\n flex-wrap: nowrap;\r\n width: 100%;\r\n`;\r\n\r\nconst Sidebar = styled.nav`\r\n position: fixed;\r\n top: 0;\r\n bottom: 0;\r\n left: 0;\r\n z-index: 100;\r\n padding: 54px 0 0;\r\n border-right: 1px solid #e3e3e3;\r\n width: 230px;\r\n background-color: #f5f5f5;\r\n`;\r\n\r\nconst Header = styled.div`\r\n padding: 10px 0;\r\n height: 64px;\r\n line-height: 44px;\r\n text-indent: 24px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n font-size: 16px;\r\n`;\r\n\r\nconst Content = styled.div`\r\n margin-left: 230px;\r\n flex: 1;\r\n`;\r\n\r\nconst Main = styled.main`\r\n min-height: calc(100vh - 54px);\r\n position: relative;\r\n`;\r\n\r\nconst Menu = styled(RcMenu)`\r\n border: none;\r\n box-shadow: none;\r\n padding: 0;\r\n\r\n .rc-menu-item {\r\n display: flex;\r\n\r\n &:hover {\r\n background-color: #f0f0f0;\r\n }\r\n\r\n a {\r\n flex: 1;\r\n text-decoration: none;\r\n color: dimgray;\r\n\r\n .bi {\r\n font-size: 16px;\r\n line-height: 18px;\r\n margin-right: 9px;\r\n min-width: 19px;\r\n text-align: center;\r\n vertical-align: text-bottom;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-sub {\r\n background-color: #eee;\r\n border-top: 1px solid #eee;\r\n border-bottom: 1px solid #eee;\r\n\r\n & > li {\r\n &:first-child {\r\n margin-top: 4px;\r\n }\r\n\r\n &:last-child {\r\n margin-bottom: 4px;\r\n }\r\n }\r\n\r\n .rc-menu-item-selected {\r\n background-color: #eee;\r\n color: var(--bs-primary);\r\n\r\n & > a {\r\n color: var(--bs-primary);\r\n }\r\n }\r\n\r\n .rc-menu-item-active {\r\n background-color: #eee;\r\n }\r\n\r\n .rc-menu-item {\r\n &:hover {\r\n background-color: #e7e7e7;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-submenu {\r\n & > .rc-menu-submenu-title {\r\n &:hover {\r\n background-color: #e7e7e7;\r\n }\r\n\r\n .bi {\r\n font-size: 16px;\r\n line-height: 18px;\r\n margin-right: 9px;\r\n min-width: 19px;\r\n text-align: center;\r\n vertical-align: text-bottom;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-submenu-active > .rc-menu-submenu-title {\r\n background-color: #eee;\r\n }\r\n\r\n .rc-menu-item,\r\n .rc-menu-submenu > .rc-menu-submenu-title {\r\n padding: 0 8px 0 24px;\r\n font-size: 14px;\r\n line-height: 36px;\r\n cursor: pointer;\r\n }\r\n\r\n .rc-menu-sub > .rc-menu-item,\r\n .rc-menu-sub > .rc-menu-submenu > .rc-menu-submenu-title {\r\n padding-top: 0;\r\n padding-bottom: 0;\r\n padding-right: 0;\r\n }\r\n\r\n .rc-menu-submenu-arrow {\r\n line-height: 38px;\r\n }\r\n\r\n .rc-menu-item-selected {\r\n background-color: #f5f5f5;\r\n color: var(--bs-primary);\r\n\r\n & > a {\r\n color: var(--bs-primary);\r\n }\r\n }\r\n\r\n .rc-menu-submenu-selected {\r\n background-color: #eee;\r\n\r\n & > .rc-menu-submenu-title {\r\n color: var(--bs-primary);\r\n font-weight: 500;\r\n }\r\n }\r\n\r\n & > .rc-menu-item {\r\n line-height: 38px;\r\n }\r\n\r\n & > .rc-menu-submenu {\r\n &.rc-menu-submenu-selected {\r\n background-color: #f5f5f5;\r\n }\r\n\r\n & > .rc-menu-submenu-title {\r\n line-height: 38px;\r\n\r\n &:hover {\r\n background-color: #f0f0f0;\r\n }\r\n }\r\n\r\n &.rc-menu-submenu-active > .rc-menu-submenu-title {\r\n background-color: #f5f5f5;\r\n }\r\n\r\n & > .rc-menu-sub {\r\n border-top: 1px solid #e6e6e6;\r\n border-bottom: 1px solid #e6e6e6;\r\n\r\n & > li {\r\n &:first-child {\r\n margin-top: 9px;\r\n }\r\n\r\n &:last-child {\r\n margin-bottom: 9px;\r\n }\r\n }\r\n }\r\n }\r\n\r\n`;\r\n","import { Loader, useAsync } from '@topthink/components';\r\nimport { Navigate } from 'react-router-dom';\r\n\r\ninterface LoginProps {\r\n onLogin: () => void | Promise<void>;\r\n}\r\n\r\nexport default function Login({ onLogin }: LoginProps) {\r\n const { result } = useAsync(async () => {\r\n await onLogin();\r\n\r\n const redirectUri = localStorage.getItem('redirect_uri');\r\n if (redirectUri) {\r\n localStorage.removeItem('redirect_uri');\r\n }\r\n return redirectUri || '/';\r\n }, []);\r\n\r\n if (result) {\r\n return <Navigate to={result} replace />;\r\n }\r\n\r\n return <Loader />;\r\n}\r\n","import { Loader, useAsync } from '@topthink/components';\r\n\r\ninterface LogoutProps {\r\n onLogout: () => void | Promise<void>;\r\n}\r\n\r\nexport default function Logout({ onLogout }: LogoutProps) {\r\n useAsync(async () => {\r\n await onLogout();\r\n }, []);\r\n\r\n return <Loader />;\r\n}\r\n","import { BrowserRouter, Route, Routes } from 'react-router-dom';\r\nimport React, { PropsWithChildren } from 'react';\r\nimport Login from '../pages/login';\r\nimport Logout from '../pages/logout';\r\nimport queryString from 'query-string';\r\nimport { User } from './types';\r\nimport * as path from 'path';\r\nimport { request, Unauthorized } from '@topthink/components';\r\n\r\ntype UserResolver = () => User | Promise<User>\r\n\r\nexport const AppContext = React.createContext<{ userResolver?: UserResolver, onUnauthorized?: (error: Unauthorized) => void }>({});\r\n\r\nfunction stripBasename(pathname: string, basename: string) {\r\n if (basename === '/') return pathname;\r\n\r\n return pathname.slice(basename.length);\r\n}\r\n\r\ninterface Options {\r\n baseURL?: string;\r\n basename?: string;\r\n authentication?: 'cookie' | 'token';\r\n onLogout?: () => void | Promise<void>;\r\n onLogin?: () => (void | string) | Promise<void | string>;\r\n userResolver?: UserResolver;\r\n}\r\n\r\nexport default function createApplication(options: Options) {\r\n const { basename = '/', onLogin, onLogout, authentication, baseURL, userResolver } = options;\r\n\r\n if (baseURL) {\r\n request.defaults.baseURL = baseURL;\r\n }\r\n\r\n if (authentication === 'token') {\r\n request.interceptors.request.use(\r\n config => {\r\n const token = localStorage.getItem('authorization');\r\n\r\n if (token) {\r\n config.headers = {\r\n ...config.headers,\r\n Authorization: `Bearer ${token}`\r\n };\r\n }\r\n return config;\r\n }\r\n );\r\n }\r\n\r\n const onUnauthorized = (error: Unauthorized) => {\r\n if (window.location.pathname !== path.join(basename, '/logout')) {\r\n localStorage.setItem('redirect_uri', stripBasename(window.location.pathname + window.location.search, basename));\r\n }\r\n const redirectUri = window.location.origin + path.join(basename, '/login');\r\n\r\n window.location.href = queryString.stringifyUrl({\r\n url: error.url,\r\n query: { redirect_uri: redirectUri }\r\n });\r\n };\r\n\r\n const handleLogin = async () => {\r\n let token: string | void;\r\n if (onLogin) {\r\n token = await onLogin();\r\n } else {\r\n const parsed = queryString.parse(window.location.hash.substr(1));\r\n if (parsed.access_token) {\r\n token = parsed.access_token as string;\r\n }\r\n }\r\n\r\n if (authentication === 'token' && token) {\r\n localStorage.setItem('authorization', token);\r\n }\r\n };\r\n\r\n const handleLogout = async () => {\r\n if (onLogout) {\r\n try {\r\n await onLogout();\r\n } catch (e) {\r\n if (e instanceof Unauthorized) {\r\n onUnauthorized(e);\r\n }\r\n }\r\n }\r\n\r\n if (authentication === 'token') {\r\n localStorage.removeItem('authorization');\r\n }\r\n };\r\n\r\n return function({ children }: PropsWithChildren<any>) {\r\n return <AppContext.Provider value={{ userResolver, onUnauthorized }}>\r\n <BrowserRouter basename={basename}>\r\n <Routes>\r\n <Route path='*' element={children} />\r\n <Route path='login' element={<Login onLogin={handleLogin} />} />\r\n <Route path='logout' element={<Logout onLogout={handleLogout} />} />\r\n </Routes>\r\n </BrowserRouter>\r\n </AppContext.Provider>;\r\n };\r\n}\r\n","import React, { PropsWithChildren, useContext, useState } from 'react';\r\nimport { User } from '../utils/types';\r\nimport { AppContext } from '../utils/create-application';\r\nimport { Loader, Unauthorized, useAsync } from '@topthink/components';\r\n\r\nexport const UserContext = React.createContext<[User, ((user: User) => void)] | null>(null);\r\n\r\nconst UserProvider = function({ children }: PropsWithChildren<any>) {\r\n const [state, setState] = useState<User | null>(null);\r\n\r\n const { userResolver, onUnauthorized } = useContext(AppContext);\r\n\r\n useAsync(async () => {\r\n if (userResolver) {\r\n return userResolver();\r\n }\r\n }, [], {\r\n onError(e) {\r\n if (e instanceof Unauthorized && onUnauthorized) {\r\n onUnauthorized(e);\r\n }\r\n },\r\n onSuccess(user) {\r\n if (user) {\r\n setState(user);\r\n }\r\n }\r\n });\r\n\r\n if (!state) {\r\n return <Loader />;\r\n }\r\n\r\n return <UserContext.Provider value={[state, setState]}>\r\n {children}\r\n </UserContext.Provider>;\r\n};\r\n\r\nexport function useUser() {\r\n const context = useContext(UserContext);\r\n if (!context) {\r\n throw new Error('please use `useUser` in UserContext');\r\n }\r\n\r\n return context;\r\n}\r\n\r\nexport default UserProvider;\r\n","import logoSrc from '../images/logo.svg';\r\nimport { Dropdown } from 'react-bootstrap';\r\nimport { PropsWithChildren, ReactNode } from 'react';\r\nimport { useUser } from './user-provider';\r\nimport classNames from 'classnames';\r\nimport { styled } from '@topthink/components';\r\n\r\nconst Avatar = styled.a`\r\n cursor: pointer;\r\n`;\r\n\r\ninterface Props {\r\n menus: ReactNode;\r\n className?: string;\r\n logo?: boolean;\r\n}\r\n\r\nexport default function Header({ children, menus, className, logo = true }: PropsWithChildren<Props>) {\r\n const [user] = useUser();\r\n\r\n return <Container\r\n className={classNames('navbar navbar-expand-lg navbar-light bg-white border-bottom sticky-top', className)}>\r\n <div className='container-fluid'>\r\n {logo && <a className='navbar-brand' href='https://www.topthink.com'>\r\n <img src={logoSrc} height='30' />\r\n </a>}\r\n {children}\r\n <Dropdown navbar>\r\n <Dropdown.Toggle as={Avatar} className='nav-link'>\r\n <img className='rounded-circle' width='25' height='25' src={user.avatar} />\r\n </Dropdown.Toggle>\r\n <Dropdown.Menu className={'shadow'}>\r\n {menus}\r\n </Dropdown.Menu>\r\n </Dropdown>\r\n </div>\r\n </Container>;\r\n}\r\n\r\nconst Container = styled.header`\r\n height: 54px;\r\n`;\r\n","var img = \"data:image/svg+xml,%3csvg width='485' height='132' xmlns='http://www.w3.org/2000/svg' xml:space='preserve' style='enable-background:new 0 0 531.69 198.43%3b' version='1.1'%3e %3cstyle type='text/css'%3e.st0%7bfill:%233C60FF%3b%7d%3c/style%3e %3cg%3e %3ctitle%3ebackground%3c/title%3e %3crect fill='none' id='canvas_background' height='134' width='487' y='-1' x='-1'/%3e %3c/g%3e %3cg%3e %3ctitle%3eLayer 1%3c/title%3e %3cpath id='svg_1' d='m132.29%2c62.34c-1.19%2c-18.77 -10.34%2c-35.36 -24.11%2c-46.46c-11.15%2c-8.99 -25.34%2c-14.38 -40.79%2c-14.38c-0.55%2c0 -1.09%2c0.01 -1.63%2c0.02c-3.32%2c0.08 -6.57%2c0.41 -9.75%2c0.98c-30.49%2c5.38 -53.65%2c32 -53.65%2c64.04c0%2c1.87 0.08%2c3.73 0.24%2c5.57c2.5%2c29.51 24.7%2c53.4 53.41%2c58.47c2.38%2c0.42 4.8%2c0.72 7.26%2c0.86c0.83%2c0.05 1.66%2c0.09 2.5%2c0.11c0.54%2c0.01 1.08%2c0.02 1.63%2c0.02c34.04%2c0 61.97%2c-26.16 64.79%2c-59.46c0.16%2c-1.83 0.24%2c-3.69 0.24%2c-5.57c0%2c-1.42 -0.05%2c-2.82 -0.14%2c-4.2zm-76.27%2c32.5c-0.26%2c0.01 -0.53%2c0.01 -0.79%2c0.01c-14.56%2c0 -26.88%2c-9.57 -31.03%2c-22.76c-0.97%2c-3.08 -1.49%2c-6.35 -1.49%2c-9.75c0%2c-17.95 14.56%2c-32.52 32.51%2c-32.52c0.26%2c0 0.53%2c0 0.79%2c0.01c3.41%2c0.08 6.69%2c0.68 9.75%2c1.74c6.5%2c2.22 12.06%2c6.45 15.97%2c11.94c1.98%2c2.78 3.54%2c5.9 4.57%2c9.25c0.94%2c3.03 1.44%2c6.24 1.44%2c9.58l-9.75%2c0c0%2c-2.18 -0.31%2c-4.29 -0.88%2c-6.28c-0.92%2c-3.23 -2.55%2c-6.17 -4.69%2c-8.64c-1.86%2c-2.14 -4.12%2c-3.93 -6.65%2c-5.25c-2.93%2c-1.54 -6.24%2c-2.46 -9.75%2c-2.58c-0.26%2c-0.01 -0.52%2c-0.01 -0.79%2c-0.01c-12.57%2c0 -22.76%2c10.19 -22.76%2c22.76c0%2c3.49 0.79%2c6.8 2.19%2c9.75c3.65%2c7.69 11.49%2c13.01 20.57%2c13.01c0.27%2c0 0.53%2c-0.01 0.79%2c-0.01l0%2c9.75zm55.7%2c-17.92c-3.35%2c10.5 -13.18%2c18.09 -24.78%2c18.09c-3.13%2c0 -6.13%2c-0.55 -8.91%2c-1.57c-2.18%2c-0.8 -4.24%2c-1.88 -6.11%2c-3.21c-2.38%2c-1.68 -4.47%2c-3.76 -6.16%2c-6.13c-0.28%2c-0.39 -0.55%2c-0.79 -0.81%2c-1.2c-2.03%2c-3.2 -3.38%2c-6.87 -3.85%2c-10.82l9.87%2c0c0.33%2c1.71 0.92%2c3.32 1.74%2c4.8c1.61%2c2.91 4.09%2c5.26 7.09%2c6.72c0.57%2c0.28 1.15%2c0.53 1.76%2c0.73c1.68%2c0.6 3.49%2c0.92 5.37%2c0.92c7.92%2c0 14.52%2c-5.67 15.96%2c-13.17c0.2%2c-1 0.3%2c-2.04 0.3%2c-3.09c0%2c-2.37 -0.51%2c-4.63 -1.43%2c-6.67c-1.66%2c-3.71 -4.68%2c-6.68 -8.43%2c-8.28l3.54%2c-9.1c7.43%2c3.08 13.13%2c9.49 15.21%2c17.38c0.44%2c1.64 0.72%2c3.34 0.81%2c5.09c0.04%2c0.52 0.05%2c1.05 0.05%2c1.58c0%2c1.05 -0.07%2c2.07 -0.18%2c3.09c-0.18%2c1.68 -0.54%2c3.3 -1.04%2c4.84z' class='st0'/%3e %3cg id='svg_2'%3e %3cg id='svg_3'%3e %3crect id='svg_4' height='6.34' width='94.12' class='st0' y='20.46' x='163.29'/%3e %3c/g%3e %3cg id='svg_5'%3e %3cpath id='svg_6' d='m169.31%2c113.72l0%2c-6.34c6.49%2c0 11.77%2c-5.28 11.77%2c-11.77l0%2c-71.98l6.34%2c0l0%2c71.98c0%2c9.98 -8.12%2c18.11 -18.11%2c18.11z' class='st0'/%3e %3c/g%3e %3cg id='svg_7'%3e %3cpath id='svg_8' d='m255.49%2c91.27l-6.34%2c0l0%2c-38.2c0%2c-5.06 -4.12%2c-9.18 -9.18%2c-9.18l-19.37%2c0c-5.06%2c0 -9.18%2c4.12 -9.18%2c9.18l0%2c38.2l-6.34%2c0l0%2c-38.2c0%2c-8.55 6.96%2c-15.51 15.51%2c-15.51l19.38%2c0c8.55%2c0 15.51%2c6.96 15.51%2c15.51l0%2c38.2l0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_9'%3e %3crect id='svg_10' height='17.09' width='6.34' class='st0' y='23.63' x='227.12'/%3e %3c/g%3e %3cg id='svg_11'%3e %3cpath id='svg_12' d='m206.43%2c113.84l-3.34%2c0l0%2c-6.34l3.34%2c0c6.3%2c0 12.9%2c-3.56 15.35%2c-8.29c3.49%2c-6.71 5.33%2c-14.25 5.33%2c-21.81l0%2c-26.13l6.34%2c0l0%2c26.13c0%2c8.58 -2.09%2c17.13 -6.05%2c24.74c-3.98%2c7.68 -13.57%2c11.7 -20.97%2c11.7z' class='st0'/%3e %3c/g%3e %3cg id='svg_13'%3e %3cpath id='svg_14' d='m257.48%2c113.84l-3.34%2c0c-7.4%2c0 -16.98%2c-4.02 -20.98%2c-11.7c-3.96%2c-7.61 -6.05%2c-16.16 -6.05%2c-24.74l6.34%2c0c0%2c7.56 1.84%2c15.1 5.33%2c21.81c2.46%2c4.73 9.06%2c8.29 15.35%2c8.29l3.34%2c0l0%2c6.34l0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_15'%3e %3crect id='svg_16' height='6.34' width='42.87' class='st0' y='27.89' x='274.07'/%3e %3c/g%3e %3cg id='svg_17'%3e %3crect id='svg_18' height='61.38' width='6.34' class='st0' y='14.89' x='293.05'/%3e %3c/g%3e %3cg id='svg_19'%3e %3crect id='svg_20' height='6.34' width='33.26' class='st0' transform='matrix(0.11%2c-0.9939%2c0.9939%2c0.11%2c194.7608%2c392.0006) ' y='46.985071' x='325.728637'/%3e %3c/g%3e %3cg id='svg_21'%3e %3crect id='svg_22' height='33.26' width='6.34' class='st0' transform='matrix(0.9939%2c-0.11%2c0.11%2c0.9939%2c-7.5075%2c38.3801) ' y='37.060893' x='310.495485'/%3e %3c/g%3e %3cg id='svg_23'%3e %3cpath id='svg_24' d='m352.9%2c77.14l-15.15%2c0c-7.52%2c0 -13.64%2c-6.12 -13.64%2c-13.63l0%2c-29.61c0%2c-7.52 6.12%2c-13.64 13.64%2c-13.64l15.15%2c0c7.52%2c0 13.64%2c6.12 13.64%2c13.64l0%2c29.61c0%2c7.52 -6.12%2c13.63 -13.64%2c13.63zm-15.15%2c-50.54c-4.02%2c0 -7.3%2c3.27 -7.3%2c7.3l0%2c29.61c0%2c4.02 3.27%2c7.3 7.3%2c7.3l15.15%2c0c4.02%2c0 7.3%2c-3.27 7.3%2c-7.3l0%2c-29.61c0%2c-4.02 -3.27%2c-7.3 -7.3%2c-7.3l-15.15%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_25'%3e %3cg id='svg_26'%3e %3crect id='svg_27' height='6.34' width='17.8' class='st0' y='37.2' x='336.43'/%3e %3c/g%3e %3cg id='svg_28'%3e %3crect id='svg_29' height='6.34' width='17.8' class='st0' y='53.87' x='336.43'/%3e %3c/g%3e %3c/g%3e %3cg id='svg_30'%3e %3cpath id='svg_31' d='m352.7%2c113.84l-37.98%2c0c-8%2c0 -14.5%2c-6.51 -14.5%2c-14.5l0%2c-16.14l6.34%2c0l0%2c16.13c0%2c4.5 3.66%2c8.17 8.17%2c8.17l37.98%2c0l0%2c6.34l-0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_32'%3e %3crect id='svg_33' height='6.34' width='23.57' class='st0' transform='matrix(0.2529%2c-0.9675%2c0.9675%2c0.2529%2c114.4986%2c402.9877) ' y='83.698593' x='326.836101'/%3e %3c/g%3e %3cg id='svg_34'%3e %3crect id='svg_35' height='6.34' width='20.52' class='st0' y='86.2' x='321.58'/%3e %3c/g%3e %3cg id='svg_36'%3e %3crect id='svg_37' height='24.75' width='6.34' class='st0' transform='matrix(0.9556%2c-0.2946%2c0.2946%2c0.9556%2c-19.7967%2c122.424) ' y='75.874073' x='369.686666'/%3e %3c/g%3e %3cg id='svg_38'%3e %3crect id='svg_39' height='6.34' width='71.83' class='st0' y='20.46' x='395.51'/%3e %3c/g%3e %3cg id='svg_40'%3e %3crect id='svg_41' height='6.34' width='90.81' class='st0' y='57.44' x='386.02'/%3e %3c/g%3e %3cg id='svg_42'%3e %3cpath id='svg_43' d='m463.12%2c113.64l-56%2c0c-4.5%2c0 -8.59%2c-2.29 -10.94%2c-6.14c-2.35%2c-3.84 -2.52%2c-8.53 -0.46%2c-12.53l17.68%2c-35.81l5.64%2c2.89l-17.68%2c35.81c-1.04%2c2.02 -0.95%2c4.39 0.23%2c6.33c1.19%2c1.94 3.25%2c3.1 5.53%2c3.1l56%2c0c1.51%2c0 2.88%2c-0.71 3.74%2c-1.95c0.81%2c-1.16 1.03%2c-2.57 0.63%2c-3.91l-7.8%2c-12.34l5.36%2c-3.39l8.18%2c12.94l0.12%2c0.31c1.24%2c3.34 0.76%2c7.08 -1.28%2c10.01c-2.04%2c2.94 -5.39%2c4.68 -8.95%2c4.68z' class='st0'/%3e %3c/g%3e %3c/g%3e %3c/g%3e%3c/svg%3e\";\n export default img;","import { ReactNode } from 'react';\r\nimport { intersection } from 'lodash';\r\nimport { useUser } from './user-provider';\r\nimport { User } from '../utils/types';\r\n\r\nexport interface AccessProps {\r\n require?: string | string[] | ((user: User) => boolean);\r\n fallback?: ReactNode;\r\n children: ReactNode;\r\n}\r\n\r\nexport default function Access({\r\n require,\r\n children,\r\n fallback\r\n}: AccessProps) {\r\n const [user,] = useUser();\r\n let passed = false;\r\n if (typeof require === 'function') {\r\n passed = require(user);\r\n } else {\r\n if (typeof require === 'string') {\r\n require = [require];\r\n }\r\n passed = intersection(user.roles, require).length > 0;\r\n }\r\n if (!passed) {\r\n children = fallback;\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","import { styled } from '@topthink/components';\r\nimport { PropsWithChildren, ReactNode } from 'react';\r\n\r\ninterface ContentProps {\r\n title: string;\r\n nav?: ReactNode;\r\n extra?: ReactNode;\r\n}\r\n\r\nexport default function Content({ title, children, nav, extra }: PropsWithChildren<ContentProps>) {\r\n\r\n return <Container>\r\n <Header>\r\n <div className='container'>\r\n <Title>\r\n {title}\r\n </Title>\r\n {nav}\r\n <Extra>{extra}</Extra>\r\n </div>\r\n </Header>\r\n <Body className='container'>\r\n {children}\r\n </Body>\r\n </Container>;\r\n};\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n`;\r\n\r\nconst Header = styled.div`\r\n background-color: #fff;\r\n display: flex;\r\n\r\n .container {\r\n padding: 0 24px;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n\r\n .nav {\r\n .nav-link {\r\n position: relative;\r\n\r\n &.active {\r\n &:after {\r\n content: '';\r\n height: 2px;\r\n background: var(--bs-primary);\r\n display: block;\r\n position: absolute;\r\n left: 1rem;\r\n right: 1rem;\r\n bottom: -2px;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nconst Body = styled.div`\r\n margin-top: 24px;\r\n`;\r\n\r\nconst Title = styled.div`\r\n font-size: 22px;\r\n line-height: 64px;\r\n height: 64px;\r\n`;\r\n\r\nconst Extra = styled.div`\r\n\r\n`;\r\n"],"names":["_taggedTemplateLiteral","strings","raw","slice","Object","freeze","defineProperties","value","FooterWrapper","styled","footer","Footer","_jsx","className","formatRelativePath","routes","parent","menus","route","meta","_route$meta","hideInMenu","title","_route$meta2","path","replace","menu","icon","_route$meta3","children","_route$meta4","hideChildrenInMenu","length","push","renderMenuItems","items","map","item","_jsxs","SubMenu","MenuItem","Link","to","collapseNode","height","expandNode","node","scrollHeight","motion","motionName","motionAppear","onAppearStart","onAppearActive","onEnterStart","onEnterActive","onLeaveStart","onLeaveActive","SiderLayout","basename","useRoutes","useMemo","getMenuData","pathname","useLocation","selectedKeys","keys","split","reduce","pre","curr","join","openKeys","setOpenKeys","useState","useEffect","Container","Sidebar","Header","Menu","mode","onOpenChange","currentKey","filter","key","startsWith","Content","Main","div","nav","main","RcMenu","Login","onLogin","result","useAsync","async","redirectUri","localStorage","getItem","removeItem","Navigate","Loader","Logout","onLogout","AppContext","React","createContext","createApplication","options","authentication","baseURL","userResolver","request","defaults","interceptors","use","config","token","headers","Authorization","onUnauthorized","error","window","location","setItem","stripBasename","search","origin","href","queryString","stringifyUrl","url","query","redirect_uri","handleLogin","parsed","parse","hash","substr","access_token","handleLogout","e","Unauthorized","Provider","BrowserRouter","Routes","Route","element","UserContext","UserProvider","state","setState","useContext","onError","onSuccess","user","useUser","context","Error","Avatar","a","logo","classNames","src","Dropdown","navbar","Toggle","as","width","avatar","header","Access","require","fallback","passed","intersection","roles","extra","Title","Extra","Body"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteral.js","../src/components/footer.tsx","../src/utils/get-menu-data.ts","../src/layout/sider.tsx","../src/pages/login.tsx","../src/pages/logout.tsx","../src/utils/create-application.tsx","../src/components/user-provider.tsx","../src/components/header.tsx","../src/images/logo.svg","../src/components/access.tsx","../src/components/content.tsx"],"sourcesContent":["export default function _taggedTemplateLiteral(strings, raw) {\n if (!raw) {\n raw = strings.slice(0);\n }\n\n return Object.freeze(Object.defineProperties(strings, {\n raw: {\n value: Object.freeze(raw)\n }\n }));\n}","import { styled } from '@topthink/components';\r\n\r\nconst FooterWrapper = styled.footer`\r\n\r\n`;\r\n\r\nexport default function Footer() {\r\n return <FooterWrapper>\r\n <div className='container'>\r\n\r\n </div>\r\n </FooterWrapper>;\r\n}\r\n","import type { RouteObject } from 'react-router';\r\n\r\nexport interface MenuObject extends RouteObject {\r\n meta?: {\r\n title?: string\r\n icon?: string\r\n hideInMenu?: boolean\r\n hideChildrenInMenu?: boolean\r\n };\r\n}\r\n\r\nexport interface MenuData {\r\n path: string;\r\n title: string;\r\n icon?: string;\r\n children: MenuData[];\r\n}\r\n\r\nconst formatRelativePath = (\r\n routes: MenuObject[],\r\n parent: string = '/',\r\n): MenuData[] => {\r\n\r\n const menus: MenuData[] = [];\r\n\r\n for (const route of routes) {\r\n\r\n if (route.meta?.hideInMenu) {\r\n continue;\r\n }\r\n\r\n const title = route.meta?.title;\r\n if (!title) {\r\n continue;\r\n }\r\n\r\n let path = route.path || '';\r\n\r\n path = `${parent}/${path}`;\r\n\r\n path = path.replace(/\\/+/, '/').replace(/\\/$/, '');\r\n\r\n const icon = route.meta?.icon;\r\n\r\n const menu: MenuData = {\r\n title,\r\n icon,\r\n path,\r\n children: []\r\n };\r\n\r\n if (!route.meta?.hideChildrenInMenu) {\r\n if (route.children && route.children.length > 0) {\r\n menu.children = formatRelativePath(route.children, path);\r\n }\r\n }\r\n\r\n menus.push(menu);\r\n }\r\n\r\n return menus;\r\n};\r\n\r\nexport default function getMenuData(routes: MenuObject[], base: string = '/'): MenuData[] {\r\n return formatRelativePath(routes, base);\r\n}\r\n","import RcMenu, { MenuItem, SubMenu } from 'rc-menu';\r\nimport Footer from '../components/footer';\r\nimport { Link, useLocation, useRoutes } from 'react-router-dom';\r\nimport { useEffect, useMemo, useState } from 'react';\r\nimport getMenuData, { MenuData, MenuObject } from '../utils/get-menu-data';\r\nimport type { CSSMotionProps } from 'rc-motion';\r\nimport { styled } from '@topthink/components';\r\n\r\ninterface Props {\r\n title: string;\r\n routes: MenuObject[];\r\n basename: string;\r\n}\r\n\r\nconst renderMenuItems = (items: MenuData[]) => {\r\n return items.map((item) => {\r\n\r\n const title = <>\r\n {item.icon && <i className={`bi bi-${item.icon}`} />}\r\n {item.title}\r\n </>;\r\n\r\n if (item.children.length > 0) {\r\n return <SubMenu title={title} key={item.path}>\r\n {renderMenuItems(item.children)}\r\n </SubMenu>;\r\n } else {\r\n return <MenuItem key={item.path}>\r\n <Link to={item.path}>\r\n {title}\r\n </Link>\r\n </MenuItem>;\r\n }\r\n });\r\n};\r\n\r\nconst collapseNode = () => {\r\n return { height: 0 };\r\n};\r\nconst expandNode = (node: HTMLElement) => {\r\n return { height: node.scrollHeight };\r\n};\r\n\r\nconst motion: CSSMotionProps = {\r\n motionName: 'rc-menu-collapse',\r\n motionAppear: true,\r\n onAppearStart: collapseNode,\r\n onAppearActive: expandNode,\r\n onEnterStart: collapseNode,\r\n onEnterActive: expandNode,\r\n onLeaveStart: expandNode,\r\n onLeaveActive: collapseNode,\r\n};\r\n\r\n\r\nexport default function SiderLayout({ routes, basename, title }: Props) {\r\n\r\n const children = useRoutes(routes);\r\n\r\n const menu = useMemo(() => getMenuData(routes, basename), [routes, basename]);\r\n\r\n const { pathname } = useLocation();\r\n\r\n const selectedKeys = useMemo(() => {\r\n const keys: string[] = [];\r\n const parts = pathname.split('/');\r\n parts.reduce<string[]>((pre, curr) => {\r\n if (pre.length > 1) {\r\n keys.push(pre.join('/'));\r\n }\r\n return [...pre, curr];\r\n }, []);\r\n keys.push(pathname);\r\n return keys;\r\n }, [pathname]);\r\n\r\n const [openKeys, setOpenKeys] = useState<string[]>([]);\r\n\r\n useEffect(() => {\r\n setOpenKeys(selectedKeys.slice(0, -1));\r\n }, [selectedKeys]);\r\n\r\n const onOpenChange = (openKeys: string[]) => {\r\n const currentKey = openKeys[openKeys.length - 1];\r\n setOpenKeys(openKeys.filter(key => currentKey.startsWith(key)));\r\n };\r\n\r\n return <Container>\r\n <Sidebar>\r\n <Header>{title}</Header>\r\n <Menu\r\n mode='inline'\r\n motion={motion}\r\n openKeys={openKeys}\r\n onOpenChange={onOpenChange}\r\n selectedKeys={selectedKeys}\r\n >\r\n {renderMenuItems(menu)}\r\n </Menu>\r\n </Sidebar>\r\n <Content>\r\n <Main>{children}</Main>\r\n <Footer />\r\n </Content>\r\n </Container>;\r\n}\r\n\r\nconst Container = styled.div`\r\n display: flex;\r\n flex-wrap: nowrap;\r\n width: 100%;\r\n`;\r\n\r\nconst Sidebar = styled.nav`\r\n position: fixed;\r\n top: 0;\r\n bottom: 0;\r\n left: 0;\r\n z-index: 100;\r\n padding: 54px 0 0;\r\n border-right: 1px solid #e3e3e3;\r\n width: 230px;\r\n background-color: #f5f5f5;\r\n`;\r\n\r\nconst Header = styled.div`\r\n padding: 10px 0;\r\n height: 64px;\r\n line-height: 44px;\r\n text-indent: 24px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n font-size: 16px;\r\n`;\r\n\r\nconst Content = styled.div`\r\n margin-left: 230px;\r\n flex: 1;\r\n`;\r\n\r\nconst Main = styled.main`\r\n min-height: calc(100vh - 54px);\r\n position: relative;\r\n`;\r\n\r\nconst Menu = styled(RcMenu)`\r\n border: none;\r\n box-shadow: none;\r\n padding: 0;\r\n\r\n .rc-menu-item {\r\n display: flex;\r\n\r\n &:hover {\r\n background-color: #f0f0f0;\r\n }\r\n\r\n a {\r\n flex: 1;\r\n text-decoration: none;\r\n color: dimgray;\r\n\r\n .bi {\r\n font-size: 16px;\r\n line-height: 18px;\r\n margin-right: 9px;\r\n min-width: 19px;\r\n text-align: center;\r\n vertical-align: text-bottom;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-sub {\r\n background-color: #eee;\r\n border-top: 1px solid #eee;\r\n border-bottom: 1px solid #eee;\r\n\r\n & > li {\r\n &:first-child {\r\n margin-top: 4px;\r\n }\r\n\r\n &:last-child {\r\n margin-bottom: 4px;\r\n }\r\n }\r\n\r\n .rc-menu-item-selected {\r\n background-color: #eee;\r\n color: var(--bs-primary);\r\n\r\n & > a {\r\n color: var(--bs-primary);\r\n }\r\n }\r\n\r\n .rc-menu-item-active {\r\n background-color: #eee;\r\n }\r\n\r\n .rc-menu-item {\r\n &:hover {\r\n background-color: #e7e7e7;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-submenu {\r\n & > .rc-menu-submenu-title {\r\n &:hover {\r\n background-color: #e7e7e7;\r\n }\r\n\r\n .bi {\r\n font-size: 16px;\r\n line-height: 18px;\r\n margin-right: 9px;\r\n min-width: 19px;\r\n text-align: center;\r\n vertical-align: text-bottom;\r\n }\r\n }\r\n }\r\n\r\n .rc-menu-submenu-active > .rc-menu-submenu-title {\r\n background-color: #eee;\r\n }\r\n\r\n .rc-menu-item,\r\n .rc-menu-submenu > .rc-menu-submenu-title {\r\n padding: 0 8px 0 24px;\r\n font-size: 14px;\r\n line-height: 36px;\r\n cursor: pointer;\r\n }\r\n\r\n .rc-menu-sub > .rc-menu-item,\r\n .rc-menu-sub > .rc-menu-submenu > .rc-menu-submenu-title {\r\n padding-top: 0;\r\n padding-bottom: 0;\r\n padding-right: 0;\r\n }\r\n\r\n .rc-menu-submenu-arrow {\r\n line-height: 38px;\r\n }\r\n\r\n .rc-menu-item-selected {\r\n background-color: #f5f5f5;\r\n color: var(--bs-primary);\r\n\r\n & > a {\r\n color: var(--bs-primary);\r\n }\r\n }\r\n\r\n .rc-menu-submenu-selected {\r\n background-color: #eee;\r\n\r\n & > .rc-menu-submenu-title {\r\n color: var(--bs-primary);\r\n font-weight: 500;\r\n }\r\n }\r\n\r\n & > .rc-menu-item {\r\n line-height: 38px;\r\n }\r\n\r\n & > .rc-menu-submenu {\r\n &.rc-menu-submenu-selected {\r\n background-color: #f5f5f5;\r\n }\r\n\r\n & > .rc-menu-submenu-title {\r\n line-height: 38px;\r\n\r\n &:hover {\r\n background-color: #f0f0f0;\r\n }\r\n }\r\n\r\n &.rc-menu-submenu-active > .rc-menu-submenu-title {\r\n background-color: #f5f5f5;\r\n }\r\n\r\n & > .rc-menu-sub {\r\n border-top: 1px solid #e6e6e6;\r\n border-bottom: 1px solid #e6e6e6;\r\n\r\n & > li {\r\n &:first-child {\r\n margin-top: 9px;\r\n }\r\n\r\n &:last-child {\r\n margin-bottom: 9px;\r\n }\r\n }\r\n }\r\n }\r\n\r\n`;\r\n","import { Loader, useAsync } from '@topthink/components';\r\nimport { Navigate } from 'react-router-dom';\r\n\r\ninterface LoginProps {\r\n onLogin: () => void | Promise<void>;\r\n}\r\n\r\nexport default function Login({ onLogin }: LoginProps) {\r\n const { result } = useAsync(async () => {\r\n await onLogin();\r\n\r\n const redirectUri = localStorage.getItem('redirect_uri');\r\n if (redirectUri) {\r\n localStorage.removeItem('redirect_uri');\r\n }\r\n return redirectUri || '/';\r\n }, []);\r\n\r\n if (result) {\r\n return <Navigate to={result} replace />;\r\n }\r\n\r\n return <Loader />;\r\n}\r\n","import { Loader, useAsync } from '@topthink/components';\r\n\r\ninterface LogoutProps {\r\n onLogout: () => void | Promise<void>;\r\n}\r\n\r\nexport default function Logout({ onLogout }: LogoutProps) {\r\n useAsync(async () => {\r\n await onLogout();\r\n }, []);\r\n\r\n return <Loader />;\r\n}\r\n","import { BrowserRouter, Route, Routes } from 'react-router-dom';\r\nimport React, { PropsWithChildren } from 'react';\r\nimport Login from '../pages/login';\r\nimport Logout from '../pages/logout';\r\nimport queryString from 'query-string';\r\nimport { User } from './types';\r\nimport * as path from 'path';\r\nimport { request, Unauthorized } from '@topthink/components';\r\n\r\ntype UserResolver = () => User | Promise<User>\r\n\r\nexport const AppContext = React.createContext<{ userResolver?: UserResolver, onUnauthorized?: (error: Unauthorized) => void }>({});\r\n\r\nfunction stripBasename(pathname: string, basename: string) {\r\n if (basename === '/') return pathname;\r\n\r\n return pathname.slice(basename.length);\r\n}\r\n\r\ninterface Options {\r\n baseURL?: string;\r\n basename?: string;\r\n authentication?: 'cookie' | 'token';\r\n onLogout?: () => void | Promise<void>;\r\n onLogin?: () => (void | string) | Promise<void | string>;\r\n userResolver?: UserResolver;\r\n}\r\n\r\nexport default function createApplication(options: Options) {\r\n const { basename = '/', onLogin, onLogout, authentication, baseURL, userResolver } = options;\r\n\r\n if (baseURL) {\r\n request.defaults.baseURL = baseURL;\r\n }\r\n\r\n if (authentication === 'token') {\r\n request.interceptors.request.use(\r\n config => {\r\n const token = localStorage.getItem('authorization');\r\n\r\n if (token) {\r\n config.headers = {\r\n ...config.headers,\r\n Authorization: `Bearer ${token}`\r\n };\r\n }\r\n return config;\r\n }\r\n );\r\n }\r\n\r\n const onUnauthorized = (error: Unauthorized) => {\r\n if (window.location.pathname !== path.join(basename, '/logout')) {\r\n localStorage.setItem('redirect_uri', stripBasename(window.location.pathname + window.location.search, basename));\r\n }\r\n const redirectUri = window.location.origin + path.join(basename, '/login');\r\n\r\n window.location.href = queryString.stringifyUrl({\r\n url: error.url,\r\n query: { redirect_uri: redirectUri }\r\n });\r\n };\r\n\r\n const handleLogin = async () => {\r\n let token: string | void;\r\n if (onLogin) {\r\n token = await onLogin();\r\n } else {\r\n const parsed = queryString.parse(window.location.hash.substr(1));\r\n if (parsed.access_token) {\r\n token = parsed.access_token as string;\r\n }\r\n }\r\n\r\n if (authentication === 'token' && token) {\r\n localStorage.setItem('authorization', token);\r\n }\r\n };\r\n\r\n const handleLogout = async () => {\r\n if (onLogout) {\r\n try {\r\n await onLogout();\r\n } catch (e) {\r\n if (e instanceof Unauthorized) {\r\n onUnauthorized(e);\r\n }\r\n }\r\n }\r\n\r\n if (authentication === 'token') {\r\n localStorage.removeItem('authorization');\r\n }\r\n };\r\n\r\n return function({ children }: PropsWithChildren<any>) {\r\n return <AppContext.Provider value={{ userResolver, onUnauthorized }}>\r\n <BrowserRouter basename={basename}>\r\n <Routes>\r\n <Route path='*' element={children} />\r\n <Route path='login' element={<Login onLogin={handleLogin} />} />\r\n <Route path='logout' element={<Logout onLogout={handleLogout} />} />\r\n </Routes>\r\n </BrowserRouter>\r\n </AppContext.Provider>;\r\n };\r\n}\r\n","import React, { PropsWithChildren, useContext, useState } from 'react';\r\nimport { User } from '../utils/types';\r\nimport { AppContext } from '../utils/create-application';\r\nimport { Loader, Unauthorized, useAsync } from '@topthink/components';\r\n\r\nexport const UserContext = React.createContext<[User, ((user: User) => void)] | null>(null);\r\n\r\nconst UserProvider = function({ children }: PropsWithChildren<any>) {\r\n const [state, setState] = useState<User | null>(null);\r\n\r\n const { userResolver, onUnauthorized } = useContext(AppContext);\r\n\r\n useAsync(async () => {\r\n if (userResolver) {\r\n return userResolver();\r\n }\r\n }, [], {\r\n onError(e) {\r\n if (e instanceof Unauthorized && onUnauthorized) {\r\n onUnauthorized(e);\r\n }\r\n },\r\n onSuccess(user) {\r\n if (user) {\r\n setState(user);\r\n }\r\n }\r\n });\r\n\r\n if (!state) {\r\n return <Loader />;\r\n }\r\n\r\n return <UserContext.Provider value={[state, setState]}>\r\n {children}\r\n </UserContext.Provider>;\r\n};\r\n\r\nexport function useUser() {\r\n const context = useContext(UserContext);\r\n if (!context) {\r\n throw new Error('please use `useUser` in UserContext');\r\n }\r\n\r\n return context;\r\n}\r\n\r\nexport default UserProvider;\r\n","import logoSrc from '../images/logo.svg';\r\nimport { Dropdown } from 'react-bootstrap';\r\nimport { PropsWithChildren, ReactNode } from 'react';\r\nimport { useUser } from './user-provider';\r\nimport classNames from 'classnames';\r\nimport { styled } from '@topthink/components';\r\n\r\nconst Avatar = styled.a`\r\n cursor: pointer;\r\n`;\r\n\r\ninterface Props {\r\n menus: ReactNode;\r\n className?: string;\r\n logo?: boolean;\r\n}\r\n\r\nexport default function Header({ children, menus, className, logo = true }: PropsWithChildren<Props>) {\r\n const [user] = useUser();\r\n\r\n return <Container\r\n className={classNames('navbar navbar-expand-lg navbar-light bg-white border-bottom sticky-top', className)}>\r\n <div className='container-fluid'>\r\n {logo && <a className='navbar-brand' href='https://www.topthink.com'>\r\n <img src={logoSrc} height='30' />\r\n </a>}\r\n {children}\r\n <Dropdown navbar>\r\n <Dropdown.Toggle as={Avatar} className='nav-link'>\r\n <img className='rounded-circle' width='25' height='25' src={user.avatar} />\r\n </Dropdown.Toggle>\r\n <Dropdown.Menu className={'shadow'}>\r\n {menus}\r\n </Dropdown.Menu>\r\n </Dropdown>\r\n </div>\r\n </Container>;\r\n}\r\n\r\nconst Container = styled.header`\r\n height: 54px;\r\n`;\r\n","var img = \"data:image/svg+xml,%3csvg width='485' height='132' xmlns='http://www.w3.org/2000/svg' xml:space='preserve' style='enable-background:new 0 0 531.69 198.43%3b' version='1.1'%3e %3cstyle type='text/css'%3e.st0%7bfill:%233C60FF%3b%7d%3c/style%3e %3cg%3e %3ctitle%3ebackground%3c/title%3e %3crect fill='none' id='canvas_background' height='134' width='487' y='-1' x='-1'/%3e %3c/g%3e %3cg%3e %3ctitle%3eLayer 1%3c/title%3e %3cpath id='svg_1' d='m132.29%2c62.34c-1.19%2c-18.77 -10.34%2c-35.36 -24.11%2c-46.46c-11.15%2c-8.99 -25.34%2c-14.38 -40.79%2c-14.38c-0.55%2c0 -1.09%2c0.01 -1.63%2c0.02c-3.32%2c0.08 -6.57%2c0.41 -9.75%2c0.98c-30.49%2c5.38 -53.65%2c32 -53.65%2c64.04c0%2c1.87 0.08%2c3.73 0.24%2c5.57c2.5%2c29.51 24.7%2c53.4 53.41%2c58.47c2.38%2c0.42 4.8%2c0.72 7.26%2c0.86c0.83%2c0.05 1.66%2c0.09 2.5%2c0.11c0.54%2c0.01 1.08%2c0.02 1.63%2c0.02c34.04%2c0 61.97%2c-26.16 64.79%2c-59.46c0.16%2c-1.83 0.24%2c-3.69 0.24%2c-5.57c0%2c-1.42 -0.05%2c-2.82 -0.14%2c-4.2zm-76.27%2c32.5c-0.26%2c0.01 -0.53%2c0.01 -0.79%2c0.01c-14.56%2c0 -26.88%2c-9.57 -31.03%2c-22.76c-0.97%2c-3.08 -1.49%2c-6.35 -1.49%2c-9.75c0%2c-17.95 14.56%2c-32.52 32.51%2c-32.52c0.26%2c0 0.53%2c0 0.79%2c0.01c3.41%2c0.08 6.69%2c0.68 9.75%2c1.74c6.5%2c2.22 12.06%2c6.45 15.97%2c11.94c1.98%2c2.78 3.54%2c5.9 4.57%2c9.25c0.94%2c3.03 1.44%2c6.24 1.44%2c9.58l-9.75%2c0c0%2c-2.18 -0.31%2c-4.29 -0.88%2c-6.28c-0.92%2c-3.23 -2.55%2c-6.17 -4.69%2c-8.64c-1.86%2c-2.14 -4.12%2c-3.93 -6.65%2c-5.25c-2.93%2c-1.54 -6.24%2c-2.46 -9.75%2c-2.58c-0.26%2c-0.01 -0.52%2c-0.01 -0.79%2c-0.01c-12.57%2c0 -22.76%2c10.19 -22.76%2c22.76c0%2c3.49 0.79%2c6.8 2.19%2c9.75c3.65%2c7.69 11.49%2c13.01 20.57%2c13.01c0.27%2c0 0.53%2c-0.01 0.79%2c-0.01l0%2c9.75zm55.7%2c-17.92c-3.35%2c10.5 -13.18%2c18.09 -24.78%2c18.09c-3.13%2c0 -6.13%2c-0.55 -8.91%2c-1.57c-2.18%2c-0.8 -4.24%2c-1.88 -6.11%2c-3.21c-2.38%2c-1.68 -4.47%2c-3.76 -6.16%2c-6.13c-0.28%2c-0.39 -0.55%2c-0.79 -0.81%2c-1.2c-2.03%2c-3.2 -3.38%2c-6.87 -3.85%2c-10.82l9.87%2c0c0.33%2c1.71 0.92%2c3.32 1.74%2c4.8c1.61%2c2.91 4.09%2c5.26 7.09%2c6.72c0.57%2c0.28 1.15%2c0.53 1.76%2c0.73c1.68%2c0.6 3.49%2c0.92 5.37%2c0.92c7.92%2c0 14.52%2c-5.67 15.96%2c-13.17c0.2%2c-1 0.3%2c-2.04 0.3%2c-3.09c0%2c-2.37 -0.51%2c-4.63 -1.43%2c-6.67c-1.66%2c-3.71 -4.68%2c-6.68 -8.43%2c-8.28l3.54%2c-9.1c7.43%2c3.08 13.13%2c9.49 15.21%2c17.38c0.44%2c1.64 0.72%2c3.34 0.81%2c5.09c0.04%2c0.52 0.05%2c1.05 0.05%2c1.58c0%2c1.05 -0.07%2c2.07 -0.18%2c3.09c-0.18%2c1.68 -0.54%2c3.3 -1.04%2c4.84z' class='st0'/%3e %3cg id='svg_2'%3e %3cg id='svg_3'%3e %3crect id='svg_4' height='6.34' width='94.12' class='st0' y='20.46' x='163.29'/%3e %3c/g%3e %3cg id='svg_5'%3e %3cpath id='svg_6' d='m169.31%2c113.72l0%2c-6.34c6.49%2c0 11.77%2c-5.28 11.77%2c-11.77l0%2c-71.98l6.34%2c0l0%2c71.98c0%2c9.98 -8.12%2c18.11 -18.11%2c18.11z' class='st0'/%3e %3c/g%3e %3cg id='svg_7'%3e %3cpath id='svg_8' d='m255.49%2c91.27l-6.34%2c0l0%2c-38.2c0%2c-5.06 -4.12%2c-9.18 -9.18%2c-9.18l-19.37%2c0c-5.06%2c0 -9.18%2c4.12 -9.18%2c9.18l0%2c38.2l-6.34%2c0l0%2c-38.2c0%2c-8.55 6.96%2c-15.51 15.51%2c-15.51l19.38%2c0c8.55%2c0 15.51%2c6.96 15.51%2c15.51l0%2c38.2l0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_9'%3e %3crect id='svg_10' height='17.09' width='6.34' class='st0' y='23.63' x='227.12'/%3e %3c/g%3e %3cg id='svg_11'%3e %3cpath id='svg_12' d='m206.43%2c113.84l-3.34%2c0l0%2c-6.34l3.34%2c0c6.3%2c0 12.9%2c-3.56 15.35%2c-8.29c3.49%2c-6.71 5.33%2c-14.25 5.33%2c-21.81l0%2c-26.13l6.34%2c0l0%2c26.13c0%2c8.58 -2.09%2c17.13 -6.05%2c24.74c-3.98%2c7.68 -13.57%2c11.7 -20.97%2c11.7z' class='st0'/%3e %3c/g%3e %3cg id='svg_13'%3e %3cpath id='svg_14' d='m257.48%2c113.84l-3.34%2c0c-7.4%2c0 -16.98%2c-4.02 -20.98%2c-11.7c-3.96%2c-7.61 -6.05%2c-16.16 -6.05%2c-24.74l6.34%2c0c0%2c7.56 1.84%2c15.1 5.33%2c21.81c2.46%2c4.73 9.06%2c8.29 15.35%2c8.29l3.34%2c0l0%2c6.34l0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_15'%3e %3crect id='svg_16' height='6.34' width='42.87' class='st0' y='27.89' x='274.07'/%3e %3c/g%3e %3cg id='svg_17'%3e %3crect id='svg_18' height='61.38' width='6.34' class='st0' y='14.89' x='293.05'/%3e %3c/g%3e %3cg id='svg_19'%3e %3crect id='svg_20' height='6.34' width='33.26' class='st0' transform='matrix(0.11%2c-0.9939%2c0.9939%2c0.11%2c194.7608%2c392.0006) ' y='46.985071' x='325.728637'/%3e %3c/g%3e %3cg id='svg_21'%3e %3crect id='svg_22' height='33.26' width='6.34' class='st0' transform='matrix(0.9939%2c-0.11%2c0.11%2c0.9939%2c-7.5075%2c38.3801) ' y='37.060893' x='310.495485'/%3e %3c/g%3e %3cg id='svg_23'%3e %3cpath id='svg_24' d='m352.9%2c77.14l-15.15%2c0c-7.52%2c0 -13.64%2c-6.12 -13.64%2c-13.63l0%2c-29.61c0%2c-7.52 6.12%2c-13.64 13.64%2c-13.64l15.15%2c0c7.52%2c0 13.64%2c6.12 13.64%2c13.64l0%2c29.61c0%2c7.52 -6.12%2c13.63 -13.64%2c13.63zm-15.15%2c-50.54c-4.02%2c0 -7.3%2c3.27 -7.3%2c7.3l0%2c29.61c0%2c4.02 3.27%2c7.3 7.3%2c7.3l15.15%2c0c4.02%2c0 7.3%2c-3.27 7.3%2c-7.3l0%2c-29.61c0%2c-4.02 -3.27%2c-7.3 -7.3%2c-7.3l-15.15%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_25'%3e %3cg id='svg_26'%3e %3crect id='svg_27' height='6.34' width='17.8' class='st0' y='37.2' x='336.43'/%3e %3c/g%3e %3cg id='svg_28'%3e %3crect id='svg_29' height='6.34' width='17.8' class='st0' y='53.87' x='336.43'/%3e %3c/g%3e %3c/g%3e %3cg id='svg_30'%3e %3cpath id='svg_31' d='m352.7%2c113.84l-37.98%2c0c-8%2c0 -14.5%2c-6.51 -14.5%2c-14.5l0%2c-16.14l6.34%2c0l0%2c16.13c0%2c4.5 3.66%2c8.17 8.17%2c8.17l37.98%2c0l0%2c6.34l-0.01%2c0z' class='st0'/%3e %3c/g%3e %3cg id='svg_32'%3e %3crect id='svg_33' height='6.34' width='23.57' class='st0' transform='matrix(0.2529%2c-0.9675%2c0.9675%2c0.2529%2c114.4986%2c402.9877) ' y='83.698593' x='326.836101'/%3e %3c/g%3e %3cg id='svg_34'%3e %3crect id='svg_35' height='6.34' width='20.52' class='st0' y='86.2' x='321.58'/%3e %3c/g%3e %3cg id='svg_36'%3e %3crect id='svg_37' height='24.75' width='6.34' class='st0' transform='matrix(0.9556%2c-0.2946%2c0.2946%2c0.9556%2c-19.7967%2c122.424) ' y='75.874073' x='369.686666'/%3e %3c/g%3e %3cg id='svg_38'%3e %3crect id='svg_39' height='6.34' width='71.83' class='st0' y='20.46' x='395.51'/%3e %3c/g%3e %3cg id='svg_40'%3e %3crect id='svg_41' height='6.34' width='90.81' class='st0' y='57.44' x='386.02'/%3e %3c/g%3e %3cg id='svg_42'%3e %3cpath id='svg_43' d='m463.12%2c113.64l-56%2c0c-4.5%2c0 -8.59%2c-2.29 -10.94%2c-6.14c-2.35%2c-3.84 -2.52%2c-8.53 -0.46%2c-12.53l17.68%2c-35.81l5.64%2c2.89l-17.68%2c35.81c-1.04%2c2.02 -0.95%2c4.39 0.23%2c6.33c1.19%2c1.94 3.25%2c3.1 5.53%2c3.1l56%2c0c1.51%2c0 2.88%2c-0.71 3.74%2c-1.95c0.81%2c-1.16 1.03%2c-2.57 0.63%2c-3.91l-7.8%2c-12.34l5.36%2c-3.39l8.18%2c12.94l0.12%2c0.31c1.24%2c3.34 0.76%2c7.08 -1.28%2c10.01c-2.04%2c2.94 -5.39%2c4.68 -8.95%2c4.68z' class='st0'/%3e %3c/g%3e %3c/g%3e %3c/g%3e%3c/svg%3e\";\n export default img;","import { ReactNode } from 'react';\r\nimport { intersection } from 'lodash';\r\nimport { useUser } from './user-provider';\r\nimport { User } from '../utils/types';\r\n\r\nexport interface AccessProps {\r\n require?: string | string[] | ((user: User) => boolean);\r\n fallback?: ReactNode;\r\n children: ReactNode;\r\n}\r\n\r\nexport default function Access({\r\n require,\r\n children,\r\n fallback\r\n}: AccessProps) {\r\n const [user,] = useUser();\r\n let passed = false;\r\n if (typeof require === 'function') {\r\n passed = require(user);\r\n } else {\r\n if (typeof require === 'string') {\r\n require = [require];\r\n }\r\n passed = intersection(user.roles, require).length > 0;\r\n }\r\n if (!passed) {\r\n children = fallback;\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","import { styled } from '@topthink/components';\r\nimport { PropsWithChildren, ReactNode } from 'react';\r\n\r\ninterface ContentProps {\r\n title: string;\r\n nav?: ReactNode;\r\n extra?: ReactNode;\r\n}\r\n\r\nexport default function Content({ title, children, nav, extra }: PropsWithChildren<ContentProps>) {\r\n\r\n return <Container>\r\n <Header>\r\n <div className='container'>\r\n <Title>\r\n {title}\r\n </Title>\r\n {nav}\r\n <Extra>{extra}</Extra>\r\n </div>\r\n </Header>\r\n <Body className='container'>\r\n {children}\r\n </Body>\r\n </Container>;\r\n};\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n`;\r\n\r\nconst Header = styled.div`\r\n background-color: #fff;\r\n display: flex;\r\n\r\n .container {\r\n padding: 0 24px;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n\r\n .nav {\r\n .nav-link {\r\n position: relative;\r\n\r\n &.active {\r\n &:after {\r\n content: '';\r\n height: 2px;\r\n background: var(--bs-primary);\r\n display: block;\r\n position: absolute;\r\n left: 1rem;\r\n right: 1rem;\r\n bottom: -2px;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nconst Body = styled.div`\r\n margin-top: 24px;\r\n`;\r\n\r\nconst Title = styled.div`\r\n font-size: 22px;\r\n line-height: 64px;\r\n height: 64px;\r\n`;\r\n\r\nconst Extra = styled.div`\r\n\r\n`;\r\n"],"names":["_taggedTemplateLiteral","strings","raw","slice","Object","freeze","defineProperties","value","FooterWrapper","styled","footer","Footer","_jsx","className","formatRelativePath","routes","parent","menus","route","meta","_route$meta","hideInMenu","title","_route$meta2","path","replace","menu","icon","_route$meta3","children","_route$meta4","hideChildrenInMenu","length","push","renderMenuItems","items","map","item","_jsxs","SubMenu","MenuItem","Link","to","collapseNode","height","expandNode","node","scrollHeight","motion","motionName","motionAppear","onAppearStart","onAppearActive","onEnterStart","onEnterActive","onLeaveStart","onLeaveActive","SiderLayout","basename","useRoutes","useMemo","getMenuData","pathname","useLocation","selectedKeys","keys","split","reduce","pre","curr","join","openKeys","setOpenKeys","useState","useEffect","Container","Sidebar","Header","Menu","mode","onOpenChange","currentKey","filter","key","startsWith","Content","Main","div","nav","main","RcMenu","Login","onLogin","result","useAsync","async","redirectUri","localStorage","getItem","removeItem","Navigate","Loader","Logout","onLogout","AppContext","React","createContext","createApplication","options","authentication","baseURL","userResolver","request","defaults","interceptors","use","config","token","headers","Authorization","onUnauthorized","error","window","location","setItem","stripBasename","search","origin","href","queryString","stringifyUrl","url","query","redirect_uri","handleLogin","parsed","parse","hash","substr","access_token","handleLogout","e","Unauthorized","Provider","BrowserRouter","Routes","Route","element","UserContext","UserProvider","state","setState","useContext","onError","onSuccess","user","useUser","context","Error","Avatar","a","logo","classNames","src","Dropdown","navbar","Toggle","as","width","avatar","header","Access","require","fallback","passed","intersection","roles","extra","Title","Extra","Body"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topthink/common",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.19",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "rollup -c --environment NODE_ENV:production",
|
|
6
6
|
"build:dev": "rollup -c",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
},
|
|
52
52
|
"author": "yunwuxin <tzzhangyajun@qq.com> (https://github.com/yunwuxin)",
|
|
53
53
|
"license": "MIT",
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "bc0eb27807b226d3b29c54e61553b20d5842613b"
|
|
55
55
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
declare module 'react-router' {
|
|
2
|
-
interface RouteObject {
|
|
3
|
-
meta?: {
|
|
4
|
-
title?: string;
|
|
5
|
-
icon?: string;
|
|
6
|
-
hideInMenu?: boolean;
|
|
7
|
-
hideChildrenInMenu?: boolean;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
1
|
export { default as SiderLayout } from './layout/sider';
|
|
12
2
|
export { default as Header } from './components/header';
|
|
13
3
|
export { default as Footer } from './components/footer';
|
|
@@ -18,4 +8,5 @@ export { User } from './utils/types';
|
|
|
18
8
|
export { default as createApplication } from './utils/create-application';
|
|
19
9
|
export { useRoutes, Link } from 'react-router-dom';
|
|
20
10
|
export { RouteObject, Outlet, useLocation, useNavigate, useOutlet, useParams, Navigate } from 'react-router';
|
|
11
|
+
export { MenuObject } from './utils/get-menu-data';
|
|
21
12
|
export * from '@topthink/components';
|
package/types/layout/sider.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import
|
|
2
|
+
import { MenuObject } from '../utils/get-menu-data';
|
|
3
3
|
interface Props {
|
|
4
4
|
title: string;
|
|
5
|
-
routes:
|
|
5
|
+
routes: MenuObject[];
|
|
6
6
|
basename: string;
|
|
7
7
|
}
|
|
8
8
|
export default function SiderLayout({ routes, basename, title }: Props): JSX.Element;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { RouteObject } from 'react-router';
|
|
2
|
+
export interface MenuObject extends RouteObject {
|
|
3
|
+
meta?: {
|
|
4
|
+
title?: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
hideInMenu?: boolean;
|
|
7
|
+
hideChildrenInMenu?: boolean;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
2
10
|
export interface MenuData {
|
|
3
11
|
path: string;
|
|
4
12
|
title: string;
|
|
5
13
|
icon?: string;
|
|
6
14
|
children: MenuData[];
|
|
7
15
|
}
|
|
8
|
-
export default function getMenuData(routes:
|
|
16
|
+
export default function getMenuData(routes: MenuObject[], base?: string): MenuData[];
|