
taurinext-shadcn
by Lightbridge-KS
Tauri + Next JS + shadcn / ui
SKILL.md
name: taurinext-shadcn description: taurinext-shadcn template reference doc. Use this when to find in-depth information about this template.
TauriNext-shadcn
This document provides context for AI assistants (like Claude) working on this taurinext-shadcn template codebase.
Project Architecture
This TauriNext-shadcn is a template repository for building cross-platform applications that run as:
- Web app (SPA in browser)
- Desktop app (native via Tauri)
Both targets share the same Next.js codebase with shadcn/ui components.
Tech Stack
- Frontend Framework: Next.js 15.5.5 (App Router)
- UI Library: React 19.1.0
- Component System: shadcn/ui (New York style)
- Styling: Tailwind CSS v3.4.18 (CRITICAL: NOT v4)
- CSS Utilities:
class-variance-authority- Component variantsclsx+tailwind-merge- Class name mergingtailwindcss-animate- Animations
- Icons: Lucide React
- Desktop Runtime: Tauri v2
- Language: TypeScript (strict mode)
- Build Mode: Static Export (CSR only, NO SSR)
CRITICAL Configuration Details
1. Tailwind & PostCSS Config Location
MUST BE IN src-next/ DIRECTORY, NOT ROOT
✅ CORRECT:
src-next/tailwind.config.cjs
src-next/postcss.config.cjs
❌ WRONG:
tailwind.config.cjs (at root)
postcss.config.cjs (at root)
Why:
npm run dev:nextexecutescd src-next && next dev- Next.js runs from inside
src-next/directory - It looks for configs in its working directory
- If configs are at root, Tailwind won't process CSS
2. Config File Format: CommonJS (.cjs)
MUST USE .cjs EXTENSION, NOT .js
// ✅ CORRECT: tailwind.config.cjs
module.exports = {
darkMode: ["class"],
content: ["./app/**/*.{js,ts,jsx,tsx,mdx}"],
// ...
}
// ❌ WRONG: tailwind.config.js with ES modules
export default {
// This will NOT work
}
Why:
- Root
package.jsonhas"type": "module" - This makes
.jsfiles use ES module syntax by default - PostCSS loader requires CommonJS format
.cjsexplicitly forces CommonJS, overriding package.json setting
3. Tailwind CSS Version
MUST BE v3.4.x, NEVER v4.x
{
"devDependencies": {
"tailwindcss": "^3.4.18", // ✅ CORRECT
"tailwindcss-animate": "^1.0.7" // ✅ Required
}
}
Why:
- shadcn/ui components built for Tailwind v3
- Tailwind v4 uses completely different config format (
@importin CSS) - v4 incompatible with current shadcn/ui components
- v4 config syntax is radically different
If v4 accidentally installed:
npm uninstall tailwindcss
npm install -D tailwindcss@^3.4.18
4. shadcn/ui CLI Limitation
THE SHADCN CLI DOES NOT WORK WITH THIS PROJECT
Reason:
- CLI expects standard Next.js structure (project root = Next.js root)
- This project has Next.js in
src-next/subdirectory - CLI cannot find
tsconfig.jsonat root level - CLI fails with "Couldn't find tsconfig.json"
Solution: Manual Component Installation
- Visit https://ui.shadcn.com/docs/components/[component-name]
- Find component code (often linked to GitHub)
- Check for required dependencies (e.g.,
@radix-uipackages) - Install dependencies:
npm install @radix-ui/react-dialog - Create file in
src-next/components/ui/[name].tsx - Copy component code
- Verify imports use
@/aliases
Example: Installing Dialog component
# 1. Install dependencies
npm install @radix-ui/react-dialog
# 2. Create file
# File: src-next/components/ui/dialog.tsx
# 3. Copy code from https://ui.shadcn.com/docs/components/dialog
# or from GitHub: https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/new-york/ui/dialog.tsx
# 4. Verify imports
import { cn } from "@/lib/utils" // ✅ Uses @ alias
Directory Structure
taurinext-shadcn/
├── src-next/ # Next.js application
│ ├── app/ # App Router
│ │ ├── layout.tsx # Root layout (NO 'use client')
│ │ ├── page.tsx # Counter demo ('use client')
│ │ └── globals.css # Tailwind + CSS variables
│ ├── components/ # React components
│ │ └── ui/ # shadcn/ui components
│ │ ├── button.tsx # Installed
│ │ ├── card.tsx # Installed
│ │ └── badge.tsx # Installed
│ ├── lib/ # Utilities
│ │ └── utils.ts # cn() helper
│ ├── public/ # Static assets
│ ├── tailwind.config.cjs # ⚠️ MUST be .cjs in src-next/
│ ├── postcss.config.cjs # ⚠️ MUST be .cjs in src-next/
│ ├── next.config.ts # Next.js config
│ └── tsconfig.json # TypeScript config
├── src-tauri/ # Tauri Rust code
├── components.json # shadcn config (root level)
└── package.json # "type": "module"
Installed shadcn/ui Components
Button (src-next/components/ui/button.tsx)
Dependencies:
{
"dependencies": {
"@radix-ui/react-slot": "^1.x"
}
}
Variants: default, destructive, outline, secondary, ghost, link
Sizes: default, sm, lg, icon
Key Features:
- Polymorphic via
asChildprop (uses Radix Slot) - Uses
cva(class-variance-authority) for variants - Supports all button HTML attributes
Usage:
import { Button } from "@/components/ui/button"
<Button variant="outline" size="lg">Click Me</Button>
<Button asChild><Link href="/page">Link Button</Link></Button>
Card (src-next/components/ui/card.tsx)
Dependencies: None (pure Tailwind)
Exports: Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter
Usage:
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
<CardContent>Content here</CardContent>
</Card>
Badge (src-next/components/ui/badge.tsx)
Dependencies: None
Variants: default, secondary, destructive, outline
Usage:
import { Badge } from "@/components/ui/badge"
<Badge variant="secondary">New</Badge>
Styling System
CSS Variables (HSL Format)
File: src-next/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%; /* HSL values (no hsl() wrapper) */
--foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
/* ... more colors */
}
.dark {
--background: 0 0% 3.9%; /* Dark mode values */
--foreground: 0 0% 98%;
/* ... more colors */
}
}
body {
background-color: hsl(var(--background)); /* Wrap in hsl() here */
color: hsl(var(--foreground));
}
Format Notes:
- Variables defined as bare HSL values:
0 0% 100% - Used with
hsl()wrapper:hsl(var(--background)) - Allows Tailwind opacity modifiers:
bg-primary/50
Tailwind Color Mappings
File: src-next/tailwind.config.cjs
module.exports = {
darkMode: ["class"],
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
// ... all color mappings
},
},
},
plugins: [require("tailwindcss-animate")],
}
This enables:
bg-backgroundclass →background-color: hsl(var(--background))text-primaryclass →color: hsl(var(--primary))bg-primary/50class →background-color: hsl(var(--primary) / 0.5)
cn() Utility Function
File: src-next/lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Purpose:
- Combines
clsx(conditional classes) +twMerge(deduplication) - Properly merges Tailwind classes
- Later classes override earlier ones
Usage:
// Conditional classes
cn("base-class", condition && "conditional-class")
// Merging with prop classes
cn("px-4 py-2", className) // className from props can override
// Complex example
cn(
"inline-flex items-center",
variant === "default" && "bg-primary text-white",
variant === "outline" && "border border-input",
disabled && "opacity-50 cursor-not-allowed",
className
)
Critical Constraints
1. Static Export Mode (CSR Only)
Configuration:
// src-next/next.config.ts
output: 'export',
images: { unoptimized: true },
Allowed:
- ✅ Client Components (
'use client') - ✅ Static generation at build time
- ✅ Client-side routing
- ✅ Client-side data fetching
- ✅ Tailwind CSS
- ✅ shadcn/ui components
NOT Allowed:
- ❌ Server Components requiring runtime
- ❌ API Routes
- ❌ Server Actions
- ❌ SSR, ISR
- ❌ Middleware
2. TypeScript Strict Mode
// src-next/tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}
Requirements:
- Explicit types (no
any) - Proper null/undefined handling
- Function return types (e.g.,
: void,: Promise<void>)
3. Path Aliases
Configuration: Already set in src-next/tsconfig.json
Usage:
import { Button } from "@/components/ui/button" // ✅
import { cn } from "@/lib/utils" // ✅
import { Button } from "../../components/ui/button" // ❌ Avoid
Common Development Tasks
Adding a New Page
// src-next/app/newpage/page.tsx
'use client';
import { Card, CardContent } from "@/components/ui/card";
export default function NewPage() {
return (
<div className="container mx-auto p-4">
<Card>
<CardContent className="p-6">
<h1 className="text-2xl font-bold">New Page</h1>
</CardContent>
</Card>
</div>
);
}
Adding Client-Side Data Fetching
'use client';
import { useEffect, useState } from 'react';
import { Card, CardContent } from '@/components/ui/card';
interface Post {
id: number;
title: string;
}
export default function Posts() {
const [posts, setPosts] = useState<Post[]>([]);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
fetch('https://api.example.com/posts')
.then((res) => res.json())
.then((data: Post[]) => setPosts(data))
.finally(() => setLoading(false));
}, []);
if (loading) return <div>Loading...</div>;
return (
<div className="space-y-4">
{posts.map((post) => (
<Card key={post.id}>
<CardContent className="p-4">
<h2 className="font-semibold">{post.title}</h2>
</CardContent>
</Card>
))}
</div>
);
}
Using Tauri APIs
'use client';
import { invoke } from '@tauri-apps/api/core';
import { Button } from '@/components/ui/button';
import { useState } from 'react';
export default function TauriDemo() {
const [result, setResult] = useState<string>('');
const handleClick = async (): Promise<void> => {
try {
const message = await invoke<string>('greet', { name: 'World' });
setResult(message);
} catch (error) {
console.error('Tauri command failed:', error);
}
};
return (
<div>
<Button onClick={handleClick}>Call Tauri</Button>
{result && <p>{result}</p>}
</div>
);
}
Dark Mode
Dark mode is configured but NOT automatically implemented. To add:
Option 1: Simple useState Toggle
'use client';
import { useEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Moon, Sun } from 'lucide-react';
export function ThemeToggle() {
const [dark, setDark] = useState<boolean>(false);
useEffect(() => {
document.documentElement.classList.toggle('dark', dark);
}, [dark]);
return (
<Button variant="ghost" size="icon" onClick={() => setDark(!dark)}>
{dark ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
</Button>
);
}
Option 2: next-themes Package (Recommended)
npm install next-themes
See TauriNextShadcn.md for full implementation.
Troubleshooting Guide
Tailwind Styles Not Applying
Symptoms:
- Components render as unstyled HTML
- No visual styling from Tailwind classes
Common Causes & Solutions:
-
Configs in wrong location
# Check files exist in src-next/ ls src-next/tailwind.config.cjs ls src-next/postcss.config.cjs -
Wrong file extension
- Must be
.cjs(CommonJS) - NOT
.jsor.mjs
- Must be
-
Missing Tailwind directives
/* src-next/app/globals.css must have: */ @tailwind base; @tailwind components; @tailwind utilities; -
Cache issues
rm -rf src-next/.next npm run dev:next
Component Import Errors
Error: Cannot find module '@/components/ui/button'
Solutions:
- Verify file exists:
src-next/components/ui/button.tsx - Check tsconfig.json has path aliases
- Restart TypeScript server in VS Code
- Check import statement uses exact filename
Tailwind v4 Accidentally Installed
Symptoms:
- Config using
@import "tailwindcss"in CSS - Different config syntax errors
Solution:
npm uninstall tailwindcss
npm install -D tailwindcss@^3.4.18
shadcn CLI Errors
Error: "Couldn't find tsconfig.json"
Solution: Don't use the CLI. Install components manually (see section above).
Build Process
Development
# Web only (fast iteration)
npm run dev:next
# Desktop app
npm run dev
Production
# Build desktop app (includes Next.js build)
npm run build
# Or just Next.js static export
npm run build:next
Output: src-next/out/ contains:
index.html_next/static/(compiled CSS, JS)- All routes as HTML files
Best Practices for AI Assistants
- Always check config locations before making changes
- Use
.cjsextension for Tailwind/PostCSS configs - Install components manually - don't suggest using shadcn CLI
- Check Tailwind version - must be v3, never v4
- Use explicit TypeScript types - follow strict mode
- Add
'use client'to interactive components - Use
@/path aliases for imports - Use
cn()utility for conditional classes - Test in both web and desktop modes when possible
Summary Checklist for AI Assistants
When working on this codebase, remember:
- Configs in
src-next/, not root - Configs use
.cjsextension - Tailwind CSS v3 (NOT v4)
- shadcn CLI doesn't work - manual install only
- Static export mode (CSR only, no SSR)
- TypeScript strict mode enforced
- Use
@/path aliases - Use
cn()for class merging - Dark mode requires manual implementation
When uncertain: Refer to SETUP.md or TauriNextShadcn.md for detailed guidance.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


