diff --git a/kits/automation/changelog-generator/.env.example b/kits/automation/changelog-generator/.env.example new file mode 100644 index 00000000..09d63678 --- /dev/null +++ b/kits/automation/changelog-generator/.env.example @@ -0,0 +1,4 @@ +LAMATIC_PROJECT_ENDPOINT=YOUR_API_ENDPOINT +LAMATIC_FLOW_ID=YOUR_FLOW_ID +LAMATIC_PROJECT_ID=YOUR_PROJECT_ID +LAMATIC_PROJECT_API_KEY=YOUR_API_KEY \ No newline at end of file diff --git a/kits/automation/changelog-generator/.gitignore b/kits/automation/changelog-generator/.gitignore new file mode 100644 index 00000000..7b8da95f --- /dev/null +++ b/kits/automation/changelog-generator/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* +!.env.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/kits/automation/changelog-generator/README.md b/kits/automation/changelog-generator/README.md new file mode 100644 index 00000000..a3521ff3 --- /dev/null +++ b/kits/automation/changelog-generator/README.md @@ -0,0 +1,98 @@ +# ๐Ÿ“‹ Changelog Generator โ€” AgentKit + +An AI-powered kit that generates professional, well-structured changelogs from GitHub repository information. Paste a repo URL and date range โ€” get a complete changelog in seconds. + +![Changelog Generator](./public/preview.png) + +## โœจ What It Does + +- Takes a **GitHub repository URL** and a **date range** as input +- Generates a structured changelog with sections: + - ๐Ÿ“‹ Summary (plain English for non-technical stakeholders) + - ๐Ÿš€ New Features + - ๐Ÿ› Bug Fixes + - ๐Ÿ”ง Improvements + - โš ๏ธ Breaking Changes + - ๐Ÿ“ฆ Dependencies +- **One-click copy** of the full markdown output +- Powered by **Groq LLaMA** via Lamatic Flows + +## ๐Ÿš€ Quick Deploy + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit/tree/main/kits/automation/changelog-generator) + +## ๐Ÿ“ฆ Prerequisites + +- Node.js 18+ +- A [Lamatic.ai](https://lamatic.ai) account +- A [Groq](https://console.groq.com) API key (free) + +## โš™๏ธ Setup + +### 1. Clone and Install + +```bash +git clone https://github.com/Lamatic/AgentKit.git +cd AgentKit/kits/automation/changelog-generator +npm install +``` + +### 2. Set Up Lamatic Flow + +1. Sign in to [studio.lamatic.ai](https://studio.lamatic.ai) +2. Create a new project โ†’ "Changelog Generator" +3. Create a new Flow with: + - **Trigger node** with inputs: `repo_url`, `date_from`, `date_to` (all String) + - **Generate Text node** using Groq `llama-3.3-70b-versatile` with the prompt from `flows/changelog-flow/README.md` +4. Deploy the flow +5. Note your **Flow ID**, **API Key**, **Project ID**, and **API URL** + +### 3. Configure Environment Variables + +```bash +cp .env.example .env +``` + +Fill in your `.env`: + +```env +LAMATIC_FLOW_ID="your-flow-id" +LAMATIC_PROJECT_ENDPOINT="your-api-endpoint" +LAMATIC_PROJECT_ID="your-project-id" +LAMATIC_PROJECT_API_KEY="your-api-key" +``` + +### 4. Run Locally + +```bash +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) + +## ๐ŸŒ Deploy to Vercel + +1. Push your fork to GitHub +2. Go to [vercel.com](https://vercel.com) โ†’ New Project โ†’ Import your fork +3. Set **Root Directory** to `kits/automation/changelog-generator` +4. Add all 4 environment variables +5. Click Deploy + +## ๐Ÿ“ Project Structure + +``` +changelog-generator/ +โ”œโ”€โ”€ app/ +โ”‚ โ””โ”€โ”€ page.tsx # Main UI +โ”œโ”€โ”€ actions/ +โ”‚ โ””โ”€โ”€ orchestrate.ts # Lamatic Flow API call +โ”œโ”€โ”€ flows/ +โ”‚ โ””โ”€โ”€ changelog-flow/ # Exported Lamatic flow files +โ”œโ”€โ”€ .env.example # Environment variables template +โ”œโ”€โ”€ config.json # Kit metadata +โ””โ”€โ”€ README.md +``` + +## ๐Ÿค Contributing + +See [CONTRIBUTING.md](../../../CONTRIBUTING.md) for guidelines. \ No newline at end of file diff --git a/kits/automation/changelog-generator/actions/orchestrate.ts b/kits/automation/changelog-generator/actions/orchestrate.ts new file mode 100644 index 00000000..3d16c62f --- /dev/null +++ b/kits/automation/changelog-generator/actions/orchestrate.ts @@ -0,0 +1,67 @@ +"use server"; + +import { Lamatic } from "lamatic"; + +function createLamaticClient() { + const endpoint = process.env.LAMATIC_PROJECT_ENDPOINT; + const projectId = process.env.LAMATIC_PROJECT_ID; + const apiKey = process.env.LAMATIC_PROJECT_API_KEY; + if (!endpoint || !projectId || !apiKey) { + throw new Error("Missing Lamatic project configuration"); + } + + return new Lamatic({ endpoint, projectId, apiKey }); +} + +const lamaticClient = createLamaticClient(); + +interface ChangelogInput { + repoUrl: string; + dateFrom: string; + dateTo: string; +} + +export async function generateChangelog({ + repoUrl, + dateFrom, + dateTo, +}: ChangelogInput): Promise { + const parsedRepoUrl = new URL(repoUrl); + const [owner, repo] = parsedRepoUrl.pathname.split("/").filter(Boolean); + if (parsedRepoUrl.hostname !== "github.com" || !owner || !repo) { + throw new Error("repoUrl must be a valid GitHub repository URL"); + } + if (!dateFrom || !dateTo || dateFrom > dateTo) { + throw new Error("Invalid date range"); + } + const flowId = process.env.LAMATIC_FLOW_ID; + if (!flowId) throw new Error("Missing LAMATIC_FLOW_ID"); + + const response = await lamaticClient.executeFlow(flowId, { + repo_url: repoUrl, + date_from: dateFrom, + date_to: dateTo, + }) as any; + + const extractChangelog = (payload: any) => + payload?.result?.changeLog ?? + payload?.data?.output?.result?.changeLog ?? + payload?.data?.changeLog; + + // Handle async flow (returns requestId) + if (response?.result?.requestId) { + const finalResult = await lamaticClient.checkStatus( + response.result.requestId, + 5, + 120 + ) as any; + const changelog = extractChangelog(finalResult); + if (!changelog) throw new Error("Failed to extract changelog from Lamatic response"); + return changelog; + } + + // Handle sync flow (returns result directly) + const changelog = extractChangelog(response); + if (!changelog) throw new Error("Failed to extract changelog from Lamatic response"); + return changelog; +} \ No newline at end of file diff --git a/kits/automation/changelog-generator/app/favicon.ico b/kits/automation/changelog-generator/app/favicon.ico new file mode 100644 index 00000000..718d6fea Binary files /dev/null and b/kits/automation/changelog-generator/app/favicon.ico differ diff --git a/kits/automation/changelog-generator/app/globals.css b/kits/automation/changelog-generator/app/globals.css new file mode 100644 index 00000000..f71e3bd2 --- /dev/null +++ b/kits/automation/changelog-generator/app/globals.css @@ -0,0 +1,130 @@ +@import "tailwindcss"; +@import "tw-animate-css"; +@import "shadcn/tailwind.css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --font-heading: var(--font-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); +} + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} \ No newline at end of file diff --git a/kits/automation/changelog-generator/app/layout.tsx b/kits/automation/changelog-generator/app/layout.tsx new file mode 100644 index 00000000..768d0883 --- /dev/null +++ b/kits/automation/changelog-generator/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Changelog Generator", + description: "Generate structured changelogs from GitHub repositories and date ranges.", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + +); +} diff --git a/kits/automation/changelog-generator/app/page.tsx b/kits/automation/changelog-generator/app/page.tsx new file mode 100644 index 00000000..db00207a --- /dev/null +++ b/kits/automation/changelog-generator/app/page.tsx @@ -0,0 +1,232 @@ +"use client"; + +import { useState } from "react"; +import { generateChangelog } from "@/actions/orchestrate"; +import ReactMarkdown from "react-markdown"; + +export default function ChangelogPage() { + const [repoUrl, setRepoUrl] = useState(""); + const [dateFrom, setDateFrom] = useState(""); + const [dateTo, setDateTo] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [result, setResult] = useState(null); + const [error, setError] = useState(""); + const [copied, setCopied] = useState(false); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!repoUrl || !dateFrom || !dateTo) { + setError("Please fill in all fields."); + return; + } + setError(""); + setResult(null); + setIsLoading(true); + try { + const changelog = await generateChangelog({ repoUrl, dateFrom, dateTo }); + setResult(changelog); + } catch (err) { + setError("Something went wrong. Please try again."); + } finally { + setIsLoading(false); + } + }; + + const handleCopy = () => { + if (result) { + navigator.clipboard.writeText(result); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + + return ( +
+ {/* Grid background */} +
+ +
+ {/* Header */} +
+
+ + AI-Powered +
+

+ Changelog + Generator +

+

+ Turn your GitHub repository activity into a beautifully structured + changelog โ€” in seconds. +

+
+ +
+ {/* Left: Form */} +
+

+ Repository Details +

+
+
+ + setRepoUrl(e.target.value)} + placeholder="https://github.com/owner/repo" + className="w-full bg-zinc-800/80 border border-zinc-700 rounded-lg px-4 py-3 text-sm text-white placeholder-zinc-600 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500/50 transition-all" + /> +
+ +
+
+ + setDateFrom(e.target.value)} + className="w-full bg-zinc-800/80 border border-zinc-700 rounded-lg px-4 py-3 text-sm text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500/50 transition-all [color-scheme:dark]" + /> +
+
+ + setDateTo(e.target.value)} + className="w-full bg-zinc-800/80 border border-zinc-700 rounded-lg px-4 py-3 text-sm text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500/50 transition-all [color-scheme:dark]" + /> +
+
+ + {error && ( +

+ {error} +

+ )} + + +
+ + {/* Info box */} +
+

+ Provide a GitHub repo URL and date range. The AI will generate a + professional changelog with features, fixes, improvements, and + breaking changes. +

+
+
+ + {/* Right: Output */} +
+
+

+ Output +

+ {result && ( + + )} +
+ +
+ {!result && !isLoading && ( +
+
+ + + +
+

+ Your generated changelog will appear here +

+
+ )} + + {isLoading && ( +
+
+ + + + +
+

Generating your changelog...

+

This may take a few seconds

+
+ )} + + {result && ( +
+ {result} +
+ )} +
+
+
+ + {/* Footer */} +

+ POWERED BY LAMATIC AI ยท AGENTKIT +

+
+
+ ); +} \ No newline at end of file diff --git a/kits/automation/changelog-generator/components.json b/kits/automation/changelog-generator/components.json new file mode 100644 index 00000000..02e61e07 --- /dev/null +++ b/kits/automation/changelog-generator/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "radix-nova", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/kits/automation/changelog-generator/components/ui/button.tsx b/kits/automation/changelog-generator/components/ui/button.tsx new file mode 100644 index 00000000..c88ffd6f --- /dev/null +++ b/kits/automation/changelog-generator/components/ui/button.tsx @@ -0,0 +1,67 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from "radix-ui" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + outline: + "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", + ghost: + "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + destructive: + "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: + "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", + lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3", + icon: "size-8", + "icon-xs": + "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", + "icon-sm": + "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg", + "icon-lg": "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot.Root : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/kits/automation/changelog-generator/components/ui/card.tsx b/kits/automation/changelog-generator/components/ui/card.tsx new file mode 100644 index 00000000..40cac5f9 --- /dev/null +++ b/kits/automation/changelog-generator/components/ui/card.tsx @@ -0,0 +1,103 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ + className, + size = "default", + ...props +}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) { + return ( +
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", + className + )} + {...props} + /> + ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/kits/automation/changelog-generator/components/ui/select.tsx b/kits/automation/changelog-generator/components/ui/select.tsx new file mode 100644 index 00000000..f09dfb48 --- /dev/null +++ b/kits/automation/changelog-generator/components/ui/select.tsx @@ -0,0 +1,192 @@ +"use client" + +import * as React from "react" +import { Select as SelectPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react" + +function Select({ + ...props +}: React.ComponentProps) { + return +} + +function SelectGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default" +}) { + return ( + + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "item-aligned", + align = "center", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} diff --git a/kits/automation/changelog-generator/components/ui/textarea.tsx b/kits/automation/changelog-generator/components/ui/textarea.tsx new file mode 100644 index 00000000..04d27f7d --- /dev/null +++ b/kits/automation/changelog-generator/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +