Conversation
- Adds design for `@arkenv/fumadocs-ui-theme` - Outlines proposal for theme externalization - Details requirements and specifications - Includes implementation tasks and overall plan
🦋 Changeset detectedLatest commit: 5d33421 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughThis PR extracts a new Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant AIActions as "AIActions (client)"
participant Origin as "window.location"
participant Fetch as "Markdown URL (remote/GitHub)"
participant Clipboard as "navigator.clipboard"
User->>AIActions: Click "Copy Markdown"
AIActions->>Origin: read origin (useEffect)
AIActions->>Fetch: fetch(fullMarkdownUrl)
Fetch-->>AIActions: response (markdown text)
AIActions->>Clipboard: navigator.clipboard.writeText(markdown)
Clipboard-->>AIActions: success
AIActions-->>User: show copied feedback
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Outlines new theme package proposal - Details architecture and components - Specifies functional and style requirements - Lists implementation and migration tasks
- Create `@arkenv/fumadocs-ui-theme` package - Move custom MDX components to new theme -
- Centralize URL utility functions - Remove duplicated `isExternalUrl` and `optimizeInternalLink` - Update
- Delete redundant URL utilities from `apps/www` - Rename `Url` type to `ArkenvUrl` for clarity -
- Update package dependencies and lockfile - Add `tsdown` to dev dependencies
- Configure tsdown for package build - Set entry points: index.ts, mdx.tsx - Output
- Separates utilities into a dedicated bundle - Allows importing utils without client directive - Refactors tsdown config for multiple outputs -
- Separate MDX components into own bundle - Remove global 'use client' from MDX bundle - Enable granular client directives in MDX
- Replaced tsdown with tsc and tsc-alias - Updated import paths to use '@/' alias - Changed declaration file extension from .mts to .ts
- Set allowImportingTsExtensions to false - Prevents importing .ts files directly in build
This comment was marked as resolved.
This comment was marked as resolved.
…nks; update imports in index and mdx files
…ross the application
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@openspec/changes/publish-fumadocs-ui/design.md`:
- Around line 32-42: The documentation shows the folder as
packages/fumadocs-ui-theme but the package is actually named
`@arkenv/fumadocs-ui`; update the design.md tree and any occurrences of
packages/fumadocs-ui-theme to packages/fumadocs-ui, and confirm the package.json
"name" field inside that package matches "@arkenv/fumadocs-ui" (also check
related mentions such as mdx.tsx export mappings like arkenvComponents and
index.ts exports to ensure they reference the corrected package name).
In `@openspec/changes/publish-fumadocs-ui/tasks.md`:
- Around line 1-29: The checklist and all task entries still reference the old
package identifier "fumadocs-ui-theme" and paths like
"packages/fumadocs-ui-theme/*"; update every occurrence to the final package
name used in this PR (e.g., replace "fumadocs-ui-theme" and
"packages/fumadocs-ui-theme" in the task list, checklist items, import/package
references, and README/checklist titles), ensure package.json name, tsconfig
path, and any import strings (e.g., in MDX mapping or app imports) match the
final package name, and verify the migration steps (install/import/cleanup
entries) use the new package path.
In `@packages/fumadocs-ui/package.json`:
- Around line 1-71: The package `@arkenv/fumadocs-ui` is missing a changeset for
release/versioning; run the interactive changeset flow (pnpm changeset) from the
repo root, select `@arkenv/fumadocs-ui` in the prompt, choose the appropriate bump
type, and save the generated changeset file (usually under .changeset/) so the
package will be included in the next release; ensure the changeset references
the package name "@arkenv/fumadocs-ui".
In `@packages/fumadocs-ui/src/components/ai-actions.tsx`:
- Around line 55-60: Remove the redundant setLoading(false) inside the catch
block and rely on the existing finally block to clear loading; locate the async
handler in packages/fumadocs-ui/src/components/ai-actions.tsx where setLoading
is toggled (the try/catch/finally surrounding the async operation that logs
errors with console.error(err)) and delete the duplicate setLoading(false) from
the catch clause so only the finally calls setLoading(false).
In `@packages/fumadocs-ui/src/components/code-blocks.tsx`:
- Around line 113-123: The code injects raw SVG via dangerouslySetInnerHTML when
the icon prop is a string (see the conditional rendering around icon); replace
this with a sanitized string: validate or sanitize the string before use
(preferably run it through a sanitizer like DOMPurify or a strict SVG-only
whitelist) and only then pass the sanitized HTML to dangerouslySetInnerHTML, and
update the component prop docs to state that icon must be trusted SVG or will be
sanitized at runtime; ensure the change is applied to the string-branch where
typeof icon === "string" and keep the non-string branch returning icon
unchanged.
🧹 Nitpick comments (11)
packages/fumadocs-ui/src/utils/cn.ts (1)
1-6: Add JSDoc for the publiccnhelper.It’s part of the exported utils surface, so a short doc (with an example) keeps the API self-documenting.
As per coding guidelines, add JSDoc for public APIs.📝 Proposed doc addition
+/** + * Merge conditional class names with Tailwind conflict resolution. + * + * `@example` + * cn("px-2", isActive && "bg-blue-500") + */ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }packages/fumadocs-ui/css/theme.css (2)
9-17: Consider extracting repeated SVG paths to reduce duplication.The external link icons for light and dark modes share identical SVG structure, differing only in the stroke color (
#374151vs#d1d5db). While functional, this creates maintenance overhead if the icon shape changes.One alternative approach is to use
currentColorwith CSS filters or a single icon with color inheritance, though this may increase complexity.
19-36: Excessive!importantusage may complicate future overrides.Multiple
!importantdeclarations (lines 23, 35) are used to override Fumadocs defaults. While necessary for the current integration, this creates a specificity ceiling that makes downstream customization difficult.Consider documenting why these overrides are required, or explore whether Fumadocs provides CSS custom property hooks that could be used instead.
packages/fumadocs-ui/src/utils/url.ts (2)
3-27: Add JSDoc comments for public API functions.Per coding guidelines, public APIs should include JSDoc comments. The
isExternalUrlfunction is part of the package's public surface and would benefit from documentation explaining its behavior, especially the internal domain allowlist.📝 Suggested JSDoc addition
+/** + * Determines whether a URL points to an external site. + * + * `@param` url - The URL to check + * `@returns` `true` if the URL is external, `false` for internal paths, + * Arkenv domains (arkenv.js.org), localhost, or invalid URLs + * + * `@example` + * isExternalUrl("https://github.com") // true + * isExternalUrl("/docs/intro") // false + * isExternalUrl("https://arkenv.js.org/docs") // false + */ export function isExternalUrl(url: string | undefined): boolean {
29-51: Add JSDoc foroptimizeInternalLinkpublic API.Similar to
isExternalUrl, this function should have JSDoc documentation explaining its purpose and behavior.📝 Suggested JSDoc addition
+/** + * Optimizes internal Arkenv links by converting absolute URLs to relative paths. + * + * `@param` url - The URL to optimize + * `@returns` The pathname + search + hash for Arkenv domains, or the original URL otherwise + * + * `@example` + * optimizeInternalLink("https://arkenv.js.org/docs?tab=api#intro") + * // Returns "/docs?tab=api#intro" + */ export function optimizeInternalLink(url: string): string;apps/www/components/announcement-badge.tsx (1)
13-14: TODO comment can be addressed—the detection logic already exists.The TODO suggests detecting arrow direction based on
href, but lines 40-44 already implement this logic usingisExternalUrl(href). The comment may be outdated or refers to making thearrowprop auto-infer its value. Consider removing or clarifying the TODO.Would you like me to help refactor this to auto-detect the arrow type by default, removing the need for manual specification while keeping the override capability?
packages/fumadocs-ui/src/mdx/index.tsx (2)
14-14: Type assertion for MDX component compatibility.The
as anyis a pragmatic workaround for MDX component type incompatibilities. If you want stricter typing later, consider creating a typed wrapper or usingsatisfieswith a looser constraint.
32-37: Consider extracting repetitive heading mappings.The h1-h6 mappings follow an identical pattern. This is fine for clarity, but could be consolidated if preferred:
♻️ Optional DRY refactor
+const headingComponents = Object.fromEntries( + (["h1", "h2", "h3", "h4", "h5", "h6"] as const).map((tag) => [ + tag, + (props: any) => <Heading as={tag} {...props} />, + ]), +) as Pick<MDXComponents, "h1" | "h2" | "h3" | "h4" | "h5" | "h6">; export const arkenvComponents: MDXComponents = { ...defaultComponents, // ... other components - h1: (props: any) => <Heading as="h1" {...props} />, - h2: (props: any) => <Heading as="h2" {...props} />, - h3: (props: any) => <Heading as="h3" {...props} />, - h4: (props: any) => <Heading as="h4" {...props} />, - h5: (props: any) => <Heading as="h5" {...props} />, - h6: (props: any) => <Heading as="h6" {...props} />, + ...headingComponents, };apps/www/app/(home)/page.tsx (1)
93-100: Consider removing redundanttargetandrelattributes.Per the spec,
ExternalLinkautomatically addstarget="_blank"andrel="noopener noreferrer"for external URLs. Sincehttps://arktype.io/...is external, these explicit attributes may be redundant.♻️ Optional cleanup
<ExternalLink href="https://arktype.io/docs/ecosystem#arkenv" - target="_blank" - rel="noopener noreferrer" className="text-gray-900 dark:text-gray-100 transition-colors" > ArkType ecosystem </ExternalLink>apps/www/app/docs/[[...slug]]/page.tsx (1)
29-43: Consider extracting the GitHub URL path computation.The IIFE inside JSX for computing
githubUrlworks but adds cognitive complexity. Consider extracting this to a helper function or computing it before the JSX return.♻️ Suggested refactor
+ const basePath = ( + process.env.NEXT_PUBLIC_DOCS_CONTENT_PATH ?? "apps/www/content/docs/" + ).replace(/\/$/, ""); + const pagePath = page.path.replace(/^\//, ""); + const githubUrl = getLinkTitleAndHref(`${basePath}/${pagePath}`).href; + return ( <DocsPage toc={page.data.toc} full={page.data.full}> <div className="grow"> <DocsTitle className="mb-4">{page.data.title}</DocsTitle> <DocsDescription>{page.data.description}</DocsDescription> <div className="flex flex-row gap-2 items-center border-b pt-2 pb-6 mb-8 mt-4"> <AIActions markdownUrl={`${page.url}.mdx`} - githubUrl={ - getLinkTitleAndHref( - (() => { - const basePath = ( - process.env.NEXT_PUBLIC_DOCS_CONTENT_PATH ?? - "apps/www/content/docs/" - ).replace(/\/$/, ""); // Remove trailing slash if present - const pagePath = page.path.replace(/^\//, ""); // Remove leading slash if present - return `${basePath}/${pagePath}`; - })(), - ).href - } + githubUrl={githubUrl} /> </div>openspec/changes/publish-fumadocs-ui/proposal.md (1)
5-16: Section structure does not match the required format per coding guidelines.The proposal should use sections: "Why", "What Changes" (with BREAKING markers where applicable), and "Impact". Currently the document uses "Motivation", "Scope", and "Relationships".
Additionally, Line 12 references
packages/fumadocs-ui-themebut the PR indicates the package was renamed topackages/fumadocs-ui.📝 Suggested structure alignment
-## Motivation +## Why The custom styling, external link handling, and MDX enhancements developed for Bedstack (a different repository) are highly reusable. Centralizing them into a theme package, but exporting them as an ArkEnv theme allows for: - Consistent branding across all ArkEnv-related documentation. - Simplified maintenance of visual standards (e.g., sharpened corners, header offsets). - Easier adoption of these refinements in other apps. -## Scope -- New package: `packages/fumadocs-ui-theme`. +## What Changes +- New package: `packages/fumadocs-ui`. - CSS Design System (Tailwind v4 based). - Custom MDX Components (`Heading`, `ExternalLink`, `CodeBlock` wrappers). - Shared utilities (`isExternalUrl`). - Migration of `apps/www` to use the new package. -## Relationships +## Impact - This change introduces a new dependency for `apps/www`. - It depends on `fumadocs-ui` and `tailwindcss`.Based on coding guidelines, proposal.md should have sections: Why, What Changes (with BREAKING markers), and Impact.
…build; create README for @arkenv/fumadocs-ui package
📦 Bundle Size Report✅ All size limits passed! |
…o publish-fumadocs-ui; adjust loading state handling in AIActions component
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/fumadocs-ui/README.md`:
- Around line 30-36: The code fence in the README is missing a language
specifier which prevents proper syntax highlighting; update the fenced block
surrounding the import/exports so the opening triple backticks include "ts"
(TypeScript) for the snippet that contains arkenvComponents and the
mdxComponents export to ensure correct highlighting and accessibility.
🧹 Nitpick comments (4)
packages/fumadocs-ui/src/components/ai-actions.tsx (1)
222-222: Remove explicitanytype annotation.The
anytype is unnecessary here since TypeScript can infer the item type from theitemsarray. If explicit typing is preferred, define a proper type for the item shape.♻️ Suggested fix
- {items.map((item: any) => ( + {items.map((item) => (Alternatively, define a type for better documentation:
type ActionItem = { title: string; href: string; icon: React.ReactNode; };packages/fumadocs-ui/README.md (1)
13-13: List specific peer dependencies for clarity.The current instruction to "ensure peer dependencies from
fumadocs-uiare available" is vague. Users need to know exactly which packages and versions are required.📝 Recommended enhancement
Consider replacing line 13 with specific peer dependency information:
-Ensure peer dependencies from `fumadocs-ui` are available, then install: +This package requires the following peer dependencies: + +```bash +pnpm add fumadocs-ui fumadocs-core react react-dom +``` + +Then install the theme package:Alternatively, add a Prerequisites section before Install that lists Node.js version requirements and peer dependencies explicitly.
Based on learnings, README files should document environment requirements clearly.
packages/fumadocs-ui/src/components/code-blocks.tsx (1)
24-62: Prefertypeoverinterfaceper coding guidelines.As per coding guidelines, prefer
typeoverinterfacefor type definitions in TypeScript.♻️ Suggested change
-export interface CodeBlockProps extends ComponentProps<"figure"> { +export type CodeBlockProps = ComponentProps<"figure"> & { /** * Icon of code block * * When passed as a string, it assumes the value is SVG markup. * The string will be sanitized at runtime and should be trusted SVG only. */ icon?: ReactNode; // ... rest of properties Actions?: (props: { className?: string; children?: ReactNode }) => ReactNode; -} +};apps/www/bin/mdx.js (1)
5-45: Consider extracting shared preflight logic withpostinstall.js.
This block mirrors the same Node-options/pnpm/dist checks; a shared helper would reduce drift between scripts.
…ng; update turbo configuration for mdx dependency
…eck for built @arkenv/fumadocs-ui
…of specific config file
…puts and remove output existence check in mdx.js
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
We still need to fix the headings, and the theme itself can be improved but that can be in a separate PR, except for the header I think what we have is working |
- Add guides for applying changes - Add guides for archiving changes - Add guides for creating proposals - Include general OpenSpec instructions
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.claude/commands/openspec/apply.md:
- Line 8: Replace the bolded section titles "**Guardrails**", "**Steps**", and
"**Reference**" with proper level-2 Markdown headings by changing them to "##
Guardrails", "## Steps", and "## Reference"; locate these literal strings in
.claude/commands/openspec/apply.md and update each occurrence to the `##` form
so markdownlint warnings are resolved and document structure uses proper
headings.
🧹 Nitpick comments (2)
.claude/commands/openspec/proposal.md (2)
15-22: Add explicit guidance on proposal.md structure.Based on learnings, the proposal.md created by users should contain specific sections: "Why", "What Changes" (with BREAKING markers when applicable), and "Impact". The current scaffold provides excellent procedural steps but doesn't explicitly instruct users to include these sections in their proposal.md file.
Consider adding a step or note that clarifies the expected structure of the resulting proposal.md document.
📝 Suggested addition to make structure explicit
Add a step or clarification after step 2, for example:
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`. + - Your `proposal.md` should include: **Why** (rationale), **What Changes** (with BREAKING markers for breaking changes), and **Impact** (affected areas/users). 3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.Based on learnings, this is the expected structure for OpenSpec proposals.
8-8: Consider using markdown headings instead of bold text.The section labels (
**Guardrails**,**Steps**,**Reference**) are flagged by markdownlint for using emphasis instead of proper headings. If these represent structural divisions, they should use heading syntax (### Guardrails, etc.) for better semantic markup and consistency with markdown conventions.However, if the bold formatting is intentional for this specific OPENSPEC scaffold format, this can be safely ignored.
♻️ Optional refinement
-**Guardrails** +### Guardrails + - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.Apply similar changes to
**Steps**(line 15) and**Reference**(line 24).Also applies to: 15-15, 24-24
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @arkenv/fumadocs-ui@0.0.2 ### Patch Changes - #### First release _[`#775`](#775) [`bb34860`](bb34860) [@yamcodes](https://github.com/yamcodes)_ `@arkenv/fumadocs-ui` provides a theme, and components, for `fumadocs-ui` to replicate the "ArkEnv" website look. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Closes #774
Summary by CodeRabbit
New Features
Improvements
Chores
✏️ Tip: You can customize this high-level summary in your review settings.