diff --git a/package-lock.json b/package-lock.json
index d7049824..5581d450 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"@fortawesome/react-fontawesome": "0.2.2",
"@mdx-js/react": "^3.0.0",
"@microsoft/clarity": "1.0.0",
+ "@typebot.io/react": "0.3.47",
"clsx": "^2.0.0",
"docusaurus-lunr-search": "^3.3.2",
"docusaurus-plugin-image-zoom": "^2.0.0",
@@ -4759,6 +4760,26 @@
"node": ">=10.13.0"
}
},
+ "node_modules/@typebot.io/js": {
+ "version": "0.3.46",
+ "resolved": "https://registry.npmjs.org/@typebot.io/js/-/js-0.3.46.tgz",
+ "integrity": "sha512-CMTLNyQCtVnJEeod+AB4Xp7X4tKOxxtk11hnPkWbV70KoVgGEPDIu+sN4vAOUw1ZmebXIbWVGC+0F3vOAX1/lA==",
+ "license": "FSL-1.1-ALv2"
+ },
+ "node_modules/@typebot.io/react": {
+ "version": "0.3.47",
+ "resolved": "https://registry.npmjs.org/@typebot.io/react/-/react-0.3.47.tgz",
+ "integrity": "sha512-JcOSWlpF96m3H3NWquDXz8ks8DvqB7iTGNuiWWRBPbxsQbRsrIZevO69MLCDfE8EuRDogCQhgKxCtDYuxjxceQ==",
+ "license": "FSL-1.1-ALv2",
+ "dependencies": {
+ "@typebot.io/js": "0.3.46",
+ "react": "18.2.0"
+ },
+ "peerDependencies": {
+ "@typebot.io/js": "0.3.22",
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/@types/acorn": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
diff --git a/package.json b/package.json
index 120fa650..3f784947 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,8 @@
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-cookie-consent": "9.0.0",
- "react-dom": "^18.0.0"
+ "react-dom": "^18.0.0",
+ "@typebot.io/react": "0.3.47"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.7.0",
diff --git a/src/components/Support/AssistantModal.tsx b/src/components/Support/AssistantModal.tsx
new file mode 100644
index 00000000..a8fd63f2
--- /dev/null
+++ b/src/components/Support/AssistantModal.tsx
@@ -0,0 +1,72 @@
+import React from "react";
+import { Standard } from "@typebot.io/react";
+
+function AssistantModal({ isOpen, onClose }) {
+ if (!isOpen) return null; // Prevent modal from rendering when isOpen is false.
+
+ // Get the current page URL.
+ const currentUrl = window.location.href;
+
+ // Check if the user is on the Japanese documentation page.
+ const isJapanese = currentUrl.includes("/ja-jp");
+
+ return (
+
+
+ {/* Close the button. */}
+
+ ×
+
+
+ {/* Conditionally render the Typebot based on language. */}
+
+
+
+ );
+}
+
+const styles = {
+ modal: {
+ display: "block",
+ position: "fixed",
+ zIndex: 1000,
+ left: 0,
+ top: 0,
+ width: "100%",
+ height: "100%",
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
+ },
+ modalContent: {
+ backgroundColor: "#fff",
+ margin: "10% auto",
+ padding: "20px",
+ borderRadius: "10px",
+ width: "90%",
+ maxWidth: "900px",
+ position: "relative", // Allow absolute positioning of the close button.
+ },
+ closeButton: {
+ position: "absolute",
+ top: "10px",
+ right: "20px",
+ fontSize: "30px",
+ fontWeight: "bold",
+ cursor: "pointer",
+ color: "#333",
+ backgroundColor: "transparent",
+ border: "none",
+ padding: "0",
+ zIndex: 1100, // Ensure the close button is above the modal content.
+ },
+};
+
+export default AssistantModal;
diff --git a/src/components/Support/SupportDropdownMenu.tsx b/src/components/Support/SupportDropdownMenu.tsx
new file mode 100644
index 00000000..f66c35d4
--- /dev/null
+++ b/src/components/Support/SupportDropdownMenu.tsx
@@ -0,0 +1,165 @@
+import React, { useState, useEffect, useRef, lazy, Suspense, MouseEvent } from 'react';
+import { useDoc } from '@docusaurus/plugin-content-docs/client';
+import { useLocation } from "@docusaurus/router";
+
+// Lazy-load AssistantModal.
+const AssistantModal = lazy(() => import('./AssistantModal'));
+
+const SupportDropdownMenu: React.FC = () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [storedUrl, setStoredUrl] = useState(null);
+ const dropdownRef = useRef(null);
+ const location = useLocation();
+
+ // Get document metadata from Docusaurus.
+ const { metadata } = useDoc();
+ const docTitle: string = metadata?.title || "Issue with documentation page";
+
+ // Detect the language based on the URL path.
+ const isJapanese: boolean = location.pathname.startsWith("/ja-jp");
+
+ useEffect(() => {
+ if (typeof window !== "undefined") {
+ const currentUrl = `https://scalardb.scalar-labs.com${location.pathname}`;
+ localStorage.setItem("currentUrl", currentUrl);
+
+ const savedUrl = localStorage.getItem("currentUrl");
+ if (savedUrl) {
+ setStoredUrl(savedUrl);
+ }
+ }
+ }, [location]);
+
+ const toggleDropdown = () => {
+ setIsOpen((prev) => !prev);
+ };
+
+ const openModal = (event: MouseEvent) => {
+ event.preventDefault();
+ setIsModalOpen(true);
+ setIsOpen(false);
+ };
+
+ const closeModal = () => {
+ setIsModalOpen(false);
+ };
+
+ const handleSupportClick = () => {
+ if (typeof window !== "undefined") {
+ const finalUrl = storedUrl || `https://scalardb.scalar-labs.com${location.pathname}`;
+ const reportUrl = `https://support.scalar-labs.com/hc/ja/requests/new?ticket_form_id=8641483507983&tf_11847415366927=${encodeURIComponent(finalUrl)}`;
+
+ window.open(reportUrl, "_blank");
+ }
+ };
+
+ const githubIssueUrl: string = typeof window !== "undefined" ? (() => {
+ const repoUrl = "https://github.com/scalar-labs/docs-scalardb/issues/new";
+ const issueTitle = encodeURIComponent(
+ isJapanese ? `フィードバック: \`${docTitle}\` ページ` : `Feedback: \`${docTitle}\` page`
+ );
+
+ const issueBody = encodeURIComponent(
+ isJapanese
+ ? `**ドキュメントページの URL:** ${window.location.href.replace(/#.*$/, '')}
+
+## 期待される動作
+
+どのような動作を期待しましたか?
+
+## 問題の説明
+
+問題の内容をわかりやすく説明してください。
+
+### 再現手順 (該当する場合)
+
+問題を再現できる場合、手順を記載してください。
+
+### スクリーンショット (該当する場合)
+
+該当する場合は、スクリーンショットを添付してください。
+`
+ : `**Documentation page URL:** ${window.location.href.replace(/#.*$/, '')}
+
+## Expected behavior
+
+What did you expect to happen?
+
+## Describe the problem
+
+Please provide a clear and concise description of what the issue is.
+
+### Steps to reproduce (if applicable)
+
+If the issue is reproducible, please list the steps to reproduce it.
+
+### Screenshots (if applicable)
+
+If applicable, add screenshots to help explain your problem.
+`
+ );
+
+ const issueUrl = `${repoUrl}?title=${issueTitle}&body=${issueBody}&labels=documentation`;
+
+ console.log("GitHub Issue URL: ", issueUrl); // Debugging line
+
+ return issueUrl;
+ })() : "#";
+
+ useEffect(() => {
+ function handleClickOutside(event: MouseEvent | Event) {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
+ setIsOpen(false);
+ }
+ }
+
+ if (isOpen) {
+ document.addEventListener("mousedown", handleClickOutside);
+ } else {
+ document.removeEventListener("mousedown", handleClickOutside);
+ }
+
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, [isOpen]);
+
+ return (
+
+
+
+
+
+ {isModalOpen && (
+
Loading... }>
+
+
+ )}
+
+ );
+};
+
+export default SupportDropdownMenu;
diff --git a/src/css/custom.css b/src/css/custom.css
index 5139db01..4822ed61 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -251,3 +251,108 @@ html[data-theme="dark"] .tooltip-glossary {
width: 333px !important;
}
}
+
+/* Support button and dropdown */
+.supportDropdown {
+ display: inline-block;
+ position: relative;
+}
+
+.supportDropdownContent {
+ background-color: #f9f9f9;
+ border-radius: 8px;
+ box-shadow: var(--ifm-global-shadow-md);
+ color: var(--ifm-color-emphasis-700);
+ font-size: 14px;
+ min-width: 303px;
+ opacity: 0;
+ overflow: hidden;
+ padding: 8px 0px;
+ position: absolute;
+ right: 0;
+ transform: translateY(-10px);
+ transition: opacity 0.3s ease-out, transform 0.3s ease-out;
+ visibility: hidden;
+ z-index: 1;
+}
+
+.supportDropdown:hover .supportDropdownContent {
+ visibility: visible;
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.supportDropdownContent {
+ transition-delay: 0.1s;
+}
+
+.supportDropBtn {
+ align-items: center;
+ background-color: inherit;
+ border: 0;
+ border-radius: var(--ifm-badge-border-radius);
+ color: var(--ifm-navbar-link-color);
+ cursor: pointer;
+ display: flex;
+ font-family: var(--ifm-font-family-base);
+ font-size: 14.5px;
+ font-weight: var(--ifm-font-weight-semibold);
+ justify-content: space-between;
+ min-width: 145px;
+ padding: 6px 0;
+ text-align: left;
+ z-index: 1;
+}
+
+.supportDropBtn svg { /* Keep dropdown open when moving the mouse between text and icon. */
+ pointer-events: none;
+}
+
+.supportDropdown:hover .supportDropBtn {
+ color: var(--ifm-color-primary);
+}
+
+@media (max-width: 996px) {
+ .supportDropBtn {
+ font-size: 15px;
+ }
+ .supportDropdownContent {
+ font-size: 15px;
+ left: 0;
+ min-width: 320px;
+ }
+}
+
+.supportDropdownContent a {
+ color: var(--ifm-dropdown-link-color);
+ display: block;
+ margin: 4px 10px;
+ padding: 4px 10px;
+ text-decoration: none;
+}
+
+.supportDropdownContent a:hover {
+ background-color: var(--ifm-dropdown-hover-background-color);
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+html[data-theme="dark"] .supportDropBtn {
+ background-color: inherit;
+ border: 0;
+ color: #f9f9f9;
+}
+
+html[data-theme="dark"] .supportDropdownContent {
+ background-color: var(--ifm-dropdown-background-color);
+
+ a {
+ color: #f9f9f9;
+ }
+}
+
+hr {
+ text-align: center;
+ margin: auto;
+ max-width: 91%;
+}
diff --git a/src/theme/DocItem/Layout/index.tsx b/src/theme/DocItem/Layout/index.tsx
new file mode 100644
index 00000000..b191b0d6
--- /dev/null
+++ b/src/theme/DocItem/Layout/index.tsx
@@ -0,0 +1,95 @@
+import SupportDropdownMenu from '../../../components/Support/SupportDropdownMenu';
+import React from 'react';
+import clsx from 'clsx';
+import { useWindowSize } from '@docusaurus/theme-common';
+import { useDoc } from '@docusaurus/plugin-content-docs/client';
+import DocItemPaginator from '@theme/DocItem/Paginator';
+import DocVersionBanner from '@theme/DocVersionBanner';
+import DocVersionBadge from '@theme/DocVersionBadge';
+import DocItemFooter from '@theme/DocItem/Footer';
+import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile';
+import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop';
+import DocItemContent from '@theme/DocItem/Content';
+import DocBreadcrumbs from '@theme/DocBreadcrumbs';
+import ContentVisibility from '@theme/ContentVisibility';
+
+import styles from './styles.module.css';
+
+// Define the type for the useDocTOC return value.
+interface DocTOC {
+ hidden: boolean;
+ mobile?: JSX.Element;
+ desktop?: JSX.Element;
+}
+
+// Type for the DocItemLayout props
+interface DocItemLayoutProps {
+ children: React.ReactNode;
+}
+
+// Hook to handle the Table of Contents visibility and rendering
+function useDocTOC(): DocTOC {
+ const { frontMatter, toc } = useDoc();
+ const windowSize = useWindowSize();
+ const hidden = frontMatter.hide_table_of_contents;
+ const canRender = !hidden && toc.length > 0;
+
+ return {
+ hidden,
+ mobile: canRender ? : undefined,
+ desktop: canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? : undefined,
+ };
+}
+
+// DocItemLayout component
+const DocItemLayout: React.FC = ({ children }) => {
+ const docTOC = useDocTOC();
+ const { metadata, frontMatter } = useDoc();
+ const hideTOC = frontMatter.hide_table_of_contents;
+ const windowSize = useWindowSize();
+
+ // Check if the current page is the home page or a version homepage.
+ const isHomePage = metadata.permalink === '/docs/latest/' ||
+ /^\/docs\/\d+\.\d+\/$/.test(metadata.permalink) ||
+ metadata.permalink === '/ja-jp/docs/latest/' ||
+ /^\/ja-jp\/docs\/\d+\.\d+\/$/.test(metadata.permalink);
+
+ return (
+
+
+
+
+
+
+
+
+ {windowSize === 'mobile' && !isHomePage && (
+
+
+
+ )}
+ {docTOC.mobile}
+ {children}
+
+
+
+
+
+
+ {!hideTOC && windowSize !== 'mobile' && (
+
+
+ {!isHomePage && (
+
+
+
+ )}
+ {docTOC.desktop}
+
+
+ )}
+
+ );
+};
+
+export default DocItemLayout;
diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css
new file mode 100644
index 00000000..d5aaec13
--- /dev/null
+++ b/src/theme/DocItem/Layout/styles.module.css
@@ -0,0 +1,10 @@
+.docItemContainer header + *,
+.docItemContainer article > *:first-child {
+ margin-top: 0;
+}
+
+@media (min-width: 997px) {
+ .docItemCol {
+ max-width: 75% !important;
+ }
+}