blodemd 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +11 -47
  2. package/dev-server/app/layout.tsx +1 -1
  3. package/dist/cli.mjs +708 -120
  4. package/dist/cli.mjs.map +1 -1
  5. package/docs/app/globals.css +15 -1
  6. package/docs/components/api/api-playground.tsx +2 -2
  7. package/docs/components/docs/copy-page-menu.tsx +55 -27
  8. package/docs/components/docs/doc-header.tsx +1 -1
  9. package/docs/components/docs/doc-shell.tsx +89 -88
  10. package/docs/components/docs/doc-sidebar.tsx +6 -3
  11. package/docs/components/docs/doc-toc.tsx +1 -1
  12. package/docs/components/docs/mobile-nav.tsx +8 -16
  13. package/docs/components/docs/sidebar-scroll-area.tsx +58 -0
  14. package/docs/components/git/repo-picker.tsx +526 -0
  15. package/docs/components/mdx/agent-instructions.tsx +17 -0
  16. package/docs/components/mdx/code-block.tsx +6 -1
  17. package/docs/components/mdx/code-group.tsx +1 -1
  18. package/docs/components/mdx/iframe.tsx +62 -0
  19. package/docs/components/mdx/index.tsx +4 -0
  20. package/docs/components/mdx/tabs.tsx +5 -5
  21. package/docs/components/mdx/video.tsx +45 -12
  22. package/docs/components/third-parties.tsx +29 -0
  23. package/docs/components/ui/badge.tsx +61 -0
  24. package/docs/components/ui/breadcrumb.tsx +61 -41
  25. package/docs/components/ui/button-group.tsx +83 -0
  26. package/docs/components/ui/button.tsx +30 -55
  27. package/docs/components/ui/command.tsx +32 -4
  28. package/docs/components/ui/copy-button.tsx +12 -19
  29. package/docs/components/ui/dialog.tsx +50 -1
  30. package/docs/components/ui/input.tsx +16 -97
  31. package/docs/components/ui/kbd.tsx +98 -0
  32. package/docs/components/ui/morph-icon.tsx +79 -0
  33. package/docs/components/ui/popover.tsx +225 -30
  34. package/docs/components/ui/search.tsx +0 -9
  35. package/docs/components/ui/sheet.tsx +30 -1
  36. package/docs/components/ui/sidebar.tsx +332 -7
  37. package/docs/components/ui/site-footer.tsx +6 -4
  38. package/docs/components/ui/skeleton.tsx +11 -0
  39. package/docs/components/ui/switch.tsx +32 -0
  40. package/docs/components/ui/tabs.tsx +138 -0
  41. package/docs/lib/api-client.ts +72 -0
  42. package/docs/lib/contextual-options.ts +9 -0
  43. package/docs/lib/dashboard-session.ts +167 -0
  44. package/docs/lib/db.ts +13 -0
  45. package/docs/lib/env.ts +4 -3
  46. package/docs/lib/etag.ts +22 -0
  47. package/docs/lib/github-install.ts +33 -0
  48. package/docs/lib/project-authz.ts +46 -0
  49. package/docs/lib/routes.ts +5 -1
  50. package/docs/lib/supabase.ts +30 -6
  51. package/docs/lib/tenancy.ts +1 -0
  52. package/docs/lib/tenant-static.ts +206 -4
  53. package/docs/lib/tenants.ts +5 -1
  54. package/docs/lib/time-ago.ts +24 -0
  55. package/docs/lib/use-tab-observer.ts +71 -0
  56. package/package.json +1 -1
  57. package/packages/@repo/contracts/dist/git.d.ts +28 -0
  58. package/packages/@repo/contracts/dist/git.d.ts.map +1 -0
  59. package/packages/@repo/contracts/dist/git.js +24 -0
  60. package/packages/@repo/contracts/dist/index.d.ts +1 -1
  61. package/packages/@repo/contracts/dist/index.d.ts.map +1 -1
  62. package/packages/@repo/contracts/dist/index.js +1 -1
  63. package/packages/@repo/contracts/src/git.ts +31 -0
  64. package/packages/@repo/contracts/src/index.ts +1 -1
  65. package/packages/@repo/models/dist/docs-config.d.ts +6 -0
  66. package/packages/@repo/models/dist/docs-config.d.ts.map +1 -1
  67. package/packages/@repo/models/dist/docs-config.js +1 -0
  68. package/packages/@repo/models/src/docs-config.ts +1 -0
  69. package/packages/@repo/previewing/dist/index.d.ts +3 -0
  70. package/packages/@repo/previewing/dist/index.d.ts.map +1 -1
  71. package/packages/@repo/previewing/dist/index.js +48 -0
  72. package/packages/@repo/previewing/src/index.ts +56 -0
  73. package/packages/@repo/validation/src/blodemd-docs-schema.json +1 -0
  74. package/scripts/prepare-package.mjs +14 -0
  75. package/packages/@repo/contracts/dist/api-key.d.ts +0 -30
  76. package/packages/@repo/contracts/dist/api-key.d.ts.map +0 -1
  77. package/packages/@repo/contracts/dist/api-key.js +0 -20
  78. package/packages/@repo/contracts/src/api-key.ts +0 -27
@@ -1,12 +1,45 @@
1
- export const Video = ({ src }: { src: string }) => (
2
- <div className="relative overflow-hidden rounded-xl border border-border bg-black pt-[56.25%]">
3
- <iframe
4
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
5
- allowFullScreen
6
- className="absolute inset-0 h-full w-full border-0"
7
- sandbox="allow-popups allow-presentation allow-scripts"
8
- src={src}
9
- title="Video"
10
- />
11
- </div>
12
- );
1
+ import { cn } from "@/lib/utils";
2
+
3
+ type AspectRatio = "16:9" | "4:3" | "1:1" | "21:9";
4
+
5
+ const aspectRatioMap: Record<AspectRatio, string> = {
6
+ "16:9": "pt-[56.25%]",
7
+ "1:1": "pt-[100%]",
8
+ "21:9": "pt-[42.86%]",
9
+ "4:3": "pt-[75%]",
10
+ };
11
+
12
+ interface VideoProps {
13
+ src: string;
14
+ title?: string;
15
+ height?: number;
16
+ aspectRatio?: AspectRatio;
17
+ }
18
+
19
+ export const Video = ({
20
+ src,
21
+ title = "Video",
22
+ height,
23
+ aspectRatio = "16:9",
24
+ }: VideoProps) => {
25
+ const useFixedHeight = typeof height === "number";
26
+
27
+ return (
28
+ <div
29
+ className={cn(
30
+ "relative overflow-hidden rounded-xl border border-border bg-black",
31
+ !useFixedHeight && aspectRatioMap[aspectRatio]
32
+ )}
33
+ style={useFixedHeight ? { height: `${height}px` } : undefined}
34
+ >
35
+ <iframe
36
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
37
+ allowFullScreen
38
+ className="absolute inset-0 h-full w-full border-0"
39
+ sandbox="allow-popups allow-presentation allow-same-origin allow-scripts"
40
+ src={src}
41
+ title={title}
42
+ />
43
+ </div>
44
+ );
45
+ };
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ import { GoogleAnalytics } from "@next/third-parties/google";
4
+ import { SpeedInsights } from "@vercel/speed-insights/next";
5
+ import { usePathname } from "next/navigation";
6
+
7
+ const PRIVATE_PATH_PREFIXES = ["/app", "/oauth"];
8
+
9
+ const isPrivatePath = (pathname: string | null) => {
10
+ if (!pathname) {
11
+ return false;
12
+ }
13
+ return PRIVATE_PATH_PREFIXES.some(
14
+ (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`)
15
+ );
16
+ };
17
+
18
+ export const ThirdParties = () => {
19
+ const pathname = usePathname();
20
+ if (isPrivatePath(pathname)) {
21
+ return null;
22
+ }
23
+ return (
24
+ <>
25
+ <SpeedInsights />
26
+ <GoogleAnalytics gaId="G-WE1RCNSC4E" />
27
+ </>
28
+ );
29
+ };
@@ -0,0 +1,61 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva } from "class-variance-authority";
4
+ import type { VariantProps } from "class-variance-authority";
5
+ import type * as React from "react";
6
+
7
+ import { cn } from "@/lib/utils";
8
+
9
+ const badgeVariants = cva(
10
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded-full border border-transparent px-2 py-0.5 font-medium text-xs transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
11
+ {
12
+ defaultVariants: {
13
+ variant: "default",
14
+ },
15
+ variants: {
16
+ variant: {
17
+ default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
18
+ destructive:
19
+ "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",
20
+ ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
21
+ link: "text-primary underline-offset-4 [a&]:hover:underline",
22
+ outline:
23
+ "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
24
+ secondary:
25
+ "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
26
+ success:
27
+ "bg-green-50 text-green-700 dark:bg-green-950 dark:text-green-300 [a&]:hover:bg-green-50/80 dark:[a&]:hover:bg-green-950/80",
28
+ warning:
29
+ "bg-yellow-50 text-yellow-700 dark:bg-yellow-950 dark:text-yellow-300 [a&]:hover:bg-yellow-50/80 dark:[a&]:hover:bg-yellow-950/80",
30
+ },
31
+ },
32
+ }
33
+ );
34
+
35
+ type BadgeProps = React.ComponentProps<"span"> &
36
+ VariantProps<typeof badgeVariants> & { asChild?: boolean };
37
+
38
+ const Badge = ({
39
+ className,
40
+ variant = "default",
41
+ asChild = false,
42
+ children,
43
+ ...props
44
+ }: BadgeProps) =>
45
+ useRender({
46
+ defaultTagName: "span",
47
+ props: mergeProps<"span">(
48
+ {
49
+ className: cn(badgeVariants({ variant }), className),
50
+ },
51
+ asChild ? props : { ...props, children }
52
+ ),
53
+ render: asChild ? (children as React.ReactElement) : undefined,
54
+ state: {
55
+ slot: "badge",
56
+ variant,
57
+ },
58
+ });
59
+
60
+ export { Badge, badgeVariants };
61
+ export type { BadgeProps };
@@ -1,27 +1,35 @@
1
- import { Slot } from "radix-ui";
2
- import type { ComponentProps } from "react";
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { ChevronRight, MoreHorizontal } from "blode-icons-react";
4
+ import type * as React from "react";
3
5
 
4
6
  import { cn } from "@/lib/utils";
5
7
 
6
- const Breadcrumb = ({ ...props }: ComponentProps<"nav">) => (
8
+ const Breadcrumb = ({ ...props }: React.ComponentProps<"nav">) => (
7
9
  <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
8
10
  );
9
11
 
10
- const BreadcrumbList = ({ className, ...props }: ComponentProps<"ol">) => (
12
+ const BreadcrumbList = ({
13
+ className,
14
+ ...props
15
+ }: React.ComponentProps<"ol">) => (
11
16
  <ol
12
- data-slot="breadcrumb-list"
13
17
  className={cn(
14
- "flex flex-wrap items-center gap-1.5 text-sm text-muted-foreground break-words sm:gap-2.5",
18
+ "flex flex-wrap items-center gap-1.5 break-words text-muted-foreground text-sm sm:gap-2.5",
15
19
  className
16
20
  )}
21
+ data-slot="breadcrumb-list"
17
22
  {...props}
18
23
  />
19
24
  );
20
25
 
21
- const BreadcrumbItem = ({ className, ...props }: ComponentProps<"li">) => (
26
+ const BreadcrumbItem = ({
27
+ className,
28
+ ...props
29
+ }: React.ComponentProps<"li">) => (
22
30
  <li
23
- data-slot="breadcrumb-item"
24
31
  className={cn("inline-flex items-center gap-1.5", className)}
32
+ data-slot="breadcrumb-item"
25
33
  {...props}
26
34
  />
27
35
  );
@@ -29,25 +37,34 @@ const BreadcrumbItem = ({ className, ...props }: ComponentProps<"li">) => (
29
37
  const BreadcrumbLink = ({
30
38
  asChild,
31
39
  className,
40
+ children,
32
41
  ...props
33
- }: ComponentProps<"a"> & { asChild?: boolean }) => {
34
- const Comp = asChild ? Slot.Root : "a";
42
+ }: React.ComponentProps<"a"> & {
43
+ asChild?: boolean;
44
+ }) =>
45
+ useRender({
46
+ defaultTagName: "a",
47
+ props: mergeProps<"a">(
48
+ {
49
+ className: cn("transition-colors hover:text-foreground", className),
50
+ },
51
+ asChild ? props : { ...props, children }
52
+ ),
53
+ render: asChild ? (children as React.ReactElement) : undefined,
54
+ state: {
55
+ slot: "breadcrumb-link",
56
+ },
57
+ });
35
58
 
36
- return (
37
- <Comp
38
- data-slot="breadcrumb-link"
39
- className={cn("transition-colors hover:text-foreground", className)}
40
- {...props}
41
- />
42
- );
43
- };
44
-
45
- const BreadcrumbPage = ({ className, ...props }: ComponentProps<"span">) => (
59
+ const BreadcrumbPage = ({
60
+ className,
61
+ ...props
62
+ }: React.ComponentProps<"span">) => (
46
63
  <span
47
- data-slot="breadcrumb-page"
48
- aria-disabled="true"
49
64
  aria-current="page"
65
+ aria-disabled="true"
50
66
  className={cn("font-normal text-foreground", className)}
67
+ data-slot="breadcrumb-page"
51
68
  {...props}
52
69
  />
53
70
  );
@@ -56,37 +73,40 @@ const BreadcrumbSeparator = ({
56
73
  children,
57
74
  className,
58
75
  ...props
59
- }: ComponentProps<"li">) => (
76
+ }: React.ComponentProps<"li">) => (
60
77
  <li
61
- data-slot="breadcrumb-separator"
62
- role="presentation"
63
78
  aria-hidden="true"
64
79
  className={cn("[&>svg]:size-3.5", className)}
80
+ data-slot="breadcrumb-separator"
81
+ role="presentation"
65
82
  {...props}
66
83
  >
67
- {children ?? (
68
- <svg
69
- xmlns="http://www.w3.org/2000/svg"
70
- width="16"
71
- height="16"
72
- viewBox="0 0 24 24"
73
- fill="none"
74
- stroke="currentColor"
75
- strokeWidth="2"
76
- strokeLinecap="round"
77
- strokeLinejoin="round"
78
- >
79
- <path d="m9 18 6-6-6-6" />
80
- </svg>
81
- )}
84
+ {children ?? <ChevronRight />}
82
85
  </li>
83
86
  );
84
87
 
88
+ const BreadcrumbEllipsis = ({
89
+ className,
90
+ ...props
91
+ }: React.ComponentProps<"span">) => (
92
+ <span
93
+ aria-hidden="true"
94
+ className={cn("flex size-9 items-center justify-center", className)}
95
+ data-slot="breadcrumb-ellipsis"
96
+ role="presentation"
97
+ {...props}
98
+ >
99
+ <MoreHorizontal className="size-4" />
100
+ <span className="sr-only">More</span>
101
+ </span>
102
+ );
103
+
85
104
  export {
86
105
  Breadcrumb,
106
+ BreadcrumbList,
87
107
  BreadcrumbItem,
88
108
  BreadcrumbLink,
89
- BreadcrumbList,
90
109
  BreadcrumbPage,
91
110
  BreadcrumbSeparator,
111
+ BreadcrumbEllipsis,
92
112
  };
@@ -0,0 +1,83 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva } from "class-variance-authority";
4
+ import type { VariantProps } from "class-variance-authority";
5
+
6
+ import { Separator } from "@/components/ui/separator";
7
+ import { cn } from "@/lib/utils";
8
+
9
+ const buttonGroupVariants = cva(
10
+ "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
11
+ {
12
+ defaultVariants: {
13
+ orientation: "horizontal",
14
+ },
15
+ variants: {
16
+ orientation: {
17
+ horizontal:
18
+ "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
19
+ vertical:
20
+ "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0",
21
+ },
22
+ },
23
+ }
24
+ );
25
+
26
+ const ButtonGroup = ({
27
+ className,
28
+ orientation,
29
+ ...props
30
+ }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) => (
31
+ <div
32
+ className={cn(buttonGroupVariants({ orientation }), className)}
33
+ data-orientation={orientation}
34
+ data-slot="button-group"
35
+ role="group"
36
+ {...props}
37
+ />
38
+ );
39
+
40
+ const ButtonGroupText = ({
41
+ className,
42
+ render,
43
+ ...props
44
+ }: useRender.ComponentProps<"div">) =>
45
+ useRender({
46
+ defaultTagName: "div",
47
+ props: mergeProps<"div">(
48
+ {
49
+ className: cn(
50
+ "flex items-center gap-2 rounded-lg border bg-muted px-2.5 font-medium text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
51
+ className
52
+ ),
53
+ },
54
+ props
55
+ ),
56
+ render,
57
+ state: {
58
+ slot: "button-group-text",
59
+ },
60
+ });
61
+
62
+ const ButtonGroupSeparator = ({
63
+ className,
64
+ orientation = "vertical",
65
+ ...props
66
+ }: React.ComponentProps<typeof Separator>) => (
67
+ <Separator
68
+ className={cn(
69
+ "relative self-stretch bg-input data-horizontal:mx-px data-vertical:my-px data-vertical:h-auto data-horizontal:w-auto",
70
+ className
71
+ )}
72
+ data-slot="button-group-separator"
73
+ orientation={orientation}
74
+ {...props}
75
+ />
76
+ );
77
+
78
+ export {
79
+ ButtonGroup,
80
+ ButtonGroupSeparator,
81
+ ButtonGroupText,
82
+ buttonGroupVariants,
83
+ };
@@ -1,13 +1,12 @@
1
- import { mergeProps } from "@base-ui/react/merge-props";
2
- import { useRender } from "@base-ui/react/use-render";
3
1
  import { cva } from "class-variance-authority";
4
2
  import type { VariantProps } from "class-variance-authority";
5
- import type * as React from "react";
3
+ import { Slot } from "radix-ui";
4
+ import * as React from "react";
6
5
 
7
6
  import { cn } from "@/lib/utils";
8
7
 
9
8
  const buttonVariants = cva(
10
- "group/button inline-flex shrink-0 select-none items-center justify-center whitespace-nowrap rounded-lg border border-transparent bg-clip-padding font-medium text-sm outline-none transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-150 ease-out focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-45 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:opacity-45 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
9
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
11
10
  {
12
11
  defaultVariants: {
13
12
  size: "default",
@@ -15,46 +14,26 @@ const buttonVariants = cva(
15
14
  },
16
15
  variants: {
17
16
  size: {
18
- default:
19
- "h-10 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
20
- icon: "size-10",
21
- "icon-lg": "size-11",
22
- "icon-sm":
23
- "size-9 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),12px)]",
24
- "icon-xs":
25
- "size-8 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),10px)] [&_svg:not([class*='size-'])]:size-3",
26
- input:
27
- "h-[var(--field-height)] gap-2 rounded-[var(--field-radius)] px-[var(--field-padding-x)] py-[var(--field-padding-y)]",
28
- "input-sm":
29
- "h-[var(--field-height-sm)] gap-2 rounded-[var(--field-radius)] px-[var(--field-padding-x)] py-[var(--field-padding-y)]",
30
- lg: "h-11 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3.5 has-data-[icon=inline-start]:pl-3.5",
31
- sm: "h-9 gap-1 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),12px)] px-3 text-[0.8rem] has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3.5",
32
- xs: "h-8 gap-1 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),10px)] px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
17
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
18
+ icon: "size-9",
19
+ "icon-lg": "size-10",
20
+ "icon-sm": "size-8",
21
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
22
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
23
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
24
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
33
25
  },
34
26
  variant: {
35
- default:
36
- "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/95 aria-pressed:bg-primary/95",
27
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
37
28
  destructive:
38
- "bg-red-600 text-white hover:bg-red-700 focus-visible:border-red-600 focus-visible:ring-red-500/30 active:bg-red-800 aria-pressed:bg-red-800 dark:bg-red-500 dark:aria-pressed:bg-red-300 dark:active:bg-red-300 dark:hover:bg-red-400",
39
- destructiveSecondary:
40
- "border-red-200 text-red-700 hover:bg-red-50 active:bg-red-100 aria-pressed:bg-red-100 dark:border-red-800 dark:text-red-300 dark:aria-pressed:bg-red-950 dark:active:bg-red-950 dark:hover:bg-red-950/60",
29
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
41
30
  ghost:
42
- "hover:bg-muted hover:text-foreground active:bg-muted/80 aria-expanded:bg-muted aria-pressed:bg-muted/80 dark:aria-pressed:bg-muted/60 dark:active:bg-muted/60 dark:hover:bg-muted/50",
43
- input:
44
- "border-input bg-card font-normal font-sans text-base text-foreground leading-snug shadow-input hover:border-input-hover focus-visible:ring-2 focus-visible:ring-ring/15 focus-visible:ring-offset-1 focus-visible:ring-offset-background active:border-input-hover/80 aria-pressed:border-input-hover aria-invalid:border-destructive-foreground data-[placeholder]:text-placeholder-foreground",
45
- link: "text-primary underline-offset-4 hover:underline active:opacity-80 aria-pressed:underline aria-pressed:opacity-80",
31
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
32
+ link: "text-primary underline-offset-4 hover:underline",
46
33
  outline:
47
- "border-border bg-background hover:bg-muted hover:text-foreground active:bg-muted/80 aria-expanded:bg-muted aria-pressed:bg-muted/80 dark:border-input dark:bg-input/30 dark:aria-pressed:bg-input/60 dark:active:bg-input/60 dark:hover:bg-input/50",
34
+ "border bg-background hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
48
35
  secondary:
49
- "bg-secondary text-secondary-foreground hover:bg-secondary/85 active:bg-secondary/75 aria-expanded:bg-secondary aria-pressed:bg-secondary/75",
50
- success:
51
- "bg-green-600 text-white hover:bg-green-700 focus-visible:border-green-600 focus-visible:ring-green-500/30 active:bg-green-800 aria-pressed:bg-green-800 dark:bg-green-500 dark:aria-pressed:bg-green-300 dark:active:bg-green-300 dark:hover:bg-green-400",
52
- successSecondary:
53
- "border-green-200 text-green-700 hover:bg-green-50 active:bg-green-100 aria-pressed:bg-green-100 dark:border-green-800 dark:text-green-300 dark:aria-pressed:bg-green-950 dark:active:bg-green-950 dark:hover:bg-green-950/60",
54
- warning:
55
- "bg-yellow-600 text-white hover:bg-yellow-700 focus-visible:border-yellow-600 focus-visible:ring-yellow-500/30 active:bg-yellow-800 aria-pressed:bg-yellow-800 dark:bg-yellow-500 dark:text-yellow-950 dark:aria-pressed:bg-yellow-300 dark:active:bg-yellow-300 dark:hover:bg-yellow-400",
56
- warningSecondary:
57
- "border-yellow-200 text-yellow-700 hover:bg-yellow-50 active:bg-yellow-100 aria-pressed:bg-yellow-100 dark:border-yellow-800 dark:text-yellow-300 dark:aria-pressed:bg-yellow-950 dark:active:bg-yellow-950 dark:hover:bg-yellow-950/60",
36
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
58
37
  },
59
38
  },
60
39
  }
@@ -65,26 +44,22 @@ const Button = ({
65
44
  variant = "default",
66
45
  size = "default",
67
46
  asChild = false,
68
- children,
69
47
  ...props
70
48
  }: React.ComponentProps<"button"> &
71
49
  VariantProps<typeof buttonVariants> & {
72
50
  asChild?: boolean;
73
- }) =>
74
- useRender({
75
- defaultTagName: "button",
76
- props: mergeProps<"button">(
77
- {
78
- className: cn(buttonVariants({ className, size, variant })),
79
- },
80
- asChild ? props : { ...props, children }
81
- ),
82
- render: asChild ? (children as React.ReactElement) : undefined,
83
- state: {
84
- size,
85
- slot: "button",
86
- variant,
87
- },
88
- });
51
+ }) => {
52
+ const Comp = asChild ? Slot.Root : "button";
53
+
54
+ return (
55
+ <Comp
56
+ data-slot="button"
57
+ data-variant={variant}
58
+ data-size={size}
59
+ className={cn(buttonVariants({ className, size, variant }))}
60
+ {...props}
61
+ />
62
+ );
63
+ };
89
64
 
90
65
  export { Button, buttonVariants };
@@ -42,14 +42,14 @@ const CommandDialog = ({
42
42
  showCloseButton?: boolean;
43
43
  } & Omit<React.ComponentProps<typeof Dialog>, "children">) => (
44
44
  <Dialog {...props}>
45
+ <DialogHeader className="sr-only">
46
+ <DialogTitle>{title}</DialogTitle>
47
+ <DialogDescription>{description}</DialogDescription>
48
+ </DialogHeader>
45
49
  <DialogContent
46
50
  className={cn("overflow-hidden p-0", className)}
47
51
  showCloseButton={showCloseButton}
48
52
  >
49
- <DialogHeader className="sr-only">
50
- <DialogTitle>{title}</DialogTitle>
51
- <DialogDescription>{description}</DialogDescription>
52
- </DialogHeader>
53
53
  <Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
54
54
  {children}
55
55
  </Command>
@@ -115,6 +115,17 @@ const CommandGroup = ({
115
115
  />
116
116
  );
117
117
 
118
+ const CommandSeparator = ({
119
+ className,
120
+ ...props
121
+ }: React.ComponentProps<typeof CommandPrimitive.Separator>) => (
122
+ <CommandPrimitive.Separator
123
+ className={cn("-mx-1 h-px bg-border", className)}
124
+ data-slot="command-separator"
125
+ {...props}
126
+ />
127
+ );
128
+
118
129
  const CommandItem = ({
119
130
  className,
120
131
  ...props
@@ -129,11 +140,28 @@ const CommandItem = ({
129
140
  />
130
141
  );
131
142
 
143
+ const CommandShortcut = ({
144
+ className,
145
+ ...props
146
+ }: React.ComponentProps<"span">) => (
147
+ <span
148
+ className={cn(
149
+ "ml-auto text-muted-foreground text-xs tracking-widest",
150
+ className
151
+ )}
152
+ data-slot="command-shortcut"
153
+ {...props}
154
+ />
155
+ );
156
+
132
157
  export {
158
+ Command,
133
159
  CommandDialog,
134
160
  CommandInput,
135
161
  CommandList,
136
162
  CommandEmpty,
137
163
  CommandGroup,
138
164
  CommandItem,
165
+ CommandShortcut,
166
+ CommandSeparator,
139
167
  };
@@ -6,7 +6,6 @@ import {
6
6
  } from "blode-icons-react";
7
7
  import { cva } from "class-variance-authority";
8
8
  import type { VariantProps } from "class-variance-authority";
9
- import { AnimatePresence, motion } from "motion/react";
10
9
  import { useCallback } from "react";
11
10
  import type { MouseEvent } from "react";
12
11
 
@@ -30,18 +29,17 @@ const buttonVariants = cva(
30
29
  xs: "size-7 rounded-md [&_svg:not([class*='size-'])]:size-3.5",
31
30
  },
32
31
  variant: {
33
- accent: "bg-accent text-accent-foreground shadow-xs hover:bg-accent/90",
34
- default:
35
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
32
+ accent: "bg-accent text-accent-foreground hover:bg-accent/90",
33
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
36
34
  destructive:
37
- "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
35
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
38
36
  ghost:
39
37
  "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
40
38
  link: "text-primary underline-offset-4 hover:underline",
41
39
  outline:
42
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
40
+ "border bg-background hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
43
41
  secondary:
44
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
42
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
45
43
  },
46
44
  },
47
45
  }
@@ -103,18 +101,13 @@ const CopyButton = ({
103
101
  onClick={handleCopy}
104
102
  {...props}
105
103
  >
106
- <AnimatePresence mode="popLayout">
107
- <motion.span
108
- animate={{ filter: "blur(0px)", opacity: 1, scale: 1 }}
109
- data-slot="copy-button-icon"
110
- exit={{ filter: "blur(4px)", opacity: 0.4, scale: 0 }}
111
- initial={false}
112
- key={isCopied ? "check" : "copy"}
113
- transition={{ duration: 0.25 }}
114
- >
115
- <Icon />
116
- </motion.span>
117
- </AnimatePresence>
104
+ <span
105
+ className="inline-flex animate-in fade-in-0 zoom-in-95 duration-200 motion-reduce:animate-none"
106
+ data-slot="copy-button-icon"
107
+ key={isCopied ? "check" : "copy"}
108
+ >
109
+ <Icon />
110
+ </span>
118
111
  </ButtonPrimitive>
119
112
  );
120
113
  };