1
0
silverbullet/web/components/top_bar.tsx

167 lines
4.9 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;
2023-08-29 19:17:29 +00:00
class?: string;
callback: () => void;
href?: string;
};
export function TopBar({
pageName,
unsavedChanges,
2023-08-16 09:40:31 +00:00
syncFailures,
isLoading,
notifications,
onRename,
actionButtons,
darkMode,
vimMode,
2023-06-14 18:58:08 +00:00
progressPerc,
completer,
2022-04-04 16:33:13 +00:00
lhs,
onClick,
2022-04-04 16:33:13 +00:00
rhs,
}: {
pageName?: string;
unsavedChanges: boolean;
2023-08-16 09:40:31 +00:00
syncFailures: number;
isLoading: boolean;
notifications: Notification[];
darkMode: boolean;
vimMode: boolean;
2023-06-14 18:58:08 +00:00
progressPerc?: number;
onRename: (newName?: string) => Promise<void>;
onClick: () => void;
completer: (context: CompletionContext) => Promise<CompletionResult | null>;
actionButtons: ActionButton[];
lhs?: ComponentChildren;
rhs?: ComponentChildren;
}) {
// 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 = `${
2023-08-30 15:25:54 +00:00
Math.min(editorWidth - 170, innerDiv.clientWidth - 170)
}px`;
}
}
globalThis.addEventListener("resize", resizeHandler);
// Stop listening on unmount
return () => {
globalThis.removeEventListener("resize", resizeHandler);
};
}, []);
return (
<div
id="sb-top"
className={syncFailures > 1 ? "sb-sync-error" : undefined}
onClick={onClick}
>
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">
2023-06-14 18:58:08 +00:00
{progressPerc !== undefined &&
(
<div className="progress-wrapper" title={`${progressPerc}%`}>
<div
className="progress-bar"
style={`background: radial-gradient(closest-side, white 79%, transparent 80% 100%), conic-gradient(#282828 ${progressPerc}%, #adadad 0);`}
>
2023-06-14 18:58:08 +00:00
{progressPerc}%
</div>
</div>
)}
{actionButtons.map((actionButton) => {
const button = (
<button
onClick={(e) => {
e.preventDefault();
actionButton.callback();
e.stopPropagation();
}}
title={actionButton.description}
2023-08-29 19:17:29 +00:00
className={actionButton.class}
2023-06-14 18:58:08 +00:00
>
<actionButton.icon size={18} />
</button>
);
2023-06-14 18:58:08 +00:00
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>
);
}