├── src ├── env.d.ts ├── lib │ └── utils.ts ├── components │ ├── Avatar.tsx │ ├── Footer.astro │ └── ui │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ └── card.tsx ├── layouts │ └── Layout.astro ├── styles │ └── globals.css └── pages │ └── index.astro ├── public ├── opengraph.png └── favicon.svg ├── tsconfig.json ├── astro.config.mjs ├── components.json ├── .gitignore ├── package.json ├── LICENSE ├── tailwind.config.mjs └── README.md /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/opengraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dansholds/astro-shadcn-starter/HEAD/public/opengraph.png -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "react", 6 | "baseUrl": ".", 7 | "paths": { 8 | "@/*": [ 9 | "./src/*" 10 | ] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | import react from "@astrojs/react"; 3 | 4 | import tailwind from "@astrojs/tailwind"; 5 | 6 | // https://astro.build/config 7 | export default defineConfig({ 8 | integrations: [ 9 | react(), 10 | tailwind({ 11 | applyBaseStyles: false, 12 | }), 13 | ], 14 | }); -------------------------------------------------------------------------------- /src/components/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; 2 | 3 | export const AvatarComponent = ({ src, alt, fallbackText }: { src: string, alt: string, fallbackText: string }) => { 4 | return ( 5 | 6 | 7 | {fallbackText} 8 | 9 | ); 10 | }; -------------------------------------------------------------------------------- /src/components/Footer.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "@/layouts/Layout.astro" 3 | --- 4 | 5 |
6 |

© 2024 Astro x Shadcn Starter by Dan

7 |
-------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.mjs", 8 | "css": "./src/styles/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | 4 | # generated types 5 | .astro/ 6 | 7 | # dependencies 8 | node_modules/ 9 | 10 | # logs 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | # jetbrains setting folder 24 | .idea/ 25 | 26 | # lock files 27 | package-lock.json 28 | 29 | # vscode settings 30 | .vscode/ -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zapping-zero", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro check && astro build", 9 | "preview": "astro preview", 10 | "astro": "astro" 11 | }, 12 | "dependencies": { 13 | "@astrojs/check": "^0.8.3", 14 | "@astrojs/react": "^3.6.0", 15 | "@astrojs/tailwind": "^5.1.0", 16 | "@fontsource-variable/space-grotesk": "^5.0.18", 17 | "@radix-ui/react-accordion": "^1.2.0", 18 | "@radix-ui/react-avatar": "^1.1.0", 19 | "@radix-ui/react-slot": "^1.1.0", 20 | "@types/react": "^18.3.3", 21 | "@types/react-dom": "^18.3.0", 22 | "astro": "^4.12.2", 23 | "class-variance-authority": "^0.7.0", 24 | "clsx": "^2.1.1", 25 | "lucide-react": "^0.417.0", 26 | "react": "^18.3.1", 27 | "react-dom": "^18.3.1", 28 | "tailwind-merge": "^2.4.0", 29 | "tailwindcss": "^3.4.7", 30 | "tailwindcss-animate": "^1.0.7", 31 | "typescript": "^5.5.4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 dsh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/ui/avatar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as AvatarPrimitive from "@radix-ui/react-avatar" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Avatar = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 18 | )) 19 | Avatar.displayName = AvatarPrimitive.Root.displayName 20 | 21 | const AvatarImage = React.forwardRef< 22 | React.ElementRef, 23 | React.ComponentPropsWithoutRef 24 | >(({ className, ...props }, ref) => ( 25 | 30 | )) 31 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 32 | 33 | const AvatarFallback = React.forwardRef< 34 | React.ElementRef, 35 | React.ComponentPropsWithoutRef 36 | >(({ className, ...props }, ref) => ( 37 | 45 | )) 46 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 47 | 48 | export { Avatar, AvatarImage, AvatarFallback } 49 | -------------------------------------------------------------------------------- /src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | interface Props { 3 | title: string; 4 | } 5 | 6 | const { title } = Astro.props; 7 | import '@fontsource-variable/space-grotesk'; 8 | --- 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {title} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 60 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 |
17 | )) 18 | Card.displayName = "Card" 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 |
29 | )) 30 | CardHeader.displayName = "CardHeader" 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 |

44 | )) 45 | CardTitle.displayName = "CardTitle" 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |

56 | )) 57 | CardDescription.displayName = "CardDescription" 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 |

64 | )) 65 | CardContent.displayName = "CardContent" 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 |
76 | )) 77 | CardFooter.displayName = "CardFooter" 78 | 79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 80 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 84% 4.9%; 9 | --card: 0 0% 100%; 10 | --card-foreground: 222.2 84% 4.9%; 11 | --popover: 0 0% 100%; 12 | --popover-foreground: 222.2 84% 4.9%; 13 | --primary: 222.2 47.4% 11.2%; 14 | --primary-foreground: 210 40% 98%; 15 | --secondary: 210 40% 96.1%; 16 | --secondary-foreground: 222.2 47.4% 11.2%; 17 | --muted: 210 40% 96.1%; 18 | --muted-foreground: 215.4 16.3% 46.9%; 19 | --accent: 210 40% 96.1%; 20 | --accent-foreground: 222.2 47.4% 11.2%; 21 | --destructive: 0 84.2% 60.2%; 22 | --destructive-foreground: 210 40% 98%; 23 | --border: 214.3 31.8% 91.4%; 24 | --input: 214.3 31.8% 91.4%; 25 | --ring: 222.2 84% 4.9%; 26 | --radius: 0.5rem; 27 | --chart-1: 12 76% 61%; 28 | --chart-2: 173 58% 39%; 29 | --chart-3: 197 37% 24%; 30 | --chart-4: 43 74% 66%; 31 | --chart-5: 27 87% 67%; 32 | } 33 | 34 | .dark { 35 | --background: 222.2 84% 4.9%; 36 | --foreground: 210 40% 98%; 37 | --card: 222.2 84% 4.9%; 38 | --card-foreground: 210 40% 98%; 39 | --popover: 222.2 84% 4.9%; 40 | --popover-foreground: 210 40% 98%; 41 | --primary: 210 40% 98%; 42 | --primary-foreground: 222.2 47.4% 11.2%; 43 | --secondary: 217.2 32.6% 17.5%; 44 | --secondary-foreground: 210 40% 98%; 45 | --muted: 217.2 32.6% 17.5%; 46 | --muted-foreground: 215 20.2% 65.1%; 47 | --accent: 217.2 32.6% 17.5%; 48 | --accent-foreground: 210 40% 98%; 49 | --destructive: 0 62.8% 30.6%; 50 | --destructive-foreground: 210 40% 98%; 51 | --border: 217.2 32.6% 17.5%; 52 | --input: 217.2 32.6% 17.5%; 53 | --ring: 212.7 26.8% 83.9%; 54 | --chart-1: 220 70% 50%; 55 | --chart-2: 160 60% 45%; 56 | --chart-3: 30 80% 55%; 57 | --chart-4: 280 65% 60%; 58 | --chart-5: 340 75% 55%; 59 | } 60 | } 61 | 62 | body, p, h1, h2, h3, h4, h5, h6 { 63 | font-family: 'Space Grotesk Variable', sans-serif; 64 | } 65 | 66 | @layer base { 67 | * { 68 | @apply border-border; 69 | } 70 | body { 71 | @apply bg-background text-foreground; 72 | } 73 | } -------------------------------------------------------------------------------- /tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | darkMode: ["class"], 4 | content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}" 5 | ], 6 | prefix: "", 7 | theme: { 8 | container: { 9 | center: true, 10 | padding: "2rem", 11 | screens: { 12 | "2xl": "1400px", 13 | }, 14 | }, 15 | extend: { 16 | keyframes: { 17 | "accordion-down": { 18 | from: { height: "0" }, 19 | to: { height: "var(--radix-accordion-content-height)" }, 20 | }, 21 | "accordion-up": { 22 | from: { height: "var(--radix-accordion-content-height)" }, 23 | to: { height: "0" }, 24 | }, 25 | }, 26 | animation: { 27 | "accordion-down": "accordion-down 0.2s ease-out", 28 | "accordion-up": "accordion-up 0.2s ease-out", 29 | }, 30 | colors: { 31 | border: "hsl(var(--border))", 32 | input: "hsl(var(--input))", 33 | ring: "hsl(var(--ring))", 34 | background: "hsl(var(--background))", 35 | foreground: "hsl(var(--foreground))", 36 | primary: { 37 | DEFAULT: "hsl(var(--primary))", 38 | foreground: "hsl(var(--primary-foreground))", 39 | }, 40 | secondary: { 41 | DEFAULT: "hsl(var(--secondary))", 42 | foreground: "hsl(var(--secondary-foreground))", 43 | }, 44 | destructive: { 45 | DEFAULT: "hsl(var(--destructive))", 46 | foreground: "hsl(var(--destructive-foreground))", 47 | }, 48 | muted: { 49 | DEFAULT: "hsl(var(--muted))", 50 | foreground: "hsl(var(--muted-foreground))", 51 | }, 52 | accent: { 53 | DEFAULT: "hsl(var(--accent))", 54 | foreground: "hsl(var(--accent-foreground))", 55 | }, 56 | popover: { 57 | DEFAULT: "hsl(var(--popover))", 58 | foreground: "hsl(var(--popover-foreground))", 59 | }, 60 | card: { 61 | DEFAULT: "hsl(var(--card))", 62 | foreground: "hsl(var(--card-foreground))", 63 | }, 64 | }, 65 | borderRadius: { 66 | lg: "var(--radius)", 67 | md: "calc(var(--radius) - 2px)", 68 | sm: "calc(var(--radius) - 4px)", 69 | }, 70 | keyframes: { 71 | "accordion-down": { 72 | from: { height: "0" }, 73 | to: { height: "var(--radix-accordion-content-height)" }, 74 | }, 75 | "accordion-up": { 76 | from: { height: "var(--radix-accordion-content-height)" }, 77 | to: { height: "0" }, 78 | }, 79 | }, 80 | animation: { 81 | "accordion-down": "accordion-down 0.2s ease-out", 82 | "accordion-up": "accordion-up 0.2s ease-out", 83 | }, 84 | }, 85 | }, 86 | plugins: [require("tailwindcss-animate")], 87 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Astro + Shadcn Starter 2 | 3 | Welcome to the Astro + Shadcn Starter Template! This project is designed to help you get started quickly with [Astro](https://astro.build) and [Shadcn UI](https://ui.shadcn.com). It includes Tailwind CSS for styling and React for building interactive components. 4 | 5 | ![astroxshadcn](https://github.com/user-attachments/assets/99b0b2a1-3ef9-4f28-a347-91c665279c2d) 6 | 7 | ## Table of Contents 8 | 9 | - [Features](#features) 10 | - [Getting Started](#getting-started) 11 | - [Project Structure](#project-structure) 12 | - [Usage](#usage) 13 | - [Important Notes About Astro & Shadcn](#important) 14 | 15 | ## Features 16 | 17 | - 🚀 **Astro** - Modern static site generator. 18 | - 🎨 **Shadcn UI** - Beautifully designed components built with Radix UI and Tailwind CSS. 19 | - 📦 **Tailwind CSS** - Utility-first CSS framework. 20 | - 🔥 **React** - Library for building user interfaces. 21 | 22 | ## Getting Started 23 | 24 | Follow these instructions to set up the project locally. 25 | 26 | ### Prerequisites 27 | 28 | Ensure you have the following installed: 29 | 30 | - [Node.js](https://nodejs.org/en/download/) 31 | - [npm](https://www.npmjs.com/get-npm) 32 | 33 | ### Installation 34 | 35 | 1. **Clone the repository**: 36 | 37 | ```sh 38 | git clone https://github.com/your-username/astro-shadcn-starter.git 39 | cd astro-shadcn-starter 40 | ``` 41 | 42 | 2. **Install dependencies**: 43 | 44 | ```sh 45 | npm install 46 | ``` 47 | 48 | 3. **Start the development server**: 49 | 50 | ```sh 51 | npm run dev 52 | ``` 53 | 54 | Open [http://localhost:3000](http://localhost:3000) in your browser to see the result. 55 | 56 | ## Project Structure 57 | ``` 58 | ├── public # Static assets 59 | ├── src 60 | │ ├── components # React components 61 | │ ├────ui # Shadcn installed components 62 | │ ├── layouts # Layout components 63 | │ ├── pages # Astro pages 64 | │ ├── styles # Global styles 65 | │ └── utils # Utility functions 66 | ├── astro.config.mjs # Astro configuration 67 | ├── tailwind.config.mjs # Tailwind CSS configuration 68 | └── package.json # Project metadata and dependencies 69 | ``` 70 | 71 | ## Usage 72 | 73 | ### Adding a New Page 74 | 75 | To add a new page, create a new `.astro` file in the `src/pages` directory. 76 | 77 | Example: 78 | 79 | ```astro 80 | --- 81 | import Layout from '../layouts/Layout.astro'; 82 | --- 83 | 84 | 85 |

New Page

86 |

This is a new page.

87 |
88 | ``` 89 | 90 | ## Important 91 | 92 | Due to the static and island based nature of Astro, a lot of Shadcn components won't work out of the box, 93 | some components such as the Avatar require more work on your side to enable them to work (see `src/components/Avatar.tsx`). 94 | 95 | You can find useful information on this from the following links: 96 | 97 | - [Issues with Astro Islands when using Shadcn](https://github.com/shadcn-ui/ui/issues/2249) 98 | - [Abstract components into react, ts components](https://github.com/shadcn-ui/ui/issues/2890) 99 | -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../layouts/Layout.astro'; 3 | import '@/styles/globals.css'; 4 | 5 | import { buttonVariants } from "@/components/ui/button"; 6 | import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"; 7 | import { AvatarComponent } from "../components/Avatar.tsx"; 8 | import Footer from '@/components/Footer.astro'; 9 | 10 | --- 11 | 12 | 13 |
14 |

15 | Astro x Shadcn Starter Template 16 |

17 | 18 | 19 | 20 | Getting Started 21 | Your new project is ready to go! 22 | 23 | 24 |

This starter template includes:

25 |
    26 |
  • 🚀 Astro
  • 27 |
  • 🎨 Shadcn UI
  • 28 |
  • 📦 Tailwind CSS
  • 29 |
  • 🔥 React
  • 30 |
31 |
32 | 33 | 34 | Explore Shadcn Documentation 35 | 36 | 37 | Explore Astro Documentation 38 | 39 | 40 | View GitHub Repository 41 | 42 | 43 |
44 | 45 |
46 | 47 | 48 | 49 | 50 | Astro 51 | 52 | 53 | 54 | Build faster websites with less client-side JavaScript. 55 | 56 | 57 | 58 | 59 | 60 | 61 | Shadcn UI 62 | 63 | 64 | 65 | Beautifully designed components built with Radix UI and Tailwind CSS. 66 | 67 | 68 |
69 |
70 |