diff --git a/src/theme/DocItem/DocContent.js b/src/theme/DocItem/DocContent.js
new file mode 100644
index 000000000..1fa177d21
--- /dev/null
+++ b/src/theme/DocItem/DocContent.js
@@ -0,0 +1,113 @@
+import React from "react";
+import Head from "@docusaurus/Head";
+import MDXComponents from "../MDXComponents";
+import { MDXProvider } from "@mdx-js/react";
+import {
+ useDoc,
+ useDocsVersion,
+} from "@docusaurus/plugin-content-docs/client";
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import useBaseUrl from "@docusaurus/useBaseUrl";
+import DocPaginator from "@theme/DocPaginator";
+import DocVersionBanner from "@theme/DocVersionBanner";
+import TOC from "@theme/TOC";
+import clsx from "clsx";
+import styles from "./styles.module.css";
+import DocsInfo from "./DocsInfo";
+import DocsRating from "./DocsRating";
+
+export const DocContent = ({ Content, contentRef, readingTimeInWords }) => {
+ const { siteConfig } = useDocusaurusContext();
+ const {
+ metadata,
+ frontMatter: {
+ image: metaImage,
+ keywords,
+ hide_title: hideTitle,
+ hide_table_of_contents: hideTableOfContents,
+ },
+ toc,
+ } = useDoc();
+
+ const { url: siteUrl } = siteConfig;
+ const versionMetadata = useDocsVersion();
+ const {
+ description,
+ title,
+ permalink,
+ editUrl,
+ lastUpdatedAt,
+ lastUpdatedBy,
+ unversionedId,
+ } = metadata;
+
+ const metaImageUrl = useBaseUrl(metaImage, {
+ absolute: true,
+ });
+
+ return (
+ <>
+
+ {description && }
+ {description && (
+
+ )}
+ {keywords && keywords.length && (
+
+ )}
+ {metaImage && }
+ {metaImage && }
+ {metaImage && (
+
+ )}
+ {permalink && }
+ {permalink && }
+
+
+
+
+ {/*
*/}
+
+
+ {!hideTitle && (
+
+ )}
+ {(editUrl || lastUpdatedAt || lastUpdatedBy) && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!hideTableOfContents && toc && (
+
+
+
+ )}
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src/theme/DocItem/DocsInfo.js b/src/theme/DocItem/DocsInfo.js
new file mode 100644
index 000000000..028aa56c8
--- /dev/null
+++ b/src/theme/DocItem/DocsInfo.js
@@ -0,0 +1,89 @@
+import React from "react";
+import { useLocation } from "react-router-dom";
+import {
+ FiEdit3,
+ FiPrinter,
+ FiAlertCircle,
+ FiClock,
+ FiUser,
+} from "react-icons/fi";
+import styles from "./styles.module.css";
+import ShareButton from "./ShareButton";
+
+function DocsInfo({ docsPluginId, ...props }) {
+ const location = useLocation();
+ const openDocIssueURL =
+ "https://github.com/codeharborhub/codeharborhub.github.io/issues/new?assignees=&labels=&template=---doc-error-report.md&title=Issue with codeharborhub.github.io" +
+ `${location.pathname}`;
+
+ return (
+
+
+ {/* Left Section – Meta Info */}
+ {(props.lastUpdatedAt || props.lastUpdatedBy) && (
+
+ {props.lastUpdatedAt && (
+
+
+
+
+ )}
+ {props.readingTimeInWords && (
+
+ ⏱ {props.readingTimeInWords}
+
+ )}
+ {props.lastUpdatedBy && (
+
+
+ {props.lastUpdatedBy}
+
+ )}
+
+ )}
+
+ {/* Right Section – Actions */}
+
+ {props.editUrl && (
+
+
+ Edit
+
+ )}
+
+
+
+ {openDocIssueURL && (
+
+
+ Report
+
+ )}
+
+
+
+
+
+ );
+}
+
+export default DocsInfo;
\ No newline at end of file
diff --git a/src/theme/DocItem/DocsRating.js b/src/theme/DocItem/DocsRating.js
new file mode 100644
index 000000000..9925068b3
--- /dev/null
+++ b/src/theme/DocItem/DocsRating.js
@@ -0,0 +1,82 @@
+import React, { useState } from "react";
+import { useLocation } from "react-router-dom";
+import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
+// import { useColorMode } from "@docusaurus/theme-common";
+import { FiThumbsUp, FiThumbsDown } from "react-icons/fi";
+import styles from "./styles.module.css";
+
+const DocsRating = ({ label }) => {
+ if (!ExecutionEnvironment.canUseDOM) return null;
+
+ const location = useLocation();
+ // const { colorMode } = useColorMode();
+ const DiscordInviteURL = "https://discord.gg/8p9Z6jkVru";
+ const openDocIssueURL =
+ `https://github.com/codeharborhub/codeharborhub.github.io/issues/new?assignees=&labels=&template=---doc-error-report.md&title=Issue with codeharborhub.github.io${location.pathname}`;
+ const docEnhancementURL =
+ `https://github.com/codeharborhub/codeharborhub.github.io/issues/new?assignees=&labels=&template=---doc-site-enhancement-request.md&title=Doc enhancement request for codeharborhub.github.io${location.pathname}`;
+
+ const [haveVoted, setHaveVoted] = useState(false);
+ const [liked, setLiked] = useState(false);
+
+ const giveFeedback = (value) => {
+ if (window.ga) {
+ window.ga("send", {
+ hitType: "event",
+ eventCategory: "button",
+ eventAction: "feedback",
+ eventLabel: label,
+ eventValue: value,
+ });
+ }
+ setLiked(value === 1);
+ setHaveVoted(true);
+ };
+
+ return (
+
+ {haveVoted ? (
+ liked ? (
+
🎉 Thanks for letting us know!
+ ) : (
+
+ )
+ ) : (
+
+
Was this topic helpful?
+
+
+
+
+
+ )}
+
+ );
+};
+
+export default DocsRating;
diff --git a/src/theme/DocItem/Layout.js b/src/theme/DocItem/Layout.js
new file mode 100644
index 000000000..d20a731d0
--- /dev/null
+++ b/src/theme/DocItem/Layout.js
@@ -0,0 +1,61 @@
+//Swizzled this component to fix TOC sidebar not showing on small screens
+
+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 Unlisted from '@theme/Unlisted';
+import styles from './styles.module.css';
+
+/**
+ * Decide if the toc should be rendered, on mobile or desktop viewports
+ */
+function useDocTOC() {
+ const {frontMatter, toc} = useDoc();
+ const windowSize = useWindowSize({ desktopBreakpoint: 1150 });
+ const hidden = frontMatter.hide_table_of_contents;
+ const canRender = !hidden && toc.length > 0;
+ const mobile = canRender ? : undefined;
+ const desktop =
+ canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? (
+
+ ) : undefined;
+ return {
+ hidden,
+ mobile,
+ desktop,
+ };
+}
+export default function DocItemLayout({children}) {
+ const docTOC = useDocTOC();
+ const {
+ metadata: {unlisted},
+ } = useDoc();
+ return (
+
+
+ {unlisted &&
}
+
+
+
+
+
+ {docTOC.mobile}
+ {children}
+
+
+
+
+
+ {docTOC.desktop &&
{docTOC.desktop}
}
+
+ );
+}
\ No newline at end of file
diff --git a/src/theme/DocItem/ShareButton.js b/src/theme/DocItem/ShareButton.js
new file mode 100644
index 000000000..d5882a1cb
--- /dev/null
+++ b/src/theme/DocItem/ShareButton.js
@@ -0,0 +1,75 @@
+import React from "react";
+import { useLocation } from "react-router-dom";
+import { useColorMode } from "@docusaurus/theme-common";
+import {
+ FiShare2,
+ FiTwitter,
+ FiLinkedin,
+ FiFacebook,
+ FiMail,
+} from "react-icons/fi";
+import styles from "./shareButton.module.css";
+
+function ShareButton({ title }) {
+ const location = useLocation();
+ const { colorMode } = useColorMode();
+ const baseUrl = "https://codeharborhub.github.io";
+ const fullUrl = baseUrl + location.pathname;
+
+ const shareLinks = [
+ {
+ name: "Twitter",
+ url: `https://twitter.com/share?url=${fullUrl}&text=Check out this article on ${title}&hashtags=codeharborhub,opensource`,
+ icon: ,
+ color: "#1DA1F2",
+ },
+ {
+ name: "LinkedIn",
+ url: `https://www.linkedin.com/shareArticle?mini=true&url=${fullUrl}&source=CodeHarborHub`,
+ icon: ,
+ color: "#0A66C2",
+ },
+ {
+ name: "Facebook",
+ url: `https://www.facebook.com/sharer/sharer.php?u=${fullUrl}`,
+ icon: ,
+ color: "#1877F2",
+ },
+ {
+ name: "Email",
+ url: `mailto:?subject=Shared Article | ${title} | CodeHarborHub Docs&body=Check out this article on ${title}: ${fullUrl}`,
+ icon: ,
+ color: "#D44638",
+ },
+ ];
+
+ return (
+
+ );
+}
+
+export default ShareButton;
\ No newline at end of file
diff --git a/src/theme/DocItem/index.js b/src/theme/DocItem/index.js
new file mode 100644
index 000000000..7cfe71d63
--- /dev/null
+++ b/src/theme/DocItem/index.js
@@ -0,0 +1,25 @@
+import React, { useEffect, useRef, useState } from "react";
+import readingTime from "reading-time/lib/reading-time";
+import { DocProvider } from "@docusaurus/plugin-content-docs/client";
+
+//Components
+import { DocContent } from "./DocContent";
+
+function DocItem(props) {
+ const contentRef = useRef();
+ const [readingTimeInWords, setReadingTimeInWords] = useState("");
+
+ useEffect(() => {
+ if (contentRef.current) {
+ const readTime = readingTime(contentRef.current.innerText);
+ setReadingTimeInWords(readTime.text);
+ }
+ }, [contentRef]);
+ return (
+
+
+
+ );
+}
+
+export default DocItem;
\ No newline at end of file
diff --git a/src/theme/DocItem/shareButton.module.css b/src/theme/DocItem/shareButton.module.css
new file mode 100644
index 000000000..013b5cf47
--- /dev/null
+++ b/src/theme/DocItem/shareButton.module.css
@@ -0,0 +1,67 @@
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+.trigger {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ padding: 0.4rem 0.7rem;
+ border: 1px solid var(--ifm-color-emphasis-200);
+ border-radius: 6px;
+ background: var(--ifm-background-surface-color);
+ cursor: pointer;
+ color: var(--ifm-font-color-base);
+ transition: background 0.2s;
+ font-size: 0.9rem;
+}
+
+.trigger:hover {
+ background: var(--ifm-color-emphasis-100);
+}
+
+.shareIcon {
+ font-size: 1rem;
+}
+
+.menu {
+ display: none;
+ position: absolute;
+ top: 100%;
+ right: 0;
+ margin-top: 0.4rem;
+ padding: 0.4rem 0;
+ background: var(--ifm-background-surface-color);
+ border: 1px solid var(--ifm-color-emphasis-200);
+ border-radius: 6px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ min-width: 160px;
+ z-index: 20;
+ list-style: none;
+}
+
+.dropdown:hover .menu {
+ display: block;
+}
+
+.menuItem {
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+ padding: 0.6rem 0.8rem;
+ color: var(--ifm-font-color-base);
+ text-decoration: none;
+ transition: background 0.2s, color 0.2s;
+ font-size: 0.9rem;
+}
+
+.menuItem:hover {
+ background: var(--ifm-color-emphasis-100);
+ color: var(--hover-color);
+ text-decoration: none;
+}
+
+.icon {
+ font-size: 1rem;
+}
diff --git a/src/theme/DocItem/styles.module.css b/src/theme/DocItem/styles.module.css
new file mode 100644
index 000000000..1964309c5
--- /dev/null
+++ b/src/theme/DocItem/styles.module.css
@@ -0,0 +1,131 @@
+.docTitle {
+ font-size: 3rem;
+ margin-bottom: -calc(var(--ifm-leading-desktop) * var(--ifm-leading));
+ text-align: justify;
+}
+
+.docsInfoWrapper {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+.docsInfoContainer {
+ width: 100%;
+ padding: 1rem 0.2rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ border-radius: 8px;
+}
+
+.metaInfo {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem;
+ color: var(--ifm-color-content-secondary);
+ font-size: 0.9rem;
+}
+
+.metaItem {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+}
+
+.actions {
+ display: flex;
+ align-items: center;
+ gap: 0.8rem;
+ margin-top: 0.6rem;
+}
+
+.actionBtn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.4rem 0.75rem;
+ border: 1px solid var(--ifm-color-emphasis-200);
+ border-radius: 6px;
+ background: var(--ifm-background-surface-color);
+ font-size: 0.85rem;
+ color: var(--ifm-font-color-base);
+ text-decoration: none;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.actionBtn:hover {
+ background: var(--ifm-color-primary);
+ color: #fff;
+ border-color: var(--ifm-color-primary);
+}
+
+.icon {
+ font-size: 1rem;
+ vertical-align: middle;
+}
+
+.docsRating {
+ max-width: 600px;
+ text-align: center;
+ font-family: var(--ifm-font-family-base);
+}
+
+.heading {
+ font-size: 1.2rem;
+ margin-bottom: 1rem;
+}
+
+.buttonGroup {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+.voteBtn {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ background: var(--ifm-background-surface-color);
+ border: 1px solid var(--ifm-color-emphasis-200);
+ color: var(--ifm-font-color-base);
+ padding: 0.6rem 1.2rem;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background 0.2s, color 0.2s, border 0.2s;
+ font-size: 0.95rem;
+}
+
+.voteBtn:hover {
+ background: var(--ifm-color-emphasis-100);
+ border-color: var(--ifm-color-primary);
+ color: var(--ifm-color-primary);
+}
+
+.icon {
+ font-size: 1.1rem;
+}
+
+.thankYou {
+ font-size: 1.1rem;
+ color: var(--ifm-color-success);
+ font-weight: 500;
+}
+
+.feedbackLinks {
+ text-align: left;
+ margin-top: 0.5rem;
+ line-height: 1.6;
+}
+
+.feedbackLinks a {
+ color: var(--ifm-color-primary);
+ text-decoration: none;
+}
+
+.feedbackLinks a:hover {
+ text-decoration: underline;
+}
diff --git a/static/img/bug-icon.svg b/static/img/bug-icon.svg
new file mode 100644
index 000000000..bb1ed4d5b
--- /dev/null
+++ b/static/img/bug-icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/static/img/email-dark-icon.svg b/static/img/email-dark-icon.svg
new file mode 100644
index 000000000..b04f0f8b1
--- /dev/null
+++ b/static/img/email-dark-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/email-light-icon.svg b/static/img/email-light-icon.svg
new file mode 100644
index 000000000..3647bb427
--- /dev/null
+++ b/static/img/email-light-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/facebook-dark-icon.svg b/static/img/facebook-dark-icon.svg
new file mode 100644
index 000000000..6817f3dfb
--- /dev/null
+++ b/static/img/facebook-dark-icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/static/img/facebook-light-icon.svg b/static/img/facebook-light-icon.svg
new file mode 100644
index 000000000..be11510b0
--- /dev/null
+++ b/static/img/facebook-light-icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/static/img/linkedin-dark-icon.svg b/static/img/linkedin-dark-icon.svg
new file mode 100644
index 000000000..2e5f13d8d
--- /dev/null
+++ b/static/img/linkedin-dark-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/linkedin-light-icon.svg b/static/img/linkedin-light-icon.svg
new file mode 100644
index 000000000..901c18416
--- /dev/null
+++ b/static/img/linkedin-light-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/print-icon.svg b/static/img/print-icon.svg
new file mode 100644
index 000000000..1b697afa2
--- /dev/null
+++ b/static/img/print-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/share-icon.svg b/static/img/share-icon.svg
new file mode 100644
index 000000000..30f1ba9af
--- /dev/null
+++ b/static/img/share-icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/static/img/twitter-dark-icon.svg b/static/img/twitter-dark-icon.svg
new file mode 100644
index 000000000..b25f0739e
--- /dev/null
+++ b/static/img/twitter-dark-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/img/twitter-light-icon.svg b/static/img/twitter-light-icon.svg
new file mode 100644
index 000000000..0114e5a3c
--- /dev/null
+++ b/static/img/twitter-light-icon.svg
@@ -0,0 +1,3 @@
+