Skip to content

[WIP] Tweakcn import support for shadcn registry JSON format#106

Closed
Copilot wants to merge 1 commit into
mainfrom
copilot/tweakcn-import-support-shadcn-json
Closed

[WIP] Tweakcn import support for shadcn registry JSON format#106
Copilot wants to merge 1 commit into
mainfrom
copilot/tweakcn-import-support-shadcn-json

Conversation

Copilot AI commented May 21, 2026

Copy link
Copy Markdown

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.


This section details on the original issue you should resolve

<issue_title>Tweakcn import: support shadcn-registry JSON format from /r/themes/<name>.json</issue_title>
<issue_description>## Context

The new tweakcn import flow (app/src/themes/tweakcn_import.rs::parse_blocks) parses the CSS-block format users get from tweakcn's "Copy CSS" button:

```css
:root { --background: oklch(...); ... }
.dark { --background: oklch(...); ... }
```

But tweakcn also publishes themes as a shadcn registry JSON at stable URLs like https://tweakcn.com/r/themes/<name>.json (e.g. /r/themes/vercel.json):

```json
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "vercel",
"type": "registry:style",
"cssVars": {
"theme": { "font-sans": "Geist, sans-serif", ... },
"light": { "background": "oklch(0.99 0 0)", "foreground": "oklch(0 0 0)", ... },
"dark": { "background": "oklch(0 0 0)", "foreground": "oklch(1 0 0)", ... }
}
}
```

The editor-URL pattern users see in their browser (https://tweakcn.com/editor/theme?theme=vercel) maps deterministically to https://tweakcn.com/r/themes/vercel.json.

Why this matters

Users who hand a Cast-Codes contributor a tweakcn share URL today have to:

  1. Open tweakcn.com
  2. Click "Code" / "Copy CSS"
  3. Paste into the import modal

Each manual step is a place to drop content. Worse, the modal currently chokes on full pastes (issue #91). If we supported the JSON path:

  • Drag a .json file onto the modal directly, OR
  • Paste a tweakcn URL into the modal and we fetch + extract (still local-only — https://tweakcn.com is the user's choice of source, not a Cast-Codes hosted dependency).

Suggested implementation

Add a sibling parser at parse_registry_json(input: &str) -> Result<ParsedBlocks, ImportError> in app/src/themes/tweakcn_import.rs:

```rust
pub fn parse_blocks_or_json(input: &str) -> Result<ParsedBlocks, ImportError> {
let trimmed = input.trim_start();
if trimmed.starts_with('{') {
parse_registry_json(input)
} else {
parse_blocks(input)
}
}

fn parse_registry_json(input: &str) -> Result<ParsedBlocks, ImportError> {
let v: serde_json::Value = serde_json::from_str(input)
.map_err(|e| ImportError::Io(format!("invalid JSON: {e}")))?;
let css_vars = v.get("cssVars").ok_or(ImportError::NoColorBlocksFound)?;
let name = v.get("name").and_then(|n| n.as_str()).map(String::from);

let mut blocks = ParsedBlocks { name_comment: name, ..Default::default() };

for (mode_key, target) in [("light", &mut blocks.light), ("dark", &mut blocks.dark)] {
    if let Some(map) = css_vars.get(mode_key).and_then(|m| m.as_object()) {
        for (k, v) in map {
            let s = match v.as_str() { Some(s) => s, None => continue };
            // Same oklch(L C H) parsing as parse_blocks's parse_decls closure.
            let Some(args) = s.strip_prefix("oklch(").and_then(|t| t.strip_suffix(')')) else { continue };
            // … reuse the triple-parsing logic …
        }
    }
}

if blocks.light.is_empty() && blocks.dark.is_empty() {
    return Err(ImportError::NoColorBlocksFound);
}
Ok(blocks)

}
```

Then wire the modal's on_css_changed to call parse_blocks_or_json. Drag-drop already handles .css; extend the extension check to allow .json too.

URL-fetch is more involved (network call from the OSS build — needs to clear the [castcodes-fork-local-boundary](skill: castcodes-fork-local-boundary) check). A safer middle step: if the user pastes https://tweakcn.com/..., surface a hint "Paste the JSON from the registry URL instead of the share URL" with a click-to-copy curl command.

Discovery context

Validated during smoke test of branch castcodes/theme-tweakcn-impl. The user pasted a Vercel-theme tweakcn URL into the modal expecting it to work; the modal showed CSS but with so much overhead the user gave up and asked us to extract via URL externally. I curl'd /r/themes/vercel.json and converted to CSS via a one-off Python script, then ran through parse_blocks + to_warp_theme — output landed cleanly in ~/.cast-codes/themes/vercel.yaml. Adding native JSON support would have eliminated the conversion step.</issue_description>

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@BunsDev

BunsDev commented May 21, 2026

Copy link
Copy Markdown
Member

Closing as superseded by #107, which implements the registry JSON parser, modal wiring, focused tests, and local verification.

@BunsDev BunsDev closed this May 21, 2026
@BunsDev BunsDev deleted the copilot/tweakcn-import-support-shadcn-json branch June 15, 2026 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tweakcn import: support shadcn-registry JSON format from /r/themes/<name>.json

3 participants