Skip to content

Commit 6950447

Browse files
authored
Add support dropdown menu to right-hand sidebar of pages (#1027)
* Swizzle component to add support dropdown menu This component has been swizzled so that we can add a support dropdown menu. * Add `@typebot.io/react` * Create AssistantModal.tsx This is called when the user clicks the AI Assistant button in the Support dropdown menu. * Create ContactSupportLink.tsx This is called when the user clicks the Contact Technical Support button in the Support dropdown menu. * Create SupportDropdownMenu.tsx * Create SupportDropdownMenu.module.css * Add Support dropdown menu above TOC * Make Support button appear with or without ToC Before this change, the Support button would only appear if the page had a ToC. * Pass URL as parameter to Typebot * Show Japanese text on Japanese version of site * Justify alignment for Support button text and arrow icon * Make Support button appear static above ToC By making the Support button static above the ToC, visitors can access the button without having to scroll to the top of the page. * Hide Support button when hiding ToC on page Some pages purposely hide the ToC by using `hide_table_of_contents: true`. We don't want the Support button to appear on those pages since the contents of the page are wider (taking up the space where the ToC would be). * Re-order styles * Show Support button on mobile * Make Support button and ToC appear behind language dropdown When the `zIndex` is too high, the Support button and ToC appear on top of the language dropdown menu. reducing the `zIndex` makes the language dropdown menu appear over the Support button and ToC. * Revise code comments for clarity * Fix spelling * Add support for dark mode * Delete SupportDropdownMenu.module.css No longer needed since I added styles to custom.css. * Add Support button styles These styles were originally in src/css/SupportDropdownMenu.module.css. * Change from using `JSX.Element` to `ReactNode` `ReactNode` should be used since it's what Docusaurus is based on. * Add GitHub issue link and template * Fix styles Styles exist in the custom.css file now rather than a separate CSS file * Revise wording on links * Delete ContactSupportLink.tsx Combined the contents into "src/components/Support/SupportDropdownMenu.tsx" for easier manageability. * Update SupportDropdownMenu.tsx Added the contents from "src/components/Support/ContactSupportLink.tsx" for easier manageability. * Change component link from absolute to relative Using an absolute link shows as an error for some reason. Changing the absolute link to a relative link doesn't show an error and still imports the component. * Adjust width and padding for Support button Need to adjust the width and padding to accommodate changes to the wording. * Specify Support dropdown arrow size The dropdown arrow size should be specified here since doing so in the component causes a flash of unstyled content. * Revised wording in dropdown * Update font style and link behavior * Refactor support dropdown to fix errors on build This refactor is necessary because the error `[cause]: TypeError: Layout_styles_module_default is not a function` occurred. After trying to fix this issue by changing the import for **styles.module.css** to the global **custom.css** file instead, the error `[cause]: ReferenceError: Cannot access 'SupportDropdownMenu' before initialization` occurred. This refactor resolves those issues by ensuring that the support dropdown menu component is initialized first before the Layout component is built. * Hide Stack Overflow link We've decided to not show the Stack Overflow link for now. Commented it out so that we can easily show it later. * Make dropdown menu appear on hover (instead of on click) Making the dropdown menu appear on hover instead of on click matches the natural behavior of other dropdown menus in Docusaurus. * Modify support dropdown menu styles Styles modified to support on-hover behavior instead of on-click behavior and to make the dropdown transitions match the transitions of other dropdown menus in Docusaurus. * Change dropdown arrow icon Changed the arrow icon to match the same icon used in other dropdown menus in Docusaurus. * Fix support dropdown from disappearing This style keeps the support button dropdown menu open when moving the mouse between the button text and icon. * Put support button styles in alphabetical order * Make support button font consistent with other buttons * Add `some` to English button Simply `Need help?` results in the arrow being a little too far away from the text. Being a little casual here fixes that. * Remove comments that were for quick, personal reference * Add rounded corners to dropdown and on link hover * Move file * Move file * Update import The component was move in 18027a5, so this import needs to be updated to reflect that. * Create AssistantModal.tsx * Update link to chatbot * Remove Font Awesome plugin We decided not to use Font Awesome icons in this component, so we don't need to refer to this plugin here. * Show AI assistant based on language * Move back to `Support` folder * Delete AssistantModal.tsx This file isn't needed since we can manage the AI assistants in a single file: b160ea8 * Revert "Update import" This reverts commit b530b67. * Fix GitHub issue link The GitHub issue link was opening a new tab with the same page that the visitor was on. * Change dropdown item font color Change dropdown item font color to match the default color of other fonts in Docusaurus. * Hide support dropdown menu from home page
1 parent 584aa56 commit 6950447

File tree

7 files changed

+470
-1
lines changed

7 files changed

+470
-1
lines changed

package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"prism-react-renderer": "^2.3.0",
3636
"react": "^18.0.0",
3737
"react-cookie-consent": "9.0.0",
38-
"react-dom": "^18.0.0"
38+
"react-dom": "^18.0.0",
39+
"@typebot.io/react": "0.3.47"
3940
},
4041
"devDependencies": {
4142
"@docusaurus/module-type-aliases": "^3.7.0",
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React from "react";
2+
import { Standard } from "@typebot.io/react";
3+
4+
function AssistantModal({ isOpen, onClose }) {
5+
if (!isOpen) return null; // Prevent modal from rendering when isOpen is false.
6+
7+
// Get the current page URL.
8+
const currentUrl = window.location.href;
9+
10+
// Check if the user is on the Japanese documentation page.
11+
const isJapanese = currentUrl.includes("/ja-jp");
12+
13+
return (
14+
<div className="modal" style={styles.modal}>
15+
<div className="modal-content" style={styles.modalContent}>
16+
{/* Close the button. */}
17+
<span className="close" onClick={onClose} style={styles.closeButton}>
18+
&times;
19+
</span>
20+
21+
{/* Conditionally render the Typebot based on language. */}
22+
<Standard
23+
typebot={isJapanese
24+
? "ja-jp-scalar-docs-ai-assistant-for-scalar-membership-program-members-201712"
25+
: "en-us-scalar-docs-ai-assistant-for-scalar-membership-program-members-201712"
26+
}
27+
style={{ width: "100%", height: "600px" }}
28+
prefilledVariables={{
29+
"Current page URL": `${currentUrl}`, // Pass page URL as a query parameter.
30+
}}
31+
/>
32+
</div>
33+
</div>
34+
);
35+
}
36+
37+
const styles = {
38+
modal: {
39+
display: "block",
40+
position: "fixed",
41+
zIndex: 1000,
42+
left: 0,
43+
top: 0,
44+
width: "100%",
45+
height: "100%",
46+
backgroundColor: "rgba(0, 0, 0, 0.7)",
47+
},
48+
modalContent: {
49+
backgroundColor: "#fff",
50+
margin: "10% auto",
51+
padding: "20px",
52+
borderRadius: "10px",
53+
width: "90%",
54+
maxWidth: "900px",
55+
position: "relative", // Allow absolute positioning of the close button.
56+
},
57+
closeButton: {
58+
position: "absolute",
59+
top: "10px",
60+
right: "20px",
61+
fontSize: "30px",
62+
fontWeight: "bold",
63+
cursor: "pointer",
64+
color: "#333",
65+
backgroundColor: "transparent",
66+
border: "none",
67+
padding: "0",
68+
zIndex: 1100, // Ensure the close button is above the modal content.
69+
},
70+
};
71+
72+
export default AssistantModal;
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import React, { useState, useEffect, useRef, lazy, Suspense, MouseEvent } from 'react';
2+
import { useDoc } from '@docusaurus/plugin-content-docs/client';
3+
import { useLocation } from "@docusaurus/router";
4+
5+
// Lazy-load AssistantModal.
6+
const AssistantModal = lazy(() => import('./AssistantModal'));
7+
8+
const SupportDropdownMenu: React.FC = () => {
9+
const [isOpen, setIsOpen] = useState<boolean>(false);
10+
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
11+
const [storedUrl, setStoredUrl] = useState<string | null>(null);
12+
const dropdownRef = useRef<HTMLDivElement | null>(null);
13+
const location = useLocation();
14+
15+
// Get document metadata from Docusaurus.
16+
const { metadata } = useDoc();
17+
const docTitle: string = metadata?.title || "Issue with documentation page";
18+
19+
// Detect the language based on the URL path.
20+
const isJapanese: boolean = location.pathname.startsWith("/ja-jp");
21+
22+
useEffect(() => {
23+
if (typeof window !== "undefined") {
24+
const currentUrl = `https://scalardb.scalar-labs.com${location.pathname}`;
25+
localStorage.setItem("currentUrl", currentUrl);
26+
27+
const savedUrl = localStorage.getItem("currentUrl");
28+
if (savedUrl) {
29+
setStoredUrl(savedUrl);
30+
}
31+
}
32+
}, [location]);
33+
34+
const toggleDropdown = () => {
35+
setIsOpen((prev) => !prev);
36+
};
37+
38+
const openModal = (event: MouseEvent<HTMLAnchorElement>) => {
39+
event.preventDefault();
40+
setIsModalOpen(true);
41+
setIsOpen(false);
42+
};
43+
44+
const closeModal = () => {
45+
setIsModalOpen(false);
46+
};
47+
48+
const handleSupportClick = () => {
49+
if (typeof window !== "undefined") {
50+
const finalUrl = storedUrl || `https://scalardb.scalar-labs.com${location.pathname}`;
51+
const reportUrl = `https://support.scalar-labs.com/hc/ja/requests/new?ticket_form_id=8641483507983&tf_11847415366927=${encodeURIComponent(finalUrl)}`;
52+
53+
window.open(reportUrl, "_blank");
54+
}
55+
};
56+
57+
const githubIssueUrl: string = typeof window !== "undefined" ? (() => {
58+
const repoUrl = "https://github.com/scalar-labs/docs-scalardb/issues/new";
59+
const issueTitle = encodeURIComponent(
60+
isJapanese ? `フィードバック: \`${docTitle}\` ページ` : `Feedback: \`${docTitle}\` page`
61+
);
62+
63+
const issueBody = encodeURIComponent(
64+
isJapanese
65+
? `**ドキュメントページの URL:** ${window.location.href.replace(/#.*$/, '')}
66+
67+
## 期待される動作
68+
69+
どのような動作を期待しましたか?
70+
71+
## 問題の説明
72+
73+
問題の内容をわかりやすく説明してください。
74+
75+
### 再現手順 (該当する場合)
76+
77+
問題を再現できる場合、手順を記載してください。
78+
79+
### スクリーンショット (該当する場合)
80+
81+
該当する場合は、スクリーンショットを添付してください。
82+
`
83+
: `**Documentation page URL:** ${window.location.href.replace(/#.*$/, '')}
84+
85+
## Expected behavior
86+
87+
What did you expect to happen?
88+
89+
## Describe the problem
90+
91+
Please provide a clear and concise description of what the issue is.
92+
93+
### Steps to reproduce (if applicable)
94+
95+
If the issue is reproducible, please list the steps to reproduce it.
96+
97+
### Screenshots (if applicable)
98+
99+
If applicable, add screenshots to help explain your problem.
100+
`
101+
);
102+
103+
const issueUrl = `${repoUrl}?title=${issueTitle}&body=${issueBody}&labels=documentation`;
104+
105+
console.log("GitHub Issue URL: ", issueUrl); // Debugging line
106+
107+
return issueUrl;
108+
})() : "#";
109+
110+
useEffect(() => {
111+
function handleClickOutside(event: MouseEvent | Event) {
112+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
113+
setIsOpen(false);
114+
}
115+
}
116+
117+
if (isOpen) {
118+
document.addEventListener("mousedown", handleClickOutside);
119+
} else {
120+
document.removeEventListener("mousedown", handleClickOutside);
121+
}
122+
123+
return () => document.removeEventListener("mousedown", handleClickOutside);
124+
}, [isOpen]);
125+
126+
return (
127+
<div className="supportDropdown" ref={dropdownRef}>
128+
<button className="supportDropBtn" onMouseOver={toggleDropdown}>
129+
{isJapanese ? "何かお困りですか?" : "Need some help?"}<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m12 16l-6-6h12z"/></svg>
130+
</button>
131+
132+
<div className="supportDropdownContent">
133+
<div>
134+
<a href="#" onClick={handleSupportClick} rel="noopener noreferrer">
135+
<b>{isJapanese ? "テクニカルサポートに問い合わせ" : "Contact technical support"}</b><br />
136+
{isJapanese ? "商用ライセンスをご契約のお客様のみご利用いただけます。" : "Available only to customers with a commercial license."}
137+
</a>
138+
</div>
139+
<hr />
140+
{/* <a href="https://stackoverflow.com/questions/tagged/scalardb" target="_blank" rel="noopener noreferrer">
141+
<b>{isJapanese ? "Stack Overflow をチェック" : "Check Stack Overflow"}</b><br />
142+
{isJapanese ? "すべてのユーザーがご利用いただけます。" : "Available to all users."}
143+
</a>
144+
<hr /> */}
145+
<a href="#" onClick={openModal}>
146+
<b>{isJapanese ? "AI に聞く (試験運用中)" : "Ask AI (experimental)"}</b><br />
147+
{isJapanese ? "Scalar Membership Programにご参加の方のみご利用いただけます。" : "Available only to members of the Scalar Membership Program."}
148+
</a>
149+
<hr />
150+
<a href={githubIssueUrl} target="_blank" rel="noopener noreferrer">
151+
<b>{isJapanese ? "ドキュメントの問題を報告" : "Report doc issue"}</b><br />
152+
{isJapanese ? "このページについて何かお気づきの点がありましたら、こちらから報告いただけます。" : "If you have any feedback about this page, please submit an issue."}
153+
</a>
154+
</div>
155+
156+
{isModalOpen && (
157+
<Suspense fallback={<div>Loading...</div>}>
158+
<AssistantModal isOpen={isModalOpen} onClose={closeModal} />
159+
</Suspense>
160+
)}
161+
</div>
162+
);
163+
};
164+
165+
export default SupportDropdownMenu;

src/css/custom.css

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,108 @@ html[data-theme="dark"] .tooltip-glossary {
251251
width: 333px !important;
252252
}
253253
}
254+
255+
/* Support button and dropdown */
256+
.supportDropdown {
257+
display: inline-block;
258+
position: relative;
259+
}
260+
261+
.supportDropdownContent {
262+
background-color: #f9f9f9;
263+
border-radius: 8px;
264+
box-shadow: var(--ifm-global-shadow-md);
265+
color: var(--ifm-color-emphasis-700);
266+
font-size: 14px;
267+
min-width: 303px;
268+
opacity: 0;
269+
overflow: hidden;
270+
padding: 8px 0px;
271+
position: absolute;
272+
right: 0;
273+
transform: translateY(-10px);
274+
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
275+
visibility: hidden;
276+
z-index: 1;
277+
}
278+
279+
.supportDropdown:hover .supportDropdownContent {
280+
visibility: visible;
281+
opacity: 1;
282+
transform: translateY(0);
283+
}
284+
285+
.supportDropdownContent {
286+
transition-delay: 0.1s;
287+
}
288+
289+
.supportDropBtn {
290+
align-items: center;
291+
background-color: inherit;
292+
border: 0;
293+
border-radius: var(--ifm-badge-border-radius);
294+
color: var(--ifm-navbar-link-color);
295+
cursor: pointer;
296+
display: flex;
297+
font-family: var(--ifm-font-family-base);
298+
font-size: 14.5px;
299+
font-weight: var(--ifm-font-weight-semibold);
300+
justify-content: space-between;
301+
min-width: 145px;
302+
padding: 6px 0;
303+
text-align: left;
304+
z-index: 1;
305+
}
306+
307+
.supportDropBtn svg { /* Keep dropdown open when moving the mouse between text and icon. */
308+
pointer-events: none;
309+
}
310+
311+
.supportDropdown:hover .supportDropBtn {
312+
color: var(--ifm-color-primary);
313+
}
314+
315+
@media (max-width: 996px) {
316+
.supportDropBtn {
317+
font-size: 15px;
318+
}
319+
.supportDropdownContent {
320+
font-size: 15px;
321+
left: 0;
322+
min-width: 320px;
323+
}
324+
}
325+
326+
.supportDropdownContent a {
327+
color: var(--ifm-dropdown-link-color);
328+
display: block;
329+
margin: 4px 10px;
330+
padding: 4px 10px;
331+
text-decoration: none;
332+
}
333+
334+
.supportDropdownContent a:hover {
335+
background-color: var(--ifm-dropdown-hover-background-color);
336+
border-radius: 8px;
337+
overflow: hidden;
338+
}
339+
340+
html[data-theme="dark"] .supportDropBtn {
341+
background-color: inherit;
342+
border: 0;
343+
color: #f9f9f9;
344+
}
345+
346+
html[data-theme="dark"] .supportDropdownContent {
347+
background-color: var(--ifm-dropdown-background-color);
348+
349+
a {
350+
color: #f9f9f9;
351+
}
352+
}
353+
354+
hr {
355+
text-align: center;
356+
margin: auto;
357+
max-width: 91%;
358+
}

0 commit comments

Comments
 (0)