mirror of
https://github.com/zadam/trilium.git
synced 2025-02-24 23:13:43 +08:00
basic bookmark support
This commit is contained in:
parent
0654dc855f
commit
8d42ffca6d
9 changed files with 214 additions and 31 deletions
38
package-lock.json
generated
38
package-lock.json
generated
|
@ -1602,16 +1602,16 @@
|
|||
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.17.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.2.tgz",
|
||||
"integrity": "sha512-jSDZyqJmkKMEMi7SZAgX5UltFdR5NAO43vY0AwTpu4X3sGH7GLLQ83KiUomgrnvZRCeW0yPPnKqnxPqQOER9zQ==",
|
||||
"version": "4.17.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz",
|
||||
"integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001261",
|
||||
"electron-to-chromium": "^1.3.854",
|
||||
"caniuse-lite": "^1.0.30001264",
|
||||
"electron-to-chromium": "^1.3.857",
|
||||
"escalade": "^3.1.1",
|
||||
"nanocolors": "^0.2.12",
|
||||
"node-releases": "^1.1.76"
|
||||
"node-releases": "^1.1.77",
|
||||
"picocolors": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
|
@ -3578,9 +3578,9 @@
|
|||
}
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.857",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.857.tgz",
|
||||
"integrity": "sha512-a5kIr2lajm4bJ5E4D3fp8Y/BRB0Dx2VOcCRE5Gtb679mXIME/OFhWler8Gy2ksrf8gFX+EFCSIGA33FB3gqYpg==",
|
||||
"version": "1.3.859",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.859.tgz",
|
||||
"integrity": "sha512-gXRXKNWedfdiKIzwr0Mg/VGCvxXzy+4SuK9hp1BDvfbCwx0O5Ot+2f4CoqQkqEJ3Zj/eAV/GoAFgBVFgkBLXuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"electron-window-state": {
|
||||
|
@ -5824,12 +5824,6 @@
|
|||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"nanocolors": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz",
|
||||
"integrity": "sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==",
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.25",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
|
||||
|
@ -6363,6 +6357,12 @@
|
|||
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
|
||||
"integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA=="
|
||||
},
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
|
@ -8098,9 +8098,9 @@
|
|||
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.56.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.56.1.tgz",
|
||||
"integrity": "sha512-MRbTPooHJuSAfbx7Lh/qEMRUe/d0p4cRj2GPo/fq+4JUeR/+Q1EfLvS1lexslbMcJZyPXxxz/k/NzVepkA5upA==",
|
||||
"version": "5.57.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.57.0.tgz",
|
||||
"integrity": "sha512-kbKX1HOJpEhX9GZDFgHauU/7HfgGeGzUzjSUV+wZjGxP3PFeau7BgYFtm5+UTtJJSqmXYKFuBpWRDrSdQ3d8zA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.0",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"jsdoc": "3.6.7",
|
||||
"lorem-ipsum": "2.0.4",
|
||||
"rcedit": "3.0.1",
|
||||
"webpack": "5.56.1",
|
||||
"webpack": "5.57.0",
|
||||
"webpack-cli": "4.8.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
|
|
@ -140,6 +140,10 @@ function getSomePathInner(note, path, respectHoisting) {
|
|||
path.push(note.noteId);
|
||||
path.reverse();
|
||||
|
||||
if (path.includes("hidden")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (respectHoisting && !path.includes(cls.getHoistedNoteId())) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import CalendarMenuWidget from "../widgets/buttons/calendar_menu.js";
|
|||
import EditedNotesWidget from "../widgets/ribbon_widgets/edited_notes.js";
|
||||
import OpenNoteButtonWidget from "../widgets/buttons/open_note_button_widget.js";
|
||||
import MermaidWidget from "../widgets/mermaid.js";
|
||||
import BookmarkButtons from "../widgets/bookmark_buttons.js";
|
||||
|
||||
export default class DesktopLayout {
|
||||
constructor(customWidgets) {
|
||||
|
@ -72,8 +73,6 @@ export default class DesktopLayout {
|
|||
.title("Jump to note")
|
||||
.command("jumpToNote"))
|
||||
.child(new OpenNoteButtonWidget()
|
||||
.icon("bx-map-alt")
|
||||
.title("Global note map")
|
||||
.targetNote('globalnotemap'))
|
||||
.child(new ButtonWidget()
|
||||
.icon("bx-history")
|
||||
|
@ -84,6 +83,7 @@ export default class DesktopLayout {
|
|||
.child(new FlexContainer("column")
|
||||
.id("plugin-buttons")
|
||||
.contentSized())
|
||||
.child(new BookmarkButtons())
|
||||
.child(new SpacerWidget(0, 1000))
|
||||
.child(new ProtectedSessionStatusWidget())
|
||||
.child(new SyncStatusWidget())
|
||||
|
|
52
src/public/app/widgets/bookmark_buttons.js
Normal file
52
src/public/app/widgets/bookmark_buttons.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
import FlexContainer from "./containers/flex_container.js";
|
||||
import searchService from "../services/search.js";
|
||||
import OpenNoteButtonWidget from "./buttons/open_note_button_widget.js";
|
||||
|
||||
export default class BookmarkButtons extends FlexContainer {
|
||||
constructor() {
|
||||
super("column");
|
||||
|
||||
this.contentSized();
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
const bookmarkedNotes = await searchService.searchForNotes("#bookmarked");
|
||||
|
||||
this.$widget.empty();
|
||||
this.children = [];
|
||||
this.noteIds = [];
|
||||
|
||||
for (const note of bookmarkedNotes) {
|
||||
this.noteIds.push(note.noteId);
|
||||
|
||||
const buttonWidget = new OpenNoteButtonWidget().targetNote(note.noteId);
|
||||
|
||||
this.child(buttonWidget);
|
||||
|
||||
this.$widget.append(buttonWidget.render());
|
||||
|
||||
buttonWidget.refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
initialRenderCompleteEvent() {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.getAttributes().find(attr => attr.type === 'label' && attr.name === 'bookmarked')) {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
if (loadResults.getNoteIds().find(noteId => this.noteIds.includes(noteId))) {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
if (loadResults.getAttributes().find(attr => attr.type === 'label'
|
||||
&& ['iconClass', 'workspaceIconClass'].includes(attr.name)
|
||||
&& this.noteIds.includes(attr.noteId))
|
||||
) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
107
src/public/app/widgets/bookmark_switch.js
Normal file
107
src/public/app/widgets/bookmark_switch.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||
import protectedSessionService from "../services/protected_session.js";
|
||||
import attributeService from "../services/attributes.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="bookmark-switch">
|
||||
<style>
|
||||
/* The switch - the box around the slider */
|
||||
.bookmark-switch .switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.bookmark-switch .slider {
|
||||
border-radius: 24px;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--more-accented-background-color);
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.bookmark-switch .slider:before {
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: var(--main-background-color);
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.bookmark-switch .slider.checked {
|
||||
background-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
.bookmark-switch .slider.checked:before {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="add-bookmark-button">
|
||||
Bookmark
|
||||
|
||||
|
||||
|
||||
<span title="Bookmark this note to the left side panel">
|
||||
<label class="switch">
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="remove-bookmark-button">
|
||||
Bookmark
|
||||
|
||||
|
||||
|
||||
<span title="Remove bookmark">
|
||||
<label class="switch">
|
||||
<span class="slider checked"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class BookmarkSwitchWidget extends NoteContextAwareWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
|
||||
this.$addBookmarkButton = this.$widget.find(".add-bookmark-button");
|
||||
this.$addBookmarkButton.on('click', () => attributeService.setLabel(this.noteId, 'bookmarked'));
|
||||
|
||||
this.$removeBookmarkButton = this.$widget.find(".remove-bookmark-button");
|
||||
this.$removeBookmarkButton.on('click', async () => {
|
||||
for (const label of this.note.getLabels('bookmarked')) {
|
||||
await attributeService.removeAttributeById(this.noteId, label.attributeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshWithNote(note) {
|
||||
const isBookmarked = note.hasLabel('bookmarked');
|
||||
|
||||
this.$addBookmarkButton.toggle(!isBookmarked);
|
||||
this.$removeBookmarkButton.toggle(isBookmarked);
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
for (const attr of loadResults.getAttributes()) {
|
||||
if (attr.type === 'label'
|
||||
&& attr.name === 'bookmarked'
|
||||
&& attributeService.isAffecting(attr, this.note)) {
|
||||
|
||||
this.refresh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,22 @@
|
|||
import ButtonWidget from "./button_widget.js";
|
||||
import appContext from "../../services/app_context.js";
|
||||
|
||||
// TODO: here we could read icon and title of the target note and use it for tooltip and displayed icon
|
||||
import froca from "../../services/froca.js";
|
||||
|
||||
export default class OpenNoteButtonWidget extends ButtonWidget {
|
||||
targetNote(noteId) {
|
||||
froca.getNote(noteId).then(note => {
|
||||
this.icon(note.getIcon());
|
||||
this.title(note.title);
|
||||
|
||||
this.refreshIcon();
|
||||
});
|
||||
|
||||
this.onClick(() => appContext.tabManager.openTabWithNoteWithHoisting(noteId, true));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
initialRenderCompleteEvent() {
|
||||
// we trigger refresh above
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ const TPL = `
|
|||
<div class="protected-note-switch">
|
||||
<style>
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
.protected-note-switch .switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
|
@ -14,7 +14,7 @@ const TPL = `
|
|||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
.protected-note-switch .slider {
|
||||
border-radius: 24px;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
@ -26,7 +26,7 @@ const TPL = `
|
|||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
.protected-note-switch .slider:before {
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
content: "";
|
||||
|
@ -39,11 +39,11 @@ const TPL = `
|
|||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider.checked {
|
||||
.protected-note-switch .slider.checked {
|
||||
background-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
.slider.checked:before {
|
||||
.protected-note-switch .slider.checked:before {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,6 +2,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
|||
import NoteTypeWidget from "../note_type.js";
|
||||
import ProtectedNoteSwitchWidget from "../protected_note_switch.js";
|
||||
import EditabilitySelectWidget from "../editability_select.js";
|
||||
import BookmarkSwitchWidget from "../bookmark_switch.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="basic-properties-widget">
|
||||
|
@ -33,6 +34,8 @@ const TPL = `
|
|||
<div class="editability-select-container">
|
||||
<span>Editable:</span>
|
||||
</div>
|
||||
|
||||
<div class="bookmark-switch-container"></div>
|
||||
</div>`;
|
||||
|
||||
export default class BasicPropertiesWidget extends NoteContextAwareWidget {
|
||||
|
@ -42,8 +45,14 @@ export default class BasicPropertiesWidget extends NoteContextAwareWidget {
|
|||
this.noteTypeWidget = new NoteTypeWidget().contentSized();
|
||||
this.protectedNoteSwitchWidget = new ProtectedNoteSwitchWidget().contentSized();
|
||||
this.editabilitySelectWidget = new EditabilitySelectWidget().contentSized();
|
||||
this.bookmarkSwitchWidget = new BookmarkSwitchWidget().contentSized();
|
||||
|
||||
this.child(this.noteTypeWidget, this.protectedNoteSwitchWidget, this.editabilitySelectWidget);
|
||||
this.child(
|
||||
this.noteTypeWidget,
|
||||
this.protectedNoteSwitchWidget,
|
||||
this.editabilitySelectWidget,
|
||||
this.bookmarkSwitchWidget
|
||||
);
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
@ -55,7 +64,7 @@ export default class BasicPropertiesWidget extends NoteContextAwareWidget {
|
|||
}
|
||||
|
||||
isEnabled() {
|
||||
return this.note && (this.note.type === 'text' || this.note.type === 'code' || this.note.type == 'mermaid');
|
||||
return this.note && (this.note.type === 'text' || this.note.type === 'code' || this.note.type === 'mermaid');
|
||||
}
|
||||
|
||||
getTitle() {
|
||||
|
@ -73,5 +82,6 @@ export default class BasicPropertiesWidget extends NoteContextAwareWidget {
|
|||
this.$widget.find(".note-type-container").append(this.noteTypeWidget.render());
|
||||
this.$widget.find(".protected-note-switch-container").append(this.protectedNoteSwitchWidget.render());
|
||||
this.$widget.find(".editability-select-container").append(this.editabilitySelectWidget.render());
|
||||
this.$widget.find(".bookmark-switch-container").append(this.bookmarkSwitchWidget.render());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue