mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add a Keep it free sponsor button to the top nav (#427)
Adds a prominent Keep it free sponsor button to the top nav, linking to https://github.com/sponsors/snapotter-hq. Solid orange pill on desktop (left of the avatar), orange heart icon on mobile. Opens in a new tab with rel=noopener noreferrer, so no referrer or user data leaks, and it adds no passive network activity (offline-mode compatible). Fires an opt-in, property-less sponsor_clicked analytics event. Adds sidebar.sponsor and a11y.sponsorLink across all 21 locales. Claude-Session: https://claude.ai/code/session_01DnYLLA5z4Uf1GDeEPENVgr
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { ANALYTICS_EVENTS } from "@snapotter/shared";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
FolderOpen,
|
||||
Globe,
|
||||
Heart,
|
||||
HelpCircle,
|
||||
LayoutGrid,
|
||||
MessageSquare,
|
||||
@@ -128,6 +130,8 @@ export function TopNav({
|
||||
</button>
|
||||
)}
|
||||
|
||||
<SponsorButton isDark={isDark} compact />
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={onHelpClick}
|
||||
@@ -280,12 +284,58 @@ export function TopNav({
|
||||
<HelpCircle className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<SponsorButton isDark={isDark} />
|
||||
|
||||
{!isMobile && <AvatarDropdown onSettingsClick={onSettingsClick} variant={variant} />}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
const SPONSOR_URL = "https://github.com/sponsors/snapotter-hq";
|
||||
|
||||
function SponsorButton({ isDark, compact = false }: { isDark: boolean; compact?: boolean }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = () => {
|
||||
import("@/lib/analytics").then(({ track }) => {
|
||||
track(ANALYTICS_EVENTS.SPONSOR_CLICKED);
|
||||
});
|
||||
};
|
||||
|
||||
if (compact) {
|
||||
return (
|
||||
<a
|
||||
href={SPONSOR_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={handleClick}
|
||||
aria-label={t.a11y.sponsorLink}
|
||||
title={t.a11y.sponsorLink}
|
||||
className={cn(
|
||||
"p-1.5 rounded-md transition-colors text-primary",
|
||||
isDark ? "hover:bg-[#333]" : "hover:bg-muted",
|
||||
)}
|
||||
>
|
||||
<Heart className="h-4 w-4 fill-current" />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href={SPONSOR_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={handleClick}
|
||||
className="ms-1 inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-[#1a1814] transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
|
||||
>
|
||||
<Heart className="h-3.5 w-3.5 fill-current" aria-hidden="true" />
|
||||
{t.sidebar.sponsor}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function ThemeToggle({ isDark }: { isDark: boolean }) {
|
||||
const { resolvedTheme, toggleTheme } = useTheme();
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user