Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 27, 2025

External links in documentation now display arrow icons (↗) to indicate navigation away from the site, following modern web UX patterns.

Implementation

Hybrid Approach

  • CSS Rule: Targets all <article> links starting with http:// or https://, excluding same-domain (arkenv.js.org) and localhost
  • React Component: ExternalLink wraps fumadocs Link component for programmatic control

Hybrid approach necessary because fumadocs' <include> directive processes markdown at build time, bypassing MDX component system for some links.

CSS Custom Property

@theme {
  --external-link-arrow: url('data:image/svg+xml,...');
}

article a[href^="http"]:not([href*="arkenv.js.org"])::after {
  background-image: var(--external-link-arrow);
  /* ... */
}

SSR-Safe Detection

const base = typeof window !== "undefined" 
  ? window.location.origin 
  : "https://arkenv.js.org";
const url = new URL(href, base);

Result

External links with arrows

Links like "ArkType" and "Standard Schema" now show visual indicators for external navigation.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • fonts.googleapis.com
    • Triggering command: /usr/local/bin/node node ./node_modules/.bin/../next/dist/bin/next build (dns block)
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/arkenv/arkenv/node_modules/.pnpm/[email protected]_@babel&#43;[email protected]_@opentelemetry&#43;[email protected]_@playwright&#43;[email protected]_react-d_f42438f6717e44ec3de5d0c1806f5fb0/node_modules/next/dist/server/lib/start-server.js (dns block)
  • https://api.github.com/repos/yamcodes/arkenv

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>External links should have an arrow</issue_title>
<issue_description>In modern web dev, we tend to see a "top right" arrow next to external links:

Image

Implement a component or an integrated way to achieve this within our Fumadocs/Next.js stack in the www app.
This should only apply to underlined links/buttons, not to actual distinct (primary/secondary/etc.) buttons. Basically only to things that look like a part of text.

The only exceptions are:

  1. Internal links (links that route you from within the Next.js app)
  2. External links that are actually internal (in other words have the same domain as the website)</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Summary by CodeRabbit

  • New Features
    • External links now show a subtle arrow indicator and improved underline styling across docs so off-site links are visually distinct.
    • MDX links updated to use the new external-link behavior by default.
  • UI Changes
    • Some cards no longer display icon artwork — titles and links remain unchanged.
    • "Edit on GitHub" links receive presentation attributes to opt out of underline/arrow where used.
  • Tests
    • Added tests validating external-link detection, rendering, attributes, and accessibility.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI self-assigned this Dec 27, 2025
@changeset-bot
Copy link

changeset-bot bot commented Dec 27, 2025

⚠️ No Changeset found

Latest commit: 7919ac1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Dec 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
arkenv Ready Ready Preview, Comment Dec 27, 2025 3:56pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

Warning

Rate limit exceeded

@yamcodes has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 45 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8767885 and 7919ac1.

📒 Files selected for processing (2)
  • apps/www/components/ui/card.tsx
  • apps/www/components/ui/external-link.tsx

Walkthrough

Adds an ExternalLink React component, SSR/CSR-safe URL utility, global CSS to render an external-arrow indicator, tests, MDX mapping so a uses the new component, small Card and MDX edits to opt out of arrow/underline, and minor README formatting tweaks.

Changes

Cohort / File(s) Summary
Styling
apps/www/app/globals.css
Adds --external-link-arrow data-URL SVG, rules for a[data-external-link]::after, and link underline hover/padding adjustments.
URL utils
apps/www/lib/utils/url.ts
New INTERNAL_DOMAINS and isExternalUrl(href) — SSR/CSR-aware logic for determining external links (relative/hash handling, domain/subdomain checks, parse safety).
ExternalLink component
apps/www/components/ui/external-link.tsx
New client-side ExternalLink and ExternalLinkProps; uses isExternalUrl, sets data-external-link for external URLs and appends ArrowUpRight icon; defaults to internal on parse failure; SSR/CSR branch behavior included.
Tests
apps/www/components/ui/external-link.test.tsx
New test suite (mocks fumadocs-core/link) verifying detection across http/https, relative/hash/same-domain/localhost cases, attribute propagation, and ARIA-hidden icon.
MDX integration
apps/www/mdx-components.tsx
Imports and maps aExternalLink; changes spreading order so customComponents take precedence over twoslashComponents.
Card adjustments
apps/www/components/ui/card.tsx, apps/www/content/docs/**/*.mdx
Card component now computes augmented title and may render an external arrow for external href; several MDX files remove icon prop usage and some Card usages gain data-no-underline/data-no-arrow attributes.
Docs / Examples
examples/README.md
Markdown/link formatting changes in examples README (presentation only).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I nibble links that near and far,

a tiny arrow hops beside each star.
Home burrows keep their secret trail,
while outside paths get a silver tail. ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Most changes align with objectives, but examples/README.md contains unrelated formatting changes and introduces a malformed markdown link that appears out of scope. Remove unrelated markdown formatting changes and fix the malformed link in examples/README.md, or move those changes to a separate PR focused on documentation formatting.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding visual indicators to external links in the documentation.
Linked Issues check ✅ Passed The PR fulfills all coding requirements from issue #644: implements external link indicators via CSS and React component, excludes internal links and same-domain external links, and handles SSR/CSR compatibility.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI changed the title [WIP] Add arrow indicator for external links Add external link indicators to documentation Dec 27, 2025
Copilot AI requested a review from yamcodes December 27, 2025 08:36
@yamcodes yamcodes marked this pull request as ready for review December 27, 2025 12:06
@github-actions github-actions bot added www Improvements or additions to arkenv.js.org tests This issue or PR is about adding, removing or changing tests. labels Dec 27, 2025
@yamcodes
Copy link
Owner

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (6)
apps/www/app/globals.css (1)

15-18: URL-encode special characters in SVG data URI.

The SVG data URL contains unencoded special characters (<, >, ") that may cause issues in some browsers or build tools. Encode them for maximum compatibility.

🔎 Proposed fix with URL-encoded SVG
-	--external-link-arrow: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h10v10"/><path d="M7 17 17 7"/></svg>');
+	--external-link-arrow: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M7 7h10v10"/%3E%3Cpath d="M7 17 17 7"/%3E%3C/svg%3E');
apps/www/components/ui/external-link.test.tsx (1)

16-79: Testing implementation details instead of behavior.

The tests query for querySelector("svg") to verify external link detection. This checks the implementation (that an SVG icon is rendered) rather than the behavior (that external links are visually distinguished). If the icon changes from SVG to a different element, tests break unnecessarily.

Based on learnings: test component behavior and API, not implementation details.

Consider testing the presence of the icon by its accessible role or by verifying that the link element contains a child with aria-hidden="true", or simply verify that isExternal logic works correctly via unit tests of the isExternalUrl function separately.

apps/www/components/ui/external-link.tsx (4)

7-9: Redundant href redefinition in ExternalLinkProps.

Line 8 redefines href?: string, but ComponentProps<typeof FumadocsLink> already includes href. This redefinition doesn't change the type (since both are optional strings) but adds unnecessary noise and could mask future type changes in the base component.

🔎 Proposed simplification

If the base type already includes href, simply extend without redefining:

-export interface ExternalLinkProps extends ComponentProps<typeof FumadocsLink> {
-	href?: string;
-}
+export interface ExternalLinkProps extends ComponentProps<typeof FumadocsLink> {}

Or use a type alias:

-export interface ExternalLinkProps extends ComponentProps<typeof FumadocsLink> {
-	href?: string;
-}
+export type ExternalLinkProps = ComponentProps<typeof FumadocsLink>;

14-19: Consider using a Set for O(1) domain lookups.

INTERNAL_DOMAINS is currently an array, resulting in O(n) lookups via .some() on line 42. Since the list is static and small, the performance impact is negligible, but using a Set is more idiomatic for membership checks and scales better if the list grows.

🔎 Proposed refactor to use Set
-const INTERNAL_DOMAINS = [
+const INTERNAL_DOMAINS = new Set([
 	"arkenv.js.org",
 	"www.arkenv.js.org",
 	"localhost",
 	"127.0.0.1",
-];
+]);

Then update line 42:

-		if (
-			INTERNAL_DOMAINS.some(
-				(domain) => hostname === domain || hostname.endsWith(`.${domain}`),
-			)
-		) {
+		for (const domain of INTERNAL_DOMAINS) {
+			if (hostname === domain || hostname.endsWith(`.${domain}`)) {
+				return false;
+			}
+		}
-			return false;
-		}

Or keep as array with a comment noting the small size makes performance irrelevant.


33-36: Extract hardcoded fallback base URL to a named constant.

The SSR fallback "https://arkenv.js.org" is hardcoded and duplicates the domain from INTERNAL_DOMAINS. Extracting it improves maintainability.

🔎 Proposed refactor
+/**
+ * Default base URL for SSR environments where window is not available
+ */
+const DEFAULT_BASE_URL = "https://arkenv.js.org";
+
 /**
  * List of domains that should be treated as internal (same site)
  */
 const INTERNAL_DOMAINS = [
 	"arkenv.js.org",
 	// ...
 ];

 function isExternalUrl(href: string | undefined): boolean {
 	// ...
 	try {
 		const base =
 			typeof window !== "undefined"
 				? window.location.origin
-				: "https://arkenv.js.org";
+				: DEFAULT_BASE_URL;

24-60: Consider exporting isExternalUrl for reuse and testability.

The isExternalUrl helper contains complex logic with multiple edge cases (relative paths, protocols, domain matching, SSR handling). Exporting it would enable direct unit testing of this logic independently of the component, reducing the need for indirect testing via component rendering.

Rationale
  • Testability: Unit tests can directly verify isExternalUrl behavior for all edge cases without rendering components.
  • Reusability: Other parts of the codebase may need similar external URL detection.
  • Clarity: The public API makes the component's behavior more transparent.

Example export:

 /**
  * Checks if a URL is external (not same domain or not a relative path)
+ * @public
  */
-function isExternalUrl(href: string | undefined): boolean {
+export function isExternalUrl(href: string | undefined): boolean {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12832fd and a5cd632.

📒 Files selected for processing (4)
  • apps/www/app/globals.css
  • apps/www/components/ui/external-link.test.tsx
  • apps/www/components/ui/external-link.tsx
  • apps/www/mdx-components.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

**/*.{ts,tsx}: Prefer type over interface for type definitions in TypeScript
Use TypeScript 5.1+ features when appropriate
Leverage const type parameters for better inference in TypeScript
Use JSDoc comments for public APIs
Use tabs for indentation (configured in Biome)
Use double quotes for strings (configured in Biome)
Organize imports automatically (Biome handles this)
Avoid explicit types when TypeScript can infer them (noInferrableTypes error)
Use as const where appropriate for immutable values (useAsConstAssertion error)
Don't reassign function parameters (noParameterAssign error)
Place default parameters last in function signatures (useDefaultParameterLast error)
Always initialize enum values (useEnumInitializers error)
Declare one variable per statement (useSingleVarDeclarator error)
Avoid unnecessary template literals (noUnusedTemplateLiteral error)
Prefer Number.parseInt over global parseInt (useNumberNamespace error)
Use kebab-case for TypeScript filenames (e.g., create-env.ts)
Use camelCase for function names (e.g., createEnv)
Use PascalCase for type names (e.g., ArkEnvError)
Use UPPER_SNAKE_CASE for environment variables and constants
Include examples in JSDoc comments when helpful for public APIs
Document complex type logic with JSDoc comments
Use ArkEnvError for environment variable validation errors
Provide clear, actionable error messages that include the variable name and expected type

**/*.{ts,tsx}: Use createEnv(schema) function (or default import as arkenv) to create validated environment objects in TypeScript
Use built-in validators (host, port, url, email) from ArkEnv when available instead of custom ArkType schemas
Provide default values for optional environment variables using ArkType syntax (e.g., 'boolean = false')
Use ArkEnvError for environment variable errors instead of generic Error types
For environment schema definition, use ArkType string literal syntax for enumerated values (e.g., "'deve...

Files:

  • apps/www/mdx-components.tsx
  • apps/www/components/ui/external-link.test.tsx
  • apps/www/components/ui/external-link.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Use self-closing JSX elements (useSelfClosingElements error)

Files:

  • apps/www/mdx-components.tsx
  • apps/www/components/ui/external-link.test.tsx
  • apps/www/components/ui/external-link.tsx
apps/www/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/www/.cursor/rules/posthog-integration.mdc)

apps/www/**/*.{ts,tsx,js,jsx}: If using TypeScript, use an enum to store feature flag names. If using JavaScript, store feature flag names as strings to an object declared as a constant to simulate an enum. Use UPPERCASE_WITH_UNDERSCORE naming convention for enum/const object members.
If a custom property for a person or event is referenced in two or more files or two or more callsites in the same file, use an enum or const object with UPPERCASE_WITH_UNDERSCORE naming convention, similar to feature flags.

Files:

  • apps/www/mdx-components.tsx
  • apps/www/components/ui/external-link.test.tsx
  • apps/www/components/ui/external-link.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Co-locate tests with components: Component.tsx next to Component.test.tsx

**/*.test.{ts,tsx}: Use Vitest for unit and integration tests
Test individual functions, components, and hooks in isolation with mocked dependencies in unit tests
Unit tests should focus on individual function logic and edge cases, component rendering and props, error handling and validation, and type checking
Unit tests should execute in less than 100ms per test
Mock external dependencies (clipboard, network, etc.) in unit tests
Co-locate unit test files with source files using naming convention: source file → test file (e.g., create-env.ts → create-env.test.ts)
Test component behavior, not aesthetics, and focus on what users can do and what the component guarantees through its API
Test component public API (props, events, and component contract), user behavior (clicks, typing, focus, keyboard, ARIA), state transitions, accessibility, and side effects in component tests
Do not test pure styling or CSS classes, library internals (Radix/shadcn), implementation details (hooks, setState, private variables), or visual variants in component tests
Use Testing Library with user-event for real user simulation in component tests
Query by role, name, label, and text (accessibility first) in component tests
Use beforeEach/afterEach for cleanup, not beforeAll/afterAll when possible
Keep tests fast, deterministic, and parallelizable
Mock at component boundaries (network, time, context)

Create unit tests with .test.ts or .test.tsx suffix located alongside source files, testing individual functions and components in isolation with mocked dependencies

Files:

  • apps/www/components/ui/external-link.test.tsx
**/*.{test,integration.test}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,integration.test}.{ts,tsx}: Use Vitest's describe/it structure for all test files
Test both success and failure cases in unit and integration tests
Mock process.env in unit tests to test different environment variable scenarios

Files:

  • apps/www/components/ui/external-link.test.tsx
🧠 Learnings (12)
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Test component public API (props, events, and component contract), user behavior (clicks, typing, focus, keyboard, ARIA), state transitions, accessibility, and side effects in component tests

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-23T07:09:57.082Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.082Z
Learning: Applies to **/*.integration.test.{ts,tsx} : Create integration tests with `.integration.test.ts` or `.integration.test.tsx` suffix, testing how multiple units work together without mocking their interactions (except external APIs)

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.integration.test.{ts,tsx} : Integration tests should focus on component and hook interactions, function composition and data flow, real dependencies between units, and state synchronization across boundaries

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-23T07:09:57.082Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.082Z
Learning: Applies to **/*.test.{ts,tsx} : Create unit tests with `.test.ts` or `.test.tsx` suffix located alongside source files, testing individual functions and components in isolation with mocked dependencies

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.integration.test.{ts,tsx} : Test how multiple units (components, hooks, functions) work together without mocking their interactions in integration tests

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Do not test pure styling or CSS classes, library internals (Radix/shadcn), implementation details (hooks, setState, private variables), or visual variants in component tests

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies (clipboard, network, etc.) in unit tests

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Test component behavior, not aesthetics, and focus on what users can do and what the component guarantees through its API

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Unit tests should focus on individual function logic and edge cases, component rendering and props, error handling and validation, and type checking

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to **/*.test.{ts,tsx} : Test individual functions, components, and hooks in isolation with mocked dependencies in unit tests

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-12T13:20:01.954Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-12-12T13:20:01.954Z
Learning: Applies to packages/vite-plugin/src/**/*.test.ts : Test the Vite plugin using the with-vite-react example as a fixture and validate that the plugin works with real Vite projects

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
📚 Learning: 2025-12-23T07:09:57.082Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.082Z
Learning: Applies to **/*.{test,integration.test}.{ts,tsx} : Use Vitest's `describe`/`it` structure for all test files

Applied to files:

  • apps/www/components/ui/external-link.test.tsx
🧬 Code graph analysis (1)
apps/www/mdx-components.tsx (1)
apps/www/components/ui/external-link.tsx (1)
  • ExternalLink (66-84)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test-e2e (e2e)
  • GitHub Check: test-e2e (a11y)
🔇 Additional comments (2)
apps/www/mdx-components.tsx (1)

13-13: LGTM! Clean MDX integration.

The ExternalLink mapping and component order adjustment ensure that all MDX anchor tags use the custom component, and that customComponents correctly override twoslashComponents for any overlapping keys.

Also applies to: 33-33, 53-53

apps/www/components/ui/external-link.tsx (1)

76-81: Arrow icon rendering looks correct.

The conditional rendering of <ArrowUpRight> with appropriate sizing, opacity, and aria-hidden="true" is well-implemented. Note: ensure this doesn't conflict with the CSS-based arrow (see comment on apps/www/app/globals.css).

@yamcodes
Copy link
Owner

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions bot added docs Improvements or additions to documentation example Issues or Pull Requests concerning at least one ArkEnv example. (Found in the `examples/` directory) labels Dec 27, 2025
@yamcodes
Copy link
Owner

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yamcodes
Copy link
Owner

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/www/content/docs/arkenv/index.mdx (1)

6-7: Unused imports after removing icon props.

The BookOpen, Rocket, Globe, and GitHub icons appear to be unused now that the icon props were removed from the Card components. Consider removing these imports to keep the file clean.

🔎 Suggested cleanup
-import { BookOpen, Rocket, Globe } from "lucide-react";
-import { SiGithub as GitHub } from "@icons-pack/react-simple-icons";
apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx (1)

6-6: Unused import after removing icon prop.

The Globe icon import is no longer used now that the icon prop was removed from the Card component.

🔎 Suggested cleanup
-import { Globe } from "lucide-react";
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d25b7d and 8767885.

📒 Files selected for processing (8)
  • apps/www/app/globals.css
  • apps/www/components/page/edit-on-github.tsx
  • apps/www/components/ui/card.tsx
  • apps/www/components/ui/external-link.tsx
  • apps/www/content/docs/arkenv/index.mdx
  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
  • apps/www/lib/utils/url.ts
  • examples/README.md
✅ Files skipped from review due to trivial changes (1)
  • examples/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/www/app/globals.css
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

**/*.{ts,tsx}: Prefer type over interface for type definitions in TypeScript
Use TypeScript 5.1+ features when appropriate
Leverage const type parameters for better inference in TypeScript
Use JSDoc comments for public APIs
Use tabs for indentation (configured in Biome)
Use double quotes for strings (configured in Biome)
Organize imports automatically (Biome handles this)
Avoid explicit types when TypeScript can infer them (noInferrableTypes error)
Use as const where appropriate for immutable values (useAsConstAssertion error)
Don't reassign function parameters (noParameterAssign error)
Place default parameters last in function signatures (useDefaultParameterLast error)
Always initialize enum values (useEnumInitializers error)
Declare one variable per statement (useSingleVarDeclarator error)
Avoid unnecessary template literals (noUnusedTemplateLiteral error)
Prefer Number.parseInt over global parseInt (useNumberNamespace error)
Use kebab-case for TypeScript filenames (e.g., create-env.ts)
Use camelCase for function names (e.g., createEnv)
Use PascalCase for type names (e.g., ArkEnvError)
Use UPPER_SNAKE_CASE for environment variables and constants
Include examples in JSDoc comments when helpful for public APIs
Document complex type logic with JSDoc comments
Use ArkEnvError for environment variable validation errors
Provide clear, actionable error messages that include the variable name and expected type

**/*.{ts,tsx}: Use createEnv(schema) function (or default import as arkenv) to create validated environment objects in TypeScript
Use built-in validators (host, port, url, email) from ArkEnv when available instead of custom ArkType schemas
Provide default values for optional environment variables using ArkType syntax (e.g., 'boolean = false')
Use ArkEnvError for environment variable errors instead of generic Error types
For environment schema definition, use ArkType string literal syntax for enumerated values (e.g., "'deve...

Files:

  • apps/www/lib/utils/url.ts
  • apps/www/components/ui/card.tsx
  • apps/www/components/page/edit-on-github.tsx
  • apps/www/components/ui/external-link.tsx
apps/www/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/www/.cursor/rules/posthog-integration.mdc)

apps/www/**/*.{ts,tsx,js,jsx}: If using TypeScript, use an enum to store feature flag names. If using JavaScript, store feature flag names as strings to an object declared as a constant to simulate an enum. Use UPPERCASE_WITH_UNDERSCORE naming convention for enum/const object members.
If a custom property for a person or event is referenced in two or more files or two or more callsites in the same file, use an enum or const object with UPPERCASE_WITH_UNDERSCORE naming convention, similar to feature flags.

Files:

  • apps/www/lib/utils/url.ts
  • apps/www/components/ui/card.tsx
  • apps/www/components/page/edit-on-github.tsx
  • apps/www/components/ui/external-link.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Use self-closing JSX elements (useSelfClosingElements error)

Files:

  • apps/www/components/ui/card.tsx
  • apps/www/components/page/edit-on-github.tsx
  • apps/www/components/ui/external-link.tsx
🧠 Learnings (7)
📚 Learning: 2025-09-09T17:37:19.650Z
Learnt from: yamcodes
Repo: yamcodes/arkenv PR: 132
File: packages/arkenv/README.md:13-14
Timestamp: 2025-09-09T17:37:19.650Z
Learning: For yamcodes/arkenv project: Runtime support documentation should link to specific examples: Node.js (examples/basic), Bun (examples/with-bun), Vite (examples/with-vite-react-ts).

Applied to files:

  • apps/www/content/docs/arkenv/index.mdx
  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-12-26T19:27:11.710Z
Learnt from: danciudev
Repo: yamcodes/arkenv PR: 614
File: packages/vite-plugin/src/index.test.ts:641-654
Timestamp: 2025-12-26T19:27:11.710Z
Learning: In packages/vite-plugin/src/**/*.test.ts: The test suite uses `env.test` files (without leading dot) as test fixtures that are manually read by the `readTestConfig` helper function and stubbed into process.env with `vi.stubEnv`, not as files to be read by Vite's loadEnv during tests.

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-12-23T07:09:57.130Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.130Z
Learning: Applies to **/*.{ts,tsx} : Use descriptive environment variable names that indicate purpose and format (e.g., DATABASE_URL, NODE_ENV, FEATURE_FLAG)

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-11-24T16:04:00.957Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-11-24T16:04:00.957Z
Learning: Applies to **/*.{ts,tsx} : Use `ArkEnvError` for environment variable validation errors

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Keep environment variable schemas readable and TypeScript-like using ArkType syntax

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-12-23T07:09:57.130Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.130Z
Learning: Applies to **/*.{ts,tsx} : For environment schema definition, use ArkType string literal syntax for enumerated values (e.g., "'development' | 'production' | 'test'")

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
📚 Learning: 2025-12-23T07:09:57.130Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T07:09:57.130Z
Learning: Applies to **/*.{ts,tsx} : Use `createEnv(schema)` function (or default import as `arkenv`) to create validated environment objects in TypeScript

Applied to files:

  • apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx
🧬 Code graph analysis (2)
apps/www/components/ui/card.tsx (1)
apps/www/lib/utils/url.ts (1)
  • isExternalUrl (15-52)
apps/www/components/ui/external-link.tsx (1)
apps/www/lib/utils/url.ts (1)
  • isExternalUrl (15-52)
🔇 Additional comments (8)
apps/www/components/page/edit-on-github.tsx (1)

31-32: LGTM!

The data-no-underline and data-no-arrow attributes appropriately opt this link out of the external link styling since it already has a dedicated SquarePen icon and is styled as a button.

apps/www/lib/utils/url.ts (2)

4-9: LGTM! Consider IPv6 localhost if needed.

The internal domains list covers common cases well. The subdomain matching logic at line 35 correctly prevents suffix attacks (the leading dot ensures evilarkenv.js.org won't match arkenv.js.org).

One minor consideration: if IPv6 localhost (::1) is used in any environment, it won't be recognized as internal. This is likely fine for typical use cases.


15-52: Well-structured SSR/CSR-safe URL detection.

The function handles the complexity of server vs client rendering appropriately. The fallback to treating parse failures as internal (line 50) is a safe default that prevents broken UI for malformed URLs.

apps/www/content/docs/arkenv/index.mdx (1)

30-31: LGTM!

The Card components for external links now correctly rely on the enhanced Card component to auto-render the external link indicator, avoiding redundant icon prop usage.

apps/www/content/docs/vite-plugin/arkenv-in-viteconfig.mdx (1)

45-45: LGTM!

The Card now correctly relies on the component's internal external link detection.

apps/www/components/ui/card.tsx (1)

8-18: LGTM! Clean external link augmentation logic.

The approach of wrapping the title with the arrow indicator only when external is clean. The group-hover opacity transition provides good interactive feedback within the Card context.

apps/www/components/ui/external-link.tsx (2)

8-10: Clean interface extension.

Making href explicitly optional in the interface is appropriate since isExternalUrl handles undefined gracefully by returning false.


26-32: LGTM! Arrow icon implementation.

The inline styling with align-middle and em-based sizing ensures the icon scales appropriately with the surrounding text. Using aria-hidden="true" correctly marks this decorative icon.

@yamcodes
Copy link
Owner

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yamcodes yamcodes merged commit eb33741 into main Dec 27, 2025
16 of 17 checks passed
@yamcodes yamcodes deleted the copilot/add-external-link-arrow branch December 27, 2025 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation example Issues or Pull Requests concerning at least one ArkEnv example. (Found in the `examples/` directory) tests This issue or PR is about adding, removing or changing tests. www Improvements or additions to arkenv.js.org

Projects

None yet

Development

Successfully merging this pull request may close these issues.

External links should have an arrow

2 participants