From 69cc115c46fe0e51e0f24e0ec47b45cbf943f92d Mon Sep 17 00:00:00 2001 From: JxM Date: Mon, 20 Oct 2025 17:23:07 +0200 Subject: [PATCH 1/5] fix social icons --- astro.config.mjs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index 26373eab..f5682c91 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -63,9 +63,13 @@ export default defineConfig({ Header: "./src/components/Header.astro", PageSidebar: "./src/components/PageSidebar.astro", }, - social: { - github: "https://github.com/interledger", - }, + social: [ + { + icon: "github", + label: "GitHub", + href: "https://github.com/interledger" + }, + ], sidebar: [ { label: "Overview", From 292df49fa958e90cf9ba64f1569a2cc998326e47 Mon Sep 17 00:00:00 2001 From: JxM Date: Mon, 20 Oct 2025 18:21:22 +0200 Subject: [PATCH 2/5] fix social icons --- astro.config.mjs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index f5682c91..26373eab 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -63,13 +63,9 @@ export default defineConfig({ Header: "./src/components/Header.astro", PageSidebar: "./src/components/PageSidebar.astro", }, - social: [ - { - icon: "github", - label: "GitHub", - href: "https://github.com/interledger" - }, - ], + social: { + github: "https://github.com/interledger", + }, sidebar: [ { label: "Overview", From 8d63df4ff96b9eb95d83dca30214e5825e9a3a16 Mon Sep 17 00:00:00 2001 From: JxM Date: Mon, 20 Oct 2025 18:24:47 +0200 Subject: [PATCH 3/5] feat: starlight docs pages feedback module --- astro.config.mjs | 1 + src/components/FeedbackWidget.astro | 257 ++++++++++++++++++++++++++++ src/components/Footer.astro | 12 ++ src/components/PageSidebar.astro | 2 +- 4 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 src/components/FeedbackWidget.astro create mode 100644 src/components/Footer.astro diff --git a/astro.config.mjs b/astro.config.mjs index 26373eab..a851cf33 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -62,6 +62,7 @@ export default defineConfig({ components: { Header: "./src/components/Header.astro", PageSidebar: "./src/components/PageSidebar.astro", + Footer: "./src/components/Footer.astro", }, social: { github: "https://github.com/interledger", diff --git a/src/components/FeedbackWidget.astro b/src/components/FeedbackWidget.astro new file mode 100644 index 00000000..79614bd8 --- /dev/null +++ b/src/components/FeedbackWidget.astro @@ -0,0 +1,257 @@ +--- +// Simple feedback widget that works without external services +// Feedback can be sent via GitHub Issues or collected locally +const { lang = 'en' } = Astro.props; + +const translations = { + en: { + question: "Was this page helpful?", + yes: "Yes", + no: "No", + thanks: "Thanks for your feedback!", + improve: "Help us improve", + improvePlaceholder: "What can we improve?", + submit: "Submit", + submitting: "Submitting...", + }, + es: { + question: "¿Fue útil esta página?", + yes: "Sí", + no: "No", + thanks: "¡Gracias por tu comentario!", + improve: "Ayúdanos a mejorar", + improvePlaceholder: "¿Qué podemos mejorar?", + submit: "Enviar", + submitting: "Enviando...", + } +}; + +const t = translations[lang as keyof typeof translations] || translations.en; +--- + + + + + + diff --git a/src/components/Footer.astro b/src/components/Footer.astro new file mode 100644 index 00000000..b14c5a05 --- /dev/null +++ b/src/components/Footer.astro @@ -0,0 +1,12 @@ +--- +import type { Props } from '@astrojs/starlight/props'; +import Default from '@astrojs/starlight/components/Footer.astro'; +import FeedbackWidget from './FeedbackWidget.astro'; +import { getLangFromUrl } from '../i18n/utils'; + +const lang = getLangFromUrl(Astro.url); +--- + + + + diff --git a/src/components/PageSidebar.astro b/src/components/PageSidebar.astro index 8561a284..18f4f09f 100644 --- a/src/components/PageSidebar.astro +++ b/src/components/PageSidebar.astro @@ -10,7 +10,7 @@ const toc = noOverview && Astro.props.toc !== undefined ? { ...Astro.props.toc, items: Astro.props.toc?.items.slice(1), - } + } : Astro.props.toc; --- From ec2f239258fb8c341d897e56cef3a01fe1c6a59e Mon Sep 17 00:00:00 2001 From: JxM Date: Mon, 20 Oct 2025 19:14:55 +0200 Subject: [PATCH 4/5] feat: add GitHub API integration for feedback widget --- .env.example | 4 ++ FEEDBACK_INTEGRATION_GUIDE.md | 30 +++++++++ astro.config.mjs | 1 + src/components/FeedbackWidget.astro | 95 +++++++++++++++++++++++---- src/pages/api/feedback.ts | 99 +++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 .env.example create mode 100644 FEEDBACK_INTEGRATION_GUIDE.md create mode 100644 src/pages/api/feedback.ts diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..654eb00a --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +# GitHub Personal Access Token for Feedback Widget +# Create a token at: https://github.com/settings/tokens/new +# Required scopes: public_repo (for public repositories) +GITHUB_TOKEN=ghp_your_github_token_here diff --git a/FEEDBACK_INTEGRATION_GUIDE.md b/FEEDBACK_INTEGRATION_GUIDE.md new file mode 100644 index 00000000..33bba546 --- /dev/null +++ b/FEEDBACK_INTEGRATION_GUIDE.md @@ -0,0 +1,30 @@ +# Feedback Widget - GitHub Issues Integration + +The feedback widget is **fully integrated with GitHub Issues**. When users submit feedback, it automatically creates an issue in your repository. + +## 🚀 Quick Setup (5 minutes) + +### Step 1: Create a GitHub Personal Access Token + +1. Go to: https://github.com/settings/tokens/new +2. Give it a name: "Interledger Docs Feedback" +3. Select expiration (recommend: 90 days or No expiration) +4. Select scopes: **`public_repo`** (for public repositories) +5. Click "Generate token" +6. **Copy the token** (you won't see it again!) + +### Step 2: Add Token to Environment Variables + +Create a `.env` file in your project root: + +```bash +cp .env.example .env +``` + +Edit `.env` and add your token: + +```env +GITHUB_TOKEN=ghp_your_actual_token_here +``` + +⚠️ **Important:** Make sure `.env` is in your `.gitignore` (it should be by default) diff --git a/astro.config.mjs b/astro.config.mjs index a851cf33..431499c1 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -6,6 +6,7 @@ import mdx from "@astrojs/mdx"; // https://astro.build/config export default defineConfig({ + output: 'server', site: "https://interledger.org", base: "/developers", i18n: { diff --git a/src/components/FeedbackWidget.astro b/src/components/FeedbackWidget.astro index 79614bd8..024bd351 100644 --- a/src/components/FeedbackWidget.astro +++ b/src/components/FeedbackWidget.astro @@ -219,22 +219,59 @@ const t = translations[lang as keyof typeof translations] || translations.en; // Disable button while submitting submitBtn.disabled = true; + const originalText = submitBtn.textContent; submitBtn.textContent = submitBtn.getAttribute('data-submitting') || 'Submitting...'; try { - // Log to console (in production, you could send to GitHub Issues API or analytics) - console.log('Feedback submitted:', { - type: selectedFeedback, - page: page, - message: feedback, - timestamp: new Date().toISOString() + // Send to GitHub Issues API with timeout + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout + + const response = await fetch('/developers/api/feedback', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: selectedFeedback, + page: page, + message: feedback, + }), + signal: controller.signal }); - // You can implement actual submission here: - // - Create a GitHub issue via API - // - Send to Google Forms - // - Send to your own API endpoint - // - Store in localStorage for later review + clearTimeout(timeoutId); + + const result = await response.json(); + + if (!response.ok || !result.success) { + // If GitHub token not configured, fall back to opening GitHub issue page + if (result.error?.includes('not configured') || result.error?.includes('token')) { + const emoji = selectedFeedback === 'yes' ? '👍' : '👎'; + const title = encodeURIComponent(`[Feedback] ${emoji} ${page}`); + const body = encodeURIComponent(`**Page:** ${page} +**Feedback Type:** ${selectedFeedback === 'yes' ? 'Positive 👍' : 'Negative 👎'} +**User Message:** + +${feedback || '_No additional feedback provided_'}`); + + const issueUrl = `https://github.com/JonathanMatthey/ilp-docs-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; + + window.open(issueUrl, '_blank'); + + feedbackForm?.classList.add('hidden'); + feedbackSuccess?.classList.remove('hidden'); + return; + } + + throw new Error(result.error || 'Failed to submit feedback'); + } + + // Log success + console.log('Feedback submitted successfully:', { + issueNumber: result.issueNumber, + issueUrl: result.issueUrl + }); // Show success message feedbackForm?.classList.add('hidden'); @@ -244,14 +281,44 @@ const t = translations[lang as keyof typeof translations] || translations.en; if (typeof window !== 'undefined' && (window as any).umami) { (window as any).umami.track('feedback', { type: selectedFeedback, - hasMessage: feedback.length > 0 + hasMessage: feedback.length > 0, + success: true }); } + } catch (error) { console.error('Error submitting feedback:', error); + + // Re-enable button submitBtn.disabled = false; - submitBtn.textContent = 'Submit'; - alert('Failed to submit feedback. Please try again.'); + submitBtn.textContent = originalText; + + // Show error message + const errorMsg = error instanceof Error && error.name === 'AbortError' + ? 'Request timed out. Opening GitHub issue page instead...' + : 'Failed to submit feedback. Opening GitHub issue page...'; + + alert(errorMsg); + + // Fallback: Open GitHub issue page + const emoji = selectedFeedback === 'yes' ? '👍' : '👎'; + const title = encodeURIComponent(`[Feedback] ${emoji} ${page}`); + const body = encodeURIComponent(`**Page:** ${page} +**Feedback Type:** ${selectedFeedback === 'yes' ? 'Positive 👍' : 'Negative 👎'} +**User Message:** + +${feedback || '_No additional feedback provided_'}`); + + const issueUrl = `https://github.com/JonathanMatthey/ilp-docs-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; + window.open(issueUrl, '_blank'); + + // Track error with Umami if available + if (typeof window !== 'undefined' && (window as any).umami) { + (window as any).umami.track('feedback-error', { + type: selectedFeedback, + error: error instanceof Error ? error.message : 'Unknown error' + }); + } } }); diff --git a/src/pages/api/feedback.ts b/src/pages/api/feedback.ts new file mode 100644 index 00000000..bbfc485a --- /dev/null +++ b/src/pages/api/feedback.ts @@ -0,0 +1,99 @@ +import type { APIRoute } from 'astro'; + +// Mark this endpoint as server-rendered +export const prerender = false; + +export const POST: APIRoute = async ({ request }) => { + try { + const data = await request.json(); + const { type, page, message } = data; + + // Get GitHub token from environment variable + const GITHUB_TOKEN = import.meta.env.GITHUB_TOKEN; + const GITHUB_REPO = 'JonathanMatthey/ilp-docs-feedback'; + + if (!GITHUB_TOKEN) { + console.error('GITHUB_TOKEN not configured'); + return new Response( + JSON.stringify({ + success: false, + error: 'GitHub token not configured' + }), + { + status: 500, + headers: { 'Content-Type': 'application/json' } + } + ); + } + + // Create issue title and body + const emoji = type === 'yes' ? '👍' : '👎'; + const sentiment = type === 'yes' ? 'Positive' : 'Negative'; + const issueTitle = `[Feedback] ${emoji} ${page}`; + + const issueBody = `**Page:** ${page} +**Feedback Type:** ${sentiment} ${emoji} +**User Message:** + +${message || '_No additional feedback provided_'} + +--- +_Submitted via feedback widget on ${new Date().toISOString()}_`; + + // Create GitHub issue + const response = await fetch( + `https://api.github.com/repos/${GITHUB_REPO}/issues`, + { + method: 'POST', + headers: { + 'Authorization': `token ${GITHUB_TOKEN}`, + 'Accept': 'application/vnd.github.v3+json', + 'Content-Type': 'application/json', + 'User-Agent': 'Interledger-Docs-Feedback-Widget' + }, + body: JSON.stringify({ + title: issueTitle, + body: issueBody, + labels: [ + 'feedback', + 'docs', + type === 'yes' ? 'feedback-positive' : 'feedback-negative' + ] + }) + } + ); + + if (!response.ok) { + const errorData = await response.text(); + console.error('GitHub API error:', errorData); + throw new Error(`GitHub API returned ${response.status}`); + } + + const issue = await response.json(); + + return new Response( + JSON.stringify({ + success: true, + issueUrl: issue.html_url, + issueNumber: issue.number + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' } + } + ); + + } catch (error) { + console.error('Error creating GitHub issue:', error); + return new Response( + JSON.stringify({ + success: false, + error: error instanceof Error ? error.message : 'Unknown error' + }), + { + status: 500, + headers: { 'Content-Type': 'application/json' } + } + ); + } +}; From 271f45be2e320b5704810b084e921f26c5412623 Mon Sep 17 00:00:00 2001 From: Jon M <> Date: Wed, 5 Nov 2025 10:10:24 -0600 Subject: [PATCH 5/5] fix: update issues repo --- src/components/FeedbackWidget.astro | 4 ++-- src/pages/api/feedback.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/FeedbackWidget.astro b/src/components/FeedbackWidget.astro index 024bd351..ec019123 100644 --- a/src/components/FeedbackWidget.astro +++ b/src/components/FeedbackWidget.astro @@ -255,7 +255,7 @@ const t = translations[lang as keyof typeof translations] || translations.en; ${feedback || '_No additional feedback provided_'}`); - const issueUrl = `https://github.com/JonathanMatthey/ilp-docs-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; + const issueUrl = `https://github.com/interledger/documentation-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; window.open(issueUrl, '_blank'); @@ -309,7 +309,7 @@ ${feedback || '_No additional feedback provided_'}`); ${feedback || '_No additional feedback provided_'}`); - const issueUrl = `https://github.com/JonathanMatthey/ilp-docs-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; + const issueUrl = `https://github.com/interledger/documentation-feedback/issues/new?title=${title}&body=${body}&labels=feedback,docs`; window.open(issueUrl, '_blank'); // Track error with Umami if available diff --git a/src/pages/api/feedback.ts b/src/pages/api/feedback.ts index bbfc485a..a0d67ecc 100644 --- a/src/pages/api/feedback.ts +++ b/src/pages/api/feedback.ts @@ -10,7 +10,7 @@ export const POST: APIRoute = async ({ request }) => { // Get GitHub token from environment variable const GITHUB_TOKEN = import.meta.env.GITHUB_TOKEN; - const GITHUB_REPO = 'JonathanMatthey/ilp-docs-feedback'; + const GITHUB_REPO = 'interledger/documentation-feedback'; if (!GITHUB_TOKEN) { console.error('GITHUB_TOKEN not configured');