From 8fe35e3acb6ee87abd83b7cb24f36c88824a7cae Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 28 Sep 2025 15:39:27 +0530 Subject: [PATCH] added new features --- src/theme/DocItem/DocContent.js | 113 +++++++++++++++++++ src/theme/DocItem/DocsInfo.js | 89 +++++++++++++++ src/theme/DocItem/DocsRating.js | 82 ++++++++++++++ src/theme/DocItem/Layout.js | 61 +++++++++++ src/theme/DocItem/ShareButton.js | 75 +++++++++++++ src/theme/DocItem/index.js | 25 +++++ src/theme/DocItem/shareButton.module.css | 67 ++++++++++++ src/theme/DocItem/styles.module.css | 131 +++++++++++++++++++++++ static/img/bug-icon.svg | 10 ++ static/img/email-dark-icon.svg | 3 + static/img/email-light-icon.svg | 3 + static/img/facebook-dark-icon.svg | 10 ++ static/img/facebook-light-icon.svg | 10 ++ static/img/linkedin-dark-icon.svg | 3 + static/img/linkedin-light-icon.svg | 3 + static/img/print-icon.svg | 3 + static/img/share-icon.svg | 10 ++ static/img/twitter-dark-icon.svg | 3 + static/img/twitter-light-icon.svg | 3 + 19 files changed, 704 insertions(+) create mode 100644 src/theme/DocItem/DocContent.js create mode 100644 src/theme/DocItem/DocsInfo.js create mode 100644 src/theme/DocItem/DocsRating.js create mode 100644 src/theme/DocItem/Layout.js create mode 100644 src/theme/DocItem/ShareButton.js create mode 100644 src/theme/DocItem/index.js create mode 100644 src/theme/DocItem/shareButton.module.css create mode 100644 src/theme/DocItem/styles.module.css create mode 100644 static/img/bug-icon.svg create mode 100644 static/img/email-dark-icon.svg create mode 100644 static/img/email-light-icon.svg create mode 100644 static/img/facebook-dark-icon.svg create mode 100644 static/img/facebook-light-icon.svg create mode 100644 static/img/linkedin-dark-icon.svg create mode 100644 static/img/linkedin-light-icon.svg create mode 100644 static/img/print-icon.svg create mode 100644 static/img/share-icon.svg create mode 100644 static/img/twitter-dark-icon.svg create mode 100644 static/img/twitter-light-icon.svg 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 && ( +
+

{title}

+
+ )} + {(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!
+ ) : ( +
+

Thanks for your feedback! Need help or have suggestions?

+

+ • Ask a question on our{" "} + + Discord Channel + +
+ • Report a problem
+ • Suggest an improvement +

+
+ ) + ) : ( +
+

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 @@ + + +