From 9238f80e6529b309166e0a9dec05ec9d09a74c77 Mon Sep 17 00:00:00 2001 From: Hugo Felipe Camilo Date: Tue, 28 Oct 2025 18:38:49 -0300 Subject: [PATCH 1/2] Align shadcn home with official design --- .editorconfig | 19 + .ember-cli | 7 + .github/workflows/ci.yml | 47 + .gitignore | 18 + .prettierignore | 13 + .prettierrc.js | 14 + .stylelintignore | 5 + .stylelintrc.js | 5 + .template-lintrc.js | 5 + .watchmanconfig | 3 + README.md | 45 +- app/app.js | 17 + app/components/.gitkeep | 0 app/components/shadcn-home.gjs | 8 + app/controllers/.gitkeep | 0 app/deprecation-workflow.js | 24 + app/helpers/.gitkeep | 0 app/index.html | 31 + app/models/.gitkeep | 0 app/react-components/lib/utils.js | 6 + app/react-components/shadcn-home.js | 649 + app/react-components/ui/avatar.js | 25 + app/react-components/ui/badge.js | 27 + app/react-components/ui/button.js | 46 + app/react-components/ui/card.js | 35 + app/react-components/ui/input.js | 20 + app/react-components/ui/label.js | 15 + app/react-components/ui/separator.js | 21 + app/react-components/ui/switch.js | 24 + app/react-components/ui/tabs.js | 41 + app/react-components/ui/textarea.js | 19 + app/react-components/ui/tooltip.js | 25 + app/router.js | 9 + app/routes/.gitkeep | 0 app/styles/app.css | 72 + app/templates/application.hbs | 3 + config/ember-cli-update.json | 20 + config/environment.js | 48 + config/optional-features.json | 7 + config/targets.js | 11 + ember-cli-build.js | 48 + eslint.config.mjs | 123 + package-lock.json | 26056 +++++++++++++++++++++++++ package.json | 110 + postcss.config.js | 6 + public/robots.txt | 3 + tailwind.config.js | 106 + testem.js | 23 + tests/helpers/index.js | 42 + tests/index.html | 39 + tests/integration/.gitkeep | 0 tests/test-helper.js | 14 + tests/unit/.gitkeep | 0 53 files changed, 27953 insertions(+), 1 deletion(-) create mode 100644 .editorconfig create mode 100644 .ember-cli create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.js create mode 100644 .stylelintignore create mode 100644 .stylelintrc.js create mode 100644 .template-lintrc.js create mode 100644 .watchmanconfig create mode 100644 app/app.js create mode 100644 app/components/.gitkeep create mode 100644 app/components/shadcn-home.gjs create mode 100644 app/controllers/.gitkeep create mode 100644 app/deprecation-workflow.js create mode 100644 app/helpers/.gitkeep create mode 100644 app/index.html create mode 100644 app/models/.gitkeep create mode 100644 app/react-components/lib/utils.js create mode 100644 app/react-components/shadcn-home.js create mode 100644 app/react-components/ui/avatar.js create mode 100644 app/react-components/ui/badge.js create mode 100644 app/react-components/ui/button.js create mode 100644 app/react-components/ui/card.js create mode 100644 app/react-components/ui/input.js create mode 100644 app/react-components/ui/label.js create mode 100644 app/react-components/ui/separator.js create mode 100644 app/react-components/ui/switch.js create mode 100644 app/react-components/ui/tabs.js create mode 100644 app/react-components/ui/textarea.js create mode 100644 app/react-components/ui/tooltip.js create mode 100644 app/router.js create mode 100644 app/routes/.gitkeep create mode 100644 app/styles/app.css create mode 100644 app/templates/application.hbs create mode 100644 config/ember-cli-update.json create mode 100644 config/environment.js create mode 100644 config/optional-features.json create mode 100644 config/targets.js create mode 100644 ember-cli-build.js create mode 100644 eslint.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 public/robots.txt create mode 100644 tailwind.config.js create mode 100644 testem.js create mode 100644 tests/helpers/index.js create mode 100644 tests/index.html create mode 100644 tests/integration/.gitkeep create mode 100644 tests/test-helper.js create mode 100644 tests/unit/.gitkeep diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c35a002 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.hbs] +insert_final_newline = false + +[*.{diff,md}] +trim_trailing_whitespace = false diff --git a/.ember-cli b/.ember-cli new file mode 100644 index 0000000..465c405 --- /dev/null +++ b/.ember-cli @@ -0,0 +1,7 @@ +{ + /** + Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript + rather than JavaScript by default, when a TypeScript version of a given blueprint is available. + */ + "isTypeScriptProject": false +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8a43ff0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: + - main + - master + pull_request: {} + +concurrency: + group: ci-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: "Lint" + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v3 + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + - name: Install Dependencies + run: npm ci + - name: Lint + run: npm run lint + + test: + name: "Test" + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v3 + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + - name: Install Dependencies + run: npm ci + - name: Run Tests + run: npm test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0dde6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# compiled output +/dist/ +/declarations/ + +# dependencies +/node_modules/ + +# misc +/.env* +/.pnp* +/.eslintcache +/coverage/ +/npm-debug.log* +/testem.log +/yarn-error.log + +# broccoli-debug +/DEBUG/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d7ab459 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +# unconventional js +/blueprints/*/files/ + +# compiled output +/dist/ + +# misc +/coverage/ +!.* +.*/ +/pnpm-lock.yaml +ember-cli-update.json +*.html diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..8e62a45 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,14 @@ +'use strict'; + +module.exports = { + plugins: ['prettier-plugin-ember-template-tag'], + overrides: [ + { + files: '*.{js,gjs,ts,gts,mjs,mts,cjs,cts}', + options: { + singleQuote: true, + templateSingleQuote: false, + }, + }, + ], +}; diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..fc178a0 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,5 @@ +# unconventional files +/blueprints/*/files/ + +# compiled output +/dist/ diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000..56a013c --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: ['stylelint-config-standard'], +}; diff --git a/.template-lintrc.js b/.template-lintrc.js new file mode 100644 index 0000000..f35f61c --- /dev/null +++ b/.template-lintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: 'recommended', +}; diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 0000000..f9c3d8f --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["dist"] +} diff --git a/README.md b/README.md index 1abdde3..c024316 100644 --- a/README.md +++ b/README.md @@ -1 +1,44 @@ -# -ember-react \ No newline at end of file +# shadcn/ui + Ember demo + +This project reproduces the [ui.shadcn.com](https://ui.shadcn.com) landing page inside an Ember 6.4 application. The React +components from shadcn/ui are rendered through [`@universal-ember/react`](https://github.com/universal-ember/react), allowing us +to embed modern React component libraries in classic Ember routes without losing reactivity or DX. + +## Prerequisites + +You will need the following things properly installed on your computer. + +- [Git](https://git-scm.com/) +- [Node.js](https://nodejs.org/) (with npm) +- [Ember CLI](https://cli.emberjs.com/release/) +- [Google Chrome](https://google.com/chrome/) + +## Installation + +```bash +git clone +cd -ember-react +npm install +``` + +## Running / Development + +```bash +npm run start +``` + +- Visit your app at [http://localhost:4200](http://localhost:4200). +- Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests). + +## Available scripts + +- `npm run start` – start the local development server with live reload. +- `npm run build` – create a production build (`dist/`). +- `npm run lint` – run the configured lint tasks. +- `npm run test` – execute linting and Ember tests in CI mode. + +## Further Reading + +- [@universal-ember/react documentation](https://github.com/universal-ember/react) +- [shadcn/ui documentation](https://ui.shadcn.com) +- [Ember CLI guide](https://cli.emberjs.com/release/) diff --git a/app/app.js b/app/app.js new file mode 100644 index 0000000..7eb6ab4 --- /dev/null +++ b/app/app.js @@ -0,0 +1,17 @@ +import Application from '@ember/application'; +import Resolver from 'ember-resolver'; +import loadInitializers from 'ember-load-initializers'; +import config from '-ember-react/config/environment'; +import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros'; + +if (macroCondition(isDevelopingApp())) { + importSync('./deprecation-workflow'); +} + +export default class App extends Application { + modulePrefix = config.modulePrefix; + podModulePrefix = config.podModulePrefix; + Resolver = Resolver; +} + +loadInitializers(App, config.modulePrefix); diff --git a/app/components/.gitkeep b/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/components/shadcn-home.gjs b/app/components/shadcn-home.gjs new file mode 100644 index 0000000..53d641a --- /dev/null +++ b/app/components/shadcn-home.gjs @@ -0,0 +1,8 @@ +import { makeRenderable } from '@universal-ember/react'; +import { ShadcnHome as ReactShadcnHome } from '../react-components/shadcn-home'; + +const ShadcnHome = makeRenderable(ReactShadcnHome); + + diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/deprecation-workflow.js b/app/deprecation-workflow.js new file mode 100644 index 0000000..274a689 --- /dev/null +++ b/app/deprecation-workflow.js @@ -0,0 +1,24 @@ +import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow'; + +/** + * Docs: https://github.com/ember-cli/ember-cli-deprecation-workflow + */ +setupDeprecationWorkflow({ + /** + false by default, but if a developer / team wants to be more aggressive about being proactive with + handling their deprecations, this should be set to "true" + */ + throwOnUnhandled: false, + workflow: [ + /* ... handlers ... */ + /* to generate this list, run your app for a while (or run the test suite), + * and then run in the browser console: + * + * deprecationWorkflow.flushDeprecations() + * + * And copy the handlers here + */ + /* example: */ + /* { handler: 'silence', matchId: 'template-action' }, */ + ], +}); diff --git a/app/helpers/.gitkeep b/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..021344f --- /dev/null +++ b/app/index.html @@ -0,0 +1,31 @@ + + + + + EmberReact + + + + {{content-for "head"}} + + + + + + + + + {{content-for "head-footer"}} + + + {{content-for "body"}} + + + + + {{content-for "body-footer"}} + + diff --git a/app/models/.gitkeep b/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/react-components/lib/utils.js b/app/react-components/lib/utils.js new file mode 100644 index 0000000..0ae73e1 --- /dev/null +++ b/app/react-components/lib/utils.js @@ -0,0 +1,6 @@ +import { clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs) { + return twMerge(clsx(inputs)); +} diff --git a/app/react-components/shadcn-home.js b/app/react-components/shadcn-home.js new file mode 100644 index 0000000..2fec5b8 --- /dev/null +++ b/app/react-components/shadcn-home.js @@ -0,0 +1,649 @@ +import React, { useMemo, useState } from 'react'; +import { + ArrowRight, + Check, + Copy, + CreditCard, + Gauge, + LayoutDashboard, + Menu, + Palette, + Search, + ShieldCheck, + Sparkles, + Star, + Sun, + Wand2, +} from 'lucide-react'; + +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; +import { Badge } from './ui/badge'; +import { Button } from './ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from './ui/card'; +import { Input } from './ui/input'; +import { Label } from './ui/label'; +import { Separator } from './ui/separator'; +import { Switch } from './ui/switch'; +import { Tabs, TabsList, TabsTrigger } from './ui/tabs'; +import { Textarea } from './ui/textarea'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip'; + +const navLinks = [ + { label: 'Docs', href: 'https://ui.shadcn.com/docs/installation' }, + { label: 'Components', href: 'https://ui.shadcn.com/docs/components' }, + { label: 'Blocks', href: 'https://ui.shadcn.com/blocks' }, + { label: 'Charts', href: 'https://ui.shadcn.com/examples/dashboard' }, + { label: 'Directory', href: 'https://ui.shadcn.com/docs/directory' }, + { label: 'Themes', href: 'https://ui.shadcn.com/themes' }, + { label: 'Colors', href: 'https://ui.shadcn.com/docs/colors' }, +]; + +const exampleTabs = [ + { value: 'dashboard', label: 'Dashboard' }, + { value: 'tasks', label: 'Tasks' }, + { value: 'playground', label: 'Playground' }, + { value: 'authentication', label: 'Authentication' }, +]; + +const logos = ['Vercel', 'Supabase', 'Linear', 'PlanetScale', 'Raycast', 'Aceternity']; + +const highlightCards = [ + { + title: 'Accessible components', + description: + 'Build with confidence using headless primitives wired for accessibility, keyboard navigation, and screen readers.', + icon: ShieldCheck, + }, + { + title: 'Customizable by design', + description: + 'Start with the New York theme, tweak tokens, and remix the layout. Everything lives in your codebase and ships with Tailwind.', + icon: Palette, + }, + { + title: 'Works with your stack', + description: + 'Use the CLI to scaffold components for any framework. Keep Ember on rails while pulling from the React ecosystem.', + icon: LayoutDashboard, + }, +]; + +const workflowBullets = [ + { + title: 'Copy and paste, then own it', + description: + 'Generate the components you need and keep them local. Version them, refactor them, and shape them to your product.', + }, + { + title: 'Design tokens for every surface', + description: + 'Fine tune typography, radii, and colors using Tailwind and CSS variables. Preview light and dark themes instantly.', + }, + { + title: 'Ship complex flows faster', + description: + 'Drop in polished examples such as payments, analytics, auth, and dashboards. Connect real data without rebuilding UI.', + }, +]; + +const avatars = [ + { name: 'Cameron Nguyen', initials: 'CN', src: 'https://avatar.vercel.sh/cn' }, + { name: 'Lana Rivers', initials: 'LR', src: 'https://avatar.vercel.sh/lr' }, + { name: 'Elliot Reyes', initials: 'ER', src: 'https://avatar.vercel.sh/er' }, +]; + +function AnnouncementBar() { + return ( +
+
+ + New + + + New Components: Field, Input Group, Item and more + + +
+
+ ); +} + +function SiteHeader() { + return ( +
+
+
+ + shadcn/ui +
+ +
+
+ + 98.6k +
+ + + + + + Toggle layout + + + + + + Toggle theme + + +
+
+
+ ); +} + +function HeroSection() { + return ( +
+
+
+
+
+ + Foundation + +
+

+ The Foundation for your Design System +

+

+ A set of beautifully designed components that you can customize, extend, and build on. Start here then make it your own. Open Source. Open Code. +

+
+
+ + +
+
+
+
+ + Accessible. Customizable. Open Source. +
+ +
+ + MIT Licensed +
+
+
+ +
+
+ ); +} + +function HeroPreview() { + const [activeExample, setActiveExample] = useState(exampleTabs[0].value); + const [theme, setTheme] = useState('dark'); + + const themeLabel = useMemo(() => (theme === 'dark' ? 'Dark' : 'Light'), [theme]); + const activeLabel = useMemo(() => { + return exampleTabs.find((tab) => tab.value === activeExample)?.label ?? exampleTabs[0].label; + }, [activeExample]); + + return ( + +
+ +
+
+ + Examples + +
+ Theme: + +
+
+
+ + +
+
+
+
+ + + {exampleTabs.map((tab) => ( + + {tab.label} + + ))} + + +
+
+ + +
+
+
+ + ); +} + +function PaymentExample({ exampleLabel }) { + return ( + + +
+ Example + + {exampleLabel} +
+ Payment Method + All transactions are secure and encrypted +
+ +
+ + +
+
+
+ + +

Enter your 16-digit number.

+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+ + +

+ The billing address associated with your payment method +

+
+
+
+

Same as shipping address

+

Keep shipping and billing in sync

+
+ +
+
+ +