| 1 | --- |
| 2 | type Variant = "primary" | "secondary" | "ghost" | "accent"; |
| 3 | type Icon = "github" | "arrow" | "book" | "discord"; |
| 4 | |
| 5 | interface Props { |
| 6 | variant?: Variant; |
| 7 | icon?: Icon; |
| 8 | href?: string; |
| 9 | class?: string; |
| 10 | } |
| 11 | |
| 12 | const { variant = "primary", icon, href = "#", class: className } = Astro.props; |
| 13 | --- |
| 14 | |
| 15 | <a |
| 16 | href={href} |
| 17 | class:list={["alc-btn", `alc-btn--${variant}`, className]} |
| 18 | > |
| 19 | {icon === "github" && ( |
| 20 | <svg aria-hidden width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> |
| 21 | <path |
| 22 | d="M12 .5C5.73.5.5 5.73.5 12c0 5.08 3.29 9.39 7.86 10.91.58.1.79-.25.79-.56 0-.28-.01-1.02-.02-2-3.2.69-3.88-1.54-3.88-1.54-.52-1.33-1.28-1.69-1.28-1.69-1.05-.72.08-.71.08-.71 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.71 1.26 3.37.96.1-.75.4-1.26.73-1.55-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.19-3.1-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18a11.04 11.04 0 0 1 5.79 0c2.21-1.49 3.18-1.18 3.18-1.18.63 1.59.23 2.76.11 3.05.74.81 1.19 1.84 1.19 3.1 0 4.42-2.69 5.39-5.25 5.68.41.36.78 1.07.78 2.16 0 1.56-.01 2.81-.01 3.19 0 .31.21.67.8.56C20.71 21.39 24 17.08 24 12 24 5.73 18.27.5 12 .5z" |
| 23 | ></path> |
| 24 | </svg> |
| 25 | )} |
| 26 | <slot /> |
| 27 | {icon === "arrow" && <span aria-hidden>→</span>} |
| 28 | {icon === "book" && <span aria-hidden>❏</span>} |
| 29 | {icon === "discord" && ( |
| 30 | <svg aria-hidden width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> |
| 31 | <path |
| 32 | d="M20.317 4.369A19.79 19.79 0 0 0 16.558 3.2a.075.075 0 0 0-.079.037c-.34.6-.717 1.384-.98 2-1.797-.27-3.583-.27-5.342 0-.263-.63-.654-1.4-.997-2A.077.077 0 0 0 9.08 3.2a19.736 19.736 0 0 0-3.76 1.169.07.07 0 0 0-.032.027C1.533 9.046.6 13.58 1.057 18.058a.082.082 0 0 0 .031.056 19.9 19.9 0 0 0 5.993 3.029.077.077 0 0 0 .084-.027c.462-.63.873-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.108 13.108 0 0 1-1.872-.892.077.077 0 0 1-.008-.128c.126-.094.252-.192.372-.291a.074.074 0 0 1 .077-.01c3.927 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.099.246.197.373.291a.077.077 0 0 1-.006.128 12.3 12.3 0 0 1-1.873.892.077.077 0 0 0-.04.106c.36.699.772 1.364 1.225 1.994a.076.076 0 0 0 .084.028 19.84 19.84 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.548-13.66a.061.061 0 0 0-.031-.029ZM8.02 15.331c-1.183 0-2.157-1.085-2.157-2.42 0-1.333.956-2.418 2.157-2.418 1.21 0 2.176 1.094 2.157 2.418 0 1.335-.956 2.42-2.157 2.42Zm7.974 0c-1.183 0-2.157-1.085-2.157-2.42 0-1.333.955-2.418 2.157-2.418 1.21 0 2.176 1.094 2.157 2.418 0 1.335-.946 2.42-2.157 2.42Z" |
| 33 | ></path> |
| 34 | </svg> |
| 35 | )} |
| 36 | </a> |
| 37 | |
| 38 | <style> |
| 39 | .alc-btn { |
| 40 | font-family: var(--alc-font-sans); |
| 41 | font-size: 14px; |
| 42 | font-weight: 500; |
| 43 | padding: 10px 18px; |
| 44 | border-radius: 8px; |
| 45 | border: 1px solid transparent; |
| 46 | display: inline-flex; |
| 47 | align-items: center; |
| 48 | gap: 8px; |
| 49 | white-space: nowrap; |
| 50 | cursor: pointer; |
| 51 | text-decoration: none; |
| 52 | transition: |
| 53 | background 120ms var(--alc-ease, cubic-bezier(0.2, 0, 0, 1)), |
| 54 | border-color 120ms var(--alc-ease, cubic-bezier(0.2, 0, 0, 1)), |
| 55 | color 120ms var(--alc-ease, cubic-bezier(0.2, 0, 0, 1)); |
| 56 | } |
| 57 | /* Deep forest instead of var(--alc-accent): mid-green moss cannot reach |
| 58 | the AAA 7:1 contrast ratio with any text color; #3f5a2a gives 7.2:1 |
| 59 | against --alc-fg-on-accent in both themes. */ |
| 60 | .alc-btn--primary { |
| 61 | background: #3f5a2a; |
| 62 | color: var(--alc-fg-on-accent); |
| 63 | } |
| 64 | .alc-btn--primary:hover { |
| 65 | background: #324a1e; |
| 66 | } |
| 67 | /* Secondary: transparent surface with a hairline border. Slimmer |
| 68 | padding than the primary so it doesn't feel oversized when sitting |
| 69 | next to a borderless ghost button. */ |
| 70 | .alc-btn--secondary { |
| 71 | background: transparent; |
| 72 | border-color: var(--alc-hairline-3); |
| 73 | color: var(--alc-fg-1); |
| 74 | padding: 7px 14px; |
| 75 | } |
| 76 | .alc-btn--secondary:hover { |
| 77 | border-color: var(--alc-accent); |
| 78 | color: var(--alc-accent-deep); |
| 79 | } |
| 80 | .alc-btn--ghost { |
| 81 | background: transparent; |
| 82 | color: var(--alc-fg-2); |
| 83 | } |
| 84 | .alc-btn--ghost:hover { |
| 85 | color: var(--alc-accent-deep); |
| 86 | } |
| 87 | .alc-btn--accent { |
| 88 | background: var(--alc-terracotta); |
| 89 | color: var(--alc-fg-on-accent); |
| 90 | } |
| 91 | /* MDX wraps the button's slot text in a <p>, which inherits the UA |
| 92 | stylesheet's 1em block margin (~14px) and bloats the button |
| 93 | vertically. Flatten any <p> inside the button. `display: inline` |
| 94 | keeps the icon + label on one row inside the inline-flex anchor. */ |
| 95 | .alc-btn :global(p) { |
| 96 | margin: 0; |
| 97 | display: inline; |
| 98 | } |
| 99 | </style> |