feat: dashboard card title allow edit

This commit is contained in:
moonrailgun 2024-01-07 22:42:55 +08:00
parent 90f22afe28
commit d03f60f6a1
6 changed files with 69 additions and 6 deletions

View File

@ -0,0 +1,38 @@
import { Input } from 'antd';
import clsx from 'clsx';
import React, { useState } from 'react';
import { useWatch } from '../hooks/useWatch';
interface EditableTextProps {
className?: string;
enable?: boolean;
defaultValue: string;
onSave: (text: string) => void;
}
export const EditableText: React.FC<EditableTextProps> = React.memo((props) => {
const [text, setText] = useState(props.defaultValue);
const enable = props.enable ?? true;
useWatch([props.defaultValue], () => {
setText(props.defaultValue);
});
return (
<>
{enable ? (
<Input
className={clsx(
props.className,
'border-0 p-0 outline-0 !shadow-none rounded-none'
)}
value={text}
onChange={(e) => setText(e.target.value)}
onBlur={(e) => props.onSave(e.target.value)}
/>
) : (
<span className={props.className}>{text}</span>
)}
</>
);
});
EditableText.displayName = 'EditableText';

View File

@ -23,6 +23,7 @@ export const DashboardGrid: React.FC<DashboardGridProps> = React.memo(
className={clsx('layout', isEditMode && 'select-none')} className={clsx('layout', isEditMode && 'select-none')}
layouts={layouts} layouts={layouts}
rowHeight={50} rowHeight={50}
draggableCancel=".non-draggable"
isDraggable={isEditMode} isDraggable={isEditMode}
isResizable={isEditMode} isResizable={isEditMode}
breakpoints={{ lg: 1200, md: 768, sm: 0 }} breakpoints={{ lg: 1200, md: 768, sm: 0 }}

View File

@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { DashboardItem, useDashboardStore } from '../../../store/dashboard'; import { DashboardItem, useDashboardStore } from '../../../store/dashboard';
import { WebsiteOverviewItem } from './WebsiteOverviewItem'; import { WebsiteOverviewItem } from './WebsiteOverviewItem';
import { NotFoundTip } from '../../NotFoundTip'; import { NotFoundTip } from '../../NotFoundTip';
import { Button, Card } from 'antd'; import { Button, Card, Input, Typography } from 'antd';
import React from 'react'; import React from 'react';
import { DeleteOutlined } from '@ant-design/icons'; import { DeleteOutlined } from '@ant-design/icons';
import { useEvent } from '../../../hooks/useEvent'; import { useEvent } from '../../../hooks/useEvent';
@ -11,13 +11,14 @@ import { MonitorHealthBarItem } from './MonitorHealthBarItem';
import { MonitorMetricsItem } from './MonitorMetricsItem'; import { MonitorMetricsItem } from './MonitorMetricsItem';
import { MonitorChartItem } from './MonitorChartItem'; import { MonitorChartItem } from './MonitorChartItem';
import { MonitorEventsItem } from './MonitorEventsItem'; import { MonitorEventsItem } from './MonitorEventsItem';
import { EditableText } from '../../EditableText';
interface DashboardGridItemProps { interface DashboardGridItemProps {
item: DashboardItem; item: DashboardItem;
} }
export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo( export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
(props) => { (props) => {
const { isEditMode, removeItem } = useDashboardStore(); const { isEditMode, removeItem, changeItemTitle } = useDashboardStore();
const { key, id, title, type } = props.item; const { key, id, title, type } = props.item;
const inner = useMemo(() => { const inner = useMemo(() => {
@ -40,7 +41,6 @@ export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
const handleDelete = useEvent( const handleDelete = useEvent(
(e: React.MouseEvent<HTMLElement, MouseEvent>) => { (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
console.log('e', e, key);
e.stopPropagation(); e.stopPropagation();
removeItem(key); removeItem(key);
} }
@ -49,7 +49,14 @@ export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
return ( return (
<Card <Card
className="h-full w-full overflow-auto" className="h-full w-full overflow-auto"
title={title} title={
<EditableText
className="non-draggable"
enable={isEditMode}
defaultValue={title}
onSave={(text) => changeItemTitle(key, text)}
/>
}
headStyle={{ padding: 10, minHeight: 40 }} headStyle={{ padding: 10, minHeight: 40 }}
bodyStyle={{ padding: 10 }} bodyStyle={{ padding: 10 }}
extra={ extra={

View File

@ -2,7 +2,7 @@ import { DependencyList, useLayoutEffect } from 'react';
import { useEvent } from './useEvent'; import { useEvent } from './useEvent';
/** /**
* * Listen for changes and trigger callbacks
*/ */
export function useWatch(deps: DependencyList, cb: () => void) { export function useWatch(deps: DependencyList, cb: () => void) {
const memoizedFn = useEvent(cb); const memoizedFn = useEvent(cb);

View File

@ -25,6 +25,7 @@ interface DashboardState {
items: DashboardItem[]; items: DashboardItem[];
addItem: (type: DashboardItemType, id: string, title: string) => void; addItem: (type: DashboardItemType, id: string, title: string) => void;
removeItem: (key: string) => void; removeItem: (key: string) => void;
changeItemTitle: (key: string, title: string) => void;
} }
export const defaultBlankLayouts = { export const defaultBlankLayouts = {
@ -69,6 +70,22 @@ export const useDashboardStore = create<DashboardState>((set, get) => ({
}; };
}); });
}, },
changeItemTitle: (key: string, title: string) => {
set((state) => {
return {
items: state.items.map((item) => {
if (item.key === key) {
return {
...item,
title,
};
} else {
return item;
}
}),
};
});
},
})); }));
export const defaultItemLayout: Record<DashboardItemType, Omit<Layout, 'i'>> = { export const defaultItemLayout: Record<DashboardItemType, Omit<Layout, 'i'>> = {

View File

@ -11,7 +11,7 @@ import {
TitleContentToken, TitleContentToken,
} from './type'; } from './type';
export { ContentToken }; export type { ContentToken };
export const token = { export const token = {
text: (content: string): TextContentToken => ({ text: (content: string): TextContentToken => ({