Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions public/r/action-button.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "action-button",
"type": "registry:component",
"title": "Action Button",
"description": "A call-to-action button with animated hover effect and icon.",
"files": [
{
"path": "registry/v3cn/action-button/action-button.tsx",
"content": "\"use client\";\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\nimport { ArrowRight } from \"lucide-react\";\n\nconst ActionButtonVariants = cva(\n \"relative overflow-hidden rounded-full text-sm font-semibold transition-all duration-300 group inline-flex items-center justify-center\",\n {\n variants: {\n size: {\n default: \"px-6 py-2 pr-12\",\n sm: \"px-4 py-1.5 pr-10 text-sm\",\n lg: \"px-8 py-3 pr-14 text-base\"\n },\n bgColor: {\n default: \"bg-yellow-500\",\n custom: \"\"\n },\n textColor: {\n default: \"text-white\",\n yellow: \"text-yellow-700\",\n red: \"text-red-500\",\n green: \"text-green-500\",\n blue: \"text-blue-500\"\n }\n },\n defaultVariants: {\n size: \"default\",\n bgColor: \"default\",\n textColor: \"default\"\n }\n }\n);\n\nexport interface ActionButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof ActionButtonVariants> {\n asChild?: boolean;\n text?: string;\n}\n\nconst ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>(\n (\n {\n className,\n size,\n bgColor,\n textColor,\n asChild = false,\n text = \"Start 14-day trial\",\n ...props\n },\n ref\n ) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(\n ActionButtonVariants({ size, bgColor, textColor }),\n \"group-focus:outline-none border-2 border-black\",\n className\n )}\n ref={ref}\n {...props}\n >\n <span className=\"relative z-10 transition-colors duration-300 text-black group-hover:text-white\">\n {text}\n </span>\n\n <span className=\"absolute inset-[2px] z-0 bg-black scale-x-0 origin-right transition-all duration-500 ease-out group-hover:scale-x-100 group-hover:opacity-100 rounded-full\" />\n\n <span className=\"absolute right-1 top-1/2 transform -translate-y-1/2 rounded-full bg-black p-1.5 w-7 h-7 flex items-center justify-center z-10\">\n <ArrowRight\n size={16}\n className=\"text-white transition-transform duration-500 ease-out group-hover:rotate-[-45deg]\"\n />\n </span>\n </Comp>\n );\n }\n);\n\nActionButton.displayName = \"TrialButton\";\n\nexport { ActionButton };",
"type": "registry:component",
"target": "components/action-button.tsx"
}
]
}

16 changes: 16 additions & 0 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@
"target": "components/card-demo.tsx"
}
]
},{
"name": "action button",
"type": "registry:block",
"title": "Action Button",
"registryDependencies": [
"https://v3cn.vineet.pro/r/action-button"
],
"description": "A component for displaying Action Button.",
"files": [
{
"path": "registry/v3cn/action-button/action-button.tsx",
"type": "registry:component",
"target": "components/actionButton.tsx"
}
]
}

]
}
89 changes: 89 additions & 0 deletions registry/v3cn/actionButton/actionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { ArrowRight } from "lucide-react";

const ActionButtonVariants = cva(
"relative overflow-hidden rounded-full text-sm font-semibold transition-all duration-300 group inline-flex items-center justify-center",
{
variants: {
size: {
default: "px-6 py-2 pr-12",
sm: "px-4 py-1.5 pr-10 text-sm",
lg: "px-8 py-3 pr-14 text-base",
},
bgColor: {
default: "bg-yellow-500",
custom: "",
},
textColor: {
default: "text-white",
yellow: "text-yellow-700",
red: "text-red-500",
green: "text-green-500",
blue: "text-blue-500",
},
},
defaultVariants: {
size: "default",
bgColor: "default",
textColor: "default",
},
}
);

export interface ActionButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof ActionButtonVariants> {
asChild?: boolean;
text?: string;
}

const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>(
(
{
className,
size,
bgColor,
textColor,
asChild = false,
text = "Start 14-day trial",
...props
},
ref
) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(
ActionButtonVariants({ size, bgColor, textColor }),
"group-focus:outline-none border-2 border-black", // <-- Border added here
className
)}
ref={ref}
{...props}
>
{/* Text */}
<span className="relative z-10 transition-colors duration-300 text-black group-hover:text-white">
{text}
</span>


<span className="absolute inset-[2px] z-0 bg-black scale-x-0 origin-right transition-all duration-500 ease-out group-hover:scale-x-100 group-hover:opacity-100 rounded-full" />

<span className="absolute right-1 top-1/2 transform -translate-y-1/2 rounded-full bg-black p-1.5 w-7 h-7 flex items-center justify-center z-10">
<ArrowRight
size={16}
className="text-white transition-transform duration-500 ease-out group-hover:rotate-[-45deg]"
/>
</span>
</Comp>
);
}
);

ActionButton.displayName = "TrialButton";

export { ActionButton };
189 changes: 189 additions & 0 deletions src/app/docs/components/actionbutton/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { AlertTriangle } from "lucide-react";
import { CodeBlock } from "@/components/ui/code-block";
import { ActionButton } from "@/components/demo-ui/actionbutton/demo";
import { ActionButtonInstallationCode } from "@/components/demo-ui/actionbutton/installation";
import { NavigationMenu } from "@/components/navigation-menu";
import PropItem from "@/components/prop";
import { PropTable } from "@/components/ui/prop-table";
import { SectionWrapper } from "@/components/section-wrapper";
import { basicUsageRawCode } from "@/components/demo-ui/actionbutton/code";
import { codeToHtml } from "shiki/bundle/full";
import { discordnextConfigCode } from "@/components/demo-ui/discord/installation";

// Define the PropDefinition type
type PropDefinition = {
prop: string;
type: string;
default?: string;
description: string;
};

const DiscordPresenceProps: PropDefinition[] = [
{
prop: "userId",
type: "string",
description: "The unique identifier for the Discord user.",
},
{
prop: "userName",
type: "string ",
description: "The display name of the Discord user.",
},
{
prop: "activityDescriptionClass",
type: "string",
description: "CSS class for styling the activity description.",
},
{
prop: "activityImageClassName",
type: "string",
description: "CSS class for styling the activity image.",
},
{
prop: "activityDetailClass",
type: "string",
description: "CSS class for styling the activity details.",
}, {
prop: "progressBarClassName",
type: "string",
description: "CSS class for styling the progress bar (used for Spotify playback).",
},
{
prop: "localTimeClass",
type: "string",
description: "CSS class for styling the local time display.",
},
];


export default async function DiscordPresencePage() {
const basicUsageCode = await codeToHtml(basicUsageRawCode, {
lang: "tsx",
theme: "min-dark",
});

const nextConfigCode = await codeToHtml(discordnextConfigCode, {
lang: "tsx",
theme: "min-dark",
});
return (
<SectionWrapper>
<div className="flex flex-col lg:flex-row gap-8">
<main className="flex-1 space-y-12 overflow-x-auto">
{/* Title */}
<section>
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold mb-4">
Action Button
</h1>
<p className="text-muted-foreground/90 leading-relaxed">
This is a simple action button component that can be used to trigger actions or navigate to different pages. It is designed to be flexible and customizable, allowing you to easily integrate it into your application.
</p>
</section>

{/* Playground */}
<section>
<h2 className="text-xl sm:text-2xl font-semibold mb-4" id="playground">
Playground
</h2>
<div className="border border-gray-400 bg-gray-200 flex justify-center items-center dark:border-zinc-700 rounded-lg overflow-hidden h-[300px] sm:h-[400px] md:h-[500px] dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-950">
<ActionButton
text="Start 14-Day Trial"
size="default"
bgColor="default"
textColor="default"
/>
</div>
</section>

<hr className="border-t border-gray-200 dark:border-gray-700" />

{/* Installation */}
<section>
<h2 className="text-xl sm:text-2xl font-semibold mb-4" id="installation">
Installation
</h2>
<div className="overflow-x-auto">
<ActionButtonInstallationCode/>
</div>
<div className="overflow-x-auto">
<div className="bg-yellow-50 dark:bg-yellow-950/50 p-4 border-yellow-500 border-l-4 rounded-r-lg my-6">
<div className="flex items-start gap-4">
<AlertTriangle className="mt-1 w-6 h-6 text-yellow-500 shrink-0" />
<div className="space-y-2">
<p className="font-medium text-yellow-800 dark:text-yellow-200">
Update your next config file
</p>

</div>
</div>
</div>
<CodeBlock html={nextConfigCode} maxHeight={300} expandedHeight={500} />
</div>
</section>

<hr className="border-t border-gray-200 dark:border-gray-700" />

{/* Usage Examples */}
<section>
<div className="flex flex-col gap-4">
<h2 className="ml-2 text-lg font-medium" id="props">
Usage Examples
</h2>

{/* Default Usage */}
<div className="space-y-4 md:p-4 overflow-x-auto">
<h3 className="ml-2 text-md font-medium">Default Usage</h3>
<CodeBlock html={basicUsageCode} />
</div>
<div className="bg-yellow-50 dark:bg-yellow-950/50 border-l-4 border-yellow-500 p-4 rounded-r-lg">
<div className="flex flex-col sm:flex-row items-start gap-4">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 50 640 512"
width="40"
height="20"
className="flex-shrink-0"
>
<path
fill="white"
d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"
/>
</svg>

<p className="text-sm sm:text-base">
Join this discord server to make your presence appear{" "}
<a
href="https://discord.gg/lanyard"
className="underline cursor-pointer text-blue-400 break-words"
target="_blank"
rel="noopener noreferrer"
>
https://discord.gg/lanyard
</a>
</p>
</div>
</div>
<div className="flex justify-center border-t border-gray-200 w-40 mx-auto" />
<h2 className="p-2 text-lg" id="props">
Props
</h2>
<div className="flex flex-col gap-6 border rounded-lg overflow-x-auto">

<div className="grid gap-6">
<PropTable title="<Discord Presence />" props={DiscordPresenceProps} />
</div>
</div>
</div>
</section>
</main>

{/* Right-side navigation */}
<aside className="w-full lg:w-64 shrink-0 mt-8 lg:mt-0">
<div className="sticky top-24">
<NavigationMenu />
</div>
</aside>
</div>
</SectionWrapper>
);
}
33 changes: 33 additions & 0 deletions src/components/demo-ui/actionbutton/code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ScrollArea } from "@/components/ui/scroll-area";

// Create a client component for rendering the code
export function CodeDisplay({ html }: { html: string }) {
return (
<ScrollArea className="h-[500px]">
<div
className="p-5 text-sm leading-[1.6rem] bg-zinc-900 dark:bg-transparent rounded-lg [&>pre]:!bg-transparent [&>pre]:!p-0 [&_.line-number]:pr-4 [&_.line-number]:text-zinc-500 [&_.line-number]:border-r [&_.line-number]:border-zinc-700 [&_.line-number]:mr-4"
dangerouslySetInnerHTML={{ __html: html }}
/>
</ScrollArea>
);
}

export const basicUsageRawCode = `"use client"
<div className="min-h-screen flex items-center justify-center bg-gray-100 p-8">
<div className="space-y-6 text-center">
<h1 className="text-4xl font-bold text-gray-800">Welcome to the Demo</h1>
<p className="text-lg text-gray-600">
Click the button below to start your free trial.
</p>

<ActionButton
text="Start 14-Day Trial"
size="default"
bgColor="default"
textColor="default"
onClick={() => alert("Trial started!")}
/>
</div>
</div>
);
}`;
Loading