diff --git a/.changelog/unreleased/9996-canonical-so4-brand-and-links.md b/.changelog/unreleased/9996-canonical-so4-brand-and-links.md new file mode 100644 index 00000000..ed41afe7 --- /dev/null +++ b/.changelog/unreleased/9996-canonical-so4-brand-and-links.md @@ -0,0 +1,8 @@ +--- +type: fixed +area: trade +pr: 9996 +breaking: false +--- + +Site metadata, community links, and changelog and gallery GitHub URLs now consistently point to SO4 Market and its source repository. diff --git a/apps/web/public/manifest.json b/apps/web/public/manifest.json index e676f98c..ca8d6a2b 100644 --- a/apps/web/public/manifest.json +++ b/apps/web/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "Levee", - "name": "Levee — On-chain perpetuals", + "short_name": "SO4", + "name": "SO4 Market — On-chain perpetuals", "description": "A unified-liquidity perp DEX. Deep books, sub-second matching, and self-custodied risk.", "icons": [ { diff --git a/apps/web/public/og-image.svg b/apps/web/public/og-image.svg index e7f1d491..fb5831c4 100644 --- a/apps/web/public/og-image.svg +++ b/apps/web/public/og-image.svg @@ -42,7 +42,7 @@ levee.market + fill="#F5F6F7">SO4.market diff --git a/apps/web/src/features/changelog/components/ChangelogEntry.tsx b/apps/web/src/features/changelog/components/ChangelogEntry.tsx index c4927d38..ff7c5aeb 100644 --- a/apps/web/src/features/changelog/components/ChangelogEntry.tsx +++ b/apps/web/src/features/changelog/components/ChangelogEntry.tsx @@ -2,6 +2,7 @@ import { Badge } from "@workspace/ui/components/badge" import { areaLabel, typeLabel, typeToVariant } from "../utils" import { InlineMarkdown } from "./InlineMarkdown" import type { ChangelogEntry as IChangelogEntry } from "../types" +import { REPO_URL } from "@/shared/lib/site-identity" interface ChangelogEntryProps { entry: IChangelogEntry @@ -39,7 +40,7 @@ export function ChangelogEntry({ entry, highlight }: ChangelogEntryProps) { {entry.pr && (
{ const origin = typeof window === "undefined" - ? "https://so4.market" + ? SITE_URL : window.location.origin const permalink = `${origin}/changelog${anchor}` try { diff --git a/apps/web/src/features/gallery/components/gallery-page.tsx b/apps/web/src/features/gallery/components/gallery-page.tsx index 0d4a2105..4d884816 100644 --- a/apps/web/src/features/gallery/components/gallery-page.tsx +++ b/apps/web/src/features/gallery/components/gallery-page.tsx @@ -32,6 +32,7 @@ import type { ProgressIndicatorProps } from "@workspace/ui/components/progress-i import { useDirection } from "@/ui/direction-provider" import { ChangelogCategoryBadge } from "@/features/changelog/components/ChangelogCategoryBadge" import { CHANGELOG_ENTRY_TYPES } from "@/features/changelog/types" +import { REPO_URL } from "@/shared/lib/site-identity" const BUTTON_VARIANTS = [ "default", @@ -105,14 +106,14 @@ export function GalleryPage() {

Every packages/ui primitive, all variants. See{" "} DESIGN.md {" "} and{" "} packages/ui/CONTRIBUTING.md diff --git a/apps/web/src/features/wallet/components/ConnectButton.tsx b/apps/web/src/features/wallet/components/ConnectButton.tsx index 7a5073b0..6c63ec80 100644 --- a/apps/web/src/features/wallet/components/ConnectButton.tsx +++ b/apps/web/src/features/wallet/components/ConnectButton.tsx @@ -19,6 +19,7 @@ import type { ComponentProps } from "react" import { useKeyboardShortcut } from "@/shared/hooks/useKeyboardShortcut" import { useWallet } from "@/app/providers" import { NETWORK } from "@/app/config/network" +import { SITE_URL } from "@/shared/lib/site-identity" type ConnectButtonProps = Omit< ComponentProps, @@ -278,7 +279,7 @@ function WalletModal({ ) const sep7Uri = useMemo(() => { const origin = - typeof window === "undefined" ? "https://so4.market" : window.location.origin + typeof window === "undefined" ? SITE_URL : window.location.origin const callbackUrl = new URL("/", origin).toString() if (pendingTransactionXdr) { diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 365c5eac..e0d1bac4 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -10,12 +10,10 @@ import { TooltipProvider } from "@workspace/ui/components/tooltip" import { DensityProvider } from "@workspace/ui/components/density-provider" import appCss from "@workspace/ui/globals.css?url" import { AppProviders } from "../app/providers" +import { SITE_NAME, SITE_URL, SOCIAL_URLS } from "../shared/lib/site-identity" import { RouteAnnouncer } from "../shared/components/RouteAnnouncer" -// Update this to your production domain before going live. -const SITE_URL = "https://levee.market" -const SITE_NAME = "levee.market" -const TITLE = "Levee · On-chain perpetuals" +const TITLE = `${SITE_NAME} · On-chain perpetuals` const DESCRIPTION = "A unified-liquidity perp DEX. Deep books, sub-second matching, and self-custodied risk — built for traders who care where their fills come from." // TODO(GF3-003): apply the dot-separator convention (no em dashes as list @@ -34,7 +32,7 @@ const JSON_LD = { { "@type": "WebApplication", "@id": `${SITE_URL}/#app`, - name: "Levee", + name: SITE_NAME, url: SITE_URL, description: DESCRIPTION, applicationCategory: "FinanceApplication", @@ -48,13 +46,13 @@ const JSON_LD = { { "@type": "Organization", "@id": `${SITE_URL}/#org`, - name: "Levee Labs", + name: "SO4 Markets", url: SITE_URL, logo: `${SITE_URL}/favicon.svg`, sameAs: [ - "https://twitter.com/so4market", - "https://discord.gg/so4market", - "https://t.me/so4market", + SOCIAL_URLS.x, + SOCIAL_URLS.discord, + SOCIAL_URLS.telegram, ], }, { @@ -81,7 +79,7 @@ export const Route = createRootRoute({ content: "perpetual DEX, on-chain perps, crypto derivatives, DeFi trading, BTC perp, ETH perp, low fee perp, self-custodied trading, unified liquidity", }, - { name: "author", content: "Levee Labs" }, + { name: "author", content: "SO4 Markets" }, { name: "robots", content: "index, follow, max-image-preview:large" }, // ds-allow: requires a literal color string for // mobile browser chrome tinting — can't reference a CSS custom @@ -105,7 +103,7 @@ export const Route = createRootRoute({ { property: "og:image:alt", content: - "Levee · On-chain perpetuals DEX · unified liquidity for modern markets", + `${SITE_NAME} · On-chain perpetuals DEX · unified liquidity for modern markets`, }, // ── Twitter / X Card ──────────────────────────────────────── @@ -118,7 +116,7 @@ export const Route = createRootRoute({ { name: "twitter:image:alt", content: - "Levee · On-chain perpetuals DEX · unified liquidity for modern markets", + `${SITE_NAME} · On-chain perpetuals DEX · unified liquidity for modern markets`, }, ], links: [ diff --git a/apps/web/src/shared/lib/site-identity.test.ts b/apps/web/src/shared/lib/site-identity.test.ts new file mode 100644 index 00000000..6bbb7677 --- /dev/null +++ b/apps/web/src/shared/lib/site-identity.test.ts @@ -0,0 +1,35 @@ +import { readFileSync } from "node:fs" +import { describe, expect, it } from "vitest" +import { DOCS_URL, REPO_URL, SITE_NAME, SITE_URL, SOCIAL_URLS } from "./site-identity" + +describe("canonical product identity (#846)", () => { + it("uses the documented SO4 website, repository, and community channels", () => { + expect(SITE_NAME).toBe("SO4 Market") + expect(SITE_URL).toBe("https://so4.market") + expect(REPO_URL).toBe("https://github.com/SO4-Markets/interface") + expect(DOCS_URL).toBe("https://docs.so4.market") + expect(SOCIAL_URLS).toMatchObject({ + github: REPO_URL, + x: "https://twitter.com/so4market", + discord: "https://discord.gg/so4market", + telegram: "https://t.me/so4market", + }) + }) + + it("does not keep the competing domain or repository links in runtime sources", () => { + const files = [ + "../../routes/__root.tsx", + "../../ui/landing/roadmap-section.tsx", + "../../ui/landing/social-section.tsx", + "../../features/changelog/components/ChangelogEntry.tsx", + "../../features/gallery/components/gallery-page.tsx", + "../../../public/og-image.svg", + "../../../public/manifest.json", + ] + + for (const path of files) { + const source = readFileSync(new URL(path, import.meta.url), "utf8") + expect(source, path).not.toMatch(/Levee-HQ|levee\.market/) + } + }) +}) diff --git a/apps/web/src/shared/lib/site-identity.ts b/apps/web/src/shared/lib/site-identity.ts new file mode 100644 index 00000000..913fd047 --- /dev/null +++ b/apps/web/src/shared/lib/site-identity.ts @@ -0,0 +1,12 @@ +// Canonical destinations for web metadata, product links, and community links. +// Product name/domain pending confirmation in SO4-Markets/interface#846. +export const SITE_NAME = "SO4 Market" +export const SITE_URL = "https://so4.market" +export const REPO_URL = "https://github.com/SO4-Markets/interface" +export const DOCS_URL = "https://docs.so4.market" +export const SOCIAL_URLS = { + x: "https://twitter.com/so4market", + discord: "https://discord.gg/so4market", + telegram: "https://t.me/so4market", + github: REPO_URL, +} as const diff --git a/apps/web/src/ui/landing/faq-section.tsx b/apps/web/src/ui/landing/faq-section.tsx index 0d756447..0f803d52 100644 --- a/apps/web/src/ui/landing/faq-section.tsx +++ b/apps/web/src/ui/landing/faq-section.tsx @@ -6,8 +6,9 @@ import { } from "@workspace/ui/components/accordion" import { LANDING_FAQS } from "./faq.generated" +import { DOCS_URL } from "@/shared/lib/site-identity" -const DOCS_ORIGIN = "https://docs.so4.market" +const DOCS_ORIGIN = DOCS_URL export function FaqSection() { return ( diff --git a/apps/web/src/ui/landing/roadmap-section.tsx b/apps/web/src/ui/landing/roadmap-section.tsx index c92f9ec3..d2bb711b 100644 --- a/apps/web/src/ui/landing/roadmap-section.tsx +++ b/apps/web/src/ui/landing/roadmap-section.tsx @@ -1,5 +1,6 @@ import { Quarter } from "./quarter" import type { QuarterData } from "./quarter" +import { REPO_URL } from "@/shared/lib/site-identity" // No dated roadmap exists in the repo — GMX's quarter labels (Q1..Q4) imply // specific committed dates, which would be a fabricated public promise if @@ -48,7 +49,7 @@ export function RoadmapSection() { {/* No dev-plan writeup exists yet — links to the source repo, a real destination, rather than a dead "#" anchor. */}