Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 23, 2025

Overview

This PR adds a "Copy entire file" button next to the dictation instructions link in the Authoring Agentic Workflows documentation page. Users can now easily copy the full contents of the dictation instructions file to their clipboard with a single click.

Implementation

The solution uses a pure Astro component with vanilla JavaScript to avoid SSR/static generation complexities:

1. Copy Button Component (docs/src/components/CopyEntireFileButton.astro)

  • Fetches file content directly from the raw GitHub URL at runtime
  • Uses modern Clipboard API with fallback for older browsers
  • Provides visual feedback during copy operation:
    • Default state: "Copy full instructions"
    • Loading: "Copying…"
    • Success: "Copied!" (resets after 2s)
    • Error: "Error" (resets after 3s)
  • Styled with Starlight CSS variables for consistent theming

2. Documentation Update

  • Converted docs/src/content/docs/tools/agentic-authoring.md to .mdx to support component imports
  • Added copy button inline with existing dictation instructions link
  • Button fetches content from https://raw.githubusercontent.com/githubnext/gh-aw/main/.github/instructions/dictation.instructions.md
  • Maintains existing link for users who prefer to view the file in browser

Screenshot

The button appears inline with the text in the "Dictating Agentic Workflows" section, styled consistently with the Starlight theme.

Technical Notes

  • Initially attempted React integration but encountered SSR/static generation issues with the "No matching renderer" error
  • Pivoted to pure Astro component solution which works seamlessly with static site generation
  • Uses raw GitHub URL directly instead of custom API endpoint for simplicity and better performance
  • Leverages GitHub's CDN and caching infrastructure
  • No additional runtime dependencies required
  • All 35 documentation pages build successfully
  • Component is fully accessible with proper ARIA labels

Testing

  • ✅ Build verification: npm run build completes successfully
  • ✅ Local dev server testing: Button renders correctly
  • ✅ Raw GitHub URL accessibility: File content fetched successfully
  • ✅ Functionality testing: Copy operation works in modern browsers
Original prompt

Here’s a concise implementation plan and code to add a “Copy entire file” button next to the instruction link in the dictation documentation, using a React component loaded in Astro Starlight. It will copy the entire contents of dictation.instructions.md.

Overview

  • Create a small React component that fetches /docs/dictation.instructions.md (or the correct public path) at runtime and copies it to clipboard.
  • Load the component on the dictation documentation page using Starlight’s MDX/MDX partial or Astro integration.
  • Place the button next to the existing instruction link.
  1. React component: CopyEntireFileButton.tsx
  • Place under: src/components/CopyEntireFileButton.tsx

Code:
import React, { useState, useCallback } from 'react';

type Props = {
filePath: string; // e.g. '/docs/dictation.instructions.md'
label?: string; // optional button text
};

export default function CopyEntireFileButton({ filePath, label = 'Copy instructions' }: Props) {
const [status, setStatus] = useState<'idle' | 'copying' | 'success' | 'error'>('idle');

const handleCopy = useCallback(async () => {
try {
setStatus('copying');
const res = await fetch(filePath, { cache: 'no-store' });
if (!res.ok) throw new Error(Failed to fetch file: ${res.status});
const text = await res.text();

  // Prefer Async Clipboard API
  if (navigator.clipboard && window.isSecureContext) {
    await navigator.clipboard.writeText(text);
  } else {
    // Fallback
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.top = '-9999px';
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand('copy');
    document.body.removeChild(textarea);
  }

  setStatus('success');
  setTimeout(() => setStatus('idle'), 2000);
} catch (e) {
  console.error(e);
  setStatus('error');
  setTimeout(() => setStatus('idle'), 3000);
}

}, [filePath]);

const textByStatus: Record<typeof status, string> = {
idle: label,
copying: 'Copying…',
success: 'Copied!',
error: 'Error',
};

return (
<button
type="button"
onClick={handleCopy}
aria-label="Copy entire instructions file to clipboard"
title="Copy entire instructions file to clipboard"
disabled={status === 'copying'}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '0.4rem',
padding: '0.4rem 0.6rem',
borderRadius: '6px',
border: '1px solid var(--sl-color-hairline)',
background: 'var(--sl-color-bg)',
color: 'var(--sl-color-text)',
cursor: 'pointer',
}}
>



{textByStatus[status]}

);
}

  1. Make the file accessible to the client
  • Ensure dictation.instructions.md is fetchable by the site. You have two common options:
    a) If dictation.instructions.md is part of the built docs site at a known URL (e.g., /docs/dictation.instructions/), fetch that route’s raw source is tricky since the built page is HTML. Instead, add a raw copy under public, or expose the raw content via an endpoint.
    b) Easiest: add a build step that copies the raw source to public for fetch:
    • Place a copy of the source file at: public/docs/dictation.instructions.md
    • Then use filePath="/docs/dictation.instructions.md" in the component.

If you prefer not to duplicate files, create an Astro endpoint to return the raw source:

  • File: src/pages/api/dictation-instructions.txt.ts

// Astro endpoint returning the raw instructions
import type { APIRoute } from 'astro';
import fs from 'node:fs/promises';
import path from 'node:path';

export const GET: APIRoute = async () => {
const file = path.resolve(import.meta.env.PROJECT_ROOT || process.cwd(), 'docs/dictation.instructions.md');
try {
const content = await fs.readFile(file, 'utf8');
return new Response(content, {
status: 200,
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
} catch (e) {
return new Response('Not found', { status: 404 });
}
};

  • Then set filePath="/api/dictation-instructions.txt".
  1. Use the component in the dictation documentation
  • If your Starlight pages are MDX/Markdown, you can import the component and place it inline next to the link.

In docs/dictation.md (or wherever the dictation page lives):

title: Dictation

Instructions

import CopyEntireFileButton from '@/components/CopyEntireFileButton.tsx';

{/* Place the button next to the instr...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits October 23, 2025 22:59
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add copy entire file button to dictation documentation Add copy button for dictation instructions in documentation Oct 23, 2025
Copilot AI requested a review from pelikhan October 23, 2025 23:05
@@ -0,0 +1,22 @@
import type { APIRoute } from 'astro';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use the raw GitHub URL directly. Removed the custom API endpoint and simplified the implementation. (06a0786)

Updated implementation

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 23, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • telemetry.astro.build
    • Triggering command: node /home/REDACTED/work/gh-aw/gh-aw/docs/node_modules/.bin/astro build (dns block)
    • Triggering command: node /home/REDACTED/work/gh-aw/gh-aw/docs/node_modules/.bin/astro preview (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from pelikhan October 23, 2025 23:22
@pelikhan pelikhan marked this pull request as ready for review October 23, 2025 23:23
@github-actions
Copy link
Contributor

Agentic Changeset Generator triggered by this pull request.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pelikhan pelikhan merged commit c5a8e3f into main Oct 23, 2025
4 checks passed
@pelikhan pelikhan deleted the copilot/add-copy-file-button branch October 23, 2025 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants