Skip to content

Magnetize arrow to last word in external links#668

Merged
yamcodes merged 8 commits intomainfrom
external-link-magnetize
Dec 29, 2025
Merged

Magnetize arrow to last word in external links#668
yamcodes merged 8 commits intomainfrom
external-link-magnetize

Conversation

@yamcodes
Copy link
Owner

@yamcodes yamcodes commented Dec 29, 2025

Summary by CodeRabbit

  • Style
    • External link indicator moved from inline icon to CSS-rendered background image for consistent placement and spacing across light and dark themes.
    • Visual external-arrow removed from markup; styling now uniformly handles the indicator.
    • Spacing and color contrast for external links improved, preserving readability and theme-specific contrast.
    • Decorative icon removed to simplify DOM and accessibility handling.

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

@changeset-bot
Copy link

changeset-bot bot commented Dec 29, 2025

⚠️ No Changeset found

Latest commit: 8491e6a

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 29, 2025

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

Project Deployment Review Updated (UTC)
arkenv Ready Ready Preview, Comment Dec 29, 2025 9:01pm

@yamcodes yamcodes changed the title Ensure external links and their icons remain on a single line. Ensure external links and their icons remain on a single line Dec 29, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

Walkthrough

Replaces the external-link visual indicator: CSS now uses a background-image SVG (light/dark stroke variants, padding, sizing) applied via a[data-external-link] (and related selectors); the external-link component no longer renders the ArrowUpRight SVG and tests now assert the data-external-link attribute instead of an icon.

Changes

Cohort / File(s) Summary
CSS: external-link styling
apps/www/app/globals.css
Replace ::after/mask-based arrow with a right-aligned inline-SVG background-image for external links; add padding-right, background-size/no-repeat, and adapt stroke color for light/dark themes; use [data-no-arrow] to suppress.
Component & tests
apps/www/components/ui/external-link.tsx, apps/www/components/ui/external-link.test.tsx
Remove ArrowUpRight import and JSX icon rendering; keep data-external-link attribute on external hrefs. Update tests to assert presence/absence of data-external-link and that no decorative SVG is rendered.

Sequence Diagram(s)

(omitted — change is styling + small component update; no multi-component sequential flow)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

tests

Poem

🐰 I hopped through CSS with care and cheer,

Swapped masks for images, made the arrows clear,
The JSX kept only a single trait,
Links now sparkle with a lighter gait,
A tiny hop — the UI’s near.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: refactoring external link arrow styling from pseudo-element to background-image approach, positioning it relative to the last word via background properties.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between adf4e5f and 8491e6a.

📒 Files selected for processing (2)
  • apps/www/app/globals.css
  • apps/www/components/ui/external-link.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/www/app/globals.css
🧰 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/components/ui/external-link.test.tsx
**/*.tsx

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

Use self-closing JSX elements (useSelfClosingElements error)

Files:

  • apps/www/components/ui/external-link.test.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
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/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 (10)
📚 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-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} : 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 **/*.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-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} : Query by role, name, label, and text (accessibility first) 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 tooling/playwright-www/**/*.{ts,tsx} : End-to-end tests should focus on user-facing behavior, not implementation details

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-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 **/*.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-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 **/*.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
🧬 Code graph analysis (1)
apps/www/components/ui/external-link.test.tsx (1)
apps/www/components/ui/external-link.tsx (1)
  • ExternalLink (15-31)
⏰ 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). (5)
  • GitHub Check: test-e2e (a11y)
  • GitHub Check: test-e2e (e2e)
  • GitHub Check: test-typesafety
  • GitHub Check: test-build (latest)
  • GitHub Check: test-build (lts/*)
🔇 Additional comments (2)
apps/www/components/ui/external-link.test.tsx (2)

17-80: LGTM! Tests correctly updated for CSS-based external link indicator.

The test suite has been appropriately updated to verify the component's public API (the data-external-link attribute) rather than checking for SVG elements in the DOM. This aligns perfectly with the architectural change to CSS-based indicators and follows testing best practices by focusing on behavior rather than implementation details.

The coverage is thorough:

  • ✓ External HTTP/HTTPS links
  • ✓ Internal relative links
  • ✓ Hash links
  • ✓ Undefined href edge case
  • ✓ Same-domain links
  • ✓ Localhost links

Based on learnings, these tests correctly focus on the component's public API and user-visible behavior rather than implementation details.


105-112: LGTM! Accessibility test correctly updated.

The accessibility test has been appropriately renamed and updated to verify that no SVG icon is rendered in the DOM (since it's now a decorative CSS background-image). This is the correct approach for testing the new implementation.


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.

@github-actions github-actions bot added the www Improvements or additions to arkenv.js.org label Dec 29, 2025
@yamcodes yamcodes changed the title Ensure external links and their icons remain on a single line Magnetize arrow to last word in external links Dec 29, 2025
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

♻️ Duplicate comments (1)
apps/www/app/globals.css (1)

58-64: Dark mode inherits URL matching concerns.

This rule has the same imprecise substring matching issue as the light mode variant (lines 44-56). Address the URL matching concern in both rules together.

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

149-149: Consider removing manual timestamp comment.

Git already tracks file modification history. Manual timestamp comments add maintenance burden and can become stale.

🔎 Proposed change
-/* Last modified: Mon Dec 29 11:45:01 +05 2025 */

To check the last modification time, use:

git log -1 --format="%ai" -- apps/www/app/globals.css
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4de02bc and 110fa96.

📒 Files selected for processing (2)
  • apps/www/app/globals.css
  • apps/www/components/ui/external-link.tsx
🧰 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/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/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/components/ui/external-link.tsx
🧠 Learnings (3)
📚 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.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.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.tsx
⏰ 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 (a11y)
  • GitHub Check: test-e2e (e2e)
🔇 Additional comments (3)
apps/www/components/ui/external-link.tsx (3)

23-29: LGTM! Clean early return optimization.

The early return for non-external links simplifies the component logic and avoids unnecessary attribute/icon rendering for internal links.


34-35: LGTM! Arrow magnetization implemented correctly.

The non-breaking space (\u00A0) combined with whitespace-nowrap ensures the arrow icon stays attached to the last word when text wraps, which directly addresses the PR objective.


37-37: LGTM! Margin removal aligns with new spacing approach.

Removing ml-0.5 is correct since the non-breaking space (\u00A0) now handles spacing between text and icon.

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: 1

♻️ Duplicate comments (1)
apps/www/app/globals.css (1)

44-58: The URL matching issue from the previous review remains unresolved.

The selector on line 46 still uses substring matching ([href*="arkenv.js.org"] and [href*="localhost"]) which can incorrectly match malicious URLs like:

  • fake-arkenv.js.org
  • arkenv.js.org.evil.com
  • https://evil.com?redirect=arkenv.js.org

This was flagged in the previous review and should be addressed before merging.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 110fa96 and adf4e5f.

📒 Files selected for processing (2)
  • apps/www/app/globals.css
  • apps/www/components/ui/external-link.tsx
💤 Files with no reviewable changes (1)
  • apps/www/components/ui/external-link.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 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/app/globals.css
⏰ 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). (5)
  • GitHub Check: test-e2e (a11y)
  • GitHub Check: test-e2e (e2e)
  • GitHub Check: test-typesafety
  • GitHub Check: test-build (latest)
  • GitHub Check: test-build (lts/*)

@github-actions github-actions bot added the tests This issue or PR is about adding, removing or changing tests label Dec 29, 2025
@yamcodes yamcodes merged commit 20c8d62 into main Dec 29, 2025
15 checks passed
@yamcodes yamcodes deleted the external-link-magnetize branch December 29, 2025 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

1 participant