mirror of
https://github.com/zadam/trilium.git
synced 2025-12-25 16:54:25 +01:00
client/status bar panes: improve
This commit is contained in:
parent
1f55ff536e
commit
bdc0b062d5
@ -818,7 +818,8 @@
|
||||
},
|
||||
"inherited_attribute_list": {
|
||||
"title": "Inherited Attributes",
|
||||
"no_inherited_attributes": "No inherited attributes."
|
||||
"no_inherited_attributes": "No inherited attributes.",
|
||||
"none": "none"
|
||||
},
|
||||
"note_info_widget": {
|
||||
"note_id": "Note ID",
|
||||
@ -2203,6 +2204,9 @@
|
||||
"note_paths_title": "Note paths",
|
||||
"code_note_switcher": "Change language mode"
|
||||
},
|
||||
"attributes_panel": {
|
||||
"title": "Note Attributes"
|
||||
},
|
||||
"right_pane": {
|
||||
"empty_message": "Nothing to show for this note",
|
||||
"empty_button": "Hide the panel",
|
||||
|
||||
@ -244,20 +244,44 @@
|
||||
> .attribute-list {
|
||||
font-size: 0.9em;
|
||||
|
||||
.inherited-attributes-widget > div {
|
||||
padding: 0;
|
||||
font-size: 0.9em;
|
||||
.attributes-panel-label {
|
||||
opacity: .5;
|
||||
margin-inline-end: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.attribute-list-editor {
|
||||
padding-block: 0 !important;
|
||||
padding-inline: 0 100px !important ;
|
||||
}
|
||||
.inherited-attributes-widget {
|
||||
display: inline;
|
||||
|
||||
> div {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.attribute-list-editor-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
padding-bottom: 0 !important;
|
||||
|
||||
.attribute-list-editor {
|
||||
padding-block: 0 !important;
|
||||
padding-inline: 0 100px !important ;
|
||||
}
|
||||
|
||||
.attribute-errors {
|
||||
padding: 4px 0;
|
||||
color: var(--dropdown-item-icon-destructive-color);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.ck.ck-editor__editable::after {
|
||||
/* Remove a hidden spinner that causes overflow */
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ck.ck-editor__editable::after {
|
||||
/* Remove a hidden spinner that causes overflow */
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
div.similar-notes-widget div.similar-notes-wrapper {
|
||||
|
||||
@ -268,7 +268,7 @@ function NoteInfoValue({ text, title, value }: { text: string; title?: string, v
|
||||
|
||||
function SimilarNotesPane({ note, similarNotesShown, setSimilarNotesShown }: NoteInfoContext) {
|
||||
return (similarNotesShown &&
|
||||
<StatusBarPane title="Similar notes"
|
||||
<StatusBarPane title={t("similar_notes.title")}
|
||||
className="similar-notes-pane"
|
||||
visible={similarNotesShown}
|
||||
setVisible={setSimilarNotesShown}
|
||||
@ -371,12 +371,13 @@ function AttributesPane({ note, noteContext, attributesShown, setAttributesShown
|
||||
}), [ api ]));
|
||||
|
||||
return (context &&
|
||||
<StatusBarPane title="Attributes"
|
||||
<StatusBarPane title={t("attributes_panel.title")}
|
||||
className="attribute-list"
|
||||
visible={attributesShown}
|
||||
setVisible={setAttributesShown}>
|
||||
|
||||
<InheritedAttributesTab {...context} />
|
||||
|
||||
<span class="attributes-panel-label">{t("inherited_attribute_list.title")}</span>
|
||||
<InheritedAttributesTab {...context} emptyListString="inherited_attribute_list.none" />
|
||||
|
||||
<AttributeEditor
|
||||
{...context}
|
||||
|
||||
@ -9,7 +9,11 @@ import RawHtml from "../react/RawHtml";
|
||||
import { joinElements } from "../react/react_utils";
|
||||
import AttributeDetailWidget from "../attribute_widgets/attribute_detail";
|
||||
|
||||
export default function InheritedAttributesTab({ note, componentId }: Pick<TabContext, "note" | "componentId">) {
|
||||
type InheritedAttributesTabArgs = Pick<TabContext, "note" | "componentId"> & {
|
||||
emptyListString?: string;
|
||||
}
|
||||
|
||||
export default function InheritedAttributesTab({ note, componentId, emptyListString }: InheritedAttributesTabArgs) {
|
||||
const [ inheritedAttributes, setInheritedAttributes ] = useState<FAttribute[]>();
|
||||
const [ attributeDetailWidgetEl, attributeDetailWidget ] = useLegacyWidget(() => new AttributeDetailWidget());
|
||||
|
||||
@ -63,7 +67,7 @@ export default function InheritedAttributesTab({ note, componentId }: Pick<TabCo
|
||||
/>
|
||||
)), " ")
|
||||
) : (
|
||||
<>{t("inherited_attribute_list.no_inherited_attributes")}</>
|
||||
<>{t(emptyListString ?? "inherited_attribute_list.no_inherited_attributes")}</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@ -283,6 +283,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
||||
return (
|
||||
<>
|
||||
{!hidden && <div
|
||||
className="attribute-list-editor-wrapper"
|
||||
ref={wrapperRef}
|
||||
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
||||
onKeyDown={(e) => {
|
||||
@ -296,106 +297,107 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
||||
setTimeout(() => save(), 100);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CKEditor
|
||||
apiRef={editorRef}
|
||||
className="attribute-list-editor"
|
||||
tabIndex={200}
|
||||
editor={CKEditorAttributeEditor}
|
||||
currentValue={currentValue}
|
||||
config={{
|
||||
toolbar: { items: [] },
|
||||
placeholder: t("attribute_editor.placeholder"),
|
||||
mention: { feeds: mentionSetup },
|
||||
licenseKey: "GPL",
|
||||
language: "en"
|
||||
}}
|
||||
onChange={(currentValue) => {
|
||||
currentValueRef.current = currentValue ?? "";
|
||||
|
||||
const oldValue = getPreprocessedData(lastSavedContent.current ?? "").trimEnd();
|
||||
const newValue = getPreprocessedData(currentValue ?? "").trimEnd();
|
||||
setNeedsSaving(oldValue !== newValue);
|
||||
setError(undefined);
|
||||
}}
|
||||
onClick={(e, pos) => {
|
||||
if (pos && pos.textNode && pos.textNode.data) {
|
||||
const clickIndex = getClickIndex(pos);
|
||||
|
||||
let parsedAttrs: Attribute[];
|
||||
|
||||
try {
|
||||
parsedAttrs = attribute_parser.lexAndParse(getPreprocessedData(currentValueRef.current), true);
|
||||
} catch (e: unknown) {
|
||||
// the input is incorrect because the user messed up with it and now needs to fix it manually
|
||||
console.log(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
let matchedAttr: Attribute | null = null;
|
||||
|
||||
for (const attr of parsedAttrs) {
|
||||
if (attr.startIndex && clickIndex > attr.startIndex && attr.endIndex && clickIndex <= attr.endIndex) {
|
||||
matchedAttr = attr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (matchedAttr) {
|
||||
attributeDetailWidget.showAttributeDetail({
|
||||
allAttributes: parsedAttrs,
|
||||
attribute: matchedAttr,
|
||||
isOwned: true,
|
||||
x: e.pageX,
|
||||
y: e.pageY
|
||||
});
|
||||
setState("showAttributeDetail");
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}}
|
||||
onKeyDown={() => attributeDetailWidget.hide()}
|
||||
onBlur={() => save()}
|
||||
onInitialized={() => editorRef.current?.focus()}
|
||||
disableNewlines disableSpellcheck
|
||||
/>
|
||||
|
||||
<div className="attribute-editor-buttons">
|
||||
{ needsSaving && <ActionButton
|
||||
icon="bx bx-save"
|
||||
className="save-attributes-button tn-tool-button"
|
||||
text={escapeQuotes(t("attribute_editor.save_attributes"))}
|
||||
onClick={save}
|
||||
/> }
|
||||
|
||||
<ActionButton
|
||||
icon="bx bx-plus"
|
||||
className="add-new-attribute-button tn-tool-button"
|
||||
text={escapeQuotes(t("attribute_editor.add_a_new_attribute"))}
|
||||
onClick={(e) => {
|
||||
// Prevent automatic hiding of the context menu due to the button being clicked.
|
||||
e.stopPropagation();
|
||||
|
||||
contextMenu.show<AttributeCommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
orientation: "left",
|
||||
items: [
|
||||
{ title: t("attribute_editor.add_new_label"), command: "addNewLabel", uiIcon: "bx bx-hash" },
|
||||
{ title: t("attribute_editor.add_new_relation"), command: "addNewRelation", uiIcon: "bx bx-transfer" },
|
||||
{ kind: "separator" },
|
||||
{ title: t("attribute_editor.add_new_label_definition"), command: "addNewLabelDefinition", uiIcon: "bx bx-empty" },
|
||||
{ title: t("attribute_editor.add_new_relation_definition"), command: "addNewRelationDefinition", uiIcon: "bx bx-empty" }
|
||||
],
|
||||
selectMenuItemHandler: (item) => handleAddNewAttributeCommand(item.command)
|
||||
});
|
||||
> <div style="position: relative;">
|
||||
<CKEditor
|
||||
apiRef={editorRef}
|
||||
className="attribute-list-editor"
|
||||
tabIndex={200}
|
||||
editor={CKEditorAttributeEditor}
|
||||
currentValue={currentValue}
|
||||
config={{
|
||||
toolbar: { items: [] },
|
||||
placeholder: t("attribute_editor.placeholder"),
|
||||
mention: { feeds: mentionSetup },
|
||||
licenseKey: "GPL",
|
||||
language: "en"
|
||||
}}
|
||||
onChange={(currentValue) => {
|
||||
currentValueRef.current = currentValue ?? "";
|
||||
|
||||
const oldValue = getPreprocessedData(lastSavedContent.current ?? "").trimEnd();
|
||||
const newValue = getPreprocessedData(currentValue ?? "").trimEnd();
|
||||
setNeedsSaving(oldValue !== newValue);
|
||||
setError(undefined);
|
||||
}}
|
||||
onClick={(e, pos) => {
|
||||
if (pos && pos.textNode && pos.textNode.data) {
|
||||
const clickIndex = getClickIndex(pos);
|
||||
|
||||
let parsedAttrs: Attribute[];
|
||||
|
||||
try {
|
||||
parsedAttrs = attribute_parser.lexAndParse(getPreprocessedData(currentValueRef.current), true);
|
||||
} catch (e: unknown) {
|
||||
// the input is incorrect because the user messed up with it and now needs to fix it manually
|
||||
console.log(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
let matchedAttr: Attribute | null = null;
|
||||
|
||||
for (const attr of parsedAttrs) {
|
||||
if (attr.startIndex && clickIndex > attr.startIndex && attr.endIndex && clickIndex <= attr.endIndex) {
|
||||
matchedAttr = attr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (matchedAttr) {
|
||||
attributeDetailWidget.showAttributeDetail({
|
||||
allAttributes: parsedAttrs,
|
||||
attribute: matchedAttr,
|
||||
isOwned: true,
|
||||
x: e.pageX,
|
||||
y: e.pageY
|
||||
});
|
||||
setState("showAttributeDetail");
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}}
|
||||
onKeyDown={() => attributeDetailWidget.hide()}
|
||||
onBlur={() => save()}
|
||||
onInitialized={() => editorRef.current?.focus()}
|
||||
disableNewlines disableSpellcheck
|
||||
/>
|
||||
|
||||
<div className="attribute-editor-buttons">
|
||||
{ needsSaving && <ActionButton
|
||||
icon="bx bx-save"
|
||||
className="save-attributes-button tn-tool-button"
|
||||
text={escapeQuotes(t("attribute_editor.save_attributes"))}
|
||||
onClick={save}
|
||||
/> }
|
||||
|
||||
<ActionButton
|
||||
icon="bx bx-plus"
|
||||
className="add-new-attribute-button tn-tool-button"
|
||||
text={escapeQuotes(t("attribute_editor.add_a_new_attribute"))}
|
||||
onClick={(e) => {
|
||||
// Prevent automatic hiding of the context menu due to the button being clicked.
|
||||
e.stopPropagation();
|
||||
|
||||
contextMenu.show<AttributeCommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
orientation: "left",
|
||||
items: [
|
||||
{ title: t("attribute_editor.add_new_label"), command: "addNewLabel", uiIcon: "bx bx-hash" },
|
||||
{ title: t("attribute_editor.add_new_relation"), command: "addNewRelation", uiIcon: "bx bx-transfer" },
|
||||
{ kind: "separator" },
|
||||
{ title: t("attribute_editor.add_new_label_definition"), command: "addNewLabelDefinition", uiIcon: "bx bx-empty" },
|
||||
{ title: t("attribute_editor.add_new_relation_definition"), command: "addNewRelationDefinition", uiIcon: "bx bx-empty" }
|
||||
],
|
||||
selectMenuItemHandler: (item) => handleAddNewAttributeCommand(item.command)
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ error && (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user