diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 24aa44bb5..1fb02a9d0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,8 +4,7 @@ This file is automatically synced from docs/pages/contribute/contributing.mdx du
⚠️ DO NOT EDIT THIS FILE DIRECTLY.
Instead, make changes to docs/pages/contribute/contributing.mdx and make this be synced just by running the build command.
-Both files contain the same content: the docs file is there to render the content on the website,
-while this copy is needed to make it highlighted in the repository dashboard.
+Both files contain the same content: the docs file is there to render the content on the website, while this copy is needed to make it highlighted in the repository dashboard.
-->
# **Contributing guidelines**
@@ -279,8 +278,8 @@ the site renders each one as its own section on the page: "Authored by", "Review
the bar is the same one: the page has to be more accurate afterwards than it was before.
The three roles carry the same weight. A page is only as good as the writing, the checking, and the sign-off behind
-it, and the Security Frameworks need all three to be worth trusting. What follows is about describing different kinds of work
-accurately, not about ranking contributors.
+it, and the Security Frameworks need all three to be worth trusting. What follows is about describing different kinds
+of work accurately, not about ranking contributors.
The short version: a reviewer answers "is this page good?", a fact-checker answers "is this statement true?". Both
roles are earned by the work of checking, not by the size of the diff. Text that adds words without settling either
@@ -482,6 +481,9 @@ Pages with minimal content which need more work to cover the topic need to inclu
This page is also open for contributions. Suggest improvements to our style and guidelines in the GitHub repo.
+Funding the work is another way to contribute. [Support the Frameworks](https://securityalliance.org/donate) to help
+keep them free, open, and independent.
+
## About this page
Originally inspired by the [Ethereum Protocol Fellows](https://github.com/eth-protocol-fellows/protocol-studies).
diff --git a/README.md b/README.md
index 796fe88e2..1384f71c7 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,9 @@ Every contribution helps strengthen the resource and improve security practices
See our [Contributing Guide](https://github.com/security-alliance/frameworks/blob/develop/CONTRIBUTING.md) for details
on how to get started.
+Funding is another way to contribute. [Support the Frameworks](https://securityalliance.org/donate) to help keep
+this resource free, open, and independent.
+
## License
Security Frameworks © 2026 by Security Alliance, licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/components/donate/DonateNavButton.css b/components/donate/DonateNavButton.css
new file mode 100644
index 000000000..7c4351fee
--- /dev/null
+++ b/components/donate/DonateNavButton.css
@@ -0,0 +1,46 @@
+.donate-nav-button {
+ display: inline-flex;
+ align-items: center;
+ align-self: stretch; /* matches the search box height */
+ gap: 0.5rem;
+ flex-shrink: 0;
+ padding: 0 0.75rem;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 450;
+ white-space: nowrap;
+ text-decoration: none;
+ color: var(--vocs-text-color-secondary);
+ background-color: var(--vocs-background-color-surface);
+ border: 1px solid var(--vocs-border-color-primary);
+ border-radius: 0.75rem;
+ transition: color 0.1s ease, background-color 0.1s ease, border-color 0.1s ease;
+}
+
+/* Light mode borders are set alongside the search trigger in docs/pages/_root.css,
+ which overrides the Vocs default for both controls together. */
+
+.donate-nav-button:hover {
+ color: var(--vocs-text-color-primary);
+ background-color: var(--vocs-background-color-surfaceTint);
+}
+
+/* The one accent: SEAL blue, matching the sidebar heart and the footer buttons.
+ Deliberately not `--vocs-color-accent`, which defaults to
+ light-dark(black, white) and is not overridden by this site. */
+.donate-nav-button svg {
+ color: #4339db;
+ flex-shrink: 0;
+}
+
+:root[data-vocs-theme='dark'] .donate-nav-button svg {
+ color: #6b63e8; /* Brighter SEAL Blue for dark themes */
+}
+
+/* Follows the search input, which Vocs hides below its `md` breakpoint.
+ Vocs overrides that breakpoint to 748px, so this is not Tailwind's default. */
+@media (width < 748px) {
+ .donate-nav-button {
+ display: none;
+ }
+}
diff --git a/components/donate/DonateNavButton.tsx b/components/donate/DonateNavButton.tsx
new file mode 100644
index 000000000..aca92a612
--- /dev/null
+++ b/components/donate/DonateNavButton.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { createPortal } from 'react-dom'
+import { DONATE_URL } from '../shared/donate'
+import { usePortalTargets } from './usePortalTargets'
+import './DonateNavButton.css'
+
+const LABEL = 'Support us'
+const TITLE = 'Help sustain the Frameworks'
+
+function DonateButton() {
+ return (
+
+
+ {LABEL}
+
+ )
+}
+
+/**
+ * Renders a donation button beside the top nav search box.
+ *
+ * Vocs exposes no slot in the top nav, so the button is portalled into
+ * `[data-v-gutter-top-left]`, the flex row that holds the logo and search.
+ * It is hidden on small screens along with the search input itself, where the
+ * mobile nav drawer carries the donation link instead.
+ */
+export function DonateNavButton() {
+ const targets = usePortalTargets('[data-v-gutter-top-left]')
+
+ return targets.map(target => createPortal(
+ Short on time? Supporting SEAL keeps the Frameworks free and independent. +
); diff --git a/components/index.ts b/components/index.ts index c69a3ee8d..47df7880d 100644 --- a/components/index.ts +++ b/components/index.ts @@ -12,12 +12,15 @@ export { TagFilter } from './tags/TagFilter' export { TagList } from './tags/TagList' export { AttributionList } from './attribution/AttributionList' export { ContributeFooter } from './footer/ContributeFooter' +export { DonateSidebarLink } from './donate/DonateSidebarLink' +export { DonateNavButton } from './donate/DonateNavButton' export { Contributors } from './contributors/Contributors' export { BenchmarkList } from './benchmark/Benchmark' export { CertList } from './cert/CertList' export { ExportAllCerts } from './cert/ExportAllCerts' export type { Control, Section, CertListProps, ControlState, ControlData } from './cert/types' export * from './shared/tagColors' +export * from './shared/donate' export { CertifiedProtocols } from './cert/certified-protocols/CertifiedProtocols' export { CertifiedProtocolsWrapper } from './cert/certified-protocols/CertifiedProtocolsWrapper' export { BadgeLegend } from './contributors/BadgeLegend' diff --git a/components/shared/donate.ts b/components/shared/donate.ts new file mode 100644 index 000000000..b3abb6db6 --- /dev/null +++ b/components/shared/donate.ts @@ -0,0 +1,5 @@ +/** + * Donation link + */ + +export const DONATE_URL = 'https://securityalliance.org/donate' diff --git a/docs/pages/_root.css b/docs/pages/_root.css index a85c540aa..e1b0b2ffe 100644 --- a/docs/pages/_root.css +++ b/docs/pages/_root.css @@ -34,11 +34,15 @@ html:not([data-vocs-theme='dark']) [data-v-content] blockquote>p { font-weight: bolder; } -html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] button[aria-haspopup='dialog'] { +/* Light-mode border treatment for the top-left controls: the search trigger + and the donate button, which is styled to match it. */ +html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] button[aria-haspopup='dialog'], +html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] .donate-nav-button { border-color: #908f8f; } -html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] button[aria-haspopup='dialog']:hover { +html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] button[aria-haspopup='dialog']:hover, +html:not([data-vocs-theme='dark']) [data-v-gutter-top-left] .donate-nav-button:hover { border-color: #303030; color: #1e1e1e; } diff --git a/docs/pages/_slots.tsx b/docs/pages/_slots.tsx index ac371dbd5..b0d04e8f8 100644 --- a/docs/pages/_slots.tsx +++ b/docs/pages/_slots.tsx @@ -1,4 +1,4 @@ -import { TagFilter } from '../../components' +import { DonateNavButton, DonateSidebarLink, TagFilter } from '../../components' export function Footer() { return ( @@ -9,5 +9,11 @@ export function Footer() { } export function SidebarHeader() { - return