Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 14 additions & 49 deletions apps/roam/src/components/BirdEatsBugs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import getCurrentUserEmail from "roamjs-components/queries/getCurrentUserEmail";
import { OnloadArgs } from "roamjs-components/types";

// Option types detailed in https://docs.birdeatsbug.com/latest/sdk/options.html

export type FeedbackWidget = {
initialize?: boolean;
Expand All @@ -15,9 +16,11 @@ export type FeedbackWidget = {
publicAppId: string;
ui?: {
position?: string;
defaultButton?: {
icon?: string;
};
defaultButton?:
| {
icon?: string;
}
| boolean;
text?: {
defaultButton?: string;
previewScreen?: {
Expand All @@ -42,41 +45,7 @@ declare global {
}
}

const STYLE_ID = "feedback-button-hiding-styles";

const addFeedbackButtonHidingStyles = () => {
if (document.getElementById(STYLE_ID)) {
return;
}

const styleElement = document.createElement("style");
styleElement.id = STYLE_ID;
styleElement.textContent = `
#birdeatsbug-default-button {
display: none !important;
}
`;

document.head.appendChild(styleElement);
};

const removeFeedbackButtonHidingStyles = () => {
const styleElement = document.getElementById(STYLE_ID);
if (styleElement) {
styleElement.remove();
}
};

export const initFeedbackWidget = (
extensionAPI: OnloadArgs["extensionAPI"],
): void => {
if (extensionAPI.settings.get("hide-feedback-button") as boolean) {
addFeedbackButtonHidingStyles();
return;
}

removeFeedbackButtonHidingStyles();

export const initFeedbackWidget = (): void => {
const birdeatsbug = (window.birdeatsbug =
window.birdeatsbug || []) as FeedbackWidget;

Expand Down Expand Up @@ -141,22 +110,22 @@ export const initFeedbackWidget = (

const customStyles = document.createElement("style");
customStyles.textContent = `

#birdeatsbug-sdk {
--distance-to-window-edge-vertical: 50px;
--distance-to-window-edge-horizontal: 20px;
}

#birdeatsbug-sdk .form-error {
font-size: 1.2rem;
}

#birdeatsbug-sdk:has(.screen) {
box-shadow: none !important;
border-radius: 0 !important;
border: none !important;
}

#birdeatsbug-sdk.dark {
--button-primary-bg-color: #1976d2;
}
Expand All @@ -180,7 +149,7 @@ export const initFeedbackWidget = (

#birdeatsbug-sdk .caret {
height: initial;
width: initial;
width: initial;
border-top: initial;
}
`;
Expand All @@ -195,9 +164,8 @@ export const initFeedbackWidget = (
},
ui: {
position: "bottom-right",
defaultButton: { icon: undefined },
defaultButton: false, // hide, will be triggered in DiscourseFloatingMenu
text: {
defaultButton: "Send feedback",
previewScreen: {
title: "Discourse Graphs feedback",
},
Expand All @@ -211,6 +179,3 @@ export const initFeedbackWidget = (
});
}
};

export const hideFeedbackButton = addFeedbackButtonHidingStyles;
export const showFeedbackButton = removeFeedbackButtonHidingStyles;
128 changes: 128 additions & 0 deletions apps/roam/src/components/DiscourseFloatingMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from "react";
import ReactDOM from "react-dom";
import { OnloadArgs } from "roamjs-components/types";
import {
Popover,
Menu,
MenuItem,
Button,
Intent,
Position,
PopoverInteractionKind,
} from "@blueprintjs/core";
import { FeedbackWidget } from "./BirdEatsBugs";

type DiscourseFloatingMenuProps = {
// CSS placement class
position: "top-left" | "top-right" | "bottom-left" | "bottom-right";
theme: string; // e.g., "bp3-light" | "bp3-dark"
buttonTheme?: string; // e.g., "bp3-light" | "bp3-dark"
};

const ANCHOR_ID = "dg-floating-menu-anchor";

export const DiscourseFloatingMenu = (props: DiscourseFloatingMenuProps) => (
<div
id="discourse-floating-menu"
className={`${props.position} ${props.theme}`}
>
<Popover
autoFocus={false}
content={
<Menu>
<MenuItem
text="Send feedback"
icon="send-message"
onClick={() => {
try {
(window.birdeatsbug as FeedbackWidget | undefined)?.trigger?.();
} catch (error) {
console.error("Failed to trigger feedback widget:", error);
}
}}
/>
<MenuItem
text="Docs"
icon="document-open"
href="https://discoursegraphs.com/docs/roam"
rel="noopener noreferrer"
target="_blank"
/>
<MenuItem
text="Community"
icon="people"
href="https://join.slack.com/t/discoursegraphs/shared_invite/zt-37xklatti-cpEjgPQC0YyKYQWPNgAkEg"
rel="noopener noreferrer"
target="_blank"
/>
</Menu>
}
position={Position.TOP}
className="bp3-popover-content-sizing"
interactionKind={PopoverInteractionKind.HOVER}
boundary="viewport"
modifiers={{
arrow: {
enabled: false,
},
}}
>
<Button
intent={Intent.PRIMARY}
text="Discourse Graphs"
id="dg-floating-menu-button"
aria-label="Open Discourse Graphs menu"
className={props.buttonTheme}
/>
</Popover>
</div>
);

export const hideDiscourseFloatingMenu = () => {
const anchor = document.getElementById(ANCHOR_ID);
anchor?.classList.add("hidden");
};

export const showDiscourseFloatingMenu = () => {
const anchor = document.getElementById(ANCHOR_ID);
anchor?.classList.remove("hidden");
};

export const installDiscourseFloatingMenu = (
extensionAPI: OnloadArgs["extensionAPI"],
props: DiscourseFloatingMenuProps = {
position: "bottom-right",
theme: "bp3-light",
buttonTheme: "bp3-dark",
},
) => {
let floatingMenuAnchor = document.getElementById(ANCHOR_ID);
if (!floatingMenuAnchor) {
floatingMenuAnchor = document.createElement("div");
floatingMenuAnchor.id = ANCHOR_ID;
document.getElementById("app")?.appendChild(floatingMenuAnchor);
}
if (extensionAPI.settings.get("hide-feedback-button") as boolean) {
floatingMenuAnchor.classList.add("hidden");
}
ReactDOM.render(
<DiscourseFloatingMenu
position={props.position}
theme={props.theme}
buttonTheme={props.buttonTheme}
/>,
floatingMenuAnchor,
);
};

export const removeDiscourseFloatingMenu = () => {
const anchor = document.getElementById(ANCHOR_ID);
if (anchor) {
try {
ReactDOM.unmountComponentAtNode(anchor);
} catch (e) {
// no-op: unmount best-effort
}
anchor.remove();
}
};
10 changes: 5 additions & 5 deletions apps/roam/src/components/settings/HomePersonalSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {
previewPageRefHandler,
} from "~/utils/pageRefObserverHandlers";
import {
hideFeedbackButton,
showFeedbackButton,
} from "~/components/BirdEatsBugs";
showDiscourseFloatingMenu,
hideDiscourseFloatingMenu,
} from "~/components/DiscourseFloatingMenu";
import { NodeSearchMenuTriggerSetting } from "../DiscourseNodeSearchMenu";

const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
Expand Down Expand Up @@ -127,9 +127,9 @@ const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
extensionAPI.settings.set("hide-feedback-button", target.checked);

if (target.checked) {
hideFeedbackButton();
hideDiscourseFloatingMenu();
} else {
showFeedbackButton();
showDiscourseFloatingMenu();
}
}}
labelElement={
Expand Down
18 changes: 16 additions & 2 deletions apps/roam/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ import { addGraphViewNodeStyling } from "./utils/graphViewNodeStyling";
import { setQueryPages } from "./utils/setQueryPages";
import initializeDiscourseNodes from "./utils/initializeDiscourseNodes";
import styles from "./styles/styles.css";
import discourseFloatingMenuStyles from "./styles/discourseFloatingMenuStyles.css";
import settingsStyles from "./styles/settingsStyles.css";
import discourseGraphStyles from "./styles/discourseGraphStyles.css";
import posthog from "posthog-js";
import getDiscourseNodes from "./utils/getDiscourseNodes";
import { initFeedbackWidget } from "./components/BirdEatsBugs";
import {
installDiscourseFloatingMenu,
removeDiscourseFloatingMenu,
} from "./components/DiscourseFloatingMenu";

const initPostHog = () => {
posthog.init("phc_SNMmBqwNfcEpNduQ41dBUjtGNEUEKAy6jTn63Fzsrax", {
Expand Down Expand Up @@ -65,7 +70,7 @@ export default runExtension(async (onloadArgs) => {
});
}

initFeedbackWidget(onloadArgs.extensionAPI);
initFeedbackWidget();

if (window?.roamjs?.loaded?.has("query-builder")) {
renderToast({
Expand Down Expand Up @@ -94,6 +99,7 @@ export default runExtension(async (onloadArgs) => {
const style = addStyle(styles);
const discourseGraphStyle = addStyle(discourseGraphStyles);
const settingsStyle = addStyle(settingsStyles);
const discourseFloatingMenuStyle = addStyle(discourseFloatingMenuStyles);

const { observers, listeners } = await initObservers({ onloadArgs });
const {
Expand Down Expand Up @@ -128,8 +134,15 @@ export default runExtension(async (onloadArgs) => {
getDiscourseNodes: getDiscourseNodes,
};

installDiscourseFloatingMenu(onloadArgs.extensionAPI);

return {
elements: [style, settingsStyle, discourseGraphStyle],
elements: [
style,
settingsStyle,
discourseGraphStyle,
discourseFloatingMenuStyle,
],
observers: observers,
unload: () => {
window.roamjs.extension?.smartblocks?.unregisterCommand("QUERYBUILDER");
Expand All @@ -146,6 +159,7 @@ export default runExtension(async (onloadArgs) => {
"selectionchange",
nodeCreationPopoverListener,
);
removeDiscourseFloatingMenu();
window.roamAlphaAPI.ui.graphView.wholeGraph.removeCallback({
label: "discourse-node-styling",
});
Expand Down
Loading