From c6b6703121f67b4f314bc9eb894eeb13bac91f48 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Feb 2026 04:16:18 +0000 Subject: [PATCH 1/3] feat: add portfolio link to backend sidebar menu Adds a Portfolio navigation item in the Site section of the backend dashboard, allowing easy access to the portfolio page via iframe. https://claude.ai/code/session_0138bAjho1fWwiRZju3nJFJ3 --- backend.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend.html b/backend.html index 6b6dd9683..94d3b7328 100644 --- a/backend.html +++ b/backend.html @@ -319,6 +319,12 @@

Supabase Integration

Reader + + + + + Portfolio + From 0c3e060d687405ddaa5144646880780a1db11493 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Feb 2026 06:26:18 +0000 Subject: [PATCH 2/3] fix: multiple improvements to backend and portfolio - Create docs.html with markdown parsing via GitHub API - Fix backend: bypass login (Supabase not configured), link to docs.html - Fix portfolio: repo count shows only non-fork repos - Fix footer links: point to ThePhoenixAgency.github.io https://claude.ai/code/session_0138bAjho1fWwiRZju3nJFJ3 --- about.html | 2 +- backend.html | 12 +- docs.html | 406 +++++++++++++++++++++++++++++++++++++++++++++++++ portfolio.html | 43 +++--- 4 files changed, 435 insertions(+), 28 deletions(-) create mode 100644 docs.html diff --git a/about.html b/about.html index 55c9abffe..0c0ab1df3 100644 --- a/about.html +++ b/about.html @@ -144,7 +144,7 @@

Privacy First

Portfolio - ThePhoenixAgency + ThePhoenixAgency GitHub diff --git a/backend.html b/backend.html index 94d3b7328..f0f750f03 100644 --- a/backend.html +++ b/backend.html @@ -327,11 +327,11 @@

Supabase Integration

- + - Technical Docs + Documentation @@ -405,12 +405,10 @@

Active Today

const dashboardView = document.getElementById('dashboard-view'); const pageTitle = document.getElementById('page-title'); - // Check if already logged in + // Check if already logged in - bypass login for now function checkSession() { - const session = localStorage.getItem('supabase_session'); - if (session) { - showDashboard(); - } + // Always show dashboard (Supabase not configured) + showDashboard(); } // Login handler diff --git a/docs.html b/docs.html new file mode 100644 index 000000000..574fbcd87 --- /dev/null +++ b/docs.html @@ -0,0 +1,406 @@ + + + + + + + Documentation | AI-Pulse + + + + + + + + + + + +
+
+ + + + +
+
+
+

Loading documentation...

+
+
+
+
+ +
+ + +
+ + + + + + + + + + diff --git a/portfolio.html b/portfolio.html index 5c76e6a18..094273f95 100644 --- a/portfolio.html +++ b/portfolio.html @@ -309,7 +309,7 @@

About

Statistics - ThePhoenixAgency + ThePhoenixAgency GitHub @@ -415,35 +415,38 @@

About

const loading = document.getElementById('loadingProjects'); try { - // Fetch org stats - const orgResponse = await fetch(`https://api.github.com/orgs/${PORTFOLIO_CONFIG.githubOrg}`); - if (orgResponse.ok) { - const orgData = await orgResponse.json(); - const reposEl = document.getElementById('totalRepos'); - const followersEl = document.getElementById('totalFollowers'); - const followingEl = document.getElementById('totalFollowing'); - - if (reposEl) reposEl.textContent = String(orgData.public_repos || 0); - if (followersEl) followersEl.textContent = String(orgData.followers || 0); - if (followingEl) followingEl.textContent = String(orgData.following || 0); - } - - // Fetch repos + // Fetch repos first (single API call for all data) const reposResponse = await fetch(`https://api.github.com/orgs/${PORTFOLIO_CONFIG.githubOrg}/repos?per_page=100`); if (!reposResponse.ok) throw new Error('Failed to fetch repos'); let repos = await reposResponse.json(); if (!Array.isArray(repos)) throw new Error('Invalid response'); - // Calculate total stars + // Filter: hide forks FIRST before counting + if (PORTFOLIO_CONFIG.hideForks) { + repos = repos.filter(r => !r.fork); + } + + // Now count repos (only non-forks) + const reposEl = document.getElementById('totalRepos'); + if (reposEl) reposEl.textContent = String(repos.length); + + // Calculate total stars (only from non-fork repos) const totalStars = repos.reduce((sum, r) => sum + (r.stargazers_count || 0), 0); const starsEl = document.getElementById('totalStars'); if (starsEl) starsEl.textContent = String(totalStars); - // Filter: hide forks - if (PORTFOLIO_CONFIG.hideForks) { - repos = repos.filter(r => !r.fork); - } + // Fetch org stats for followers/following only + fetch(`https://api.github.com/orgs/${PORTFOLIO_CONFIG.githubOrg}`) + .then(r => r.ok ? r.json() : null) + .then(orgData => { + if (orgData) { + const followersEl = document.getElementById('totalFollowers'); + const followingEl = document.getElementById('totalFollowing'); + if (followersEl) followersEl.textContent = String(orgData.followers || 0); + if (followingEl) followingEl.textContent = String(orgData.following || 0); + } + }); // Filter: exclude specific projects repos = repos.filter(r => !PORTFOLIO_CONFIG.excludeProjects.includes(r.name)); From 9c24f88f327b4431d781daaf70f4875daab29069 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Feb 2026 06:28:26 +0000 Subject: [PATCH 3/3] feat: add viewer for external links + sticky section anchors - Create viewer.html to display GitHub repos with template styling - Update portfolio to open project links in viewer instead of new tabs - Add section anchors sidebar in docs.html with sticky navigation - Generate anchor IDs from markdown headings https://claude.ai/code/session_0138bAjho1fWwiRZju3nJFJ3 --- docs.html | 75 +++++++++++- portfolio.html | 6 +- viewer.html | 308 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+), 10 deletions(-) create mode 100644 viewer.html diff --git a/docs.html b/docs.html index 574fbcd87..25639930e 100644 --- a/docs.html +++ b/docs.html @@ -25,7 +25,38 @@ border: 1px solid rgba(255, 255, 255, 0.08); height: fit-content; position: sticky; - top: 100px; + top: 20px; + max-height: calc(100vh - 40px); + overflow-y: auto; + } + + .section-anchors { + margin-top: 20px; + padding-top: 15px; + border-top: 1px solid rgba(255, 255, 255, 0.1); + } + + .section-anchors h4 { + color: var(--text-dim); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 10px; + } + + .section-anchors a { + display: block; + padding: 6px 10px; + color: var(--text-dim); + text-decoration: none; + font-size: 0.85rem; + border-radius: 4px; + transition: all 0.2s; + } + + .section-anchors a:hover { + background: rgba(0, 217, 255, 0.1); + color: var(--primary); } .docs-sidebar h3 { @@ -216,6 +247,10 @@

Documentation

Supabase Setup GitHub Actions +
+

On this page

+ +
@@ -265,9 +300,17 @@

Documentation

const docsNav = document.getElementById('docsNav'); const docsContent = document.getElementById('docsContent'); - // Simple markdown to HTML parser + const sectionAnchors = document.getElementById('sectionAnchors'); + + // Generate slug from text + function slugify(text) { + return text.toLowerCase().replace(/[^\w]+/g, '-').replace(/^-|-$/g, ''); + } + + // Simple markdown to HTML parser with anchor generation function parseMarkdown(md) { let html = md; + const anchors = []; // Escape HTML first html = html.replace(/&/g, '&') @@ -282,10 +325,21 @@

Documentation

// Inline code html = html.replace(/`([^`]+)`/g, '$1'); - // Headers - html = html.replace(/^### (.+)$/gm, '

$1

'); - html = html.replace(/^## (.+)$/gm, '

$1

'); - html = html.replace(/^# (.+)$/gm, '

$1

'); + // Headers with IDs for anchoring + html = html.replace(/^### (.+)$/gm, (match, title) => { + const id = slugify(title); + return `

${title}

`; + }); + html = html.replace(/^## (.+)$/gm, (match, title) => { + const id = slugify(title); + anchors.push({ id, title, level: 2 }); + return `

${title}

`; + }); + html = html.replace(/^# (.+)$/gm, (match, title) => { + const id = slugify(title); + anchors.push({ id, title, level: 1 }); + return `

${title}

`; + }); // Bold and italic html = html.replace(/\*\*(.+?)\*\*/g, '$1'); @@ -321,6 +375,15 @@

Documentation

return block; }).join('\n'); + // Update section anchors sidebar + if (anchors.length > 0) { + sectionAnchors.innerHTML = '

On this page

' + + anchors.map(a => `${a.title}`).join(''); + sectionAnchors.style.display = 'block'; + } else { + sectionAnchors.style.display = 'none'; + } + return html; } diff --git a/portfolio.html b/portfolio.html index 094273f95..ebbd00a51 100644 --- a/portfolio.html +++ b/portfolio.html @@ -232,7 +232,7 @@

ThePhoenixAgency

AI & Cybersecurity Specialist | Full Stack Developer | Open Source