mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
feat(react/ribbon): reintroduce combobox collection properties
This commit is contained in:
parent
2b8b185b5b
commit
d7e36bdf93
@ -39,15 +39,22 @@ export default function FormSelect<T>({ name, id, onChange, style, ...restProps
|
||||
/**
|
||||
* Similar to {@link FormSelect}, but the top-level elements are actually groups.
|
||||
*/
|
||||
export function FormSelectWithGroups<T>({ name, id, values, keyProperty, titleProperty, currentValue, onChange }: FormSelectProps<T, FormSelectGroup<T>>) {
|
||||
export function FormSelectWithGroups<T>({ name, id, values, keyProperty, titleProperty, currentValue, onChange }: FormSelectProps<T, FormSelectGroup<T> | T>) {
|
||||
return (
|
||||
<FormSelectBody name={name} id={id} onChange={onChange}>
|
||||
{values.map(({ title, items }) => {
|
||||
return (
|
||||
<optgroup label={title}>
|
||||
<FormSelectGroup values={items} keyProperty={keyProperty} titleProperty={titleProperty} currentValue={currentValue} />
|
||||
</optgroup>
|
||||
);
|
||||
{values.map((item) => {
|
||||
if (!item) return <></>;
|
||||
if (typeof item === "object" && "items" in item) {
|
||||
return (
|
||||
<optgroup label={item.title}>
|
||||
<FormSelectGroup values={item.items} keyProperty={keyProperty} titleProperty={titleProperty} currentValue={currentValue} />
|
||||
</optgroup>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<FormSelectGroup values={[ item ]} keyProperty={keyProperty} titleProperty={titleProperty} currentValue={currentValue} />
|
||||
)
|
||||
}
|
||||
})}
|
||||
</FormSelectBody>
|
||||
)
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { useContext, useMemo } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import { ViewTypeOptions } from "../../services/note_list_renderer";
|
||||
import FormSelect from "../react/FormSelect";
|
||||
import FormSelect, { FormSelectWithGroups } from "../react/FormSelect";
|
||||
import { TabContext } from "./ribbon-interface";
|
||||
import { mapToKeyValueArray } from "../../services/utils";
|
||||
import { useNoteLabel, useNoteLabelBoolean } from "../react/hooks";
|
||||
import { bookPropertiesConfig, BookProperty, ButtonProperty, CheckBoxProperty, NumberProperty } from "../ribbon_widgets/book_properties_config";
|
||||
import { bookPropertiesConfig, BookProperty, ButtonProperty, CheckBoxProperty, ComboBoxGroup, ComboBoxProperty, NumberProperty } from "../ribbon_widgets/book_properties_config";
|
||||
import Button from "../react/Button";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import FNote from "../../entities/fnote";
|
||||
@ -69,6 +69,8 @@ function mapPropertyView({ note, property }: { note: FNote, property: BookProper
|
||||
return <CheckboxPropertyView note={note} property={property} />
|
||||
case "number":
|
||||
return <NumberPropertyView note={note} property={property} />
|
||||
case "combobox":
|
||||
return <ComboBoxPropertyView note={note} property={property} />
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,4 +119,22 @@ function NumberPropertyView({ note, property }: { note: FNote, property: NumberP
|
||||
</label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ComboBoxPropertyView({ note, property }: { note: FNote, property: ComboBoxProperty }) {
|
||||
const [ value, setValue ] = useNoteLabel(note, property.bindToLabel);
|
||||
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
{property.label}
|
||||
|
||||
<FormSelectWithGroups
|
||||
values={property.options}
|
||||
keyProperty="value" titleProperty="label"
|
||||
currentValue={value ?? ""} onChange={setValue}
|
||||
/>
|
||||
</label>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { bookPropertiesConfig, BookProperty } from "./book_properties_config.js";
|
||||
import attributes from "../../services/attributes.js";
|
||||
|
||||
export default class BookPropertiesWidget extends NoteContextAwareWidget {
|
||||
|
||||
private $viewTypeSelect!: JQuery<HTMLElement>;
|
||||
private $propertiesContainer!: JQuery<HTMLElement>;
|
||||
private labelsToWatch: string[] = [];
|
||||
|
||||
doRender() {
|
||||
|
||||
this.$viewTypeSelect = this.$widget.find(".view-type-select");
|
||||
this.$viewTypeSelect.on("change", () => this.toggleViewType(String(this.$viewTypeSelect.val())));
|
||||
|
||||
this.$propertiesContainer = this.$widget.find(".book-properties-container");
|
||||
}
|
||||
|
||||
async refreshWithNote(note: FNote) {
|
||||
if (!this.note) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewType = this.note.getLabelValue("viewType") || "grid";
|
||||
|
||||
this.$viewTypeSelect.val(viewType);
|
||||
|
||||
this.$propertiesContainer.empty();
|
||||
|
||||
const bookPropertiesData = bookPropertiesConfig[viewType];
|
||||
if (bookPropertiesData) {
|
||||
for (const property of bookPropertiesData.properties) {
|
||||
this.$propertiesContainer.append(this.renderBookProperty(property));
|
||||
this.labelsToWatch.push(property.bindToLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||
if (loadResults.getAttributeRows().find((attr) =>
|
||||
attr.noteId === this.noteId
|
||||
&& (attr.name === "viewType" || this.labelsToWatch.includes(attr.name ?? "")))) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
renderBookProperty(property: BookProperty) {
|
||||
const $container = $("<div>");
|
||||
$container.addClass(`type-${property.type}`);
|
||||
const note = this.note;
|
||||
if (!note) {
|
||||
return $container;
|
||||
}
|
||||
switch (property.type) {
|
||||
case "combobox":
|
||||
const $select = $("<select>", {
|
||||
class: "form-select form-select-sm"
|
||||
});
|
||||
const actualValue = note.getLabelValue(property.bindToLabel) ?? property.defaultValue ?? "";
|
||||
for (const option of property.options) {
|
||||
if ("items" in option) {
|
||||
const $optGroup = $("<optgroup>", { label: option.name });
|
||||
for (const item of option.items) {
|
||||
buildComboBoxItem(item, actualValue).appendTo($optGroup);
|
||||
}
|
||||
$optGroup.appendTo($select);
|
||||
} else {
|
||||
buildComboBoxItem(option, actualValue).appendTo($select);
|
||||
}
|
||||
}
|
||||
$select.on("change", () => {
|
||||
const value = $select.val();
|
||||
if (value === null || value === "") {
|
||||
attributes.removeOwnedLabelByName(note, property.bindToLabel);
|
||||
} else {
|
||||
attributes.setLabel(note.noteId, property.bindToLabel, String(value));
|
||||
}
|
||||
});
|
||||
$container.append($("<label>")
|
||||
.text(property.label)
|
||||
.append(" ".repeat(2))
|
||||
.append($select));
|
||||
break;
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function buildComboBoxItem({ value, label }: { value: string, label: string }, actualValue: string) {
|
||||
const $option = $("<option>", {
|
||||
value,
|
||||
text: label
|
||||
});
|
||||
if (actualValue === value) {
|
||||
$option.prop("selected", true);
|
||||
}
|
||||
return $option;
|
||||
}
|
@ -37,11 +37,11 @@ interface ComboBoxItem {
|
||||
}
|
||||
|
||||
interface ComboBoxGroup {
|
||||
name: string;
|
||||
title: string;
|
||||
items: ComboBoxItem[];
|
||||
}
|
||||
|
||||
interface ComboBoxProperty {
|
||||
export interface ComboBoxProperty {
|
||||
type: "combobox",
|
||||
label: string;
|
||||
bindToLabel: string;
|
||||
@ -120,19 +120,19 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
|
||||
defaultValue: DEFAULT_MAP_LAYER_NAME,
|
||||
options: [
|
||||
{
|
||||
name: t("book_properties_config.raster"),
|
||||
title: t("book_properties_config.raster"),
|
||||
items: Object.entries(MAP_LAYERS)
|
||||
.filter(([_, layer]) => layer.type === "raster")
|
||||
.map(buildMapLayer)
|
||||
},
|
||||
{
|
||||
name: t("book_properties_config.vector_light"),
|
||||
title: t("book_properties_config.vector_light"),
|
||||
items: Object.entries(MAP_LAYERS)
|
||||
.filter(([_, layer]) => layer.type === "vector" && !layer.isDarkTheme)
|
||||
.map(buildMapLayer)
|
||||
},
|
||||
{
|
||||
name: t("book_properties_config.vector_dark"),
|
||||
title: t("book_properties_config.vector_dark"),
|
||||
items: Object.entries(MAP_LAYERS)
|
||||
.filter(([_, layer]) => layer.type === "vector" && layer.isDarkTheme)
|
||||
.map(buildMapLayer)
|
||||
|
Loading…
x
Reference in New Issue
Block a user