mirror of
https://github.com/zadam/trilium.git
synced 2025-11-15 19:08:56 +01:00
feat(board/relation): basic support for editing relations in columns
This commit is contained in:
parent
d1e80815d5
commit
092a84693f
@ -119,7 +119,7 @@ export default function Card({
|
|||||||
setTitle(newTitle);
|
setTitle(newTitle);
|
||||||
}}
|
}}
|
||||||
dismiss={() => api.dismissEditingTitle()}
|
dismiss={() => api.dismissEditingTitle()}
|
||||||
multiline
|
mode="multiline"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -124,6 +124,7 @@ export default function Column({
|
|||||||
currentValue={column}
|
currentValue={column}
|
||||||
save={newTitle => api.renameColumn(column, newTitle)}
|
save={newTitle => api.renameColumn(column, newTitle)}
|
||||||
dismiss={() => setColumnNameToEdit?.(undefined)}
|
dismiss={() => setColumnNameToEdit?.(undefined)}
|
||||||
|
mode={isInRelationMode ? "relation" : "normal"}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
@ -187,7 +188,7 @@ function AddNewItem({ column, api }: { column: string, api: BoardApi }) {
|
|||||||
placeholder={t("board_view.new-item-placeholder")}
|
placeholder={t("board_view.new-item-placeholder")}
|
||||||
save={(title) => api.createNewItem(column, title)}
|
save={(title) => api.createNewItem(column, title)}
|
||||||
dismiss={() => setIsCreatingNewItem(false)}
|
dismiss={() => setIsCreatingNewItem(false)}
|
||||||
multiline isNewItem
|
mode="multiline" isNewItem
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Column from "./column";
|
|||||||
import BoardApi from "./api";
|
import BoardApi from "./api";
|
||||||
import FormTextArea from "../../react/FormTextArea";
|
import FormTextArea from "../../react/FormTextArea";
|
||||||
import FNote from "../../../entities/fnote";
|
import FNote from "../../../entities/fnote";
|
||||||
|
import NoteAutocomplete from "../../react/NoteAutocomplete";
|
||||||
|
|
||||||
export interface BoardViewData {
|
export interface BoardViewData {
|
||||||
columns?: BoardColumnData[];
|
columns?: BoardColumnData[];
|
||||||
@ -188,14 +189,14 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC
|
|||||||
<div className="column-drop-placeholder show" />
|
<div className="column-drop-placeholder show" />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<AddNewColumn api={api} />
|
<AddNewColumn api={api} isInRelationMode={isInRelationMode} />
|
||||||
</div>
|
</div>
|
||||||
</BoardViewContext.Provider>
|
</BoardViewContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddNewColumn({ api }: { api: BoardApi }) {
|
function AddNewColumn({ api, isInRelationMode }: { api: BoardApi, isInRelationMode: boolean }) {
|
||||||
const [ isCreatingNewColumn, setIsCreatingNewColumn ] = useState(false);
|
const [ isCreatingNewColumn, setIsCreatingNewColumn ] = useState(false);
|
||||||
|
|
||||||
const addColumnCallback = useCallback(() => {
|
const addColumnCallback = useCallback(() => {
|
||||||
@ -215,19 +216,20 @@ function AddNewColumn({ api }: { api: BoardApi }) {
|
|||||||
save={(columnName) => api.addNewColumn(columnName)}
|
save={(columnName) => api.addNewColumn(columnName)}
|
||||||
dismiss={() => setIsCreatingNewColumn(false)}
|
dismiss={() => setIsCreatingNewColumn(false)}
|
||||||
isNewItem
|
isNewItem
|
||||||
|
mode={isInRelationMode ? "relation" : "normal"}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TitleEditor({ currentValue, placeholder, save, dismiss, multiline, isNewItem }: {
|
export function TitleEditor({ currentValue, placeholder, save, dismiss, mode, isNewItem }: {
|
||||||
currentValue?: string;
|
currentValue?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
save: (newValue: string) => void;
|
save: (newValue: string) => void;
|
||||||
dismiss: () => void;
|
dismiss: () => void;
|
||||||
multiline?: boolean;
|
|
||||||
isNewItem?: boolean;
|
isNewItem?: boolean;
|
||||||
|
mode?: "normal" | "multiline" | "relation";
|
||||||
}) {
|
}) {
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
const focusElRef = useRef<Element>(null);
|
const focusElRef = useRef<Element>(null);
|
||||||
@ -240,8 +242,6 @@ export function TitleEditor({ currentValue, placeholder, save, dismiss, multilin
|
|||||||
inputRef.current?.select();
|
inputRef.current?.select();
|
||||||
}, [ inputRef ]);
|
}, [ inputRef ]);
|
||||||
|
|
||||||
const Element = multiline ? FormTextArea : FormTextBox;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dismissOnNextRefreshRef.current) {
|
if (dismissOnNextRefreshRef.current) {
|
||||||
dismiss();
|
dismiss();
|
||||||
@ -249,14 +249,7 @@ export function TitleEditor({ currentValue, placeholder, save, dismiss, multilin
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
const onKeyDown = (e: TargetedKeyboardEvent<HTMLInputElement | HTMLTextAreaElement> | KeyboardEvent) => {
|
||||||
<Element
|
|
||||||
inputRef={inputRef}
|
|
||||||
currentValue={currentValue ?? ""}
|
|
||||||
placeholder={placeholder}
|
|
||||||
autoComplete="trilium-title-entry" // forces the auto-fill off better than the "off" value.
|
|
||||||
rows={multiline ? 4 : undefined}
|
|
||||||
onKeyDown={(e: TargetedKeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
||||||
if (e.key === "Enter" || e.key === "Escape") {
|
if (e.key === "Enter" || e.key === "Escape") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -265,15 +258,43 @@ export function TitleEditor({ currentValue, placeholder, save, dismiss, multilin
|
|||||||
focusElRef.current.focus();
|
focusElRef.current.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
};
|
||||||
onBlur={(newValue) => {
|
|
||||||
|
const onBlur = (newValue) => {
|
||||||
if (!shouldDismiss.current && newValue.trim() && (newValue !== currentValue || isNewItem)) {
|
if (!shouldDismiss.current && newValue.trim() && (newValue !== currentValue || isNewItem)) {
|
||||||
save(newValue);
|
save(newValue);
|
||||||
dismissOnNextRefreshRef.current = true;
|
dismissOnNextRefreshRef.current = true;
|
||||||
} else {
|
} else {
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
}}
|
};
|
||||||
|
|
||||||
|
if (mode !== "relation") {
|
||||||
|
const Element = mode === "multiline" ? FormTextArea : FormTextBox;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Element
|
||||||
|
inputRef={inputRef}
|
||||||
|
currentValue={currentValue ?? ""}
|
||||||
|
placeholder={placeholder}
|
||||||
|
autoComplete="trilium-title-entry" // forces the auto-fill off better than the "off" value.
|
||||||
|
rows={mode === "multiline" ? 4 : undefined}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
onBlur={onBlur}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<NoteAutocomplete
|
||||||
|
inputRef={inputRef}
|
||||||
|
noteId={currentValue ?? ""}
|
||||||
|
opts={{
|
||||||
|
hideAllButtons: true,
|
||||||
|
allowCreatingNotes: true
|
||||||
|
}}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
onBlur={onBlur}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,11 +15,13 @@ interface NoteAutocompleteProps {
|
|||||||
opts?: Omit<Options, "container">;
|
opts?: Omit<Options, "container">;
|
||||||
onChange?: (suggestion: Suggestion | null) => void;
|
onChange?: (suggestion: Suggestion | null) => void;
|
||||||
onTextChange?: (text: string) => void;
|
onTextChange?: (text: string) => void;
|
||||||
|
onKeyDown?: (e: KeyboardEvent) => void;
|
||||||
|
onBlur?: (newValue: string) => void;
|
||||||
noteIdChanged?: (noteId: string) => void;
|
noteIdChanged?: (noteId: string) => void;
|
||||||
noteId?: string;
|
noteId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NoteAutocomplete({ id, inputRef: externalInputRef, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged }: NoteAutocompleteProps) {
|
export default function NoteAutocomplete({ id, inputRef: externalInputRef, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged, onKeyDown, onBlur }: NoteAutocompleteProps) {
|
||||||
const ref = useSyncedRef<HTMLInputElement>(externalInputRef);
|
const ref = useSyncedRef<HTMLInputElement>(externalInputRef);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -57,6 +59,12 @@ export default function NoteAutocomplete({ id, inputRef: externalInputRef, text,
|
|||||||
if (onTextChange) {
|
if (onTextChange) {
|
||||||
$autoComplete.on("input", () => onTextChange($autoComplete[0].value));
|
$autoComplete.on("input", () => onTextChange($autoComplete[0].value));
|
||||||
}
|
}
|
||||||
|
if (onKeyDown) {
|
||||||
|
$autoComplete.on("keydown", (e) => e.originalEvent && onKeyDown(e.originalEvent));
|
||||||
|
}
|
||||||
|
if (onBlur) {
|
||||||
|
$autoComplete.on("blur", () => onBlur($autoComplete.getSelectedNoteId() ?? ""));
|
||||||
|
}
|
||||||
}, [opts, container?.current]);
|
}, [opts, container?.current]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user