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')}
layouts={layouts}
rowHeight={50}
draggableCancel=".non-draggable"
isDraggable={isEditMode}
isResizable={isEditMode}
breakpoints={{ lg: 1200, md: 768, sm: 0 }}

View File

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

View File

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

View File

@ -25,6 +25,7 @@ interface DashboardState {
items: DashboardItem[];
addItem: (type: DashboardItemType, id: string, title: string) => void;
removeItem: (key: string) => void;
changeItemTitle: (key: string, title: string) => void;
}
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'>> = {

View File

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