generated from template/vite-react-template
	Compare commits
	
		
			1 Commits
		
	
	
		
			508ec96029
			...
			a99d9c2322
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a99d9c2322 | 
| @@ -17,6 +17,7 @@ | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "@kevisual/query-mark": "workspace:*", | ||||
|     "@kevisual/components": "workspace:*", | ||||
|     "@kevisual/router": "0.0.9", | ||||
|     "@kevisual/store": "workspace:*", | ||||
|     "@types/lodash-es": "^4.17.12", | ||||
| @@ -28,6 +29,7 @@ | ||||
|     "react": "^19.0.0", | ||||
|     "react-dom": "^19.0.0", | ||||
|     "react-hook-form": "^7.54.2", | ||||
|     "react-i18next": "^15.4.1", | ||||
|     "react-toastify": "^11.0.5", | ||||
|     "zustand": "^5.0.3" | ||||
|   }, | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/Module.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/Module.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| import { App as Manager } from './manager/Manager'; | ||||
|  | ||||
| export { Manager }; | ||||
| @@ -2,7 +2,7 @@ import { useManagerStore } from './store'; | ||||
| import { useEffect, useMemo, useState } from 'react'; | ||||
| import { useShallow } from 'zustand/shallow'; | ||||
| import { ManagerProvider } from './Provider'; | ||||
| import { ChevronDown, ChevronLeft, Edit, Plus, Search, Trash, Menu as MenuIcon, MenuSquare } from 'lucide-react'; | ||||
| import { ChevronDown, ChevronLeft, X, Edit, Plus, Search, Trash, Menu as MenuIcon, MenuSquare } from 'lucide-react'; | ||||
| import dayjs from 'dayjs'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import { EditMark as EditMarkComponent } from './edit/Edit'; | ||||
| @@ -16,17 +16,19 @@ type ManagerProps = { | ||||
|   showAdd?: boolean; | ||||
|   onClick?: (data?: any) => void; | ||||
|   markType?: MarkType; | ||||
|   showSelect?: boolean; | ||||
| }; | ||||
| export const Manager = (props: ManagerProps) => { | ||||
|   const { showSearch = true, showAdd = false, onClick } = props; | ||||
|   const { showSearch = true, showAdd = false, onClick, showSelect = true } = props; | ||||
|  | ||||
|   const { control } = useForm({ defaultValues: { search: '' } }); | ||||
|   const { list, init, setCurrentMarkId, currentMarkId, deleteMark, getMark, setMarkData, pagination, setPagination, getList, search, setSearch } = | ||||
|   const { list, init, setCurrentMarkId, currentMarkId, markData, deleteMark, getMark, setMarkData, pagination, setPagination, getList, search, setSearch } = | ||||
|     useManagerStore( | ||||
|       useShallow((state) => { | ||||
|         return { | ||||
|           list: state.list, | ||||
|           init: state.init, | ||||
|           markData: state.markData, | ||||
|           currentMarkId: state.currentMarkId, | ||||
|           setCurrentMarkId: state.setCurrentMarkId, | ||||
|           deleteMark: state.deleteMark, | ||||
| @@ -87,8 +89,9 @@ export const Manager = (props: ManagerProps) => { | ||||
|     } | ||||
|   }; | ||||
|   console.log('list', list.length, pagination.total); | ||||
|    | ||||
|   return ( | ||||
|     <div className='w-full h-full p-4  relative'> | ||||
|     <div className='w-full h-full p-4 bg-white border-r border-r-gray-200  relative'> | ||||
|       <div className='flex  px-4 mb-4 justify-between items-center absolute top-0 left-0 h-[56px] w-full'> | ||||
|         <div className='flex ml-12 items-center space-x-2 '> | ||||
|           <Controller | ||||
| @@ -122,34 +125,38 @@ export const Manager = (props: ManagerProps) => { | ||||
|           /> | ||||
|         </div> | ||||
|         <div className={'flex items-center space-x-2'}> | ||||
|           <IconButton onClick={handleClick}> | ||||
|             <MenuIcon className='w-4 h-4' /> | ||||
|           </IconButton> | ||||
|           <Menu | ||||
|             anchorEl={anchorEl} | ||||
|             open={open} | ||||
|             onClose={handleClose} | ||||
|             onClick={(e) => { | ||||
|               console.log('e', e); | ||||
|             }}> | ||||
|             {['md', 'mdx', 'wallnote', 'excalidraw'].map((option) => ( | ||||
|               <MenuItem | ||||
|                 key={option} | ||||
|                 value={option} | ||||
|                 onClick={() => { | ||||
|                   handleMenuItemClick(option); | ||||
|           {showSelect && ( | ||||
|             <> | ||||
|               <IconButton onClick={handleClick}> | ||||
|                 <MenuIcon className='w-4 h-4' /> | ||||
|               </IconButton> | ||||
|               <Menu | ||||
|                 anchorEl={anchorEl} | ||||
|                 open={open} | ||||
|                 onClose={handleClose} | ||||
|                 onClick={(e) => { | ||||
|                   console.log('e', e); | ||||
|                 }}> | ||||
|                 {option} | ||||
|               </MenuItem> | ||||
|             ))} | ||||
|           </Menu> | ||||
|                 {['md', 'mdx', 'wallnote', 'excalidraw'].map((option) => ( | ||||
|                   <MenuItem | ||||
|                     key={option} | ||||
|                     value={option} | ||||
|                     onClick={() => { | ||||
|                       handleMenuItemClick(option); | ||||
|                     }}> | ||||
|                     {option} | ||||
|                   </MenuItem> | ||||
|                 ))} | ||||
|               </Menu> | ||||
|             </> | ||||
|           )} | ||||
|           <button | ||||
|             className={clsx( | ||||
|               'text-blue-500 cursor-pointer hover:underline flex items-center p-2 rounded-md hover:bg-blue-100 transition duration-200', | ||||
|               showAdd ? '' : 'hidden', | ||||
|             )}> | ||||
|             <Plus | ||||
|               className={clsx('w-4 h-4 ', currentMarkId ? 'rotate-12' : 'rotate-0')} | ||||
|               className={clsx('w-4 h-4 ')} | ||||
|               onClick={() => { | ||||
|                 setCurrentMarkId(''); | ||||
|  | ||||
| @@ -157,7 +164,7 @@ export const Manager = (props: ManagerProps) => { | ||||
|                   id: '', | ||||
|                   title: '', | ||||
|                   description: '', | ||||
|                   markType: 'md' as any, | ||||
|                   markType: props.markType || ('md' as any), | ||||
|                   summary: '', | ||||
|                   tags: [], | ||||
|                   link: '', | ||||
| @@ -165,6 +172,16 @@ export const Manager = (props: ManagerProps) => { | ||||
|               }} | ||||
|             /> | ||||
|           </button> | ||||
|           {markData && ( | ||||
|             <button | ||||
|               className='text-blue-500 cursor-pointer hover:underline flex items-center p-2 rounded-md hover:bg-blue-100 transition duration-200' | ||||
|               onClick={() => { | ||||
|                 setCurrentMarkId(''); | ||||
|                 setMarkData(undefined); | ||||
|               }}> | ||||
|               <X className='w-4 h-4 ' /> | ||||
|             </button> | ||||
|           )} | ||||
|         </div> | ||||
|       </div> | ||||
|       <div className='mt-[56px] overflow-auto scrollbar' style={{ height: 'calc(100% - 56px)' }}> | ||||
| @@ -259,11 +276,25 @@ export const EditMark = () => { | ||||
|   } | ||||
|   return <div className='w-full h-full'></div>; | ||||
| }; | ||||
| export const LayoutMain = (props: { children?: React.ReactNode }) => { | ||||
| export const LayoutMain = (props: { children?: React.ReactNode; expandChildren?: React.ReactNode }) => { | ||||
|   const [openMenu, setOpenMenu] = useState(false); | ||||
|   const getDocumentHeight = () => { | ||||
|     return document.documentElement.scrollHeight; | ||||
|   }; | ||||
|   const markData = useManagerStore((state) => state.markData); | ||||
|   const isEdit = !!markData; | ||||
|   const hasExpandChildren = !!props.expandChildren; | ||||
|   const style = useMemo(() => { | ||||
|     if (!hasExpandChildren || openMenu) { | ||||
|       return {}; | ||||
|     } | ||||
|     return { | ||||
|       top: getDocumentHeight() / 2 + 10, | ||||
|     }; | ||||
|   }, [getDocumentHeight, hasExpandChildren, openMenu]); | ||||
|   return ( | ||||
|     <div className='w-full h-full flex'> | ||||
|       <div className='absolute top-4 left-4 z-10'> | ||||
|       <div className={clsx('absolute top-4 z-10', openMenu ? 'left-4' : '-left-4')} style={style}> | ||||
|         <Button | ||||
|           variant='contained' | ||||
|           color={openMenu ? 'info' : 'primary'} | ||||
| @@ -278,9 +309,12 @@ export const LayoutMain = (props: { children?: React.ReactNode }) => { | ||||
|         </Button> | ||||
|       </div> | ||||
|       <div className={clsx('h-full w-full sm:w-1/3', openMenu ? '' : 'hidden')}>{props.children}</div> | ||||
|       <div className={clsx('h-full hidden sm:block sm:w-2/3', openMenu ? '' : 'hidden')}> | ||||
|         <EditMark /> | ||||
|       </div> | ||||
|       {(!props.expandChildren || isEdit) && ( | ||||
|         <div className={clsx('h-full hidden sm:block sm:w-2/3', openMenu ? '' : 'hidden')}> | ||||
|           <EditMark /> | ||||
|         </div> | ||||
|       )} | ||||
|       {props.expandChildren && <div className='h-full grow'>{props.expandChildren}</div>} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| @@ -305,12 +339,19 @@ export type AppProps = { | ||||
|    * 管理器id, 存储到store的id | ||||
|    */ | ||||
|   managerId?: string; | ||||
|   children?: React.ReactNode; | ||||
|   showSelect?: boolean; | ||||
| }; | ||||
| export const App = (props: AppProps) => { | ||||
|   return ( | ||||
|     <ManagerProvider id={props.managerId}> | ||||
|       <LayoutMain> | ||||
|         <Manager markType={props.markType} showSearch={props.showSearch} showAdd={props.showAdd} onClick={props.onClick} /> | ||||
|       <LayoutMain expandChildren={props.children}> | ||||
|         <Manager | ||||
|           markType={props.markType} | ||||
|           showSearch={props.showSearch} | ||||
|           showAdd={props.showAdd} | ||||
|           onClick={props.onClick} | ||||
|           showSelect={props.showSelect}></Manager> | ||||
|       </LayoutMain> | ||||
|     </ManagerProvider> | ||||
|   ); | ||||
|   | ||||
| @@ -91,9 +91,20 @@ export const EditMark = () => { | ||||
|         defaultValue={mark?.thumbnail || ''} | ||||
|         render={({ field }) => <TextField {...field} label={t('thumbnail')} variant='outlined' fullWidth margin='normal' />} | ||||
|       /> | ||||
|       <Button type='submit' variant='contained' color='primary'> | ||||
|         {t('save')} | ||||
|       </Button> | ||||
|       <div className='flex gap-2'> | ||||
|         <Button type='submit' variant='contained' color='primary'> | ||||
|           {t('save')} | ||||
|         </Button> | ||||
|         <Button | ||||
|           variant='contained' | ||||
|           color='secondary' | ||||
|           onClick={() => { | ||||
|             setCurrentMarkId(''); | ||||
|             setMarkData(undefined); | ||||
|           }}> | ||||
|           {t('cancel')} | ||||
|         </Button> | ||||
|       </div> | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -61,7 +61,7 @@ export const createManagerStore: StateCreator<ManagerStore, [], [], any> = (set, | ||||
|     }, | ||||
|     updateMark: async (mark: Mark) => { | ||||
|       const queryMark = get().queryMark; | ||||
|       const res = await queryMark.updateMark(mark.id, mark); | ||||
|       const res = await queryMark.updateMark(mark); | ||||
|       if (res.code === 200) { | ||||
|         set((state) => { | ||||
|           const oldList = state.list; | ||||
|   | ||||
							
								
								
									
										30
									
								
								vite.lib.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vite.lib.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| import { defineConfig } from 'vite'; | ||||
| import react from '@vitejs/plugin-react'; | ||||
| import path from 'path'; | ||||
| import tailwindcss from '@tailwindcss/vite'; | ||||
| import pkgs from './package.json' with { type: 'json' }; | ||||
| const version = pkgs.version || '0.0.1'; | ||||
| const isDev = process.env.NODE_ENV === 'development'; | ||||
|  | ||||
| const basename = isDev ? '/' : pkgs?.basename || '/'; | ||||
| // https://vitejs.dev/config/ | ||||
| export default defineConfig({ | ||||
|   plugins: [react(), tailwindcss()], | ||||
|   resolve: { | ||||
|     alias: { | ||||
|       '@': path.resolve(__dirname, './src'), | ||||
|     }, | ||||
|   }, | ||||
|   base: basename, | ||||
|   define: { | ||||
|     BASE_NAME: JSON.stringify(basename), | ||||
|   }, | ||||
|   build: { | ||||
|     target: 'esnext', | ||||
|     lib: { | ||||
|       entry: path.resolve(__dirname, './src/pages/App.tsx'), | ||||
|       name: 'Mark', | ||||
|       fileName: (format) => `mark.${format}.js`, | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user