Componentry UI Components

repository·main·Indexed 42 days ago

https://github.com/harshjdhv/componentry

A collection of high-quality, interactive UI components built with React 19, Tailwind CSS 4, and Framer Motion. Following a 'copy-and-paste' philosophy similar to shadcn/ui, components are installed via the shadcn CLI rather than as dependencies. Features include cursor-following effects, 3D transforms, and full dark mode support.

Tokens
52.2K
Snippets
133
Records
202
Agent score
59%

What's inside Componentry

  1. Componentry core features and tech stack

    main

    Componentry provides interactive, copy-and-paste UI components designed for React applications.

    Key Features

    • Copy & Paste: Components are added directly to your project, not as a dependency.
    • Interactive: Includes cursor-following effects, 3D transforms, and smooth animations.
    • Customizable: Built with Tailwind CSS for easy styling.
    • Accessible: Native controls with keyboard and motion support.
    • Dark Mode: Full support for light and dark modes.
    • TypeScript: Fully typed components.

    Tech Stack

    • Framework: Next.js 16
    • Styling: Tailwind CSS 4
    • Components: React 19
    • Build System: Turborepo
    • Package Manager: pnpm
  2. Project directory structure

    main

    Understanding the repository layout:

    • packages/ui/src/components/: Source code for reusable components.
    • apps/web/components/docs/: Documentation and optional client previews.
    • apps/web/registry/index.ts: Component metadata (used for navigation, search, SEO, and llms.txt).
    • apps/web/components/docs/lazy-registry.ts: Documentation import map for the /docs/components/[slug] route.
    • apps/web/public/r/: Installable shadcn registry payloads.
    • apps/web/registry/blocks/_registry.ts: Block definitions and source mappings.
    • scripts/: Scripts for generation, validation, and consumer installation checks.

    Important: @workspace/ui is a private workspace package. It is not distributed as an npm package; users install components via the shadcn registry.

  3. Verify component and block distribution quality

    main

    Component and block generators include automated checks to ensure distribution reliability:

    • Freshness Checks: Supports read-only freshness checks.
    • Registry Validation: Validates dependency declarations, internal imports, helper resolution, index membership, and documentation coverage.
    • Consumer Smoke Test: A 'fresh-consumer' smoke test performs a real-world simulation by installing representative payloads using the actual CLI and performing typechecks without using workspace aliases. In browser mode, it also exercises the installed magnetic dock.
  4. Third-party license requirements for specific components

    main

    Some Componentry components rely on third-party libraries that have specific licensing terms. If you use or redistribute these components, you are responsible for complying with their licenses:

    • image-trail and layered-stack require gsap (GSAP).
    • Refer to the GSAP licensing page for details.
  5. Understand the Componentry architecture boundaries

    main

    Componentry is organized into specific functional boundaries to separate reusable source, documentation, and metadata:

    • Reusable Source: Resides in the private packages/ui workspace.
    • Documentation & Marketing: The Next.js website manages documentation layouts, previews, and marketing pages.
    • Component Metadata: apps/web/registry/index.ts provides component metadata, navigation, search, and page metadata.
    • Dynamic Documentation Routing: components/docs/lazy-registry.ts maps component slugs to asynchronous documentation modules, which are then handled by a single [slug] route.
    • Distribution Format: The Registry JSON is used as the distribution format for shadcn installations.
    • Blocks: Blocks use their own typed source registry and generated artifacts.
  6. Understand the preview media URL convention

    main

    Component previews consist of three remote assets in Cloudflare R2. The /docs page uses the .webm URL stored in apps/web/registry/index.ts for the video, but it automatically derives the static poster URL by replacing the video extension with .webp.

    Important: The .webp poster must use the exact same path and base filename as the uploaded videos to ensure the derivation works correctly.

    Asset Structure:

    • preview-videos/<category-folder>/<asset-name>.webm (Video)
    • preview-videos/<category-folder>/<asset-name>.mp4 (Video)
    • preview-videos/<category-folder>/<asset-name>.webp (Static Poster)

    Registry Example:

    previewVideo: "https://pub-a50e7f4ea75a4970a1738e50d53b6eb1.r2.dev/preview-videos/component-animations/example.webm"

    The poster URL will be derived as: .../example.webp

  7. Lazy-load source code highlighting via API

    main

    To prevent massive Shiki source code from being inlined in HTML and bloating the initial payload, move highlighting from build-time to on-demand.

    1. Create an API route at app/api/highlight/route.ts to handle highlighting requests.
    2. Modify the component wrapper (e.g., DocsPreviewWrapper) to receive raw sourceCode instead of pre-rendered HTML. Use fetch to call the API route only when the user clicks "View Source".
    3. Update layouts to pass only the raw sourceCode string and sourceCodeFilename instead of sourceCodeContent.
    4. Remove build-time calls to readComponentSource() from individual docs components.
    // 1. API Route: app/api/highlight/route.ts
    import { highlightCode } from "@/lib/shiki"
    import { NextRequest, NextResponse } from "next/server"
    
    export async function POST(req: NextRequest) {
      const { code, lang = "tsx" } = await req.json()
      const html = await highlightCode(code, lang)
      return NextResponse.json({ html })
    }
    
    // 2. Client-side implementation in DocsPreviewWrapper
    const [sourceHtml, setSourceHtml] = useState<string | null>(null)
    const [isLoadingSource, setIsLoadingSource] = useState(false)
    
    const handleViewSource = async () => {
      setShowSource(true)
      if (!sourceHtml && sourceCode) {
        setIsLoadingSource(true)
        const res = await fetch("/api/highlight", {
          method: "POST",
          body: JSON.stringify({ code: sourceCode }),
        })
        const { html } = await res.json()
        setSourceHtml(html)
        setIsLoadingSource(false)
      }
    }
  8. Eliminate duplicate inline <style> tags

    main

    The application currently embeds duplicate CSS rules via inline <style> tags within components like CodeBlock, DynamicCodeBlock, and InstallCommand. This increases HTML weight and parsing time.

    Fix: Move all component-specific styles (such as Shiki styles and scrollbar utilities) into the global CSS file located at packages/ui/src/styles/globals.css and remove the inline <style> blocks from the components.

  9. Optimize Shiki source code highlighting performance

    main

    The current implementation of DocsPageLayout inlines massive Shiki-highlighted source code directly into the RSC payload via the sourceCodeContent prop. This can increase HTML size by hundreds of kilobytes (e.g., ~352KB for a single component), significantly delaying First Contentful Paint (FCP).

    To fix this, avoid SSR-ing the full highlighted source code for elements that are hidden by default (like the source code drawer). Instead:

    1. Remove sourceCodeContent from the server-side render.
    2. Implement a client component that fetches highlighting via an API route only when the user clicks the <CodeXml> button.
    3. Alternatively, use a lightweight client-side highlighter like shiki/wasm loaded lazily.
    // Current problematic implementation in docs-page-layout.tsx
    sourceCodeContent={
      installSourceCode ? (
        <Suspense fallback={<CodeBlockSkeleton />}>
          <CodeBlock
            code={installSourceCode}    // ← Full source code string
            lang="tsx"
            className="..."
          />
        </Suspense>
      ) : null
    }
  10. Lazy-load heavy components with React.lazy

    main

    Reduce the initial JavaScript bundle size by lazy-loading heavy UI elements like the CommandMenu using React.lazy and Suspense.

    // In docs-preview-wrapper.tsx
    import { lazy, Suspense } from "react"
    
    const CommandMenu = lazy(() =>
      import("@/components/command-menu").then(m => ({ default: m.CommandMenu }))
    )
    
    // In JSX:
    <Suspense fallback={<button className={iconButtonClass}><Search className="w-4 h-4" /></button>}>
      <CommandMenu trigger={...} />
    </Suspense>