Build Osias landing page and privacy policy

Calm-dark aesthetic (warm near-black, glass cards, amber accent,
Newsreader + Inter) translated from the Claude Design canvas mockup:
hero with a faithful mock of the extension's real blur-lock treatment,
how-it-works, shipped features, an honestly-labeled coming-soon
section, and a privacy policy page matching the text already
submitted to AMO.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
This commit is contained in:
2026-09-09 13:07:40 +02:00
co-authored by claude
parent 5800969e70
commit 8b93696b0f
13 changed files with 586 additions and 93 deletions
+27 -19
View File
@@ -1,26 +1,34 @@
@import "tailwindcss";
@theme {
--color-ink: #17130f;
--color-cream: #f3eee6;
--color-muted: #a79e90;
--color-muted-2: #756c5e;
--color-muted-3: #5c554a;
--color-accent: #e2824c;
--color-accent-hover: #ec935a;
--color-accent-soft: #eda06e;
--color-loss: #e2734a;
--color-gain: #7fd89a;
--font-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
--font-display: var(--font-newsreader), Georgia, "Times New Roman", serif;
}
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
color-scheme: dark;
}
@layer base {
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
background: var(--color-ink);
color: var(--color-cream);
font-family: var(--font-sans);
text-wrap: pretty;
}
a {
color: var(--color-accent);
}
}
+12 -12
View File
@@ -1,29 +1,29 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Inter, Newsreader } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
const inter = Inter({
variable: "--font-inter",
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
const newsreader = Newsreader({
variable: "--font-newsreader",
subsets: ["latin"],
weight: ["400", "500", "600"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "Osias — the pause before the trade you'll regret",
description:
"Osias watches your connected Solana wallet in real time and locks buy actions when your trading turns loss-driven.",
};
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
<html lang="en" className={`${inter.variable} ${newsreader.variable} h-full antialiased`}>
<body className="flex min-h-full flex-col bg-ink text-cream">{children}</body>
</html>
);
}
+15 -63
View File
@@ -1,69 +1,21 @@
import Image from "next/image";
import { ComingSoon } from "@/components/ComingSoon";
import { Features } from "@/components/Features";
import { Hero } from "@/components/Hero";
import { HowItWorks } from "@/components/HowItWorks";
import { SiteFooter } from "@/components/SiteFooter";
import { SiteHeader } from "@/components/SiteHeader";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert h-5 w-[100px]"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the{" "}
<code className="rounded bg-black/[.06] px-1.5 py-0.5 font-mono text-[0.9em] dark:bg-white/[.08]">
page.tsx
</code>{" "}
file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert h-[14px] w-4"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={14}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
<>
<SiteHeader />
<main className="flex-1">
<Hero />
<HowItWorks />
<Features />
<ComingSoon />
</main>
</div>
<SiteFooter />
</>
);
}
+118
View File
@@ -0,0 +1,118 @@
import type { Metadata } from "next";
import { SiteFooter } from "@/components/SiteFooter";
import { SiteHeader } from "@/components/SiteHeader";
import { LINKS } from "@/lib/links";
export const metadata: Metadata = {
title: "Privacy Policy — Osias",
description: "What Osias collects, why, and how it's handled.",
};
function H2({ children }: { children: React.ReactNode }) {
return <h2 className="mb-3.5 font-display text-xl font-medium text-cream">{children}</h2>;
}
function P({ children }: { children: React.ReactNode }) {
return <p className="mb-10 text-[15px] leading-[1.75] text-[#b8ae9e]">{children}</p>;
}
export default function PrivacyPolicy() {
return (
<>
<SiteHeader />
<main className="flex-1">
<div className="mx-auto max-w-[720px] px-8 py-16 sm:px-16 sm:py-24">
<h1 className="mb-3.5 font-display text-[36px] font-medium leading-tight text-cream sm:text-[42px]">
Privacy Policy
</h1>
<p className="mb-12 text-[13.5px] text-muted-3">Last updated: September 9, 2026</p>
<P>
Osias is a browser extension that helps you notice and interrupt loss-driven trading by watching your
connected wallet&rsquo;s on-chain activity. This policy explains what data the extension and its backend
collect, why, and how it&rsquo;s handled.
</P>
<H2>What we collect</H2>
<p className="mb-3 text-[15px] leading-[1.75] text-[#b8ae9e]">
<strong className="text-[#dcc9b6]">Wallet address.</strong> Collected when you connect your Phantom
wallet — used as your account identifier and to subscribe to your wallet&rsquo;s on-chain activity.
</p>
<p className="mb-3 text-[15px] leading-[1.75] text-[#b8ae9e]">
<strong className="text-[#dcc9b6]">Authentication data.</strong> To verify you control the wallet, you
sign a one-time nonce message; we store the resulting session token. Your private key and seed phrase
never leave your wallet and are never accessible to us.
</p>
<p className="mb-3 text-[15px] leading-[1.75] text-[#b8ae9e]">
<strong className="text-[#dcc9b6]">On-chain trading activity.</strong> While you&rsquo;re actively
connected (extension open, on a supported trading site), our backend subscribes to your wallet&rsquo;s
transaction activity via a Solana RPC provider (Helius) to calculate realized profit/loss. This is
public blockchain data, no different from what anyone could see on a block explorer.
</p>
<P>
<strong className="text-[#dcc9b6]">Settings.</strong> Your configured lock thresholds and cooldown
period, stored so they persist across sessions.
</P>
<H2>What we don&rsquo;t collect</H2>
<ul className="mb-10 list-disc space-y-1.5 pl-5 text-[15px] leading-[1.75] text-[#b8ae9e]">
<li>Private keys or seed phrases</li>
<li>Browsing history or page content on any site</li>
<li>Any data from sites other than the specific trading sites Osias supports</li>
</ul>
<H2>Why we collect it</H2>
<P>
Solely to run the core feature — detecting loss-driven trading against your configured thresholds and
applying/lifting the buy-lock. We do not use this data for advertising and we do not sell it.
</P>
<H2>Who we share it with</H2>
<P>
<strong className="text-[#dcc9b6]">Helius</strong> (our Solana RPC infrastructure provider) receives
your wallet address to stream transaction data to our backend, governed by their own privacy policy. We
do not otherwise share, sell, or disclose your wallet address, trading activity, or account data to any
third party.
</P>
<H2>Data retention</H2>
<P>
Your wallet address, session data, and settings are retained for as long as your account exists.
On-chain subscriptions are only active while you have a live connection — we don&rsquo;t monitor while
you&rsquo;re offline. There&rsquo;s no self-serve account deletion yet — to request deletion, open an
issue at{" "}
<a href={LINKS.githubIssues} target="_blank" rel="noreferrer">
github.com/osias-trade/copilot/issues
</a>{" "}
and we&rsquo;ll process it manually.
</P>
<H2>Your controls</H2>
<P>
You can disconnect your wallet and sign out at any time from the extension popup, which revokes access
and ends your session.
</P>
<H2>Open source</H2>
<P>
The extension&rsquo;s frontend is open source (Apache License 2.0):{" "}
<a href={LINKS.github} target="_blank" rel="noreferrer">
github.com/osias-trade/copilot
</a>{" "}
— you can review exactly what it collects and transmits.
</P>
<H2>Contact</H2>
<p className="text-[15px] leading-[1.75] text-[#b8ae9e]">
Questions about this policy or your data: open an issue at{" "}
<a href={LINKS.githubIssues} target="_blank" rel="noreferrer">
github.com/osias-trade/copilot/issues
</a>
.
</p>
</div>
</main>
<SiteFooter />
</>
);
}
+38
View File
@@ -0,0 +1,38 @@
const upcoming = [
{
title: "Full-site block escalation",
body: "If the buy-lock is circumvented, escalate to blocking the entire site.",
},
{
title: "More site support",
body: "axiom.trade first — the architecture is built so new sites are a self-contained addition.",
},
{
title: "In-extension chat",
body: "A real check-in with Osias during a lock, not just a static reason message.",
},
{
title: "Multi-wallet linking",
body: "One account, more than one wallet under it.",
},
];
export function ComingSoon() {
return (
<section className="mx-auto max-w-[1180px] px-8 pb-20 sm:px-16 sm:pb-32">
<div className="mb-10 flex items-baseline gap-3">
<h2 className="font-display text-2xl font-medium text-[#cfc6b6]">Coming soon</h2>
<span className="text-xs text-muted-3">not yet shipped</span>
</div>
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
{upcoming.map((item) => (
<div key={item.title} className="flex flex-col gap-2.5 rounded-2xl border border-dashed border-white/13 p-5">
<h3 className="text-[14.5px] font-semibold text-[#b8ae9e]">{item.title}</h3>
<p className="text-[13px] leading-relaxed text-muted-3">{item.body}</p>
</div>
))}
</div>
</section>
);
}
+50
View File
@@ -0,0 +1,50 @@
import { CodeIcon, KeyIcon, SignalIcon, SlidersIcon } from "./icons";
const features = [
{
icon: KeyIcon,
title: "Real Phantom wallet auth",
body: "Connect, sign, sign out, switch accounts — genuine wallet signing, no stub keypair.",
},
{
icon: SlidersIcon,
title: "Configurable thresholds",
body: "Single-trade and losing-streak triggers, plus your auto-unlock cooldown — all tunable from the popup.",
},
{
icon: SignalIcon,
title: "Live connection status",
body: 'Always know whether Osias is actually watching — a broken connection is never silently mistaken for "unlocked".',
},
{
icon: CodeIcon,
title: "Open source frontend",
body: "Apache 2.0. The detection and enforcement logic is auditable, not a black box asking for trust.",
},
];
export function Features() {
return (
<section id="features" className="mx-auto max-w-[1180px] px-8 pb-16 sm:px-16 sm:pb-28">
<div className="mb-14 max-w-[560px]">
<h2 className="font-display text-[28px] font-medium text-cream sm:text-[34px]">What&rsquo;s shipped today</h2>
<p className="mt-3.5 text-[15.5px] leading-relaxed text-muted">
This is an early, working MVP — not a promise, a thing you can install right now.
</p>
</div>
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
{features.map((feature) => (
<div
key={feature.title}
className="flex flex-col gap-3.5 rounded-2xl border border-white/8 p-[22px] transition-all hover:-translate-y-0.5 hover:border-accent/35"
>
<feature.icon className="h-5 w-5 text-accent" />
<h3 className="text-[15.5px] font-semibold text-cream">{feature.title}</h3>
<p className="text-[13.5px] leading-relaxed text-muted">{feature.body}</p>
</div>
))}
</div>
</section>
);
}
+46
View File
@@ -0,0 +1,46 @@
import { LockDemoCard } from "./LockDemoCard";
import { LINKS } from "@/lib/links";
export function Hero() {
return (
<div className="mx-auto flex max-w-[1180px] flex-col items-center gap-14 px-8 py-16 sm:px-16 sm:py-24 lg:flex-row lg:py-28">
<div className="flex flex-1 flex-col gap-7">
<div className="inline-flex self-start rounded-full border border-white/8 bg-white/6 px-3 py-1.5 text-xs tracking-wide text-muted">
Browser extension · Firefox &amp; Chromium
</div>
<h1 className="font-display text-[42px] font-medium leading-[1.1] tracking-tight text-cream sm:text-[56px] sm:leading-[1.08]">
The pause before the trade you&rsquo;ll regret.
</h1>
<p className="max-w-[460px] text-[17px] leading-relaxed text-[#b8ae9e]">
Osias watches your connected wallet in real time and locks buy actions when your trading turns
loss-driven — so the moment passes before your money does.
</p>
<div className="mt-2 flex items-center gap-6">
<a
href={LINKS.firefoxAddon}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-2 rounded-[10px] bg-accent px-6 py-3.5 text-[15px] font-semibold text-ink transition-all hover:-translate-y-px hover:bg-accent-hover"
>
Add to Firefox — Free
</a>
<a
href={LINKS.github}
target="_blank"
rel="noreferrer"
className="text-sm font-medium text-[#cfc6b6] hover:text-cream"
>
View on GitHub →
</a>
</div>
<p className="text-[13px] text-muted-3">
Open source (Apache 2.0). No seed phrase or private key ever touches the extension.
</p>
</div>
<div className="w-full flex-1">
<LockDemoCard />
</div>
</div>
);
}
+55
View File
@@ -0,0 +1,55 @@
import { ClockIcon, LockIcon, PulseIcon, WalletIcon } from "./icons";
const steps = [
{
icon: WalletIcon,
label: "Step 1",
title: "Connect your wallet",
body: "Real Phantom sign-in via message signing. Your seed phrase and private key never touch the extension.",
},
{
icon: PulseIcon,
label: "Step 2",
title: "Osias watches",
body: "A live Solana subscription tracks your realized P&L in the background — while you're connected, nothing more.",
},
{
icon: LockIcon,
label: "Step 3",
title: "Buying locks",
body: "Cross your threshold — a single bad trade or a losing streak — and new buys disable. Sell and manage stay untouched.",
},
{
icon: ClockIcon,
label: "Step 4",
title: "The moment passes",
body: "Auto-unlocks after your configured cooldown, or unlock manually with an explicit confirmation.",
},
];
export function HowItWorks() {
return (
<section id="how-it-works" className="mx-auto max-w-[1180px] border-t border-white/6 px-8 py-16 sm:px-16 sm:py-28">
<div className="mb-14 max-w-[560px]">
<h2 className="font-display text-[28px] font-medium text-cream sm:text-[34px]">How it works</h2>
<p className="mt-3.5 text-[15.5px] leading-relaxed text-muted">
No manual logging. Your trades are already on-chain — Osias just watches, and steps in only when it
matters.
</p>
</div>
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-4">
{steps.map((step) => (
<div key={step.title} className="flex flex-col gap-4">
<div className="flex h-10 w-10 items-center justify-center rounded-[10px] border border-white/9 bg-white/5">
<step.icon className="h-[19px] w-[19px] text-accent" />
</div>
<div className="text-xs font-semibold tracking-wide text-muted-3">{step.label.toUpperCase()}</div>
<h3 className="text-[16.5px] font-semibold text-cream">{step.title}</h3>
<p className="text-sm leading-relaxed text-muted">{step.body}</p>
</div>
))}
</div>
</section>
);
}
+39
View File
@@ -0,0 +1,39 @@
import { LockIcon } from "./icons";
// The hero's product visual — a faithful mock of the real lock treatment
// (blur-disable.ts's overlay + toast.ts's reason banner), not abstract art.
export function LockDemoCard() {
return (
<div className="rounded-[18px] border border-white/9 bg-white/[0.035] p-6 shadow-[0_30px_70px_-30px_rgba(0,0,0,0.55)] backdrop-blur-xl">
<div className="mb-[18px] flex items-center justify-between">
<div className="flex items-center gap-2.5">
<div className="h-[34px] w-[34px] rounded-full bg-white/8" />
<div>
<div className="text-sm font-semibold text-cream">PIXELCAT</div>
<div className="text-xs text-loss">−41.2% today</div>
</div>
</div>
<div className="text-xs text-muted-3">axiom.trade</div>
</div>
<div className="flex gap-2.5">
<div className="flex-1 rounded-[10px] bg-white/6 py-3 text-center text-sm font-semibold text-[#cfc6b6]">
Sell
</div>
<div className="relative flex-1 overflow-hidden rounded-[10px]">
<div className="rounded-[10px] bg-gain/16 py-3 text-center text-sm font-semibold text-gain">Buy</div>
<div className="absolute -inset-[3px] flex cursor-not-allowed items-center justify-center rounded-xl bg-black/28 backdrop-blur-[1.5px] backdrop-grayscale backdrop-brightness-[0.55]">
<LockIcon className="h-[17px] w-[17px] text-cream" />
</div>
</div>
</div>
<div className="mt-4 flex items-start gap-2.5 rounded-[10px] border border-accent/25 bg-accent/10 px-3.5 py-3">
<LockIcon className="mt-px h-[15px] w-[15px] flex-none text-accent" />
<div className="text-[12.5px] leading-relaxed text-[#dcc9b6]">
Buying paused — down $62 on PIXELCAT, past your $50 threshold. Auto-unlocks in 24m, or unlock now.
</div>
</div>
</div>
);
}
+49
View File
@@ -0,0 +1,49 @@
import Link from "next/link";
import { LockIcon } from "./icons";
import { LINKS } from "@/lib/links";
export function SiteFooter() {
return (
<footer className="border-t border-white/7">
<div className="mx-auto flex max-w-[1180px] flex-col gap-10 px-8 py-14 sm:flex-row sm:items-start sm:justify-between sm:px-16">
<div className="flex max-w-[340px] flex-col gap-3">
<Link href="/" className="flex items-center gap-2.5">
<span className="flex h-[26px] w-[26px] items-center justify-center rounded-md border border-white/10 bg-white/6">
<LockIcon className="h-[13px] w-[13px] text-accent" />
</span>
<span className="font-display text-base font-medium text-cream">Osias</span>
</Link>
<p className="text-[13px] leading-relaxed text-muted-2">
Your blockchain-powered trading companion. Early beta — we&rsquo;d genuinely love your honest feedback.
</p>
</div>
<div className="flex flex-col gap-3">
<div className="text-xs font-semibold tracking-wide text-muted-2">PROJECT</div>
<a
href={LINKS.firefoxAddon}
target="_blank"
rel="noreferrer"
className="text-[13.5px] text-muted transition-colors hover:text-cream"
>
Firefox Add-ons
</a>
<a
href={LINKS.github}
target="_blank"
rel="noreferrer"
className="text-[13.5px] text-muted transition-colors hover:text-cream"
>
GitHub
</a>
<Link href="/privacy" className="text-[13.5px] text-muted transition-colors hover:text-cream">
Privacy Policy
</Link>
</div>
</div>
<div className="mx-auto max-w-[1180px] px-8 pb-10 text-[12.5px] text-muted-3 sm:px-16">
© {new Date().getFullYear()} Osias. Open source under the Apache License 2.0.
</div>
</footer>
);
}
+32
View File
@@ -0,0 +1,32 @@
import Link from "next/link";
import { LockIcon } from "./icons";
import { LINKS } from "@/lib/links";
export function SiteHeader() {
return (
<header className="flex items-center justify-between px-8 py-7 border-b border-white/7 sm:px-16">
<Link href="/" className="flex items-center gap-2.5">
<span className="flex h-[30px] w-[30px] items-center justify-center rounded-lg border border-white/10 bg-white/6">
<LockIcon className="h-[15px] w-[15px] text-accent" />
</span>
<span className="font-display text-xl font-medium text-cream">Osias</span>
</Link>
<nav className="hidden items-center gap-9 text-sm sm:flex">
<Link href="/#how-it-works" className="text-muted transition-colors hover:text-cream">
How it works
</Link>
<Link href="/#features" className="text-muted transition-colors hover:text-cream">
Features
</Link>
<a
href={LINKS.github}
target="_blank"
rel="noreferrer"
className="text-muted transition-colors hover:text-cream"
>
GitHub
</a>
</nav>
</header>
);
}
+99
View File
@@ -0,0 +1,99 @@
type IconProps = {
className?: string;
};
// Shared stroke props keep every icon in the set visually consistent —
// same weight, cap and join, so icons from different sections read as one system.
const stroke = {
fill: "none",
stroke: "currentColor",
strokeWidth: 1.8,
strokeLinecap: "round" as const,
strokeLinejoin: "round" as const,
};
export function LockIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke} strokeWidth={2}>
<rect x="4" y="10" width="16" height="10" rx="2" />
<path d="M8 10V7a4 4 0 0 1 8 0v3" />
</svg>
);
}
export function WalletIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<rect x="3" y="7" width="18" height="13" rx="2" />
<path d="M16 13h.01" />
<path d="M3 9V6a2 2 0 0 1 2-2h11a2 2 0 0 1 2 2v3" />
</svg>
);
}
export function PulseIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" />
<circle cx="12" cy="12" r="3" />
</svg>
);
}
export function ClockIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 3" />
</svg>
);
}
export function KeyIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<path d="M12 2v6" />
<path d="m4.9 10.1 4.2 2.5" />
<path d="m14.9 12.6 4.2-2.5" />
<path d="M12 16v6" />
<circle cx="12" cy="14" r="3" />
</svg>
);
}
export function SlidersIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<path d="M4 21V14" />
<path d="M4 10V3" />
<path d="M12 21v-9" />
<path d="M12 8V3" />
<path d="M20 21v-6" />
<path d="M20 11V3" />
<path d="M2 14h4" />
<path d="M10 8h4" />
<path d="M18 11h4" />
</svg>
);
}
export function SignalIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<path d="M2 12h3" />
<path d="M19 12h3" />
<path d="M12 2v3" />
<path d="M12 19v3" />
<circle cx="12" cy="12" r="5" />
</svg>
);
}
export function CodeIcon({ className }: IconProps) {
return (
<svg viewBox="0 0 24 24" className={className} {...stroke}>
<path d="m8 6-4 6 4 6" />
<path d="m16 6 4 6-4 6" />
</svg>
);
}
+7
View File
@@ -0,0 +1,7 @@
// Central place for external URLs used across the site — update here, not per-component.
export const LINKS = {
github: "https://github.com/osias-trade/copilot",
githubIssues: "https://github.com/osias-trade/copilot/issues",
// TODO: fill in once the AMO listing is live (e.g. https://addons.mozilla.org/firefox/addon/osias/).
firefoxAddon: "#",
};