@dreadkn1ght123/ui
v0.8.0
Published
A component library built on [shadcn/ui](https://ui.shadcn.com/) and [Radix UI](https://www.radix-ui.com/) primitives, styled with [Tailwind CSS v4](https://tailwindcss.com/).
Readme
@dreadkn1ght123/ui
A component library built on shadcn/ui and Radix UI primitives, styled with Tailwind CSS v4.
Installation
pnpm add @dreadkn1ght123/uiRequired peer dependencies
The library declares its runtime libraries as peer dependencies so the consuming app controls their versions and only one copy is bundled. These are always required:
pnpm add react react-dom tailwindcss class-variance-authority clsx tailwind-merge lucide-reactThe remaining peers are optional — install only the ones backing the components you actually import (your package manager will warn you which are missing):
| Component(s) | Peer dependency |
| --- | --- |
| Accordion, Alert Dialog, Avatar, Checkbox, Dialog, Dropdown Menu, Popover, Select, Tabs, Tooltip, … | the matching @radix-ui/react-* package |
| Chart | recharts |
| Command, Combobox | cmdk |
| Drawer | vaul |
| Carousel | embla-carousel-react |
| Input OTP | input-otp |
| Sonner / theming | sonner, next-themes |
| Calendar, Date Picker | react-day-picker, date-fns |
| Form | react-hook-form |
| Resizable | react-resizable-panels |
| animations | framer-motion, tw-animate-css |
Tailwind CSS v4 + theme setup
This library ships class names only — Tailwind must be configured in the consuming project to generate the styles, and the design-system theme tokens must be present.
The theme tokens (the @theme mapping, :root / .dark CSS variables for colors,
radius, shadows, fonts, plus the hover/active elevate utilities) are published with
the package as @dreadkn1ght123/ui/theme.css. Import it in your CSS entry file —
no manual copying required:
/* app.css */
@import "tailwindcss";
@import "@dreadkn1ght123/ui/theme.css";
/* Scan the library so Tailwind picks up the class names it uses */
@source "../node_modules/@dreadkn1ght123/ui/dist";Order matters: @import "tailwindcss" must come first, then the theme. Dark mode is
class-based — but you should not toggle the dark class yourself: use the shipped
ThemeProvider / ThemeToggle below.
Single source of truth for colors. All theme tokens (
--primary,--background,--radius, etc.) come only from@dreadkn1ght123/ui/theme.css. Do not redefine these tokens or paste your own:root/.darkcolor blocks in the consuming app — that is what makes the palette drift between projects. Importtheme.cssin the exact order above and leave the tokens untouched.
Theming
The package ships the theming primitives so dark-mode wiring is identical across
projects — no per-project reinvention of next-themes.
import { ThemeProvider, ThemeToggle } from "@dreadkn1ght123/ui";
// Wrap your app once at the root. Defaults: class-based dark mode, light default (light/dark only).
export default function Root() {
return (
<ThemeProvider>
<App />
</ThemeProvider>
);
}
// Drop the toggle anywhere inside the provider (typically a header):
<ThemeToggle />;ThemeProvider is a thin wrapper over next-themes (install it as a peer). It accepts
all next-themes props if you need to override the defaults.
App shell (sidebar + theme switch in one import)
The most-rebuilt combo — an app sidebar (with the theme switcher in the user footer)
plus a header — ships as a single AppShell import. Reach for this before composing one
by hand.
import { ThemeProvider, AppShell } from "@dreadkn1ght123/ui";
import { LayoutDashboard, FileText } from "lucide-react";
export default function App() {
return (
<ThemeProvider>
<AppShell
appName="Acme Inc"
navGroups={[
{ items: [{ title: "Dashboard", url: "/", icon: LayoutDashboard, isActive: true }] },
{ label: "Workspace", items: [{ title: "Notes", url: "/notes", icon: FileText }] },
]}
user={{ name: "Ada Lovelace", email: "[email protected]" }}
breadcrumbs={[{ title: "Workspace", url: "/" }, { title: "Dashboard" }]}
>
<YourPageContent />
</AppShell>
</ThemeProvider>
);
}AppShell renders the ThemeToggle in its sidebar footer (next to the user) automatically. Every prop is optional.
For a custom brand logo, use the brand slot instead of logo + appName. It renders
directly in the sidebar header — no clickable button, no fixed height, no clipping, and
not tied to appName — so you fully control sizing and collapse behaviour:
import { AppShell, Logo, LogoMark } from "@dreadkn1ght123/ui";
<AppShell
brand={
<a href="/" className="flex w-full items-center" aria-label="My Company">
{/* full wordmark when expanded, compact mark when collapsed to icons */}
<Logo className="h-6 w-auto group-data-[collapsible=icon]:hidden" />
<LogoMark className="hidden size-6 group-data-[collapsible=icon]:block" />
</a>
}
>
<YourPageContent />
</AppShell>;Give SVG logos an explicit height (h-6 w-auto) — viewBox-only SVGs collapse inside
flex. The plain logo prop is still fine for a small icon tile next to appName; omit
appName for a wordmark that already includes the name (no empty text/gap is rendered).
Reusable blocks
Reuse these composed blocks instead of rebuilding common screens from scratch:
| Import | What it is |
| --- | --- |
| AppShell | App sidebar (theme switch in the user footer) + header — start here for dashboard-style apps. |
| Sidebar01–Sidebar07 | Seven full sidebar layout variants. |
| Dashboard01 | Admin dashboard (KPI cards, revenue chart, recent sales). |
| Login01 / Login02 | Centered-card login / split-screen sign-up. |
| ControlsShowcase | Kitchen-sink card of every interactive control. |
| Logo / LogoMark | Brand wordmark + lettermark. |
Responsive / mobile
This is a web library (shadcn/ui + Radix + Tailwind v4, DOM-rendered). It targets responsive websites and web apps — not native mobile apps (it cannot run in React Native / Expo).
The shipped blocks are responsive out of the box: AppShell and Sidebar01–07 collapse
the sidebar into a slide-over drawer below 768px, Dashboard01 grids stack to one column,
and Login01/02 are fluid centered cards. Reuse them and mobile works for free.
When composing your own layouts, build mobile-first:
- Base classes target the phone; add
sm:/md:/lg:to scale up. - Grids start at one column (
grid-cols-1 md:grid-cols-2 lg:grid-cols-4); never ship a baregrid-cols-3/4. - Use
w-full max-w-…, not fixedw-[600px](avoids horizontal scroll). - Wrap
<Table>inoverflow-x-auto, or restack as cards on small screens. - Prefer
DraweroverDialogfor mobile flows; useuseIsMobile()to swap. - Scale padding (
p-4 md:p-6 lg:p-8) and headings (text-xl sm:text-2xl). - Keep tap targets ≥ 44px (default Button/Input sizes; icon buttons ≥
size-9).
QA every screen at 375–414px: no horizontal scroll, grids in one column, tables scroll,
no clipped text, comfortable tap targets. Full rules live in llms.txt.
Agent / AI consumption guide
An authoritative, machine-readable consumption guide ships inside the package as
llms.txt (also exported as @dreadkn1ght123/ui/llms.txt). It documents
the exact install + import order, dark-mode wiring, the full block list, and the rule to
reuse blocks rather than rebuild. Point any AI agent at it.
Copy-paste setup prompt
Hand this to any new project's agent to get an identical, correctly-themed setup:
Use the @dreadkn1ght123/ui design system for this project. Do not build UI primitives,
sidebars, dashboards, login pages, or theme switching from scratch — reuse the package.
1. Install: `pnpm add @dreadkn1ght123/ui react react-dom tailwindcss class-variance-authority clsx tailwind-merge lucide-react next-themes`, plus any optional peers the components I use require.
2. In my CSS entry, in EXACTLY this order:
@import "tailwindcss";
@import "@dreadkn1ght123/ui/theme.css";
@source "../node_modules/@dreadkn1ght123/ui/dist";
Do NOT define or override any theme tokens (--primary, --background, --radius, etc.)
anywhere in my app — all colors must come only from theme.css.
3. Wrap the app root in <ThemeProvider> from @dreadkn1ght123/ui and put a <ThemeToggle>
in the header (or use <AppShell>, which includes it).
4. For a dashboard-style app, use <AppShell> from @dreadkn1ght123/ui (app sidebar +
header + theme toggle in one import) instead of composing a layout by hand. For other
layouts, reuse Sidebar01–07, Dashboard01, Login01/02 before building anything custom.
5. Import all components from "@dreadkn1ght123/ui".Usage
import { Button } from "@dreadkn1ght123/ui";
export default function App() {
return <Button variant="default">Click me</Button>;
}Utility
import { cn } from "@dreadkn1ght123/ui";Hooks
import { useToast, toast, useIsMobile } from "@dreadkn1ght123/ui";Brand logo
The VVP Group logo ships as React components with the SVG inlined (no extra asset loading required):
import { Logo, LogoMark } from "@dreadkn1ght123/ui";
// Theme-aware by default (variant="auto"): brand colors on light, solid white
// on dark — automatically. Just size it; no manual swapping per theme.
<Logo className="h-8 w-auto" />
<LogoMark className="h-10 w-10" />
// Force a specific look regardless of theme:
<Logo variant="color" className="h-8 w-auto" /> // always brand colors
<Logo variant="mono" className="h-8 w-auto text-white" /> // inherits currentColor
<LogoMark variant="color" className="h-10 w-10" /> // always blue tile
<LogoMark variant="mono" className="h-10 w-10" /> // letters in currentColorThe
autovariant relies on class-based dark mode (the.darkclass thatThemeProvidertoggles). If you wire dark mode yourself, make sure.darkis set on a parent element.
The raw SVG files are also published and can be referenced directly:
@dreadkn1ght123/ui/assets/vvp-wordmark-color.svg
@dreadkn1ght123/ui/assets/vvp-wordmark-black.svg
@dreadkn1ght123/ui/assets/vvp-wordmark-white.svg
@dreadkn1ght123/ui/assets/vvp-favicon.svgAvailable components
All components from shadcn/ui are exported, including:
Accordion, Alert, AlertDialog, AspectRatio, Avatar, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Chart, Checkbox, Collapsible, Command, ContextMenu, Dialog, Drawer, DropdownMenu, Empty, Field, Form, HoverCard, Input, InputGroup, InputOtp, Item, Kbd, Label, Menubar, NavigationMenu, Pagination, Popover, Progress, RadioGroup, Resizable, ScrollArea, Select, Separator, Sheet, Sidebar, Skeleton, Slider, Sonner, Spinner, Switch, Table, Tabs, Textarea, Toast, Toaster, Toggle, ToggleGroup, Tooltip
Publishing a new version
Authentication uses the NPM_TOKEN secret. The committed .npmrc references it as
${NPM_TOKEN} (no token value is stored in the repo). The token must have
publish (read + write) permission for the @dreadkn1ght123 scope.
- Bump the version:
npm version patch|minor|major(run inlib/ui/). - Publish:
pnpm --filter @dreadkn1ght123/ui run release.
The release script runs vite build and then pnpm publish --no-git-checks.
publishConfig pins publishing to https://registry.npmjs.org/ with public access,
and pnpm resolves the catalog: versions to concrete numbers in the published
manifest. Only the dist directory (plus package.json and this README) is shipped.
