diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..909e028d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + push: + branches: + - main + + pull_request: + branches: + - main + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - id: checkout + name: Checkout + uses: actions/checkout@v3 + - id: setup-bun + name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - id: install-deps + name: Install dependencies + run: | + bun install + + - name: Lint + run: bun lint + + typecheck: + runs-on: ubuntu-latest + steps: + - id: checkout + name: Checkout + uses: actions/checkout@v3 + - id: setup-bun + name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - id: install-deps + name: Install dependencies + run: | + bun install + + - name: Typecheck + run: bun nuxi typecheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..431a96be --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,26 @@ +name: Release + +permissions: + contents: write + +on: + push: + tags: + - 'v*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - id: setup-bun + name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + + - run: bunx changelogithub + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4a7f73a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Nuxt dev/build outputs +.output +.data +.nuxt +.nitro +.cache +dist + +# Node dependencies +node_modules + +# Logs +logs +*.log + +# Misc +.DS_Store +.fleet +.idea + +# Local env files +.env +.env.* +!.env.example diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..725f5f38 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,48 @@ +{ + // Enable the ESlint flat config support + // (remove this if your ESLint extension above v3.0.5) + "eslint.experimental.useFlatConfig": true, + + // Disable the default formatter, use eslint instead + "prettier.enable": false, + "editor.formatOnSave": true, + + // Auto fix + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "never" + }, + + // Silent the stylistic rules in you IDE, but still auto fix them + "eslint.rules.customizations": [ + { "rule": "style/*", "severity": "off" }, + { "rule": "format/*", "severity": "off" }, + { "rule": "*-indent", "severity": "off" }, + { "rule": "*-spacing", "severity": "off" }, + { "rule": "*-spaces", "severity": "off" }, + { "rule": "*-order", "severity": "off" }, + { "rule": "*-dangle", "severity": "off" }, + { "rule": "*-newline", "severity": "off" }, + { "rule": "*quotes", "severity": "off" }, + { "rule": "*semi", "severity": "off" } + ], + + // Enable eslint for all supported languages + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "jsonc", + "yaml", + "toml", + "xml", + "gql", + "graphql", + "astro" + ] +} diff --git a/README.md b/README.md new file mode 100644 index 00000000..f5db2a2d --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# Nuxt 3 Minimal Starter + +Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. + +## Setup + +Make sure to install the dependencies: + +```bash +# npm +npm install + +# pnpm +pnpm install + +# yarn +yarn install + +# bun +bun install +``` + +## Development Server + +Start the development server on `http://localhost:3000`: + +```bash +# npm +npm run dev + +# pnpm +pnpm run dev + +# yarn +yarn dev + +# bun +bun run dev +``` + +## Production + +Build the application for production: + +```bash +# npm +npm run build + +# pnpm +pnpm run build + +# yarn +yarn build + +# bun +bun run build +``` + +Locally preview production build: + +```bash +# npm +npm run preview + +# pnpm +pnpm run preview + +# yarn +yarn preview + +# bun +bun run preview +``` + +Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. diff --git a/app.vue b/app.vue new file mode 100644 index 00000000..a495b757 --- /dev/null +++ b/app.vue @@ -0,0 +1,5 @@ + diff --git a/assets/css/tailwind.css b/assets/css/tailwind.css new file mode 100644 index 00000000..8a04b2ba --- /dev/null +++ b/assets/css/tailwind.css @@ -0,0 +1,78 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + + --ring: 240 10% 3.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --ring: 240 4.9% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 00000000..f354b85d Binary files /dev/null and b/bun.lockb differ diff --git a/components.json b/components.json new file mode 100644 index 00000000..91c859b6 --- /dev/null +++ b/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://shadcn-vue.com/schema.json", + "style": "default", + "typescript": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "assets/css/tailwind.css", + "baseColor": "zinc", + "cssVariables": true + }, + "framework": "nuxt", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/components/ui/button/Button.vue b/components/ui/button/Button.vue new file mode 100644 index 00000000..5cfd668a --- /dev/null +++ b/components/ui/button/Button.vue @@ -0,0 +1,26 @@ + + + diff --git a/components/ui/button/index.ts b/components/ui/button/index.ts new file mode 100644 index 00000000..1b00c326 --- /dev/null +++ b/components/ui/button/index.ts @@ -0,0 +1,35 @@ +import { type VariantProps, cva } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + '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', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + xs: 'h-7 rounded px-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export type ButtonVariants = VariantProps diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..32ff0b90 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,18 @@ +import antfu from '@antfu/eslint-config'; + +export default antfu({ + stylistic: { + indent: 2, + quotes: 'single', + semi: true, + }, + typescript: true, + vue: true, +}, { + rules: { + 'style/brace-style': ['warn', '1tbs', { allowSingleLine: true }], + 'vue/block-order': ['error', { + order: ['template', 'script', 'style'], + }], + }, +}); diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 00000000..9ad0df42 --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/nuxt.config.ts b/nuxt.config.ts new file mode 100644 index 00000000..860d6611 --- /dev/null +++ b/nuxt.config.ts @@ -0,0 +1,18 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: [ + '@nuxtjs/tailwindcss', + 'shadcn-nuxt', + ], + shadcn: { + /** + * Prefix for all the imported component + */ + prefix: '', + /** + * Directory that the component lives in. + * @default "./components/ui" + */ + componentDir: './components/ui', + }, +}); diff --git a/package.json b/package.json new file mode 100644 index 00000000..bcb50bd7 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "nuxt-app", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare", + "lint": "eslint .", + "lint:fix": "eslint . --fix" + }, + "dependencies": { + "@nuxtjs/tailwindcss": "^6.12.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-vue-next": "^0.378.0", + "nuxt": "^3.11.2", + "radix-vue": "^1.8.0", + "shadcn-nuxt": "^0.10.4", + "tailwind-merge": "^2.3.0", + "tailwindcss-animate": "^1.0.7", + "vue": "^3.4.27", + "vue-router": "^4.3.2" + }, + "devDependencies": { + "@antfu/eslint-config": "^2.18.1", + "eslint": "9.2.0", + "vue-tsc": "^2.0.19" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..18993ad9 Binary files /dev/null and b/public/favicon.ico differ diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 00000000..b9ed69c1 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../.nuxt/tsconfig.server.json" +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..6bb5adc1 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,86 @@ +const animate = require('tailwindcss-animate'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ['class'], + safelist: ['dark'], + prefix: '', + + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + 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))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + xl: 'calc(var(--radius) + 4px)', + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { height: 0 }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: 0 }, + }, + 'collapsible-down': { + from: { height: 0 }, + to: { height: 'var(--radix-collapsible-content-height)' }, + }, + 'collapsible-up': { + from: { height: 'var(--radix-collapsible-content-height)' }, + to: { height: 0 }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + 'collapsible-down': 'collapsible-down 0.2s ease-in-out', + 'collapsible-up': 'collapsible-up 0.2s ease-in-out', + }, + }, + }, + plugins: [animate], +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..a746f2a7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,4 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" +}