Move shadcn directories to client shared folder + update shadcn docs a bit (#551)

This commit is contained in:
Franjo Mindek
2025-11-14 16:03:59 +01:00
committed by GitHub
parent f0b4d61797
commit adb8bb62e6
65 changed files with 146 additions and 139 deletions

View File

@@ -1,6 +1,6 @@
--- template/app/README.md --- template/app/README.md
+++ opensaas-sh/app/README.md +++ opensaas-sh/app/README.md
@@ -1,6 +1,8 @@ @@ -1,12 +1,27 @@
-# <YOUR_APP_NAME> -# <YOUR_APP_NAME>
+# opensaas.sh (demo) app +# opensaas.sh (demo) app
@@ -9,10 +9,6 @@
+ +
+It is deployed to https://opensaas.sh and serves both as a landing page for Open Saas and as a demo app. +It is deployed to https://opensaas.sh and serves both as a landing page for Open Saas and as a demo app.
## UI Components
@@ -8,9 +10,22 @@
## Development ## Development
+### .env files +### .env files

View File

@@ -4,13 +4,13 @@
import { Link as ReactRouterLink } from "react-router-dom"; import { Link as ReactRouterLink } from "react-router-dom";
import { useAuth } from "wasp/client/auth"; import { useAuth } from "wasp/client/auth";
import { Link as WaspRouterLink, routes } from "wasp/client/router"; import { Link as WaspRouterLink, routes } from "wasp/client/router";
+import { Button } from "../../../components/ui/button"; +import { Button } from "../../../client/components/ui/button";
import { import {
Sheet, Sheet,
SheetContent, SheetContent,
@@ -17,6 +18,7 @@ @@ -17,6 +18,7 @@
import { useIsLandingPage } from "../../hooks/useIsLandingPage";
import logo from "../../static/logo.webp"; import logo from "../../static/logo.webp";
import { cn } from "../../utils";
import DarkModeSwitcher from "../DarkModeSwitcher"; import DarkModeSwitcher from "../DarkModeSwitcher";
+import RepoInfo from "../RepoInfo"; +import RepoInfo from "../RepoInfo";
import { Announcement } from "./Announcement"; import { Announcement } from "./Announcement";

View File

@@ -3,8 +3,8 @@
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
+import { useEffect, useState } from "react"; +import { useEffect, useState } from "react";
+import { FaGithub } from "react-icons/fa"; +import { FaGithub } from "react-icons/fa";
+import { Button } from "../../components/ui/button"; +import { Button } from "../../client/components/ui/button";
+import { formatNumber } from "../../lib/utils"; +import { formatNumber } from "../utils";
+ +
+const RepoInfo = () => { +const RepoInfo = () => {
+ const [repoInfo, setRepoInfo] = useState<null | any>(null); + const [repoInfo, setRepoInfo] = useState<null | any>(null);

View File

@@ -1,12 +1,6 @@
--- template/app/src/components/ui/button.tsx --- template/app/src/client/components/ui/button.tsx
+++ opensaas-sh/app/src/components/ui/button.tsx +++ opensaas-sh/app/src/client/components/ui/button.tsx
@@ -5,26 +5,31 @@ @@ -10,21 +10,26 @@
import { cn } from "../../lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: { variants: {
variant: { variant: {
default: default:

View File

@@ -1,5 +1,5 @@
--- template/app/src/components/ui/card.tsx --- template/app/src/client/components/ui/card.tsx
+++ opensaas-sh/app/src/components/ui/card.tsx +++ opensaas-sh/app/src/client/components/ui/card.tsx
@@ -12,7 +12,11 @@ @@ -12,7 +12,11 @@
accent: "bg-card-accent text-card-accent-foreground hover:scale-[1.02]", accent: "bg-card-accent text-card-accent-foreground hover:scale-[1.02]",
faded: "text-card-faded-foreground scale-95 opacity-50", faded: "text-card-faded-foreground scale-95 opacity-50",

View File

@@ -1,5 +1,5 @@
--- template/app/src/lib/utils.ts --- template/app/src/client/utils.ts
+++ opensaas-sh/app/src/lib/utils.ts +++ opensaas-sh/app/src/client/utils.ts
@@ -4,3 +4,12 @@ @@ -4,3 +4,12 @@
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));

View File

@@ -3,9 +3,9 @@
@@ -0,0 +1,163 @@ @@ -0,0 +1,163 @@
+import { useState } from "react"; +import { useState } from "react";
+import { FaDiscord, FaGithub, FaGoogle, FaSlack } from "react-icons/fa"; +import { FaDiscord, FaGithub, FaGoogle, FaSlack } from "react-icons/fa";
+import { Button } from "../../../components/ui/button"; +import { Button } from "../../../client/components/ui/button";
+import { Card, CardContent, CardHeader } from "../../../components/ui/card"; +import { Card, CardContent, CardHeader } from "../../../client/components/ui/card";
+import { Input } from "../../../components/ui/input"; +import { Input } from "../../../client/components/ui/input";
+import { DocsUrl } from "../../../shared/common"; +import { DocsUrl } from "../../../shared/common";
+import HighlightedFeature from "../HighlightedFeature"; +import HighlightedFeature from "../HighlightedFeature";
+ +

View File

@@ -5,7 +5,7 @@
+import { Link as ReactRouterLink } from "react-router-dom"; +import { Link as ReactRouterLink } from "react-router-dom";
+import { useAuth } from "wasp/client/auth"; +import { useAuth } from "wasp/client/auth";
+import { Link as WaspRouterLink, routes } from "wasp/client/router"; +import { Link as WaspRouterLink, routes } from "wasp/client/router";
+import { Button } from "../../../components/ui/button"; +import { Button } from "../../../client/components/ui/button";
+import { DocsUrl, WaspUrl } from "../../../shared/common"; +import { DocsUrl, WaspUrl } from "../../../shared/common";
+import Orbit from "./Orbit"; +import Orbit from "./Orbit";
+ +

View File

@@ -9,7 +9,7 @@
+import stripeLogo from "../../../client/static/logos/stripe-light.webp"; +import stripeLogo from "../../../client/static/logos/stripe-light.webp";
+import tailwindLogoDark from "../../../client/static/logos/tailwind-dark.webp"; +import tailwindLogoDark from "../../../client/static/logos/tailwind-dark.webp";
+import tailwindLogo from "../../../client/static/logos/tailwind-light.webp"; +import tailwindLogo from "../../../client/static/logos/tailwind-light.webp";
+import { cn } from "../../../lib/utils"; +import { cn } from "../../../client/utils";
+import AstroLogo from "../../logos/AstroLogo"; +import AstroLogo from "../../logos/AstroLogo";
+import OpenAILogo from "../../logos/OpenAILogo"; +import OpenAILogo from "../../logos/OpenAILogo";
+import PrismaLogo from "../../logos/PrismaLogo"; +import PrismaLogo from "../../logos/PrismaLogo";

View File

@@ -1,6 +1,6 @@
--- template/app/src/payment/paymentProcessor.ts --- template/app/src/payment/paymentProcessor.ts
+++ opensaas-sh/app/src/payment/paymentProcessor.ts +++ opensaas-sh/app/src/payment/paymentProcessor.ts
@@ -28,9 +28,4 @@ @@ -29,9 +29,4 @@
webhookMiddlewareConfigFn: MiddlewareConfigFn; webhookMiddlewareConfigFn: MiddlewareConfigFn;
} }

View File

@@ -1,6 +1,6 @@
--- template/app/src/payment/stripe/user.ts --- template/app/src/payment/stripe/user.ts
+++ opensaas-sh/app/src/payment/stripe/user.ts +++ opensaas-sh/app/src/payment/stripe/user.ts
@@ -3,7 +3,7 @@ @@ -4,7 +4,7 @@
import type { SubscriptionStatus } from "../plans"; import type { SubscriptionStatus } from "../plans";
import { PaymentPlanId } from "../plans"; import { PaymentPlanId } from "../plans";
@@ -9,7 +9,7 @@
userId: User["id"], userId: User["id"],
prismaUserDelegate: PrismaClient["user"], prismaUserDelegate: PrismaClient["user"],
): Promise<string | null> { ): Promise<string | null> {
@@ -12,20 +12,20 @@ @@ -13,20 +13,20 @@
id: userId, id: userId,
}, },
select: { select: {
@@ -36,7 +36,7 @@
prismaUserDelegate: PrismaClient["user"], prismaUserDelegate: PrismaClient["user"],
): Promise<User> { ): Promise<User> {
return prismaUserDelegate.update({ return prismaUserDelegate.update({
@@ -33,7 +33,7 @@ @@ -34,7 +34,7 @@
id: userId, id: userId,
}, },
data: { data: {
@@ -45,7 +45,7 @@
}, },
}); });
} }
@@ -54,7 +54,7 @@ @@ -55,7 +55,7 @@
): Promise<User> { ): Promise<User> {
return userDelegate.update({ return userDelegate.update({
where: { where: {
@@ -54,7 +54,7 @@
}, },
data: { data: {
datePaid, datePaid,
@@ -81,7 +81,7 @@ @@ -82,7 +82,7 @@
): Promise<User> { ): Promise<User> {
return userDelegate.update({ return userDelegate.update({
where: { where: {

View File

@@ -2,40 +2,45 @@
description: Describes where the ui components built on top with Shadcn UI exist, how they are customized, and Wasp specific rules concerning how new ShadCN UI components should be installed description: Describes where the ui components built on top with Shadcn UI exist, how they are customized, and Wasp specific rules concerning how new ShadCN UI components should be installed
alwaysApply: false alwaysApply: false
--- ---
Only ShadCN UI version 2.3.0 should be used with Wasp at the moment. Due to dependency conflicts Wasp cannot be used with Tailwindcss v4, which the newer version of Shadcn depends on. Due to dependency conflicts Wasp cannot be used with Tailwindcss v4.
Shadcn has already been setup with this project template, so there is no need to install it. All the ShadCN specific components exist in [src/components/ui](../../src/components/ui/) ShadCN has already been setup with this project template, so there is no need to install it. All the ShadCN specific components exist in [src/client/components/ui](../../src/client/components/ui/)
## Adding a new ShadCN component ## Adding a new ShadCN component
We will use button as an example.
Same rules apply to any ShadCN component.
### 1. Add a new component ### 1. Add a new component
```bash ```bash
npx shadcn@2.3.0 add button npx shadcn@latest add button
``` ```
### 2. Adjust the `utils` import in `button.tsx` (for each component you add) This will generate a button component in `src/client/components/ui/button.tsx`.
### 2. Adjust the `utils` import in `button.tsx`
There will be a brand new `button.tsx` file in `src/components/ui`. We need to fix some import issues:
```diff ```diff
import * as React from "react" import * as React from "react"
import { Slot } from "@radix-ui/react-slot" import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority"
-import { cn } from "s/lib/utils" -import { cn } from "src/lib/utils"
+import { cn } from "../../lib/utils" +import { cn } from "../../utils"
``` ```
### 3. Use the `Button` component ### 3. Use the `Button` React component
Now you are ready to use the `Button` component. That's it!
```jsx
import './Main.css'
Now you are ready to use the `Button` component. That's it!
```tsx
import { Button } from './components/ui/button' import { Button } from './components/ui/button'
export const MainPage = () => { function SomePage() {
return ( return (
<div className="container"> <div>
<Button>This works</Button> <Button>This works</Button>
</div> </div>
) )
} }
```

View File

@@ -2,10 +2,6 @@
Built with [Wasp](https://wasp.sh), based on the [Open Saas](https://opensaas.sh) template. Built with [Wasp](https://wasp.sh), based on the [Open Saas](https://opensaas.sh) template.
## UI Components
This template includes [ShadCN UI](https://ui.shadcn.com/) v2 for beautiful, accessible React components. See [SHADCN_SETUP.md](./SHADCN_SETUP.md) for details on how to use ShadCN components in your app.
## Development ## Development
### Running locally ### Running locally

View File

@@ -11,11 +11,11 @@
"prefix": "" "prefix": ""
}, },
"aliases": { "aliases": {
"components": "src/components", "lib": "src/client",
"utils": "src/lib/utils", "components": "src/client/components",
"ui": "src/components/ui", "ui": "src/client/components/ui",
"lib": "src/lib", "utils": "src/client/utils",
"hooks": "src/hooks" "hooks": "src/client/hooks"
}, },
"iconLibrary": "lucide" "iconLibrary": "lucide"
} }

View File

@@ -1,6 +1,6 @@
import { type AuthUser } from "wasp/auth"; import { type AuthUser } from "wasp/auth";
import { getDailyStats, useQuery } from "wasp/client/operations"; import { getDailyStats, useQuery } from "wasp/client/operations";
import { cn } from "../../../lib/utils"; import { cn } from "../../../client/utils";
import DefaultLayout from "../../layout/DefaultLayout"; import DefaultLayout from "../../layout/DefaultLayout";
import RevenueAndProfitChart from "./RevenueAndProfitChart"; import RevenueAndProfitChart from "./RevenueAndProfitChart";
import SourcesTable from "./SourcesTable"; import SourcesTable from "./SourcesTable";

View File

@@ -1,6 +1,10 @@
import { ArrowDown, ArrowUp, Eye } from "lucide-react"; import { ArrowDown, ArrowUp, Eye } from "lucide-react";
import { Card, CardContent, CardHeader } from "../../../components/ui/card"; import {
import { cn } from "../../../lib/utils"; Card,
CardContent,
CardHeader,
} from "../../../client/components/ui/card";
import { cn } from "../../../client/utils";
type PageViewsStats = { type PageViewsStats = {
totalPageViews: number | undefined; totalPageViews: number | undefined;

View File

@@ -1,8 +1,12 @@
import { ArrowDown, ArrowUp, ShoppingBag } from "lucide-react"; import { ArrowDown, ArrowUp, ShoppingBag } from "lucide-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { type DailyStatsProps } from "../../../analytics/stats"; import { type DailyStatsProps } from "../../../analytics/stats";
import { Card, CardContent, CardHeader } from "../../../components/ui/card"; import {
import { cn } from "../../../lib/utils"; Card,
CardContent,
CardHeader,
} from "../../../client/components/ui/card";
import { cn } from "../../../client/utils";
const TotalPayingUsersCard = ({ dailyStats, isLoading }: DailyStatsProps) => { const TotalPayingUsersCard = ({ dailyStats, isLoading }: DailyStatsProps) => {
const isDeltaPositive = useMemo(() => { const isDeltaPositive = useMemo(() => {

View File

@@ -1,8 +1,12 @@
import { ArrowDown, ArrowUp, ShoppingCart } from "lucide-react"; import { ArrowDown, ArrowUp, ShoppingCart } from "lucide-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { type DailyStatsProps } from "../../../analytics/stats"; import { type DailyStatsProps } from "../../../analytics/stats";
import { Card, CardContent, CardHeader } from "../../../components/ui/card"; import {
import { cn } from "../../../lib/utils"; Card,
CardContent,
CardHeader,
} from "../../../client/components/ui/card";
import { cn } from "../../../client/utils";
const TotalRevenueCard = ({ const TotalRevenueCard = ({
dailyStats, dailyStats,

View File

@@ -1,8 +1,12 @@
import { ArrowUp, UsersRound } from "lucide-react"; import { ArrowUp, UsersRound } from "lucide-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { type DailyStatsProps } from "../../../analytics/stats"; import { type DailyStatsProps } from "../../../analytics/stats";
import { Card, CardContent, CardHeader } from "../../../components/ui/card"; import {
import { cn } from "../../../lib/utils"; Card,
CardContent,
CardHeader,
} from "../../../client/components/ui/card";
import { cn } from "../../../client/utils";
const TotalSignupsCard = ({ dailyStats, isLoading }: DailyStatsProps) => { const TotalSignupsCard = ({ dailyStats, isLoading }: DailyStatsProps) => {
const isDeltaPositive = useMemo(() => { const isDeltaPositive = useMemo(() => {

View File

@@ -4,7 +4,7 @@ import {
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "../../../components/ui/dropdown-menu"; } from "../../../client/components/ui/dropdown-menu";
const DropdownEditDelete = () => { const DropdownEditDelete = () => {
return ( return (

View File

@@ -7,19 +7,19 @@ import {
useQuery, useQuery,
} from "wasp/client/operations"; } from "wasp/client/operations";
import { type User } from "wasp/entities"; import { type User } from "wasp/entities";
import useDebounce from "../../../client/hooks/useDebounce"; import { Button } from "../../../client/components/ui/button";
import { Button } from "../../../components/ui/button"; import { Checkbox } from "../../../client/components/ui/checkbox";
import { Checkbox } from "../../../components/ui/checkbox"; import { Input } from "../../../client/components/ui/input";
import { Input } from "../../../components/ui/input"; import { Label } from "../../../client/components/ui/label";
import { Label } from "../../../components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "../../../components/ui/select"; } from "../../../client/components/ui/select";
import { Switch } from "../../../components/ui/switch"; import { Switch } from "../../../client/components/ui/switch";
import useDebounce from "../../../client/hooks/useDebounce";
import { SubscriptionStatus } from "../../../payment/plans"; import { SubscriptionStatus } from "../../../payment/plans";
import LoadingSpinner from "../../layout/LoadingSpinner"; import LoadingSpinner from "../../layout/LoadingSpinner";
import DropdownEditDelete from "./DropdownEditDelete"; import DropdownEditDelete from "./DropdownEditDelete";

View File

@@ -1,16 +1,16 @@
import { FileText, Mail, Upload, User } from "lucide-react"; import { FileText, Mail, Upload, User } from "lucide-react";
import { FormEvent } from "react"; import { FormEvent } from "react";
import { type AuthUser } from "wasp/auth"; import { type AuthUser } from "wasp/auth";
import { Button } from "../../../components/ui/button"; import { Button } from "../../../client/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../../../components/ui/card"; } from "../../../client/components/ui/card";
import { Input } from "../../../components/ui/input"; import { Input } from "../../../client/components/ui/input";
import { Label } from "../../../components/ui/label"; import { Label } from "../../../client/components/ui/label";
import { Textarea } from "../../../components/ui/textarea"; import { Textarea } from "../../../client/components/ui/textarea";
import Breadcrumb from "../../layout/Breadcrumb"; import Breadcrumb from "../../layout/Breadcrumb";
import DefaultLayout from "../../layout/DefaultLayout"; import DefaultLayout from "../../layout/DefaultLayout";

View File

@@ -1,6 +1,6 @@
import { Heart, Plus, Trash2 } from "lucide-react"; import { Heart, Plus, Trash2 } from "lucide-react";
import { type AuthUser } from "wasp/auth"; import { type AuthUser } from "wasp/auth";
import { Button } from "../../../components/ui/button"; import { Button } from "../../../client/components/ui/button";
import Breadcrumb from "../../layout/Breadcrumb"; import Breadcrumb from "../../layout/Breadcrumb";
import DefaultLayout from "../../layout/DefaultLayout"; import DefaultLayout from "../../layout/DefaultLayout";

View File

@@ -1,6 +1,6 @@
import { type AuthUser } from "wasp/auth"; import { type AuthUser } from "wasp/auth";
import DarkModeSwitcher from "../../client/components/DarkModeSwitcher"; import DarkModeSwitcher from "../../client/components/DarkModeSwitcher";
import { cn } from "../../lib/utils"; import { cn } from "../../client/utils";
import { UserDropdown } from "../../user/UserDropdown"; import { UserDropdown } from "../../user/UserDropdown";
import MessageButton from "../dashboards/messages/MessageButton"; import MessageButton from "../dashboards/messages/MessageButton";

View File

@@ -11,7 +11,7 @@ import {
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { NavLink, useLocation } from "react-router-dom"; import { NavLink, useLocation } from "react-router-dom";
import Logo from "../../client/static/logo.webp"; import Logo from "../../client/static/logo.webp";
import { cn } from "../../lib/utils"; import { cn } from "../../client/utils";
import SidebarLinkGroup from "./SidebarLinkGroup"; import SidebarLinkGroup from "./SidebarLinkGroup";
interface SidebarProps { interface SidebarProps {

View File

@@ -1,7 +1,7 @@
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { Outlet, useLocation } from "react-router-dom"; import { Outlet, useLocation } from "react-router-dom";
import { routes } from "wasp/client/router"; import { routes } from "wasp/client/router";
import { Toaster } from "../components/ui/toaster"; import { Toaster } from "../client/components/ui/toaster";
import "./Main.css"; import "./Main.css";
import NavBar from "./components/NavBar/NavBar"; import NavBar from "./components/NavBar/NavBar";
import { import {

View File

@@ -1,7 +1,7 @@
import { Moon, Sun } from "lucide-react"; import { Moon, Sun } from "lucide-react";
import { Label } from "../../components/ui/label"; import { Label } from "../../client/components/ui/label";
import { cn } from "../../lib/utils";
import useColorMode from "../hooks/useColorMode"; import useColorMode from "../hooks/useColorMode";
import { cn } from "../utils";
const DarkModeSwitcher = () => { const DarkModeSwitcher = () => {
const [colorMode, setColorMode] = useColorMode(); const [colorMode, setColorMode] = useColorMode();

View File

@@ -9,13 +9,13 @@ import {
SheetHeader, SheetHeader,
SheetTitle, SheetTitle,
SheetTrigger, SheetTrigger,
} from "../../../components/ui/sheet"; } from "../../../client/components/ui/sheet";
import { cn } from "../../../lib/utils";
import { throttleWithTrailingInvocation } from "../../../shared/utils"; import { throttleWithTrailingInvocation } from "../../../shared/utils";
import { UserDropdown } from "../../../user/UserDropdown"; import { UserDropdown } from "../../../user/UserDropdown";
import { UserMenuItems } from "../../../user/UserMenuItems"; import { UserMenuItems } from "../../../user/UserMenuItems";
import { useIsLandingPage } from "../../hooks/useIsLandingPage"; import { useIsLandingPage } from "../../hooks/useIsLandingPage";
import logo from "../../static/logo.webp"; import logo from "../../static/logo.webp";
import { cn } from "../../utils";
import DarkModeSwitcher from "../DarkModeSwitcher"; import DarkModeSwitcher from "../DarkModeSwitcher";
import { Announcement } from "./Announcement"; import { Announcement } from "./Announcement";

View File

@@ -2,7 +2,7 @@ import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react"; import { ChevronDown } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Accordion = AccordionPrimitive.Root; const Accordion = AccordionPrimitive.Root;

View File

@@ -1,7 +1,7 @@
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const alertVariants = cva( const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",

View File

@@ -1,7 +1,7 @@
import * as AvatarPrimitive from "@radix-ui/react-avatar"; import * as AvatarPrimitive from "@radix-ui/react-avatar";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Avatar = React.forwardRef< const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>, React.ElementRef<typeof AvatarPrimitive.Root>,

View File

@@ -2,10 +2,10 @@ import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{ {
variants: { variants: {
variant: { variant: {

View File

@@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import { cva, VariantProps } from "class-variance-authority"; import { cva, VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const cardVariants = cva( const cardVariants = cva(
"rounded-xl border shadow hover:shadow-lg transition-all duration-300 xur", "rounded-xl border shadow hover:shadow-lg transition-all duration-300 xur",

View File

@@ -2,7 +2,7 @@ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react"; import { Check } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Checkbox = React.forwardRef< const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>, React.ElementRef<typeof CheckboxPrimitive.Root>,

View File

@@ -2,7 +2,7 @@ import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Dialog = DialogPrimitive.Root; const Dialog = DialogPrimitive.Root;

View File

@@ -2,7 +2,7 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Check, ChevronRight, Circle } from "lucide-react"; import { Check, ChevronRight, Circle } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const DropdownMenu = DropdownMenuPrimitive.Root; const DropdownMenu = DropdownMenuPrimitive.Root;

View File

@@ -10,7 +10,7 @@ import {
type FieldValues, type FieldValues,
} from "react-hook-form"; } from "react-hook-form";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
import { Label } from "./label"; import { Label } from "./label";
const Form = FormProvider; const Form = FormProvider;

View File

@@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>( const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
({ className, type, ...props }, ref) => { ({ className, type, ...props }, ref) => {

View File

@@ -4,7 +4,7 @@ import * as LabelPrimitive from "@radix-ui/react-label";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const labelVariants = cva( const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",

View File

@@ -1,7 +1,7 @@
import * as ProgressPrimitive from "@radix-ui/react-progress"; import * as ProgressPrimitive from "@radix-ui/react-progress";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Progress = React.forwardRef< const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>, React.ElementRef<typeof ProgressPrimitive.Root>,

View File

@@ -2,7 +2,7 @@ import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown, ChevronUp } from "lucide-react"; import { Check, ChevronDown, ChevronUp } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Select = SelectPrimitive.Root; const Select = SelectPrimitive.Root;

View File

@@ -1,7 +1,7 @@
import * as SeparatorPrimitive from "@radix-ui/react-separator"; import * as SeparatorPrimitive from "@radix-ui/react-separator";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Separator = React.forwardRef< const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>, React.ElementRef<typeof SeparatorPrimitive.Root>,

View File

@@ -3,7 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Sheet = SheetPrimitive.Root; const Sheet = SheetPrimitive.Root;

View File

@@ -1,7 +1,7 @@
import * as SwitchPrimitives from "@radix-ui/react-switch"; import * as SwitchPrimitives from "@radix-ui/react-switch";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Switch = React.forwardRef< const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>, React.ElementRef<typeof SwitchPrimitives.Root>,

View File

@@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const Textarea = React.forwardRef< const Textarea = React.forwardRef<
HTMLTextAreaElement, HTMLTextAreaElement,

View File

@@ -3,7 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../utils";
const ToastProvider = ToastPrimitives.Provider; const ToastProvider = ToastPrimitives.Provider;

View File

@@ -12,19 +12,19 @@ import { Link, routes } from "wasp/client/router";
import { ArrowRight, Loader2, Trash2 } from "lucide-react"; import { ArrowRight, Loader2, Trash2 } from "lucide-react";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { Button } from "../components/ui/button"; import { Button } from "../client/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../components/ui/card"; } from "../client/components/ui/card";
import { Checkbox } from "../components/ui/checkbox"; import { Checkbox } from "../client/components/ui/checkbox";
import { Input } from "../components/ui/input"; import { Input } from "../client/components/ui/input";
import { Label } from "../components/ui/label"; import { Label } from "../client/components/ui/label";
import { ToastAction } from "../components/ui/toast"; import { ToastAction } from "../client/components/ui/toast";
import { toast } from "../hooks/use-toast"; import { toast } from "../client/hooks/use-toast";
import { cn } from "../lib/utils"; import { cn } from "../client/utils";
import type { import type {
GeneratedSchedule, GeneratedSchedule,
Task as ScheduleTask, Task as ScheduleTask,

View File

@@ -10,9 +10,9 @@ import {
import type { File } from "wasp/entities"; import type { File } from "wasp/entities";
import { Download, Trash } from "lucide-react"; import { Download, Trash } from "lucide-react";
import { Alert, AlertDescription } from "../components/ui/alert"; import { Alert, AlertDescription } from "../client/components/ui/alert";
import { Button } from "../components/ui/button"; import { Button } from "../client/components/ui/button";
import { Card, CardContent, CardTitle } from "../components/ui/card"; import { Card, CardContent, CardTitle } from "../client/components/ui/card";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@@ -20,12 +20,12 @@ import {
DialogFooter, DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "../components/ui/dialog"; } from "../client/components/ui/dialog";
import { Input } from "../components/ui/input"; import { Input } from "../client/components/ui/input";
import { Label } from "../components/ui/label"; import { Label } from "../client/components/ui/label";
import { Progress } from "../components/ui/progress"; import { Progress } from "../client/components/ui/progress";
import { toast } from "../hooks/use-toast"; import { toast } from "../client/hooks/use-toast";
import { cn } from "../lib/utils"; import { cn } from "../client/utils";
import { uploadFileWithProgress, validateFile } from "./fileUploading"; import { uploadFileWithProgress, validateFile } from "./fileUploading";
import { ALLOWED_FILE_TYPES } from "./validation"; import { ALLOWED_FILE_TYPES } from "./validation";

View File

@@ -1,5 +1,5 @@
import { forwardRef, useEffect, useRef, useState } from "react"; import { forwardRef, useEffect, useRef, useState } from "react";
import { Card, CardContent } from "../../components/ui/card"; import { Card, CardContent } from "../../client/components/ui/card";
const EXAMPLES_CAROUSEL_INTERVAL = 3000; const EXAMPLES_CAROUSEL_INTERVAL = 3000;
const EXAMPLES_CAROUSEL_SCROLL_TIMEOUT = 200; const EXAMPLES_CAROUSEL_SCROLL_TIMEOUT = 200;

View File

@@ -3,7 +3,7 @@ import {
AccordionContent, AccordionContent,
AccordionItem, AccordionItem,
AccordionTrigger, AccordionTrigger,
} from "../../components/ui/accordion"; } from "../../client/components/ui/accordion";
interface FAQ { interface FAQ {
id: number; id: number;

View File

@@ -4,8 +4,8 @@ import {
CardContent, CardContent,
CardDescription, CardDescription,
CardTitle, CardTitle,
} from "../../components/ui/card"; } from "../../client/components/ui/card";
import { cn } from "../../lib/utils"; import { cn } from "../../client/utils";
import { Feature } from "./Features"; import { Feature } from "./Features";
import SectionTitle from "./SectionTitle"; import SectionTitle from "./SectionTitle";

View File

@@ -1,7 +1,7 @@
import { Link as WaspRouterLink, routes } from "wasp/client/router"; import { Link as WaspRouterLink, routes } from "wasp/client/router";
import { Button } from "../../client/components/ui/button";
import openSaasBannerDark from "../../client/static/open-saas-banner-dark.svg"; import openSaasBannerDark from "../../client/static/open-saas-banner-dark.svg";
import openSaasBannerLight from "../../client/static/open-saas-banner-light.svg"; import openSaasBannerLight from "../../client/static/open-saas-banner-light.svg";
import { Button } from "../../components/ui/button";
export default function Hero() { export default function Hero() {
return ( return (

View File

@@ -1,4 +1,4 @@
import { cn } from "../../lib/utils"; import { cn } from "../../client/utils";
interface FeatureProps { interface FeatureProps {
name: string; name: string;

View File

@@ -5,7 +5,7 @@ import {
CardDescription, CardDescription,
CardFooter, CardFooter,
CardTitle, CardTitle,
} from "../../components/ui/card"; } from "../../client/components/ui/card";
import SectionTitle from "./SectionTitle"; import SectionTitle from "./SectionTitle";
interface Testimonial { interface Testimonial {

View File

@@ -7,15 +7,15 @@ import {
getCustomerPortalUrl, getCustomerPortalUrl,
useQuery, useQuery,
} from "wasp/client/operations"; } from "wasp/client/operations";
import { Alert, AlertDescription } from "../components/ui/alert"; import { Alert, AlertDescription } from "../client/components/ui/alert";
import { Button } from "../components/ui/button"; import { Button } from "../client/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardFooter, CardFooter,
CardTitle, CardTitle,
} from "../components/ui/card"; } from "../client/components/ui/card";
import { cn } from "../lib/utils"; import { cn } from "../client/utils";
import { import {
PaymentPlanId, PaymentPlanId,
paymentPlans, paymentPlans,

View File

@@ -1,14 +1,14 @@
import { getCustomerPortalUrl, useQuery } from "wasp/client/operations"; import { getCustomerPortalUrl, useQuery } from "wasp/client/operations";
import { Link as WaspRouterLink, routes } from "wasp/client/router"; import { Link as WaspRouterLink, routes } from "wasp/client/router";
import type { User } from "wasp/entities"; import type { User } from "wasp/entities";
import { Button } from "../components/ui/button"; import { Button } from "../client/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../components/ui/card"; } from "../client/components/ui/card";
import { Separator } from "../components/ui/separator"; import { Separator } from "../client/components/ui/separator";
import { import {
PaymentPlanId, PaymentPlanId,
SubscriptionStatus, SubscriptionStatus,

View File

@@ -8,7 +8,7 @@ import {
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "../components/ui/dropdown-menu"; } from "../client/components/ui/dropdown-menu";
import { userMenuItems } from "./constants"; import { userMenuItems } from "./constants";
export function UserDropdown({ user }: { user: Partial<UserEntity> }) { export function UserDropdown({ user }: { user: Partial<UserEntity> }) {