diff --git a/docusaurus/src/components/GitHubStars/index.js b/docusaurus/src/components/GitHubStars/index.js
new file mode 100644
index 00000000..9843476a
--- /dev/null
+++ b/docusaurus/src/components/GitHubStars/index.js
@@ -0,0 +1,82 @@
+import React, {useState, useEffect} from 'react';
+import styles from './styles.module.css';
+
+const REPO = 'devoxx/DevoxxGenieIDEAPlugin';
+const CACHE_KEY = 'devoxxgenie_github_stars';
+const CACHE_TTL = 3600000; // 1 hour in milliseconds
+
+function formatStars(count) {
+ if (count >= 1000) {
+ return (count / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
+ }
+ return count.toLocaleString();
+}
+
+export default function GitHubStars() {
+ const [stars, setStars] = useState(null);
+
+ useEffect(() => {
+ // Check localStorage cache first
+ try {
+ const cached = JSON.parse(localStorage.getItem(CACHE_KEY));
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
+ setStars(cached.count);
+ return;
+ }
+ } catch {
+ // ignore parse errors
+ }
+
+ fetch(`https://api.github.com/repos/${REPO}`)
+ .then((res) => {
+ if (!res.ok) throw new Error('GitHub API error');
+ return res.json();
+ })
+ .then((data) => {
+ const count = data.stargazers_count;
+ setStars(count);
+ try {
+ localStorage.setItem(
+ CACHE_KEY,
+ JSON.stringify({count, timestamp: Date.now()})
+ );
+ } catch {
+ // ignore storage errors
+ }
+ })
+ .catch(() => {
+ // On error, show cached value if available (even if expired)
+ try {
+ const cached = JSON.parse(localStorage.getItem(CACHE_KEY));
+ if (cached) setStars(cached.count);
+ } catch {
+ // ignore
+ }
+ });
+ }, []);
+
+ if (stars === null) return null;
+
+ return (
+
+
+ {formatStars(stars)}
+ Stars
+
+ );
+}
diff --git a/docusaurus/src/components/GitHubStars/styles.module.css b/docusaurus/src/components/GitHubStars/styles.module.css
new file mode 100644
index 00000000..4cd4a0ce
--- /dev/null
+++ b/docusaurus/src/components/GitHubStars/styles.module.css
@@ -0,0 +1,45 @@
+.starBadge {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 8px 16px;
+ border-radius: 8px;
+ background: rgba(255, 255, 255, 0.15);
+ backdrop-filter: blur(4px);
+ border: 1px solid rgba(255, 255, 255, 0.3);
+ color: #fff;
+ font-size: 0.95rem;
+ font-weight: 600;
+ text-decoration: none;
+ transition: background 0.2s ease, transform 0.2s ease;
+ cursor: pointer;
+ margin-left: 12px;
+}
+
+.starBadge:hover {
+ background: rgba(255, 255, 255, 0.25);
+ transform: translateY(-1px);
+ color: #fff;
+ text-decoration: none;
+}
+
+.starIcon {
+ color: #ffd700;
+ flex-shrink: 0;
+}
+
+.starCount {
+ font-variant-numeric: tabular-nums;
+}
+
+.starLabel {
+ opacity: 0.85;
+ font-weight: 400;
+}
+
+@media (max-width: 600px) {
+ .starBadge {
+ margin-left: 0;
+ margin-top: 10px;
+ }
+}
diff --git a/docusaurus/src/pages/index.js b/docusaurus/src/pages/index.js
index 9830fd6a..acb1dabd 100644
--- a/docusaurus/src/pages/index.js
+++ b/docusaurus/src/pages/index.js
@@ -6,6 +6,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import Layout from '@theme/Layout';
import Head from '@docusaurus/Head';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
+import GitHubStars from '@site/src/components/GitHubStars';
const softwareSchema = {
'@context': 'https://schema.org',
@@ -55,6 +56,7 @@ function HomepageHeader() {
to={useBaseUrl('/docs/getting-started/introduction')}>
Get Started with DevoxxGenie
+