mirror of
https://github.com/zadam/trilium.git
synced 2025-11-12 08:15:52 +01:00
feat(react/ribbon): port editability select
This commit is contained in:
30
apps/client/src/widgets/react/FormDropdownList.tsx
Normal file
30
apps/client/src/widgets/react/FormDropdownList.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import Dropdown from "./Dropdown";
|
||||
import { FormListItem } from "./FormList";
|
||||
|
||||
interface FormDropdownList<T> {
|
||||
values: T[];
|
||||
keyProperty: keyof T;
|
||||
titleProperty: keyof T;
|
||||
descriptionProperty?: keyof T;
|
||||
currentValue: string;
|
||||
onChange(newValue: string): void;
|
||||
}
|
||||
|
||||
export default function FormDropdownList<T>({ values, keyProperty, titleProperty, descriptionProperty, currentValue, onChange }: FormDropdownList<T>) {
|
||||
const currentValueData = values.find(value => value[keyProperty] === currentValue);
|
||||
|
||||
return (
|
||||
<Dropdown text={currentValueData?.[titleProperty] ?? ""}>
|
||||
{values.map(item => (
|
||||
<FormListItem
|
||||
onClick={() => onChange(item[keyProperty] as string)}
|
||||
checked={currentValue === item[keyProperty]}
|
||||
description={descriptionProperty && item[descriptionProperty] as string}
|
||||
selected={currentValue === item[keyProperty]}
|
||||
>
|
||||
{item[titleProperty] as string}
|
||||
</FormListItem>
|
||||
))}
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
5
apps/client/src/widgets/react/FormList.css
Normal file
5
apps/client/src/widgets/react/FormList.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.dropdown-item .description {
|
||||
font-size: small;
|
||||
color: var(--muted-text-color);
|
||||
white-space: normal;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Dropdown as BootstrapDropdown } from "bootstrap";
|
||||
import { ComponentChildren } from "preact";
|
||||
import Icon from "./Icon";
|
||||
import { useEffect, useMemo, useRef, type CSSProperties } from "preact/compat";
|
||||
import "./FormList.css";
|
||||
|
||||
interface FormListOpts {
|
||||
children: ComponentChildren;
|
||||
@@ -76,27 +77,33 @@ interface FormListItemOpts {
|
||||
active?: boolean;
|
||||
badges?: FormListBadge[];
|
||||
disabled?: boolean;
|
||||
checked?: boolean;
|
||||
checked?: boolean | null;
|
||||
selected?: boolean;
|
||||
onClick?: () => void;
|
||||
description?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function FormListItem({ children, icon, value, title, active, badges, disabled, checked, onClick }: FormListItemOpts) {
|
||||
export function FormListItem({ children, icon, value, title, active, badges, disabled, checked, onClick, description, selected }: FormListItemOpts) {
|
||||
if (checked) {
|
||||
icon = "bx bx-check";
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
class={`dropdown-item ${active ? "active" : ""} ${disabled ? "disabled" : ""}`}
|
||||
class={`dropdown-item ${active ? "active" : ""} ${disabled ? "disabled" : ""} ${selected ? "selected" : ""}`}
|
||||
data-value={value} title={title}
|
||||
tabIndex={0}
|
||||
onClick={onClick}
|
||||
>
|
||||
<Icon icon={icon} />
|
||||
{children}
|
||||
{badges && badges.map(({ className, text }) => (
|
||||
<span className={`badge ${className ?? ""}`}>{text}</span>
|
||||
))}
|
||||
<div>
|
||||
{children}
|
||||
{badges && badges.map(({ className, text }) => (
|
||||
<span className={`badge ${className ?? ""}`}>{text}</span>
|
||||
))}
|
||||
{description && <div className="description">{description}</div>}
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -314,12 +314,12 @@ export function useNoteProperty<T extends keyof FNote>(note: FNote | null | unde
|
||||
}
|
||||
|
||||
export function useNoteLabel(note: FNote | undefined | null, labelName: string): [string | null | undefined, (newValue: string) => void] {
|
||||
const [ labelValue, setNoteValue ] = useState<string | null | undefined>(note?.getLabelValue(labelName));
|
||||
const [ labelValue, setLabelValue ] = useState<string | null | undefined>(note?.getLabelValue(labelName));
|
||||
|
||||
useTriliumEventBeta("entitiesReloaded", ({ loadResults }) => {
|
||||
for (const attr of loadResults.getAttributeRows()) {
|
||||
if (attr.type === "label" && attr.name === labelName && attributes.isAffecting(attr, note)) {
|
||||
setNoteValue(attr.value ?? null);
|
||||
setLabelValue(attr.value ?? null);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -334,4 +334,28 @@ export function useNoteLabel(note: FNote | undefined | null, labelName: string):
|
||||
labelValue,
|
||||
setter
|
||||
] as const;
|
||||
}
|
||||
|
||||
export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: string): [ boolean | null | undefined, (newValue: boolean) => void] {
|
||||
const [ labelValue, setLabelValue ] = useState<boolean | null | undefined>(note?.hasLabel(labelName));
|
||||
|
||||
useTriliumEventBeta("entitiesReloaded", ({ loadResults }) => {
|
||||
for (const attr of loadResults.getAttributeRows()) {
|
||||
if (attr.type === "label" && attr.name === labelName && attributes.isAffecting(attr, note)) {
|
||||
setLabelValue(!attr.isDeleted);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const setter = useCallback((value: boolean) => {
|
||||
if (note) {
|
||||
if (value) {
|
||||
attributes.setLabel(note.noteId, labelName, "");
|
||||
} else {
|
||||
attributes.removeOwnedLabelByName(note, labelName);
|
||||
}
|
||||
}
|
||||
}, [note]);
|
||||
|
||||
return [ labelValue, setter ] as const;
|
||||
}
|
||||
Reference in New Issue
Block a user