mirror of
https://github.com/zadam/trilium.git
synced 2025-12-04 22:44:25 +01:00
Merge 5b310f3e46e18071bef89ae7cf5cba17c7cd6ae8 into b8585594cd138783588a7ac4d6a3260de779427d
This commit is contained in:
commit
341b85a8cb
@ -30,7 +30,6 @@ import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||
import ScrollPadding from "../widgets/scroll_padding.js";
|
||||
import SearchResult from "../widgets/search_result.jsx";
|
||||
import SharedInfo from "../widgets/shared_info.jsx";
|
||||
import SpacerWidget from "../widgets/spacer.js";
|
||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||
import SqlResults from "../widgets/sql_result.js";
|
||||
import SqlTableSchemas from "../widgets/sql_table_schemas.js";
|
||||
@ -43,8 +42,8 @@ import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
|
||||
import utils from "../services/utils.js";
|
||||
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
|
||||
import NoteDetail from "../widgets/NoteDetail.jsx";
|
||||
import RightPanelWidget from "../widgets/sidebar/RightPanelWidget.jsx";
|
||||
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
|
||||
import SpacerWidget from "../widgets/launch_bar/SpacerWidget.jsx";
|
||||
|
||||
export default class DesktopLayout {
|
||||
|
||||
@ -125,7 +124,7 @@ export default class DesktopLayout {
|
||||
.cssBlock(".title-row > * { margin: 5px; }")
|
||||
.child(<NoteIconWidget />)
|
||||
.child(<NoteTitleWidget />)
|
||||
.child(new SpacerWidget(0, 1))
|
||||
.child(<SpacerWidget baseSize={0} growthFactor={1} />)
|
||||
.child(<MovePaneButton direction="left" />)
|
||||
.child(<MovePaneButton direction="right" />)
|
||||
.child(<ClosePaneButton />)
|
||||
|
||||
@ -150,7 +150,7 @@ export function isMac() {
|
||||
|
||||
export const hasTouchBar = (isMac() && isElectron());
|
||||
|
||||
function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent<HTMLCanvasElement> | JQueryEventObject) {
|
||||
export function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent<HTMLCanvasElement> | JQueryEventObject) {
|
||||
return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import FlexContainer from "./containers/flex_container.js";
|
||||
import OpenNoteButtonWidget from "./buttons/open_note_button_widget.js";
|
||||
import BookmarkFolderWidget from "./buttons/bookmark_folder.js";
|
||||
import froca from "../services/froca.js";
|
||||
import utils from "../services/utils.js";
|
||||
@ -23,10 +22,6 @@ export default class BookmarkButtons extends FlexContainer<Component> {
|
||||
}
|
||||
|
||||
async refresh(): Promise<void> {
|
||||
this.$widget.empty();
|
||||
this.children = [];
|
||||
this.noteIds = [];
|
||||
|
||||
const bookmarkParentNote = await froca.getNote("_lbBookmarks");
|
||||
|
||||
if (!bookmarkParentNote) {
|
||||
@ -37,16 +32,7 @@ export default class BookmarkButtons extends FlexContainer<Component> {
|
||||
this.noteIds.push(note.noteId);
|
||||
|
||||
let buttonWidget: OpenNoteButtonWidget | BookmarkFolderWidget = note.isLabelTruthy("bookmarkFolder")
|
||||
? new BookmarkFolderWidget(note)
|
||||
: new OpenNoteButtonWidget(note).class("launcher-button");
|
||||
|
||||
if (this.settings.titlePlacement) {
|
||||
if (!("settings" in buttonWidget)) {
|
||||
(buttonWidget as any).settings = {};
|
||||
}
|
||||
|
||||
(buttonWidget as any).settings.titlePlacement = this.settings.titlePlacement;
|
||||
}
|
||||
? new BookmarkFolderWidget(note);
|
||||
|
||||
this.child(buttonWidget);
|
||||
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
import RightDropdownButtonWidget from "./right_dropdown_button.js";
|
||||
import linkService from "../../services/link.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
|
||||
const DROPDOWN_TPL = `
|
||||
<div class="bookmark-folder-widget">
|
||||
<style>
|
||||
.bookmark-folder-widget {
|
||||
min-width: 400px;
|
||||
max-height: 500px;
|
||||
padding: 7px 15px 0 15px;
|
||||
font-size: 1.2rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget ul {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget .note-link {
|
||||
display: block;
|
||||
padding: 5px 10px 5px 5px;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget .note-link:hover {
|
||||
background-color: var(--accented-background-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown-menu .bookmark-folder-widget a:hover {
|
||||
text-decoration: none;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget li .note-link {
|
||||
padding-inline-start: 35px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="parent-note"></div>
|
||||
|
||||
<ul class="children-notes"></ul>
|
||||
</div>`;
|
||||
|
||||
interface LinkOptions {
|
||||
showTooltip: boolean;
|
||||
showNoteIcon: boolean;
|
||||
}
|
||||
|
||||
export default class BookmarkFolderWidget extends RightDropdownButtonWidget {
|
||||
private note: FNote;
|
||||
private $parentNote!: JQuery<HTMLElement>;
|
||||
private $childrenNotes!: JQuery<HTMLElement>;
|
||||
declare $dropdownContent: JQuery<HTMLElement>;
|
||||
|
||||
constructor(note: FNote) {
|
||||
super(utils.escapeHtml(note.title), note.getIcon(), DROPDOWN_TPL);
|
||||
|
||||
this.note = note;
|
||||
}
|
||||
|
||||
doRender(): void {
|
||||
super.doRender();
|
||||
|
||||
this.$parentNote = this.$dropdownContent.find(".parent-note");
|
||||
this.$childrenNotes = this.$dropdownContent.find(".children-notes");
|
||||
}
|
||||
|
||||
async dropdownShown(): Promise<void> {
|
||||
this.$parentNote.empty();
|
||||
this.$childrenNotes.empty();
|
||||
|
||||
const linkOptions: LinkOptions = {
|
||||
showTooltip: false,
|
||||
showNoteIcon: true
|
||||
};
|
||||
|
||||
this.$parentNote.append((await linkService.createLink(this.note.noteId, linkOptions)).addClass("note-link"));
|
||||
|
||||
for (const childNote of await this.note.getChildNotes()) {
|
||||
this.$childrenNotes.append($("<li>").append((await linkService.createLink(childNote.noteId, linkOptions)).addClass("note-link")));
|
||||
}
|
||||
}
|
||||
|
||||
refreshIcon(): void {}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
import OnClickButtonWidget from "./onclick_button.js";
|
||||
import linkContextMenuService from "../../menus/link_context_menu.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
|
||||
export default class OpenNoteButtonWidget extends OnClickButtonWidget {
|
||||
|
||||
private noteToOpen: FNote;
|
||||
|
||||
constructor(noteToOpen: FNote) {
|
||||
super();
|
||||
|
||||
this.noteToOpen = noteToOpen;
|
||||
|
||||
this.title(() => utils.escapeHtml(this.noteToOpen.title))
|
||||
.icon(() => this.noteToOpen.getIcon())
|
||||
.onClick((widget, evt) => this.launch(evt))
|
||||
.onAuxClick((widget, evt) => this.launch(evt))
|
||||
.onContextMenu((evt) => {
|
||||
if (evt) {
|
||||
linkContextMenuService.openContextMenu(this.noteToOpen.noteId, evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async launch(evt: JQuery.ClickEvent | JQuery.TriggeredEvent | JQuery.ContextMenuEvent) {
|
||||
if (evt.which === 3) {
|
||||
return;
|
||||
}
|
||||
const hoistedNoteId = this.getHoistedNoteId();
|
||||
const ctrlKey = utils.isCtrlKey(evt);
|
||||
|
||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
||||
const activate = evt.shiftKey ? true : false;
|
||||
await appContext.tabManager.openInNewTab(this.noteToOpen.noteId, hoistedNoteId, activate);
|
||||
} else {
|
||||
await appContext.tabManager.openInSameTab(this.noteToOpen.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
getHoistedNoteId() {
|
||||
return this.noteToOpen.getRelationValue("hoistedNote") || appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||
}
|
||||
|
||||
initialRenderCompleteEvent() {
|
||||
// we trigger refresh above
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
import CalendarWidget from "../buttons/calendar.js";
|
||||
import SpacerWidget from "../spacer.js";
|
||||
import BookmarkButtons from "../bookmark_buttons.js";
|
||||
import ProtectedSessionStatusWidget from "../buttons/protected_session_status.js";
|
||||
import SyncStatusWidget from "../sync_status.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import BasicWidget, { wrapReactWidgets } from "../basic_widget.js";
|
||||
import NoteLauncher from "../buttons/launcher/note_launcher.js";
|
||||
import ScriptLauncher from "../buttons/launcher/script_launcher.js";
|
||||
import CommandButtonWidget from "../buttons/command_button.js";
|
||||
@ -14,6 +12,8 @@ import QuickSearchLauncherWidget from "../quick_search_launcher.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { CommandNames } from "../../components/app_context.js";
|
||||
import AiChatButton from "../buttons/ai_chat_button.js";
|
||||
import BookmarkButtons from "../launch_bar/BookmarkButtons.jsx";
|
||||
import SpacerWidget from "../launch_bar/SpacerWidget.jsx";
|
||||
|
||||
interface InnerWidget extends BasicWidget {
|
||||
settings?: {
|
||||
@ -64,7 +64,7 @@ export default class LauncherWidget extends BasicWidget {
|
||||
} else if (launcherType === "customWidget") {
|
||||
widget = await this.initCustomWidget(note);
|
||||
} else if (launcherType === "builtinWidget") {
|
||||
widget = this.initBuiltinWidget(note);
|
||||
widget = wrapReactWidgets<BasicWidget>([ this.initBuiltinWidget(note) ])[0];
|
||||
} else {
|
||||
throw new Error(`Unrecognized launcher type '${launcherType}' for launcher '${note.noteId}' title '${note.title}'`);
|
||||
}
|
||||
@ -109,9 +109,9 @@ export default class LauncherWidget extends BasicWidget {
|
||||
const baseSize = parseInt(note.getLabelValue("baseSize") || "40");
|
||||
const growthFactor = parseInt(note.getLabelValue("growthFactor") || "100");
|
||||
|
||||
return new SpacerWidget(baseSize, growthFactor);
|
||||
return <SpacerWidget baseSize={baseSize} growthFactor={growthFactor} />;
|
||||
case "bookmarks":
|
||||
return new BookmarkButtons(this.isHorizontalLayout);
|
||||
return <BookmarkButtons isHorizontalLayout={this.isHorizontalLayout} />
|
||||
case "protectedSession":
|
||||
return new ProtectedSessionStatusWidget();
|
||||
case "syncStatus":
|
||||
31
apps/client/src/widgets/launch_bar/BookmarkButtons.css
Normal file
31
apps/client/src/widgets/launch_bar/BookmarkButtons.css
Normal file
@ -0,0 +1,31 @@
|
||||
.bookmark-folder-widget {
|
||||
min-width: 400px;
|
||||
max-height: 500px;
|
||||
padding: 7px 15px 0 15px;
|
||||
font-size: 1.2rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget ul {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget .note-link {
|
||||
display: block;
|
||||
padding: 5px 10px 5px 5px;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget .note-link:hover {
|
||||
background-color: var(--accented-background-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown-menu .bookmark-folder-widget a:hover:not(.disabled) {
|
||||
text-decoration: none;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.bookmark-folder-widget li .note-link {
|
||||
padding-inline-start: 35px;
|
||||
}
|
||||
98
apps/client/src/widgets/launch_bar/BookmarkButtons.tsx
Normal file
98
apps/client/src/widgets/launch_bar/BookmarkButtons.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
import { useMemo } from "preact/hooks";
|
||||
import { LaunchBarActionButton, LaunchBarDropdownButton, type LaunchBarWidgetProps } from "./launch_bar_widgets";
|
||||
import { CSSProperties } from "preact";
|
||||
import type FNote from "../../entities/fnote";
|
||||
import { useChildNotes, useNoteLabel, useNoteLabelBoolean, useNoteProperty } from "../react/hooks";
|
||||
import appContext from "../../components/app_context";
|
||||
import { escapeHtml, isCtrlKey } from "../../services/utils";
|
||||
import link_context_menu from "../../menus/link_context_menu";
|
||||
import "./BookmarkButtons.css";
|
||||
import NoteLink from "../react/NoteLink";
|
||||
|
||||
const PARENT_NOTE_ID = "_lbBookmarks";
|
||||
|
||||
export default function BookmarkButtons({ isHorizontalLayout }: LaunchBarWidgetProps) {
|
||||
const style = useMemo<CSSProperties>(() => ({
|
||||
display: "flex",
|
||||
flexDirection: isHorizontalLayout ? "row" : "column",
|
||||
contain: "none"
|
||||
}), [ isHorizontalLayout ]);
|
||||
const childNotes = useChildNotes(PARENT_NOTE_ID);
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
{childNotes?.map(childNote => <SingleBookmark note={childNote} />)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SingleBookmark({ note }: { note: FNote }) {
|
||||
const [ bookmarkFolder ] = useNoteLabelBoolean(note, "bookmarkFolder");
|
||||
return bookmarkFolder
|
||||
? <BookmarkFolder note={note} />
|
||||
: <OpenNoteButtonWidget note={note} />
|
||||
}
|
||||
|
||||
function OpenNoteButtonWidget({ note }: { note: FNote }) {
|
||||
const [ iconClass ] = useNoteLabel(note, "iconClass");
|
||||
const title = useNoteProperty(note, "title");
|
||||
|
||||
async function launch(evt: MouseEvent) {
|
||||
if (evt.which === 3) {
|
||||
return;
|
||||
}
|
||||
const hoistedNoteId = getHoistedNoteId(note);
|
||||
const ctrlKey = isCtrlKey(evt);
|
||||
|
||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
||||
const activate = evt.shiftKey ? true : false;
|
||||
await appContext.tabManager.openInNewTab(note.noteId, hoistedNoteId, activate);
|
||||
} else {
|
||||
await appContext.tabManager.openInSameTab(note.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
return title && iconClass && (
|
||||
<LaunchBarActionButton
|
||||
icon={iconClass}
|
||||
text={escapeHtml(title)}
|
||||
onClick={launch}
|
||||
onAuxClick={launch}
|
||||
onContextMenu={evt => {
|
||||
evt.preventDefault();
|
||||
link_context_menu.openContextMenu(note.noteId, evt);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function BookmarkFolder({ note }: { note: FNote }) {
|
||||
const [ iconClass ] = useNoteLabel(note, "iconClass");
|
||||
const title = useNoteProperty(note, "title");
|
||||
const childNotes = useChildNotes(note.noteId);
|
||||
|
||||
return title && iconClass && (
|
||||
<LaunchBarDropdownButton
|
||||
icon={iconClass}
|
||||
title={escapeHtml(title)}
|
||||
>
|
||||
<div className="bookmark-folder-widget">
|
||||
<div className="parent-note">
|
||||
<NoteLink notePath={note.noteId} noPreview showNoteIcon containerClassName="note-link" noTnLink />
|
||||
</div>
|
||||
|
||||
<ul className="children-notes">
|
||||
{childNotes.map(childNote => (
|
||||
<li>
|
||||
<NoteLink notePath={childNote.noteId} noPreview showNoteIcon containerClassName="note-link" noTnLink />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</LaunchBarDropdownButton>
|
||||
)
|
||||
}
|
||||
|
||||
function getHoistedNoteId(noteToOpen: FNote) {
|
||||
return noteToOpen.getRelationValue("hoistedNote") || appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
export default function RightDropdownButton() {
|
||||
return <p>Button goes here.</p>;
|
||||
}
|
||||
35
apps/client/src/widgets/launch_bar/SpacerWidget.tsx
Normal file
35
apps/client/src/widgets/launch_bar/SpacerWidget.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import appContext, { CommandNames } from "../../components/app_context";
|
||||
import contextMenu from "../../menus/context_menu";
|
||||
import { t } from "../../services/i18n";
|
||||
import { isMobile } from "../../services/utils";
|
||||
|
||||
interface SpacerWidgetProps {
|
||||
baseSize?: number;
|
||||
growthFactor?: number;
|
||||
}
|
||||
|
||||
export default function SpacerWidget({ baseSize, growthFactor }: SpacerWidgetProps) {
|
||||
return (
|
||||
<div
|
||||
className="spacer"
|
||||
style={{
|
||||
flexBasis: baseSize ?? 0,
|
||||
flexGrow: growthFactor ?? 1000,
|
||||
flexShrink: 1000
|
||||
}}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
contextMenu.show<CommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [{ title: t("spacer.configure_launchbar"), command: "showLaunchBarSubtree", uiIcon: "bx " + (isMobile() ? "bx-mobile" : "bx-sidebar") }],
|
||||
selectMenuItemHandler: ({ command }) => {
|
||||
if (command) {
|
||||
appContext.triggerCommand(command);
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
30
apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx
Normal file
30
apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import ActionButton, { ActionButtonProps } from "../react/ActionButton";
|
||||
import Dropdown, { DropdownProps } from "../react/Dropdown";
|
||||
import Icon from "../react/Icon";
|
||||
|
||||
export interface LaunchBarWidgetProps {
|
||||
isHorizontalLayout: boolean;
|
||||
}
|
||||
|
||||
export function LaunchBarActionButton(props: Omit<ActionButtonProps, "className" | "noIconActionClass" | "titlePosition">) {
|
||||
return (
|
||||
<ActionButton
|
||||
className="button-widget launcher-button"
|
||||
noIconActionClass
|
||||
titlePosition="right"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function LaunchBarDropdownButton({ children, icon, ...props }: Pick<DropdownProps, "title" | "children"> & { icon: string }) {
|
||||
return (
|
||||
<Dropdown
|
||||
className="right-dropdown-widget"
|
||||
buttonClassName="right-dropdown-button launcher-button"
|
||||
hideToggleArrow
|
||||
text={<Icon icon={icon} />}
|
||||
{...props}
|
||||
>{children}</Dropdown>
|
||||
)
|
||||
}
|
||||
@ -2,13 +2,13 @@ import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import { CommandNames } from "../../components/app_context";
|
||||
import { useStaticTooltip } from "./hooks";
|
||||
import keyboard_actions from "../../services/keyboard_actions";
|
||||
import { HTMLAttributes } from "preact";
|
||||
|
||||
export interface ActionButtonProps {
|
||||
export interface ActionButtonProps extends Pick<HTMLAttributes<HTMLButtonElement>, "onClick" | "onAuxClick" | "onContextMenu"> {
|
||||
text: string;
|
||||
titlePosition?: "top" | "right" | "bottom" | "left";
|
||||
icon: string;
|
||||
className?: string;
|
||||
onClick?: (e: MouseEvent) => void;
|
||||
triggerCommand?: CommandNames;
|
||||
noIconActionClass?: boolean;
|
||||
frame?: boolean;
|
||||
@ -16,7 +16,7 @@ export interface ActionButtonProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function ActionButton({ text, icon, className, onClick, triggerCommand, titlePosition, noIconActionClass, frame, active, disabled }: ActionButtonProps) {
|
||||
export default function ActionButton({ text, icon, className, triggerCommand, titlePosition, noIconActionClass, frame, active, disabled, ...restProps }: ActionButtonProps) {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [ keyboardShortcut, setKeyboardShortcut ] = useState<string[]>();
|
||||
|
||||
@ -35,8 +35,8 @@ export default function ActionButton({ text, icon, className, onClick, triggerCo
|
||||
return <button
|
||||
ref={buttonRef}
|
||||
class={`${className ?? ""} ${!noIconActionClass ? "icon-action" : "btn"} ${icon} ${frame ? "btn btn-primary" : ""} ${disabled ? "disabled" : ""} ${active ? "active" : ""}`}
|
||||
onClick={onClick}
|
||||
data-trigger-command={triggerCommand}
|
||||
disabled={disabled}
|
||||
{...restProps}
|
||||
/>;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { useImperativeSearchHighlighlighting, useTriliumEvent } from "./hooks";
|
||||
|
||||
interface NoteLinkOpts {
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
notePath: string | string[];
|
||||
showNotePath?: boolean;
|
||||
showNoteIcon?: boolean;
|
||||
@ -17,7 +18,7 @@ interface NoteLinkOpts {
|
||||
noContextMenu?: boolean;
|
||||
}
|
||||
|
||||
export default function NoteLink({ className, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens, title, viewScope, noContextMenu }: NoteLinkOpts) {
|
||||
export default function NoteLink({ className, containerClassName, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens, title, viewScope, noContextMenu }: NoteLinkOpts) {
|
||||
const stringifiedNotePath = Array.isArray(notePath) ? notePath.join("/") : notePath;
|
||||
const noteId = stringifiedNotePath.split("/").at(-1);
|
||||
const ref = useRef<HTMLSpanElement>(null);
|
||||
@ -71,6 +72,6 @@ export default function NoteLink({ className, notePath, showNotePath, showNoteIc
|
||||
$linkEl?.addClass(className);
|
||||
}
|
||||
|
||||
return <span ref={ref} />
|
||||
return <span className={containerClassName} ref={ref} />
|
||||
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import toast, { ToastOptions } from "../../services/toast";
|
||||
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
||||
import server from "../../services/server";
|
||||
import { removeIndividualBinding } from "../../services/shortcuts";
|
||||
import froca from "../../services/froca";
|
||||
|
||||
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
@ -836,3 +837,15 @@ async function isNoteReadOnly(note: FNote, noteContext: NoteContext) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function useChildNotes(parentNoteId: string) {
|
||||
const [ childNotes, setChildNotes ] = useState<FNote[]>([]);
|
||||
async function refreshChildNotes() {
|
||||
const parentNote = await froca.getNote(parentNoteId);
|
||||
const childNotes = await parentNote?.getChildNotes();
|
||||
setChildNotes(childNotes ?? []);
|
||||
}
|
||||
useEffect(() => { refreshChildNotes() }, [ parentNoteId ]);
|
||||
|
||||
return childNotes;
|
||||
}
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
import { t } from "../services/i18n.js";
|
||||
import BasicWidget from "./basic_widget.js";
|
||||
import contextMenu from "../menus/context_menu.js";
|
||||
import appContext, { type CommandNames } from "../components/app_context.js";
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const TPL = /*html*/`<div class="spacer"></div>`;
|
||||
|
||||
export default class SpacerWidget extends BasicWidget {
|
||||
private baseSize: number;
|
||||
private growthFactor: number;
|
||||
|
||||
constructor(baseSize = 0, growthFactor = 1000) {
|
||||
super();
|
||||
|
||||
this.baseSize = baseSize;
|
||||
this.growthFactor = growthFactor;
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$widget.css("flex-basis", this.baseSize);
|
||||
this.$widget.css("flex-grow", this.growthFactor);
|
||||
this.$widget.css("flex-shrink", 1000);
|
||||
|
||||
this.$widget.on("contextmenu", (e) => {
|
||||
this.$widget.tooltip("hide");
|
||||
|
||||
contextMenu.show<CommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [{ title: t("spacer.configure_launchbar"), command: "showLaunchBarSubtree", uiIcon: "bx " + (utils.isMobile() ? "bx-mobile" : "bx-sidebar") }],
|
||||
selectMenuItemHandler: ({ command }) => {
|
||||
if (command) {
|
||||
appContext.triggerCommand(command);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false; // blocks default browser right click menu
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,9 @@ type Labels = {
|
||||
orderBy: string;
|
||||
orderDirection: string;
|
||||
|
||||
// Launch bar
|
||||
bookmarkFolder: boolean;
|
||||
|
||||
// Collection-specific
|
||||
viewType: string;
|
||||
status: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user