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
10 changes: 5 additions & 5 deletions src/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import type * as React from "react";
import { twMerge } from "tailwind-merge";

const buttonVariants = cva(
"cursor-pointer inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors text-white dark:text-white/80",
"inline-flex items-center justify-center rounded-mc-btn text-sm font-medium transition-colors text-mc-btn-fg",
{
variants: {
variant: {
default: "bg-blue-500 hover:bg-blue-500/90 gap-1",
default: "bg-mc-btn hover:bg-mc-btn-hv gap-mc-btn-gap",
link: "underline-offset-4 hover:underline",
},
size: {
default: "px-4 py-2",
icon: "p-2",
default: "px-mc-btn-px py-mc-btn-py",
icon: "p-mc-2",
},
},
defaultVariants: {
Expand All @@ -33,7 +33,7 @@ function Button({
}: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants>) {
return (
<button
data-slot="button"
data-slot="mc-btn"
className={twMerge(clsx(buttonVariants({ variant, size, className })))}
{...props}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/file-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function FileUpload({
data-slot="file-upload"
type="button"
className={twMerge(
clsx("cursor-pointer text-gray-500 hover:text-gray-500/80", className),
clsx("cursor-pointer text-mc-fu-fg hover:text-mc-fu-hv", className),
)}
onClick={() => fileInputRef.current?.click()}
{...props}
Expand Down
22 changes: 17 additions & 5 deletions src/list.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "./tailwind.css";

import clsx from "clsx";
import { twMerge } from "tailwind-merge";

Expand Down Expand Up @@ -130,7 +132,9 @@ export const List = ({
key={key}
role-slot="list-group"
aria-label={String(groupContent || "")}
className={clsx("font-bold dark:text-gray-400 py-2 px-4 text-sm")}
className={clsx(
"font-bold text-mc-sd-mut py-mc-li-py px-mc-li-px text-sm",
)}
style={listGroupStyle}
>
{String(groupContent || " ")}
Expand All @@ -153,9 +157,12 @@ export const List = ({
key={key}
role-slot="list-item"
className={twMerge(
clsx("py-2 px-4 hover:bg-gray-200 text-gray-600 cursor-pointer", {
"bg-blue-500 text-white hover:bg-blue-600": isSelected,
}),
clsx(
"py-mc-li-py px-mc-li-px hover:bg-mc-li-hv text-mc-fg cursor-pointer",
{
"bg-mc-li-act text-mc-li-act-fg": isSelected,
},
),
)}
id={`lo_id_${index}`}
style={listItemStyle}
Expand Down Expand Up @@ -192,7 +199,12 @@ export const List = ({
const list = createList();

return (
<div style={listStyle} data-slot="list" {...props}>
<div
className={twMerge(clsx("bg-mc-bg", props.className))}
style={listStyle}
data-slot="list"
{...props}
>
{list}
</div>
);
Expand Down
30 changes: 15 additions & 15 deletions src/prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { twMerge } from "tailwind-merge";
const promptsVariants = cva("flex", {
variants: {
size: {
xs: "gap-2",
sm: "gap-3",
default: "gap-4",
md: "gap-4",
lg: "gap-5",
xs: "gap-mc-pt-layout-gap-xs",
sm: "gap-mc-pt-layout-gap-sm",
default: "gap-mc-pt-layout-gap",
md: "gap-mc-pt-layout-gap",
lg: "gap-mc-pt-layout-gap-lg",
},
},
defaultVariants: {
Expand All @@ -21,15 +21,15 @@ const promptsVariants = cva("flex", {
});

const promptVariants = cva(
"flex flex-col justify-center bg-white border border-gray-200 rounded-lg hover:border-gray-300 hover:shadow-sm transition-all duration-150 cursor-pointer",
"flex flex-col justify-center bg-mc-pt-bg border-mc-pt-brd rounded-mc-pt transition-all duration-mc-pt hover:shadow-mc-pt-el",
{
variants: {
size: {
xs: "px-3 py-2 gap-1",
sm: "px-4 py-2.5 gap-1.5",
default: "px-4 py-3 gap-2",
md: "px-5 py-3.5 gap-2",
lg: "px-6 py-4 gap-2.5",
xs: "px-mc-pt-px-xs py-mc-pt-py-xs gap-mc-pt-gap-xs",
sm: "px-mc-pt-px-sm py-mc-pt-py-sm gap-mc-pt-gap-sm",
default: "px-mc-pt-px py-mc-pt-py gap-mc-pt-gap",
md: "px-mc-pt-px-md py-mc-pt-py-md gap-mc-pt-gap",
lg: "px-mc-pt-px-lg py-mc-pt-py-lg gap-mc-pt-gap-lg",
},
},
defaultVariants: {
Expand All @@ -38,7 +38,7 @@ const promptVariants = cva(
},
);

const promptTitleVariants = cva("font-medium text-gray-900", {
const promptTitleVariants = cva("font-medium text-mc-pt-fg", {
variants: {
size: {
xs: "text-sm",
Expand All @@ -53,7 +53,7 @@ const promptTitleVariants = cva("font-medium text-gray-900", {
},
});

const promptDescriptionVariants = cva("text-gray-600", {
const promptDescriptionVariants = cva("text-mc-pt-mut", {
variants: {
size: {
xs: "text-xs",
Expand Down Expand Up @@ -106,7 +106,7 @@ export function PromptTitle({
? twMerge(clsx(promptTitleVariants({ size, className })))
: twMerge(
clsx(
"font-medium text-gray-900",
"font-medium text-mc-pt-fg",
"[div[data-size='xs']_&]:text-sm",
"[div[data-size='sm']_&]:text-base",
"[div[data-size='default']_&]:text-base",
Expand All @@ -130,7 +130,7 @@ export function PromptDescription({
? twMerge(clsx(promptDescriptionVariants({ size, className })))
: twMerge(
clsx(
"text-gray-600",
"text-mc-pt-mut",
"[div[data-size='xs']_&]:text-xs",
"[div[data-size='sm']_&]:text-sm",
"[div[data-size='default']_&]:text-sm",
Expand Down
28 changes: 12 additions & 16 deletions src/sender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function InputCount({
...props
}: InputCountProps) {
return (
<span className={clsx("text-gray-400", className)} {...props}>
<span className={clsx("text-mc-sd-mut", className)} {...props}>
{count} / {limit}
</span>
);
Expand Down Expand Up @@ -58,15 +58,15 @@ export function SenderButton({
data-slot="sender-button"
className={twMerge(
clsx(
"flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 hover:bg-blue-500/90 text-white cursor-pointer",
"flex items-center justify-center cursor-pointer size-mc-btn-ic rounded-full bg-mc-btn text-mc-btn-fg hover:bg-mc-btn-hv",
className,
),
)}
{...props}
>
{icon ?? (
<img
className="filter !brightness-0 invert"
className="filter brightness-0! invert"
src={isSending ? QuickStop : PublishNew}
alt={isSending ? "icon-quick-stop" : "icon-publish-new"}
/>
Expand Down Expand Up @@ -211,15 +211,16 @@ export function Sender({
data-slot="sender"
className={twMerge(
clsx(
"relative px-1 flex flex-col items-center border rounded-2xl",
"border-gray-200 dark:border-gray-700 shadow-sm transition-all duration-300 hover:shadow-md",
"focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500",
"relative px-1 flex flex-col items-center border rounded-mc-sd",
"bg-mc-sd-bg border-mc-sd-brd shadow-mc-sd transition-all",
"focus-within:ring-2 focus-within:ring-mc-ring focus-within:border-mc-pri",
className,
className,
),
)}
{...props}
>
<div className="absolute bottom-full left-0 w-full bg-white dark:bg-gray-50 rounded-lg shadow-amber-50 max-h-64 overflow-y-auto">
<div className="absolute bottom-full left-0 w-full bg-mc-sd-bg rounded-mc-sd-el shadow-mc-sd max-h-mc-sd-drp-max overflow-y-auto custom-scrollbar">
<Suggestion
message={message}
textareaRef={textareaRef}
Expand All @@ -234,18 +235,13 @@ export function Sender({
onKeyDown={handleKeyDown}
placeholder={placeholder}
className={clsx(
"w-full pt-4 px-4 border-0 rounded-2xl !resize-none bg-transparent",
"focus:ring-0 focus:outline-none text-gray-700 placeholder-gray-400",
"overflow-y-auto max-h-32",
"[scrollbar-gutter:stable] [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full",
"[&::-webkit-scrollbar-thumb]:cursor-auto",
"[&::-webkit-scrollbar-thumb]:bg-gray-300 dark:[&::-webkit-scrollbar-thumb]:bg-gray-600",
"[&::-webkit-scrollbar-thumb:hover]:bg-gray-400 dark:[&::-webkit-scrollbar-thumb:hover]:bg-gray-500",
"[&::-webkit-scrollbar-track]:mt-3",
"w-full pt-mc-4 px-mc-4 border-0 rounded-mc-sd resize-none! bg-transparent",
"focus:ring-0 focus:outline-none text-mc-sd-fg placeholder-mc-sd-mut",
"overflow-y-auto max-h-mc-sd-max custom-scrollbar",
)}
rows={2}
/>
<div className="flex items-center w-full px-4 py-2 gap-4">
<div className="flex items-center w-full px-mc-sd-p py-mc-li-py gap-mc-2">
{toolbar}
<SenderButton
onClick={handleSend}
Expand Down
117 changes: 116 additions & 1 deletion src/tailwind.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,118 @@
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

@theme {
/* Base */
--color-mc-bg: oklch(1 0 0); /* bg-white */
--color-mc-fg: oklch(0.2 0 0); /* text-slate-900 */
--color-mc-pri: oklch(0.62 0.21 260); /* bg-blue-600 */
--color-mc-pri-fg: oklch(1 0 0); /* text-white */
--color-mc-brd: oklch(0.87 0.01 260); /* border-slate-200 */
--color-mc-elev: oklch(1 0 0); /* bg-white */
--color-mc-mut: oklch(0.6 0 0); /* text-slate-600 */
--color-mc-mut-fg: oklch(0.55 0 0); /* text-slate-500 */
--color-mc-ring: var(--color-mc-pri); /* focus:ring-blue-600 */
--duration-mc-norm: 300ms; /* duration-300 */
--spacing-mc-1: 0.25rem; /* gap-1 */
--spacing-mc-2: 0.5rem; /* gap-2 */
--spacing-mc-3: 0.75rem; /* gap-3 */
--spacing-mc-4: 1rem; /* gap-4 */
/* Button Component*/
--color-mc-btn: var(--color-mc-pri); /* bg-blue-600 */
--color-mc-btn-fg: var(--color-mc-pri-fg); /* text-white */
--radius-mc-btn: 0.375rem; /* rounded-md */
--spacing-mc-btn-px: 1rem; /* px-4 */
--spacing-mc-btn-py: 0.5rem; /* py-2 */
--spacing-mc-btn-gap: 0.25rem; /* gap-1 */
--size-mc-btn-ic: 2rem; /* w-8 h-8 */
/* Sender Component */
--color-mc-sd-bg: var(--color-mc-elev); /* bg-white */
--color-mc-sd-brd: var(--color-mc-brd); /* border-slate-200 */
--color-mc-sd-mut: var(--color-mc-mut-fg); /* text-slate-500 */
--color-mc-sd-fg: var(--color-mc-fg); /* text-slate-900 */
--radius-mc-sd: 0.75rem; /* rounded-xl */
--radius-mc-sd-el: 0.5rem; /* rounded-lg */
--radius-mc-full: 9999px; /* rounded-full */
--shadow-mc-sd: 0 1px 3px 0 rgb(0 0 0 / 0.1); /* shadow-sm */
--shadow-mc-el: var(--shadow-mc-pt-el); /* shadow-xl */
--h-mc-sd-max: 8rem; /* max-h-32 */
--h-mc-sd-drp-max: 16rem; /* max-h-64 */
--spacing-mc-sd-p: 1rem; /* p-4 */
--spacing-mc-sd-pt: 1rem; /* pt-4 */
--spacing-mc-sd-inner-gap: var(--spacing-mc-2); /* gap-2 */
/* List Component */
--color-mc-li-act: var(--color-mc-pri); /* bg-blue-600 */
--color-mc-li-act-fg: var(--color-mc-pri-fg); /* text-white */
--color-mc-li-hv: oklch(0.96 0 0); /* hover:bg-slate-50 */
--spacing-mc-li-py: 0.5rem; /* py-2 */
--spacing-mc-li-px: 1rem; /* px-4 */
--spacing-mc-li-gap: 0.5rem; /* gap-2 */
--h-mc-li-max: 16rem; /* max-h-64 */
/* Prompt Component */
--color-mc-pt-bg: var(--color-mc-elev); /* bg-white */
--color-mc-pt-brd: var(--color-mc-brd); /* border-slate-200 */
--color-mc-pt-fg: var(--color-mc-fg); /* text-slate-900 */
--color-mc-pt-mut: var(--color-mc-mut-fg); /* text-slate-500 */
--radius-mc-pt: 0.5rem; /* rounded-lg */
--shadow-mc-pt-el: 0 10px 15px -3px rgb(0 0 0 / 0.1); /* shadow-xl */
--duration-mc-pt: var(--duration-mc-norm); /* duration-300 */
--spacing-mc-pt-px: 1rem; /* px-4 */
--spacing-mc-pt-py: 0.75rem; /* py-3 */
--spacing-mc-pt-gap: 0.5rem; /* gap-2 */
--spacing-mc-pt-px-xs: 0.75rem; /* px-3 */
--spacing-mc-pt-py-xs: 0.5rem; /* py-2 */
--spacing-mc-pt-px-sm: 1rem; /* px-4 */
--spacing-mc-pt-py-sm: 0.625rem; /* py-2.5 */
--spacing-mc-pt-gap-sm: 0.375rem; /* gap-1.5 */
--spacing-mc-pt-px-md: 1.25rem; /* px-5 */
--spacing-mc-pt-py-md: 0.875rem; /* py-3.5 */
--spacing-mc-pt-px-lg: 1.5rem; /* px-6 */
--spacing-mc-pt-py-lg: 1rem; /* py-4 */
--spacing-mc-pt-gap-lg: 0.625rem; /* gap-2.5 */
--spacing-mc-pt-layout-gap: 1rem; /* gap-4 */
--spacing-mc-pt-layout-gap-xs: 0.5rem; /* gap-2 */
--spacing-mc-pt-layout-gap-sm: 0.75rem; /* gap-3 */
--spacing-mc-pt-layout-gap-lg: 1.25rem; /* gap-5 */
/* FileUpload Component */
--color-mc-fu-fg: oklch(0.6 0 0); /* text-gray-500 */
--color-mc-fu-hv: oklch(0.45 0 0); /* hover:text-gray-700 */

/* Global */
--color-mc-sb: var(--color-mc-brd); /* border-slate-200 */
--color-mc-sb-hv: oklch(0.7 0.01 260); /* bg-slate-300 */
--w-mc-sb: 0.375rem; /* w-1.5 */
}
.dark {
@theme {
--color-mc-bg: oklch(0.15 0.01 260); /* bg-slate-900 (approx) */
--color-mc-fg: oklch(0.9 0 0); /* text-slate-100 */
--color-mc-elev: oklch(0.13 0 0); /* bg-slate-950 (approx) */
--color-mc-brd: oklch(0.3 0.01 260); /* border-slate-700 */

--color-mc-sb-hv: oklch(0.5 0.01 260);
--shadow-mc-pt-el:
0 10px 15px -3px rgb(0 0 0 / 0.5), 0 0 0 1px oklch(1 0 0 / 0.05);
}
}
@layer components {
.bg-mc-btn-hv {
background-color: color-mix(
in oklab,
var(--color-mc-pri) 90%,
transparent
); /* hover:bg-blue-600/90 */
}
.custom-scrollbar {
scrollbar-gutter: stable;
&::-webkit-scrollbar {
width: var(--w-mc-sb);
}
&::-webkit-scrollbar-thumb {
border-radius: 9999px;
background-color: var(--color-mc-sb);
&:hover {
background-color: var(--color-mc-sb-hv);
}
}
}
}
4 changes: 2 additions & 2 deletions tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ test("single prompt", () => {
);
expect(titleElement).toBeInTheDocument();
expect(descriptionElement).toBeInTheDocument();
expect(titleElement).toHaveClass("font-medium", "text-gray-900");
expect(titleElement).toHaveClass("font-medium", "text-mc-pt-fg");
expect(titleElement.tagName).toBe("H3");
expect(descriptionElement).toHaveClass("text-gray-600");
expect(descriptionElement).toHaveClass("text-mc-pt-mut");
});