PageTitle.astro 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. ---
  2. import Default from '@astrojs/starlight/components/PageTitle.astro';
  3. const { entry } = Astro.locals.starlightRoute;
  4. const rawPath = `/raw/${entry.id || 'index'}.md`;
  5. ---
  6. <Default><slot /></Default>
  7. <div class="page-actions" data-page-actions data-raw-path={rawPath}>
  8. <button type="button" data-copy-page aria-label="Copy this page as Markdown">
  9. <svg aria-hidden="true" viewBox="0 0 24 24" width="15" height="15">
  10. <path d="M8 7V5a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-2M5 7h9a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z" />
  11. </svg>
  12. <span data-copy-label>Copy page</span>
  13. </button>
  14. <a href={rawPath} target="_blank" rel="noreferrer">View Markdown</a>
  15. </div>
  16. <script>
  17. document.addEventListener('click', async (event) => {
  18. const button = (event.target as HTMLElement).closest<HTMLButtonElement>('[data-copy-page]');
  19. if (!button) return;
  20. const actions = button.closest<HTMLElement>('[data-page-actions]');
  21. const label = button.querySelector<HTMLElement>('[data-copy-label]');
  22. const rawPath = actions?.dataset.rawPath;
  23. if (!rawPath || !label) return;
  24. try {
  25. const response = await fetch(rawPath);
  26. if (!response.ok) throw new Error('Markdown source unavailable');
  27. await navigator.clipboard.writeText(await response.text());
  28. label.textContent = 'Copied';
  29. } catch {
  30. label.textContent = 'Copy failed';
  31. }
  32. window.setTimeout(() => (label.textContent = 'Copy page'), 1600);
  33. });
  34. </script>
  35. <style>
  36. .page-actions {
  37. align-items: center;
  38. display: flex;
  39. flex-wrap: wrap;
  40. gap: 0.5rem;
  41. margin-block: 1rem 0;
  42. }
  43. button,
  44. a {
  45. align-items: center;
  46. background: var(--sl-color-bg-nav);
  47. border: 1px solid var(--sl-color-gray-5);
  48. border-radius: 0.5rem;
  49. color: var(--sl-color-gray-2);
  50. cursor: pointer;
  51. display: inline-flex;
  52. font: 600 0.72rem/1 var(--sl-font-system-mono);
  53. gap: 0.45rem;
  54. min-height: 2rem;
  55. padding: 0.48rem 0.68rem;
  56. text-decoration: none;
  57. transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
  58. }
  59. button:hover,
  60. a:hover {
  61. background: var(--sl-color-gray-6);
  62. border-color: var(--sl-color-accent);
  63. color: var(--sl-color-white);
  64. }
  65. button:focus-visible,
  66. a:focus-visible {
  67. outline: 2px solid var(--sl-color-accent);
  68. outline-offset: 2px;
  69. }
  70. svg {
  71. fill: none;
  72. stroke: currentColor;
  73. stroke-linecap: round;
  74. stroke-linejoin: round;
  75. stroke-width: 1.8;
  76. }
  77. </style>