1
0
silverbullet/web/components/top_bar.tsx

145 lines
4.2 KiB
TypeScript
Raw Normal View History

import {
CompletionContext,
CompletionResult,
useEffect,
useRef,
} from "../deps.ts";
import type { ComponentChildren, FunctionalComponent } from "../deps.ts";
import { Notification } from "../types.ts";
import { FeatherProps } from "https://esm.sh/v99/preact-feather@4.2.1/dist/types";
import { MiniEditor } from "./mini_editor.tsx";
export type ActionButton = {
icon: FunctionalComponent<FeatherProps>;
description: string;
callback: () => void;
href?: string;
};
export function TopBar({
pageName,
unsavedChanges,
synced,
isLoading,
notifications,
onRename,
actionButtons,
darkMode,
vimMode,
completer,
2022-04-04 16:33:13 +00:00
lhs,
rhs,
}: {
pageName?: string;
unsavedChanges: boolean;
synced: boolean;
isLoading: boolean;
notifications: Notification[];
darkMode: boolean;
vimMode: boolean;
onRename: (newName?: string) => Promise<void>;
completer: (context: CompletionContext) => Promise<CompletionResult | null>;
actionButtons: ActionButton[];
lhs?: ComponentChildren;
rhs?: ComponentChildren;
}) {
const inputRef = useRef<HTMLInputElement>(null);
2022-09-24 17:01:16 +00:00
// Another one of my less proud moments:
// Somehow I cannot seem to proerply limit the width of the page name, so I'm doing
// it this way. If you have a better way to do this, please let me know!
useEffect(() => {
function resizeHandler() {
const editorWidth = parseInt(
getComputedStyle(document.getElementById("sb-root")!).getPropertyValue(
"--editor-width",
),
);
const currentPageElement = document.getElementById("sb-current-page");
if (currentPageElement) {
// Temporarily make it very narrow to give the parent space
currentPageElement.style.width = "10px";
const innerDiv = currentPageElement.parentElement!.parentElement!;
// Then calculate a new width
currentPageElement.style.width = `${
Math.min(editorWidth - 150, innerDiv.clientWidth - 150)
}px`;
}
}
globalThis.addEventListener("resize", resizeHandler);
// Stop listening on unmount
return () => {
globalThis.removeEventListener("resize", resizeHandler);
};
}, []);
return (
<div id="sb-top" className={synced ? undefined : "sb-sync-error"}>
2022-04-04 16:33:13 +00:00
{lhs}
<div className="main">
<div className="inner">
2022-12-16 10:39:46 +00:00
<div className="wrapper">
<span
id="sb-current-page"
className={isLoading
? "sb-loading"
: unsavedChanges
? "sb-unsaved"
: "sb-saved"}
2022-12-16 10:39:46 +00:00
>
<MiniEditor
text={pageName ?? ""}
vimMode={vimMode}
darkMode={darkMode}
onBlur={(newName) => {
if (newName !== pageName) {
return onRename(newName);
} else {
return onRename();
2022-12-16 10:39:46 +00:00
}
}}
completer={completer}
onEnter={(newName) => {
onRename(newName);
2022-12-16 10:39:46 +00:00
}}
/>
</span>
{notifications.length > 0 && (
<div className="sb-notifications">
{notifications.map((notification) => (
<div
key={notification.id}
className={`sb-notification-${notification.type}`}
>
{notification.message}
</div>
))}
</div>
)}
<div className="sb-actions">
{actionButtons.map((actionButton) => {
const button =
<button
onClick={(e) => {
e.preventDefault();
actionButton.callback();
e.stopPropagation();
}}
title={actionButton.description}
>
<actionButton.icon size={18} />
</button>
return actionButton.href !== undefined ? (<a href={actionButton.href}>{button}</a>) : button;
})}
2022-04-04 16:33:13 +00:00
</div>
2022-05-06 16:55:04 +00:00
</div>
2022-04-04 16:33:13 +00:00
</div>
</div>
2022-04-04 16:33:13 +00:00
{rhs}
</div>
);
}