mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-04-07 11:28:09 +02:00
Update popup + misc standardization (#3906)
* pop * various minor improvements * improvement * finalize * update
This commit is contained in:
parent
e9b892301b
commit
6ff452a2e1
@ -67,6 +67,7 @@ jobs:
|
||||
NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}
|
||||
NEXT_PUBLIC_GTM_ENABLED=true
|
||||
NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true
|
||||
NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
# needed due to weird interactions with the builds for different platforms
|
||||
no-cache: true
|
||||
|
@ -81,6 +81,9 @@ ENV NEXT_PUBLIC_GTM_ENABLED=${NEXT_PUBLIC_GTM_ENABLED}
|
||||
ARG NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED
|
||||
ENV NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED}
|
||||
|
||||
ARG NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK
|
||||
ENV NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=${NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK}
|
||||
|
||||
# Use NODE_OPTIONS in the build command
|
||||
RUN NODE_OPTIONS="${NODE_OPTIONS}" npx next build
|
||||
|
||||
@ -160,6 +163,9 @@ ENV NEXT_PUBLIC_GTM_ENABLED=${NEXT_PUBLIC_GTM_ENABLED}
|
||||
ARG NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED
|
||||
ENV NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED}
|
||||
|
||||
ARG NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK
|
||||
ENV NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=${NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK}
|
||||
|
||||
# Note: Don't expose ports here, Compose will handle that for us if necessary.
|
||||
# If you want to run this without compose, specify the ports to
|
||||
# expose via cli
|
||||
|
@ -28,6 +28,7 @@ import { Spinner } from "@/components/Spinner";
|
||||
import { deleteApiKey, regenerateApiKey } from "./lib";
|
||||
import { OnyxApiKeyForm } from "./OnyxApiKeyForm";
|
||||
import { APIKey } from "./types";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const API_KEY_TEXT = `API Keys allow you to access Onyx APIs programmatically. Click the button below to generate a new API Key.`;
|
||||
|
||||
@ -111,14 +112,7 @@ function Main() {
|
||||
}
|
||||
|
||||
const newApiKeyButton = (
|
||||
<Button
|
||||
variant="navigate"
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
onClick={() => setShowCreateUpdateForm(true)}
|
||||
>
|
||||
Create API Key
|
||||
</Button>
|
||||
<CreateButton href="/admin/api-key/new" text="Create API Key" />
|
||||
);
|
||||
|
||||
if (apiKeys.length === 0) {
|
||||
|
@ -40,7 +40,12 @@ import * as Yup from "yup";
|
||||
import CollapsibleSection from "./CollapsibleSection";
|
||||
import { SuccessfulPersonaUpdateRedirectType } from "./enums";
|
||||
import { Persona, PersonaLabel, StarterMessage } from "./interfaces";
|
||||
import { PersonaUpsertParameters, createPersona, updatePersona } from "./lib";
|
||||
import {
|
||||
PersonaUpsertParameters,
|
||||
createPersona,
|
||||
updatePersona,
|
||||
deletePersona,
|
||||
} from "./lib";
|
||||
import {
|
||||
CameraIcon,
|
||||
GroupsIconSkeleton,
|
||||
@ -71,7 +76,6 @@ import { LLMSelector } from "@/components/llm/LLMSelector";
|
||||
import useSWR from "swr";
|
||||
import { errorHandlingFetcher } from "@/lib/fetcher";
|
||||
import { DeleteEntityModal } from "@/components/modals/DeleteEntityModal";
|
||||
import { DeletePersonaButton } from "./[id]/DeletePersonaButton";
|
||||
import Title from "@/components/ui/title";
|
||||
import { SEARCH_TOOL_ID } from "@/app/chat/tools/constants";
|
||||
|
||||
@ -322,10 +326,39 @@ export function AssistantEditor({
|
||||
}));
|
||||
};
|
||||
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
||||
|
||||
if (!labels) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const openDeleteModal = () => {
|
||||
setDeleteModalOpen(true);
|
||||
};
|
||||
|
||||
const closeDeleteModal = () => {
|
||||
setDeleteModalOpen(false);
|
||||
};
|
||||
|
||||
const handleDeletePersona = async () => {
|
||||
if (existingPersona) {
|
||||
const response = await deletePersona(existingPersona.id);
|
||||
if (response.ok) {
|
||||
await refreshAssistants();
|
||||
router.push(
|
||||
redirectType === SuccessfulPersonaUpdateRedirectType.ADMIN
|
||||
? `/admin/assistants?u=${Date.now()}`
|
||||
: `/chat`
|
||||
);
|
||||
} else {
|
||||
setPopup({
|
||||
type: "error",
|
||||
message: `Failed to delete persona - ${await response.text()}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<style>
|
||||
@ -364,6 +397,14 @@ export function AssistantEditor({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{deleteModalOpen && existingPersona && (
|
||||
<DeleteEntityModal
|
||||
entityType="Persona"
|
||||
entityName={existingPersona.name}
|
||||
onClose={closeDeleteModal}
|
||||
onSubmit={handleDeletePersona}
|
||||
/>
|
||||
)}
|
||||
{popup}
|
||||
<Formik
|
||||
enableReinitialize={true}
|
||||
@ -1312,14 +1353,6 @@ export function AssistantEditor({
|
||||
explanationLink="https://docs.onyx.app/guides/assistants"
|
||||
className="[&_textarea]:placeholder:text-text-muted/50"
|
||||
/>
|
||||
<div className="flex justify-end">
|
||||
{existingPersona && (
|
||||
<DeletePersonaButton
|
||||
personaId={existingPersona!.id}
|
||||
redirectType={SuccessfulPersonaUpdateRedirectType.ADMIN}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -1338,6 +1371,18 @@ export function AssistantEditor({
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
{existingPersona && (
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={openDeleteModal}
|
||||
type="button"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
|
@ -17,6 +17,7 @@ import { FiEdit2 } from "react-icons/fi";
|
||||
import { TrashIcon } from "@/components/icons/icons";
|
||||
import { useUser } from "@/components/user/UserProvider";
|
||||
import { useAssistants } from "@/components/context/AssistantsContext";
|
||||
import { DeleteEntityModal } from "@/components/modals/DeleteEntityModal";
|
||||
|
||||
function PersonaTypeDisplay({ persona }: { persona: Persona }) {
|
||||
if (persona.builtin_persona) {
|
||||
@ -53,6 +54,8 @@ export function PersonasTable() {
|
||||
}, [editablePersonas]);
|
||||
|
||||
const [finalPersonas, setFinalPersonas] = useState<Persona[]>([]);
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
||||
const [personaToDelete, setPersonaToDelete] = useState<Persona | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const editable = editablePersonas.sort(personaComparator);
|
||||
@ -98,9 +101,42 @@ export function PersonasTable() {
|
||||
await refreshUser();
|
||||
};
|
||||
|
||||
const openDeleteModal = (persona: Persona) => {
|
||||
setPersonaToDelete(persona);
|
||||
setDeleteModalOpen(true);
|
||||
};
|
||||
|
||||
const closeDeleteModal = () => {
|
||||
setDeleteModalOpen(false);
|
||||
setPersonaToDelete(null);
|
||||
};
|
||||
|
||||
const handleDeletePersona = async () => {
|
||||
if (personaToDelete) {
|
||||
const response = await deletePersona(personaToDelete.id);
|
||||
if (response.ok) {
|
||||
await refreshAssistants();
|
||||
closeDeleteModal();
|
||||
} else {
|
||||
setPopup({
|
||||
type: "error",
|
||||
message: `Failed to delete persona - ${await response.text()}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{popup}
|
||||
{deleteModalOpen && personaToDelete && (
|
||||
<DeleteEntityModal
|
||||
entityType="Persona"
|
||||
entityName={personaToDelete.name}
|
||||
onClose={closeDeleteModal}
|
||||
onSubmit={handleDeletePersona}
|
||||
/>
|
||||
)}
|
||||
|
||||
<DraggableTable
|
||||
headers={["Name", "Description", "Type", "Is Visible", "Delete"]}
|
||||
@ -170,16 +206,7 @@ export function PersonasTable() {
|
||||
{!persona.builtin_persona && isEditable ? (
|
||||
<div
|
||||
className="hover:bg-hover rounded p-1 cursor-pointer"
|
||||
onClick={async () => {
|
||||
const response = await deletePersona(persona.id);
|
||||
if (response.ok) {
|
||||
await refreshAssistants();
|
||||
} else {
|
||||
alert(
|
||||
`Failed to delete persona - ${await response.text()}`
|
||||
);
|
||||
}
|
||||
}}
|
||||
onClick={() => openDeleteModal(persona)}
|
||||
>
|
||||
<TrashIcon />
|
||||
</div>
|
||||
|
@ -1,15 +1,12 @@
|
||||
"use client";
|
||||
import { PersonasTable } from "./PersonaTable";
|
||||
import { FiPlusSquare } from "react-icons/fi";
|
||||
import Link from "next/link";
|
||||
import Text from "@/components/ui/text";
|
||||
import Title from "@/components/ui/title";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { AssistantsIcon } from "@/components/icons/icons";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import LabelManagement from "./LabelManagement";
|
||||
import { SubLabel } from "@/components/admin/connectors/Field";
|
||||
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
export default async function Page() {
|
||||
return (
|
||||
<div className="mx-auto container">
|
||||
@ -33,15 +30,7 @@ export default async function Page() {
|
||||
<Separator />
|
||||
|
||||
<Title>Create an Assistant</Title>
|
||||
<Link
|
||||
href="/admin/assistants/new"
|
||||
className="flex py-2 px-4 mt-2 border border-border h-fit cursor-pointer hover:bg-hover text-sm w-40"
|
||||
>
|
||||
<div className="mx-auto flex">
|
||||
<FiPlusSquare className="my-auto mr-2" />
|
||||
New Assistant
|
||||
</div>
|
||||
</Link>
|
||||
<CreateButton href="/admin/assistants/new" text="New Assistant" />
|
||||
|
||||
<Separator />
|
||||
|
||||
|
@ -11,6 +11,7 @@ import { SourceIcon } from "@/components/SourceIcon";
|
||||
import { SlackBotTable } from "./SlackBotTable";
|
||||
import { useSlackBots } from "./[bot-id]/hooks";
|
||||
import { ValidSources } from "@/lib/types";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const Main = () => {
|
||||
const {
|
||||
@ -71,27 +72,7 @@ const Main = () => {
|
||||
found in the Onyx documentation to get started!
|
||||
</p>
|
||||
|
||||
<Link
|
||||
className="
|
||||
flex
|
||||
py-2
|
||||
px-4
|
||||
mt-2
|
||||
border
|
||||
border-border
|
||||
h-fit
|
||||
cursor-pointer
|
||||
hover:bg-hover
|
||||
text-sm
|
||||
w-40
|
||||
"
|
||||
href="/admin/bots/new"
|
||||
>
|
||||
<div className="mx-auto flex">
|
||||
<FiPlusSquare className="my-auto mr-2" />
|
||||
New Slack Bot
|
||||
</div>
|
||||
</Link>
|
||||
<CreateButton href="/admin/bots/new" text="New Slack Bot" />
|
||||
|
||||
<SlackBotTable slackBots={slackBots} />
|
||||
</div>
|
||||
|
@ -40,6 +40,7 @@ import {
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const numToDisplay = 50;
|
||||
|
||||
@ -305,9 +306,13 @@ const Main = () => {
|
||||
<div className="mb-3"></div>
|
||||
|
||||
<div className="flex mb-6">
|
||||
<Link href="/admin/documents/sets/new">
|
||||
<CreateButton
|
||||
href="/admin/documents/sets/new"
|
||||
text="New Document Set"
|
||||
/>
|
||||
{/* <Link href="/admin/documents/sets/new">
|
||||
<Button variant="navigate">New Document Set</Button>
|
||||
</Link>
|
||||
</Link> */}
|
||||
</div>
|
||||
|
||||
{documentSets.length > 0 && (
|
||||
|
@ -18,6 +18,7 @@ import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { CreateRateLimitModal } from "./CreateRateLimitModal";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
import { ShieldIcon } from "@/components/icons/icons";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const BASE_URL = "/api/admin/token-rate-limits";
|
||||
const GLOBAL_TOKEN_FETCH_URL = `${BASE_URL}/global`;
|
||||
@ -138,15 +139,10 @@ function Main() {
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Button
|
||||
variant="navigate"
|
||||
size="sm"
|
||||
className="my-4"
|
||||
onClick={() => setModalIsOpen(true)}
|
||||
>
|
||||
Create a Token Rate Limit
|
||||
</Button>
|
||||
|
||||
<CreateButton
|
||||
href="/admin/token-rate-limits/new"
|
||||
text="Create a Token Rate Limit"
|
||||
/>
|
||||
{isPaidEnterpriseFeaturesEnabled && (
|
||||
<Tabs
|
||||
value={tabIndex.toString()}
|
||||
|
@ -9,6 +9,7 @@ import { fetchSS } from "@/lib/utilsSS";
|
||||
import { ErrorCallout } from "@/components/ErrorCallout";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import { ToolIcon } from "@/components/icons/icons";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
export default async function Page() {
|
||||
const toolResponse = await fetchSS("/tool");
|
||||
@ -39,27 +40,7 @@ export default async function Page() {
|
||||
<Separator />
|
||||
|
||||
<Title>Create a Tool</Title>
|
||||
<Link
|
||||
href="/admin/tools/new"
|
||||
className="
|
||||
flex
|
||||
py-2
|
||||
px-4
|
||||
mt-2
|
||||
border
|
||||
border-border
|
||||
h-fit
|
||||
cursor-pointer
|
||||
hover:bg-hover
|
||||
text-sm
|
||||
w-40
|
||||
"
|
||||
>
|
||||
<div className="mx-auto flex">
|
||||
<FiPlusSquare className="my-auto mr-2" />
|
||||
New Tool
|
||||
</div>
|
||||
</Link>
|
||||
<CreateButton href="/admin/tools/new" text="New Tool" />
|
||||
|
||||
<Separator />
|
||||
|
||||
|
@ -11,6 +11,7 @@ import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { useUser } from "@/components/user/UserProvider";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const Main = () => {
|
||||
const { popup, setPopup } = usePopup();
|
||||
@ -52,18 +53,10 @@ const Main = () => {
|
||||
<>
|
||||
{popup}
|
||||
{isAdmin && (
|
||||
<div className="my-3">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="navigate"
|
||||
onClick={() => setShowForm(true)}
|
||||
>
|
||||
Create New User Group
|
||||
</Button>
|
||||
</div>
|
||||
<CreateButton href="/admin/groups/new" text="Create New User Group" />
|
||||
)}
|
||||
{data.length > 0 && (
|
||||
<div>
|
||||
<div className="mt-2">
|
||||
<UserGroupsTable
|
||||
userGroups={data}
|
||||
setPopup={setPopup}
|
||||
|
@ -29,6 +29,7 @@ import { PageSelector } from "@/components/PageSelector";
|
||||
import { CustomCheckbox } from "@/components/CustomCheckbox";
|
||||
import Text from "@/components/ui/text";
|
||||
import { TableHeader } from "@/components/ui/table";
|
||||
import CreateButton from "@/components/ui/createButton";
|
||||
|
||||
const NUM_RESULTS_PER_PAGE = 10;
|
||||
|
||||
@ -402,11 +403,10 @@ const Main = () => {
|
||||
)}
|
||||
<div className="mb-2"></div>
|
||||
|
||||
<Link className="flex mb-3 mt-2 w-fit" href="/admin/standard-answer/new">
|
||||
<Button className="my-auto" variant="submit" size="sm">
|
||||
New Standard Answer
|
||||
</Button>
|
||||
</Link>
|
||||
<CreateButton
|
||||
href="/admin/standard-answer/new"
|
||||
text="New Standard Answer"
|
||||
/>
|
||||
|
||||
<Separator />
|
||||
|
||||
|
@ -85,7 +85,7 @@ export function Modal({
|
||||
ease-in-out
|
||||
relative
|
||||
${width ?? "w-11/12 max-w-4xl"}
|
||||
${noPadding ? "" : removeBottomPadding ? "pt-10 px-10" : "p-10"}
|
||||
${noPadding ? "" : removeBottomPadding ? "pt-8 px-8" : "p-8"}
|
||||
${className || ""}
|
||||
flex
|
||||
flex-col
|
||||
|
@ -3,6 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Check, CheckCircle, XCircle } from "lucide-react";
|
||||
import { Warning } from "@phosphor-icons/react";
|
||||
import { NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK } from "@/lib/constants";
|
||||
const popupVariants = cva(
|
||||
"fixed bottom-4 left-4 p-4 rounded-lg shadow-xl text-white z-[10000] flex items-center space-x-3 transition-all duration-300 ease-in-out",
|
||||
{
|
||||
@ -59,7 +60,23 @@ export const Popup: React.FC<PopupSpec> = ({ message, type }) => (
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
<span className="font-medium">{message}</span>
|
||||
<div className="flex flex-col justify-center items-start">
|
||||
<p className="font-medium">{message}</p>
|
||||
{type === "error" && NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK && (
|
||||
<p className="text-xs">
|
||||
Need help?{" "}
|
||||
<a
|
||||
href="https://join.slack.com/t/onyx-dot-app/shared_invite/zt-2twesxdr6-5iQitKZQpgq~hYIZ~dv3KA"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:text-red-100"
|
||||
>
|
||||
Join our community
|
||||
</a>{" "}
|
||||
for support!
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { FiTrash, FiX } from "react-icons/fi";
|
||||
import { BasicClickable } from "@/components/BasicClickable";
|
||||
import { Modal } from "../Modal";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
export const DeleteEntityModal = ({
|
||||
onClose,
|
||||
@ -20,7 +21,7 @@ export const DeleteEntityModal = ({
|
||||
includeCancelButton?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Modal width="max-w-4xl" onOutsideClick={onClose}>
|
||||
<Modal width="rounded max-w-sm w-full" onOutsideClick={onClose}>
|
||||
<>
|
||||
<div className="flex mb-4">
|
||||
<h2 className="my-auto text-2xl font-bold">
|
||||
@ -28,26 +29,20 @@ export const DeleteEntityModal = ({
|
||||
</h2>
|
||||
</div>
|
||||
<p className="mb-4">
|
||||
Click below to confirm that you want to {deleteButtonText || "delete"}{" "}
|
||||
<b>{entityName}</b>
|
||||
Are you sure you want to {deleteButtonText || "delete"}{" "}
|
||||
<b>{entityName}</b>?
|
||||
</p>
|
||||
{additionalDetails && <p className="mb-4">{additionalDetails}</p>}
|
||||
<div className="flex">
|
||||
<div className="mx-auto flex gap-x-2">
|
||||
<div className="flex items-end justify-end">
|
||||
<div className="flex gap-x-2">
|
||||
{includeCancelButton && (
|
||||
<BasicClickable onClick={onClose}>
|
||||
<div className="flex mx-2">
|
||||
<FiX className="my-auto mr-2" />
|
||||
Cancel
|
||||
</div>
|
||||
</BasicClickable>
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
<div className="flex mx-2">Cancel</div>
|
||||
</Button>
|
||||
)}
|
||||
<BasicClickable onClick={onSubmit}>
|
||||
<div className="flex mx-2">
|
||||
<FiTrash className="my-auto mr-2" />
|
||||
{deleteButtonText || "Delete"}
|
||||
</div>
|
||||
</BasicClickable>
|
||||
<Button size="sm" variant="destructive" onClick={onSubmit}>
|
||||
<div className="flex mx-2">{deleteButtonText || "Delete"}</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@ -13,7 +13,6 @@ const buttonVariants = cva(
|
||||
"bg-green-100 text-green-600 hover:bg-green-500/90 dark:bg-blue-500 dark:text-neutral-50 dark:hover:bg-green-900/90",
|
||||
"success-reverse":
|
||||
"bg-[#2BAD30] text-white hover:bg-[#45a049] dark:bg-[#2E7D32] dark:text-white dark:hover:bg-[#1B5E20]",
|
||||
|
||||
default:
|
||||
"bg-neutral-900 border-border text-neutral-50 hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
|
||||
"default-reverse":
|
||||
@ -24,6 +23,8 @@ const buttonVariants = cva(
|
||||
"bg-neutral-50 text-red-500 hover:bg-neutral-50/90 dark:bg-neutral-50 dark:text-red-900 dark:hover:bg-neutral-50/90",
|
||||
outline:
|
||||
"border border-neutral-300 bg-white hover:bg-neutral-50 hover:text-neutral-900 dark:border-neutral-800 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
|
||||
create:
|
||||
"border border-neutral-300 bg-background-50 text-neutral-700 hover:bg-neutral-100 hover:text-neutral-900 transition-colors duration-200 ease-in-out shadow-sm dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700 dark:hover:text-neutral-100",
|
||||
"outline-reverse":
|
||||
"border border-neutral-300 bg-neutral-900 hover:bg-neutral-800 hover:text-neutral-50 dark:border-neutral-800 dark:bg-white dark:hover:bg-neutral-50 dark:hover:text-neutral-900",
|
||||
secondary:
|
||||
@ -39,8 +40,6 @@ const buttonVariants = cva(
|
||||
"text-neutral-50 underline-offset-4 hover:underline dark:text-neutral-900",
|
||||
submit:
|
||||
"bg-green-500 text-inverted hover:bg-green-600/90 dark:bg-neutral-50 dark:text-blue-500 dark:hover:bg-green-100/90",
|
||||
|
||||
// "bg-blue-600 text-neutral-50 hover:bg-blue-600/80 dark:bg-blue-600 dark:text-neutral-50 dark:hover:bg-blue-600/90",
|
||||
"submit-reverse":
|
||||
"bg-neutral-50 text-blue-600 hover:bg-neutral-50/80 dark:bg-neutral-50 dark:text-blue-600 dark:hover:bg-neutral-50/90",
|
||||
navigate:
|
||||
|
22
web/src/components/ui/createButton.tsx
Normal file
22
web/src/components/ui/createButton.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { FiPlusCircle } from "react-icons/fi";
|
||||
|
||||
interface CreateButtonProps {
|
||||
href: string;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export default function CreateButton({
|
||||
href,
|
||||
text = "Create",
|
||||
}: CreateButtonProps) {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<Button className="font-normal mt-2" variant="create">
|
||||
<FiPlusCircle />
|
||||
{text}
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
}
|
@ -87,3 +87,7 @@ export const NEXT_PUBLIC_DELETE_ALL_CHATS_ENABLED =
|
||||
|
||||
export const NEXT_PUBLIC_ENABLE_CHROME_EXTENSION =
|
||||
process.env.NEXT_PUBLIC_ENABLE_CHROME_EXTENSION?.toLowerCase() === "true";
|
||||
|
||||
export const NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK =
|
||||
process.env.NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK?.toLowerCase() ===
|
||||
"true";
|
||||
|
Loading…
x
Reference in New Issue
Block a user