complete customChatGpt model selection

This commit is contained in:
Danny Avila 2023-03-03 15:52:06 -05:00
parent 0f9cfd0395
commit 214228542a
18 changed files with 742 additions and 63 deletions

View file

@ -54,7 +54,7 @@ export default function Message({
let icon = `${sender}:`;
let backgroundColor = bgColors[sender];
if (notUser) {
if (notUser && backgroundColor) {
props.className =
'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-100 dark:bg-[#444654]';
icon = (
@ -77,7 +77,9 @@ export default function Message({
onMouseOut={handleMouseOut}
>
<div className="m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
<strong className="relative flex w-[30px] flex-col items-end">{icon}</strong>
<strong className="relative flex w-[30px] flex-col items-end text-right">
{icon}
</strong>
<div className="relative flex w-[calc(100%-50px)] flex-col gap-1 whitespace-pre-wrap md:gap-3 lg:w-[calc(100%-115px)]">
<div className="flex flex-grow flex-col gap-3">
{error ? (

View file

@ -1,10 +1,13 @@
import React, { useEffect } from 'react';
import React, { useState, useEffect } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { useSelector, useDispatch } from 'react-redux';
import { setModel } from '~/store/submitSlice';
import { setModel, setDisabled, setCustomGpt } from '~/store/submitSlice';
import GPTIcon from '../svg/GPTIcon';
import BingIcon from '../svg/BingIcon';
import { Button } from '../ui/Button.tsx';
import { Input } from '../ui/Input.tsx';
import { Label } from '../ui/Label.tsx';
import {
DropdownMenu,
DropdownMenuContent,
@ -15,25 +18,56 @@ import {
DropdownMenuTrigger
} from '../ui/DropdownMenu.tsx';
import {
Dialog,
DialogTrigger,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle
} from '../ui/Dialog.tsx';
export default function ModelMenu() {
const dispatch = useDispatch();
const { model } = useSelector((state) => state.submit);
const onChange = (value) => {
dispatch(setModel(value));
};
const [chatGptLabel, setChatGptLabel] = useState('');
const [promptPrefix, setPromptPrefix] = useState('');
const [required, setRequired] = useState(false);
useEffect(() => {
const lastSelectedModel = JSON.parse(localStorage.getItem('model'));
if (lastSelectedModel) {
if (lastSelectedModel && lastSelectedModel !== 'chatgptCustom') {
dispatch(setModel(lastSelectedModel));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
localStorage.setItem('model', JSON.stringify(model));
}, [model]);
const onChange = (value) => {
if (value === 'chatgptCustom') {
// dispatch(setDisabled(true));
} else {
dispatch(setModel(value));
dispatch(setDisabled(false));
}
};
const submitHandler = (e) => {
if (chatGptLabel.length === 0) {
e.preventDefault();
setRequired(true);
return;
}
dispatch(setCustomGpt({ chatGptLabel, promptPrefix }));
dispatch(setModel('chatgptCustom'));
dispatch(setDisabled(false));
};
const defaultColorProps = [
'text-gray-500',
'hover:bg-gray-100',
@ -54,32 +88,100 @@ export default function ModelMenu() {
'dark:disabled:hover:bg-transparent'
];
const requiredProp = required ? { required: true } : {};
const colorProps = model === 'chatgpt' ? chatgptColorProps : defaultColorProps;
const icon = model === 'bingai' ? <BingIcon button={true} /> : <GPTIcon button={true} /> ;
const icon = model === 'bingai' ? <BingIcon button={true} /> : <GPTIcon button={true} />;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
// style={{backgroundColor: 'rgb(16, 163, 127)'}}
className={`absolute bottom-0.5 rounded-md border-0 p-1 pl-2 outline-none ${colorProps.join(' ')} focus:ring-0 focus:ring-offset-0 disabled:bottom-0.5 md:pl-1 md:bottom-1 md:left-2 md:disabled:bottom-1`}
>
{icon}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>Select a Model</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup
value={model}
onValueChange={onChange}
>
<DropdownMenuRadioItem value="chatgpt">ChatGPT</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="bingai">BingAI</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="chatgptBrowser">{'ChatGPT (free)'}</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<Dialog>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
// style={{backgroundColor: 'rgb(16, 163, 127)'}}
className={`absolute bottom-0.5 rounded-md border-0 p-1 pl-2 outline-none ${colorProps.join(
' '
)} focus:ring-0 focus:ring-offset-0 disabled:bottom-0.5 md:bottom-1 md:left-2 md:pl-1 md:disabled:bottom-1`}
>
{icon}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>Select a Model</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup
value={model}
onValueChange={onChange}
>
<DropdownMenuRadioItem value="chatgpt">
ChatGPT <sup>$</sup>
</DropdownMenuRadioItem>
<DialogTrigger asChild>
<DropdownMenuRadioItem value="chatgptCustom">
CustomGPT <sup>$</sup>
</DropdownMenuRadioItem>
</DialogTrigger>
<DropdownMenuRadioItem value="bingai">BingAI</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="chatgptBrowser">ChatGPT</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<DialogContent>
<DialogHeader>
<DialogTitle>Customize ChatGPT</DialogTitle>
<DialogDescription>
Note: important instructions are often better placed in your message rather than
the prefix.{' '}
<a href="https://platform.openai.com/docs/guides/chat/instructing-chat-models">
<u>More info here</u>
</a>
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label
htmlFor="chatGptLabel"
className="text-right"
>
Custom Name
</Label>
<Input
id="chatGptLabel"
value={chatGptLabel}
onChange={(e) => setChatGptLabel(e.target.value)}
placeholder="Set a custom name for ChatGPT"
className="col-span-3 invalid:border-red-400 invalid:text-red-600 invalid:placeholder-red-600 invalid:placeholder-opacity-70
focus:ring-opacity-20 focus:invalid:border-red-400 focus:invalid:ring-red-400 focus:invalid:ring-opacity-20"
{...requiredProp}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label
htmlFor="promptPrefix"
className="text-right"
>
Prompt Prefix
</Label>
<TextareaAutosize
id="promptPrefix"
value={promptPrefix}
onChange={(e) => setPromptPrefix(e.target.value)}
placeholder="Set custom instructions. Defaults to: 'You are ChatGPT, a large language model trained by OpenAI.'"
className="col-span-3 flex h-20 w-full resize-none rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900"
/>
</div>
</div>
<DialogFooter>
<DialogClose>Cancel</DialogClose>
<DialogClose
onClick={submitHandler}
className="inline-flex h-10 items-center justify-center rounded-md border-none bg-slate-900 py-2 px-4 text-sm font-semibold text-white transition-colors hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900"
>
Submit
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View file

@ -2,7 +2,7 @@ import React from 'react';
import { useSelector } from 'react-redux';
export default function SubmitButton({ submitMessage }) {
const { isSubmitting } = useSelector((state) => state.submit);
const { isSubmitting, disabled } = useSelector((state) => state.submit);
const clickHandler = (e) => {
e.preventDefault();
submitMessage();
@ -22,6 +22,7 @@ export default function SubmitButton({ submitMessage }) {
return (
<button
onClick={clickHandler}
disabled={disabled}
className="absolute bottom-1.5 right-1 rounded-md p-1 text-gray-500 hover:bg-gray-100 disabled:hover:bg-transparent dark:hover:bg-gray-900 dark:hover:text-gray-400 dark:disabled:hover:bg-transparent md:bottom-2.5 md:right-2"
>
<svg

View file

@ -15,7 +15,7 @@ export default function TextChat({ messages }) {
const [errorMessage, setErrorMessage] = useState('');
const dispatch = useDispatch();
const convo = useSelector((state) => state.convo);
const { isSubmitting, model } = useSelector((state) => state.submit);
const { isSubmitting, disabled, model, chatGptLabel, promptPrefix } = useSelector((state) => state.submit);
const { text } = useSelector((state) => state.text);
const { error } = convo;
@ -30,15 +30,20 @@ export default function TextChat({ messages }) {
dispatch(setSubmitState(true));
const message = text.trim();
const currentMsg = { sender: 'User', text: message, current: true };
const initialResponse = { sender: model, text: '' };
const sender = model === 'chatgptCustom' ? chatGptLabel : model
const initialResponse = { sender, text: '' };
dispatch(setMessages([...messages, currentMsg, initialResponse]));
dispatch(setText(''));
const messageHandler = (data) => {
dispatch(setMessages([...messages, currentMsg, { sender: model, text: data }]));
dispatch(setMessages([...messages, currentMsg, { sender, text: data }]));
};
const convoHandler = (data) => {
dispatch(
setMessages([...messages, currentMsg, { sender: model, text: data.text || data.response }])
setMessages([
...messages,
currentMsg,
{ sender, text: data.text || data.response }
])
);
if (
@ -116,7 +121,9 @@ export default function TextChat({ messages }) {
convo,
messageHandler,
convoHandler,
errorHandler
errorHandler,
chatGptLabel,
promptPrefix
};
console.log('User Input:', message);
handleSubmit(submission);
@ -167,7 +174,13 @@ export default function TextChat({ messages }) {
errorMessage={errorMessage}
/>
) : (
<div className="relative flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 dark:bg-gray-700 dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4">
<div
className={`relative flex w-full flex-grow flex-col rounded-md border border-black/10 ${
disabled ? 'bg-gray-100' : 'bg-white'
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
} dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`}
>
<ModelMenu />
<TextareaAutosize
tabIndex="0"
@ -177,7 +190,8 @@ export default function TextChat({ messages }) {
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
onChange={changeHandler}
placeholder=""
placeholder={disabled ? 'Choose another model or customize GPT again' : ''}
disabled={disabled}
className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-9 pr-8 leading-6 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent md:pl-8"
/>
<SubmitButton submitMessage={submitMessage} />

View file

@ -0,0 +1,156 @@
"use client"
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
import { cn } from "../../utils"
const AlertDialog = AlertDialogPrimitive.Root
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
const AlertDialogPortal = ({
className,
children,
...props
}: AlertDialogPrimitive.AlertDialogPortalProps) => (
<AlertDialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-end justify-center sm:items-center">
{children}
</div>
</AlertDialogPrimitive.Portal>
)
AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName
const AlertDialogOverlay = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, children, ...props }, ref) => (
<AlertDialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-opacity animate-in fade-in",
className
)}
{...props}
ref={ref}
/>
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-50 grid w-full max-w-lg scale-100 gap-4 bg-white p-6 opacity-100 animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full",
"dark:bg-slate-900",
className
)}
{...props}
/>
</AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
const AlertDialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
AlertDialogHeader.displayName = "AlertDialogHeader"
const AlertDialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
AlertDialogFooter.displayName = "AlertDialogFooter"
const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold text-slate-900",
"dark:text-slate-50",
className
)}
{...props}
/>
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-sm text-slate-500", "dark:text-slate-400", className)}
{...props}
/>
))
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName
const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-slate-900 py-2 px-4 text-sm font-semibold text-white transition-colors hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
className
)}
{...props}
/>
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
"mt-2 inline-flex h-10 items-center justify-center rounded-md border border-slate-200 bg-transparent py-2 px-4 text-sm font-semibold text-slate-900 transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-700 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 sm:mt-0",
className
)}
{...props}
/>
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
export {
AlertDialog,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
}

View file

@ -0,0 +1,144 @@
import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"
import { cn } from "../../utils"
const Dialog = DialogPrimitive.Root
const DialogTrigger = DialogPrimitive.Trigger
const DialogPortal = ({
className,
children,
...props
}: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
{children}
</div>
</DialogPrimitive.Portal>
)
DialogPortal.displayName = DialogPrimitive.Portal.displayName
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, children, ...props }, ref) => (
<DialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out",
className
)}
{...props}
ref={ref}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-50 grid w-full gap-4 rounded-b-lg bg-white p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
"dark:bg-slate-900",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 dark:data-[state=open]:bg-slate-800">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName
const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
DialogHeader.displayName = "DialogHeader"
const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold text-slate-900",
"dark:text-slate-50",
className
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-slate-500", "dark:text-slate-400", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName
const DialogClose = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Close>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Close
ref={ref}
className={cn(
"mt-2 inline-flex h-10 items-center justify-center rounded-md border border-slate-200 bg-transparent py-2 px-4 text-sm font-semibold text-slate-900 transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-700 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 sm:mt-0",
className
)}
{...props}
/>
))
DialogClose.displayName = DialogPrimitive.Title.displayName
export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
DialogClose,
}

View file

@ -0,0 +1,24 @@
import * as React from "react"
import { cn } from "../../utils"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, ...props }, ref) => {
return (
<input
className={cn(
"flex h-10 w-full rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
export { Input }

View file

@ -0,0 +1,21 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cn } from "../../utils"
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(
"text-sm font-medium dark:text-gray-200 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
className
)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
export { Label }

View file

@ -0,0 +1,26 @@
/* eslint-disable */
import * as React from "react"
import TextareaAutosize from 'react-textarea-autosize';
import { cn } from "../../utils"
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex h-20 w-full resize-none rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
export { Textarea }