update mark

This commit is contained in:
abearxiong 2025-03-29 23:16:44 +08:00
parent 508ec96029
commit a99d9c2322
6 changed files with 124 additions and 37 deletions

View File

@ -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
View File

@ -0,0 +1,3 @@
import { App as Manager } from './manager/Manager';
export { Manager };

View File

@ -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,6 +125,8 @@ export const Manager = (props: ManagerProps) => {
/>
</div>
<div className={'flex items-center space-x-2'}>
{showSelect && (
<>
<IconButton onClick={handleClick}>
<MenuIcon className='w-4 h-4' />
</IconButton>
@ -143,13 +148,15 @@ export const Manager = (props: ManagerProps) => {
</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>
{(!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>
);

View File

@ -91,9 +91,20 @@ export const EditMark = () => {
defaultValue={mark?.thumbnail || ''}
render={({ field }) => <TextField {...field} label={t('thumbnail')} variant='outlined' fullWidth margin='normal' />}
/>
<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>
);
};

View File

@ -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
View 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`,
},
},
});