mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): add notes popover to field title bar
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
FormControl,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
Textarea,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { useFieldNotes } from 'features/nodes/hooks/useFieldNotes';
|
||||
import { fieldNotesChanged } from 'features/nodes/store/nodesSlice';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiNoteBold } from 'react-icons/pi';
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
fieldName: string;
|
||||
};
|
||||
|
||||
export const FieldNotesIconButton = memo(({ nodeId, fieldName }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const notes = useFieldNotes(nodeId, fieldName);
|
||||
const onChange = useCallback(
|
||||
(e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
dispatch(fieldNotesChanged({ nodeId, fieldName, val: e.target.value }));
|
||||
},
|
||||
[dispatch, fieldName, nodeId]
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
tooltip={t('nodes.notes')}
|
||||
aria-label={t('nodes.notes')}
|
||||
icon={<PiNoteBold />}
|
||||
pointerEvents="auto"
|
||||
size="xs"
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent p={2} w={256}>
|
||||
<FormControl orientation="vertical">
|
||||
<FormLabel>{t('nodes.notes')}</FormLabel>
|
||||
<Textarea
|
||||
className="nodrag nopan nowheel"
|
||||
fontSize="sm"
|
||||
value={notes ?? ''}
|
||||
onChange={onChange}
|
||||
p={2}
|
||||
resize="none"
|
||||
rows={5}
|
||||
/>
|
||||
</FormControl>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
});
|
||||
|
||||
FieldNotesIconButton.displayName = 'FieldNotesIconButton';
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Flex, FormControl } from '@invoke-ai/ui-library';
|
||||
import { FieldNotesIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/FieldNotesIconButton';
|
||||
import FieldResetToDefaultValueButton from 'features/nodes/components/flow/nodes/Invocation/fields/FieldResetToDefaultValueButton';
|
||||
import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
|
||||
import { useFieldInputTemplate } from 'features/nodes/hooks/useFieldInputTemplate';
|
||||
@@ -71,6 +72,7 @@ const InputField = ({ nodeId, fieldName }: Props) => {
|
||||
<Flex flexDir="column" w="full" gap={1} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
<Flex gap={1}>
|
||||
<EditableFieldTitle nodeId={nodeId} fieldName={fieldName} kind="inputs" isInvalid={isInvalid} withTooltip />
|
||||
{isHovered && <FieldNotesIconButton nodeId={nodeId} fieldName={fieldName} />}
|
||||
{isHovered && <FieldResetToDefaultValueButton nodeId={nodeId} fieldName={fieldName} />}
|
||||
{isHovered && <FieldLinearViewToggle nodeId={nodeId} fieldName={fieldName} />}
|
||||
</Flex>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldNotes = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(selectNodesSlice, (nodes) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.notes;
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
const notes = useAppSelector(selector);
|
||||
return notes;
|
||||
};
|
||||
Reference in New Issue
Block a user