Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Contributing to solid-ui

Thank you for helping improve Solid UI, the docs site, and `solidui-cli`.

## Repository layout

| Path | Purpose |
| ---- | ------- |
| `apps/docs` | solid-ui.com — registry source, MDX docs, examples |
| `packages/cli` | `solidui-cli` published to npm |

## Local setup

```bash
pnpm install
```

If `pnpm install` fails on older Corepack pnpm, use Node 22+ and `corepack prepare pnpm@9 --activate`, or install dependencies per-package.

### Docs app

```bash
pnpm --filter docs dev
```

### CLI

```bash
cd packages/cli
pnpm install
pnpm build
node dist/index.js --help
```

## Registry changes

1. Edit files under `apps/docs/src/registry/` (`ui/`, `example/`, `block/`).
2. Register entries in `registry-ui.ts`, `registry-examples.ts`, or `registry-blocks.ts`.
3. Rebuild published JSON:

```bash
pnpm --filter docs build:registry
```

4. Commit both source **and** `apps/docs/public/registry/**` if your PR includes registry output (maintainers may run this on release).

### Promoting examples to CLI-installable components

- `solidui-cli add` only lists `type: "ui"` in `registry/index.json`.
- If the docs site uses a pattern in production (e.g. `mode-toggle`), add `registry/ui/<name>.tsx` and an entry in `registry-ui.ts` with `registryDependencies` as needed.

### Blocks

- Define in `registry-blocks.ts` with SolidStart-friendly `target` paths (`src/routes/...`, `src/components/...`).
- Install via `solidui-cli add-block <name>` (after registry build).

## Pull requests

- Target `main` unless maintainers direct you to `dev` (Tailwind v4 migration).
- One feature per PR when possible (CLI change vs component fix vs docs).
- Link related issues (e.g. #229 sidebar / Tailwind).

## Claiming work (V4 checklist)

See [issue #199](https://github.com/stefan-karger/solid-ui/issues/199). Comment on the issue or open a draft PR with the component name you are implementing to avoid duplicate effort.

## Fork testing the CLI against your registry

```bash
cd packages/cli && pnpm build
SOLIDUI_REGISTRY_URL=https://your-preview.example.com node dist/index.js add mode-toggle
```

Deploy `apps/docs/public/registry` to that host or run docs locally and point the env var at `http://localhost:3000`.
39 changes: 39 additions & 0 deletions CONTRIBUTION-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# solid-ui contribution execution plan

Branch: `feat/cli-dx-and-registry` (fork: AMDphreak/solid-ui)

## Quick wins

- [x] `SOLIDUI_REGISTRY_URL` env var in CLI `registry.ts`
- [x] Docs/cli copy fixes (`componentDir`, `components.json` → `ui.config.json`)
- [x] `init --with-color-mode` (+ `COLOR_MODE.md` snippets for SolidStart / Vite)
- [x] `init -y`, `init --with-tailwind` (+ postcss.config.cjs)
- [x] `docs/dark-mode/tauri.mdx` + link from overview
- [x] `mode-toggle` UI component (merged from prior PR branch)

## Medium

- [x] `solidui-cli add-block <name>` + SolidStart-friendly block targets
- [x] `solidui-cli update [components...]` with overwrite
- [x] Sidebar: v3-compatible `w-[var(--*)]` classes + docs callout

## Strategic

- [x] `CONTRIBUTING.md`
- [x] `apps/docs/public/llms.txt`
- [x] Tailwind v3/v4 callout in CLI `COLOR_MODE.md`, sidebar docs, CONTRIBUTING

## Skipped (per user)

- UnoCSS support
- cva → tailwind-variants migration
- Full shadcn block parity in one PR
- Separate `command-palette` ui (`command` already exports `CommandDialog`)

## Resume in a new chat

```text
Continue solid-ui fork AMDphreak/solid-ui branch feat/cli-dx-and-registry.
Read CONTRIBUTION-PLAN.md. Run pnpm --filter docs build:registry, commit public/registry,
pnpm --filter solidui-cli build, push branch, open/update PR to stefan-karger/solid-ui.
```
33 changes: 33 additions & 0 deletions apps/docs/public/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# solid-ui

> Unofficial SolidJS port of shadcn/ui — copy-paste components (Kobalte, corvu, Tailwind).

## Docs

- Site: https://www.solid-ui.com
- Introduction: https://www.solid-ui.com/docs/introduction
- CLI: https://www.solid-ui.com/docs/cli
- Installation (SolidStart): https://www.solid-ui.com/docs/installation/solid-start
- Dark mode (SolidStart): https://www.solid-ui.com/docs/dark-mode/solid-start
- Registry index: https://www.solid-ui.com/registry/index.json

## CLI

```bash
npx solidui-cli@latest init
npx solidui-cli@latest init -y --with-color-mode --with-tailwind
npx solidui-cli@latest add button mode-toggle
npx solidui-cli@latest add-block sidebar-01
npx solidui-cli@latest update button
```

Environment: `SOLIDUI_REGISTRY_URL` overrides the registry host.

## Stack

- SolidJS, Kobalte, corvu, Tailwind CSS
- CLI scaffolds Tailwind v3 (`tailwind.config.cjs`); docs app may use Tailwind v4

## Repository

https://github.com/stefan-karger/solid-ui
39 changes: 1 addition & 38 deletions apps/docs/src/components/mode-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1 @@
import { useColorMode } from "@kobalte/core"

import { IconLaptop, IconMoon, IconSun } from "~/components/icons"
import { Button } from "~/registry/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "~/registry/ui/dropdown-menu"

export function ModeToggle() {
const { setColorMode } = useColorMode()

return (
<DropdownMenu>
<DropdownMenuTrigger as={Button<"button">} variant="ghost" size="sm" class="w-9 px-0">
<IconSun class="size-6 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<IconMoon class="absolute size-6 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span class="sr-only">Toggle theme</span>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onSelect={() => setColorMode("light")}>
<IconSun class="mr-2 size-4" />
<span>Light</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("dark")}>
<IconMoon class="mr-2 size-4" />
<span>Dark</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("system")}>
<IconLaptop class="mr-2 size-4" />
<span>System</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
export { ModeToggle } from "~/registry/ui/mode-toggle"
39 changes: 1 addition & 38 deletions apps/docs/src/registry/example/mode-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1 @@
import { useColorMode } from "@kobalte/core"

import { IconLaptop, IconMoon, IconSun } from "~/components/icons"
import { Button } from "~/registry/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "~/registry/ui/dropdown-menu"

export default function ModeToggle() {
const { setColorMode } = useColorMode()

return (
<DropdownMenu>
<DropdownMenuTrigger as={Button<"button">} variant="ghost" size="sm" class="w-9 px-0">
<IconSun class="size-6 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<IconMoon class="absolute size-6 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span class="sr-only">Toggle theme</span>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onSelect={() => setColorMode("light")}>
<IconSun class="mr-2 size-4" />
<span>Light</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("dark")}>
<IconMoon class="mr-2 size-4" />
<span>Dark</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("system")}>
<IconLaptop class="mr-2 size-4" />
<span>System</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
export { ModeToggle as default } from "~/registry/ui/mode-toggle"
14 changes: 9 additions & 5 deletions apps/docs/src/registry/registry-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ export const blocks: Registry = [
{
path: "block/sidebar-01/index.tsx",
type: "page",
target: "app/dashboard/page.tsx"
target: "src/routes/dashboard/index.tsx"
},
{
path: "block/sidebar-01/components/app-sidebar.tsx",
type: "component"
type: "component",
target: "src/components/dashboard/app-sidebar.tsx"
},
{
path: "block/sidebar-01/components/search-form.tsx",
type: "component"
type: "component",
target: "src/components/dashboard/search-form.tsx"
},
{
path: "block/sidebar-01/components/version-switcher.tsx",
type: "component"
type: "component",
target: "src/components/dashboard/version-switcher.tsx"
}
]
},
Expand All @@ -32,7 +35,8 @@ export const blocks: Registry = [
files: [
{
path: "block/demo-sidebar.tsx",
type: "component"
type: "component",
target: "src/components/demo-sidebar.tsx"
}
]
}
Expand Down
12 changes: 12 additions & 0 deletions apps/docs/src/registry/registry-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,18 @@ export const ui: Registry = [
}
]
},
{
name: "mode-toggle",
type: "ui",
dependencies: ["@kobalte/core", "lucide-solid"],
registryDependencies: ["button", "dropdown-menu"],
files: [
{
path: "ui/mode-toggle.tsx",
type: "ui"
}
]
},
{
name: "navigation-menu",
type: "ui",
Expand Down
38 changes: 38 additions & 0 deletions apps/docs/src/registry/ui/mode-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useColorMode } from "@kobalte/core"
import { Laptop, Moon, Sun } from "lucide-solid"

import { Button } from "~/registry/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "~/registry/ui/dropdown-menu"

export function ModeToggle() {
const { setColorMode } = useColorMode()

return (
<DropdownMenu>
<DropdownMenuTrigger as={Button<"button">} variant="ghost" size="sm" class="w-9 px-0">
<Sun class="size-6 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon class="absolute size-6 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span class="sr-only">Toggle theme</span>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onSelect={() => setColorMode("light")}>
<Sun class="mr-2 size-4" />
<span>Light</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("dark")}>
<Moon class="mr-2 size-4" />
<span>Dark</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => setColorMode("system")}>
<Laptop class="mr-2 size-4" />
<span>System</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
18 changes: 9 additions & 9 deletions apps/docs/src/registry/ui/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const Sidebar: Component<SidebarProps> = (rawProps) => {
<Match when={local.collapsible === "none"}>
<div
class={cn(
"test w-(--sidebar-width) flex h-full flex-col bg-sidebar text-sidebar-foreground",
"flex h-full w-[var(--sidebar-width)] flex-col bg-sidebar text-sidebar-foreground",
local.class
)}
{...others}
Expand All @@ -196,7 +196,7 @@ const Sidebar: Component<SidebarProps> = (rawProps) => {
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
class="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
class="w-[var(--sidebar-width)] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
style={{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE
}}
Expand All @@ -217,24 +217,24 @@ const Sidebar: Component<SidebarProps> = (rawProps) => {
{/* This is what handles the sidebar gap on desktop */}
<div
class={cn(
"w-(--sidebar-width) relative h-svh bg-transparent transition-[width] duration-200 ease-linear",
"w-[var(--sidebar-width)] relative h-svh bg-transparent transition-[width] duration-200 ease-linear",
"group-data-[collapsible=offcanvas]:w-0",
"group-data-[side=right]:rotate-180",
local.variant === "floating" || local.variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]"
: "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]"
)}
/>
<div
class={cn(
"w-(--sidebar-width) fixed inset-y-0 z-10 hidden h-svh transition-[left,right,width] duration-200 ease-linear md:flex",
"w-[var(--sidebar-width)] fixed inset-y-0 z-10 hidden h-svh transition-[left,right,width] duration-200 ease-linear md:flex",
local.side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
// Adjust the padding for floating and inset variants.
local.variant === "floating" || local.variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem+2px)]"
: "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)] group-data-[side=left]:border-r group-data-[side=right]:border-l",
local.class
)}
{...others}
Expand Down Expand Up @@ -602,7 +602,7 @@ const SidebarMenuSkeleton: Component<SidebarMenuSkeletonProps> = (rawProps) => {
>
{local.showIcon && <Skeleton class="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
<Skeleton
class="max-w-(--skeleton-width) h-4 flex-1"
class="max-w-[var(--skeleton-width)] h-4 flex-1"
data-sidebar="menu-skeleton-text"
style={{
"--skeleton-width": width()
Expand Down
Loading