mirror of
https://github.com/zadam/trilium.git
synced 2026-01-04 21:54:23 +01:00
client/status bar panes: improve
This commit is contained in:
parent
1f55ff536e
commit
bdc0b062d5
@ -818,7 +818,8 @@
|
|||||||
},
|
},
|
||||||
"inherited_attribute_list": {
|
"inherited_attribute_list": {
|
||||||
"title": "Inherited Attributes",
|
"title": "Inherited Attributes",
|
||||||
"no_inherited_attributes": "No inherited attributes."
|
"no_inherited_attributes": "No inherited attributes.",
|
||||||
|
"none": "none"
|
||||||
},
|
},
|
||||||
"note_info_widget": {
|
"note_info_widget": {
|
||||||
"note_id": "Note ID",
|
"note_id": "Note ID",
|
||||||
@ -2203,6 +2204,9 @@
|
|||||||
"note_paths_title": "Note paths",
|
"note_paths_title": "Note paths",
|
||||||
"code_note_switcher": "Change language mode"
|
"code_note_switcher": "Change language mode"
|
||||||
},
|
},
|
||||||
|
"attributes_panel": {
|
||||||
|
"title": "Note Attributes"
|
||||||
|
},
|
||||||
"right_pane": {
|
"right_pane": {
|
||||||
"empty_message": "Nothing to show for this note",
|
"empty_message": "Nothing to show for this note",
|
||||||
"empty_button": "Hide the panel",
|
"empty_button": "Hide the panel",
|
||||||
|
|||||||
@ -244,20 +244,44 @@
|
|||||||
> .attribute-list {
|
> .attribute-list {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
|
||||||
.inherited-attributes-widget > div {
|
.attributes-panel-label {
|
||||||
padding: 0;
|
opacity: .5;
|
||||||
font-size: 0.9em;
|
margin-inline-end: 4px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attribute-list-editor {
|
.inherited-attributes-widget {
|
||||||
padding-block: 0 !important;
|
display: inline;
|
||||||
padding-inline: 0 100px !important ;
|
|
||||||
}
|
> 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 {
|
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) {
|
function SimilarNotesPane({ note, similarNotesShown, setSimilarNotesShown }: NoteInfoContext) {
|
||||||
return (similarNotesShown &&
|
return (similarNotesShown &&
|
||||||
<StatusBarPane title="Similar notes"
|
<StatusBarPane title={t("similar_notes.title")}
|
||||||
className="similar-notes-pane"
|
className="similar-notes-pane"
|
||||||
visible={similarNotesShown}
|
visible={similarNotesShown}
|
||||||
setVisible={setSimilarNotesShown}
|
setVisible={setSimilarNotesShown}
|
||||||
@ -371,12 +371,13 @@ function AttributesPane({ note, noteContext, attributesShown, setAttributesShown
|
|||||||
}), [ api ]));
|
}), [ api ]));
|
||||||
|
|
||||||
return (context &&
|
return (context &&
|
||||||
<StatusBarPane title="Attributes"
|
<StatusBarPane title={t("attributes_panel.title")}
|
||||||
className="attribute-list"
|
className="attribute-list"
|
||||||
visible={attributesShown}
|
visible={attributesShown}
|
||||||
setVisible={setAttributesShown}>
|
setVisible={setAttributesShown}>
|
||||||
|
|
||||||
<InheritedAttributesTab {...context} />
|
<span class="attributes-panel-label">{t("inherited_attribute_list.title")}</span>
|
||||||
|
<InheritedAttributesTab {...context} emptyListString="inherited_attribute_list.none" />
|
||||||
|
|
||||||
<AttributeEditor
|
<AttributeEditor
|
||||||
{...context}
|
{...context}
|
||||||
|
|||||||
@ -9,7 +9,11 @@ import RawHtml from "../react/RawHtml";
|
|||||||
import { joinElements } from "../react/react_utils";
|
import { joinElements } from "../react/react_utils";
|
||||||
import AttributeDetailWidget from "../attribute_widgets/attribute_detail";
|
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 [ inheritedAttributes, setInheritedAttributes ] = useState<FAttribute[]>();
|
||||||
const [ attributeDetailWidgetEl, attributeDetailWidget ] = useLegacyWidget(() => new AttributeDetailWidget());
|
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>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -283,6 +283,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!hidden && <div
|
{!hidden && <div
|
||||||
|
className="attribute-list-editor-wrapper"
|
||||||
ref={wrapperRef}
|
ref={wrapperRef}
|
||||||
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@ -296,106 +297,107 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
|||||||
setTimeout(() => save(), 100);
|
setTimeout(() => save(), 100);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
> <div style="position: relative;">
|
||||||
<CKEditor
|
<CKEditor
|
||||||
apiRef={editorRef}
|
apiRef={editorRef}
|
||||||
className="attribute-list-editor"
|
className="attribute-list-editor"
|
||||||
tabIndex={200}
|
tabIndex={200}
|
||||||
editor={CKEditorAttributeEditor}
|
editor={CKEditorAttributeEditor}
|
||||||
currentValue={currentValue}
|
currentValue={currentValue}
|
||||||
config={{
|
config={{
|
||||||
toolbar: { items: [] },
|
toolbar: { items: [] },
|
||||||
placeholder: t("attribute_editor.placeholder"),
|
placeholder: t("attribute_editor.placeholder"),
|
||||||
mention: { feeds: mentionSetup },
|
mention: { feeds: mentionSetup },
|
||||||
licenseKey: "GPL",
|
licenseKey: "GPL",
|
||||||
language: "en"
|
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)
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
|
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>
|
</div>
|
||||||
|
|
||||||
{ error && (
|
{ error && (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user