mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 08:29:00 +01:00
client: make the info bar part of the scrollable content, prevent overlapping with the floating buttons
This commit is contained in:
parent
d8d80ed936
commit
285a7253e3
@ -499,6 +499,10 @@ type EventMappings = {
|
|||||||
noteIds: string[];
|
noteIds: string[];
|
||||||
};
|
};
|
||||||
refreshData: { ntxId: string | null | undefined };
|
refreshData: { ntxId: string | null | undefined };
|
||||||
|
contentSafeMarginChanged: {
|
||||||
|
top: number;
|
||||||
|
noteContext: NoteContext;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EventListener<T extends EventNames> = {
|
export type EventListener<T extends EventNames> = {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.
|
|||||||
import ApiLog from "../widgets/api_log.jsx";
|
import ApiLog from "../widgets/api_log.jsx";
|
||||||
import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
|
import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
|
||||||
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
|
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
|
||||||
|
import ContentHeader from "../widgets/content-header.js";
|
||||||
import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
|
import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
|
||||||
import FindWidget from "../widgets/find.js";
|
import FindWidget from "../widgets/find.js";
|
||||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||||
@ -131,13 +132,14 @@ export default class DesktopLayout {
|
|||||||
)
|
)
|
||||||
.child(<Ribbon />)
|
.child(<Ribbon />)
|
||||||
.child(<SharedInfo />)
|
.child(<SharedInfo />)
|
||||||
.child(<ReadOnlyNoteInfoBar />)
|
|
||||||
.child(new WatchedFileUpdateStatusWidget())
|
.child(new WatchedFileUpdateStatusWidget())
|
||||||
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
|
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
|
||||||
.child(
|
.child(
|
||||||
new ScrollingContainer()
|
new ScrollingContainer()
|
||||||
.filling()
|
.filling()
|
||||||
.child(<ReadOnlyNoteInfoBar zenModeOnly />)
|
.child(new ContentHeader()
|
||||||
|
.child(<ReadOnlyNoteInfoBar />)
|
||||||
|
)
|
||||||
.child(new PromotedAttributesWidget())
|
.child(new PromotedAttributesWidget())
|
||||||
.child(<SqlTableSchemas />)
|
.child(<SqlTableSchemas />)
|
||||||
.child(new NoteDetailWidget())
|
.child(new NoteDetailWidget())
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibb
|
|||||||
import TabRowWidget from "../widgets/tab_row.js";
|
import TabRowWidget from "../widgets/tab_row.js";
|
||||||
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
||||||
import type AppContext from "../components/app_context.js";
|
import type AppContext from "../components/app_context.js";
|
||||||
|
import ContentHeader from "../widgets/content-header.js";
|
||||||
|
|
||||||
const MOBILE_CSS = `
|
const MOBILE_CSS = `
|
||||||
<style>
|
<style>
|
||||||
@ -151,14 +152,15 @@ export default class MobileLayout {
|
|||||||
.child(<MobileDetailMenu />)
|
.child(<MobileDetailMenu />)
|
||||||
)
|
)
|
||||||
.child(<SharedInfoWidget />)
|
.child(<SharedInfoWidget />)
|
||||||
.child(<ReadOnlyNoteInfoBar />)
|
|
||||||
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
||||||
.child(<ReadOnlyNoteInfoBar zenModeOnly />)
|
|
||||||
.child(new PromotedAttributesWidget())
|
.child(new PromotedAttributesWidget())
|
||||||
.child(
|
.child(
|
||||||
new ScrollingContainer()
|
new ScrollingContainer()
|
||||||
.filling()
|
.filling()
|
||||||
.contentSized()
|
.contentSized()
|
||||||
|
.child(new ContentHeader()
|
||||||
|
.child(<ReadOnlyNoteInfoBar />)
|
||||||
|
)
|
||||||
.child(new NoteDetailWidget())
|
.child(new NoteDetailWidget())
|
||||||
.child(<NoteList media="screen" />)
|
.child(<NoteList media="screen" />)
|
||||||
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
|
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import "./FloatingButtons.css";
|
import "./FloatingButtons.css";
|
||||||
import { useNoteContext, useNoteLabel, useNoteLabelBoolean } from "./react/hooks";
|
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "./react/hooks";
|
||||||
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
|
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
|
||||||
import { ParentComponent } from "./react/react_utils";
|
import { ParentComponent } from "./react/react_utils";
|
||||||
import { EventData, EventNames } from "../components/app_context";
|
import { EventData, EventNames } from "../components/app_context";
|
||||||
@ -20,6 +20,7 @@ interface FloatingButtonsProps {
|
|||||||
* properly handle rounded corners, as defined by the --border-radius CSS variable.
|
* properly handle rounded corners, as defined by the --border-radius CSS variable.
|
||||||
*/
|
*/
|
||||||
export default function FloatingButtons({ items }: FloatingButtonsProps) {
|
export default function FloatingButtons({ items }: FloatingButtonsProps) {
|
||||||
|
const [ top, setTop ] = useState(0);
|
||||||
const { note, noteContext } = useNoteContext();
|
const { note, noteContext } = useNoteContext();
|
||||||
const parentComponent = useContext(ParentComponent);
|
const parentComponent = useContext(ParentComponent);
|
||||||
const [ viewType ] = useNoteLabel(note, "viewType");
|
const [ viewType ] = useNoteLabel(note, "viewType");
|
||||||
@ -47,8 +48,14 @@ export default function FloatingButtons({ items }: FloatingButtonsProps) {
|
|||||||
const [ visible, setVisible ] = useState(true);
|
const [ visible, setVisible ] = useState(true);
|
||||||
useEffect(() => setVisible(true), [ note ]);
|
useEffect(() => setVisible(true), [ note ]);
|
||||||
|
|
||||||
|
useTriliumEvent("contentSafeMarginChanged", (e) => {
|
||||||
|
if (e.noteContext === noteContext) {
|
||||||
|
setTop(e.top);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="floating-buttons no-print">
|
<div className="floating-buttons no-print" style={{top}}>
|
||||||
<div className={`floating-buttons-children ${!visible ? "temporarily-hidden" : ""}`}>
|
<div className={`floating-buttons-children ${!visible ? "temporarily-hidden" : ""}`}>
|
||||||
{context && items.map((Component) => (
|
{context && items.map((Component) => (
|
||||||
<Component {...context} />
|
<Component {...context} />
|
||||||
|
|||||||
63
apps/client/src/widgets/content-header.ts
Normal file
63
apps/client/src/widgets/content-header.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { EventData } from "../components/app_context";
|
||||||
|
import BasicWidget from "./basic_widget";
|
||||||
|
import Container from "./containers/container";
|
||||||
|
import NoteContext from "../components/note_context";
|
||||||
|
|
||||||
|
export default class ContentHeader extends Container<BasicWidget> {
|
||||||
|
|
||||||
|
noteContext?: NoteContext;
|
||||||
|
thisElement?: HTMLElement;
|
||||||
|
parentElement?: HTMLElement;
|
||||||
|
resizeObserver: ResizeObserver;
|
||||||
|
currentHeight: number = 0;
|
||||||
|
currentSafeMargin: number = NaN;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.css("contain", "unset");
|
||||||
|
this.resizeObserver = new ResizeObserver(this.onResize.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
setNoteContextEvent({ noteContext }: EventData<"setNoteContext">) {
|
||||||
|
this.noteContext = noteContext;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.parentElement = this.parent!.$widget.get(0);
|
||||||
|
|
||||||
|
if (!this.parentElement) {
|
||||||
|
console.warn("No parent set for <ContentHeader>.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.thisElement = this.$widget.get(0)!;
|
||||||
|
|
||||||
|
this.resizeObserver.observe(this.thisElement);
|
||||||
|
this.parentElement.addEventListener("scroll", this.updateSafeMargin.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSafeMargin() {
|
||||||
|
const newSafeMargin = Math.max(this.currentHeight - this.parentElement!.scrollTop, 0);
|
||||||
|
|
||||||
|
if (newSafeMargin !== this.currentSafeMargin) {
|
||||||
|
this.currentSafeMargin = newSafeMargin;
|
||||||
|
|
||||||
|
this.triggerEvent("contentSafeMarginChanged", {
|
||||||
|
top: newSafeMargin,
|
||||||
|
noteContext: this.noteContext!
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize(entries: ResizeObserverEntry[]) {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.target === this.thisElement) {
|
||||||
|
this.currentHeight = entry.contentRect.height;
|
||||||
|
this.updateSafeMargin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user