Update primary color palette (#497)

This commit is contained in:
Jeremy 2024-11-06 19:12:46 +03:00 committed by GitHub
parent b5c165714b
commit d948b99719
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 180 additions and 111 deletions

View file

@ -30,9 +30,9 @@
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary: 217 100% 45%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary: 213 100% 96%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
@ -40,7 +40,7 @@
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--border: 214 32% 91%;
--input: 240 5.9% 90%;
--ring: 240 10% 3.9%;
--chart-1: 12 76% 61%;
@ -65,8 +65,8 @@
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--primary: 208.69 100% 24.18%;
--primary-foreground: 207 100% 96%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
@ -142,5 +142,5 @@
}
.suggestion-highlight {
@apply bg-blue-100 hover:bg-blue-200 dark:hover:bg-blue-400/50 dark:text-blue-50 dark:bg-blue-400/40;
@apply bg-blue-200 hover:bg-blue-300 dark:hover:bg-blue-400/50 dark:text-blue-50 dark:bg-blue-500/40;
}

View file

@ -29,6 +29,7 @@ import { MultimodalInput } from './multimodal-input';
import { Toolbar } from './toolbar';
import { useScrollToBottom } from './use-scroll-to-bottom';
import { VersionFooter } from './version-footer';
import { Button } from '../ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
export interface UICanvas {
title: string;
@ -254,10 +255,10 @@ export function Canvas({
{!isMobile && (
<motion.div
className="relative w-[400px] bg-muted dark:bg-background h-dvh shrink-0"
initial={{ opacity: 0, x: windowWidth - 420, scale: 1 }}
initial={{ opacity: 0, x: 10, scale: 1 }}
animate={{
opacity: 1,
x: windowWidth - 400,
x: 0,
scale: 1,
transition: {
delay: 0.2,
@ -268,7 +269,7 @@ export function Canvas({
}}
exit={{
opacity: 0,
x: windowWidth - 420,
x: 0,
scale: 0.95,
transition: { delay: 0 },
}}
@ -370,7 +371,7 @@ export function Canvas({
}
: {
opacity: 1,
x: 0,
x: 400,
y: 0,
height: windowHeight,
width: windowWidth ? windowWidth - 400 : 'calc(100dvw-400px)',
@ -396,8 +397,9 @@ export function Canvas({
>
<div className="p-2 flex flex-row justify-between items-start">
<div className="flex flex-row gap-4 items-start">
<div
className="cursor-pointer hover:bg-muted dark:hover:bg-zinc-700 p-2 rounded-lg text-muted-foreground"
<Button
variant="outline"
className="h-fit p-2 dark:hover:bg-zinc-700"
onClick={() => {
setCanvas((currentCanvas) => ({
...currentCanvas,
@ -406,9 +408,9 @@ export function Canvas({
}}
>
<CrossIcon size={18} />
</div>
</Button>
<div className="flex flex-col pt-1">
<div className="flex flex-col">
<div className="font-medium">
{document?.title ?? canvas.title}
</div>
@ -433,58 +435,63 @@ export function Canvas({
<div className="flex flex-row gap-1">
<Tooltip>
<TooltipTrigger>
<div
className="cursor-pointer hover:bg-muted p-2 rounded-lg text-muted-foreground dark:hover:bg-zinc-700"
<TooltipTrigger asChild>
<Button
variant="outline"
className="p-2 h-fit dark:hover:bg-zinc-700"
onClick={() => {
copyToClipboard(canvas.content);
toast.success('Copied to clipboard!');
}}
>
<CopyIcon size={18} />
</div>
</Button>
</TooltipTrigger>
<TooltipContent>Copy to clipboard</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<div
className="cursor-pointer hover:bg-muted p-2 rounded-lg text-muted-foreground dark:hover:bg-zinc-700"
<TooltipTrigger asChild>
<Button
variant="outline"
className="p-2 h-fit dark:hover:bg-zinc-700 !pointer-events-auto"
onClick={() => {
handleVersionChange('prev');
}}
disabled={currentVersionIndex === 0}
>
<UndoIcon size={18} />
</div>
</Button>
</TooltipTrigger>
<TooltipContent>View Previous version</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<div
className="cursor-pointer hover:bg-muted p-2 rounded-lg text-muted-foreground dark:hover:bg-zinc-700"
<TooltipTrigger asChild>
<Button
variant="outline"
className="p-2 h-fit dark:hover:bg-zinc-700 !pointer-events-auto"
onClick={() => {
handleVersionChange('next');
}}
disabled={isCurrentVersion}
>
<RedoIcon size={18} />
</div>
</Button>
</TooltipTrigger>
<TooltipContent>View Next version</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<div
className={cx(
'cursor-pointer hover:bg-muted p-2 rounded-lg text-muted-foreground dark:hover:bg-zinc-700',
{ 'bg-muted dark:bg-zinc-700': mode === 'diff' }
)}
<TooltipTrigger asChild>
<Button
variant="outline"
className={cx('p-2 h-fit dark:hover:bg-zinc-700', {
'bg-muted': mode === 'diff',
})}
onClick={() => {
handleVersionChange('toggle');
}}
>
<DeltaIcon size={18} />
</div>
</Button>
</TooltipTrigger>
<TooltipContent>View changes</TooltipContent>
</Tooltip>

View file

@ -38,7 +38,7 @@ export function ChatHeader({ selectedModelId }: { selectedModelId: string }) {
className="order-1 md:order-2"
/>
<Button
className="hidden md:flex py-1.5 px-2 h-fit md:h-[34px] order-4 md:ml-auto"
className="bg-zinc-900 dark:bg-zinc-100 hover:bg-zinc-800 dark:hover:bg-zinc-200 text-zinc-50 dark:text-zinc-900 hidden md:flex py-1.5 px-2 h-fit md:h-[34px] order-4 md:ml-auto"
asChild
>
<Link

View file

@ -31,7 +31,7 @@ export function DocumentToolResult({
}: DocumentToolResultProps) {
return (
<div
className="cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
className="bg-background cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
onClick={(event) => {
const rect = event.currentTarget.getBoundingClientRect();

View file

@ -836,3 +836,22 @@ export const SparklesIcon = ({ size = 16 }: { size?: number }) => (
></path>
</svg>
);
export const CheckCirclFillIcon = ({ size = 16 }: { size?: number }) => {
return (
<svg
height={size}
strokeLinejoin="round"
viewBox="0 0 16 16"
width={size}
style={{ color: 'currentcolor' }}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM11.5303 6.53033L12.0607 6L11 4.93934L10.4697 5.46967L6.5 9.43934L5.53033 8.46967L5 7.93934L3.93934 9L4.46967 9.53033L5.96967 11.0303C6.26256 11.3232 6.73744 11.3232 7.03033 11.0303L11.5303 6.53033Z"
fill="currentColor"
></path>
</svg>
);
};

View file

@ -32,19 +32,14 @@ export const PreviewMessage = ({
}) => {
return (
<motion.div
className="w-full mx-auto max-w-3xl px-4 group/message "
className="w-full mx-auto max-w-3xl px-4 group/message"
initial={{ y: 5, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
data-role={message.role}
>
<div
className={cx(
'flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl',
{
'group-data-[role=user]/message:bg-muted': !canvas,
'group-data-[role=user]/message:bg-zinc-300 dark:group-data-[role=user]/message:bg-zinc-800':
canvas,
}
'group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl'
)}
>
{message.role === 'assistant' && (

View file

@ -1,6 +1,5 @@
'use client';
import { Check, ChevronDown } from 'lucide-react';
import { startTransition, useMemo, useOptimistic, useState } from 'react';
import { models } from '@/ai/models';
@ -14,7 +13,7 @@ import {
} from '@/components/ui/dropdown-menu';
import { cn } from '@/lib/utils';
import { ChevronDownIcon } from './icons';
import { CheckCirclFillIcon, ChevronDownIcon } from './icons';
export function ModelSelector({
selectedModelId,
@ -57,7 +56,7 @@ export function ModelSelector({
saveModelId(model.id);
});
}}
className="gap-4 group/item"
className="gap-4 group/item flex flex-row justify-between items-center"
data-active={model.id === optimisticModelId}
>
<div className="flex flex-col gap-1 items-start">
@ -68,7 +67,9 @@ export function ModelSelector({
</div>
)}
</div>
<Check className="size-4 ml-auto opacity-0 group-data-[active=true]/item:opacity-100" />
<div className="text-primary dark:text-primary-foreground opacity-0 group-data-[active=true]/item:opacity-100">
<CheckCirclFillIcon />
</div>
</DropdownMenuItem>
))}
</DropdownMenuContent>

View file

@ -31,7 +31,7 @@ const suggestedActions = [
{
title: 'Help me draft an essay',
label: 'about Silicon Valley',
action: 'Help me draft an essay about Silicon Valley',
action: 'Help me draft a short essay about Silicon Valley',
},
];
@ -283,7 +283,7 @@ export function MultimodalInput({
{isLoading ? (
<Button
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5"
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
onClick={(event) => {
event.preventDefault();
stop();
@ -294,7 +294,7 @@ export function MultimodalInput({
</Button>
) : (
<Button
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5"
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
onClick={(event) => {
event.preventDefault();
submitForm();
@ -306,7 +306,7 @@ export function MultimodalInput({
)}
<Button
className="rounded-full p-1.5 h-fit absolute bottom-2 right-10 m-0.5 dark:border-zinc-700"
className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
onClick={(event) => {
event.preventDefault();
fileInputRef.current?.click();

View file

@ -26,6 +26,7 @@ import {
StopIcon,
SummarizeIcon,
} from './icons';
import { Button } from '../ui/button';
type ToolProps = {
type: 'final-polish' | 'request-suggestions' | 'adjust-reading-level';
@ -61,29 +62,7 @@ const Tool = ({
}
}, [selectedTool, type]);
return (
<Tooltip open={isHovered && !isAnimating}>
<TooltipTrigger>
<motion.div
className={cx('p-3 rounded-full', {
'bg-foreground !text-background': selectedTool === type,
})}
onHoverStart={() => {
setIsHovered(true);
}}
onHoverEnd={() => {
if (selectedTool !== type) setIsHovered(false);
}}
initial={{ scale: 1, opacity: 0 }}
animate={{ opacity: 1, transition: { delay: 0.1 } }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
exit={{
scale: 0.9,
opacity: 0,
transition: { duration: 0.1 },
}}
onClick={() => {
const handleSelect = () => {
if (!isToolbarVisible && setIsToolbarVisible) {
setIsToolbarVisible(true);
return;
@ -116,6 +95,37 @@ const Tool = ({
setSelectedTool(null);
}
}
};
return (
<Tooltip open={isHovered && !isAnimating}>
<TooltipTrigger asChild>
<motion.div
className={cx('p-3 rounded-full', {
'bg-primary !text-primary-foreground': selectedTool === type,
})}
onHoverStart={() => {
setIsHovered(true);
}}
onHoverEnd={() => {
if (selectedTool !== type) setIsHovered(false);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
handleSelect();
}
}}
initial={{ scale: 1, opacity: 0 }}
animate={{ opacity: 1, transition: { delay: 0.1 } }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
exit={{
scale: 0.9,
opacity: 0,
transition: { duration: 0.1 },
}}
onClick={() => {
handleSelect();
}}
>
{selectedTool === type ? <ArrowUpIcon /> : icon}
@ -192,7 +202,7 @@ const ReadingLevelSelector = ({
className={cx(
'absolute bg-background p-3 border rounded-full flex flex-row items-center',
{
'bg-foreground text-background': currentLevel !== 2,
'bg-primary text-primary-foreground': currentLevel !== 2,
'bg-background text-foreground': currentLevel === 2,
}
)}
@ -241,37 +251,31 @@ const ReadingLevelSelector = ({
);
};
export const Toolbar = ({
export const Tools = ({
isToolbarVisible,
setIsToolbarVisible,
selectedTool,
setSelectedTool,
append,
isLoading,
stop,
setMessages,
isAnimating,
setIsToolbarVisible,
}: {
isToolbarVisible: boolean;
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
isLoading: boolean;
selectedTool: string | null;
setSelectedTool: Dispatch<SetStateAction<string | null>>;
append: (
message: Message | CreateMessage,
chatRequestOptions?: ChatRequestOptions
) => Promise<string | null | undefined>;
stop: () => void;
setMessages: Dispatch<SetStateAction<Message[]>>;
isAnimating: boolean;
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
}) => {
const toolbarRef = useRef<HTMLDivElement>(null);
const timeoutRef = useRef<NodeJS.Timeout>();
const [selectedTool, setSelectedTool] = useState<string | null>(null);
const [isAnimating, setIsAnimating] = useState(false);
useOnClickOutside(toolbarRef, () => {
setIsToolbarVisible(false);
setSelectedTool(null);
});
const Tools = (
<>
return (
<motion.div
className="flex flex-col"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
>
<AnimatePresence>
{isToolbarVisible && (
<>
@ -309,8 +313,38 @@ export const Toolbar = ({
append={append}
isAnimating={isAnimating}
/>
</>
</motion.div>
);
};
export const Toolbar = ({
isToolbarVisible,
setIsToolbarVisible,
append,
isLoading,
stop,
setMessages,
}: {
isToolbarVisible: boolean;
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
isLoading: boolean;
append: (
message: Message | CreateMessage,
chatRequestOptions?: ChatRequestOptions
) => Promise<string | null | undefined>;
stop: () => void;
setMessages: Dispatch<SetStateAction<Message[]>>;
}) => {
const toolbarRef = useRef<HTMLDivElement>(null);
const timeoutRef = useRef<NodeJS.Timeout>();
const [selectedTool, setSelectedTool] = useState<string | null>(null);
const [isAnimating, setIsAnimating] = useState(false);
useOnClickOutside(toolbarRef, () => {
setIsToolbarVisible(false);
setSelectedTool(null);
});
const startCloseTimer = () => {
if (timeoutRef.current) {
@ -389,7 +423,11 @@ export const Toolbar = ({
ref={toolbarRef}
>
{isLoading ? (
<div
<motion.div
key="stop-icon"
initial={{ scale: 1 }}
animate={{ scale: 1.4 }}
exit={{ scale: 1 }}
className="p-3"
onClick={() => {
stop();
@ -397,15 +435,24 @@ export const Toolbar = ({
}}
>
<StopIcon />
</div>
</motion.div>
) : selectedTool === 'adjust-reading-level' ? (
<ReadingLevelSelector
key="reading-level-selector"
append={append}
setSelectedTool={setSelectedTool}
isAnimating={isAnimating}
/>
) : (
Tools
<Tools
key="tools"
append={append}
isAnimating={isAnimating}
isToolbarVisible={isToolbarVisible}
selectedTool={selectedTool}
setIsToolbarVisible={setIsToolbarVisible}
setSelectedTool={setSelectedTool}
/>
)}
</motion.div>
</TooltipProvider>