增加可编辑描述组件。
This commit is contained in:
parent
0cb158e23d
commit
0b59b0a405
27
src/components/EditableDescription.module.css
Normal file
27
src/components/EditableDescription.module.css
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
@layer components {
|
||||||
|
.editable_description_layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
padding-inline: var(--spacing-xxl);
|
||||||
|
.content {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 45em;
|
||||||
|
height: fit-content;
|
||||||
|
overflow: hidden;
|
||||||
|
resize: none;
|
||||||
|
min-height: calc(1.2em * 2);
|
||||||
|
max-height: calc(1.2em * 5);
|
||||||
|
}
|
||||||
|
.invalid_content {
|
||||||
|
color: var(--color-neutral-focus);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
font-style: italic;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
src/components/EditableDescription.tsx
Normal file
49
src/components/EditableDescription.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Icon } from '@iconify/react/dist/iconify.js';
|
||||||
|
import { isEmpty, isNil } from 'lodash-es';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import styles from './EditableDescription.module.css';
|
||||||
|
|
||||||
|
type EditableDescriptionProps = {
|
||||||
|
content?: string | null;
|
||||||
|
onChange?: (newContent: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EditableDescription({ content, onChange }: EditableDescriptionProps) {
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
|
const cancelEdit = () => {
|
||||||
|
setIsEditing(false);
|
||||||
|
formRef.current?.reset();
|
||||||
|
};
|
||||||
|
const handleSubmit = (data: FormData) => {
|
||||||
|
const newDescription = data.get('description') as string;
|
||||||
|
if (newDescription !== content) {
|
||||||
|
onChange?.(isEmpty(newDescription) ? null : newDescription);
|
||||||
|
}
|
||||||
|
cancelEdit();
|
||||||
|
};
|
||||||
|
|
||||||
|
return isEditing ? (
|
||||||
|
<form className={styles.editable_description_layout} action={handleSubmit} ref={formRef}>
|
||||||
|
<textarea name="description" className={styles.content} defaultValue={content} />
|
||||||
|
<div className="action_icon success" onClick={() => formRef.current?.requestSubmit()}>
|
||||||
|
<Icon icon="tabler:check" />
|
||||||
|
</div>
|
||||||
|
<div className="action_icon danger" onClick={cancelEdit}>
|
||||||
|
<Icon icon="tabler:x" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<div className={styles.editable_description_layout}>
|
||||||
|
<div className={styles.content}>
|
||||||
|
{isNil(content) || isEmpty(content) ? (
|
||||||
|
<div className={styles.invalid_content} onClick={() => setIsEditing(true)}>
|
||||||
|
Click to add description.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
content
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user