From 717269fac0a09b2dbc402cb93e366da2560691a6 Mon Sep 17 00:00:00 2001 From: Nikita Krupin Date: Tue, 23 Dec 2025 18:06:55 -0500 Subject: [PATCH 1/4] faqs page PoC --- app/docs/faq/page.tsx | 49 +++++++++ app/global.css | 20 ++-- components.json | 22 ++++ components/faq-accordion.tsx | 127 +++++++++++++++++++++++ components/ui/accordion.tsx | 66 ++++++++++++ content/blog/meta.json | 1 + content/docs/meta.json | 1 + content/v5/meta.json | 1 + lib/utils.ts | 6 ++ package.json | 7 +- pnpm-lock.yaml | 195 ++++++++++++++++++++++++++++++++--- 11 files changed, 471 insertions(+), 24 deletions(-) create mode 100644 app/docs/faq/page.tsx create mode 100644 components.json create mode 100644 components/faq-accordion.tsx create mode 100644 components/ui/accordion.tsx create mode 100644 lib/utils.ts diff --git a/app/docs/faq/page.tsx b/app/docs/faq/page.tsx new file mode 100644 index 0000000..0c5d940 --- /dev/null +++ b/app/docs/faq/page.tsx @@ -0,0 +1,49 @@ +import { + DocsPage, + DocsBody, + DocsTitle, + DocsDescription, +} from "fumadocs-ui/page"; + +import { FaqAccordion, FaqItem } from "@/components/faq-accordion"; + +const items: FaqItem[] = [ + { + title: + "Does Nativewind Nativewind", + content: + 'Yes, Nativewind Nativewinds', + }, + { + title: + "Is Nativewind v5 out yet", + content: + "not yet", + }, +]; + +export default async function Page() { + return ( + <> +
+
+
+
+
+ + +
+
+ FAQ + Frequently answered questions +
+
+ {/* TODO: redo FAQAccordion to accept children instead of items and make this a normal mdx page */} +
+ +
+ {/* */} +
+ + ); +} diff --git a/app/global.css b/app/global.css index 4b05066..1841b69 100644 --- a/app/global.css +++ b/app/global.css @@ -1,6 +1,7 @@ @import 'tailwindcss'; @import 'fumadocs-ui/css/neutral.css'; @import 'fumadocs-ui/css/preset.css'; +@import "tw-animate-css"; @source '../node_modules/fumadocs-ui/dist/**/*.js'; @@ -125,7 +126,6 @@ linear-gradient(to bottom, #8884 1px, transparent 1px); } - .bg-grid-lines-y-lg { background-position: -20px -20px; background-size: 40px 40px; @@ -148,16 +148,16 @@ .cut-corners { background:var(transparent, rgb(214, 233, 255)); mask:linear-gradient( - -45deg, - transparent 10.313708498984761px, - white 11.313708498984761px, - white calc(100% - 10.313708498984761px), + -45deg, + transparent 10.313708498984761px, + white 11.313708498984761px, + white calc(100% - 10.313708498984761px), transparent calc(100% - 11.313708498984761px) ), linear-gradient( - 45deg, - transparent -1px, - white 0px, + 45deg, + transparent -1px, + white 0px, white calc(100% - -1px), transparent calc(100% - 0px) );-webkit-mask-composite:destination-in;mask-composite:intersect @@ -217,3 +217,7 @@ html { .cursed { mask-image:radial-gradient(transparent 1px, rgb(15, 17, 21), #ffffff 1px);mask-size:4px 4px; } + +.bevel { + corner-shape: bevel +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..3a64255 --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/global.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/components/faq-accordion.tsx b/components/faq-accordion.tsx new file mode 100644 index 0000000..d0d3a04 --- /dev/null +++ b/components/faq-accordion.tsx @@ -0,0 +1,127 @@ +"use client"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { CheckCheck, Link } from "lucide-react"; +import { useEffect, useState } from "react"; + +export type FaqItem = { + icon?: React.ReactNode; + title: string; + content: React.ReactNode | string; +}; + +let hashListenerAttached = false; + +export function FaqAccordion({ items }: { items: FaqItem[] }) { + useEffect(() => { + if (hashListenerAttached) return; + hashListenerAttached = true; + + const handleHashChange = () => { + const id = decodeURIComponent(location.href).split("#")[1]; + console.log("FAQ Accordion hash change detected:", id); + + // trigger opening the accordion item + const accordionItem = document.getElementById(id); + const h3 = accordionItem?.querySelector("h3"); + const trigger = h3?.querySelector("button"); + if (trigger && trigger.getAttribute("data-state") !== "open") + trigger.click(); + }; + + window.addEventListener("hashchange", handleHashChange); + handleHashChange(); // Call it initially to handle the current hash + + return () => { + window.removeEventListener("hashchange", handleHashChange); + hashListenerAttached = false; + }; + }, []); + + return ( + + {items.map((item, index) => ( + + + +
+ {item.title} + {item.icon} +
+
+ + {item.content} + +
+ ))} +
+ ); +} + +export function ExternalLink({ + href, + children, +}: { + href: string; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +function CopyLinkToHighlight({ title }: { title: string }) { + const [copied, setCopied] = useState(false); + + const handleCopyLink = (e: React.MouseEvent) => { + setCopied(true); + + e.preventDefault(); + const base = window.location.origin + window.location.pathname; + const encoded = encodeURIComponent(title); + const url = `${base}#${encoded}:~:text=${encoded.replace(/-/g, "%2D")}`; + navigator.clipboard.writeText(url); + + setTimeout(() => { + setCopied(false); + }, 1500); + }; + + return ( + + ); +} diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx new file mode 100644 index 0000000..4a8cca4 --- /dev/null +++ b/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/content/blog/meta.json b/content/blog/meta.json index 09fc7a7..be455b0 100644 --- a/content/blog/meta.json +++ b/content/blog/meta.json @@ -1,5 +1,6 @@ { "pages": [ + "[FileQuestionMark][FAQ](/docs/faq/)", "[BookOpen][Docs](/docs/)", "[LayoutTemplate][Showcase](/#showcase)", "[Box][Resources](/resources/)", diff --git a/content/docs/meta.json b/content/docs/meta.json index df0c741..ae745cd 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -1,5 +1,6 @@ { "pages": [ + "[FileQuestionMark][FAQ](/docs/faq/)", "[BookText][Blog](/blog/)", "[LayoutTemplate][Showcase](/#showcase)", "[Box][Resources](/resources/)", diff --git a/content/v5/meta.json b/content/v5/meta.json index d470be3..6026f1a 100644 --- a/content/v5/meta.json +++ b/content/v5/meta.json @@ -1,5 +1,6 @@ { "pages": [ + "[FileQuestionMark][FAQ](/docs/faq/)", "[BookText][Blog](/blog/)", "[LayoutTemplate][Showcase](/#showcase)", "[Box][Resources](/resources/)", diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/package.json b/package.json index 5b2724d..906b1d9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "validate": "tsx scripts/validate-urls.ts ." }, "dependencies": { + "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-collapsible": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.2.6", "@radix-ui/react-popover": "^1.1.7", @@ -18,10 +19,11 @@ "@radix-ui/react-tabs": "^1.1.4", "@vercel/analytics": "^1.5.0", "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "fumadocs-core": "15.2.7", "fumadocs-mdx": "11.6.0", "fumadocs-ui": "15.2.7", - "lucide-react": "^0.488.0", + "lucide-react": "^0.562.0", "next": "15.3.8", "next-themes": "^0.4.6", "react": "19.1.0", @@ -39,7 +41,8 @@ "postcss": "^8.5.3", "tailwindcss": "^4.1.4", "ts-node": "^10.9.2", + "tw-animate-css": "^1.4.0", "typescript": "^5.8.3" }, - "packageManager": "pnpm@10.25.0" + "packageManager": "pnpm@10.26.2" } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d73e0a..3373801 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@radix-ui/react-accordion': + specifier: ^1.2.12 + version: 1.2.12(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-collapsible': specifier: ^1.1.4 version: 1.1.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -32,6 +35,9 @@ importers: class-variance-authority: specifier: ^0.7.1 version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 fumadocs-core: specifier: 15.2.7 version: 15.2.7(@types/react@19.1.0)(next@15.3.8(@babel/core@7.26.10)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -42,8 +48,8 @@ importers: specifier: 15.2.7 version: 15.2.7(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(next@15.3.8(@babel/core@7.26.10)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tailwindcss@4.1.4) lucide-react: - specifier: ^0.488.0 - version: 0.488.0(react@19.1.0) + specifier: ^0.562.0 + version: 0.562.0(react@19.1.0) next: specifier: 15.3.8 version: 15.3.8(@babel/core@7.26.10)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -90,6 +96,9 @@ importers: ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.14.1)(typescript@5.8.3) + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 typescript: specifier: ^5.8.3 version: 5.8.3 @@ -1031,8 +1040,11 @@ packages: '@radix-ui/primitive@1.1.2': resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} - '@radix-ui/react-accordion@1.2.4': - resolution: {integrity: sha512-SGCxlSBaMvEzDROzyZjsVNzu9XY5E28B3k8jOENyrz6csOv/pG1eHyYfLJai1n9tRjwG61coXDhfpgtxKxUv5g==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-accordion@1.2.12': + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1057,6 +1069,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collapsible@1.1.12': + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-collapsible@1.1.4': resolution: {integrity: sha512-u7LCw1EYInQtBNLGjm9nZ89S/4GcvX1UR5XbekEgnQae2Hkpq39ycJ1OhdeN1/JDfVNG91kWaWoest127TaEKQ==} peerDependencies: @@ -1083,6 +1108,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: @@ -1232,6 +1270,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@2.0.3': resolution: {integrity: sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g==} peerDependencies: @@ -1245,6 +1296,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-roving-focus@1.1.3': resolution: {integrity: sha512-ufbpLUjZiOg4iYgb2hQrWXEPYX6jOLBbR27bDyAff5GYMRrCzcze8lukjuXVUQvJ6HZe8+oL+hhswDcjmcgVyg==} peerDependencies: @@ -1280,6 +1344,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-tabs@1.1.4': resolution: {integrity: sha512-fuHMHWSf5SRhXke+DbHXj2wVMo+ghVH30vhX3XVacdXqDl+J4XWafMIGOOER861QpBx1jxgwKXL2dQnfrsd8MQ==} peerDependencies: @@ -1311,6 +1384,24 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-escape-keydown@1.1.1': resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: @@ -2261,8 +2352,8 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@0.488.0: - resolution: {integrity: sha512-ronlL0MyKut4CEzBY/ai2ZpKPxyWO4jUqdAkm2GNK5Zn3Rj+swDz+3lvyAUXN0PNqPKIX6XM9Xadwz/skLs/pQ==} + lucide-react@0.562.0: + resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -2816,6 +2907,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} @@ -3922,17 +4016,19 @@ snapshots: '@radix-ui/primitive@1.1.2': {} - '@radix-ui/react-accordion@1.2.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collapsible': 1.1.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-collection': 1.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.0)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.0)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.0)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.0)(react@19.1.0) - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.0)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: @@ -3948,6 +4044,22 @@ snapshots: '@types/react': 19.1.0 '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.0 + '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-collapsible@1.1.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -3976,6 +4088,18 @@ snapshots: '@types/react': 19.1.0 '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.0 + '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.0)(react@19.1.0)': dependencies: react: 19.1.0 @@ -4136,6 +4260,16 @@ snapshots: '@types/react': 19.1.0 '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.0 + '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-slot': 1.2.0(@types/react@19.1.0)(react@19.1.0) @@ -4145,6 +4279,15 @@ snapshots: '@types/react': 19.1.0 '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.0 + '@types/react-dom': 19.1.0(@types/react@19.1.0) + '@radix-ui/react-roving-focus@1.1.3(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -4186,6 +4329,13 @@ snapshots: optionalDependencies: '@types/react': 19.1.0 + '@radix-ui/react-slot@1.2.3(@types/react@19.1.0)(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.0 + '@radix-ui/react-tabs@1.1.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -4215,6 +4365,21 @@ snapshots: optionalDependencies: '@types/react': 19.1.0 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.0)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.0)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.0 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.0)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.0)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.0 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.0)(react@19.1.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.0)(react@19.1.0) @@ -4921,7 +5086,7 @@ snapshots: fumadocs-ui@15.2.7(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(next@15.3.8(@babel/core@7.26.10)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tailwindcss@4.1.4): dependencies: - '@radix-ui/react-accordion': 1.2.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-collapsible': 1.1.4(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-dialog': 1.1.7(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.0)(react@19.1.0) @@ -5179,7 +5344,7 @@ snapshots: dependencies: react: 19.1.0 - lucide-react@0.488.0(react@19.1.0): + lucide-react@0.562.0(react@19.1.0): dependencies: react: 19.1.0 @@ -6075,6 +6240,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tw-animate-css@1.4.0: {} + typescript@5.8.3: {} undici-types@6.21.0: {} From 90b166e495314d67ed07e98d72d7ed07b53e2888 Mon Sep 17 00:00:00 2001 From: Nikita Krupin Date: Tue, 6 Jan 2026 18:21:08 -0500 Subject: [PATCH 2/4] added stable scrollbar-gutter (to fix jumping with scrollbars), split faqs for /v5/ and /docs/, update faq accordion mobile styles --- app/docs/faq/page.tsx | 22 +++++++++++---- app/global.css | 1 + app/v5/faq/page.tsx | 54 ++++++++++++++++++++++++++++++++++++ components/faq-accordion.tsx | 4 +-- content/blog/meta.json | 1 - content/v5/meta.json | 2 +- 6 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 app/v5/faq/page.tsx diff --git a/app/docs/faq/page.tsx b/app/docs/faq/page.tsx index 0c5d940..144f264 100644 --- a/app/docs/faq/page.tsx +++ b/app/docs/faq/page.tsx @@ -6,6 +6,8 @@ import { } from "fumadocs-ui/page"; import { FaqAccordion, FaqItem } from "@/components/faq-accordion"; +import Link from "fumadocs-core/link"; +import { FileQuestionMark } from "lucide-react"; const items: FaqItem[] = [ { @@ -18,11 +20,15 @@ const items: FaqItem[] = [ title: "Is Nativewind v5 out yet", content: - "not yet", + ( + <> + not yet, check out the v5 FAQ for more info. + + ), }, ]; -export default async function Page() { +export default async function FAQPage() { return ( <>
@@ -32,17 +38,21 @@ export default async function Page() {
-
+
FAQ - Frequently answered questions + Frequently answered questions +
+
+ + + v5 +
- {/* TODO: redo FAQAccordion to accept children instead of items and make this a normal mdx page */}
- {/* */} ); diff --git a/app/global.css b/app/global.css index 1841b69..c95c9f8 100644 --- a/app/global.css +++ b/app/global.css @@ -183,6 +183,7 @@ /* smooth scroll */ html { + scrollbar-gutter: stable; scroll-behavior: smooth; scroll-padding-top: 3rem; } diff --git a/app/v5/faq/page.tsx b/app/v5/faq/page.tsx new file mode 100644 index 0000000..9739cb3 --- /dev/null +++ b/app/v5/faq/page.tsx @@ -0,0 +1,54 @@ +import { + DocsPage, + DocsTitle, + DocsDescription, +} from "fumadocs-ui/page"; + +import { FaqAccordion, type FaqItem } from "@/components/faq-accordion"; +import Link from "fumadocs-core/link"; +import { FileQuestionMark } from "lucide-react"; + +const items: FaqItem[] = [ + { + title: + "Is v5 out yet?", + content: + 'maybe', + }, + { + title: + "Is v5 stable?", + content: + "almost", + }, +]; + +export default async function FAQPage() { + return ( + <> +
+
+
+
+
+ + +
+
+ V5 FAQ + Frequently answered questions for v5 +
+
+ + + v4 + +
+
+
+ +
+
+ + ); +} diff --git a/components/faq-accordion.tsx b/components/faq-accordion.tsx index d0d3a04..163847d 100644 --- a/components/faq-accordion.tsx +++ b/components/faq-accordion.tsx @@ -52,8 +52,8 @@ export function FaqAccordion({ items }: { items: FaqItem[] }) { value={`item-${index + 1}`} > - -
+ +
{item.title} {item.icon}
diff --git a/content/blog/meta.json b/content/blog/meta.json index be455b0..09fc7a7 100644 --- a/content/blog/meta.json +++ b/content/blog/meta.json @@ -1,6 +1,5 @@ { "pages": [ - "[FileQuestionMark][FAQ](/docs/faq/)", "[BookOpen][Docs](/docs/)", "[LayoutTemplate][Showcase](/#showcase)", "[Box][Resources](/resources/)", diff --git a/content/v5/meta.json b/content/v5/meta.json index 6026f1a..242c493 100644 --- a/content/v5/meta.json +++ b/content/v5/meta.json @@ -1,6 +1,6 @@ { "pages": [ - "[FileQuestionMark][FAQ](/docs/faq/)", + "[FileQuestionMark][FAQ](/v5/faq/)", "[BookText][Blog](/blog/)", "[LayoutTemplate][Showcase](/#showcase)", "[Box][Resources](/resources/)", From aaf1c386c811c30bdda46c49c187600f964b7fb0 Mon Sep 17 00:00:00 2001 From: Nikita Krupin Date: Tue, 6 Jan 2026 18:34:12 -0500 Subject: [PATCH 3/4] cleanup, organize imports, add metadata to faq pages --- app/docs/[[...slug]]/page.tsx | 72 ++++++++++++++------------------ app/docs/faq/faq-items.tsx | 21 ++++++++++ app/docs/faq/page.tsx | 65 +++++++++-------------------- app/docs/faq/v5-faq-link.tsx | 11 +++++ app/docs/layout.tsx | 6 +++ app/v5/[[...slug]]/page.tsx | 78 ++++++++++++++++------------------- app/v5/faq/page.tsx | 60 +++++++++------------------ app/v5/faq/v4-faq-link.tsx | 11 +++++ app/v5/faq/v5-faq-items.tsx | 16 +++++++ app/v5/layout.tsx | 6 +++ 10 files changed, 178 insertions(+), 168 deletions(-) create mode 100644 app/docs/faq/faq-items.tsx create mode 100644 app/docs/faq/v5-faq-link.tsx create mode 100644 app/v5/faq/v4-faq-link.tsx create mode 100644 app/v5/faq/v5-faq-items.tsx diff --git a/app/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx index 20c63e4..4b542f4 100644 --- a/app/docs/[[...slug]]/page.tsx +++ b/app/docs/[[...slug]]/page.tsx @@ -7,13 +7,13 @@ import { } from 'fumadocs-ui/page'; import { notFound } from 'next/navigation'; -import { ComponentProps, FC } from 'react'; +import type { ComponentProps, FC } from 'react'; import defaultMdxComponents from 'fumadocs-ui/mdx'; import { Callout } from '@/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { createRelativeLink } from 'fumadocs-ui/mdx'; -import FooterSection from '@/app/(home)/FooterSection'; +// import FooterSection from '@/app/(home)/FooterSection'; import { EditButton } from '@/components/edit-button'; export default async function Page(props: { @@ -39,45 +39,37 @@ export default async function Page(props: { } return ( - <> -
-
-
-
-
- - - {/* TODO: install DocsPage FumaDocsv15 and reorder contents */} - {/* lastUpdate={page.data.lastModified && new Date(page.data.lastModified)} */} - {page.data.lastModified && ( -

- Last updated on {Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(new Date(page.data.lastModified))} -

- )} -
-
- {page.data.title} - {page.data.description} -
- + + {/* TODO: install DocsPage FumaDocsv15 and reorder contents */} + {/* lastUpdate={page.data.lastModified && new Date(page.data.lastModified)} */} + {page.data.lastModified && ( +

+ Last updated on {Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(new Date(page.data.lastModified))} +

+ )} +
+
+ {page.data.title} + {page.data.description}
- - >, - Tab, Tabs, - Callout, - }} /> - - {/* */} - - + +
+ + >, + Tab, Tabs, + Callout, + }} /> + + {/* */} +
); } diff --git a/app/docs/faq/faq-items.tsx b/app/docs/faq/faq-items.tsx new file mode 100644 index 0000000..3d0dce0 --- /dev/null +++ b/app/docs/faq/faq-items.tsx @@ -0,0 +1,21 @@ +import Link from "fumadocs-core/link"; +import type { FaqItem } from "@/components/faq-accordion" + +export const items: FaqItem[] = [ + { + title: + "Does Nativewind Nativewind", + content: + 'Yes, Nativewind Nativewinds', + }, + { + title: + "Is Nativewind v5 out yet", + content: + ( + <> + not yet, check out the v5 FAQ for more info. + + ), + }, +]; \ No newline at end of file diff --git a/app/docs/faq/page.tsx b/app/docs/faq/page.tsx index 144f264..193486e 100644 --- a/app/docs/faq/page.tsx +++ b/app/docs/faq/page.tsx @@ -1,59 +1,34 @@ import { DocsPage, - DocsBody, DocsTitle, DocsDescription, } from "fumadocs-ui/page"; +import type { Metadata } from "next"; -import { FaqAccordion, FaqItem } from "@/components/faq-accordion"; -import Link from "fumadocs-core/link"; -import { FileQuestionMark } from "lucide-react"; +import { items } from "./faq-items"; +import { V5FAQLink } from "./v5-faq-link"; +import { FaqAccordion } from "@/components/faq-accordion"; -const items: FaqItem[] = [ - { - title: - "Does Nativewind Nativewind", - content: - 'Yes, Nativewind Nativewinds', - }, - { - title: - "Is Nativewind v5 out yet", - content: - ( - <> - not yet, check out the v5 FAQ for more info. - - ), - }, -]; +export const metadata: Metadata = { + title: "FAQ", + description: "Frequently answered questions about NativeWind", +}; export default async function FAQPage() { return ( - <> -
-
-
-
-
- - -
-
- FAQ - Frequently answered questions -
-
- - - v5 - -
+ +
+
+ FAQ + Frequently answered questions
-
- +
+
- - +
+
+ +
+ ); } diff --git a/app/docs/faq/v5-faq-link.tsx b/app/docs/faq/v5-faq-link.tsx new file mode 100644 index 0000000..a3a0675 --- /dev/null +++ b/app/docs/faq/v5-faq-link.tsx @@ -0,0 +1,11 @@ +import Link from "fumadocs-core/link"; +import { FileQuestionMark } from "lucide-react"; + +export function V5FAQLink() { + return ( + + + v5 + + ); +} \ No newline at end of file diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx index 5d34095..f064b19 100644 --- a/app/docs/layout.tsx +++ b/app/docs/layout.tsx @@ -80,6 +80,12 @@ export default function Layout({ children }: { children: ReactNode }) { ), }} > + {/* background decoration */} +
+
+
+
+
{children} ); diff --git a/app/v5/[[...slug]]/page.tsx b/app/v5/[[...slug]]/page.tsx index db8b1c4..ee2f0ad 100644 --- a/app/v5/[[...slug]]/page.tsx +++ b/app/v5/[[...slug]]/page.tsx @@ -7,13 +7,13 @@ import { } from 'fumadocs-ui/page'; import { notFound } from 'next/navigation'; -import { ComponentProps, FC } from 'react'; +import type { ComponentProps, FC } from 'react'; import defaultMdxComponents from 'fumadocs-ui/mdx'; import { Callout } from '@/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { createRelativeLink } from 'fumadocs-ui/mdx'; -import FooterSection from '@/app/(home)/FooterSection'; +// import FooterSection from '@/app/(home)/FooterSection'; import { EditButton } from '@/components/edit-button'; import { CopyInstallationButton } from '@/components/copy-installation-button'; @@ -43,48 +43,40 @@ export default async function Page(props: { const isInstallationPage = params.slug?.join('/') === 'getting-started/installation'; return ( - <> -
-
-
-
-
- - - {/* TODO: install DocsPage FumaDocsv15 and reorder contents */} - {/* lastUpdate={page.data.lastModified && new Date(page.data.lastModified)} */} - {page.data.lastModified && ( -

- Last updated on {Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(new Date(page.data.lastModified))} -

- )} -
-
- {page.data.title} - {page.data.description} -
-
- - {isInstallationPage && } -
+ + {/* // TODO: install DocsPage FumaDocsv15 and reorder contents */} + {/* lastUpdate={page.data.lastModified && new Date(page.data.lastModified)} */} + {page.data.lastModified && ( +

+ Last updated on {Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(new Date(page.data.lastModified))} +

+ )} +
+
+ {page.data.title} + {page.data.description} +
+
+ + {isInstallationPage && }
- - >, - Tab, Tabs, - Callout, - }} /> - - {/* */} - - +
+ + >, + Tab, Tabs, + Callout, + }} /> + + {/* */} +
); } diff --git a/app/v5/faq/page.tsx b/app/v5/faq/page.tsx index 9739cb3..a7f20fe 100644 --- a/app/v5/faq/page.tsx +++ b/app/v5/faq/page.tsx @@ -3,52 +3,32 @@ import { DocsTitle, DocsDescription, } from "fumadocs-ui/page"; +import type { Metadata } from "next"; -import { FaqAccordion, type FaqItem } from "@/components/faq-accordion"; -import Link from "fumadocs-core/link"; -import { FileQuestionMark } from "lucide-react"; +import { items } from "./v5-faq-items"; +import { V4FAQLink } from "./v4-faq-link"; +import { FaqAccordion } from "@/components/faq-accordion"; -const items: FaqItem[] = [ - { - title: - "Is v5 out yet?", - content: - 'maybe', - }, - { - title: - "Is v5 stable?", - content: - "almost", - }, -]; +export const metadata: Metadata = { + title: "v5 FAQ", + description: "Frequently answered questions about NativeWind v5", +}; export default async function FAQPage() { return ( - <> -
-
-
-
-
- - -
-
- V5 FAQ - Frequently answered questions for v5 -
-
- - - v4 - -
+ +
+
+ V5 FAQ + Frequently answered questions for v5
-
- +
+
- - +
+
+ +
+ ); } diff --git a/app/v5/faq/v4-faq-link.tsx b/app/v5/faq/v4-faq-link.tsx new file mode 100644 index 0000000..a80b607 --- /dev/null +++ b/app/v5/faq/v4-faq-link.tsx @@ -0,0 +1,11 @@ +import Link from "fumadocs-core/link"; +import { FileQuestionMark } from "lucide-react"; + +export function V4FAQLink() { + return ( + + + v4 + + ); +} \ No newline at end of file diff --git a/app/v5/faq/v5-faq-items.tsx b/app/v5/faq/v5-faq-items.tsx new file mode 100644 index 0000000..9127506 --- /dev/null +++ b/app/v5/faq/v5-faq-items.tsx @@ -0,0 +1,16 @@ +import type { FaqItem } from "@/components/faq-accordion"; + +export const items: FaqItem[] = [ + { + title: + "Is v5 out yet?", + content: + 'maybe', + }, + { + title: + "Is v5 stable?", + content: + "almost", + }, +]; diff --git a/app/v5/layout.tsx b/app/v5/layout.tsx index a922dd2..4f2c812 100644 --- a/app/v5/layout.tsx +++ b/app/v5/layout.tsx @@ -80,6 +80,12 @@ export default function Layout({ children }: { children: ReactNode }) { ), }} > + {/* background decoration */} +
+
+
+
+
{children} ); From 11e00a0a5559e10ff0087659a17124fa0e9724ef Mon Sep 17 00:00:00 2001 From: Nikita Krupin Date: Tue, 6 Jan 2026 18:38:15 -0500 Subject: [PATCH 4/4] remove a console.log --- components/faq-accordion.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/faq-accordion.tsx b/components/faq-accordion.tsx index 163847d..89943e2 100644 --- a/components/faq-accordion.tsx +++ b/components/faq-accordion.tsx @@ -23,7 +23,6 @@ export function FaqAccordion({ items }: { items: FaqItem[] }) { const handleHashChange = () => { const id = decodeURIComponent(location.href).split("#")[1]; - console.log("FAQ Accordion hash change detected:", id); // trigger opening the accordion item const accordionItem = document.getElementById(id);