fix(web): UX/a11y polish + middleware metadata route fix
- footer.tsx: Discord link → canonical discord.gg/PUwSMR9XNk (was outdated invite that 404'd). - [locale]/layout.tsx: hooks count 40 → 54 (matches AGENTS.md). - lib/stats.ts:88: drop '!' non-null assertion; use '??' fallback. Removes the only '!' in packages/web (project rule). - nav-header.tsx: hamburger Button size='icon' → explicit h-11 w-11; mobile drawer links min-h-11 px-3 rounded-md. WCAG 2.5.5 tap target 44x44 minimum. - install-command.tsx: copy button h-8 w-8 → h-11 w-11 (was 32px, below WCAG). Icon stays 16x16; padding fills to 44. - middleware.ts: matcher excludes opengraph-image, twitter-image, icon, apple-icon, manifest.webmanifest, robots.txt, sitemap.xml. Previously next-intl redirected /opengraph-image → /en/opengraph-image breaking OG previews for crawlers that hit the unlocalized path.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { JSX } from "react"
|
||||
import { getTranslations } from "next-intl/server"
|
||||
import { Link } from "@/i18n/routing"
|
||||
|
||||
export async function Footer({ locale }: { locale?: string } = {}) {
|
||||
export async function Footer({ locale }: { readonly locale?: string } = {}): Promise<JSX.Element> {
|
||||
const t = locale
|
||||
? await getTranslations({ locale, namespace: "footer" })
|
||||
: await getTranslations("footer")
|
||||
@@ -27,7 +28,7 @@ export async function Footer({ locale }: { locale?: string } = {}) {
|
||||
{t("github")}
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/indentcorp"
|
||||
href="https://discord.gg/PUwSMR9XNk"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="transition-colors hover:text-cyan-400"
|
||||
|
||||
@@ -27,7 +27,7 @@ export function InstallCommand({ command }: { command: string }) {
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-zinc-400 hover:text-white"
|
||||
className="h-11 w-11 text-zinc-400 hover:text-white"
|
||||
onClick={copyCommand}
|
||||
aria-label="Copy install command"
|
||||
>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type { JSX } from "react"
|
||||
import { useState } from "react"
|
||||
import { useTranslations } from "next-intl"
|
||||
import { Menu, X } from "lucide-react"
|
||||
@@ -7,7 +8,7 @@ import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Link } from "@/i18n/routing"
|
||||
|
||||
function GitHubMark({ className }: { readonly className?: string }) {
|
||||
function GitHubMark({ className }: { readonly className?: string }): JSX.Element {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" className={className} fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.58 2 12.25c0 4.53 2.87 8.37 6.84 9.73.5.1.68-.22.68-.49v-1.9c-2.78.62-3.37-1.22-3.37-1.22-.46-1.2-1.11-1.52-1.11-1.52-.91-.64.07-.63.07-.63 1 .07 1.53 1.06 1.53 1.06.9 1.57 2.35 1.12 2.92.85.09-.67.35-1.12.63-1.38-2.22-.26-4.55-1.14-4.55-5.06 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.71 0 0 .84-.28 2.75 1.05A9.3 9.3 0 0 1 12 6.94c.85 0 1.7.12 2.5.34 1.9-1.33 2.74-1.05 2.74-1.05.55 1.41.2 2.45.1 2.71.64.72 1.03 1.63 1.03 2.75 0 3.93-2.34 4.8-4.57 5.05.36.32.68.95.68 1.91v2.84c0 .27.18.59.69.49A10.18 10.18 0 0 0 22 12.25C22 6.58 17.52 2 12 2" />
|
||||
@@ -15,7 +16,7 @@ function GitHubMark({ className }: { readonly className?: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
export function NavHeader() {
|
||||
export function NavHeader(): JSX.Element {
|
||||
const t = useTranslations("nav")
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
@@ -59,7 +60,7 @@ export function NavHeader() {
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-zinc-400 hover:bg-zinc-800 hover:text-white md:hidden"
|
||||
className="h-11 w-11 text-zinc-400 hover:bg-zinc-800 hover:text-white md:hidden"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
aria-label={isOpen ? "Close menu" : "Open menu"}
|
||||
aria-expanded={isOpen}
|
||||
@@ -80,31 +81,31 @@ export function NavHeader() {
|
||||
}
|
||||
aria-hidden={!isOpen}
|
||||
>
|
||||
<nav className="flex flex-col gap-4 p-4 text-sm font-medium text-zinc-400">
|
||||
<nav className="flex flex-col gap-1 p-3 text-sm font-medium text-zinc-400">
|
||||
<Link
|
||||
href="/#features"
|
||||
className="transition-colors hover:text-cyan-400"
|
||||
className="flex min-h-11 items-center rounded-md px-3 transition-colors hover:bg-zinc-900 hover:text-cyan-400"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
{t("features")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/#agents"
|
||||
className="transition-colors hover:text-cyan-400"
|
||||
className="flex min-h-11 items-center rounded-md px-3 transition-colors hover:bg-zinc-900 hover:text-cyan-400"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
{t("agents")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs"
|
||||
className="transition-colors hover:text-cyan-400"
|
||||
className="flex min-h-11 items-center rounded-md px-3 transition-colors hover:bg-zinc-900 hover:text-cyan-400"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
{t("docs")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/manifesto"
|
||||
className="transition-colors hover:text-cyan-400"
|
||||
className="flex min-h-11 items-center rounded-md px-3 transition-colors hover:bg-zinc-900 hover:text-cyan-400"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
{t("manifesto")}
|
||||
@@ -113,7 +114,7 @@ export function NavHeader() {
|
||||
href="https://github.com/code-yeongyu/oh-my-openagent"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 transition-colors hover:text-cyan-400 sm:hidden"
|
||||
className="flex min-h-11 items-center gap-2 rounded-md px-3 transition-colors hover:bg-zinc-900 hover:text-cyan-400 sm:hidden"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
<GitHubMark className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user