Merge pull request #2318 from siiddhantt/feat/standardize-css

feat: update styles and improve accessibility across frontend
This commit is contained in:
Alex
2026-03-30 23:26:45 +01:00
committed by GitHub
101 changed files with 1483 additions and 1660 deletions

View File

@@ -37,7 +37,7 @@ function MainLayout() {
const [navOpen, setNavOpen] = useState(!(isMobile || isTablet));
return (
<div className="dark:bg-raisin-black relative h-screen overflow-hidden">
<div className="bg-background relative h-screen overflow-hidden">
<Navigation navOpen={navOpen} setNavOpen={setNavOpen} />
<ActionButtons showNewChat={true} showShare={true} />
<div

View File

@@ -21,10 +21,10 @@ export default function Hero({
}>;
return (
<div className="text-black-1000 dark:text-bright-gray flex h-full w-full flex-col items-center justify-between">
<div className="text-black-1000 dark:text-foreground flex h-full w-full flex-col items-center justify-between">
{/* Header Section */}
<div className="flex grow flex-col items-center justify-center pt-8 md:pt-0">
<div className="mb-4 flex items-center">
<div className="mb-px flex items-center">
<span className="text-4xl font-semibold">DocsGPT</span>
<img className="mb-1 inline w-14" src={DocsGPT3} alt="docsgpt" />
</div>
@@ -44,9 +44,9 @@ export default function Hero({
<button
key={key}
onClick={() => handleQuestion({ question: demo.query })}
className={`border-dark-gray text-just-black hover:bg-cultured dark:border-dim-gray dark:text-chinese-white dark:hover:bg-charleston-green w-full rounded-[66px] border bg-transparent px-6 py-[14px] text-left transition-colors ${key >= 2 ? 'hidden md:block' : ''}`}
className={`border-border text-foreground hover:bg-muted dark:hover:bg-muted/50 bg-card w-full rounded-[66px] border px-6 py-3.5 text-left transition-colors dark:bg-transparent ${key >= 2 ? 'hidden md:block' : ''}`}
>
<p className="text-black-1000 dark:text-bright-gray mb-2 font-semibold">
<p className="text-black-1000 dark:text-foreground mb-2 font-semibold">
{demo.header}
</p>
<span className="line-clamp-2 text-gray-700 opacity-60 dark:text-gray-300">

View File

@@ -328,7 +328,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
/>
</button>
)}
<div className="text-gray-4000 text-[20px] font-medium">
<div className="text-muted-foreground text-[20px] font-medium">
DocsGPT
</div>
</div>
@@ -338,7 +338,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
ref={navRef}
className={`${
!navOpen && '-ml-96 md:-ml-72'
} bg-lotion dark:border-r-purple-taupe dark:bg-chinese-black fixed top-0 z-20 flex h-full w-72 flex-col border-r border-b-0 transition-all duration-300 ease-in-out dark:text-white`}
} bg-sidebar dark:border-r-sidebar-border fixed top-0 z-20 flex h-full w-72 flex-col border-r border-b-0 transition-all duration-300 ease-in-out dark:text-white`}
>
<div
className={'visible mt-2 flex h-[6vh] w-full justify-between md:h-12'}
@@ -380,7 +380,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className={({ isActive }) =>
`${
isActive ? 'bg-transparent' : ''
} group border-silver hover:border-rainy-gray dark:border-purple-taupe sticky mx-4 mt-4 flex cursor-pointer gap-2.5 rounded-3xl border p-3 hover:bg-transparent dark:text-white`
} group border-sidebar-border hover:border-sidebar-border sticky mx-4 mt-4 flex cursor-pointer gap-2.5 rounded-3xl border p-3 hover:bg-transparent dark:text-white`
}
>
<img
@@ -388,13 +388,13 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
alt="Create new chat"
className="opacity-80 group-hover:opacity-100"
/>
<p className="text-dove-gray dark:text-chinese-silver dark:group-hover:text-bright-gray text-sm group-hover:text-neutral-600">
<p className="text-muted-foreground dark:text-foreground dark:group-hover:text-bright-gray text-sm group-hover:text-neutral-600">
{t('newChat')}
</p>
</NavLink>
<div
id="conversationsMainDiv"
className="mb-auto h-[78vh] overflow-x-hidden overflow-y-auto scrollbar-overlay dark:text-white"
className="scrollbar-overlay mb-auto h-[78vh] overflow-x-hidden overflow-y-auto dark:text-white"
>
{conversations?.loading && !isDeletingConversation && (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform">
@@ -417,9 +417,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
{recentAgents.map((agent, idx) => (
<div
key={idx}
className={`group hover:bg-bright-gray dark:hover:bg-dark-charcoal mx-4 my-auto mt-4 flex h-9 cursor-pointer items-center justify-between rounded-3xl pl-4 ${
className={`group hover:bg-sidebar-accent mx-4 my-auto mt-4 flex h-9 cursor-pointer items-center justify-between rounded-3xl pl-4 ${
agent.id === selectedAgent?.id && !conversationId
? 'bg-bright-gray dark:bg-dark-charcoal'
? 'bg-sidebar-accent'
: ''
}`}
onClick={() => handleAgentClick(agent)}
@@ -432,7 +432,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="h-6 w-6 rounded-full object-contain"
/>
</div>
<p className="text-eerie-black dark:text-bright-gray overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
<p className="text-foreground dark:text-foreground overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
{agent.name}
</p>
</div>
@@ -456,7 +456,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
))}
</div>
<div
className="hover:bg-bright-gray dark:hover:bg-dark-charcoal mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4"
className="hover:bg-sidebar-accent mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4"
onClick={() => {
dispatch(setSelectedAgent(null));
if (isMobile || isTablet) {
@@ -472,7 +472,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="h-[18px] w-[18px]"
/>
</div>
<p className="text-eerie-black dark:text-bright-gray overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
<p className="text-foreground dark:text-foreground overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
{t('manageAgents')}
</p>
</div>
@@ -480,7 +480,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
</div>
) : (
<div
className="hover:bg-bright-gray dark:hover:bg-dark-charcoal mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4"
className="hover:bg-sidebar-accent mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4"
onClick={() => {
if (isMobile || isTablet) {
setNavOpen(false);
@@ -496,7 +496,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="h-[18px] w-[18px]"
/>
</div>
<p className="text-eerie-black dark:text-bright-gray overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
<p className="text-foreground dark:text-foreground overflow-hidden text-sm leading-6 text-ellipsis whitespace-nowrap">
{t('manageAgents')}
</p>
</div>
@@ -529,8 +529,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<></>
)}
</div>
<div className="text-eerie-black flex h-auto flex-col justify-end dark:text-white">
<div className="dark:border-b-purple-taupe flex flex-col gap-2 border-b py-2">
<div className="text-foreground flex h-auto flex-col justify-end dark:text-white">
<div className="dark:border-b-sidebar-border flex flex-col gap-2 border-b py-2">
<NavLink
onClick={() => {
if (isMobile || isTablet) {
@@ -540,8 +540,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
}}
to="/settings"
className={({ isActive }) =>
`mx-4 my-auto flex h-9 cursor-pointer items-center gap-4 rounded-3xl hover:bg-gray-100 dark:hover:bg-[#28292E] ${
isActive ? 'bg-gray-3000 dark:bg-transparent' : ''
`hover:bg-sidebar-accent mx-4 my-auto flex h-9 cursor-pointer items-center gap-4 rounded-3xl ${
isActive ? 'bg-sidebar-accent' : ''
}`
}
>
@@ -552,12 +552,12 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
height={21}
className="my-auto ml-2 filter dark:invert"
/>
<p className="text-eerie-black text-sm dark:text-white">
<p className="text-foreground text-sm dark:text-white">
{t('settings.label')}
</p>
</NavLink>
</div>
<div className="text-eerie-black flex flex-col justify-end dark:text-white">
<div className="text-foreground flex flex-col justify-end dark:text-white">
<div className="flex items-center justify-between py-1">
<Help />
@@ -565,9 +565,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink
target="_blank"
to={'https://discord.gg/vN7YFfdMpj'}
className={
'rounded-full hover:bg-gray-100 dark:hover:bg-[#28292E]'
}
className={'hover:bg-sidebar-accent rounded-full'}
>
<img
src={Discord}
@@ -580,9 +578,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink
target="_blank"
to={'https://x.com/docsgptai'}
className={
'rounded-full hover:bg-gray-100 dark:hover:bg-[#28292E]'
}
className={'hover:bg-sidebar-accent rounded-full'}
>
<img
src={Twitter}
@@ -595,9 +591,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink
target="_blank"
to={'https://github.com/arc53/docsgpt'}
className={
'rounded-full hover:bg-gray-100 dark:hover:bg-[#28292E]'
}
className={'hover:bg-sidebar-accent rounded-full'}
>
<img
src={Github}
@@ -612,7 +606,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
</div>
</div>
</div>
<div className="dark:border-b-purple-taupe dark:bg-chinese-black sticky z-10 h-16 w-full border-b-2 bg-gray-50 lg:hidden">
<div className="dark:border-b-sidebar-border bg-sidebar sticky z-10 h-16 w-full border-b-2 lg:hidden">
<div className="ml-6 flex h-full items-center gap-6">
<button
className="h-6 w-6 lg:hidden"
@@ -624,7 +618,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="w-7 filter dark:invert"
/>
</button>
<div className="text-gray-4000 text-[20px] font-medium">DocsGPT</div>
<div className="text-muted-foreground text-[20px] font-medium">
DocsGPT
</div>
</div>
</div>
<DeleteConvModal

View File

@@ -5,8 +5,8 @@ export default function PageNotFound() {
const { t } = useTranslation();
return (
<div className="dark:bg-raisin-black grid min-h-screen">
<p className="text-jet dark:bg-outer-space mx-auto my-auto mt-20 flex w-full max-w-6xl flex-col place-items-center gap-6 rounded-3xl bg-gray-100 p-6 lg:p-10 xl:p-16 dark:text-gray-100">
<div className="bg-background grid min-h-screen">
<p className="text-foreground dark:bg-card mx-auto my-auto mt-20 flex w-full max-w-6xl flex-col place-items-center gap-6 rounded-3xl bg-gray-100 p-6 lg:p-10 xl:p-16">
<h1>{t('pageNotFound.title')}</h1>
<p>{t('pageNotFound.message')}</p>
<button className="pointer-cursor bg-blue-1000 hover:bg-blue-3000 mr-4 flex cursor-pointer items-center justify-center rounded-full px-4 py-2 text-white transition-colors duration-100">

View File

@@ -251,7 +251,7 @@ export default function AgentCard({
};
return (
<div
className={`relative flex h-44 flex-col justify-between rounded-[1.2rem] bg-[#F6F6F6] px-4 py-5 hover:bg-[#ECECEC] sm:w-48 sm:px-6 dark:bg-[#383838] dark:hover:bg-[#383838]/80 ${agent.status === 'published' && 'cursor-pointer'}`}
className={`bg-muted hover:bg-accent relative flex h-44 flex-col justify-between rounded-[1.2rem] px-4 py-5 sm:w-48 sm:px-6 ${agent.status === 'published' && 'cursor-pointer'}`}
onClick={(e) => {
e.stopPropagation();
handleClick();
@@ -283,17 +283,17 @@ export default function AgentCard({
className="h-7 w-7 rounded-full object-contain"
/>
{agent.status === 'draft' && (
<p className="text-xs text-black opacity-50 dark:text-[#E0E0E0]">{`(Draft)`}</p>
<p className="text-foreground text-xs opacity-50">{`(Draft)`}</p>
)}
</div>
<div className="mt-2">
<p
title={agent.name}
className="truncate px-1 text-[13px] leading-relaxed font-semibold text-[#020617] capitalize dark:text-[#E0E0E0]"
className="text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{agent.name}
</p>
<p className="dark:text-sonic-silver-light mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed text-[#64748B]">
<p className="dark:text-muted-foreground text-muted-foreground mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed">
{agent.description}
</p>
</div>
@@ -320,4 +320,4 @@ export default function AgentCard({
/>
</div>
);
}
}

View File

@@ -41,25 +41,25 @@ export default function AgentLogs() {
<div className="p-4 md:p-12">
<div className="flex items-center gap-3 px-4">
<button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
onClick={() => navigate('/agents')}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<p className="text-eerie-black dark:text-bright-gray mt-px text-sm font-semibold">
<p className="text-foreground dark:text-foreground mt-px text-sm font-semibold">
{t('agents.backToAll')}
</p>
</div>
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
<h1 className="text-eerie-black m-0 text-[32px] font-bold md:text-[40px] dark:text-white">
<h1 className="text-foreground m-0 text-[32px] font-bold md:text-[40px] dark:text-white">
{t('agents.logs.title')}
</h1>
</div>
<div className="mt-6 flex flex-col gap-3 px-4">
{agent && (
<div className="flex flex-col gap-1">
<p className="text-[#28292E] dark:text-[#E0E0E0]">{agent.name}</p>
<p className="text-xs text-[#28292E] dark:text-[#E0E0E0]/40">
<p className="text-foreground">{agent.name}</p>
<p className="text-muted-foreground text-xs">
{agent.last_used_at
? t('agents.logs.lastUsedAt') +
' ' +

View File

@@ -131,7 +131,7 @@ export default function AgentPreview() {
autoFocus={false}
/>
</div>
<p className="text-gray-4000 dark:text-sonic-silver w-full bg-transparent text-center text-xs md:inline">
<p className="text-muted-foreground w-full bg-transparent text-center text-xs md:inline">
{t('agents.preview.testMessage')}
</p>
</div>

View File

@@ -159,10 +159,10 @@ export default function AgentsList() {
return (
<div className="p-4 md:p-12">
<h1 className="text-eerie-black mb-0 text-[32px] font-bold lg:text-[40px] dark:text-[#E0E0E0]">
<h1 className="text-foreground mb-0 text-[32px] font-bold lg:text-[40px]">
{t('agents.title')}
</h1>
<p className="dark:text-gray-4000 mt-5 text-[15px] leading-6 text-[#71717A]">
<p className="text-muted-foreground mt-5 text-[15px] leading-6">
{t('agents.description')}
</p>
@@ -178,7 +178,7 @@ export default function AgentsList() {
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder={t('agents.searchPlaceholder')}
className="h-11 w-full rounded-full border border-[#E5E5E5] bg-white py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none placeholder:text-[#9CA3AF] focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white dark:shadow-none dark:placeholder:text-[#6B7280]"
className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/>
</div>
@@ -189,8 +189,8 @@ export default function AgentsList() {
onClick={() => setActiveFilter(tab.id)}
className={`rounded-full px-4 py-2 text-sm transition-colors ${
activeFilter === tab.id
? 'bg-[#E0E0E0] text-[#18181B] dark:bg-[#4A4A4A] dark:text-white'
: 'dark:text-gray bg-transparent text-[#71717A] hover:bg-[#F5F5F5] dark:hover:bg-[#383838]/50'
? 'bg-border text-foreground dark:bg-accent dark:text-white'
: 'dark:text-gray text-muted-foreground hover:bg-accent/50 bg-transparent'
}`}
>
{t(tab.labelKey)}
@@ -224,7 +224,7 @@ export default function AgentsList() {
))}
{showSearchEmptyState && (
<div className="mt-12 flex flex-col items-center justify-center gap-2 text-[#71717A]">
<div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-2">
<p className="text-lg">{t('agents.noSearchResults')}</p>
<p className="text-sm">{t('agents.tryDifferentSearch')}</p>
</div>
@@ -399,7 +399,7 @@ function AgentSection({
if (isFilteredView && isSearchingWithNoResults) {
return (
<div className="mt-12 flex flex-col items-center justify-center gap-2 text-[#71717A]">
<div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-2">
<p className="text-lg">{t('agents.noSearchResults')}</p>
<p className="text-sm">{t('agents.tryDifferentSearch')}</p>
</div>
@@ -408,11 +408,11 @@ function AgentSection({
if (isFilteredView && hasNoAgentsAtAll) {
return (
<div className="mt-12 flex flex-col items-center justify-center gap-3 text-[#71717A]">
<div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-3">
<p>{t(`agents.sections.${config.id}.emptyState`)}</p>
{config.showNewAgentButton && (
<button
className="bg-purple-30 hover:bg-violets-are-blue rounded-full px-4 py-2 text-sm text-white"
className="bg-primary hover:bg-primary/90 rounded-full px-4 py-2 text-sm text-white"
onClick={() => {
setModalFolderId(null);
setShowAgentTypeModal(true);
@@ -456,12 +456,12 @@ function AgentSection({
<div className="mt-8 flex flex-col gap-4">
<div className="flex w-full flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex flex-col gap-2">
<h2 className="flex flex-wrap items-center gap-2 text-[18px] font-semibold text-[#18181B] dark:text-[#E0E0E0]">
<h2 className="text-foreground flex flex-wrap items-center gap-2 text-[18px] font-semibold">
{config.id === 'user' && folderPath.length > 0 ? (
<>
<button
onClick={() => handleNavigateToPath(-1)}
className="text-[#71717A] hover:text-[#18181B] dark:hover:text-white"
className="text-muted-foreground hover:text-foreground dark:hover:text-white"
>
{t(`agents.sections.${config.id}.title`)}
</button>
@@ -473,7 +473,7 @@ function AgentSection({
) : (
<button
onClick={() => handleNavigateToPath(index)}
className="text-[#71717A] hover:text-[#18181B] dark:hover:text-white"
className="text-muted-foreground hover:text-foreground dark:hover:text-white"
>
{item.name}
</button>
@@ -485,7 +485,7 @@ function AgentSection({
t(`agents.sections.${config.id}.title`)
)}
</h2>
<p className="text-[13px] text-[#71717A]">
<p className="text-muted-foreground text-[13px]">
{t(`agents.sections.${config.id}.description`)}
</p>
</div>
@@ -513,12 +513,12 @@ function AgentSection({
}
}}
placeholder={t('agents.folders.newFolder')}
className="w-28 rounded-full border border-[#E5E5E5] bg-white px-4 py-2 text-sm text-[#18181B] outline-none placeholder:text-[#9CA3AF] sm:w-auto dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white dark:placeholder:text-[#6B7280]"
className="border-border bg-card text-foreground placeholder:text-muted-foreground w-28 rounded-full border px-4 py-2 text-sm outline-none sm:w-auto"
autoFocus
/>
) : (
<button
className="shrink-0 rounded-full border border-[#E5E5E5] bg-white px-4 py-2 text-sm whitespace-nowrap text-[#18181B] hover:bg-[#F5F5F5] dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white dark:hover:bg-[#383838]"
className="border-border bg-card text-foreground hover:bg-accent shrink-0 rounded-full border px-4 py-2 text-sm whitespace-nowrap"
onClick={() => {
setIsCreatingFolder(true);
setTimeout(() => newFolderInputRef.current?.focus(), 0);
@@ -529,7 +529,7 @@ function AgentSection({
))}
{config.showNewAgentButton && (
<button
className="bg-purple-30 hover:bg-violets-are-blue shrink-0 rounded-full px-4 py-2 text-sm whitespace-nowrap text-white"
className="bg-primary hover:bg-primary/90 shrink-0 rounded-full px-4 py-2 text-sm whitespace-nowrap text-white"
onClick={() => {
setModalFolderId(currentFolderId);
setShowAgentTypeModal(true);
@@ -579,7 +579,7 @@ function AgentSection({
))}
</div>
) : hasNoAgentsAtAll && currentLevelFolders.length === 0 ? (
<div className="flex h-40 w-full flex-col items-center justify-center gap-3 text-[#71717A]">
<div className="text-muted-foreground flex h-40 w-full flex-col items-center justify-center gap-3">
<p>
{currentFolderId
? t('agents.folders.empty')
@@ -587,7 +587,7 @@ function AgentSection({
</p>
{config.showNewAgentButton && !currentFolderId && (
<button
className="bg-purple-30 hover:bg-violets-are-blue ml-2 rounded-full px-4 py-2 text-sm text-white"
className="bg-primary hover:bg-primary/90 ml-2 rounded-full px-4 py-2 text-sm text-white"
onClick={() => {
setModalFolderId(currentFolderId);
setShowAgentTypeModal(true);
@@ -603,4 +603,4 @@ function AgentSection({
</div>
</div>
);
}
}

View File

@@ -70,17 +70,15 @@ export default function FolderCard({
<>
<div
className={`relative flex cursor-pointer items-center justify-between rounded-[1.2rem] px-4 py-3 sm:w-48 ${
isExpanded
? 'bg-[#E5E5E5] dark:bg-[#454545]'
: 'bg-[#F6F6F6] hover:bg-[#ECECEC] dark:bg-[#383838] dark:hover:bg-[#383838]/80'
isExpanded ? 'bg-accent' : 'bg-muted hover:bg-accent'
}`}
onClick={() => onToggleExpand(folder.id)}
>
<div className="flex items-center gap-2 overflow-hidden">
<span className="truncate text-sm font-medium text-[#18181B] dark:text-[#E0E0E0]">
<span className="text-foreground truncate text-sm font-medium">
{folder.name}
</span>
<span className="shrink-0 text-xs text-[#71717A]">
<span className="text-muted-foreground shrink-0 text-xs">
({agentCount})
</span>
</div>

View File

@@ -677,17 +677,17 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
<div className="flex flex-col px-4 pt-4 pb-2 max-[1179px]:min-h-dvh min-[1180px]:h-dvh md:px-12 md:pt-12 md:pb-3">
<div className="flex items-center gap-3 px-4">
<button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
onClick={handleCancel}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<p className="text-eerie-black dark:text-bright-gray mt-px text-sm font-semibold">
<p className="text-foreground dark:text-foreground mt-px text-sm font-semibold">
{t('agents.backToAll')}
</p>
</div>
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
<h1 className="text-eerie-black m-0 text-[32px] font-bold lg:text-[40px] dark:text-white">
<h1 className="text-foreground m-0 text-[32px] font-bold lg:text-[40px] dark:text-white">
{modeConfig[effectiveMode].heading}
</h1>
{agent.agent_type === 'workflow' && (
@@ -697,14 +697,14 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)}
<div className="flex flex-wrap items-center gap-1">
<button
className="text-purple-30 dark:text-light-gray mr-4 rounded-3xl py-2 text-sm font-medium dark:bg-transparent"
className="text-primary dark:text-foreground mr-4 rounded-3xl py-2 text-sm font-medium"
onClick={handleCancel}
>
{t('agents.form.buttons.cancel')}
</button>
{modeConfig[effectiveMode].showDelete && agent.id && (
<button
className="group border-red-2000 text-red-2000 hover:bg-red-2000 flex items-center gap-2 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
className="group border-destructive text-destructive hover:bg-destructive flex items-center gap-2 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
onClick={() => setDeleteConfirmation('ACTIVE')}
>
<span className="block h-4 w-4 bg-[url('/src/assets/red-trash.svg')] bg-contain bg-center bg-no-repeat transition-all group-hover:bg-[url('/src/assets/white-trash.svg')]" />
@@ -714,7 +714,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
{modeConfig[effectiveMode].showSaveDraft && (
<button
disabled={isJsonSchemaInvalid()}
className={`border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue flex min-w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium whitespace-nowrap transition-colors hover:text-white ${
className={`border-primary text-primary hover:bg-primary/90 flex min-w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium whitespace-nowrap transition-colors hover:text-white ${
isJsonSchemaInvalid() ? 'cursor-not-allowed opacity-30' : ''
}`}
onClick={handleSaveDraft}
@@ -730,7 +730,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)}
{modeConfig[effectiveMode].showAccessDetails && (
<button
className="group border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue flex items-center gap-2 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
className="group border-primary text-primary hover:bg-primary/90 flex items-center gap-2 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
onClick={() => navigate(`/agents/logs/${agent.id}`)}
>
<span className="block h-5 w-5 bg-[url('/src/assets/monitoring-purple.svg')] bg-contain bg-center bg-no-repeat transition-all group-hover:bg-[url('/src/assets/monitoring-white.svg')]" />
@@ -739,7 +739,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)}
{modeConfig[effectiveMode].showAccessDetails && (
<button
className="hover:bg-vi</button>olets-are-blue border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
onClick={() => setAgentDetails('ACTIVE')}
>
{t('agents.form.buttons.accessDetails')}
@@ -747,7 +747,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)}
<button
disabled={!isPublishable() || !hasChanges}
className={`${!isPublishable() || !hasChanges ? 'cursor-not-allowed opacity-30' : ''} bg-purple-30 hover:bg-violets-are-blue flex min-w-28 items-center justify-center rounded-3xl px-5 py-2 text-sm font-medium whitespace-nowrap text-white`}
className={`${!isPublishable() || !hasChanges ? 'cursor-not-allowed opacity-30' : ''} bg-primary hover:bg-primary/90 flex min-w-28 items-center justify-center rounded-3xl px-5 py-2 text-sm font-medium whitespace-nowrap text-white`}
onClick={handlePublish}
>
<span className="flex items-center justify-center transition-all duration-200">
@@ -760,21 +760,21 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
</button>
</div>
</div>
<div className="mt-3 flex w-full flex-1 grid-cols-5 flex-col gap-10 rounded-[30px] bg-[#F6F6F6] p-5 max-[1179px]:overflow-visible min-[1180px]:grid min-[1180px]:gap-5 min-[1180px]:overflow-hidden dark:bg-[#383838]">
<div className="bg-muted dark:bg-background mt-3 flex w-full flex-1 grid-cols-5 flex-col gap-10 rounded-[30px] p-5 max-[1179px]:overflow-visible min-[1180px]:grid min-[1180px]:gap-5 min-[1180px]:overflow-hidden">
<div className="scrollbar-overlay col-span-2 flex flex-col gap-5 max-[1179px]:overflow-visible min-[1180px]:max-h-full min-[1180px]:overflow-y-auto min-[1180px]:pr-3">
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.meta')}
</h2>
<input
className="border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-3 w-full rounded-3xl border bg-white px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E]"
className="border-border text-foreground dark:text-foreground dark:placeholder:text-silver bg-card dark:border-border mt-3 w-full rounded-3xl border px-5 py-3 text-sm outline-hidden placeholder:text-gray-400"
type="text"
value={agent.name}
placeholder={t('agents.form.placeholders.agentName')}
onChange={(e) => setAgent({ ...agent, name: e.target.value })}
/>
<textarea
className="border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-3 h-32 w-full rounded-xl border bg-white px-5 py-4 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E]"
className="border-border text-foreground dark:text-foreground dark:placeholder:text-silver bg-card dark:border-border mt-3 h-32 w-full rounded-xl border px-5 py-4 text-sm outline-hidden placeholder:text-gray-400"
placeholder={t('agents.form.placeholders.describeAgent')}
value={agent.description}
onChange={(e) =>
@@ -784,7 +784,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
<div className="mt-3">
<FileUpload
showPreview
className="dark:bg-raisin-black"
className="bg-card"
onUpload={handleUpload}
onRemove={() => setImageFile(null)}
uploadText={[
@@ -800,7 +800,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
/>
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.source')}
</h2>
@@ -809,10 +809,10 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
<button
ref={sourceAnchorButtonRef}
onClick={() => setIsSourcePopupOpen(!isSourcePopupOpen)}
className={`border-silver dark:bg-raisin-black w-full truncate rounded-3xl border bg-white px-5 py-3 text-left text-sm dark:border-[#7E7E7E] ${
className={`border-border bg-card dark:border-border w-full truncate rounded-3xl border px-5 py-3 text-left text-sm ${
selectedSourceIds.size > 0
? 'text-jet dark:text-bright-gray'
: 'dark:text-silver text-gray-400'
? 'text-foreground dark:text-foreground'
: 'dark:text-muted-foreground text-gray-400'
}`}
>
{selectedSourceIds.size > 0
@@ -892,17 +892,13 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}
size="w-full"
rounded="3xl"
border="border"
buttonClassName="bg-white dark:bg-[#222327] border-silver dark:border-[#7E7E7E]"
optionsClassName="bg-white dark:bg-[#383838] border-silver dark:border-[#7E7E7E]"
placeholder={t('agents.form.placeholders.chunksPerQuery')}
placeholderClassName="text-gray-400 dark:text-silver"
contentSize="text-sm"
/>
</div>
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<div className="flex flex-wrap items-end gap-1">
<div className="min-w-20 grow basis-full sm:basis-0">
<Prompts
@@ -920,30 +916,24 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}
setPrompts={(newPrompts) => dispatch(setPrompts(newPrompts))}
title={t('agents.form.sections.prompt')}
titleClassName="text-lg font-semibold dark:text-[#E0E0E0]"
titleClassName="text-lg font-semibold"
showAddButton={false}
dropdownProps={{
size: 'w-full',
rounded: '3xl',
border: 'border',
buttonClassName:
'bg-white dark:bg-[#222327] border-silver dark:border-[#7E7E7E]',
optionsClassName:
'bg-white dark:bg-[#383838] border-silver dark:border-[#7E7E7E]',
placeholderClassName: 'text-gray-400 dark:text-silver',
contentSize: 'text-sm',
}}
/>
</div>
<button
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue min-w-20 shrink-0 basis-full rounded-3xl border-2 border-solid px-5 py-[11px] text-sm whitespace-nowrap transition-colors hover:text-white sm:basis-auto"
className="border-primary text-primary hover:bg-primary/90 min-w-20 shrink-0 basis-full rounded-3xl border border-solid px-5 py-3 text-sm whitespace-nowrap transition-colors hover:text-white sm:basis-auto"
onClick={() => setAddPromptModal('ACTIVE')}
>
{t('agents.form.buttons.add')}
</button>
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.tools')}
</h2>
@@ -951,10 +941,10 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
<button
ref={toolAnchorButtonRef}
onClick={() => setIsToolsPopupOpen(!isToolsPopupOpen)}
className={`border-silver dark:bg-raisin-black w-full truncate rounded-3xl border bg-white px-5 py-3 text-left text-sm dark:border-[#7E7E7E] ${
className={`border-border bg-card dark:border-border w-full truncate rounded-3xl border px-5 py-3 text-left text-sm ${
selectedTools.length > 0
? 'text-jet dark:text-bright-gray'
: 'dark:text-silver text-gray-400'
? 'text-foreground dark:text-foreground'
: 'dark:text-muted-foreground text-gray-400'
}`}
>
{selectedTools.length > 0
@@ -992,7 +982,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
/>
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.agentType')}
</h2>
@@ -1010,16 +1000,12 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}
size="w-full"
rounded="3xl"
border="border"
buttonClassName="bg-white dark:bg-[#222327] border-silver dark:border-[#7E7E7E]"
optionsClassName="bg-white dark:bg-[#383838] border-silver dark:border-[#7E7E7E]"
placeholder={t('agents.form.placeholders.selectType')}
placeholderClassName="text-gray-400 dark:text-silver"
contentSize="text-sm"
/>
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.models')}
</h2>
@@ -1027,10 +1013,10 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
<button
ref={modelAnchorButtonRef}
onClick={() => setIsModelsPopupOpen(!isModelsPopupOpen)}
className={`border-silver dark:bg-raisin-black w-full truncate rounded-3xl border bg-white px-5 py-3 text-left text-sm dark:border-[#7E7E7E] ${
className={`border-border bg-card dark:border-border w-full truncate rounded-3xl border px-5 py-3 text-left text-sm ${
selectedModelIds.size > 0
? 'text-jet dark:text-bright-gray'
: 'dark:text-silver text-gray-400'
? 'text-foreground dark:text-foreground'
: 'dark:text-muted-foreground text-gray-400'
}`}
>
{selectedModelIds.size > 0
@@ -1082,20 +1068,16 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}
size="w-full"
rounded="3xl"
border="border"
buttonClassName="bg-white dark:bg-[#222327] border-silver dark:border-[#7E7E7E]"
optionsClassName="bg-white dark:bg-[#383838] border-silver dark:border-[#7E7E7E]"
placeholder={t(
'agents.form.placeholders.selectDefaultModel',
)}
placeholderClassName="text-gray-400 dark:text-silver"
contentSize="text-sm"
/>
</div>
)}
</div>
</div>
<div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="bg-card rounded-[30px] px-6 py-3">
<button
onClick={() =>
setIsAdvancedSectionExpanded(!isAdvancedSectionExpanded)
@@ -1148,7 +1130,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
"additionalProperties": false
}`}
rows={9}
className={`border-silver text-jet dark:bg-raisin-black dark:text-bright-gray mt-2 w-full rounded-2xl border bg-white px-4 py-3 font-mono text-sm outline-hidden dark:border-[#7E7E7E]`}
className={`border-border text-foreground dark:text-foreground bg-card dark:border-border mt-2 w-full rounded-2xl border px-4 py-3 font-mono text-sm outline-hidden`}
/>
{jsonSchemaText.trim() !== '' && (
<div
@@ -1194,7 +1176,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}}
className={`relative h-6 w-11 rounded-full transition-colors ${
agent.limited_token_mode
? 'bg-purple-30'
? 'bg-primary'
: 'bg-gray-300 dark:bg-gray-600'
}`}
>
@@ -1219,7 +1201,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}
disabled={!agent.limited_token_mode}
placeholder={t('agents.form.placeholders.enterTokenLimit')}
className={`border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-2 w-full rounded-3xl border bg-white px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E] ${
className={`border-border text-foreground dark:text-foreground dark:placeholder:text-silver bg-card dark:border-border mt-2 w-full rounded-3xl border px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 ${
!agent.limited_token_mode
? 'cursor-not-allowed opacity-50'
: ''
@@ -1250,7 +1232,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
}}
className={`relative h-6 w-11 rounded-full transition-colors ${
agent.limited_request_mode
? 'bg-purple-30'
? 'bg-primary'
: 'bg-gray-300 dark:bg-gray-600'
}`}
>
@@ -1277,7 +1259,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
placeholder={t(
'agents.form.placeholders.enterRequestLimit',
)}
className={`border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-2 w-full rounded-3xl border bg-white px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E] ${
className={`border-border text-foreground dark:text-foreground dark:placeholder:text-silver bg-card dark:border-border mt-2 w-full rounded-3xl border px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 ${
!agent.limited_request_mode
? 'cursor-not-allowed opacity-50'
: ''
@@ -1288,7 +1270,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)}
</div>
</div>
<div className="col-span-3 flex flex-col gap-2 max-[1179px]:h-auto max-[1179px]:px-0 max-[1179px]:py-0 min-[1180px]:h-full min-[1180px]:py-2 dark:text-[#E0E0E0]">
<div className="col-span-3 flex flex-col gap-2 max-[1179px]:h-auto max-[1179px]:px-0 max-[1179px]:py-0 min-[1180px]:h-full min-[1180px]:py-2">
<h2 className="text-lg font-semibold">
{t('agents.form.sections.preview')}
</h2>
@@ -1331,7 +1313,7 @@ function AgentPreviewArea() {
const { t } = useTranslation();
const selectedAgent = useSelector(selectSelectedAgent);
return (
<div className="dark:bg-raisin-black w-full rounded-[30px] border border-[#F6F6F6] bg-white max-[1179px]:h-[600px] min-[1180px]:h-full dark:border-[#7E7E7E]">
<div className="bg-card dark:border-border w-full rounded-[30px] border border-[#F6F6F6] max-[1179px]:h-[600px] min-[1180px]:h-full">
{selectedAgent?.status === 'published' ? (
<div className="flex h-full w-full flex-col overflow-hidden rounded-[30px]">
<AgentPreview />
@@ -1339,7 +1321,7 @@ function AgentPreviewArea() {
) : (
<div className="flex h-full w-full flex-col items-center justify-center gap-2">
<span className="block h-12 w-12 bg-[url('/src/assets/science-spark.svg')] bg-contain bg-center bg-no-repeat transition-all dark:bg-[url('/src/assets/science-spark-dark.svg')]" />{' '}
<p className="dark:text-gray-4000 text-xs text-[#18181B]">
<p className="text-muted-foreground text-xs">
{t('agents.form.preview.publishedPreview')}
</p>
</div>

View File

@@ -143,7 +143,7 @@ export default function SharedAgent() {
alt="No agent found"
className="mx-auto mb-6 h-32 w-32"
/>
<p className="dark:text-gray-4000 text-center text-lg text-[#71717A]">
<p className="text-muted-foreground text-center text-lg">
{t('agents.shared.notFound')}
</p>
</div>
@@ -157,7 +157,7 @@ export default function SharedAgent() {
alt="agent-logo"
className="h-6 w-6 rounded-full object-contain"
/>
<h2 className="text-eerie-black text-lg font-semibold dark:text-[#E0E0E0]">
<h2 className="text-foreground text-lg font-semibold">
{sharedAgent.name}
</h2>
</div>
@@ -186,7 +186,7 @@ export default function SharedAgent() {
autoFocus={false}
/>
</div>
<p className="text-gray-4000 dark:text-sonic-silver hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full">
<p className="text-muted-foreground hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full">
{t('tagline')}
</p>
</div>

View File

@@ -10,7 +10,7 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
agent.shared_metadata !== null &&
Object.keys(agent.shared_metadata).length > 0;
return (
<div className="border-dark-gray dark:border-grey flex w-full max-w-[720px] flex-col rounded-3xl border p-6 shadow-xs sm:w-fit sm:min-w-[480px]">
<div className="border-border dark:border-border flex w-full max-w-[720px] flex-col rounded-3xl border p-6 shadow-xs sm:w-fit sm:min-w-[480px]">
<div className="flex items-center gap-3">
<div className="flex h-12 w-12 items-center justify-center overflow-hidden rounded-full p-1">
<AgentImage
@@ -19,10 +19,10 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
/>
</div>
<div className="flex max-h-[92px] w-[80%] flex-col gap-px">
<h2 className="text-eerie-black text-base font-semibold sm:text-lg dark:text-[#E0E0E0]">
<h2 className="text-foreground text-base font-semibold sm:text-lg">
{agent.name}
</h2>
<p className="dark:text-gray-4000 overflow-y-auto text-xs text-wrap break-all text-[#71717A] sm:text-sm">
<p className="text-muted-foreground overflow-y-auto text-xs text-wrap break-all sm:text-sm">
{agent.description}
</p>
</div>
@@ -30,12 +30,12 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
{hasSharedMetadata && (
<div className="mt-4 flex items-center gap-8">
{agent.shared_metadata?.shared_by && (
<p className="text-eerie-black text-xs font-light sm:text-sm dark:text-[#E0E0E0]">
<p className="text-foreground text-xs font-light sm:text-sm">
by {agent.shared_metadata.shared_by}
</p>
)}
{agent.shared_metadata?.shared_at && (
<p className="dark:text-gray-4000 text-xs font-light text-[#71717A] sm:text-sm">
<p className="text-muted-foreground text-xs font-light sm:text-sm">
Shared on{' '}
{new Date(agent.shared_metadata.shared_at).toLocaleString(
'en-US',
@@ -54,14 +54,14 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
)}
{agent.tool_details && agent.tool_details.length > 0 && (
<div className="mt-8">
<p className="text-eerie-black text-sm font-semibold sm:text-base dark:text-[#E0E0E0]">
<p className="text-foreground text-sm font-semibold sm:text-base">
Connected Tools
</p>
<div className="mt-2 flex flex-wrap gap-2">
{agent.tool_details.map((tool, index) => (
<span
key={index}
className="bg-bright-gray text-eerie-black dark:bg-dark-charcoal flex items-center gap-1 rounded-full px-3 py-1 text-xs font-light dark:text-[#E0E0E0]"
className="bg-bright-gray text-foreground dark:bg-card flex items-center gap-1 rounded-full px-3 py-1 text-xs font-light"
>
<img
src={`/toolIcons/tool_${tool.name}.svg`}

View File

@@ -579,12 +579,12 @@ function WorkflowBuilderInner() {
]);
return (
<div className="bg-lotion dark:bg-outer-space flex h-screen w-full flex-col">
<div className="border-light-silver dark:bg-raisin-black flex items-center justify-between border-b bg-white px-6 py-4 dark:border-[#3A3A3A]">
<div className="bg-background flex h-screen w-full flex-col">
<div className="border-border bg-card flex items-center justify-between border-b px-6 py-4">
<div className="flex items-center gap-4">
<button
onClick={() => navigate('/agents')}
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
@@ -613,7 +613,7 @@ function WorkflowBuilderInner() {
{showWorkflowSettings && (
<div
ref={workflowSettingsRef}
className="dark:bg-raisin-black absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border border-[#E5E5E5] bg-white p-4 shadow-lg dark:border-[#3A3A3A]"
className="border-border bg-card absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border p-4 shadow-lg"
>
<div className="mb-3">
<label className="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">
@@ -623,7 +623,7 @@ function WorkflowBuilderInner() {
type="text"
value={workflowName}
onChange={(e) => setWorkflowName(e.target.value)}
className="focus:ring-purple-30 w-full rounded-lg border border-[#E5E5E5] bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2"
placeholder="Enter workflow name"
/>
</div>
@@ -634,14 +634,14 @@ function WorkflowBuilderInner() {
<textarea
value={workflowDescription}
onChange={(e) => setWorkflowDescription(e.target.value)}
className="focus:ring-purple-30 w-full rounded-lg border border-[#E5E5E5] bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2"
rows={3}
placeholder="Describe what this workflow does"
/>
</div>
<button
onClick={() => setShowWorkflowSettings(false)}
className="bg-violets-are-blue hover:bg-purple-30 w-full rounded-lg px-3 py-2 text-sm font-medium text-white"
className="bg-primary text-primary-foreground hover:bg-primary/90 w-full rounded-lg px-3 py-2 text-sm font-medium"
>
Done
</button>
@@ -660,7 +660,7 @@ function WorkflowBuilderInner() {
}
setShowPreview(true);
}}
className="flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-gray-200 dark:hover:bg-[#383838]"
className="border-border bg-card text-foreground hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium transition-colors"
>
<Play size={16} />
Preview
@@ -668,7 +668,7 @@ function WorkflowBuilderInner() {
<button
onClick={handlePublish}
disabled={isPublishing}
className="bg-violets-are-blue hover:bg-purple-30 rounded-full px-6 py-2 text-sm font-medium text-white shadow-sm transition-colors disabled:opacity-50"
className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-full px-6 py-2 text-sm font-medium shadow-sm transition-colors disabled:opacity-50"
>
{isPublishing ? 'Publishing...' : 'Publish'}
</button>
@@ -705,20 +705,20 @@ function WorkflowBuilderInner() {
)}
<div className="flex flex-1 overflow-hidden">
<div className="border-light-silver dark:bg-raisin-black flex w-64 flex-col gap-6 border-r bg-gray-50 p-4 dark:border-[#3A3A3A]">
<div className="border-border bg-muted flex w-64 flex-col gap-6 border-r p-4">
<div>
<h3 className="mb-3 text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
Core Nodes
</h3>
<div className="flex flex-col gap-2">
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'agent')
}
>
<div className="text-violets-are-blue group-hover:bg-violets-are-blue flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-purple-100 transition-colors group-hover:text-white">
<div className="bg-primary/10 text-primary group-hover:bg-primary group-hover:text-primary-foreground flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors">
<Bot size={18} />
</div>
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">
@@ -726,7 +726,7 @@ function WorkflowBuilderInner() {
</span>
</div>
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'end')
@@ -740,7 +740,7 @@ function WorkflowBuilderInner() {
</span>
</div>
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'note')
@@ -762,7 +762,7 @@ function WorkflowBuilderInner() {
</h3>
<div className="flex flex-col gap-2">
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'state')
@@ -784,10 +784,7 @@ function WorkflowBuilderInner() {
</div>
</div>
<div
ref={reactFlowWrapper}
className="dark:bg-raisin-black/10 relative flex-1 bg-gray-50"
>
<div ref={reactFlowWrapper} className="bg-muted relative flex-1">
<ReactFlow
nodes={nodes}
edges={edges}
@@ -807,9 +804,9 @@ function WorkflowBuilderInner() {
{showNodeConfig && selectedNode && (
<div
ref={configPanelRef}
className="border-light-silver dark:bg-raisin-black absolute top-4 right-4 w-96 rounded-2xl border bg-white shadow-[0px_4px_40px_-3px_#0000001A] dark:border-[#3A3A3A]"
className="border-border bg-card absolute top-4 right-4 w-96 rounded-2xl border shadow-[0px_4px_40px_-3px_#0000001A]"
>
<div className="border-light-silver flex items-center justify-between border-b p-4 dark:border-[#3A3A3A]">
<div className="border-border flex items-center justify-between border-b p-4">
<h3 className="font-semibold text-gray-900 dark:text-white">
{selectedNode.type === 'start' && 'Start Node'}
{selectedNode.type === 'end' && 'End Node'}
@@ -827,7 +824,7 @@ function WorkflowBuilderInner() {
<div className="max-h-[calc(100vh-200px)] overflow-y-auto p-4">
<div className="mb-4 flex flex-col gap-2">
<div className="rounded-lg bg-gray-50 p-3 dark:bg-[#2C2C2C]">
<div className="bg-muted rounded-lg p-3">
<div className="mb-1 text-xs text-gray-500 dark:text-gray-400">
Node ID
</div>
@@ -856,7 +853,7 @@ function WorkflowBuilderInner() {
label: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="Enter node title"
/>
</div>
@@ -945,7 +942,7 @@ function WorkflowBuilderInner() {
},
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={3}
placeholder="System prompt for the agent"
/>
@@ -967,7 +964,7 @@ function WorkflowBuilderInner() {
},
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={4}
placeholder="Use {{variable}} for dynamic content"
/>
@@ -990,7 +987,7 @@ function WorkflowBuilderInner() {
},
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="Variable name for output"
/>
</div>
@@ -1057,7 +1054,7 @@ function WorkflowBuilderInner() {
content: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={4}
placeholder="Enter note content"
/>
@@ -1078,7 +1075,7 @@ function WorkflowBuilderInner() {
variable: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="e.g. analysis_type"
/>
</div>
@@ -1094,7 +1091,7 @@ function WorkflowBuilderInner() {
value: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="e.g. price_check"
/>
</div>
@@ -1125,7 +1122,7 @@ function WorkflowBuilderInner() {
<SheetContent
side="right"
showCloseButton={false}
className="dark:bg-raisin-black w-full max-w-none p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px] dark:border-[#3A3A3A]"
className="border-border bg-card w-full max-w-none p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px]"
>
<WorkflowPreview
workflowData={{

View File

@@ -41,4 +41,4 @@ export const agentSectionsConfig = [
selectData: selectSharedAgents,
updateAction: setSharedAgents,
},
];
];

View File

@@ -33,7 +33,7 @@ export default function AgentTypeModal({
onClick={onClose}
>
<div
className="relative w-full max-w-lg rounded-xl bg-white p-8 shadow-2xl dark:bg-[#1e1e1e]"
className="bg-card relative w-full max-w-lg rounded-xl p-8 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<button
@@ -43,7 +43,7 @@ export default function AgentTypeModal({
<X size={20} />
</button>
<h2 className="text-jet dark:text-bright-gray mb-3 text-2xl font-bold">
<h2 className="text-foreground dark:text-foreground mb-3 text-2xl font-bold">
Create New Agent
</h2>
<p className="mb-8 text-sm text-gray-500 dark:text-gray-400">
@@ -53,13 +53,13 @@ export default function AgentTypeModal({
<div className="flex flex-col gap-4">
<button
onClick={() => handleSelect('normal')}
className="hover:border-purple-30 hover:bg-purple-30/5 dark:hover:border-purple-30 dark:hover:bg-purple-30/10 group flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all dark:border-[#2E2F34]"
className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group dark:border-border flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all"
>
<div className="dark:bg-purple-30/20 bg-purple-30/10 text-purple-30 group-hover:bg-purple-30 flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary/90 flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<Bot size={28} />
</div>
<div className="flex-1">
<h3 className="text-jet dark:text-bright-gray mb-2 text-lg font-semibold">
<h3 className="text-foreground dark:text-foreground mb-2 text-lg font-semibold">
Classic Agent
</h3>
<p className="text-sm leading-relaxed text-gray-600 dark:text-gray-400">
@@ -71,13 +71,13 @@ export default function AgentTypeModal({
<button
onClick={() => handleSelect('workflow')}
className="hover:border-violets-are-blue hover:bg-violets-are-blue/5 dark:hover:border-violets-are-blue dark:hover:bg-violets-are-blue/10 group flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all dark:border-[#2E2F34]"
className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group dark:border-border flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all"
>
<div className="dark:bg-violets-are-blue/20 bg-violets-are-blue/10 text-violets-are-blue group-hover:bg-violets-are-blue flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<Workflow size={28} />
</div>
<div className="flex-1">
<h3 className="text-jet dark:text-bright-gray mb-2 text-lg font-semibold">
<h3 className="text-foreground dark:text-foreground mb-2 text-lg font-semibold">
Workflow Agent
</h3>
<p className="text-sm leading-relaxed text-gray-600 dark:text-gray-400">

View File

@@ -18,4 +18,4 @@ export default function Agents() {
<Route path="/workflow/edit/:agentId" element={<WorkflowBuilder />} />
</Routes>
);
}
}

View File

@@ -1,4 +1,10 @@
export type NodeType = 'start' | 'end' | 'agent' | 'note' | 'state' | 'condition';
export type NodeType =
| 'start'
| 'end'
| 'agent'
| 'note'
| 'state'
| 'condition';
export interface ConditionCase {
name?: string;

View File

@@ -2,13 +2,13 @@ import 'reactflow/dist/style.css';
import {
AlertCircle,
ChartColumn,
Bot,
ChartColumn,
Database,
Flag,
GitBranch,
Loader2,
Link,
Loader2,
Pencil,
Play,
Plus,
@@ -1355,12 +1355,12 @@ function WorkflowBuilderInner() {
return (
<>
<MobileBlocker />
<div className="bg-lotion dark:bg-outer-space fixed inset-0 z-50 hidden h-screen w-full flex-col md:flex">
<div className="border-light-silver dark:bg-raisin-black flex items-center justify-between border-b bg-white px-6 py-4 dark:border-[#3A3A3A]">
<div className="bg-background dark:bg-outer-space fixed inset-0 z-50 hidden h-screen w-full flex-col md:flex">
<div className="border-border bg-card dark:bg-background flex items-center justify-between border-b px-6 py-4">
<div className="flex items-center gap-4">
<button
onClick={navigateBackToAgents}
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
@@ -1390,7 +1390,7 @@ function WorkflowBuilderInner() {
{showWorkflowSettings && (
<div
ref={workflowSettingsRef}
className="dark:bg-raisin-black absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border border-[#E5E5E5] bg-white p-4 shadow-lg dark:border-[#3A3A3A]"
className="border-border bg-card absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border p-4 shadow-lg"
>
<div className="mb-3">
<label className="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">
@@ -1400,7 +1400,7 @@ function WorkflowBuilderInner() {
type="text"
value={workflowName}
onChange={(e) => setWorkflowName(e.target.value)}
className="focus:ring-purple-30 w-full rounded-lg border border-[#E5E5E5] bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="focus:ring-ring border-border bg-card w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2 dark:text-white"
placeholder="Enter workflow name"
/>
</div>
@@ -1411,7 +1411,7 @@ function WorkflowBuilderInner() {
<textarea
value={workflowDescription}
onChange={(e) => setWorkflowDescription(e.target.value)}
className="focus:ring-purple-30 w-full rounded-lg border border-[#E5E5E5] bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="focus:ring-ring border-border bg-card w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2 dark:text-white"
rows={3}
placeholder="Describe what this workflow does"
/>
@@ -1441,23 +1441,23 @@ function WorkflowBuilderInner() {
uploadText={[
{
text: 'Click to upload',
colorClass: 'text-violets-are-blue',
colorClass: 'text-primary',
},
{
text: ' or drag and drop',
colorClass: 'text-gray-500',
colorClass: 'text-muted-foreground',
},
]}
className="rounded-lg border-2 border-dashed border-[#E5E5E5] p-3 text-center transition-colors dark:border-[#3A3A3A] dark:bg-[#2C2C2C]"
className="border-border rounded-lg border-2 border-dashed p-3 text-center transition-colors"
/>
<p className="mt-1 text-[11px] text-gray-500 dark:text-gray-400">
<p className="text-muted-foreground mt-1 text-[11px]">
Image updates are included the next time you save.
</p>
</div>
<button
onClick={handleWorkflowSettingsDone}
disabled={isPublishing}
className="bg-violets-are-blue hover:bg-purple-30 w-full rounded-lg px-3 py-2 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-50"
className="bg-primary hover:bg-primary/90 w-full rounded-lg px-3 py-2 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-50"
>
Done
</button>
@@ -1468,7 +1468,7 @@ function WorkflowBuilderInner() {
<div className="flex items-center gap-2">
<button
onClick={() => setShowWorkflowSettings((prev) => !prev)}
className="flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-gray-200 dark:hover:bg-[#383838]"
className="border-border bg-card hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium text-gray-700 transition-colors dark:text-gray-200"
>
<Settings2 size={16} />
Details
@@ -1476,7 +1476,7 @@ function WorkflowBuilderInner() {
{canManageAgent && (
<button
onClick={() => navigate(`/agents/logs/${effectiveAgentId}`)}
className="flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-gray-200 dark:hover:bg-[#383838]"
className="border-border bg-card hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium text-gray-700 transition-colors dark:text-gray-200"
>
<ChartColumn size={16} />
Logs
@@ -1485,7 +1485,7 @@ function WorkflowBuilderInner() {
{canManageAgent && (
<button
onClick={() => setAgentDetails('ACTIVE')}
className="flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-gray-200 dark:hover:bg-[#383838]"
className="border-border bg-card hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium text-gray-700 transition-colors dark:text-gray-200"
>
<Link size={16} />
Access Details
@@ -1495,7 +1495,7 @@ function WorkflowBuilderInner() {
<button
onClick={() => setDeleteConfirmation('ACTIVE')}
disabled={isDeletingAgent}
className="flex items-center gap-2 rounded-full border border-red-200 bg-white px-4 py-2 text-sm font-medium text-red-600 transition-colors hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-red-900/30 dark:bg-[#2C2C2C] dark:text-red-400 dark:hover:bg-red-900/10"
className="bg-card flex items-center gap-2 rounded-full border border-red-200 px-4 py-2 text-sm font-medium text-red-600 transition-colors hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-red-900/30 dark:text-red-400 dark:hover:bg-red-900/10"
>
<Trash2 size={16} />
{isDeletingAgent ? 'Deleting...' : 'Delete'}
@@ -1511,7 +1511,7 @@ function WorkflowBuilderInner() {
}
setShowPreview(true);
}}
className="flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-gray-200 dark:hover:bg-[#383838]"
className="border-border bg-card hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium text-gray-700 transition-colors dark:text-gray-200"
>
<Play size={16} />
Preview
@@ -1521,8 +1521,8 @@ function WorkflowBuilderInner() {
disabled={isPrimaryActionDisabled}
className={`relative inline-flex items-center justify-center rounded-full px-6 py-2 text-sm font-medium shadow-sm transition-colors disabled:cursor-not-allowed ${
canManageAgent && !hasSavableChanges
? 'bg-gray-200 text-gray-500 dark:bg-[#3A3A3A] dark:text-gray-400'
: 'bg-violets-are-blue hover:bg-purple-30 text-white disabled:opacity-50'
? 'dark:bg-accent bg-gray-200 text-gray-500 dark:text-gray-400'
: 'bg-primary hover:bg-primary/90 text-white disabled:opacity-50'
}`}
>
<span
@@ -1571,18 +1571,18 @@ function WorkflowBuilderInner() {
)}
<div className="flex flex-1 overflow-hidden">
<div className="border-light-silver dark:bg-raisin-black flex w-64 flex-col gap-6 border-r bg-gray-50 p-4 dark:border-[#3A3A3A]">
<div className="border-border bg-muted dark:bg-background flex w-64 flex-col gap-6 border-r p-4">
<div>
<h3 className="mb-3 text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
Core Nodes
</h3>
<div className="flex flex-col gap-2">
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) => handleNodeDragStart(e, 'agent')}
>
<div className="text-violets-are-blue group-hover:bg-violets-are-blue flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-purple-100 transition-colors group-hover:text-white">
<div className="text-primary group-hover:bg-primary flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-purple-100 transition-colors group-hover:text-white">
<Bot size={18} />
</div>
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">
@@ -1590,7 +1590,7 @@ function WorkflowBuilderInner() {
</span>
</div>
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) => handleNodeDragStart(e, 'end')}
>
@@ -1602,7 +1602,7 @@ function WorkflowBuilderInner() {
</span>
</div>
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) => handleNodeDragStart(e, 'note')}
>
@@ -1622,7 +1622,7 @@ function WorkflowBuilderInner() {
</h3>
<div className="flex flex-col gap-2">
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) => handleNodeDragStart(e, 'state')}
>
@@ -1630,16 +1630,16 @@ function WorkflowBuilderInner() {
<Database size={18} />
</div>
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">
<span className="text-foreground text-sm font-medium">
Set State
</span>
<span className="text-[10px] text-gray-400">
<span className="text-muted-foreground text-[10px]">
Modify workflow variables
</span>
</div>
</div>
<div
className="group flex cursor-move items-center gap-3 rounded-full border bg-white px-4 py-3 shadow-sm transition-all hover:shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]"
className="group border-border bg-card flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable
onDragStart={(e) => handleNodeDragStart(e, 'condition')}
>
@@ -1647,10 +1647,10 @@ function WorkflowBuilderInner() {
<GitBranch size={18} />
</div>
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">
<span className="text-foreground text-sm font-medium">
If / Else
</span>
<span className="text-[10px] text-gray-400">
<span className="text-muted-foreground text-[10px]">
Conditional branching
</span>
</div>
@@ -1661,7 +1661,7 @@ function WorkflowBuilderInner() {
<div
ref={reactFlowWrapper}
className="dark:bg-raisin-black/10 relative flex-1 bg-gray-50"
className="bg-muted dark:bg-background/10 relative flex-1"
>
<ReactFlow
nodes={nodes}
@@ -1687,8 +1687,8 @@ function WorkflowBuilderInner() {
className="absolute inset-0 z-10"
onClick={handlePanelBackdropClick}
/>
<div className="border-light-silver dark:bg-raisin-black absolute top-4 right-4 z-20 w-96 rounded-2xl border bg-white shadow-[0px_4px_40px_-3px_#0000001A] dark:border-[#3A3A3A]">
<div className="border-light-silver flex items-center justify-between border-b p-4 dark:border-[#3A3A3A]">
<div className="border-border bg-card absolute top-4 right-4 z-20 w-96 rounded-2xl border shadow-[0px_4px_40px_-3px_#0000001A]">
<div className="border-border flex items-center justify-between border-b p-4">
<h3 className="font-semibold text-gray-900 dark:text-white">
{selectedNode.type === 'start' && 'Start Node'}
{selectedNode.type === 'end' && 'End Node'}
@@ -1707,7 +1707,7 @@ function WorkflowBuilderInner() {
<div className="max-h-[calc(100vh-200px)] overflow-y-auto p-4">
<div className="mb-4 flex flex-col gap-2">
<div className="rounded-lg bg-gray-50 p-3 dark:bg-[#2C2C2C]">
<div className="bg-muted rounded-lg p-3">
<div className="mb-1 text-xs text-gray-500 dark:text-gray-400">
Node ID
</div>
@@ -1736,7 +1736,7 @@ function WorkflowBuilderInner() {
label: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border focus:ring-ring bg-card w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
placeholder="Enter node title"
/>
</div>
@@ -1833,7 +1833,7 @@ function WorkflowBuilderInner() {
},
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border focus:ring-ring bg-card w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
rows={3}
placeholder="System prompt for the agent"
/>
@@ -1876,7 +1876,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border focus:ring-ring bg-card w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
placeholder="Variable name for output"
/>
</div>
@@ -1969,7 +1969,7 @@ function WorkflowBuilderInner() {
e.target.value,
)
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 font-mono text-xs transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border focus:ring-ring bg-card w-full rounded-xl border px-3 py-2 font-mono text-xs transition-all outline-none focus:ring-2 dark:text-white"
rows={8}
placeholder={`{
"type": "object",
@@ -2009,7 +2009,7 @@ function WorkflowBuilderInner() {
content: e.target.value,
})
}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border focus:ring-ring bg-card w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
rows={4}
placeholder="Enter note content"
/>
@@ -2034,7 +2034,7 @@ function WorkflowBuilderInner() {
) => (
<div
key={idx}
className="rounded-xl border border-gray-200 p-3 dark:border-[#3A3A3A]"
className="border-border rounded-xl border p-3"
>
<div className="mb-2 flex items-center justify-between">
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
@@ -2084,18 +2084,18 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 mb-1 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent mb-1 w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
rows={2}
placeholder="input.foo + 1"
/>
<p className="mb-3 text-[10px] text-gray-400">
<p className="text-muted-foreground mb-3 text-[10px]">
Use Common Expression Language to create
a custom expression.{' '}
<a
href="https://cel.dev/"
target="_blank"
rel="noreferrer"
className="text-violets-are-blue underline"
className="text-primary underline"
>
Learn more
</a>
@@ -2124,7 +2124,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
placeholder="variable_name"
/>
</div>
@@ -2145,7 +2145,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm font-medium text-gray-600 transition-colors hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-[#383838]"
className="hover:bg-accent flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm font-medium text-gray-600 transition-colors dark:text-gray-400"
>
<Plus size={14} />
Add
@@ -2158,7 +2158,7 @@ function WorkflowBuilderInner() {
<p className="text-xs text-gray-500 dark:text-gray-400">
Create conditions to branch your workflow
</p>
<div className="flex overflow-hidden rounded-lg border border-gray-200 dark:border-[#3A3A3A]">
<div className="border-border flex overflow-hidden rounded-lg border">
<button
onClick={() =>
handleUpdateNodeData({
@@ -2171,8 +2171,8 @@ function WorkflowBuilderInner() {
className={`flex-1 px-3 py-1.5 text-xs font-medium transition-colors ${
(selectedNode.data.config?.mode ||
'simple') === 'simple'
? 'bg-violets-are-blue text-white'
: 'text-gray-600 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-[#383838]'
? 'bg-primary text-white'
: 'hover:bg-accent text-gray-600 dark:text-gray-400'
}`}
>
Simple
@@ -2189,8 +2189,8 @@ function WorkflowBuilderInner() {
className={`flex-1 px-3 py-1.5 text-xs font-medium transition-colors ${
selectedNode.data.config?.mode ===
'advanced'
? 'bg-violets-are-blue text-white'
: 'text-gray-600 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-[#383838]'
? 'bg-primary text-white'
: 'hover:bg-accent text-gray-600 dark:text-gray-400'
}`}
>
Advanced
@@ -2201,7 +2201,7 @@ function WorkflowBuilderInner() {
(c: ConditionCase, idx: number) => (
<div
key={c.sourceHandle}
className="rounded-xl border border-gray-200 p-3 dark:border-[#3A3A3A]"
className="border-border rounded-xl border p-3"
>
<div className="mb-2 flex items-center justify-between">
<span className="text-sm font-semibold text-orange-600 dark:text-orange-400">
@@ -2266,7 +2266,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 mb-2 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent mb-2 w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
placeholder="Case name (optional)"
/>
{(selectedNode.data.config?.mode ||
@@ -2302,7 +2302,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent w-full rounded-xl border px-3 py-2 text-sm outline-none focus:ring-2 dark:text-white"
placeholder="Variable"
/>
<Select
@@ -2394,7 +2394,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent w-full rounded-xl border px-3 py-2 text-sm outline-none focus:ring-2 dark:text-white"
placeholder="Value"
/>
</div>
@@ -2419,18 +2419,18 @@ function WorkflowBuilderInner() {
},
});
}}
className="border-light-silver focus:ring-purple-30 w-full rounded-xl border bg-white px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:border-[#3A3A3A] dark:bg-[#383838] dark:text-white"
className="border-border focus:ring-ring bg-card dark:bg-accent w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2 dark:text-white"
rows={2}
placeholder="Enter condition, e.g. input == 5"
/>
<p className="mt-1 text-[10px] text-gray-400">
<p className="text-muted-foreground mt-1 text-[10px]">
Use Common Expression Language to
create a custom expression.{' '}
<a
href="https://cel.dev/"
target="_blank"
rel="noreferrer"
className="text-violets-are-blue underline"
className="text-primary underline"
>
Learn more
</a>
@@ -2461,7 +2461,7 @@ function WorkflowBuilderInner() {
},
});
}}
className="flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm font-medium text-gray-600 transition-colors hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-[#383838]"
className="hover:bg-accent flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm font-medium text-gray-600 transition-colors dark:text-gray-400"
>
<Plus size={14} />
Add
@@ -2493,7 +2493,7 @@ function WorkflowBuilderInner() {
<SheetContent
side="right"
showCloseButton={false}
className="dark:bg-raisin-black w-full max-w-none p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px] dark:border-[#3A3A3A]"
className="bg-card w-full max-w-none p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px]"
>
<WorkflowPreview
workflowData={{

View File

@@ -150,7 +150,7 @@ function ExecutionDetails({
ref={(el) => {
if (el && stepRefs) stepRefs.current.set(step.nodeId, el);
}}
className="rounded-xl bg-[#F5F5F5] p-3 dark:bg-[#383838]"
className="bg-muted dark:bg-accent rounded-xl p-3"
>
<div className="flex items-center gap-2 text-sm">
<span className="flex h-5 w-5 shrink-0 items-center justify-center text-xs font-medium text-gray-500 dark:text-gray-400">
@@ -181,7 +181,7 @@ function ExecutionDetails({
{(hasOutput || step.error || stateVars.length > 0) && (
<div className="mt-3 space-y-2 text-sm">
{hasOutput && (
<div className="rounded-lg bg-white p-2 dark:bg-[#2A2A2A]">
<div className="bg-muted rounded-lg p-2">
<span className="font-medium text-gray-600 dark:text-gray-400">
Output:{' '}
</span>
@@ -205,7 +205,7 @@ function ExecutionDetails({
{stateVars.map(([key, value]) => (
<span
key={key}
className="inline-flex items-center rounded-lg bg-white px-2 py-1 text-xs dark:bg-[#2A2A2A]"
className="bg-muted inline-flex items-center rounded-lg px-2 py-1 text-xs"
>
<span className="max-w-[100px] truncate font-medium text-gray-600 dark:text-gray-400">
{key}:
@@ -487,10 +487,10 @@ export default function WorkflowPreview({
queries.length > 0 ? queries[queries.length - 1].executionSteps || [] : [];
return (
<div className="dark:bg-raisin-black flex h-full flex-col bg-white">
<div className="border-light-silver dark:bg-raisin-black flex h-[77px] items-center justify-between border-b bg-white px-6 dark:border-[#3A3A3A]">
<div className="bg-card flex h-full flex-col">
<div className="border-border flex h-[77px] items-center justify-between border-b px-6">
<div className="flex items-center gap-3">
<div className="flex items-center justify-center rounded-full bg-gray-100 p-3 text-gray-600 dark:bg-[#2C2C2C] dark:text-gray-300">
<div className="bg-muted flex items-center justify-center rounded-full p-3 text-gray-600 dark:text-gray-300">
<Play className="h-4 w-4" />
</div>
<div>
@@ -504,7 +504,7 @@ export default function WorkflowPreview({
</div>
</div>
{status === 'loading' && (
<span className="text-purple-30 dark:text-violets-are-blue flex items-center gap-1 text-xs">
<span className="text-primary dark:text-primary flex items-center gap-1 text-xs">
<Loader2 className="h-3 w-3 animate-spin" />
Running
</span>
@@ -512,7 +512,7 @@ export default function WorkflowPreview({
</div>
<div className="flex min-h-0 flex-1">
<div className="flex w-64 shrink-0 flex-col border-r border-gray-200 dark:border-[#3A3A3A]">
<div className="border-border flex w-64 shrink-0 flex-col border-r">
<div className="flex items-center justify-between px-4 py-3">
<h3 className="text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
Workflow
@@ -537,7 +537,7 @@ export default function WorkflowPreview({
>
{queries.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center">
<div className="mb-2 flex size-14 shrink-0 items-center justify-center rounded-xl bg-gray-100 dark:bg-[#2C2C2C]">
<div className="bg-muted mb-2 flex size-14 shrink-0 items-center justify-center rounded-xl">
<MessageSquare className="size-6 text-gray-600 dark:text-gray-300" />
</div>
<p className="text-xl font-semibold text-gray-700 dark:text-gray-200">
@@ -618,7 +618,7 @@ export default function WorkflowPreview({
</div>
)}
</div>
<div className="dark:bg-raisin-black absolute right-0 bottom-0 left-0 flex w-full flex-col gap-2 bg-white px-4 pt-2 pb-4">
<div className="bg-card absolute right-0 bottom-0 left-0 flex w-full flex-col gap-2 px-4 pt-2 pb-4">
<MessageInput
onSubmit={(text) => handleQuestionSubmission(text)}
loading={status === 'loading'}

View File

@@ -2,14 +2,14 @@ import { Monitor } from 'lucide-react';
export default function MobileBlocker() {
return (
<div className="bg-lotion dark:bg-raisin-black flex min-h-screen flex-col items-center justify-center px-6 text-center md:hidden">
<div className="bg-violets-are-blue/10 dark:bg-violets-are-blue/20 mb-6 flex h-20 w-20 items-center justify-center rounded-2xl">
<Monitor className="text-violets-are-blue h-10 w-10" />
<div className="bg-background flex min-h-screen flex-col items-center justify-center px-6 text-center md:hidden">
<div className="bg-primary/10 dark:bg-primary/20 mb-6 flex h-20 w-20 items-center justify-center rounded-2xl">
<Monitor className="text-primary h-10 w-10" />
</div>
<h2 className="mb-2 text-xl font-bold text-gray-900 dark:text-white">
<h2 className="text-foreground mb-2 text-xl font-bold">
Desktop Required
</h2>
<p className="max-w-sm text-sm leading-relaxed text-gray-500 dark:text-[#E0E0E0]">
<p className="text-muted-foreground max-w-sm text-sm leading-relaxed">
The Workflow Builder requires a larger screen for the best experience.
Please open this page on a desktop or laptop computer.
</p>

View File

@@ -186,7 +186,7 @@ function HighlightedOverlay({ text }: { text: string }) {
<>
{parts.map((part, i) =>
/^\{\{[^}]*\}\}$/.test(part) ? (
<span key={i} className="text-violets-are-blue font-medium">
<span key={i} className="text-primary font-medium">
{part}
</span>
) : (
@@ -222,7 +222,7 @@ function VariableListWithSearch({
return (
<div className="flex w-full flex-col overflow-hidden">
<div className="flex items-center gap-2 border-b border-[#E5E5E5] px-3 py-2 dark:border-[#3A3A3A]">
<div className="border-border flex items-center gap-2 border-b px-3 py-2">
<Search className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
<input
type="text"
@@ -252,9 +252,9 @@ function VariableListWithSearch({
e.stopPropagation();
onSelect(v.templatePath);
}}
className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors hover:bg-gray-50 dark:hover:bg-[#383838]"
className="hover:bg-accent flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors"
>
<Braces className="text-violets-are-blue h-3.5 w-3.5 shrink-0" />
<Braces className="text-primary h-3.5 w-3.5 shrink-0" />
<span className="truncate font-medium text-gray-800 dark:text-gray-200">
{v.label}
</span>
@@ -412,7 +412,7 @@ export default function PromptTextArea({
)}
<div
ref={wrapperRef}
className="border-light-silver focus-within:ring-purple-30 relative rounded-xl border bg-white transition-all focus-within:ring-2 dark:border-[#3A3A3A] dark:bg-[#2C2C2C]"
className="border-border focus-within:ring-ring bg-card relative rounded-xl border transition-all focus-within:ring-2"
>
<div
ref={overlayRef}
@@ -463,7 +463,7 @@ export default function PromptTextArea({
<PopoverTrigger asChild>
<button
type="button"
className="text-violets-are-blue hover:bg-violets-are-blue/10 flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium transition-colors"
className="text-primary hover:bg-primary/10 flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium transition-colors"
>
<Plus className="h-3 w-3" />
Add context
@@ -472,7 +472,7 @@ export default function PromptTextArea({
<PopoverContent
align="end"
side="top"
className="w-60 rounded-xl border border-[#E5E5E5] bg-white p-0 shadow-lg dark:border-[#3A3A3A] dark:bg-[#2C2C2C]"
className="border-border bg-card w-60 rounded-xl border p-0 shadow-lg"
onOpenAutoFocus={(e) => e.preventDefault()}
>
<VariableListWithSearch
@@ -486,7 +486,7 @@ export default function PromptTextArea({
{showDropdown && filtered.length > 0 && (
<div
ref={dropdownRef}
className="absolute z-50 w-64 rounded-xl border border-[#E5E5E5] bg-white shadow-lg dark:border-[#3A3A3A] dark:bg-[#2C2C2C]"
className="border-border bg-card absolute z-50 w-64 rounded-xl border shadow-lg"
style={{ top: dropdownPos.top, left: dropdownPos.left }}
>
<VariableListWithSearch

View File

@@ -21,14 +21,13 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
icon,
handles = { source: true, target: true },
}) => {
let bgColor = 'bg-white dark:bg-[#2C2C2C]';
let borderColor = 'border-gray-200 dark:border-[#3A3A3A]';
let bgColor = 'bg-card';
let borderColor = 'border-border';
let iconBg = 'bg-gray-100 dark:bg-gray-800';
let iconColor = 'text-gray-600 dark:text-gray-400';
if (selected) {
borderColor =
'border-violets-are-blue ring-2 ring-purple-300 dark:ring-violets-are-blue';
borderColor = 'border-primary ring-2 ring-primary';
}
if (type === 'start') {
@@ -56,7 +55,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
type="target"
position={Position.Left}
isConnectable={true}
className="hover:bg-violets-are-blue! -left-1! h-3! w-3! rounded-full! border-2! border-white! bg-gray-400! transition-colors dark:border-[#2C2C2C]!"
className="hover:bg-primary/90! border-card! -left-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/>
)}
@@ -86,7 +85,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
type="source"
position={Position.Right}
isConnectable={true}
className="hover:bg-violets-are-blue! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-gray-400! transition-colors dark:border-[#2C2C2C]!"
className="hover:bg-primary/90! border-card! -right-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/>
)}
</div>

View File

@@ -36,10 +36,10 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
return (
<div
className={`relative rounded-2xl border bg-white shadow-md transition-all dark:bg-[#2C2C2C] ${
className={`bg-card relative rounded-2xl border shadow-md transition-all ${
selected
? 'border-violets-are-blue dark:ring-violets-are-blue scale-105 ring-2 ring-purple-300'
: 'border-gray-200 hover:shadow-lg dark:border-[#3A3A3A]'
? 'border-primary dark:ring-primary scale-105 ring-2 ring-purple-300'
: 'border-border hover:shadow-lg'
}`}
style={{ minWidth: 180, maxWidth: 220, height }}
>
@@ -47,7 +47,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
type="target"
position={Position.Left}
isConnectable
className="hover:bg-violets-are-blue! top-1/2! -left-1! h-3! w-3! rounded-full! border-2! border-white! bg-gray-400! transition-colors dark:border-[#2C2C2C]!"
className="hover:bg-primary/90! border-card! top-1/2! -left-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/>
<div className="flex items-center gap-3 px-3 py-2">
@@ -100,7 +100,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
id={c.sourceHandle}
isConnectable
style={{ top: getHandleTop(i, totalOutputs) }}
className="hover:bg-violets-are-blue! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-orange-400! transition-colors dark:border-[#2C2C2C]!"
className="hover:bg-primary/90! dark:border-border! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-orange-400! transition-colors"
/>
))}
<Handle
@@ -109,7 +109,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
id="else"
isConnectable
style={{ top: getHandleTop(cases.length, totalOutputs) }}
className="hover:bg-violets-are-blue! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-gray-400! transition-colors dark:border-[#2C2C2C]!"
className="hover:bg-primary/90! border-card! -right-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/>
</div>
);

View File

@@ -77,7 +77,7 @@ export const AgentNode = memo(function AgentNode({
)}
{config.model_id && (
<div
className="text-purple-30 dark:text-violets-are-blue truncate text-xs"
className="text-primary dark:text-primary truncate text-xs"
title={config.model_id}
>
{config.model_id}

View File

@@ -37,7 +37,7 @@ export default function Accordion({
className={`flex w-full items-center justify-between focus:outline-hidden ${titleClassName}`}
onClick={toggleAccordion}
>
<p className="break-words">{title}</p>
<p className="wrap-break-word">{title}</p>
<img
src={ChevronDown}
className={`h-5 w-5 transform transition-transform duration-200 dark:invert ${

View File

@@ -53,7 +53,7 @@ export default function ActionButtons({
<button
title={t('actionButtons.openNewChat')}
onClick={newChat}
className="hover:bg-bright-gray flex items-center gap-1 rounded-full p-2 lg:hidden dark:hover:bg-[#28292E]"
className="hover:bg-accent dark:hover:bg-accent flex items-center gap-1 rounded-full p-2 lg:hidden"
>
<img
className="filter dark:invert"
@@ -70,7 +70,7 @@ export default function ActionButtons({
<button
title={t('actionButtons.share')}
onClick={() => setShareModalState(true)}
className="hover:bg-bright-gray rounded-full p-2 dark:hover:bg-[#28292E]"
className="hover:bg-accent dark:hover:bg-accent rounded-full p-2"
>
<img
className="filter dark:invert"

View File

@@ -1,19 +1,19 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { useSelector } from 'react-redux';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import {
oneLight,
vscDarkPlus,
} from 'react-syntax-highlighter/dist/cjs/styles/prism';
import remarkGfm from 'remark-gfm';
import Exit from '../assets/exit.svg';
import { selectToken } from '../preferences/preferenceSlice';
import userService from '../api/services/userService';
import Spinner from './Spinner';
import CopyButton from './CopyButton';
import Exit from '../assets/exit.svg';
import { useDarkTheme } from '../hooks';
import { selectToken } from '../preferences/preferenceSlice';
import CopyButton from './CopyButton';
import Spinner from './Spinner';
type TodoItem = {
todo_id: number;
@@ -61,7 +61,8 @@ const ARTIFACT_TITLE_BY_TYPE: Record<ArtifactData['artifact_type'], string> = {
};
function getArtifactTitle(artifact: ArtifactData | null, toolName?: string) {
if (artifact) return ARTIFACT_TITLE_BY_TYPE[artifact.artifact_type] ?? 'Artifact';
if (artifact)
return ARTIFACT_TITLE_BY_TYPE[artifact.artifact_type] ?? 'Artifact';
const formattedToolName = (toolName ?? '')
.replace(/_/g, ' ')
@@ -161,7 +162,7 @@ function NoteView({ data }: { data: NoteArtifactData }) {
<div className="flex-1 overflow-y-auto p-4">
{data.content ? (
<ReactMarkdown
className="flex flex-col gap-3 text-sm leading-normal break-words whitespace-pre-wrap text-gray-800 dark:text-gray-200"
className="flex flex-col gap-3 text-sm leading-normal wrap-break-word whitespace-pre-wrap text-gray-800 dark:text-gray-200"
remarkPlugins={[remarkGfm]}
components={{
code(props) {
@@ -178,9 +179,9 @@ function NoteView({ data }: { data: NoteArtifactData }) {
const language = match ? match[1] : '';
return match ? (
<div className="group border-light-silver dark:border-raisin-black relative my-2 overflow-hidden rounded-[14px] border">
<div className="bg-platinum dark:bg-eerie-black-2 flex items-center justify-between px-2 py-1">
<span className="text-just-black dark:text-chinese-white text-xs font-medium">
<div className="group border-border relative my-2 overflow-hidden rounded-[14px] border">
<div className="bg-platinum flex items-center justify-between px-2 py-1">
<span className="text-foreground dark:text-foreground text-xs font-medium">
{language}
</span>
<CopyButton
@@ -203,7 +204,7 @@ function NoteView({ data }: { data: NoteArtifactData }) {
</div>
) : (
<code
className="dark:bg-independence dark:text-bright-gray rounded-[6px] bg-gray-200 px-[8px] py-[4px] text-xs font-normal"
className="dark:bg-accent dark:text-foreground rounded-[6px] bg-gray-200 px-2 py-1 text-xs font-normal"
{...rest}
>
{children}
@@ -315,17 +316,17 @@ export default function ArtifactSidebar({
// Generate a unique ID for this fetch
const fetchId = `${effectiveArtifactId}-${Date.now()}`;
currentFetchIdRef.current = fetchId;
setLoading(true);
setError(null);
// Note: For todo artifacts, the endpoint always returns all todos for the tool; will be coversation scoped later
userService
.getArtifact(effectiveArtifactId, token)
.then(async (res: any) => {
// Ignore if this is not the current fetch
if (currentFetchIdRef.current !== fetchId) return;
const isResponseLike = res && typeof res.json === 'function';
const status = isResponseLike ? res.status : undefined;
const ok = isResponseLike ? Boolean(res.ok) : true;
@@ -453,7 +454,7 @@ export default function ArtifactSidebar({
{title}
</span>
<button
className="rounded-full p-1 hover:bg-gray-100 dark:hover:bg-gray-800"
className="hover:bg-accent dark:hover:bg-accent rounded-full p-1"
onClick={onClose}
>
<img
@@ -472,7 +473,7 @@ export default function ArtifactSidebar({
return (
<div ref={sidebarRef} className="h-vh relative">
<div
className={`dark:bg-chinese-black fixed top-0 right-0 z-50 flex h-full w-80 transform flex-col bg-white shadow-xl transition-all duration-300 sm:w-96 ${
className={`dark:bg-card bg-card fixed top-0 right-0 z-50 flex h-full w-80 transform flex-col shadow-xl transition-all duration-300 sm:w-96 ${
isOpen ? 'translate-x-0' : 'translate-x-full'
} border-l border-[#9ca3af]/10`}
>
@@ -481,7 +482,7 @@ export default function ArtifactSidebar({
{title}
</span>
<button
className="hover:bg-gray-1000 dark:hover:bg-gun-metal rounded-full p-2"
className="hover:bg-accent rounded-full p-2"
onClick={onClose}
>
<img

View File

@@ -1,25 +1,27 @@
import React, { useState, useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { selectToken } from '../preferences/preferenceSlice';
import { useSelector } from 'react-redux';
import userService from '../api/services/userService';
import ArrowLeft from '../assets/arrow-left.svg';
import FileIcon from '../assets/file.svg';
import FolderIcon from '../assets/folder.svg';
import NoFilesDarkIcon from '../assets/no-files-dark.svg';
import NoFilesIcon from '../assets/no-files.svg';
import SearchIcon from '../assets/search.svg';
import {
useDarkTheme,
useLoaderState,
useMediaQuery,
useOutsideAlerter,
} from '../hooks';
import userService from '../api/services/userService';
import ArrowLeft from '../assets/arrow-left.svg';
import NoFilesIcon from '../assets/no-files.svg';
import NoFilesDarkIcon from '../assets/no-files-dark.svg';
import SkeletonLoader from './SkeletonLoader';
import ConfirmationModal from '../modals/ConfirmationModal';
import { ActiveState } from '../models/misc';
import { selectToken } from '../preferences/preferenceSlice';
import { ChunkType } from '../settings/types';
import Pagination from './DocumentPagination';
import FileIcon from '../assets/file.svg';
import FolderIcon from '../assets/folder.svg';
import SearchIcon from '../assets/search.svg';
import SkeletonLoader from './SkeletonLoader';
interface LineNumberedTextareaProps {
value: string;
onChange: (value: string) => void;
@@ -73,7 +75,7 @@ const LineNumberedTextarea: React.FC<LineNumberedTextareaProps> = ({
))}
</div>
<textarea
className={`w-full resize-none overflow-hidden border-none bg-transparent pl-8 font-['Inter'] text-[13.68px] leading-[19.93px] text-[#18181B] outline-none lg:pl-12 dark:text-white ${isMobile ? 'min-h-[calc(100vh-200px)]' : 'min-h-[calc(100vh-300px)]'} ${!editable ? 'select-none' : ''}`}
className={`text-foreground w-full resize-none overflow-hidden border-none bg-transparent pl-8 font-['Inter'] text-[13.68px] leading-[19.93px] outline-none lg:pl-12 dark:text-white ${isMobile ? 'min-h-[calc(100vh-200px)]' : 'min-h-[calc(100vh-300px)]'} ${!editable ? 'select-none' : ''}`}
value={value}
onChange={editable ? handleChange : undefined}
onDoubleClick={onDoubleClick}
@@ -301,7 +303,7 @@ const Chunks: React.FC<ChunksProps> = ({
<div className="mb-0 flex min-h-[38px] flex-col gap-2 text-base sm:flex-row sm:items-center sm:justify-between">
<div className="flex w-full items-center sm:w-auto">
<button
className="mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium text-gray-400 transition-all duration-200 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium text-gray-400 transition-all duration-200 dark:border-0 dark:text-gray-500"
onClick={
editingChunk
? () => setEditingChunk(null)
@@ -315,17 +317,17 @@ const Chunks: React.FC<ChunksProps> = ({
<div className="flex flex-wrap items-center">
{/* Removed the directory icon */}
<span className="font-semibold break-words text-[#7D54D1]">
<span className="font-semibold wrap-break-word text-[#7D54D1]">
{documentName}
</span>
{pathParts.length > 0 && (
<>
<span className="mx-1 flex-shrink-0 text-gray-500">/</span>
<span className="mx-1 shrink-0 text-gray-500">/</span>
{pathParts.map((part, index) => (
<React.Fragment key={index}>
<span
className={`break-words ${
className={`wrap-break-word ${
index < pathParts.length - 1
? 'font-medium text-[#7D54D1]'
: 'text-gray-700 dark:text-gray-300'
@@ -334,9 +336,7 @@ const Chunks: React.FC<ChunksProps> = ({
{part}
</span>
{index < pathParts.length - 1 && (
<span className="mx-1 flex-shrink-0 text-gray-500">
/
</span>
<span className="mx-1 shrink-0 text-gray-500">/</span>
)}
</React.Fragment>
))}
@@ -350,7 +350,7 @@ const Chunks: React.FC<ChunksProps> = ({
!isEditing ? (
<>
<button
className="bg-purple-30 hover:bg-violets-are-blue flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-nowrap text-white"
className="bg-primary hover:bg-primary/90 flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-nowrap text-white"
onClick={() => setIsEditing(true)}
>
{t('modals.chunk.edit')}
@@ -370,7 +370,7 @@ const Chunks: React.FC<ChunksProps> = ({
onClick={() => {
setIsEditing(false);
}}
className="dark:text-light-gray flex h-[38px] min-w-[108px] cursor-pointer items-center justify-center rounded-full px-4 py-1 text-sm font-medium text-nowrap hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent flex h-[38px] min-w-[108px] cursor-pointer items-center justify-center rounded-full px-4 py-1 text-sm font-medium text-nowrap"
>
{t('modals.chunk.cancel')}
</button>
@@ -402,7 +402,7 @@ const Chunks: React.FC<ChunksProps> = ({
editingText.trim() &&
(editingTitle !== (editingChunk?.metadata?.title || '') ||
editingText !== (editingChunk?.text || ''))
? 'bg-purple-30 hover:bg-violets-are-blue cursor-pointer'
? 'bg-primary hover:bg-primary/90 cursor-pointer'
: 'cursor-not-allowed bg-gray-400'
}`}
>
@@ -414,7 +414,7 @@ const Chunks: React.FC<ChunksProps> = ({
<>
<button
onClick={() => setIsAddingChunk(false)}
className="dark:text-light-gray flex h-[38px] min-w-[108px] cursor-pointer items-center justify-center rounded-full px-4 py-1 text-sm font-medium text-nowrap hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent flex h-[38px] min-w-[108px] cursor-pointer items-center justify-center rounded-full px-4 py-1 text-sm font-medium text-nowrap"
>
{t('modals.chunk.cancel')}
</button>
@@ -428,7 +428,7 @@ const Chunks: React.FC<ChunksProps> = ({
disabled={!editingText.trim()}
className={`flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 py-1 text-[14px] font-medium text-nowrap text-white transition-all ${
editingText.trim()
? 'bg-purple-30 hover:bg-violets-are-blue cursor-pointer'
? 'bg-primary hover:bg-primary/90 cursor-pointer'
: 'cursor-not-allowed bg-gray-400'
}`}
>
@@ -488,14 +488,14 @@ const Chunks: React.FC<ChunksProps> = ({
value={fileSearchQuery}
onChange={(e) => handleFileSearchChange(e.target.value)}
placeholder={t('settings.sources.searchFiles')}
className={`h-[38px] w-full border border-[#D1D9E0] py-2 pr-4 pl-10 dark:border-[#6A6A6A] ${
className={`border-border dark:border-border h-[38px] w-full border py-2 pr-4 pl-10 ${
fileSearchQuery ? 'rounded-t-[6px]' : 'rounded-[6px]'
} bg-transparent transition-all duration-200 focus:outline-none dark:text-[#E0E0E0]`}
} bg-transparent transition-all duration-200 focus:outline-none`}
/>
</div>
{fileSearchQuery && (
<div className="absolute z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[6px] border border-t-0 border-[#D1D9E0] bg-white shadow-lg dark:border-[#6A6A6A] dark:bg-[#1F2023]">
<div className="border-border bg-card dark:border-border dark:bg-card absolute z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[6px] border border-t-0 shadow-lg">
<div className="max-h-[calc(100vh-200px)] overflow-x-hidden overflow-y-auto">
{fileSearchResults.length === 0 ? (
<div className="py-2 text-center text-sm text-gray-500 dark:text-gray-400">
@@ -507,18 +507,18 @@ const Chunks: React.FC<ChunksProps> = ({
key={index}
title={result.path}
onClick={() => handleSearchResultClick(result)}
className={`flex cursor-pointer items-center px-3 py-2 hover:bg-[#ECEEEF] dark:hover:bg-[#27282D] ${
className={`hover:bg-muted dark:hover:bg-muted flex cursor-pointer items-center px-3 py-2 ${
index !== fileSearchResults.length - 1
? 'border-b border-[#D1D9E0] dark:border-[#6A6A6A]'
? 'border-border dark:border-border border-b'
: ''
}`}
>
<img
src={result.isFile ? FileIcon : FolderIcon}
alt={result.isFile ? 'File' : 'Folder'}
className="mr-2 h-4 w-4 flex-shrink-0"
className="mr-2 h-4 w-4 shrink-0"
/>
<span className="truncate text-sm dark:text-[#E0E0E0]">
<span className="truncate text-sm">
{result.name ||
result.path.split('/').pop() ||
result.path}
@@ -546,8 +546,8 @@ const Chunks: React.FC<ChunksProps> = ({
{!editingChunk && !isAddingChunk ? (
<>
<div className="mb-3 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div className="flex h-[38px] w-full flex-1 items-center overflow-hidden rounded-md border border-[#D1D9E0] dark:border-[#6A6A6A]">
<div className="flex h-full items-center px-4 font-medium whitespace-nowrap text-gray-700 dark:text-[#E0E0E0]">
<div className="border-border dark:border-border flex h-[38px] w-full flex-1 items-center overflow-hidden rounded-md border">
<div className="dark:text-foreground flex h-full items-center px-4 font-medium whitespace-nowrap text-gray-700">
{totalChunks > 999999
? `${(totalChunks / 1000000).toFixed(2)}M`
: totalChunks > 999
@@ -555,19 +555,19 @@ const Chunks: React.FC<ChunksProps> = ({
: totalChunks}{' '}
{t('settings.sources.chunks')}
</div>
<div className="h-full w-[1px] bg-[#D1D9E0] dark:bg-[#6A6A6A]"></div>
<div className="bg-border dark:bg-border h-full w-px"></div>
<div className="h-full flex-1">
<input
type="text"
placeholder={t('settings.sources.searchPlaceholder')}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="h-full w-full border-none bg-transparent px-3 py-2 text-[13.56px] leading-[100%] font-normal outline-none dark:text-[#E0E0E0]"
className="h-full w-full border-none bg-transparent px-3 py-2 text-[13.56px] leading-[100%] font-normal outline-none"
/>
</div>
</div>
<button
className="bg-purple-30 hover:bg-violets-are-blue flex h-[38px] w-full min-w-[108px] shrink-0 items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-normal text-white sm:w-auto"
className="bg-primary hover:bg-primary/90 flex h-[38px] w-full min-w-[108px] shrink-0 items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-normal text-white sm:w-auto"
title={t('settings.sources.addChunk')}
onClick={() => {
setIsAddingChunk(true);
@@ -579,11 +579,11 @@ const Chunks: React.FC<ChunksProps> = ({
</button>
</div>
{loading ? (
<div className="grid w-full grid-cols-1 justify-items-start gap-4 sm:[grid-template-columns:repeat(auto-fit,minmax(400px,1fr))]">
<div className="grid w-full grid-cols-1 justify-items-start gap-4 sm:grid-cols-[repeat(auto-fit,minmax(400px,1fr))]">
<SkeletonLoader component="chunkCards" count={perPage} />
</div>
) : (
<div className="grid w-full grid-cols-1 justify-items-start gap-4 sm:[grid-template-columns:repeat(auto-fit,minmax(400px,1fr))]">
<div className="grid w-full grid-cols-1 justify-items-start gap-4 sm:grid-cols-[repeat(auto-fit,minmax(400px,1fr))]">
{filteredChunks.length === 0 ? (
<div className="col-span-full flex min-h-[50vh] w-full flex-col items-center justify-center text-center text-gray-500 dark:text-gray-400">
<img
@@ -597,7 +597,7 @@ const Chunks: React.FC<ChunksProps> = ({
filteredChunks.map((chunk, index) => (
<div
key={index}
className="relative flex h-[197px] w-full max-w-[487px] transform cursor-pointer flex-col justify-between overflow-hidden rounded-[5.86px] border border-[#D1D9E0] transition-transform duration-200 hover:scale-105 dark:border-[#6A6A6A]"
className="border-border dark:border-border relative flex h-[197px] w-full max-w-[487px] transform cursor-pointer flex-col justify-between overflow-hidden rounded-[5.86px] border transition-transform duration-200 hover:scale-105"
onClick={() => {
setEditingChunk(chunk);
setEditingTitle(chunk.metadata?.title || '');
@@ -605,8 +605,8 @@ const Chunks: React.FC<ChunksProps> = ({
}}
>
<div className="w-full">
<div className="flex w-full items-center justify-between border-b border-[#D1D9E0] bg-[#F6F8FA] px-4 py-3 dark:border-[#6A6A6A] dark:bg-[#27282D]">
<div className="text-sm text-[#59636E] dark:text-[#E0E0E0]">
<div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="dark:text-muted-foreground text-sm text-[#59636E]">
{chunk.metadata.token_count
? chunk.metadata.token_count.toLocaleString()
: '-'}{' '}
@@ -614,7 +614,7 @@ const Chunks: React.FC<ChunksProps> = ({
</div>
</div>
<div className="px-4 pt-3 pb-6">
<p className="line-clamp-6 font-['Inter'] text-[13.68px] leading-[19.93px] font-normal text-[#18181B] dark:text-[#E0E0E0]">
<p className="text-foreground line-clamp-6 font-['Inter'] text-[13.68px] leading-[19.93px] font-normal">
{chunk.text}
</p>
</div>
@@ -627,7 +627,7 @@ const Chunks: React.FC<ChunksProps> = ({
</>
) : isAddingChunk ? (
<div className="w-full">
<div className="relative overflow-hidden rounded-lg border border-[#D1D9E0] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border relative overflow-hidden rounded-lg border">
<LineNumberedTextarea
value={editingText}
onChange={setEditingText}
@@ -639,9 +639,9 @@ const Chunks: React.FC<ChunksProps> = ({
) : (
editingChunk && (
<div className="w-full">
<div className="relative flex w-full flex-col overflow-hidden rounded-[5.86px] border border-[#D1D9E0] dark:border-[#6A6A6A]">
<div className="flex w-full items-center justify-between border-b border-[#D1D9E0] bg-[#F6F8FA] px-4 py-3 dark:border-[#6A6A6A] dark:bg-[#27282D]">
<div className="text-sm text-[#59636E] dark:text-[#E0E0E0]">
<div className="border-border dark:border-border relative flex w-full flex-col overflow-hidden rounded-[5.86px] border">
<div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="dark:text-muted-foreground text-sm text-[#59636E]">
{editingChunk.metadata.token_count
? editingChunk.metadata.token_count.toLocaleString()
: '-'}{' '}

View File

@@ -68,9 +68,7 @@ export default function ConfigFields({
<div key={key} className="flex flex-col gap-1.5">
<Label htmlFor={key}>
{spec.label || key}
{spec.required && (
<span className="text-red-500">*</span>
)}
{spec.required && <span className="text-red-500">*</span>}
</Label>
<Select
value={value || spec.default || ''}
@@ -82,7 +80,8 @@ export default function ConfigFields({
size="lg"
className={cn(
'w-full rounded-xl',
hasError && 'border-destructive aria-invalid:ring-destructive/20',
hasError &&
'border-destructive aria-invalid:ring-destructive/20',
)}
>
<SelectValue placeholder={spec.label || key} />
@@ -90,13 +89,14 @@ export default function ConfigFields({
<SelectContent>
{spec.enum.map((v) => (
<SelectItem key={v} value={v}>
{v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, ' ')}
{v.charAt(0).toUpperCase() +
v.slice(1).replace(/_/g, ' ')}
</SelectItem>
))}
</SelectContent>
</Select>
{hasError && (
<p className="text-xs text-destructive">{errors[key]}</p>
<p className="text-destructive text-xs">{errors[key]}</p>
)}
</div>
);
@@ -106,9 +106,7 @@ export default function ConfigFields({
<div key={key} className="flex flex-col gap-1.5">
<Label htmlFor={key}>
{spec.label || key}
{spec.required && (
<span className="text-red-500">*</span>
)}
{spec.required && <span className="text-red-500">*</span>}
</Label>
<Input
id={key}
@@ -134,12 +132,14 @@ export default function ConfigFields({
}}
placeholder={placeholder || spec.description || ''}
min={spec.type === 'number' ? 1 : undefined}
max={spec.type === 'number' && key === 'timeout' ? 300 : undefined}
max={
spec.type === 'number' && key === 'timeout' ? 300 : undefined
}
aria-invalid={hasError || undefined}
className={cn('rounded-xl', hasError && 'border-destructive')}
/>
{hasError && (
<p className="text-xs text-destructive">{errors[key]}</p>
<p className="text-destructive text-xs">{errors[key]}</p>
)}
</div>
);

View File

@@ -136,7 +136,7 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
</svg>
<span
className="text-sm text-[#E60000] dark:text-[#E37064]"
className="text-sm text-[#E60000] dark:text-red-400"
style={{
fontFamily: 'Inter',
lineHeight: '100%',

View File

@@ -1,30 +1,31 @@
import React, { useState, useRef, useEffect } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { formatBytes } from '../utils/stringUtils';
import { selectToken } from '../preferences/preferenceSlice';
import userService from '../api/services/userService';
import ArrowLeft from '../assets/arrow-left.svg';
import CheckmarkIcon from '../assets/checkMark2.svg';
import EyeView from '../assets/eye-view.svg';
import FileIcon from '../assets/file.svg';
import FolderIcon from '../assets/folder.svg';
import SyncIcon from '../assets/sync.svg';
import ThreeDots from '../assets/three-dots.svg';
import { useLoaderState, useOutsideAlerter } from '../hooks';
import ConfirmationModal from '../modals/ConfirmationModal';
import { ActiveState } from '../models/misc';
import { selectToken } from '../preferences/preferenceSlice';
import { formatBytes } from '../utils/stringUtils';
import Chunks from './Chunks';
import ContextMenu, { MenuOption } from './ContextMenu';
import SkeletonLoader from './SkeletonLoader';
import ConfirmationModal from '../modals/ConfirmationModal';
import userService from '../api/services/userService';
import FileIcon from '../assets/file.svg';
import FolderIcon from '../assets/folder.svg';
import ArrowLeft from '../assets/arrow-left.svg';
import ThreeDots from '../assets/three-dots.svg';
import EyeView from '../assets/eye-view.svg';
import SyncIcon from '../assets/sync.svg';
import CheckmarkIcon from '../assets/checkMark2.svg';
import { useOutsideAlerter, useLoaderState } from '../hooks';
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableBody,
TableRow,
TableHeader,
TableCell,
TableRow,
} from './Table';
interface FileNode {
@@ -325,26 +326,26 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
{/* Left side with path navigation */}
<div className="flex w-full items-center sm:w-auto">
<button
className="mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="text-muted-foreground mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium dark:border-0"
onClick={handleBackNavigation}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<div className="flex flex-wrap items-center">
<span className="font-semibold break-words text-[#7D54D1]">
<span className="font-semibold wrap-break-word text-[#7D54D1]">
{sourceName}
</span>
{currentPath.length > 0 && (
<>
<span className="mx-1 flex-shrink-0 text-gray-500">/</span>
<span className="text-muted-foreground mx-1 shrink-0">/</span>
{currentPath.map((dir, index) => (
<React.Fragment key={index}>
<span className="break-words text-gray-700 dark:text-[#E0E0E0]">
<span className="dark:text-foreground wrap-break-word text-gray-700">
{dir}
</span>
{index < currentPath.length - 1 && (
<span className="mx-1 flex-shrink-0 text-gray-500">
<span className="text-muted-foreground mx-1 shrink-0">
/
</span>
)}
@@ -364,8 +365,8 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
disabled={isSyncing}
className={`flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-nowrap transition-colors ${
isSyncing
? 'cursor-not-allowed bg-gray-300 text-gray-600 dark:bg-gray-600 dark:text-gray-400'
: 'bg-purple-30 hover:bg-violets-are-blue text-white'
? 'dark:bg-muted dark:text-muted-foreground cursor-not-allowed bg-gray-300 text-gray-600'
: 'bg-primary hover:bg-primary/90 text-white'
}`}
title={
isSyncing
@@ -402,7 +403,7 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
<img
src={FolderIcon}
alt={t('settings.sources.parentFolderAlt')}
className="mr-2 h-4 w-4 flex-shrink-0"
className="mr-2 h-4 w-4 shrink-0"
/>
<span className="truncate">..</span>
</div>
@@ -449,7 +450,7 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
<img
src={FolderIcon}
alt={t('settings.sources.folderAlt')}
className="mr-2 h-4 w-4 flex-shrink-0"
className="mr-2 h-4 w-4 shrink-0"
/>
<span className="truncate">{name}</span>
</div>
@@ -466,7 +467,7 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
<div ref={menuRef} className="relative">
<button
onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-[#26272E]"
className="dark:hover:bg-muted inline-flex h-[35px] w-6 shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')}
>
<img
@@ -512,7 +513,7 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
<img
src={FileIcon}
alt={t('settings.sources.fileAlt')}
className="mr-2 h-4 w-4 flex-shrink-0"
className="mr-2 h-4 w-4 shrink-0"
/>
<span className="truncate">{displayName}</span>
</div>
@@ -527,7 +528,7 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
<div ref={menuRef} className="relative">
<button
onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-[#26272E]"
className="dark:hover:bg-muted inline-flex h-[35px] w-6 shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')}
>
<img
@@ -625,14 +626,14 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
}
}}
placeholder={t('settings.sources.searchFiles')}
className={`h-[38px] w-full border border-[#D1D9E0] px-4 py-2 dark:border-[#6A6A6A] ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none dark:text-[#E0E0E0]`}
className={`border-border dark:border-border h-[38px] w-full border px-4 py-2 ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none`}
/>
{searchQuery && (
<div className="absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[12px] border border-t-0 border-[#D1D9E0] bg-white shadow-lg transition-all duration-200 dark:border-[#6A6A6A] dark:bg-[#1F2023]">
<div className="border-border bg-card dark:border-border dark:bg-card absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-2xl border border-t-0 shadow-lg transition-all duration-200">
<div className="max-h-[calc(100vh-200px)] overflow-x-hidden overflow-y-auto overscroll-contain">
{searchResults.length === 0 ? (
<div className="py-2 text-center text-sm text-gray-500 dark:text-gray-400">
<div className="text-muted-foreground py-2 text-center text-sm">
{t('settings.sources.noResults')}
</div>
) : (
@@ -641,9 +642,9 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
key={index}
onClick={() => handleSearchSelect(result)}
title={result.path}
className={`flex min-w-0 cursor-pointer items-center px-3 py-2 hover:bg-[#ECEEEF] dark:hover:bg-[#27282D] ${
className={`hover:bg-muted dark:hover:bg-muted flex min-w-0 cursor-pointer items-center px-3 py-2 ${
index !== searchResults.length - 1
? 'border-b border-[#D1D9E0] dark:border-[#6A6A6A]'
? 'border-border dark:border-border border-b'
: ''
}`}
>
@@ -654,9 +655,9 @@ const ConnectorTree: React.FC<ConnectorTreeProps> = ({
? t('settings.sources.fileAlt')
: t('settings.sources.folderAlt')
}
className="mr-2 h-4 w-4 flex-shrink-0"
className="mr-2 h-4 w-4 shrink-0"
/>
<span className="flex-1 truncate text-sm dark:text-[#E0E0E0]">
<span className="flex-1 truncate text-sm">
{result.name}
</span>
</div>

View File

@@ -127,7 +127,7 @@ export default function ContextMenu({
onClick={(e) => e.stopPropagation()}
>
<div
className="bg-lotion dark:bg-charleston-green-2 flex flex-col rounded-xl text-sm shadow-xl"
className="bg-background dark:bg-card flex flex-col rounded-xl text-sm shadow-xl"
style={{ minWidth: '144px' }}
>
{options.map((option, index) => (
@@ -141,8 +141,8 @@ export default function ContextMenu({
}}
className={`flex items-center justify-start gap-4 p-3 transition-colors duration-200 ease-in-out ${index === 0 ? 'rounded-t-xl' : ''} ${index === options.length - 1 ? 'rounded-b-xl' : ''} ${
option.variant === 'danger'
? 'text-rosso-corsa hover:bg-bright-gray dark:text-red-2000 dark:hover:bg-charcoal-grey/20'
: 'text-eerie-black hover:bg-bright-gray dark:text-bright-gray dark:hover:bg-charcoal-grey/20'
? 'text-destructive hover:bg-muted'
: 'text-foreground hover:bg-muted'
} `}
>
{option.icon && (

View File

@@ -39,8 +39,7 @@ export default function CopyButton({
'flex items-center justify-center rounded-full transition-colors duration-150 ease-in-out',
padding,
{
[`bg-[#FFFFFF}] dark:bg-transparent hover:bg-[#EEEEEE] dark:hover:bg-purple-taupe`]:
!isCopied,
[`bg-transparent hover:bg-muted`]: !isCopied,
'bg-green-100 dark:bg-green-900 hover:bg-green-100 dark:hover:bg-green-900':
isCopied,
},

View File

@@ -61,12 +61,12 @@ const Pagination: React.FC<PaginationProps> = ({
<div className="relative">
<button
onClick={toggleDropdown}
className="dark:bg-dark-charcoal dark:text-light-gray rounded border px-3 py-1 hover:bg-gray-200 dark:hover:bg-neutral-700"
className="dark:bg-card dark:text-foreground hover:bg-accent dark:hover:bg-accent rounded border px-3 py-1"
>
{rowsPerPage}
</button>
<div
className={`ring-opacity-5 dark:bg-dark-charcoal absolute right-0 z-50 mt-1 w-28 transform bg-white shadow-lg ring-1 ring-black transition-all duration-200 ease-in-out ${
className={`ring-opacity-5 dark:bg-card bg-card absolute right-0 z-50 mt-1 w-28 transform shadow-lg ring-1 ring-black transition-all duration-200 ease-in-out ${
isDropdownOpen
? 'block scale-100 opacity-100'
: 'hidden scale-95 opacity-0'
@@ -76,10 +76,10 @@ const Pagination: React.FC<PaginationProps> = ({
<div
key={option}
onClick={() => handleSelectRowsPerPage(option)}
className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${
className={`hover:bg-accent dark:hover:bg-accent cursor-pointer px-4 py-2 text-xs ${
rowsPerPage === option
? 'dark:text-light-gray bg-gray-100 dark:bg-neutral-700'
: 'dark:bg-dark-charcoal dark:text-light-gray bg-white'
? 'dark:text-foreground bg-gray-100 dark:bg-neutral-700'
: 'bg-card dark:text-foreground'
}`}
>
{option}

View File

@@ -1,163 +1,227 @@
import React from 'react';
import { Check, ChevronDown, Pencil, Search, Trash2 } from 'lucide-react';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import Arrow2 from '../assets/dropdown-arrow.svg';
import Edit from '../assets/edit.svg';
import Trash from '../assets/trash.svg';
import { DropdownOption, DropdownProps } from './types/Dropdown.types';
type OptionBase = { id?: string; type?: string };
type NameIdOption = { name: string; id: string } & OptionBase;
type LabelValueOption = { label: string; value: string } & OptionBase;
type ValueDescriptionOption = {
value: number;
description: string;
} & OptionBase;
export type DropdownOption =
| string
| NameIdOption
| LabelValueOption
| ValueDescriptionOption;
export type { NameIdOption, LabelValueOption, ValueDescriptionOption };
function getOptionText(option: DropdownOption): string {
if (typeof option === 'string') return option;
if ('name' in option) return option.name;
if ('label' in option) return option.label;
if ('description' in option)
return option.value < 1e9
? `${option.value} (${option.description})`
: option.description;
return '';
}
function optionMatches(
option: DropdownOption,
selected: DropdownOption | null,
): boolean {
if (!selected) return false;
if (typeof selected === 'string' && typeof option === 'string')
return selected === option;
if (typeof selected === 'string') return getOptionText(option) === selected;
if (typeof option === 'string') return getOptionText(selected) === option;
const a = option as Record<string, unknown>;
const b = selected as Record<string, unknown>;
if ('name' in a && 'name' in b) return a.name === b.name;
if ('label' in a && 'label' in b) return a.label === b.label;
if ('value' in a && 'value' in b) return a.value === b.value;
return false;
}
export interface DropdownProps<T extends DropdownOption = DropdownOption> {
options: T[];
selectedValue: DropdownOption | null;
onSelect: (value: T) => void;
size?: string;
rounded?: 'xl' | '3xl';
searchable?: boolean;
placeholder?: string;
contentSize?: string;
showEdit?: boolean;
onEdit?: (value: NameIdOption) => void;
showDelete?: boolean | ((option: T) => boolean);
onDelete?: (id: string) => void;
}
function Dropdown<T extends DropdownOption>({
options,
selectedValue,
onSelect,
size = 'w-32',
rounded = 'xl',
buttonClassName = 'border-silver bg-white dark:bg-transparent dark:border-dim-gray',
optionsClassName = 'border-silver bg-white dark:border-dim-gray dark:bg-dark-charcoal',
border = 'border-2',
size = 'w-full',
rounded = '3xl',
searchable = false,
placeholder = 'Select...',
contentSize = 'text-sm',
showEdit,
onEdit,
showDelete,
onDelete,
placeholder,
placeholderClassName = 'text-gray-500 dark:text-gray-400',
contentSize = 'text-base',
}: DropdownProps<T>) {
const dropdownRef = React.useRef<HTMLDivElement>(null);
const [isOpen, setIsOpen] = React.useState(false);
const borderRadius = rounded === 'xl' ? 'rounded-xl' : 'rounded-3xl';
const borderTopRadius = rounded === 'xl' ? 'rounded-t-xl' : 'rounded-t-3xl';
const ref = useRef<HTMLDivElement>(null);
const searchRef = useRef<HTMLInputElement>(null);
const [open, setOpen] = useState(false);
const [query, setQuery] = useState('');
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setIsOpen(false);
}
};
const radius = rounded === '3xl' ? 'rounded-3xl' : 'rounded-xl';
const radiusTop = rounded === '3xl' ? 'rounded-t-3xl' : 'rounded-t-xl';
const radiusBottom = rounded === '3xl' ? 'rounded-b-3xl' : 'rounded-b-xl';
React.useEffect(() => {
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
useEffect(() => {
const handler = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false);
setQuery('');
}
};
document.addEventListener('mousedown', handler);
return () => document.removeEventListener('mousedown', handler);
}, []);
useEffect(() => {
if (open && searchable && searchRef.current) searchRef.current.focus();
}, [open, searchable]);
const filtered = useMemo(() => {
if (!searchable || !query.trim()) return options;
const q = query.toLowerCase();
return options.filter((o) => getOptionText(o).toLowerCase().includes(q));
}, [options, query, searchable]);
const displayValue = selectedValue ? getOptionText(selectedValue) : null;
return (
<div
className={[
typeof selectedValue === 'string'
? 'relative'
: 'relative align-middle',
size,
].join(' ')}
ref={dropdownRef}
>
<div className={`relative ${size}`} ref={ref}>
<button
onClick={() => setIsOpen(!isOpen)}
className={`flex w-full cursor-pointer items-center justify-between ${border} ${buttonClassName} px-5 py-3 ${
isOpen ? `${borderTopRadius}` : `${borderRadius}`
}`}
type="button"
onClick={() => setOpen((v) => !v)}
className={`border-border bg-card text-foreground flex w-full cursor-pointer items-center justify-between border px-5 py-3 ${open ? radiusTop : radius}`}
>
{typeof selectedValue === 'string' ? (
<span className={`dark:text-bright-gray truncate ${contentSize}`}>
{selectedValue}
</span>
) : (
<span
className={`truncate ${selectedValue && `dark:text-bright-gray`} ${
!selectedValue && ` ${placeholderClassName}`
} ${contentSize}`}
>
{selectedValue && 'label' in selectedValue
? selectedValue.label
: selectedValue && 'description' in selectedValue
? `${
selectedValue.value < 1e9
? selectedValue.value + ` (${selectedValue.description})`
: selectedValue.description
}`
: placeholder
? placeholder
: 'From URL'}
</span>
)}
<img
src={Arrow2}
alt="arrow"
className={`transform ${
isOpen ? 'rotate-180' : 'rotate-0'
} h-3 w-3 transition-transform`}
<span
className={`truncate ${contentSize} ${displayValue ? '' : 'text-muted-foreground'}`}
>
{displayValue ?? placeholder}
</span>
<ChevronDown
className={`text-muted-foreground ml-2 h-4 w-4 shrink-0 transition-transform ${open ? 'rotate-180' : ''}`}
/>
</button>
{isOpen && (
{open && (
<div
className={`absolute right-0 left-0 z-20 -mt-1 max-h-40 overflow-y-auto rounded-b-xl ${border} ${optionsClassName} shadow-lg`}
className={`border-border bg-card absolute inset-x-0 z-20 -mt-px overflow-hidden border border-t-0 shadow-lg ${radiusBottom}`}
>
{options.map((option: any, index) => (
<div
key={index}
className="hover:eerie-black flex cursor-pointer items-center justify-between hover:bg-gray-100 dark:hover:bg-[#545561]"
>
<span
onClick={() => {
onSelect(option);
setIsOpen(false);
}}
className={`dark:text-light-gray ml-5 flex-1 overflow-hidden py-3 text-ellipsis whitespace-nowrap ${contentSize}`}
>
{typeof option === 'string'
? option
: option.name
? option.name
: option.label
? option.label
: `${
option.value < 1e9
? option.value + ` (${option.description})`
: option.description
}`}
</span>
{showEdit && onEdit && option.type !== 'public' && (
<img
src={Edit}
alt="Edit"
className="mr-4 h-4 w-4 cursor-pointer hover:opacity-50"
onClick={() => {
onEdit({
id: option.id,
name: option.name,
type: option.type,
});
setIsOpen(false);
}}
/>
)}
{showDelete && onDelete && (
<button
onClick={(e) => {
e.stopPropagation();
onDelete?.(typeof option === 'string' ? option : option.id);
}}
className={`${
typeof showDelete === 'function' && !showDelete(option)
? 'hidden'
: ''
} mr-2 h-4 w-4 cursor-pointer hover:opacity-50`}
>
<img
src={Trash}
alt="Delete"
className={`mr-2 h-4 w-4 cursor-pointer hover:opacity-50 ${
option.type === 'public'
? 'cursor-not-allowed opacity-50'
: ''
}`}
/>
</button>
)}
{searchable && (
<div className="flex items-center px-3 py-2">
<Search className="text-muted-foreground mr-2 h-4 w-4 shrink-0" />
<input
ref={searchRef}
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
className="text-foreground placeholder:text-muted-foreground w-full bg-transparent text-sm focus:outline-none"
onClick={(e) => e.stopPropagation()}
/>
</div>
))}
)}
<div className="scrollbar-thin border-border max-h-48 overflow-y-auto border-t">
{filtered.length === 0 ? (
<div className="text-muted-foreground px-4 py-3 text-center text-sm">
No results found
</div>
) : (
filtered.map((option, i) => {
const active = optionMatches(option, selectedValue);
const optObj =
typeof option !== 'string'
? (option as Record<string, unknown>)
: null;
return (
<div
key={i}
className={`hover:bg-accent flex cursor-pointer items-center justify-between ${active ? 'bg-accent font-medium' : ''}`}
>
<span
onClick={() => {
onSelect(option);
setOpen(false);
setQuery('');
}}
className={`text-foreground flex-1 truncate px-4 py-2.5 ${contentSize}`}
>
{getOptionText(option)}
</span>
{active && !showEdit && !showDelete && (
<Check className="text-primary mr-3 h-4 w-4 shrink-0" />
)}
{showEdit &&
onEdit &&
optObj &&
optObj.type !== 'public' && (
<button
type="button"
onClick={() => {
onEdit({
id: optObj.id as string,
name: optObj.name as string,
type: optObj.type as string,
});
setOpen(false);
setQuery('');
}}
className="hover:bg-accent mr-1 rounded p-1"
>
<Pencil className="text-muted-foreground h-3.5 w-3.5" />
</button>
)}
{showDelete && onDelete && (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onDelete(
typeof option === 'string'
? option
: ((optObj?.id as string) ?? ''),
);
}}
className={`hover:bg-accent mr-1 rounded p-1 ${
typeof showDelete === 'function' &&
!showDelete(option)
? 'hidden'
: ''
} ${optObj?.type === 'public' ? 'pointer-events-none opacity-30' : ''}`}
>
<Trash2 className="text-muted-foreground h-3.5 w-3.5" />
</button>
)}
</div>
);
})
)}
</div>
</div>
)}
</div>

View File

@@ -88,7 +88,7 @@ export default function DropdownMenu({
onClick={(e) => e.stopPropagation()}
>
<div
className={`ring-opacity-5 dark:bg-dark-charcoal w-28 transform rounded-md bg-white shadow-lg ring-1 ring-black transition-all duration-200 ease-in-out ${className}`}
className={`border-border bg-card w-28 transform rounded-md border shadow-lg transition-all duration-200 ease-in-out ${className}`}
>
<div
role="menu"
@@ -99,10 +99,8 @@ export default function DropdownMenu({
{options.map((option, idx) => (
<div
id={`option-${idx}`}
className={`dark:text-light-gray dark:hover:bg-purple-taupe cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 ${
selectedOption.value === option.value
? 'dark:bg-purple-taupe bg-gray-100'
: 'dark:bg-dark-charcoal bg-white'
className={`dark:text-foreground hover:bg-muted cursor-pointer px-4 py-2 text-xs ${
selectedOption.value === option.value ? 'bg-muted' : 'bg-card'
}`}
role="menuitem"
key={option.value}

View File

@@ -80,15 +80,15 @@ export default function DropdownModel() {
return (
<div ref={dropdownRef}>
<div
className={`bg-gray-1000 dark:bg-dark-charcoal mx-auto flex w-full cursor-pointer justify-between p-1 dark:text-white ${isOpen ? 'rounded-t-3xl' : 'rounded-3xl'}`}
className={`text-foreground bg-muted dark:bg-card mx-auto flex w-full cursor-pointer items-center justify-between px-3 py-4 ${isOpen ? 'rounded-t-4xl' : 'rounded-4xl'}`}
onClick={() => setIsOpen(!isOpen)}
>
{selectedModel?.display_name ? (
<p className="mx-4 my-3 truncate overflow-hidden whitespace-nowrap">
<p className="ml-3 truncate overflow-hidden whitespace-nowrap">
{selectedModel.display_name}
</p>
) : (
<p className="mx-4 my-3 truncate overflow-hidden whitespace-nowrap">
<p className="text-muted-foreground truncate overflow-hidden whitespace-nowrap">
Select Model
</p>
)}
@@ -101,7 +101,7 @@ export default function DropdownModel() {
/>
</div>
{isOpen && (
<div className="no-scrollbar dark:bg-dark-charcoal absolute right-0 left-0 z-20 -mt-1 max-h-52 w-full overflow-y-auto rounded-b-3xl bg-white shadow-md">
<div className="no-scrollbar bg-muted dark:bg-card absolute right-0 left-0 z-20 -mt-1 max-h-52 w-full overflow-y-auto rounded-b-3xl shadow-md">
{availableModels && (availableModels?.length ?? 0) > 0 ? (
availableModels.map((model: Model) => (
<div
@@ -110,7 +110,7 @@ export default function DropdownModel() {
dispatch(setSelectedModel(model));
setIsOpen(false);
}}
className={`border-gray-3000/75 dark:border-purple-taupe/50 hover:bg-gray-3000/75 dark:hover:bg-purple-taupe flex h-10 w-full cursor-pointer items-center justify-between border-t`}
className={`border-border/30 hover:bg-accent flex h-10 w-full cursor-pointer items-center justify-between border-t`}
>
<div className="flex w-full items-center justify-between">
<p className="flex-1 truncate py-3 pr-2 pl-5">
@@ -127,8 +127,10 @@ export default function DropdownModel() {
</div>
))
) : (
<div className="h-10 w-full border-x-2 border-b-2">
<p className="ml-5 py-3 text-gray-500">No models available</p>
<div className="border-border/30 flex h-10 w-full items-center border-t">
<p className="text-muted-foreground pl-5 text-sm">
No models available
</p>
</div>
)}
</div>

View File

@@ -93,9 +93,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
const [isConnected, setIsConnected] = useState(false);
const [userEmail, setUserEmail] = useState<string>('');
const [allowsSharedContent, setAllowsSharedContent] = useState(false);
const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>(
'my_files',
);
const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>('my_files');
const scrollContainerRef = useRef<HTMLDivElement>(null);
const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -214,9 +212,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
setIsConnected(true);
setAuthError('');
if (provider === 'share_point') {
setAllowsSharedContent(
validateData.allows_shared_content ?? false,
);
setAllowsSharedContent(validateData.allows_shared_content ?? false);
}
setFiles([]);
@@ -369,9 +365,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
{
id: null,
name:
tab === 'shared'
? 'Shared'
: getProviderConfig(provider).rootName,
tab === 'shared' ? 'Shared' : getProviderConfig(provider).rootName,
},
]);
const sessionToken = getSessionToken(provider);
@@ -380,8 +374,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
}
};
const handleFileSelect = (fileId: string, isFolder: boolean) => {
if (isFolder) {
const newSelectedFolders = selectedFolders.includes(fileId)
@@ -459,10 +451,10 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
/>
{isConnected && (
<div className="mt-3 overflow-hidden rounded-lg border border-[#D7D7D7] dark:border-[#6A6A6A]">
<div className="rounded-t-lg border-[#EEE6FF78] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border mt-3 overflow-hidden rounded-lg border">
<div className="border-border dark:border-border rounded-t-lg">
{provider === 'share_point' && allowsSharedContent && (
<div className="flex border-b border-[#D7D7D7] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border flex border-b">
<button
onClick={() => handleTabChange('my_files')}
className={`px-4 py-2 text-sm font-medium ${
@@ -485,7 +477,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</button>
</div>
)}
<div className="rounded-t-lg bg-[#EEE6FF78] px-4 pt-4 dark:bg-[#2A262E]">
<div className="dark:bg-muted rounded-t-lg bg-[#EEE6FF78] px-4 pt-4">
<div className="mb-2 flex items-center gap-1">
{folderPath.map((path, index) => (
<div
@@ -516,7 +508,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
onChange={(e) => handleSearchChange(e.target.value)}
colorVariant="silver"
borderVariant="thin"
labelBgClassName="bg-[#EEE6FF78] dark:bg-[#2A262E]"
labelBgClassName="bg-[#EEE6FF78] dark:bg-muted"
leftIcon={
<img src={SearchIcon} alt="Search" width={16} height={16} />
}
@@ -531,7 +523,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</div>
</div>
<div className="h-72 border-t border-[#D7D7D7] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border h-72 border-t">
<TableContainer
ref={scrollContainerRef}
height="288px"
@@ -586,7 +578,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
>
<TableCell width="40px" align="center">
<div
className="mx-auto flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center border border-[#EEE6FF78] p-[0.5px] text-sm dark:border-[#6A6A6A]"
className="border-border dark:border-border mx-auto flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center border p-[0.5px] text-sm"
onClick={(e) => {
e.stopPropagation();
handleFileSelect(file.id, isFolder(file));
@@ -615,7 +607,9 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
className="h-6 w-6"
/>
</div>
<span className="truncate">{file.name}</span>
<span className="truncate">
{file.name}
</span>
</div>
</TableCell>
<TableCell className="text-xs">
@@ -626,7 +620,8 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</TableCell>
</TableRow>
))}
{isLoading && files.length > 0 &&
{isLoading &&
files.length > 0 &&
Array.from({ length: 3 }).map((_, i) => (
<TableRow key={`load-more-skeleton-${i}`}>
<TableCell width="40px" align="center">

View File

@@ -1,5 +1,5 @@
const FilesSectionSkeleton = () => (
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border rounded-lg border">
<div className="p-4">
<div className="mb-4 flex items-center justify-between">
<div className="h-5 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>

View File

@@ -450,7 +450,7 @@ const FileTree: React.FC<FileTreeProps> = ({
{/* Left side with path navigation */}
<div className="flex w-full items-center sm:w-auto">
<button
className="mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="mr-3 flex h-[29px] w-[29px] items-center justify-center rounded-full border p-2 text-sm font-medium text-gray-400 dark:border-0 dark:text-gray-500"
onClick={handleBackNavigation}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
@@ -503,7 +503,7 @@ const FileTree: React.FC<FileTreeProps> = ({
{!processingRef.current && (
<button
onClick={handleAddFile}
className="bg-purple-30 hover:bg-violets-are-blue flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-nowrap text-white"
className="bg-primary hover:bg-primary/90 flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] font-medium whitespace-nowrap text-white"
title={t('settings.sources.addFile')}
>
{t('settings.sources.addFile')}
@@ -599,7 +599,7 @@ const FileTree: React.FC<FileTreeProps> = ({
<div ref={menuRef} className="relative">
<button
onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-[#26272E]"
className="dark:hover:bg-muted inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')}
>
<img
@@ -656,7 +656,7 @@ const FileTree: React.FC<FileTreeProps> = ({
<div ref={menuRef} className="relative">
<button
onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-[#26272E]"
className="dark:hover:bg-muted inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')}
>
<img
@@ -754,11 +754,11 @@ const FileTree: React.FC<FileTreeProps> = ({
}
}}
placeholder={t('settings.sources.searchFiles')}
className={`h-[38px] w-full border border-[#D1D9E0] px-4 py-2 dark:border-[#6A6A6A] ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none dark:text-[#E0E0E0]`}
className={`border-border dark:border-border h-[38px] w-full border px-4 py-2 ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none`}
/>
{searchQuery && (
<div className="absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[12px] border border-t-0 border-[#D1D9E0] bg-white shadow-lg transition-all duration-200 dark:border-[#6A6A6A] dark:bg-[#1F2023]">
<div className="border-border bg-card dark:border-border dark:bg-card absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[12px] border border-t-0 shadow-lg transition-all duration-200">
<div className="max-h-[calc(100vh-200px)] overflow-x-hidden overflow-y-auto overscroll-contain">
{searchResults.length === 0 ? (
<div className="py-2 text-center text-sm text-gray-500 dark:text-gray-400">
@@ -770,9 +770,9 @@ const FileTree: React.FC<FileTreeProps> = ({
key={index}
onClick={() => handleSearchSelect(result)}
title={result.path}
className={`flex min-w-0 cursor-pointer items-center px-3 py-2 hover:bg-[#ECEEEF] dark:hover:bg-[#27282D] ${
className={`hover:bg-muted dark:hover:bg-muted flex min-w-0 cursor-pointer items-center px-3 py-2 ${
index !== searchResults.length - 1
? 'border-b border-[#D1D9E0] dark:border-[#6A6A6A]'
? 'border-border dark:border-border border-b'
: ''
}`}
>
@@ -785,7 +785,7 @@ const FileTree: React.FC<FileTreeProps> = ({
}
className="mr-2 h-4 w-4 flex-shrink-0"
/>
<span className="flex-1 truncate text-sm dark:text-[#E0E0E0]">
<span className="flex-1 truncate text-sm">
{result.name}
</span>
</div>

View File

@@ -41,7 +41,7 @@ export const FileUpload = ({
showPreview = false,
previewSize = 80,
children,
className = 'border-2 border-dashed rounded-3xl p-6 text-center cursor-pointer transition-colors border-silver dark:border-[#7E7E7E]',
className = 'border-2 border-dashed rounded-3xl p-6 text-center cursor-pointer transition-colors border-border dark:border-border',
activeClassName = 'border-blue-500 bg-blue-50',
acceptClassName = 'border-green-500 dark:border-green-500 bg-green-50 dark:bg-green-50/10',
rejectClassName = 'border-red-500 bg-red-50 dark:bg-red-500/10 dark:border-red-500',
@@ -133,7 +133,7 @@ export const FileUpload = ({
});
const currentClassName = twMerge(
'border-2 border-dashed rounded-3xl p-8 text-center cursor-pointer transition-colors border-silver dark:border-[#7E7E7E]',
'border-2 border-dashed rounded-3xl p-8 text-center cursor-pointer transition-colors border-border dark:border-border',
className,
isDragActive && activeClassName,
isDragAccept && acceptClassName,

View File

@@ -262,7 +262,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
/>
{isConnected && (
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
<div className="border-border dark:border-border rounded-lg border">
<div className="p-4">
<div className="mb-4 flex items-center justify-between">
<h3 className="text-sm font-medium">

View File

@@ -36,20 +36,20 @@ const Help = () => {
<button
ref={buttonRef}
onClick={toggleDropdown}
className="mx-4 my-auto flex h-9 w-full items-center gap-4 rounded-3xl hover:bg-gray-100 dark:hover:bg-[#28292E]"
className="hover:bg-sidebar-accent mx-4 my-auto flex h-9 w-full items-center gap-4 rounded-3xl"
>
<img src={Info} alt="info" className="ml-2 w-5 filter dark:invert" />
{t('help')}
</button>
{isOpen && (
<div
className={`dark:bg-outer-space absolute z-10 w-48 translate-x-4 -translate-y-28 rounded-xl bg-white shadow-lg`}
className={`dark:bg-card bg-card absolute z-10 w-48 translate-x-4 -translate-y-28 rounded-xl shadow-lg`}
>
<a
href="https://docs.docsgpt.cloud/"
target="_blank"
rel="noopener noreferrer"
className="hover:bg-bright-gray flex items-start gap-4 rounded-t-xl px-4 py-2 text-black dark:text-white dark:hover:bg-[#545561]"
className="hover:bg-muted text-foreground flex items-start gap-4 rounded-t-xl px-4 py-2"
>
<img
src={PageIcon}
@@ -61,7 +61,7 @@ const Help = () => {
</a>
<a
href="mailto:support@docsgpt.cloud"
className="hover:bg-bright-gray flex items-start gap-4 rounded-b-xl px-4 py-2 text-black dark:text-white dark:hover:bg-[#545561]"
className="hover:bg-muted text-foreground flex items-start gap-4 rounded-b-xl px-4 py-2"
>
<img
src={EmailIcon}

View File

@@ -15,7 +15,7 @@ const Input = ({
borderVariant = 'thick',
textSize = 'medium',
children,
labelBgClassName = 'bg-white dark:bg-raisin-black',
labelBgClassName = 'bg-card',
leftIcon,
onChange,
onPaste,
@@ -23,9 +23,9 @@ const Input = ({
edgeRoundness = 'rounded-full',
}: InputProps) => {
const colorStyles = {
silver: 'border-silver dark:border-silver/40',
silver: 'border-border dark:border-border',
jet: 'border-jet',
gray: 'border-gray-5000 dark:text-silver',
gray: 'border-gray-5000 dark:text-muted-foreground',
};
const borderStyles = {
thin: 'border',
@@ -44,7 +44,7 @@ const Input = ({
<div className={`relative ${className}`}>
<input
ref={inputRef}
className={`peer text-jet dark:text-bright-gray h-[42px] w-full ${edgeRoundness} bg-transparent ${leftIcon ? 'pl-10' : 'px-3'} py-1 placeholder-transparent outline-hidden ${colorStyles[colorVariant]} ${borderStyles[borderVariant]} ${textSizeStyles[textSize]} [&:-webkit-autofill]:appearance-none [&:-webkit-autofill]:bg-transparent [&:-webkit-autofill_selected]:bg-transparent`}
className={`peer text-foreground dark:text-foreground h-[42px] w-full ${edgeRoundness} bg-transparent ${leftIcon ? 'pl-10' : 'px-3'} py-1 placeholder-transparent outline-hidden ${colorStyles[colorVariant]} ${borderStyles[borderVariant]} ${textSizeStyles[textSize]} [&:-webkit-autofill]:appearance-none [&:-webkit-autofill]:bg-transparent [&:-webkit-autofill_selected]:bg-transparent`}
type={type}
id={id}
name={name}
@@ -75,11 +75,11 @@ const Input = ({
: 'peer-placeholder-shown:left-3'
} peer-placeholder-shown:${
textSizeStyles[textSize]
} text-gray-4000 pointer-events-none cursor-none peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs dark:text-gray-400 ${labelBgClassName} max-w-[calc(100%-24px)] overflow-hidden text-ellipsis whitespace-nowrap`}
} text-muted-foreground pointer-events-none cursor-none peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs ${labelBgClassName} max-w-[calc(100%-24px)] overflow-hidden text-ellipsis whitespace-nowrap`}
>
{placeholder}
{required && (
<span className="ml-0.5 text-[#D30000] dark:text-[#D42626]">*</span>
<span className="ml-0.5 text-[#D30000] dark:text-red-500">*</span>
)}
</label>
)}

View File

@@ -1,16 +1,17 @@
import mermaid from 'mermaid';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import mermaid from 'mermaid';
import CopyButton from './CopyButton';
import { useSelector } from 'react-redux';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import {
oneLight,
vscDarkPlus,
} from 'react-syntax-highlighter/dist/cjs/styles/prism';
import { MermaidRendererProps } from './types';
import { useSelector } from 'react-redux';
import { selectStatus } from '../conversation/conversationSlice';
import { useDarkTheme } from '../hooks';
import CopyButton from './CopyButton';
import { MermaidRendererProps } from './types';
const MermaidRenderer: React.FC<MermaidRendererProps> = ({
code,
@@ -262,9 +263,9 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
const errorRender = !isCurrentlyLoading && error;
return (
<div className="w-inherit group border-light-silver dark:border-raisin-black dark:bg-eerie-black relative rounded-lg border bg-white">
<div className="bg-platinum dark:bg-eerie-black-2 flex items-center justify-between px-2 py-1">
<span className="text-just-black dark:text-chinese-white text-xs font-medium">
<div className="w-inherit group border-border bg-card relative rounded-lg border">
<div className="bg-platinum flex items-center justify-between px-2 py-1">
<span className="text-foreground dark:text-foreground text-xs font-medium">
mermaid
</span>
<div className="flex items-center gap-2">
@@ -280,7 +281,7 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
Download <span className="ml-1"></span>
</button>
{showDownloadMenu && (
<div className="absolute right-0 z-10 mt-1 w-40 rounded-sm border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800">
<div className="border-border bg-card absolute right-0 z-10 mt-1 w-40 rounded-sm border shadow-lg">
<ul>
{downloadOptions.map((option, index) => (
<li key={index}>
@@ -289,7 +290,7 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
option.action();
setShowDownloadMenu(false);
}}
className="w-full px-4 py-2 text-left text-xs hover:bg-gray-100 dark:hover:bg-gray-700"
className="hover:bg-muted w-full px-4 py-2 text-left text-xs"
>
{option.label}
</button>
@@ -318,14 +319,14 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
</div>
{isCurrentlyLoading ? (
<div className="dark:bg-eerie-black flex items-center justify-center bg-white p-4">
<div className="bg-card flex items-center justify-center p-4">
<div className="text-sm text-gray-500 dark:text-gray-400">
Loading diagram...
</div>
</div>
) : errorRender ? (
<div className="m-2 rounded-sm border-2 border-red-400 dark:border-red-700">
<div className="overflow-auto bg-red-100 px-4 py-2 text-sm break-words whitespace-normal text-red-800 dark:bg-red-900/30 dark:text-red-300">
<div className="overflow-auto bg-red-100 px-4 py-2 text-sm wrap-break-word whitespace-normal text-red-800 dark:bg-red-900/30 dark:text-red-300">
{error}
</div>
</div>
@@ -333,7 +334,7 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
<>
<div
ref={containerRef}
className="no-scrollbar dark:bg-eerie-black relative block w-full bg-white p-4"
className="no-scrollbar bg-card relative block w-full p-4"
style={{
overflow: 'auto',
scrollbarWidth: 'none',
@@ -399,9 +400,9 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({
</div>
{showCode && (
<div className="border-light-silver dark:border-raisin-black border-t">
<div className="bg-platinum dark:bg-eerie-black-2 p-2">
<span className="text-just-black dark:text-chinese-white text-xs font-medium">
<div className="border-border border-t">
<div className="bg-platinum p-2">
<span className="text-foreground dark:text-foreground text-xs font-medium">
Mermaid Code
</span>
</div>

View File

@@ -1438,7 +1438,7 @@ export default function MessageInput({
onChange={handleVoiceFileAttachment}
/>
<div className="border-dark-gray bg-lotion dark:border-grey relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
<div className="border-border bg-card relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
<div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3">
{attachments.map((attachment) => {
return (
@@ -1448,7 +1448,7 @@ export default function MessageInput({
onDragStart={(e) => handleDragStart(e, attachment.id)}
onDragOver={handleDragOver}
onDrop={(e) => handleDropOn(e, attachment.id)}
className={`group dark:text-bright-gray relative flex items-center rounded-xl bg-[#EFF3F4] px-2 py-1 text-[12px] text-[#5D5D5D] sm:px-3 sm:py-1.5 sm:text-[14px] dark:bg-[#393B3D] ${
className={`group dark:text-foreground bg-muted text-muted-foreground dark:bg-accent relative flex items-center rounded-xl px-2 py-1 text-[12px] sm:px-3 sm:py-1.5 sm:text-[14px] ${
attachment.status !== 'completed'
? 'opacity-70'
: 'opacity-100'
@@ -1459,7 +1459,7 @@ export default function MessageInput({
}`}
title={attachment.fileName}
>
<div className="bg-purple-30 mr-2 flex h-8 w-8 items-center justify-center rounded-md p-1">
<div className="bg-primary mr-2 flex h-8 w-8 items-center justify-center rounded-md p-1">
{attachment.status === 'completed' && (
<img
src={DocumentationDark}
@@ -1551,7 +1551,7 @@ export default function MessageInput({
}
tabIndex={1}
placeholder={t('inputPlaceholder')}
className="inputbox-style no-scrollbar bg-lotion dark:text-bright-gray dark:placeholder:text-bright-gray/50 w-full overflow-x-hidden overflow-y-auto rounded-t-[23px] px-2 text-base leading-tight whitespace-pre-wrap opacity-100 placeholder:text-gray-500 focus:outline-hidden sm:px-3 dark:bg-transparent"
className="inputbox-style no-scrollbar dark:text-foreground dark:placeholder:text-muted-foreground/50 w-full overflow-x-hidden overflow-y-auto rounded-t-[23px] bg-transparent px-2 text-base leading-tight whitespace-pre-wrap opacity-100 placeholder:text-gray-500 focus:outline-hidden sm:px-3"
onInput={handleInput}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
@@ -1564,7 +1564,7 @@ export default function MessageInput({
{showSourceButton && (
<button
ref={sourceButtonRef}
className="xs:px-3 xs:py-1.5 dark:border-purple-taupe flex max-w-[130px] items-center rounded-[32px] border border-[#AAAAAA] px-2 py-1 transition-colors hover:bg-gray-100 sm:max-w-[150px] dark:hover:bg-[#2C2E3C]"
className="xs:px-3 xs:py-1.5 dark:border-border border-border hover:bg-accent dark:hover:bg-muted flex max-w-[130px] items-center rounded-[32px] border px-2 py-1 transition-colors sm:max-w-[150px]"
onClick={() => setIsSourcesPopupOpen(!isSourcesPopupOpen)}
title={
selectedDocs && selectedDocs.length > 0
@@ -1577,7 +1577,7 @@ export default function MessageInput({
alt="Sources"
className="mr-1 h-3.5 w-3.5 shrink-0 sm:mr-1.5 sm:h-4"
/>
<span className="xs:text-[12px] dark:text-bright-gray truncate overflow-hidden text-[10px] font-medium text-[#5D5D5D] sm:text-[14px]">
<span className="xs:text-[12px] dark:text-foreground text-muted-foreground truncate overflow-hidden text-[10px] font-medium sm:text-[14px]">
{selectedDocs && selectedDocs.length > 0
? selectedDocs.length === 1
? selectedDocs[0].name
@@ -1595,7 +1595,7 @@ export default function MessageInput({
{showToolButton && (
<button
ref={toolButtonRef}
className="xs:px-3 xs:py-1.5 xs:max-w-[150px] dark:border-purple-taupe flex max-w-[130px] items-center rounded-[32px] border border-[#AAAAAA] px-2 py-1 transition-colors hover:bg-gray-100 dark:hover:bg-[#2C2E3C]"
className="xs:px-3 xs:py-1.5 xs:max-w-[150px] dark:border-border border-border hover:bg-muted dark:hover:bg-muted flex max-w-[130px] items-center rounded-[32px] border px-2 py-1 transition-colors"
onClick={() => setIsToolsPopupOpen(!isToolsPopupOpen)}
>
<img
@@ -1603,7 +1603,7 @@ export default function MessageInput({
alt="Tools"
className="mr-1 h-3.5 w-3.5 shrink-0 sm:mr-1.5 sm:h-4 sm:w-4"
/>
<span className="xs:text-[12px] dark:text-bright-gray truncate overflow-hidden text-[10px] font-medium text-[#5D5D5D] sm:text-[14px]">
<span className="xs:text-[12px] dark:text-foreground text-muted-foreground truncate overflow-hidden text-[10px] font-medium sm:text-[14px]">
{t('settings.tools.label')}
</span>
</button>
@@ -1620,7 +1620,7 @@ export default function MessageInput({
className={`xs:px-3 xs:py-1.5 dark:border-purple-taupe flex items-center rounded-[32px] border px-2 py-1 transition-colors ${
recordingState === 'recording'
? 'border-[#B42318] bg-[#FEE4E2] text-[#B42318] dark:bg-[#4A2323]'
: 'border-[#AAAAAA] hover:bg-gray-100 dark:hover:bg-[#2C2E3C]'
: 'border-border dark:hover:bg-accent hover:bg-gray-100'
} ${
loading || recordingState === 'transcribing'
? 'cursor-not-allowed opacity-60'
@@ -1645,13 +1645,13 @@ export default function MessageInput({
</span>
</button>
)}
<label className="xs:px-3 xs:py-1.5 dark:border-purple-taupe flex cursor-pointer items-center rounded-[32px] border border-[#AAAAAA] px-2 py-1 transition-colors hover:bg-gray-100 dark:hover:bg-[#2C2E3C]">
<label className="xs:px-3 xs:py-1.5 dark:border-border border-border hover:bg-muted dark:hover:bg-muted flex cursor-pointer items-center rounded-[32px] border px-2 py-1 transition-colors">
<img
src={ClipIcon}
alt="Attach"
className="mr-1 h-3.5 w-3.5 sm:mr-1.5 sm:h-4 sm:w-4"
/>
<span className="xs:text-[12px] dark:text-bright-gray text-[10px] font-medium text-[#5D5D5D] sm:text-[14px]">
<span className="xs:text-[12px] dark:text-foreground text-muted-foreground text-[10px] font-medium sm:text-[14px]">
{t('conversation.attachments.attach')}
</span>
<input
@@ -1669,7 +1669,7 @@ export default function MessageInput({
<button
onClick={handleCancel}
aria-label={t('cancel')}
className={`ml-auto flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-[#7F54D6] text-white sm:h-9 sm:w-9`}
className={`bg-primary ml-auto flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-white sm:h-9 sm:w-9`}
disabled={!loading}
>
<div className="flex h-3 w-3 items-center justify-center rounded-[3px] bg-white sm:h-3.5 sm:w-3.5" />
@@ -1683,8 +1683,8 @@ export default function MessageInput({
!loading &&
recordingState !== 'recording' &&
recordingState !== 'transcribing'
? 'bg-purple-30 text-white'
: 'bg-[#EDEDED] text-[#959595] dark:bg-[#37383D] dark:text-[#77787D]'
? 'bg-primary text-white'
: 'bg-muted text-muted-foreground dark:bg-accent dark:text-muted-foreground'
}`}
disabled={
!value.trim() ||
@@ -1729,12 +1729,12 @@ export default function MessageInput({
{handleDragActive &&
createPortal(
<div className="dark:bg-gray-alpha/50 pointer-events-none fixed top-0 left-0 z-50 flex size-full flex-col items-center justify-center bg-white/85">
<div className="dark:bg-background/85 pointer-events-none fixed top-0 left-0 z-50 flex size-full flex-col items-center justify-center bg-white/85">
<img className="filter dark:invert" src={DragFileUpload} />
<span className="text-outer-space dark:text-silver px-2 text-2xl font-bold">
<span className="text-muted-foreground dark:text-muted-foreground px-2 text-2xl font-bold">
{t('modals.uploadDoc.drag.title')}
</span>
<span className="text-s text-outer-space dark:text-silver w-48 p-2 text-center">
<span className="text-s text-muted-foreground dark:text-muted-foreground w-48 p-2 text-center">
{t('modals.uploadDoc.drag.description')}
</span>
</div>,

View File

@@ -168,7 +168,7 @@ export default function MultiSelectPopup({
return (
<div
ref={popupRef}
className="border-light-silver bg-lotion dark:border-dim-gray dark:bg-charleston-green-2 fixed z-9999 flex flex-col rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
className="border-border bg-background dark:border-border dark:bg-card fixed z-9999 flex flex-col rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
style={{
top: popupPosition.showAbove ? undefined : popupPosition.top,
bottom: popupPosition.showAbove
@@ -198,7 +198,7 @@ export default function MultiSelectPopup({
searchPlaceholder ||
t('settings.tools.searchPlaceholder', 'Search...')
}
labelBgClassName="bg-lotion dark:bg-charleston-green-2"
labelBgClassName="bg-background dark:bg-card"
borderVariant="thin"
className="mb-4"
textSize="small"
@@ -206,13 +206,13 @@ export default function MultiSelectPopup({
)}
</div>
)}
<div className="dark:border-dim-gray mx-4 mb-4 grow overflow-auto rounded-md border border-[#D9D9D9]">
<div className="dark:border-border mx-4 mb-4 grow overflow-auto rounded-md border border-[#D9D9D9]">
{loading ? (
<div className="flex h-full items-center justify-center py-4">
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-gray-900 dark:border-white"></div>
</div>
) : (
<div className="h-full overflow-y-auto scrollbar-overlay">
<div className="scrollbar-overlay h-full overflow-y-auto">
{filteredOptions.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center px-4 py-8 text-center">
<img
@@ -233,7 +233,7 @@ export default function MultiSelectPopup({
<div
key={option.id}
onClick={() => handleOptionClick(option.id)}
className="dark:border-dim-gray dark:hover:bg-charleston-green-3 flex cursor-pointer items-center justify-between border-b border-[#D9D9D9] p-3 last:border-b-0 hover:bg-gray-100"
className="dark:border-border dark:hover:bg-accent hover:bg-accent flex cursor-pointer items-center justify-between border-b border-[#D9D9D9] p-3 last:border-b-0"
role="option"
aria-selected={isSelected}
>
@@ -248,7 +248,7 @@ export default function MultiSelectPopup({
</div>
<div className="shrink-0">
<div
className={`dark:bg-charleston-green-2 flex h-4 w-4 items-center justify-center rounded-xs border-2 border-[#C6C6C6] bg-white dark:border-[#757783]`}
className={`border-border bg-card flex h-4 w-4 items-center justify-center rounded-xs border-2`}
aria-hidden="true"
>
{isSelected && (
@@ -269,7 +269,7 @@ export default function MultiSelectPopup({
)}
</div>
{footerContent && (
<div className="border-light-silver dark:border-dim-gray shrink-0 border-t p-4">
<div className="border-border dark:border-border shrink-0 border-t p-4">
{footerContent}
</div>
)}

View File

@@ -87,7 +87,7 @@ export default function Notification({
))}
</div>
<p className="text-white-3000 relative z-10 text-xs leading-6 font-semibold xl:text-sm xl:leading-7">
<p className="relative z-10 text-xs leading-6 font-semibold text-white xl:text-sm xl:leading-7">
{notificationText}
</p>
<span className="relative z-10 flex items-center">
@@ -132,4 +132,4 @@ export default function Notification({
</a>
</>
);
}
}

View File

@@ -1,271 +0,0 @@
import React from 'react';
import Arrow2 from '../assets/dropdown-arrow.svg';
import Edit from '../assets/edit.svg';
import Search from '../assets/search.svg';
import Trash from '../assets/trash.svg';
/**
* SearchableDropdown - A standalone dropdown component with built-in search functionality
*/
type SearchableDropdownOptionBase = {
id?: string;
type?: string;
};
type NameIdOption = { name: string; id: string } & SearchableDropdownOptionBase;
export type SearchableDropdownOption =
| string
| NameIdOption
| ({ label: string; value: string } & SearchableDropdownOptionBase)
| ({ value: number; description: string } & SearchableDropdownOptionBase);
export type SearchableDropdownSelectedValue = SearchableDropdownOption | null;
export interface SearchableDropdownProps<
T extends SearchableDropdownOption = SearchableDropdownOption,
> {
options: T[];
selectedValue: SearchableDropdownSelectedValue;
onSelect: (value: T) => void;
size?: string;
/** Controls border radius for both button and dropdown menu */
rounded?: 'xl' | '3xl';
border?: 'border' | 'border-2';
showEdit?: boolean;
onEdit?: (value: NameIdOption) => void;
showDelete?: boolean | ((option: T) => boolean);
onDelete?: (id: string) => void;
placeholder?: string;
}
function SearchableDropdown<T extends SearchableDropdownOption>({
options,
selectedValue,
onSelect,
size = 'w-32',
rounded = 'xl',
border = 'border-2',
showEdit,
onEdit,
showDelete,
onDelete,
placeholder,
}: SearchableDropdownProps<T>) {
const dropdownRef = React.useRef<HTMLDivElement>(null);
const searchInputRef = React.useRef<HTMLInputElement>(null);
const [isOpen, setIsOpen] = React.useState(false);
const [searchQuery, setSearchQuery] = React.useState('');
const borderRadius = rounded === 'xl' ? 'rounded-xl' : 'rounded-3xl';
React.useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setIsOpen(false);
setSearchQuery('');
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
React.useEffect(() => {
if (isOpen && searchInputRef.current) {
searchInputRef.current.focus();
}
}, [isOpen]);
const getOptionText = (option: SearchableDropdownOption): string => {
if (typeof option === 'string') return option;
if ('name' in option) return option.name;
if ('label' in option) return option.label;
if ('description' in option) return option.description;
return '';
};
const filteredOptions = React.useMemo(() => {
if (!searchQuery.trim()) return options;
const query = searchQuery.toLowerCase();
return options.filter((option) =>
getOptionText(option).toLowerCase().includes(query),
);
}, [options, searchQuery]);
const getDisplayValue = (): string => {
if (!selectedValue) return placeholder ?? 'From URL';
if (typeof selectedValue === 'string') return selectedValue;
if ('label' in selectedValue) return selectedValue.label;
if ('name' in selectedValue) return selectedValue.name;
if ('description' in selectedValue) {
return selectedValue.value < 1e9
? `${selectedValue.value} (${selectedValue.description})`
: selectedValue.description;
}
return placeholder ?? 'From URL';
};
const isOptionSelected = (option: T): boolean => {
if (!selectedValue) return false;
if (typeof selectedValue === 'string')
return selectedValue === (option as unknown as string);
if (typeof option === 'string') return false;
const optionObj = option as Record<string, unknown>;
const selectedObj = selectedValue as Record<string, unknown>;
if ('name' in optionObj && 'name' in selectedObj)
return selectedObj.name === optionObj.name;
if ('label' in optionObj && 'label' in selectedObj)
return selectedObj.label === optionObj.label;
if ('value' in optionObj && 'value' in selectedObj)
return selectedObj.value === optionObj.value;
return false;
};
return (
<div
className={`relative ${typeof selectedValue === 'string' ? '' : 'align-middle'} ${size}`}
ref={dropdownRef}
>
<button
onClick={() => setIsOpen(!isOpen)}
className={`flex w-full cursor-pointer items-center justify-between ${border} border-silver dark:border-dim-gray bg-white px-5 py-3 dark:bg-transparent ${borderRadius}`}
>
<span
className={`dark:text-bright-gray truncate ${!selectedValue ? 'text-gray-500 dark:text-gray-400' : ''}`}
>
{getDisplayValue()}
</span>
<img
src={Arrow2}
alt="arrow"
className={`h-3 w-3 transform transition-transform ${isOpen ? 'rotate-180' : 'rotate-0'}`}
/>
</button>
{isOpen && (
<div
className={`absolute right-0 left-0 z-20 mt-2 ${borderRadius} dark:bg-dark-charcoal bg-[#FBFBFB] shadow-[0px_24px_48px_0px_#00000029]`}
>
<div
className={`border-silver dark:border-dim-gray dark:bg-dark-charcoal sticky top-0 z-10 border-b bg-[#FBFBFB] px-3 py-2 ${rounded === 'xl' ? 'rounded-t-xl' : 'rounded-t-3xl'}`}
>
<div className="relative flex items-center">
<img
src={Search}
alt="search"
width={14}
height={14}
className="absolute left-3"
/>
<input
ref={searchInputRef}
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search..."
className="dark:text-bright-gray w-full rounded-lg border-0 bg-transparent py-2 pr-3 pl-10 font-['Inter'] text-[14px] leading-[16.5px] font-normal focus:ring-0 focus:outline-none"
onClick={(e) => e.stopPropagation()}
/>
</div>
</div>
<div className="max-h-40 overflow-y-auto">
{filteredOptions.length === 0 ? (
<div className="px-5 py-3 text-center text-sm text-gray-500 dark:text-gray-400">
No results found
</div>
) : (
filteredOptions.map((option, index) => {
const selected = isOptionSelected(option);
const optionObj =
typeof option !== 'string'
? (option as Record<string, unknown>)
: null;
const optionType = optionObj?.type as string | undefined;
const optionId = optionObj?.id as string | undefined;
const optionName = optionObj?.name as string | undefined;
return (
<div
key={index}
className={`flex cursor-pointer items-center justify-between hover:bg-[#ECECEC] dark:hover:bg-[#545561] ${selected ? 'bg-[#ECECEC] dark:bg-[#545561]' : ''}`}
>
<span
onClick={() => {
onSelect(option);
setIsOpen(false);
setSearchQuery('');
}}
className="dark:text-light-gray ml-5 flex-1 overflow-hidden py-3 font-['Inter'] text-[14px] leading-[16.5px] font-normal text-ellipsis whitespace-nowrap"
>
{getOptionText(option)}
</span>
{showEdit &&
onEdit &&
optionObj &&
optionType !== 'public' && (
<img
src={Edit}
alt="Edit"
className="mr-4 h-4 w-4 cursor-pointer hover:opacity-50"
onClick={() => {
if (optionName && optionId) {
onEdit({
id: optionId,
name: optionName,
type: optionType,
});
}
setIsOpen(false);
setSearchQuery('');
}}
/>
)}
{showDelete && onDelete && (
<button
onClick={(e) => {
e.stopPropagation();
const id =
typeof option === 'string'
? option
: (optionId ?? '');
onDelete(id);
}}
className={`mr-2 h-4 w-4 cursor-pointer hover:opacity-50 ${
typeof showDelete === 'function' &&
!showDelete(option)
? 'hidden'
: ''
}`}
>
<img
src={Trash}
alt="Delete"
className={`mr-2 h-4 w-4 cursor-pointer hover:opacity-50 ${
optionType === 'public'
? 'cursor-not-allowed opacity-50'
: ''
}`}
/>
</button>
)}
</div>
);
})
)}
</div>
</div>
)}
</div>
);
}
export default SearchableDropdown;

View File

@@ -51,16 +51,16 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
return (
<div className="relative mt-6 flex flex-row items-center space-x-1 overflow-auto md:space-x-0">
<div
className={`${hiddenGradient === 'left' ? 'hidden' : ''} dark:from-raisin-black pointer-events-none absolute inset-y-0 left-6 w-14 bg-linear-to-r from-white md:hidden`}
className={`${hiddenGradient === 'left' ? 'hidden' : ''} dark:from-background pointer-events-none absolute inset-y-0 left-6 w-14 bg-linear-to-r from-white md:hidden`}
></div>
<div
className={`${hiddenGradient === 'right' ? 'hidden' : ''} dark:from-raisin-black pointer-events-none absolute inset-y-0 right-6 w-14 bg-linear-to-l from-white md:hidden`}
className={`${hiddenGradient === 'right' ? 'hidden' : ''} dark:from-background pointer-events-none absolute inset-y-0 right-6 w-14 bg-linear-to-l from-white md:hidden`}
></div>
<div className="z-10 md:hidden">
<button
onClick={() => scrollTabs(-1)}
className="flex h-6 w-6 items-center justify-center rounded-full transition-all hover:bg-gray-200 dark:hover:bg-gray-700"
className="hover:bg-muted dark:hover:bg-accent flex h-6 w-6 items-center justify-center rounded-full transition-all"
aria-label={t('settings.scrollTabsLeft')}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3" />
@@ -78,8 +78,8 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
onClick={() => setActiveTab(tab)}
className={`h-9 snap-start rounded-3xl px-4 font-bold transition-colors ${
activeTab === tab
? 'dark:bg-dark-charcoal bg-[#F4F4F5] text-neutral-900 dark:text-white'
: 'text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white'
? 'bg-muted text-foreground dark:bg-accent dark:text-white'
: 'text-muted-foreground hover:text-foreground dark:text-neutral-400 dark:hover:text-white'
}`}
role="tab"
aria-selected={activeTab === tab}
@@ -93,7 +93,7 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
<div className="z-10 md:hidden">
<button
onClick={() => scrollTabs(1)}
className="flex h-6 w-6 items-center justify-center rounded-full hover:bg-gray-200 dark:hover:bg-gray-700"
className="hover:bg-muted dark:hover:bg-accent flex h-6 w-6 items-center justify-center rounded-full"
aria-label={t('settings.scrollTabsRight')}
>
<img src={ArrowRight} alt="right-arrow" className="h-3" />

View File

@@ -33,13 +33,13 @@ export default function Sidebar({
return (
<div ref={sidebarRef} className="h-vh relative">
<div
className={`dark:bg-chinese-black fixed top-0 right-0 z-50 h-full w-64 transform bg-white shadow-xl transition-all duration-300 sm:w-80 ${
className={`bg-card fixed top-0 right-0 z-50 h-full w-64 transform shadow-xl transition-all duration-300 sm:w-80 ${
isOpen ? 'translate-x-[10px]' : 'translate-x-full'
} border-l border-[#9ca3af]/10`}
>
<div className="flex w-full flex-row items-end justify-end px-4 pt-3">
<button
className="hover:bg-gray-1000 dark:hover:bg-gun-metal w-7 rounded-full p-2"
className="hover:bg-accent w-7 rounded-full p-2"
onClick={() => toggleState(!isOpen)}
>
<img className="filter dark:invert" src={Exit} />

View File

@@ -97,7 +97,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{[...Array(8)].map((_, idx) => (
<div
key={idx}
className="dark:hover:bg-dark-charcoal flex w-full items-start p-2 hover:bg-[#F9F9F9]"
className="dark:hover:bg-accent hover:bg-muted flex w-full items-start p-2"
>
<div className="flex w-full items-center gap-2">
<div className="h-3 w-3 rounded-lg bg-gray-300 dark:bg-gray-600"></div>
@@ -119,7 +119,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
key={idx}
className={`p-6 ${
skeletonCount === 1 ? 'w-full' : 'w-60'
} dark:bg-raisin-black animate-pulse rounded-3xl`}
} animate-pulse rounded-3xl`}
>
<div className="space-y-4">
<div>
@@ -154,10 +154,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
const renderAnalysis = () => (
<>
{[...Array(skeletonCount)].map((_, idx) => (
<div
key={idx}
className="dark:bg-raisin-black w-full animate-pulse rounded-3xl p-6"
>
<div key={idx} className="bg-card w-full animate-pulse rounded-3xl p-6">
<div className="space-y-6">
<div className="space-y-2">
<div className="mb-4 h-4 w-1/3 rounded-sm bg-gray-300 dark:bg-gray-600"></div>
@@ -189,10 +186,10 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{Array.from({ length: count }).map((_, index) => (
<div
key={`chunk-skel-${index}`}
className="relative flex h-[197px] w-full max-w-[487px] animate-pulse flex-col overflow-hidden rounded-[5.86px] border border-[#D1D9E0] dark:border-[#6A6A6A]"
className="border-border dark:border-border relative flex h-[197px] w-full max-w-[487px] animate-pulse flex-col overflow-hidden rounded-[5.86px] border"
>
<div className="w-full">
<div className="flex w-full items-center justify-between border-b border-[#D1D9E0] bg-[#F6F8FA] px-4 py-3 dark:border-[#6A6A6A] dark:bg-[#27282D]">
<div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="h-4 w-20 rounded bg-gray-300 dark:bg-gray-600"></div>
</div>
<div className="space-y-3 px-4 pt-4 pb-6">
@@ -214,7 +211,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{Array.from({ length: count }).map((_, idx) => (
<div
key={`source-skel-${idx}`}
className="flex h-[130px] w-full animate-pulse flex-col rounded-2xl bg-[#F9F9F9] p-3 dark:bg-[#383838]"
className="bg-muted dark:bg-accent flex h-[130px] w-full animate-pulse flex-col rounded-2xl p-3"
>
<div className="w-full flex-1">
<div className="flex w-full items-center justify-between gap-2">

View File

@@ -107,7 +107,7 @@ export default function SourcesPopup({
const popupContent = (
<div
ref={popupRef}
className="bg-lotion dark:bg-charleston-green-2 fixed z-50 flex flex-col rounded-xl shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
className="bg-background dark:bg-card fixed z-50 flex flex-col rounded-xl shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
style={{
top: popupPosition.showAbove ? popupPosition.top : undefined,
bottom: popupPosition.showAbove
@@ -122,7 +122,7 @@ export default function SourcesPopup({
>
<div className="flex h-full flex-col">
<div className="shrink-0 px-4 py-4 md:px-6">
<h2 className="dark:text-bright-gray mb-4 text-lg font-bold text-[#141414] dark:text-[20px]">
<h2 className="dark:text-foreground mb-4 text-lg font-bold text-[#141414] dark:text-[20px]">
{t('conversation.sources.text')}
</h2>
@@ -135,11 +135,11 @@ export default function SourcesPopup({
placeholder={t('settings.sources.searchPlaceholder')}
borderVariant="thin"
className="mb-4"
labelBgClassName="bg-lotion dark:bg-charleston-green-2"
labelBgClassName="bg-background dark:bg-card"
/>
</div>
<div className="dark:border-dim-gray mx-4 grow overflow-y-auto rounded-md border border-[#D9D9D9] scrollbar-overlay">
<div className="dark:border-border scrollbar-overlay mx-4 grow overflow-y-auto rounded-md border border-[#D9D9D9]">
{options ? (
<>
{filteredOptions?.map((option: any, index: number) => {
@@ -154,7 +154,7 @@ export default function SourcesPopup({
return (
<div
key={index}
className="border-opacity-80 dark:border-dim-gray flex cursor-pointer items-center border-b border-[#D9D9D9] p-3 transition-colors hover:bg-gray-100 dark:text-[14px] dark:hover:bg-[#2C2E3C]"
className="border-opacity-80 dark:border-border hover:bg-muted flex cursor-pointer items-center border-b border-[#D9D9D9] p-3 transition-colors dark:text-[14px]"
onClick={() => {
if (isSelected) {
const updatedDocs =
@@ -186,11 +186,11 @@ export default function SourcesPopup({
height={14}
className="mr-3 shrink-0"
/>
<span className="dark:text-bright-gray mr-3 grow overflow-hidden font-medium text-ellipsis whitespace-nowrap text-[#5D5D5D]">
<span className="dark:text-foreground mr-3 grow overflow-hidden font-medium text-ellipsis whitespace-nowrap text-[#5D5D5D]">
{option.name}
</span>
<div
className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px] dark:border-[#757783]`}
className={`dark:border-border flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px]`}
>
{isSelected && (
<img
@@ -205,7 +205,7 @@ export default function SourcesPopup({
})}
</>
) : (
<div className="dark:text-bright-gray p-4 text-center text-gray-500 dark:text-[14px]">
<div className="dark:text-foreground p-4 text-center text-gray-500 dark:text-[14px]">
{t('conversation.sources.noSourcesAvailable')}
</div>
)}
@@ -214,7 +214,7 @@ export default function SourcesPopup({
<div className="shrink-0 px-4 py-4 opacity-75 transition-opacity duration-200 hover:opacity-100 md:px-6">
<a
href="/settings/sources"
className="text-violets-are-blue inline-flex items-center gap-2 text-base font-medium"
className="text-primary inline-flex items-center gap-2 text-base font-medium"
onClick={onClose}
>
{t('settings.sources.goToSources')}
@@ -225,7 +225,7 @@ export default function SourcesPopup({
<div className="flex shrink-0 justify-start px-4 py-3 md:px-6">
<button
onClick={handleUploadClick}
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue w-auto rounded-full border px-4 py-2 text-[14px] font-medium transition-colors duration-200 hover:text-white"
className="border-primary text-primary hover:bg-primary/90 w-auto rounded-full border px-4 py-2 text-[14px] font-medium transition-colors duration-200 hover:text-white"
>
{t('settings.sources.uploadNew')}
</button>

View File

@@ -46,7 +46,7 @@ const TableContainer = React.forwardRef<HTMLDivElement, TableContainerProps>(
<div className={`relative rounded-[6px] ${className}`}>
<div
ref={ref}
className={`w-full overflow-x-auto rounded-[6px] bg-transparent ${bordered ? 'border border-[#D7D7D7] dark:border-[#6A6A6A]' : ''}`}
className={`w-full overflow-x-auto rounded-[6px] bg-transparent ${bordered ? 'border-border dark:border-border border' : ''}`}
style={{
maxHeight: height === 'auto' ? undefined : height,
overflowY: height === 'auto' ? 'hidden' : 'auto',
@@ -75,7 +75,7 @@ const Table: React.FC<TableProps> = ({
const TableHead: React.FC<TableHeadProps> = ({ children, className = '' }) => {
return (
<thead
className={`sticky top-0 z-10 bg-gray-100 dark:bg-[#27282D] ${className} `}
className={`dark:bg-card sticky top-0 z-10 bg-gray-100 ${className} `}
>
{children}
</thead>
@@ -96,7 +96,7 @@ const TableRow: React.FC<TableRowProps> = ({
onClick,
}) => {
const baseClasses =
'border-b border-[#D7D7D7] hover:bg-[#ECEEEF] dark:border-[#6A6A6A] dark:hover:bg-[#27282D]';
'border-b border-border hover:bg-muted dark:border-border dark:hover:bg-muted';
const cursorClass = onClick ? 'cursor-pointer' : '';
return (
@@ -127,7 +127,7 @@ const TableHeader: React.FC<TableCellProps> = ({
}
};
const baseClasses = `px-2 py-3 text-sm font-medium text-gray-700 lg:px-3 dark:text-[#59636E] border-b border-[#D7D7D7] dark:border-[#6A6A6A] relative box-border ${getAlignmentClass()}`;
const baseClasses = `px-2 py-3 text-sm font-medium text-gray-700 lg:px-3 dark:text-muted-foreground border-b border-border dark:border-border relative box-border ${getAlignmentClass()}`;
const widthClasses = minWidth ? minWidth : '';
return (
@@ -158,7 +158,7 @@ const TableCell: React.FC<TableCellProps> = ({
}
};
const baseClasses = `px-2 py-2 text-sm lg:px-3 dark:text-[#E0E0E0] box-border ${getAlignmentClass()}`;
const baseClasses = `px-2 py-2 text-sm lg:px-3 box-border ${getAlignmentClass()}`;
const widthClasses = minWidth ? minWidth : '';
return (

View File

@@ -176,9 +176,7 @@ export default function SpeakButton({ text }: { text: string }) {
<button
type="button"
className={`flex cursor-pointer items-center justify-center rounded-full p-2 ${
isSpeaking || isLoading
? 'dark:bg-purple-taupe bg-[#EEEEEE]'
: 'bg-white-3000 dark:hover:bg-purple-taupe hover:bg-[#EEEEEE] dark:bg-transparent'
isSpeaking || isLoading ? 'bg-accent' : 'hover:bg-accent bg-transparent'
}`}
onClick={handleSpeakClick}
aria-label={

View File

@@ -52,7 +52,7 @@ const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
>
{label && (
<span
className={`text-eerie-black dark:text-white ${
className={`text-foreground dark:text-white ${
labelPosition === 'left' ? 'mr-3' : 'ml-3'
}`}
>

View File

@@ -137,7 +137,7 @@ export default function ToolsPopup({
const popupContent = (
<div
ref={popupRef}
className="border-light-silver bg-lotion dark:border-dim-gray dark:bg-charleston-green-2 fixed z-50 rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
className="border-border bg-background dark:border-border dark:bg-card fixed z-50 rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
style={{
top: popupPosition.showAbove ? popupPosition.top : undefined,
bottom: popupPosition.showAbove
@@ -163,7 +163,7 @@ export default function ToolsPopup({
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder={t('settings.tools.searchPlaceholder')}
labelBgClassName="bg-lotion dark:bg-charleston-green-2"
labelBgClassName="bg-background dark:bg-card"
borderVariant="thin"
className="mb-4"
/>
@@ -174,8 +174,8 @@ export default function ToolsPopup({
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-gray-900 dark:border-white"></div>
</div>
) : (
<div className="dark:border-dim-gray mx-4 grow overflow-hidden rounded-md border border-[#D9D9D9]">
<div className="h-full overflow-y-auto scrollbar-overlay">
<div className="dark:border-border mx-4 grow overflow-hidden rounded-md border border-[#D9D9D9]">
<div className="scrollbar-overlay h-full overflow-y-auto">
{filteredTools.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center py-8">
<img
@@ -192,7 +192,7 @@ export default function ToolsPopup({
<div
key={tool.id}
onClick={() => updateToolStatus(tool.id, !tool.status)}
className="dark:border-dim-gray dark:hover:bg-charleston-green-3 flex items-center justify-between border-b border-[#D9D9D9] p-3 hover:bg-gray-100"
className="dark:border-border dark:hover:bg-accent hover:bg-accent flex items-center justify-between border-b border-[#D9D9D9] p-3"
>
<div className="mr-3 flex grow items-center">
<img
@@ -208,7 +208,7 @@ export default function ToolsPopup({
</div>
<div className="flex shrink-0 items-center">
<div
className={`flex h-4 w-4 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px] dark:border-[#757783]`}
className={`dark:border-border flex h-4 w-4 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px]`}
>
{tool.status && (
<img
@@ -230,7 +230,7 @@ export default function ToolsPopup({
<div className="shrink-0 p-4 opacity-75 transition-opacity duration-200 hover:opacity-100">
<a
href="/settings/tools"
className="text-purple-30 inline-flex items-center text-base font-medium"
className="text-primary inline-flex items-center text-base font-medium"
>
{t('settings.tools.manageTools')}
<img

View File

@@ -1,11 +1,11 @@
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { selectUploadTasks, dismissUploadTask } from '../upload/uploadSlice';
import ChevronDown from '../assets/chevron-down.svg';
import { useDispatch, useSelector } from 'react-redux';
import CheckCircleFilled from '../assets/check-circle-filled.svg';
import ChevronDown from '../assets/chevron-down.svg';
import WarnIcon from '../assets/warn.svg';
import { dismissUploadTask, selectUploadTasks } from '../upload/uploadSlice';
const PROGRESS_RADIUS = 10;
const PROGRESS_CIRCUMFERENCE = 2 * Math.PI * PROGRESS_RADIUS;
@@ -65,23 +65,17 @@ export default function UploadToast() {
return (
<div
key={task.id}
className={`w-[271px] overflow-hidden rounded-2xl border border-[#00000021] shadow-[0px_24px_48px_0px_#00000029] transition-all duration-300 ${
task.status === 'completed'
? 'bg-[#FBFBFB] dark:bg-[#26272E]'
: task.status === 'failed'
? 'bg-[#FBFBFB] dark:bg-[#26272E]'
: 'bg-[#FBFBFB] dark:bg-[#26272E]'
}`}
className={`border-border bg-card w-[271px] overflow-hidden rounded-2xl border shadow-[0px_24px_48px_0px_#00000029] transition-all duration-300`}
>
<div className="flex flex-col">
<div
className={`flex items-center justify-between px-4 py-3 ${
task.status !== 'failed'
? 'bg-[#FBF2FE] dark:bg-transparent'
: ''
? 'bg-accent/50 dark:bg-muted'
: 'bg-destructive/10 dark:bg-destructive/10'
}`}
>
<h3 className="font-inter text-[14px] leading-[16.5px] font-medium text-black dark:text-[#DCDCDC]">
<h3 className="font-inter dark:text-foreground text-[14px] leading-[16.5px] font-medium text-black">
{getStatusHeading(task.status)}
</h3>
<div className="flex items-center gap-1">
@@ -147,7 +141,7 @@ export default function UploadToast() {
>
<div className="flex items-center justify-between px-5 py-3">
<p
className="font-inter max-w-[200px] truncate text-[13px] leading-[16.5px] font-normal text-black dark:text-[#B7BAB8]"
className="font-inter dark:text-muted-foreground max-w-[200px] truncate text-[13px] leading-[16.5px] font-normal text-black"
title={task.fileName}
>
{task.fileName}
@@ -159,7 +153,7 @@ export default function UploadToast() {
width="24"
height="24"
viewBox="0 0 24 24"
className="h-6 w-6 flex-shrink-0 text-[#7D54D1]"
className="h-6 w-6 shrink-0 text-[#7D54D1]"
role="progressbar"
aria-valuemin={0}
aria-valuemax={100}
@@ -172,7 +166,7 @@ export default function UploadToast() {
)}
>
<circle
className="text-gray-300 dark:text-gray-700"
className="text-muted dark:text-muted-foreground/30"
stroke="currentColor"
strokeWidth="2"
cx="12"
@@ -200,7 +194,7 @@ export default function UploadToast() {
<img
src={CheckCircleFilled}
alt=""
className="h-6 w-6 flex-shrink-0"
className="h-6 w-6 shrink-0"
aria-hidden="true"
/>
)}
@@ -209,7 +203,7 @@ export default function UploadToast() {
<img
src={WarnIcon}
alt=""
className="h-6 w-6 flex-shrink-0"
className="h-6 w-6 shrink-0"
aria-hidden="true"
/>
)}

View File

@@ -1,45 +0,0 @@
export type DropdownOptionBase = {
id?: string;
type?: string;
};
export type StringOption = string;
export type NameIdOption = { name: string; id: string } & DropdownOptionBase;
export type LabelValueOption = {
label: string;
value: string;
} & DropdownOptionBase;
export type ValueDescriptionOption = {
value: number;
description: string;
} & DropdownOptionBase;
export type DropdownOption =
| StringOption
| NameIdOption
| LabelValueOption
| ValueDescriptionOption;
export type DropdownSelectedValue = DropdownOption | null;
export type OnSelectHandler<T extends DropdownOption = DropdownOption> = (
value: T,
) => void;
export interface DropdownProps<T extends DropdownOption = DropdownOption> {
options: T[];
selectedValue: DropdownSelectedValue;
onSelect: OnSelectHandler<T>;
size?: string;
rounded?: 'xl' | '3xl';
buttonClassName?: string;
optionsClassName?: string;
border?: 'border' | 'border-2';
showEdit?: boolean;
onEdit?: (value: NameIdOption) => void;
showDelete?: boolean | ((option: T) => boolean);
onDelete?: (id: string) => void;
placeholder?: string;
placeholderClassName?: string;
contentSize?: string;
}

View File

@@ -8,8 +8,8 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
type={type}
data-slot="input"
className={cn(
'text-foreground file:text-foreground placeholder:text-muted-foreground border-silver h-[42px] w-full min-w-0 rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'dark:border-silver/40 dark:bg-transparent dark:text-white dark:placeholder:text-gray-400',
'text-foreground file:text-foreground placeholder:text-muted-foreground border-border h-[42px] w-full min-w-0 rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'dark:border-border dark:text-white dark:placeholder:text-gray-400',
'selection:bg-primary selection:text-primary-foreground',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',

View File

@@ -70,7 +70,7 @@ export function MultiSelect({
role="combobox"
aria-expanded={open}
className={cn(
'h-auto min-h-[2.5rem] w-full justify-between border-[#E5E5E5] bg-white py-1.5 hover:bg-gray-50 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838]',
'border-border bg-card hover:bg-accent h-auto min-h-10 w-full justify-between py-1.5',
!selected.length && 'text-gray-500 dark:text-gray-400',
className,
)}
@@ -85,7 +85,7 @@ export function MultiSelect({
return (
<span
key={option?.value || label}
className="dark:bg-purple-30/30 bg-violets-are-blue/20 inline-flex max-w-[calc(100%-1rem)] items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium text-purple-700 dark:text-purple-300"
className="bg-primary/20 dark:bg-primary/30 inline-flex max-w-[calc(100%-1rem)] min-w-0 items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium text-purple-700 dark:text-purple-300"
>
<span className="truncate">{label}</span>
<span
@@ -124,7 +124,7 @@ export function MultiSelect({
</Button>
</PopoverTrigger>
<PopoverContent
className="w-(--radix-popover-trigger-width) border-[#E5E5E5] bg-white p-0 dark:border-[#3A3A3A] dark:bg-[#2C2C2C]"
className="border-border bg-card w-(--radix-popover-trigger-width) p-0"
align="start"
>
<Command className="bg-transparent">
@@ -141,13 +141,13 @@ export function MultiSelect({
key={option.value}
value={option.label}
onSelect={() => handleSelect(option.value)}
className="cursor-pointer dark:hover:bg-[#383838]"
className="cursor-pointer"
>
<div
className={cn(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border-2',
isSelected
? 'border-purple-30 bg-purple-30 text-white'
? 'border-primary bg-primary text-white'
: 'border-gray-400 dark:border-gray-500',
)}
>

View File

@@ -37,11 +37,11 @@ function SelectTrigger({
data-slot="select-trigger"
data-size={size}
className={cn(
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 data-[size=lg]:h-[42px] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-gray-600 dark:[&_svg:not([class*='text-'])]:text-gray-400",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=lg]:h-[42px] data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-gray-600 dark:[&_svg:not([class*='text-'])]:text-gray-400",
variant === 'default' &&
'border-light-silver bg-white focus-visible:ring-purple-30/50 hover:bg-gray-50 data-placeholder:text-gray-500 dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:hover:bg-[#383838] dark:data-placeholder:text-gray-400',
'border-border bg-card focus-visible:ring-ring/50 hover:bg-accent data-placeholder:text-muted-foreground',
variant === 'ghost' &&
'border-silver bg-transparent focus-visible:ring-purple-30/50 hover:bg-gray-50 data-[state=open]:bg-gray-50 data-placeholder:text-gray-500 dark:border-silver/40 dark:bg-transparent dark:hover:bg-white/5 dark:data-[state=open]:bg-white/10 dark:data-placeholder:text-gray-400',
'border-border focus-visible:ring-ring/50 hover:bg-accent data-[state=open]:bg-muted data-placeholder:text-muted-foreground dark:border-border dark:hover:bg-accent dark:data-[state=open]:bg-muted bg-transparent',
className,
)}
{...props}
@@ -66,7 +66,7 @@ function SelectContent({
<SelectPrimitive.Content
data-slot="select-content"
className={cn(
'border-light-silver bg-lotion data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-200 max-h-(--radix-select-content-available-height) min-w-32 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border text-gray-900 shadow-md dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white',
'border-border bg-card data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-200 max-h-(--radix-select-content-available-height) min-w-32 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border text-gray-900 shadow-md dark:text-white',
position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className,
@@ -113,7 +113,7 @@ function SelectItem({
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
"[&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none hover:bg-gray-100 data-disabled:pointer-events-none data-disabled:opacity-50 dark:hover:bg-[#383838] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
"[&_svg:not([class*='text-'])]:text-muted-foreground hover:bg-muted relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className,
)}
{...props}

View File

@@ -1,29 +1,29 @@
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { XIcon } from "lucide-react"
import * as React from 'react';
import * as SheetPrimitive from '@radix-ui/react-dialog';
import { XIcon } from 'lucide-react';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return <SheetPrimitive.Root data-slot="sheet" {...props} />
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
}
function SheetTrigger({
...props
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
}
function SheetClose({
...props
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
}
function SheetPortal({
...props
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
}
function SheetOverlay({
@@ -34,23 +34,23 @@ function SheetOverlay({
<SheetPrimitive.Overlay
data-slot="sheet-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
className
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
className,
)}
{...props}
/>
)
);
}
function SheetContent({
className,
children,
side = "right",
side = 'right',
showCloseButton = true,
...props
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
side?: "top" | "right" | "bottom" | "left"
showCloseButton?: boolean
side?: 'top' | 'right' | 'bottom' | 'left';
showCloseButton?: boolean;
}) {
return (
<SheetPortal>
@@ -58,16 +58,16 @@ function SheetContent({
<SheetPrimitive.Content
data-slot="sheet-content"
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
side === "right" &&
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
side === "left" &&
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
side === "top" &&
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
side === "bottom" &&
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
className
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
side === 'right' &&
'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
side === 'left' &&
'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
side === 'top' &&
'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
side === 'bottom' &&
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
className,
)}
{...props}
>
@@ -80,27 +80,27 @@ function SheetContent({
)}
</SheetPrimitive.Content>
</SheetPortal>
)
);
}
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="sheet-header"
className={cn("flex flex-col gap-1.5 p-4", className)}
className={cn('flex flex-col gap-1.5 p-4', className)}
{...props}
/>
)
);
}
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="sheet-footer"
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
{...props}
/>
)
);
}
function SheetTitle({
@@ -110,10 +110,10 @@ function SheetTitle({
return (
<SheetPrimitive.Title
data-slot="sheet-title"
className={cn("text-foreground font-semibold", className)}
className={cn('text-foreground font-semibold', className)}
{...props}
/>
)
);
}
function SheetDescription({
@@ -123,10 +123,10 @@ function SheetDescription({
return (
<SheetPrimitive.Description
data-slot="sheet-description"
className={cn("text-muted-foreground text-sm", className)}
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
)
);
}
export {
@@ -138,4 +138,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
}
};

View File

@@ -263,7 +263,7 @@ export default function Conversation() {
/>
</div>
<p className="text-gray-4000 dark:text-sonic-silver hidden w-full self-center bg-transparent py-2 text-center text-xs md:inline">
<p className="text-muted-foreground hidden w-full self-center bg-transparent py-2 text-center text-xs md:inline">
{t('tagline')}
</p>
</div>

View File

@@ -140,9 +140,9 @@ const ConversationBubble = forwardRef<
<div
key={index}
title={file.fileName}
className="dark:text-bright-gray flex items-center rounded-xl bg-[#EFF3F4] p-2 text-[14px] text-[#5D5D5D] dark:bg-[#393B3D]"
className="dark:text-foreground dark:bg-accent flex items-center rounded-xl bg-[#EFF3F4] p-2 text-[14px] text-[#5D5D5D]"
>
<div className="bg-purple-30 mr-2 items-center justify-center rounded-lg p-[5.5px]">
<div className="bg-primary mr-2 items-center justify-center rounded-lg p-[5.5px]">
<img
src={DocumentationDark}
alt="Attachment"
@@ -201,7 +201,7 @@ const ConversationBubble = forwardRef<
setIsEditClicked(true);
setEditInputBox(message ?? '');
}}
className={`hover:bg-light-silver mt-3 flex h-fit shrink-0 cursor-pointer items-center rounded-full p-2 pt-1.5 pl-1.5 dark:hover:bg-[#35363B] ${isEditClicked ? 'visible' : 'invisible group-hover:visible'}`}
className={`hover:bg-accent dark:hover:bg-accent mt-3 flex h-fit shrink-0 cursor-pointer items-center rounded-full p-2 pt-1.5 pl-1.5 ${isEditClicked ? 'visible' : 'invisible group-hover:visible'}`}
>
<img src={Edit} alt="Edit" className="cursor-pointer" />
</button>
@@ -226,17 +226,17 @@ const ConversationBubble = forwardRef<
}}
rows={5}
value={editInputBox}
className="border-silver text-carbon dark:border-philippine-grey dark:bg-raisin-black dark:text-chinese-white w-full resize-none rounded-3xl border px-4 py-3 text-base leading-relaxed focus:outline-hidden"
className="border-border text-carbon dark:border-philippine-grey dark:text-foreground w-full resize-none rounded-3xl border px-4 py-3 text-base leading-relaxed focus:outline-hidden"
/>
<div className="flex items-center justify-end gap-2">
<button
className="text-purple-30 hover:bg-gainsboro hover:text-chinese-black-2 dark:hover:bg-onyx-2 rounded-full px-4 py-2 text-sm font-semibold transition-colors dark:hover:text-[#B9BCBE]"
className="text-primary hover:bg-muted hover:text-foreground dark:hover:bg-accent dark:hover:text-foreground rounded-full px-4 py-2 text-sm font-semibold transition-colors"
onClick={() => setIsEditClicked(false)}
>
{t('conversation.edit.cancel')}
</button>
<button
className="bg-purple-30 hover:bg-violets-are-blue dark:hover:bg-royal-purple rounded-full px-4 py-2 text-sm font-medium text-white transition-colors"
className="bg-primary hover:bg-primary/90 dark:hover:bg-primary/90 rounded-full px-4 py-2 text-sm font-medium text-white transition-colors"
onClick={handleEditClick}
>
{t('conversation.edit.update')}
@@ -305,7 +305,7 @@ const ConversationBubble = forwardRef<
bubble = (
<div
ref={ref}
className={`flex flex-wrap self-start ${className} group dark:text-bright-gray flex-col`}
className={`flex flex-wrap self-start ${className} group dark:text-foreground flex-col`}
>
{DisableSourceFE ||
type === 'ERROR' ||
@@ -332,9 +332,13 @@ const ConversationBubble = forwardRef<
<div className="fade-in mr-5 ml-3 max-w-[90vw] md:max-w-[70vw] lg:max-w-[50vw]">
<div className="grid grid-cols-2 gap-2 lg:grid-cols-4">
{sources?.slice(0, 3)?.map((source, index) => (
<div key={index} id={`source-${index}`} className="relative transition-all duration-300">
<div
key={index}
id={`source-${index}`}
className="relative transition-all duration-300"
>
<div
className="bg-gray-1000 dark:bg-gun-metal h-28 cursor-pointer rounded-4xl p-4 hover:bg-[#F1F1F1] dark:hover:bg-[#2C2E3C]"
className="bg-muted hover:bg-accent dark:bg-answer-bubble dark:hover:bg-muted h-28 cursor-pointer rounded-4xl p-4"
onMouseOver={() => setActiveTooltip(index)}
onMouseOut={() => setActiveTooltip(null)}
>
@@ -344,7 +348,7 @@ const ConversationBubble = forwardRef<
<div
className={`mt-3.5 flex flex-row items-center gap-1.5 underline-offset-2 ${
source.link && source.link !== 'local'
? 'hover:text-[#007DFF] hover:underline dark:hover:text-[#48A0FF]'
? 'hover:text-[#007DFF] hover:underline dark:hover:text-blue-400'
: ''
}`}
onClick={() =>
@@ -378,7 +382,7 @@ const ConversationBubble = forwardRef<
</div>
{activeTooltip === index && (
<div
className={`dark:bg-chinese-black dark:text-chinese-silver absolute left-1/2 z-50 max-h-48 w-40 translate-x-[-50%] translate-y-[3px] rounded-xl bg-[#FBFBFB] p-4 text-black shadow-xl sm:w-56`}
className={`dark:bg-card dark:text-foreground absolute left-1/2 z-50 max-h-48 w-40 translate-x-[-50%] translate-y-[3px] rounded-xl bg-[#FBFBFB] p-4 text-black shadow-xl sm:w-56`}
onMouseOver={() => setActiveTooltip(index)}
onMouseOut={() => setActiveTooltip(null)}
>
@@ -391,7 +395,7 @@ const ConversationBubble = forwardRef<
))}
{(sources?.length ?? 0) > 3 && (
<div
className="bg-gray-1000 text-purple-30 dark:bg-gun-metal flex h-28 cursor-pointer flex-col-reverse rounded-4xl p-4 hover:bg-[#F1F1F1] hover:text-[#6D3ECC] dark:hover:bg-[#2C2E3C] dark:hover:text-[#8C67D7]"
className="bg-muted text-primary hover:bg-accent hover:text-primary dark:bg-answer-bubble dark:hover:bg-muted dark:hover:text-primary flex h-28 cursor-pointer flex-col-reverse rounded-4xl p-4"
onClick={() => setIsSidebarOpen(true)}
>
<p className="ellipsis-text h-22 text-xs">
@@ -469,9 +473,9 @@ const ConversationBubble = forwardRef<
</p>
</div>
<div
className={`fade-in-bubble bg-gray-1000 dark:bg-gun-metal mr-5 flex max-w-full rounded-[18px] px-6 py-4.5 ${
className={`fade-in-bubble bg-answer-bubble mr-5 flex max-w-full rounded-[18px] px-6 py-4.5 ${
type === 'ERROR'
? 'text-red-3000 dark:border-red-2000 relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal dark:text-white'
? 'text-destructive/80 dark:border-destructive dark:bg-destructive/15 relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal dark:text-white'
: 'flex-col rounded-3xl'
}`}
>
@@ -495,11 +499,26 @@ const ConversationBubble = forwardRef<
<button
type="button"
onClick={() => {
const el = document.getElementById(`source-${sourceIdx}`);
const el = document.getElementById(
`source-${sourceIdx}`,
);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('ring-2', 'ring-purple-500');
setTimeout(() => el.classList.remove('ring-2', 'ring-purple-500'), 2000);
el.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
el.classList.add(
'ring-2',
'ring-purple-500',
);
setTimeout(
() =>
el.classList.remove(
'ring-2',
'ring-purple-500',
),
2000,
);
}
}}
className="mx-0.5 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-purple-100 px-1.5 text-xs font-semibold text-purple-700 transition-colors hover:bg-purple-200 dark:bg-purple-900/40 dark:text-purple-300 dark:hover:bg-purple-900/60"
@@ -509,7 +528,15 @@ const ConversationBubble = forwardRef<
</button>
);
}
return <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>;
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
);
},
code(props) {
const {
@@ -525,9 +552,9 @@ const ConversationBubble = forwardRef<
const language = match ? match[1] : '';
return match ? (
<div className="group border-light-silver dark:border-raisin-black relative overflow-hidden rounded-[14px] border">
<div className="bg-platinum dark:bg-eerie-black-2 flex items-center justify-between px-2 py-1">
<span className="text-just-black dark:text-chinese-white text-xs font-medium">
<div className="group border-border relative overflow-hidden rounded-[14px] border">
<div className="bg-platinum flex items-center justify-between px-2 py-1">
<span className="text-foreground dark:text-foreground text-xs font-medium">
{language}
</span>
<CopyButton
@@ -554,7 +581,7 @@ const ConversationBubble = forwardRef<
</SyntaxHighlighter>
</div>
) : (
<code className="dark:bg-independence dark:text-bright-gray rounded-[6px] bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
<code className="dark:bg-accent dark:text-foreground rounded-[6px] bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
{children}
</code>
);
@@ -579,8 +606,8 @@ const ConversationBubble = forwardRef<
},
table({ children }) {
return (
<div className="border-silver/40 dark:border-silver/40 relative overflow-x-auto rounded-lg border">
<table className="dark:text-bright-gray w-full text-left text-gray-700">
<div className="border-silver/40 dark:border-border relative overflow-x-auto rounded-lg border">
<table className="dark:text-foreground w-full text-left text-gray-700">
{children}
</table>
</div>
@@ -588,14 +615,14 @@ const ConversationBubble = forwardRef<
},
thead({ children }) {
return (
<thead className="dark:text-bright-gray bg-gray-50 text-xs text-gray-900 uppercase dark:bg-[#26272E]/50">
<thead className="bg-muted text-foreground text-xs uppercase">
{children}
</thead>
);
},
tr({ children }) {
return (
<tr className="dark:border-silver/40 border-b border-gray-200 odd:bg-white even:bg-gray-50 dark:odd:bg-[#26272E] dark:even:bg-[#26272E]/50">
<tr className="border-border odd:bg-card even:bg-muted border-b">
{children}
</tr>
);
@@ -691,7 +718,9 @@ const ConversationBubble = forwardRef<
<button
type="button"
onClick={() => {
const blob = new Blob([message], { type: 'text/markdown' });
const blob = new Blob([message], {
type: 'text/markdown',
});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
@@ -703,8 +732,17 @@ const ConversationBubble = forwardRef<
aria-label="Export as Markdown"
title="Export as Markdown"
>
<svg className="h-5 w-5 stroke-gray-4000" fill="none" viewBox="0 0 24 24" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
<svg
className="stroke-gray-4000 h-5 w-5"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"
/>
</svg>
</button>
</div>
@@ -717,7 +755,7 @@ const ConversationBubble = forwardRef<
<div className="relative mr-2 flex items-center justify-center">
<button
type="button"
className="bg-white-3000 dark:hover:bg-purple-taupe flex cursor-pointer items-center justify-center rounded-full p-2 hover:bg-[#EEEEEE] dark:bg-transparent"
className="hover:bg-accent flex cursor-pointer items-center justify-center rounded-full bg-transparent p-2"
onClick={() => {
if (feedback === 'LIKE') {
handleFeedback?.(null);
@@ -730,7 +768,7 @@ const ConversationBubble = forwardRef<
}
>
<Like
className={`${feedback === 'LIKE' ? 'fill-white-3000 stroke-purple-30 dark:fill-transparent' : 'stroke-gray-4000 fill-none'}`}
className={`${feedback === 'LIKE' ? 'stroke-primary fill-white dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`}
></Like>
</button>
</div>
@@ -738,7 +776,7 @@ const ConversationBubble = forwardRef<
<div className="relative mr-2 flex items-center justify-center">
<button
type="button"
className="bg-white-3000 dark:hover:bg-purple-taupe flex cursor-pointer items-center justify-center rounded-full p-2 hover:bg-[#EEEEEE] dark:bg-transparent"
className="hover:bg-accent flex cursor-pointer items-center justify-center rounded-full bg-transparent p-2"
onClick={() => {
if (feedback === 'DISLIKE') {
handleFeedback?.(null);
@@ -753,7 +791,7 @@ const ConversationBubble = forwardRef<
}
>
<Dislike
className={`${feedback === 'DISLIKE' ? 'fill-white-3000 stroke-red-2000 dark:fill-transparent' : 'stroke-gray-4000 fill-none'}`}
className={`${feedback === 'DISLIKE' ? 'stroke-destructive fill-white dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`}
></Dislike>
</button>
</div>
@@ -806,7 +844,7 @@ function AllSources(sources: AllSourcesProps) {
return (
<div
key={index}
className={`group/card bg-gray-1000 relative w-full rounded-4xl p-4 transition-colors hover:bg-[#F1F1F1] dark:bg-[#28292E] dark:hover:bg-[#2C2E3C] ${
className={`group/card bg-muted hover:bg-accent dark:bg-card dark:hover:bg-muted relative w-full rounded-4xl p-4 transition-colors ${
isExternalSource ? 'cursor-pointer' : ''
}`}
onClick={() =>
@@ -817,7 +855,7 @@ function AllSources(sources: AllSourcesProps) {
title={source.title}
className={`ellipsis-text text-left text-sm font-semibold wrap-break-word ${
isExternalSource
? 'group-hover/card:text-purple-30 dark:group-hover/card:text-[#8C67D7]'
? 'group-hover/card:text-primary dark:group-hover/card:text-[#8C67D7]'
: ''
}`}
>
@@ -834,7 +872,7 @@ function AllSources(sources: AllSourcesProps) {
/>
)}
</p>
<p className="dark:text-chinese-silver mt-3 line-clamp-4 rounded-md text-left text-xs wrap-break-word text-black">
<p className="dark:text-foreground mt-3 line-clamp-4 rounded-md text-left text-xs wrap-break-word text-black">
{source.text}
</p>
</div>
@@ -850,105 +888,105 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
const [isToolCallsOpen, setIsToolCallsOpen] = useState(false);
return (
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
<div className="my-2 flex flex-row items-center justify-center gap-3">
<Avatar
className="h-[26px] w-[30px] text-xl"
avatar={
<img
src={Sources}
alt={'ToolCalls'}
className="h-full w-full object-fill"
/>
}
/>
<button
className="flex flex-row items-center gap-2"
onClick={() => setIsToolCallsOpen(!isToolCallsOpen)}
>
<p className="text-base font-semibold">Tool Calls</p>
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
<div className="my-2 flex flex-row items-center justify-center gap-3">
<Avatar
className="h-[26px] w-[30px] text-xl"
avatar={
<img
src={ChevronDown}
alt="ChevronDown"
className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`}
src={Sources}
alt={'ToolCalls'}
className="h-full w-full object-fill"
/>
</button>
</div>
{isToolCallsOpen && (
<div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full">
<div className="grid grid-cols-1 gap-2">
{toolCalls.map((toolCall, index) => (
<Accordion
key={`tool-call-${index}`}
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
className="bg-gray-1000 dark:bg-gun-metal w-full rounded-4xl hover:bg-[#F1F1F1] dark:hover:bg-[#2C2E3C]"
titleClassName="px-6 py-2 text-sm font-semibold"
>
<div className="flex flex-col gap-1">
<div className="border-silver dark:border-silver/20 flex flex-col rounded-2xl border">
<p className="dark:bg-eerie-black-2 flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Arguments
</span>{' '}
<CopyButton
textToCopy={JSON.stringify(toolCall.arguments, null, 2)}
/>
</p>
<p className="dark:tex dark:bg-raisin-black rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
}
/>
<button
className="flex flex-row items-center gap-2"
onClick={() => setIsToolCallsOpen(!isToolCallsOpen)}
>
<p className="text-base font-semibold">Tool Calls</p>
<img
src={ChevronDown}
alt="ChevronDown"
className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`}
/>
</button>
</div>
{isToolCallsOpen && (
<div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full">
<div className="grid grid-cols-1 gap-2">
{toolCalls.map((toolCall, index) => (
<Accordion
key={`tool-call-${index}`}
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
className="bg-muted dark:bg-answer-bubble w-full rounded-4xl"
titleClassName="px-6 py-2 text-sm font-semibold"
>
<div className="flex flex-col gap-1">
<div className="border-border flex flex-col rounded-2xl border">
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Arguments
</span>{' '}
<CopyButton
textToCopy={JSON.stringify(toolCall.arguments, null, 2)}
/>
</p>
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="dark:text-muted-foreground leading-[23px] text-black"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{JSON.stringify(toolCall.arguments, null, 2)}
</span>
</p>
</div>
<div className="border-border flex flex-col rounded-2xl border">
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Response
</span>{' '}
<CopyButton
textToCopy={
toolCall.status === 'error'
? toolCall.error || 'Unknown error'
: JSON.stringify(toolCall.result, null, 2)
}
/>
</p>
{toolCall.status === 'pending' && (
<span className="dark:bg-card flex w-full items-center justify-center rounded-b-2xl p-2">
<Spinner size="small" />
</span>
)}
{toolCall.status === 'completed' && (
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-black dark:text-gray-400"
className="dark:text-muted-foreground leading-[23px] text-black"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{JSON.stringify(toolCall.arguments, null, 2)}
{JSON.stringify(toolCall.result, null, 2)}
</span>
</p>
</div>
<div className="border-silver dark:border-silver/20 flex flex-col rounded-2xl border">
<p className="dark:bg-eerie-black-2 flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Response
</span>{' '}
<CopyButton
textToCopy={
toolCall.status === 'error'
? toolCall.error || 'Unknown error'
: JSON.stringify(toolCall.result, null, 2)
}
/>
</p>
{toolCall.status === 'pending' && (
<span className="dark:bg-raisin-black flex w-full items-center justify-center rounded-b-2xl p-2">
<Spinner size="small" />
)}
{toolCall.status === 'error' && (
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-red-500 dark:text-red-400"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{toolCall.error}
</span>
)}
{toolCall.status === 'completed' && (
<p className="dark:bg-raisin-black rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-black dark:text-gray-400"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{JSON.stringify(toolCall.result, null, 2)}
</span>
</p>
)}
{toolCall.status === 'error' && (
<p className="dark:bg-raisin-black rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-red-500 dark:text-red-400"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{toolCall.error}
</span>
</p>
)}
</div>
</p>
)}
</div>
</Accordion>
))}
</div>
</div>
</Accordion>
))}
</div>
)}
</div>
</div>
)}
</div>
);
}
@@ -992,7 +1030,7 @@ function Thought({
</div>
{isThoughtOpen && (
<div className="fade-in mr-5 ml-2 max-w-[90vw] md:max-w-[70vw] lg:max-w-[50vw]">
<div className="bg-gray-1000 dark:bg-gun-metal rounded-[28px] px-7 py-[18px]">
<div className="bg-muted dark:bg-answer-bubble rounded-[28px] px-7 py-[18px]">
<ReactMarkdown
className="fade-in leading-normal wrap-break-word whitespace-pre-wrap"
remarkPlugins={[remarkGfm, remarkMath]}
@@ -1004,9 +1042,9 @@ function Thought({
const language = match ? match[1] : '';
return match ? (
<div className="group border-light-silver dark:border-raisin-black relative overflow-hidden rounded-[14px] border">
<div className="bg-platinum dark:bg-eerie-black-2 flex items-center justify-between px-2 py-1">
<span className="text-just-black dark:text-chinese-white text-xs font-medium">
<div className="group border-border relative overflow-hidden rounded-[14px] border">
<div className="bg-platinum flex items-center justify-between px-2 py-1">
<span className="text-foreground dark:text-foreground text-xs font-medium">
{language}
</span>
<CopyButton
@@ -1028,7 +1066,7 @@ function Thought({
</SyntaxHighlighter>
</div>
) : (
<code className="dark:bg-independence dark:text-bright-gray rounded-[6px] bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
<code className="dark:bg-accent dark:text-foreground rounded-[6px] bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
{children}
</code>
);
@@ -1049,8 +1087,8 @@ function Thought({
},
table({ children }) {
return (
<div className="border-silver/40 dark:border-silver/40 relative overflow-x-auto rounded-lg border">
<table className="dark:text-bright-gray w-full text-left text-gray-700">
<div className="border-silver/40 dark:border-border relative overflow-x-auto rounded-lg border">
<table className="dark:text-foreground w-full text-left text-gray-700">
{children}
</table>
</div>
@@ -1058,14 +1096,14 @@ function Thought({
},
thead({ children }) {
return (
<thead className="dark:text-bright-gray bg-gray-50 text-xs text-gray-900 uppercase dark:bg-[#26272E]/50">
<thead className="bg-muted text-foreground text-xs uppercase">
{children}
</thead>
);
},
tr({ children }) {
return (
<tr className="dark:border-silver/40 border-b border-gray-200 odd:bg-white even:bg-gray-50 dark:odd:bg-[#26272E] dark:even:bg-[#26272E]/50">
<tr className="border-border odd:bg-card even:bg-muted border-b">
{children}
</tr>
);

View File

@@ -168,7 +168,7 @@ export default function ConversationMessages({
if (query.error) {
const retryButton = (
<button
className="dark:text-bright-gray flex items-center justify-center gap-3 self-center rounded-full px-5 py-3 text-lg text-gray-500 transition-colors delay-100 hover:border-gray-500 disabled:cursor-not-allowed"
className="dark:text-foreground flex items-center justify-center gap-3 self-center rounded-full px-5 py-3 text-lg text-gray-500 transition-colors delay-100 hover:border-gray-500 disabled:cursor-not-allowed"
disabled={status === 'loading'}
onClick={() => {
const questionToRetry = queries[index].prompt;
@@ -241,7 +241,7 @@ export default function ConversationMessages({
scrollConversationToBottom();
}}
aria-label={t('Scroll to bottom') || 'Scroll to bottom'}
className="border-gray-alpha bg-opacity-50 dark:bg-gunmetal md:bg-opacity-100 fixed right-14 bottom-40 z-10 flex h-7 w-7 items-center justify-center rounded-full border-[0.5px] bg-gray-100 md:h-9 md:w-9"
className="border-border bg-card fixed right-14 bottom-40 z-10 flex h-7 w-7 items-center justify-center rounded-full border md:h-9 md:w-9"
>
<img
src={ArrowDown}

View File

@@ -192,9 +192,9 @@ export default function ConversationTile({
conversationId !== conversation.id &&
selectConversation(conversation.id);
}}
className={`hover:bg-bright-gray dark:hover:bg-dark-charcoal mx-4 my-auto mt-4 flex h-9 cursor-pointer items-center justify-between gap-4 rounded-3xl pl-4 ${
className={`hover:bg-sidebar-accent mx-4 my-auto mt-4 flex h-9 cursor-pointer items-center justify-between gap-4 rounded-3xl pl-4 ${
conversationId === conversation.id || isOpen || isHovered || isEdit
? 'bg-bright-gray dark:bg-dark-charcoal'
? 'bg-sidebar-accent'
: ''
}`}
>
@@ -203,19 +203,22 @@ export default function ConversationTile({
<input
autoFocus
type="text"
className="h-6 w-full bg-transparent px-1 text-sm leading-6 rounded-2xl font-normal outline-none"
className="h-6 w-full rounded-2xl bg-transparent px-1 text-sm leading-6 font-normal outline-none"
value={conversationName}
onChange={(e) => setConversationsName(e.target.value)}
onKeyDown={handleRenameKeyDown}
/>
) : (
<p className="text-eerie-black dark:text-bright-gray my-auto overflow-hidden text-sm leading-6 font-normal text-ellipsis whitespace-nowrap">
<p className="text-foreground dark:text-foreground my-auto overflow-hidden text-sm leading-6 font-normal text-ellipsis whitespace-nowrap">
{conversationName}
</p>
)}
</div>
{(conversationId === conversation.id || isHovered || isOpen) && (
<div className="dark:text-sonic-silver flex text-white" ref={menuRef}>
<div
className="dark:text-muted-foreground flex text-white"
ref={menuRef}
>
{isEdit ? (
<div className="flex gap-1">
<img
@@ -248,7 +251,7 @@ export default function ConversationTile({
event.stopPropagation();
setOpen(!isOpen);
}}
className="mr-2 flex h-6 w-6 items-center justify-center rounded-full transition-colors duration-200 hover:bg-gray-200 dark:hover:bg-gray-700"
className="hover:bg-accent dark:hover:bg-accent mr-2 flex h-6 w-6 items-center justify-center rounded-full transition-colors duration-200"
>
<img src={threeDots} width={8} alt="menu" />
</button>

View File

@@ -4,15 +4,36 @@ import Avatar from '../components/Avatar';
import { ResearchState } from './conversationModels';
const SmallCheck = () => (
<svg className="h-3 w-3 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
<svg
className="h-3 w-3 text-green-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={3}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
);
const SmallSpinner = () => (
<svg className="h-3 w-3 animate-spin text-purple-500" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
<svg
className="h-3 w-3 animate-spin text-purple-500"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
/>
</svg>
);
@@ -32,7 +53,9 @@ function StatusText({ status, elapsed }: { status: string; elapsed?: number }) {
<span className="text-xs text-gray-500 dark:text-gray-400">
{status === 'complete' ? (
<>
<span className="text-green-600 dark:text-green-400">{labels.complete}</span>
<span className="text-green-600 dark:text-green-400">
{labels.complete}
</span>
{elapsed_str}
</>
) : (
@@ -62,13 +85,15 @@ export default function ResearchProgress({
if (!plan && !status) return null;
const completedSteps = plan?.filter((s) => s.status === 'complete').length ?? 0;
const completedSteps =
plan?.filter((s) => s.status === 'complete').length ?? 0;
const totalSteps = plan?.length ?? 0;
// Collapsed: single-line summary
const summaryText = totalSteps > 0
? `Researched ${completedSteps} topic${completedSteps !== 1 ? 's' : ''}`
: 'Research';
const summaryText =
totalSteps > 0
? `Researched ${completedSteps} topic${completedSteps !== 1 ? 's' : ''}`
: 'Research';
return (
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
@@ -93,9 +118,16 @@ export default function ResearchProgress({
</p>
<svg
className={`h-4 w-4 text-gray-500 transition-transform duration-200 dark:text-gray-400 ${isExpanded ? 'rotate-180' : ''}`}
fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 9l-7 7-7-7"
/>
</svg>
</button>
{status && <StatusText status={status} elapsed={elapsed_seconds} />}
@@ -126,13 +158,15 @@ export default function ResearchProgress({
</div>
{/* Step content */}
<div className={`pb-3 ${isLast ? '' : ''}`}>
<p className={`text-sm ${
step.status === 'complete'
? 'text-gray-700 dark:text-gray-300'
: step.status === 'researching'
? 'font-medium text-purple-700 dark:text-purple-300'
: 'text-gray-500 dark:text-gray-500'
}`}>
<p
className={`text-sm ${
step.status === 'complete'
? 'text-gray-700 dark:text-gray-300'
: step.status === 'researching'
? 'font-medium text-purple-700 dark:text-purple-300'
: 'text-gray-500 dark:text-gray-500'
}`}
>
{step.query}
</p>
</div>

View File

@@ -138,18 +138,18 @@ export const SharedConversation = () => {
twitterTitle={title}
twitterDescription="Shared conversations with DocsGPT"
/>
<div className="dark:bg-raisin-black flex h-full flex-col items-center justify-between gap-2 overflow-y-hidden">
<div className="bg-background flex h-full flex-col items-center justify-between gap-2 overflow-y-hidden">
<div className="dark:border-b-silver w-full max-w-[1200px] border-b p-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
<h1 className="font-semi-bold text-chinese-black dark:text-chinese-silver text-4xl">
<h1 className="font-semi-bold text-foreground dark:text-foreground text-4xl">
{title}
</h1>
<h2 className="font-semi-bold text-chinese-black dark:text-chinese-silver text-base">
<h2 className="font-semi-bold text-foreground dark:text-foreground text-base">
{t('sharedConv.subtitle')}{' '}
<a href="/" className="text-[#007DFF]">
DocsGPT
</a>
</h2>
<h2 className="font-semi-bold text-chinese-black dark:text-chinese-silver text-base">
<h2 className="font-semi-bold text-foreground dark:text-foreground text-base">
{date}
</h2>
</div>
@@ -174,13 +174,13 @@ export const SharedConversation = () => {
) : (
<button
onClick={() => navigate('/')}
className="bg-purple-30 hover:bg-violets-are-blue mb-14 w-fit rounded-full px-5 py-3 text-white shadow-xl transition-colors duration-200 sm:mb-0"
className="bg-primary hover:bg-primary/90 mb-14 w-fit rounded-full px-5 py-3 text-white shadow-xl transition-colors duration-200 sm:mb-0"
>
{t('sharedConv.button')}
</button>
)}
<p className="text-gray-4000 dark:text-sonic-silver hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full">
<p className="text-muted-foreground hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full">
{t('sharedConv.meta')}
</p>
</div>

View File

@@ -427,7 +427,10 @@ export const conversationSlice = createSlice({
status: 'pending',
});
}
if (progress.status === 'researching' || progress.status === 'complete') {
if (
progress.status === 'researching' ||
progress.status === 'complete'
) {
research.plan[stepIndex].status = progress.status;
}
if (progress.query) {

View File

@@ -17,12 +17,9 @@ layer(base);
--color-gray-1000: #f6f6f6;
--color-gray-2000: rgba(0, 0, 0, 0.5);
--color-gray-3000: rgba(243, 243, 243, 1);
--color-gray-4000: #949494;
--color-gray-5000: #bbbbbb;
--color-gray-6000: #757575;
--color-red-1000: rgb(254, 202, 202);
--color-red-2000: #f44336;
--color-red-3000: #621b16;
--color-blue-1000: #7d54d1;
--color-blue-2000: #002b49;
--color-blue-3000: #4b02e2;
@@ -32,7 +29,6 @@ layer(base);
--color-blue-5000: rgba(0, 125, 255);
--color-green-2000: #0fff50;
--color-light-gray: #edeef0;
--color-white-3000: #ffffff;
--color-just-black: #00000;
--color-purple-taupe: #464152;
--color-dove-gray: #6c6c6c;
@@ -57,7 +53,6 @@ layer(base);
--color-charleston-green-2: #26272e;
--color-charleston-green-3: #26272a;
--color-grey: #7e7e7e;
--color-lotion: #fbfbfb;
--color-platinum: #e6e6e6;
--color-eerie-black-2: #191919;
--color-light-silver: #d9d9d9;
@@ -69,15 +64,11 @@ layer(base);
--color-onyx-2: #35383c;
--color-philippine-grey: #929292;
--color-charcoal-grey: #53545d;
--color-rosso-corsa: #d30000;
--color-north-texas-green: #0c9d35;
--color-medium-purple: #8d66dd;
--color-slate-blue: #6f5fca;
--color-old-silver: #848484;
--color-arsenic: #4d4e58;
--color-light-gainsboro: #d7d7d7;
--color-raisin-black-light: #18181b;
--color-gunmetal: #32333b;
--color-sonic-silver-light: #7f7f82;
--color-violets-are-blue: #976af3;
}
@@ -201,7 +192,7 @@ layer(base);
}
@utility table-default {
@apply border-silver dark:border-silver/40 dark:text-bright-gray block w-full table-auto justify-center overflow-auto rounded-xl border text-center;
@apply border-border text-foreground block w-full table-auto justify-center overflow-auto rounded-xl border text-center;
& th {
@apply p-4 font-normal text-nowrap text-gray-400;
@@ -216,7 +207,7 @@ layer(base);
}
& td {
@apply border-silver dark:border-silver/40 w-full border-t px-4 py-2;
@apply border-border w-full border-t px-4 py-2;
}
& td:last-child {
@@ -262,7 +253,7 @@ layer(base);
}
body.dark {
background-color: #202124; /* raisin-black */
background-color: var(--background);
}
::-webkit-scrollbar {
width: 6px;
@@ -868,6 +859,7 @@ Avoid over-scrolling in mobile browsers
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--color-answer-bubble: var(--answer-bubble);
}
/*
@@ -876,37 +868,38 @@ Avoid over-scrolling in mobile browsers
:root {
--radius: 0.625rem;
--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.554 0.185 294.8); /* purple-30 #7d54d1 */
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.914 0.035 300.2); /* purple-3000 - light purple */
--secondary-foreground: oklch(0.554 0.185 294.8);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.914 0.035 300.2); /* purple-3000 - light purple hover */
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.870 0 0); /* neutral gray border */
--ring: oklch(0.554 0.185 294.8); /* purple-30 focus ring */
--background: #ffffff;
--foreground: #171717;
--card: #ffffff;
--card-foreground: #171717;
--popover: #ffffff;
--popover-foreground: #171717;
--primary: #7d54d1;
--primary-foreground: #ffffff;
--secondary: #f4f4f4;
--secondary-foreground: #7d54d1;
--muted: #f6f6f6;
--muted-foreground: #737373;
--accent: #ececec;
--accent-foreground: #171717;
--destructive: #ef4444;
--border: #d9d9d9;
--input: #d9d9d9;
--ring: #7d54d1;
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.554 0.185 294.8); /* purple-30 */
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.914 0.035 300.2); /* purple-3000 */
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.554 0.185 294.8); /* purple-30 */
--sidebar: #fbfbfb;
--sidebar-foreground: #171717;
--sidebar-primary: #7d54d1;
--sidebar-primary-foreground: #ffffff;
--sidebar-accent: #ececec;
--sidebar-accent-foreground: #171717;
--sidebar-border: #d9d9d9;
--sidebar-ring: #7d54d1;
--answer-bubble: #f6f6f6;
}
/*
@@ -914,37 +907,38 @@ Avoid over-scrolling in mobile browsers
*/
.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.636 0.197 295.4); /* violets-are-blue #976af3 */
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.269 0.03 295.0); /* dark muted purple */
--secondary-foreground: oklch(0.867 0.052 300.1);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0.04 295.0); /* dark purple hover */
--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.636 0.197 295.4); /* violets-are-blue focus ring */
--background: #222327;
--foreground: #fafafa;
--card: #2b2c31;
--card-foreground: #fafafa;
--popover: #2b2c31;
--popover-foreground: #fafafa;
--primary: #976af3;
--primary-foreground: #ffffff;
--secondary: #2b2c31;
--secondary-foreground: #e0e0e0;
--muted: #35363b;
--muted-foreground: #a1a1a1;
--accent: #3e3f45;
--accent-foreground: #fafafa;
--destructive: #dc2626;
--border: #44454c;
--input: #44454c;
--ring: #976af3;
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.636 0.197 295.4); /* violets-are-blue */
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0.04 295.0); /* dark purple */
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.636 0.197 295.4); /* violets-are-blue */
--sidebar: #161616;
--sidebar-foreground: #fafafa;
--sidebar-primary: #976af3;
--sidebar-primary-foreground: #ffffff;
--sidebar-accent: #222327;
--sidebar-accent-foreground: #fafafa;
--sidebar-border: #2b2c31;
--sidebar-ring: #976af3;
--answer-bubble: #2e303e;
}
/*

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "Hier kannst du alle verfügbaren Quelldateien verwalten, die dir zur Verfügung stehen und die du hochgeladen hast.",
"subtitle": "Dokumente und Wissensquellen hochladen und verwalten, die deine Antworten antreiben",
"label": "Quellen",
"name": "Quellenname",
"date": "Vektor-Datum",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "Analytik",
"subtitle": "Nachrichtenvolumen, Token-Verbrauch und Nutzerfeedback in deinem Konto verfolgen",
"filterByChatbot": "Nach Chatbot filtern",
"selectChatbot": "Chatbot auswählen",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "Protokolle",
"subtitle": "API-Aufrufe und Konversationsprotokolle einsehen und überwachen",
"filterByChatbot": "Nach Chatbot filtern",
"selectChatbot": "Chatbot auswählen",
"none": "Keine",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "Werkzeuge",
"subtitle": "Werkzeuge und Integrationen durchsuchen, verbinden und konfigurieren, die deine Agenten antreiben",
"searchPlaceholder": "Werkzeuge suchen...",
"addTool": "Werkzeug hinzufügen",
"noToolsFound": "Keine Werkzeuge gefunden",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "Here you can manage all of the source file that are available to you and those you have uploaded.",
"subtitle": "Upload and manage the documents and knowledge sources used to power your responses",
"label": "Sources",
"name": "Source Name",
"date": "Vector Date",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "Analytics",
"subtitle": "Track message volume, token usage, and user feedback across your account",
"filterByChatbot": "Filter by chatbot",
"selectChatbot": "Select chatbot",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "Logs",
"subtitle": "View and monitor API calls and conversation logs",
"filterByChatbot": "Filter by chatbot",
"selectChatbot": "Select chatbot",
"none": "None",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "Tools",
"subtitle": "Browse, connect, and configure the tools and integrations that power your agents",
"searchPlaceholder": "Search tools...",
"addTool": "Add Tool",
"noToolsFound": "No tools found",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "Aquí puedes gestionar todos los archivos fuente que están disponibles para ti y los que has subido.",
"subtitle": "Sube y gestiona los documentos y fuentes de conocimiento que impulsan tus respuestas",
"label": "Fuentes",
"name": "Nombre de la Fuente",
"date": "Fecha de Vector",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "Analítica",
"subtitle": "Realiza un seguimiento del volumen de mensajes, uso de tokens y comentarios de usuarios en tu cuenta",
"filterByChatbot": "Filtrar por chatbot",
"selectChatbot": "Seleccionar chatbot",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "Registros",
"subtitle": "Visualiza y monitorea las llamadas a la API y los registros de conversaciones",
"filterByChatbot": "Filtrar por chatbot",
"selectChatbot": "Seleccionar chatbot",
"none": "Ninguno",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "Herramientas",
"subtitle": "Explora, conecta y configura las herramientas e integraciones que impulsan a tus agentes",
"searchPlaceholder": "Buscar...",
"addTool": "Agregar Herramienta",
"noToolsFound": "No se encontraron herramientas",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "ここでは、利用可能なすべてのソースファイルとアップロードしたファイルを管理できます。",
"subtitle": "レスポンスを機能させるドキュメントとナレッジソースをアップロードして管理",
"label": "ソース",
"name": "ソース名",
"date": "ベクトル日付",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "分析",
"subtitle": "アカウント全体のメッセージ量、トークン使用量、ユーザーフィードバックを追跡",
"filterByChatbot": "チャットボットでフィルター",
"selectChatbot": "チャットボットを選択",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "ログ",
"subtitle": "APIコールと会話ログを表示・監視",
"filterByChatbot": "チャットボットでフィルター",
"selectChatbot": "チャットボットを選択",
"none": "なし",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "ツール",
"subtitle": "エージェントを強化するツールやインテグレーションを検索、接続、設定",
"searchPlaceholder": "検索...",
"addTool": "ツールを追加",
"noToolsFound": "ツールが見つかりません",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "Здесь вы можете управлять всеми исходными файлами, которые доступны вам и которые вы загрузили.",
"subtitle": "Загружайте и управляйте документами и источниками знаний, которые обеспечивают ваши ответы",
"label": "Источники",
"name": "Название источника",
"date": "Дата вектора",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "Аналитика",
"subtitle": "Отслеживайте объём сообщений, использование токенов и отзывы пользователей в вашем аккаунте",
"filterByChatbot": "Фильтровать по чат-боту",
"selectChatbot": "Выбрать чат-бота",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "Журналы",
"subtitle": "Просматривайте и отслеживайте вызовы API и журналы разговоров",
"filterByChatbot": "Фильтровать по чат-боту",
"selectChatbot": "Выбрать чат-бота",
"none": "Нет",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "Инструменты",
"subtitle": "Просматривайте, подключайте и настраивайте инструменты и интеграции для ваших агентов",
"searchPlaceholder": "Поиск...",
"addTool": "Добавить инструмент",
"noToolsFound": "Инструменты не найдены",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "在這裡您可以管理所有可用的來源檔案以及您上傳的檔案。",
"subtitle": "上傳並管理您的回答所依賴的文件和知識來源",
"label": "來源",
"name": "來源名稱",
"date": "向量日期",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "分析",
"subtitle": "追蹤您賃戶的訊息量、Token 使用量和使用者回饋",
"filterByChatbot": "按聊天機器人篩選",
"selectChatbot": "選擇聊天機器人",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "日誌",
"subtitle": "查看和監控 API 呼叫及會話日誌",
"filterByChatbot": "按聊天機器人篩選",
"selectChatbot": "選擇聊天機器人",
"none": "無",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "工具",
"subtitle": "瀏覽、連接並設定驅動您的智能體的工具和整合",
"searchPlaceholder": "搜尋工具...",
"addTool": "新增工具",
"noToolsFound": "找不到工具",

View File

@@ -54,6 +54,7 @@
},
"sources": {
"title": "在这里您可以管理所有可用的源文件以及您上传的文件。",
"subtitle": "上传并管理您的回答所依赖的文档和知识来源",
"label": "来源",
"name": "来源名称",
"date": "向量日期",
@@ -118,6 +119,7 @@
},
"analytics": {
"label": "分析",
"subtitle": "跟踪您账户的消息量、令牌使用情况和用户反馈",
"filterByChatbot": "按聊天机器人筛选",
"selectChatbot": "选择聊天机器人",
"filterOptions": {
@@ -137,6 +139,7 @@
},
"logs": {
"label": "日志",
"subtitle": "查看和监控 API 调用及会话日志",
"filterByChatbot": "按聊天机器人筛选",
"selectChatbot": "选择聊天机器人",
"none": "无",
@@ -144,6 +147,7 @@
},
"tools": {
"label": "工具",
"subtitle": "浏览、连接并配置驱动您的智能体的工具和集成",
"searchPlaceholder": "搜索工具...",
"addTool": "添加工具",
"noToolsFound": "未找到工具",

View File

@@ -40,7 +40,7 @@ export default function AddActionModal({
return (
<WrapperModal close={() => setModalState('INACTIVE')} className="sm:w-lg">
<div>
<h2 className="text-jet dark:text-bright-gray px-3 text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground px-3 text-xl font-semibold">
{t('modals.addAction.title')}
</h2>
<div className="relative mt-6 px-3">
@@ -53,13 +53,13 @@ export default function AddActionModal({
setFunctionNameError(!isValidFunctionName(value));
}}
borderVariant="thin"
labelBgClassName="bg-white dark:bg-charleston-green-2"
labelBgClassName="bg-card"
placeholder={t('modals.addAction.actionNamePlaceholder')}
required={true}
/>
<p
className={`mt-2 ml-1 text-xs italic ${
functionNameError ? 'text-red-500' : 'text-gray-500'
functionNameError ? 'text-red-500' : 'text-muted-foreground'
}`}
>
{functionNameError
@@ -70,7 +70,7 @@ export default function AddActionModal({
<div className="mt-3 flex flex-row-reverse gap-1 px-3">
<button
onClick={handleAddAction}
className="bg-purple-30 hover:bg-violets-are-blue rounded-3xl px-5 py-2 text-sm text-white transition-all"
className="bg-primary hover:bg-primary/90 rounded-3xl px-5 py-2 text-sm text-white transition-all"
>
{t('modals.addAction.addButton')}
</button>
@@ -80,7 +80,7 @@ export default function AddActionModal({
setModalState('INACTIVE');
setActionName('');
}}
className="dark:text-light-gray cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
>
{t('modals.configTool.closeButton')}
</button>

View File

@@ -116,7 +116,7 @@ export default function AddToolModal({
>
<div className="flex h-full flex-col">
<div>
<h2 className="text-jet dark:text-bright-gray px-3 text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground px-3 text-xl font-semibold">
{t('settings.tools.selectToolSetup')}
</h2>
<div className="mt-5 h-[73vh] overflow-auto px-3 py-px">
@@ -131,7 +131,7 @@ export default function AddToolModal({
role="button"
tabIndex={0}
key={index}
className="border-light-gainsboro bg-white-3000 dark:border-arsenic dark:bg-gunmetal flex h-52 w-full cursor-pointer flex-col justify-between rounded-2xl border p-6 hover:border-[#9d9d9d] dark:hover:border-[#717179]"
className="border-border bg-card hover:bg-accent hover:border-border/80 flex h-52 w-full cursor-pointer flex-col justify-between rounded-2xl border p-6"
onClick={() => {
setSelectedTool(tool);
handleAddTool(tool);
@@ -154,11 +154,11 @@ export default function AddToolModal({
<div className="mt-[9px]">
<p
title={tool.displayName}
className="text-raisin-black-light dark:text-bright-gray truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
className="text-foreground dark:text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{tool.displayName}
</p>
<p className="text-old-silver dark:text-sonic-silver-light mt-1 h-24 overflow-auto px-1 text-[12px] leading-relaxed">
<p className="text-muted-foreground mt-1 h-24 overflow-auto px-1 text-[12px] leading-relaxed">
{tool.description}
</p>
</div>

View File

@@ -1,9 +1,10 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import ExternalLinkIcon from '../assets/external-link.svg';
import { Agent } from '../agents/types';
import userService from '../api/services/userService';
import ExternalLinkIcon from '../assets/external-link.svg';
import CopyButton from '../components/CopyButton';
import Spinner from '../components/Spinner';
import { ActiveState } from '../models/misc';
@@ -81,25 +82,25 @@ export default function AgentDetailsModal({
if (modalState !== 'ACTIVE') return null;
return (
<WrapperModal
className="sm:w-[512px]"
className="sm:w-lg"
close={() => {
setModalState('INACTIVE');
}}
>
<div>
<h2 className="text-jet dark:text-bright-gray text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground text-xl font-semibold">
{t('modals.agentDetails.title')}
</h2>
<div className="mt-8 flex flex-col gap-6">
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<h2 className="text-jet dark:text-bright-gray text-base font-semibold">
<h2 className="text-foreground dark:text-foreground text-base font-semibold">
{t('modals.agentDetails.publicLink')}
</h2>
</div>
{sharedToken ? (
<div className="flex flex-col gap-2">
<p className="font-roboto inline text-[14px] leading-normal font-medium break-all text-gray-700 dark:text-[#ECECF1]">
<p className="font-roboto dark:text-foreground inline text-[14px] leading-normal font-medium break-all text-gray-700">
<a
href={`${baseURL}/shared/agent/${sharedToken}`}
target="_blank"
@@ -115,7 +116,7 @@ export default function AgentDetailsModal({
</p>
<a
href="https://docs.docsgpt.cloud/Agents/basics#core-components-of-an-agent"
className="text-purple-30 flex w-fit items-center gap-1 hover:underline"
className="text-primary flex w-fit items-center gap-1 hover:underline"
target="_blank"
rel="noopener noreferrer"
>
@@ -131,7 +132,7 @@ export default function AgentDetailsModal({
</div>
) : (
<button
className="border-purple-30 text-purple-30 hover:bg-purple-30 flex w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 flex w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
onClick={handleGeneratePublicLink}
>
{loadingStates.publicLink ? (
@@ -143,13 +144,13 @@ export default function AgentDetailsModal({
)}
</div>
<div className="flex flex-col gap-3">
<h2 className="text-jet dark:text-bright-gray text-base font-semibold">
<h2 className="text-foreground dark:text-foreground text-base font-semibold">
{t('modals.agentDetails.apiKey')}
</h2>
{apiKey ? (
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<div className="font-roboto text-[14px] leading-normal font-medium break-all text-gray-700 dark:text-[#ECECF1]">
<div className="font-roboto dark:text-foreground text-[14px] leading-normal font-medium break-all text-gray-700">
{apiKey}
{!apiKey.includes('...') && (
<CopyButton
@@ -162,7 +163,7 @@ export default function AgentDetailsModal({
{!apiKey.includes('...') && (
<a
href={`https://widget.docsgpt.cloud/?api-key=${apiKey}`}
className="group border-purple-30 text-purple-30 hover:bg-purple-30 ml-8 flex w-[101px] items-center justify-center gap-1 rounded-[62px] border py-1.5 text-sm font-medium transition-colors hover:text-white"
className="group border-primary text-primary hover:bg-primary/90 ml-8 flex w-[101px] items-center justify-center gap-1 rounded-[62px] border py-1.5 text-sm font-medium transition-colors hover:text-white"
target="_blank"
rel="noopener noreferrer"
>
@@ -177,20 +178,20 @@ export default function AgentDetailsModal({
</div>
</div>
) : (
<button className="border-purple-30 text-purple-30 hover:bg-purple-30 w-28 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white">
<button className="border-primary text-primary hover:bg-primary/90 w-28 rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white">
{t('modals.agentDetails.generate')}
</button>
)}
</div>
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<h2 className="text-jet dark:text-bright-gray text-base font-semibold">
<h2 className="text-foreground dark:text-foreground text-base font-semibold">
{t('modals.agentDetails.webhookUrl')}
</h2>
</div>
{webhookUrl ? (
<div className="flex flex-col gap-2">
<p className="font-roboto text-[14px] leading-normal font-medium break-all text-gray-700 dark:text-[#ECECF1]">
<p className="font-roboto dark:text-foreground text-[14px] leading-normal font-medium break-all text-gray-700">
<a href={webhookUrl} target="_blank" rel="noreferrer">
{webhookUrl}
</a>
@@ -202,7 +203,7 @@ export default function AgentDetailsModal({
</p>
<a
href="https://docs.docsgpt.cloud/Agents/basics#core-components-of-an-agent"
className="text-purple-30 flex w-fit items-center gap-1 hover:underline"
className="text-primary flex w-fit items-center gap-1 hover:underline"
target="_blank"
rel="noopener noreferrer"
>
@@ -218,7 +219,7 @@ export default function AgentDetailsModal({
</div>
) : (
<button
className="border-purple-30 text-purple-30 hover:bg-purple-30 flex w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 flex w-28 items-center justify-center rounded-3xl border border-solid px-5 py-2 text-sm font-medium transition-colors hover:text-white"
onClick={handleGenerateWebhook}
>
{loadingStates.webhook ? (

View File

@@ -115,7 +115,7 @@ export default function ConfigToolModal({
return (
<WrapperModal close={handleClose}>
<div className="w-[400px] max-w-[90vw]">
<h2 className="text-eerie-black dark:text-bright-gray text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground text-xl font-semibold">
{t('modals.configTool.title')}
</h2>
<p className="mt-2 text-sm text-gray-500 dark:text-gray-400">
@@ -140,19 +140,21 @@ export default function ConfigToolModal({
/>
</div>
{hasConfig && <ConfigFields
configRequirements={configRequirements}
values={configValues}
onChange={handleFieldChange}
errors={errors}
/>}
{hasConfig && (
<ConfigFields
configRequirements={configRequirements}
values={configValues}
onChange={handleFieldChange}
errors={errors}
/>
)}
</div>
<div className="mt-8 flex flex-row-reverse gap-2">
<button
onClick={handleAddTool}
disabled={saving}
className="bg-purple-30 hover:bg-violets-are-blue disabled:opacity-60 rounded-full px-5 py-2 text-sm font-medium text-white transition-colors"
className="bg-primary hover:bg-primary/90 rounded-full px-5 py-2 text-sm font-medium text-white transition-colors disabled:opacity-60"
>
{saving
? t('modals.configTool.addButton') + '…'
@@ -160,7 +162,7 @@ export default function ConfigToolModal({
</button>
<button
onClick={handleClose}
className="dark:text-light-gray cursor-pointer rounded-full px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-full px-5 py-2 text-sm font-medium"
>
{t('modals.configTool.closeButton')}
</button>

View File

@@ -26,8 +26,8 @@ export default function ConfirmationModal({
const submitButtonClasses =
variant === 'danger'
? 'rounded-3xl bg-rosso-corsa px-5 py-2 text-sm text-lotion transition-all hover:bg-red-2000 hover:font-bold tracking-[0.019em] hover:tracking-normal'
: 'rounded-3xl bg-purple-30 px-5 py-2 text-sm text-lotion transition-all hover:bg-violets-are-blue';
? 'rounded-3xl bg-destructive px-5 py-2 text-sm text-white transition-all hover:bg-destructive/90 hover:font-bold tracking-[0.019em] hover:tracking-normal'
: 'rounded-3xl bg-primary px-5 py-2 text-sm text-white transition-all hover:bg-primary/90';
const handleSubmitClick = (e: React.MouseEvent) => {
e.preventDefault();
@@ -49,7 +49,7 @@ export default function ConfirmationModal({
<WrapperModal close={() => setModalState('INACTIVE')}>
<div className="relative">
<div>
<p className="font-base text-jet dark:text-bright-gray mb-1 w-[90%] text-lg break-words">
<p className="font-base text-foreground dark:text-foreground mb-1 w-[90%] text-lg wrap-break-word">
{message}
</p>
<div>
@@ -62,7 +62,7 @@ export default function ConfirmationModal({
</button>
<button
onClick={handleCancelClick}
className="dark:text-light-gray cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
>
{cancelLabel ? cancelLabel : t('cancel')}
</button>

View File

@@ -47,7 +47,7 @@ export default function FolderNameModal({
return (
<WrapperModal close={() => setModalState('INACTIVE')}>
<div className="w-72">
<h2 className="text-jet dark:text-bright-gray mb-4 text-lg font-semibold">
<h2 className="text-foreground dark:text-foreground mb-4 text-lg font-semibold">
{mode === 'create'
? t('agents.folders.newFolder')
: t('agents.folders.rename')}
@@ -59,7 +59,7 @@ export default function FolderNameModal({
onKeyDown={handleKeyDown}
placeholder={t('agents.folders.folderName')}
autoFocus
className="w-full rounded-lg border border-[#E5E5E5] bg-white px-3 py-2 text-sm outline-none dark:border-[#3A3A3A] dark:bg-[#2C2C2C] dark:text-white"
className="border-border bg-card w-full rounded-lg border px-3 py-2 text-sm outline-none dark:text-white"
/>
<div className="mt-6 flex justify-end gap-2">
<button
@@ -67,14 +67,14 @@ export default function FolderNameModal({
setModalState('INACTIVE');
setName('');
}}
className="dark:text-light-gray cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
>
{t('cancel')}
</button>
<button
onClick={handleSubmit}
disabled={!name.trim()}
className="bg-purple-30 hover:bg-violets-are-blue rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
className="bg-primary hover:bg-primary/90 rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
>
{mode === 'create'
? t('agents.folders.createFolder')

View File

@@ -166,7 +166,7 @@ export default function ImportSpecModal({
contentClassName="max-h-[70vh]"
>
<div className="flex flex-col gap-4">
<h2 className="text-jet dark:text-bright-gray text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground text-xl font-semibold">
{t('modals.importSpec.title')}
</h2>
@@ -178,14 +178,14 @@ export default function ImportSpecModal({
<div
onClick={() => fileInputRef.current?.click()}
className="border-silver dark:border-silver/40 hover:border-purple-30 dark:hover:border-purple-30 flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-8 transition-colors"
className="border-border dark:border-border hover:border-primary dark:hover:border-primary flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-8 transition-colors"
>
<img
src={Upload}
alt="Upload"
className="mb-3 h-10 w-10 opacity-60 dark:invert"
/>
<p className="text-jet dark:text-bright-gray text-sm font-medium">
<p className="text-foreground dark:text-foreground text-sm font-medium">
{file ? file.name : t('modals.importSpec.dropzoneText')}
</p>
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
@@ -206,8 +206,8 @@ export default function ImportSpecModal({
</div>
) : (
<div className="flex flex-col gap-4">
<div className="rounded-xl bg-[#F9F9F9] p-4 dark:bg-[#28292D]">
<h3 className="text-jet dark:text-bright-gray font-medium">
<div className="bg-muted rounded-xl p-4">
<h3 className="text-foreground dark:text-foreground font-medium">
{parsedResult.metadata.title}
</h3>
{parsedResult.metadata.description && (
@@ -215,7 +215,7 @@ export default function ImportSpecModal({
{parsedResult.metadata.description}
</p>
)}
<p className="mt-2 text-xs text-gray-500">
<p className="text-muted-foreground mt-2 text-xs">
{t('modals.importSpec.version')}:{' '}
{parsedResult.metadata.version}
</p>
@@ -227,7 +227,7 @@ export default function ImportSpecModal({
type="text"
value={baseUrl}
onChange={(e) => setBaseUrl(e.target.value)}
className="border-silver dark:border-silver/40 text-jet dark:text-bright-gray w-full rounded-lg border bg-white px-3 py-2 text-sm outline-hidden dark:bg-[#2C2C2C]"
className="border-border dark:border-border text-foreground dark:text-foreground bg-card w-full rounded-lg border px-3 py-2 text-sm outline-hidden"
placeholder={
parsedResult.metadata.base_url || 'https://api.example.com'
}
@@ -236,14 +236,14 @@ export default function ImportSpecModal({
</div>
<div className="flex items-center justify-between px-1">
<p className="text-jet dark:text-bright-gray text-sm font-medium">
<p className="text-foreground dark:text-foreground text-sm font-medium">
{t('modals.importSpec.actionsFound', {
count: parsedResult.actions.length,
})}
</p>
<button
onClick={toggleAll}
className="text-purple-30 hover:text-violets-are-blue text-sm"
className="text-primary hover:text-primary text-sm"
>
{selectedActions.size === parsedResult.actions.length
? t('modals.importSpec.deselectAll')
@@ -255,13 +255,13 @@ export default function ImportSpecModal({
{parsedResult.actions.map((action, index) => (
<label
key={index}
className="border-silver dark:border-silver/40 flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors hover:bg-[#F9F9F9] dark:hover:bg-[#28292D]"
className="border-border dark:border-border hover:bg-muted dark:hover:bg-muted flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors"
>
<input
type="checkbox"
checked={selectedActions.has(index)}
onChange={() => toggleAction(index)}
className="text-purple-30 focus:ring-purple-30 mt-1 h-4 w-4 rounded border-gray-300"
className="text-primary focus:ring-ring mt-1 h-4 w-4 rounded border-gray-300"
/>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
@@ -270,7 +270,7 @@ export default function ImportSpecModal({
>
{action.method.toUpperCase()}
</span>
<span className="text-jet dark:text-bright-gray truncate font-medium">
<span className="text-foreground dark:text-foreground truncate font-medium">
{action.name}
</span>
</div>
@@ -294,7 +294,7 @@ export default function ImportSpecModal({
<button
onClick={handleParse}
disabled={!file || loading}
className="bg-purple-30 hover:bg-violets-are-blue flex w-20 items-center justify-center gap-2 rounded-3xl px-5 py-2 text-sm text-white transition-all disabled:cursor-not-allowed disabled:opacity-50"
className="bg-primary hover:bg-primary/90 flex w-20 items-center justify-center gap-2 rounded-3xl px-5 py-2 text-sm text-white transition-all disabled:cursor-not-allowed disabled:opacity-50"
>
{loading && <Spinner size="small" color="white" />}
{!loading && t('modals.importSpec.parse')}
@@ -303,14 +303,14 @@ export default function ImportSpecModal({
<button
onClick={handleImport}
disabled={selectedActions.size === 0}
className="bg-purple-30 hover:bg-violets-are-blue rounded-3xl px-5 py-2 text-sm text-white transition-all disabled:cursor-not-allowed disabled:opacity-50"
className="bg-primary hover:bg-primary/90 rounded-3xl px-5 py-2 text-sm text-white transition-all disabled:cursor-not-allowed disabled:opacity-50"
>
{t('modals.importSpec.import', { count: selectedActions.size })}
</button>
)}
<button
onClick={handleClose}
className="dark:text-light-gray cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
>
{t('modals.importSpec.cancel')}
</button>

View File

@@ -24,7 +24,7 @@ export default function JWTModal({
close={() => undefined}
>
<div className="mb-6">
<span className="text-jet dark:text-bright-gray text-lg">
<span className="text-foreground dark:text-foreground text-lg">
Add JWT Token
</span>
</div>
@@ -41,7 +41,7 @@ export default function JWTModal({
<button
disabled={jwtToken.length === 0}
onClick={handleTokenSubmit.bind(null, jwtToken)}
className="bg-purple-30 float-right mt-4 rounded-full px-5 py-2 text-sm text-white hover:bg-[#6F3FD1] disabled:opacity-50"
className="bg-primary float-right mt-4 rounded-full px-5 py-2 text-sm text-white hover:bg-[#6F3FD1] disabled:opacity-50"
>
Save Token
</button>

View File

@@ -559,7 +559,7 @@ export default function MCPServerModal({
>
<div className="flex h-full flex-col">
<div className="px-6 py-4">
<h2 className="text-jet dark:text-bright-gray text-xl font-semibold">
<h2 className="text-foreground dark:text-foreground text-xl font-semibold">
{server
? t('settings.tools.mcp.reconnectServer', {
defaultValue: 'Reconnect Server',
@@ -711,7 +711,7 @@ export default function MCPServerModal({
)}
{discoveredTools.length > 0 && testResult?.success && (
<div className="border-silver dark:border-silver/40 rounded-xl border p-4">
<div className="border-border dark:border-border rounded-xl border p-4">
<h4 className="mb-2 text-sm font-medium text-gray-900 dark:text-white">
{t('settings.tools.mcp.discoveredTools', {
count: discoveredTools.length,
@@ -724,7 +724,7 @@ export default function MCPServerModal({
key={tool.name}
className="flex items-start gap-2 rounded-lg bg-gray-50 px-3 py-2 text-sm dark:bg-white/5"
>
<span className="text-purple-30 mt-0.5">&#9679;</span>
<span className="text-primary mt-0.5">&#9679;</span>
<div className="min-w-0">
<span className="font-medium text-gray-900 dark:text-white">
{tool.name}
@@ -753,7 +753,7 @@ export default function MCPServerModal({
<button
onClick={testConnection}
disabled={testing}
className="border-silver dark:border-silver/40 dark:text-light-gray w-full rounded-3xl border px-6 py-2 text-sm font-medium transition-all hover:bg-gray-100 disabled:opacity-50 sm:w-auto dark:hover:bg-[#767183]/50"
className="border-border dark:border-border dark:text-foreground hover:bg-accent dark:hover:bg-muted/50 w-full rounded-3xl border px-6 py-2 text-sm font-medium transition-all disabled:opacity-50 sm:w-auto"
>
{testing ? (
<div className="flex items-center justify-center">
@@ -773,14 +773,14 @@ export default function MCPServerModal({
setModalState('INACTIVE');
resetForm();
}}
className="dark:text-light-gray w-full cursor-pointer rounded-3xl px-6 py-2 text-sm font-medium hover:bg-gray-100 sm:w-auto dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-muted/50 w-full cursor-pointer rounded-3xl px-6 py-2 text-sm font-medium sm:w-auto"
>
{t('settings.tools.mcp.cancel')}
</button>
<button
onClick={handleSave}
disabled={loading || !saveActive}
className="bg-purple-30 hover:bg-violets-are-blue w-full rounded-3xl px-6 py-2 text-sm font-medium text-white transition-all disabled:opacity-50 sm:w-auto"
className="bg-primary hover:bg-primary/90 w-full rounded-3xl px-6 py-2 text-sm font-medium text-white transition-all disabled:opacity-50 sm:w-auto"
>
{loading ? (
<div className="flex items-center justify-center">

View File

@@ -139,7 +139,7 @@ export default function MoveToFolderModal({
<div className="w-[800px] max-w-[90vw]">
<div className="px-6 pt-4">
<h2
className="text-jet dark:text-bright-gray mb-2 font-semibold"
className="text-foreground dark:text-foreground mb-2 font-semibold"
style={{
fontFamily: 'Inter, sans-serif',
fontSize: '22px',
@@ -151,12 +151,12 @@ export default function MoveToFolderModal({
</h2>
</div>
<div
className="flex items-center gap-1 bg-[#F6F8FA] px-8 py-2 text-xs font-semibold text-[#59636E] dark:bg-[#2A2A2A] dark:text-gray-400"
className="bg-muted dark:bg-muted flex items-center gap-1 px-8 py-2 text-xs font-semibold text-[#59636E] dark:text-gray-400"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
<button
onClick={() => handleNavigateToPath(-1)}
className={`hover:text-[#18181B] dark:hover:text-white ${folderPath.length > 0 ? 'opacity-70' : ''}`}
className={`hover:text-foreground dark:hover:text-white ${folderPath.length > 0 ? 'opacity-70' : ''}`}
>
{t('agents.filters.byMe')}
</button>
@@ -180,7 +180,7 @@ export default function MoveToFolderModal({
) : (
<button
onClick={() => handleNavigateToPath(index)}
className="opacity-70 hover:text-[#18181B] dark:hover:text-white"
className="hover:text-foreground opacity-70 dark:hover:text-white"
>
{item.name}
</button>
@@ -188,10 +188,10 @@ export default function MoveToFolderModal({
</span>
))}
</div>
<div className="max-h-60 min-h-[200px] overflow-y-auto border-t border-gray-200 dark:border-[#3A3A3A]">
<div className="dark:border-border max-h-60 min-h-[200px] overflow-y-auto border-t border-gray-200">
{isLoading ? (
<div className="flex h-[200px] items-center justify-center">
<span className="text-[14px] text-gray-500">
<span className="text-muted-foreground text-[14px]">
{t('loading')}...
</span>
</div>
@@ -204,10 +204,10 @@ export default function MoveToFolderModal({
e.stopPropagation();
setSelectedFolderId(null);
}}
className={`flex w-full items-center gap-2 border-b border-gray-200 px-8 py-2 text-left text-[14px] dark:border-[#3A3A3A] ${
className={`dark:border-border flex w-full items-center gap-2 border-b border-gray-200 px-8 py-2 text-left text-[14px] ${
selectedFolderId === null
? 'bg-[#7D54D1] text-white'
: 'bg-[#F9F9F9] hover:bg-gray-100 dark:bg-[#2A2A2A] dark:hover:bg-[#383838]'
: 'bg-muted hover:bg-accent dark:bg-muted'
}`}
>
<span
@@ -226,10 +226,10 @@ export default function MoveToFolderModal({
<button
key={folder.id}
onClick={() => setSelectedFolderId(folder.id)}
className={`flex w-full cursor-pointer items-center justify-between border-b border-gray-200 px-8 py-2 text-left text-[14px] dark:border-[#3A3A3A] ${
className={`dark:border-border flex w-full cursor-pointer items-center justify-between border-b border-gray-200 px-8 py-2 text-left text-[14px] ${
selectedFolderId === folder.id
? 'bg-[#7D54D1] text-white'
: 'bg-[#F9F9F9] hover:bg-gray-100 dark:bg-[#2A2A2A] dark:hover:bg-[#383838]'
: 'bg-muted hover:bg-accent dark:bg-muted'
}`}
>
<span className="flex flex-1 items-center gap-2">
@@ -239,7 +239,7 @@ export default function MoveToFolderModal({
className={`h-4 w-4 ${selectedFolderId === folder.id ? 'brightness-0 invert' : ''}`}
/>
<span
className={`truncate ${selectedFolderId === folder.id ? 'text-white' : 'text-[#18181B] dark:text-[#E0E0E0]'}`}
className={`truncate ${selectedFolderId === folder.id ? 'text-white' : 'text-foreground'}`}
>
{folder.name}
</span>
@@ -271,14 +271,14 @@ export default function MoveToFolderModal({
</button>
))}
{currentLevelFolders.length === 0 && folderPath.length > 0 && (
<div className="flex h-[200px] items-center justify-center text-sm text-[#71717A]">
<div className="text-muted-foreground flex h-[200px] items-center justify-center text-sm">
{t('agents.folders.noSubfolders')}
</div>
)}
{currentLevelFolders.length === 0 &&
folderPath.length === 0 &&
!currentFolderId && (
<div className="flex h-[200px] items-center justify-center text-sm text-[#71717A]">
<div className="text-muted-foreground flex h-[200px] items-center justify-center text-sm">
{t('agents.folders.noFolders')}
</div>
)}
@@ -286,7 +286,7 @@ export default function MoveToFolderModal({
)}
</div>
<div className="flex items-center justify-between border-t border-gray-200 px-8 py-4 dark:border-[#3A3A3A]">
<div className="dark:border-border flex items-center justify-between border-t border-gray-200 px-8 py-4">
{isCreatingFolder ? (
<input
ref={newFolderInputRef}
@@ -309,7 +309,7 @@ export default function MoveToFolderModal({
}
}}
placeholder={t('agents.folders.newFolder')}
className="rounded-full border border-[#7D54D1] bg-transparent px-6 py-2 text-sm font-medium text-[#7D54D1] outline-none placeholder:text-[#7D54D1]/60 dark:text-[#B794F4] dark:placeholder:text-[#B794F4]/60"
className="dark:text-primary rounded-full border border-[#7D54D1] bg-transparent px-6 py-2 text-sm font-medium text-[#7D54D1] outline-none placeholder:text-[#7D54D1]/60 dark:placeholder:text-[#B794F4]/60"
autoFocus
/>
) : (
@@ -336,7 +336,7 @@ export default function MoveToFolderModal({
setModalState('INACTIVE');
}
}}
className="dark:text-light-gray cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:hover:bg-[#767183]/50"
className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
>
{t('cancel')}
</button>
@@ -351,7 +351,7 @@ export default function MoveToFolderModal({
}
}}
disabled={!newFolderName.trim()}
className="bg-purple-30 hover:bg-violets-are-blue rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
className="bg-primary hover:bg-primary/90 rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
>
{t('agents.folders.createFolder')}
</button>
@@ -361,7 +361,7 @@ export default function MoveToFolderModal({
e.stopPropagation();
handleMove();
}}
className="bg-purple-30 hover:bg-violets-are-blue rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
className="bg-primary hover:bg-primary/90 rounded-3xl px-5 py-2 text-sm text-white disabled:opacity-50"
>
{t('agents.folders.move')}
</button>

View File

@@ -98,14 +98,14 @@ export const ShareConversationModal = ({
return (
<WrapperModal close={close} contentClassName="!overflow-visible">
<div className="flex w-[600px] max-w-[80vw] flex-col gap-2">
<h2 className="text-eerie-black dark:text-chinese-white text-xl font-medium">
<h2 className="text-foreground dark:text-foreground text-xl font-medium">
{t('modals.shareConv.label')}
</h2>
<p className="text-eerie-black dark:text-silver/60 text-sm leading-relaxed">
<p className="text-foreground dark:text-muted-foreground/60 text-sm leading-relaxed">
{t('modals.shareConv.note')}
</p>
<div className="flex items-center justify-between">
<span className="text-eerie-black text-lg dark:text-white">
<span className="text-foreground text-lg dark:text-white">
{t('modals.shareConv.option')}
</span>
<ToggleSwitch
@@ -129,19 +129,19 @@ export const ShareConversationModal = ({
</div>
)}
<div className="flex items-baseline justify-between gap-2">
<span className="no-scrollbar border-silver text-eerie-black dark:border-silver/40 w-full overflow-x-auto rounded-full border-2 px-4 py-3 whitespace-nowrap dark:text-white">
<span className="no-scrollbar border-border text-foreground dark:border-border w-full overflow-x-auto rounded-full border-2 px-4 py-3 whitespace-nowrap dark:text-white">
{`${domain}/share/${identifier ?? '....'}`}
</span>
{status === 'fetched' ? (
<button
className="bg-purple-30 hover:bg-violets-are-blue my-1 h-10 w-28 rounded-full p-2 text-sm text-white"
className="bg-primary hover:bg-primary/90 my-1 h-10 w-28 rounded-full p-2 text-sm text-white"
onClick={() => handleCopyKey(`${domain}/share/${identifier}`)}
>
{isCopied ? t('modals.saveKey.copied') : t('modals.saveKey.copy')}
</button>
) : (
<button
className="bg-purple-30 hover:bg-violets-are-blue my-1 flex h-10 w-28 items-center justify-evenly rounded-full p-2 text-center text-sm font-normal text-white"
className="bg-primary hover:bg-primary/90 my-1 flex h-10 w-28 items-center justify-evenly rounded-full p-2 text-center text-sm font-normal text-white"
onClick={() => {
shareCoversationPublicly(allowPrompt);
}}

View File

@@ -32,8 +32,7 @@ export default function WrapperModal({
)
return;
if (document.querySelector('[data-radix-select-content]')) return;
if (modalRef.current && !modalRef.current.contains(target))
close();
if (modalRef.current && !modalRef.current.contains(target)) close();
};
const handleEscapePress = (event: KeyboardEvent) => {
@@ -61,7 +60,7 @@ export default function WrapperModal({
/>
<div
ref={modalRef}
className={`relative rounded-2xl bg-white p-8 shadow-[0px_4px_40px_-3px_#0000001A] dark:bg-[#26272E] ${className}`}
className={`bg-card dark:bg-card relative rounded-2xl p-8 shadow-[0px_4px_40px_-3px_#0000001A] ${className}`}
>
{!isPerformingTask && (
<button
@@ -72,7 +71,7 @@ export default function WrapperModal({
</button>
)}
<div
className={`no-scrollbar overflow-y-auto text-[#18181B] dark:text-[#ECECF1] ${contentClassName}`}
className={`no-scrollbar text-foreground dark:text-foreground overflow-y-auto ${contentClassName}`}
>
{children}
</div>

View File

@@ -120,11 +120,11 @@ function PromptTextarea({
return (
<>
<div
className="pointer-events-none absolute inset-0 z-0 overflow-hidden rounded bg-white px-3 py-2 dark:bg-[#26272E]"
className="bg-card pointer-events-none absolute inset-0 z-0 overflow-hidden rounded px-3 py-2"
aria-hidden="true"
>
<div
className="min-h-full text-base leading-[1.5] break-words whitespace-pre-wrap text-transparent"
className="min-h-full text-base leading-normal wrap-break-word whitespace-pre-wrap text-transparent"
style={{
transform: `translate(${-scrollOffsets.left}px, ${-scrollOffsets.top}px)`,
}}
@@ -134,7 +134,7 @@ function PromptTextarea({
</div>
<textarea
id={id}
className="peer border-silver dark:border-silver/40 relative z-10 h-48 w-full resize-none rounded border-2 bg-transparent px-3 py-2 text-base text-gray-800 outline-none md:h-64 lg:h-80 dark:bg-transparent dark:text-white"
className="peer border-border dark:border-border relative z-10 h-48 w-full resize-none rounded border-2 bg-transparent px-3 py-2 text-base text-gray-800 outline-none md:h-64 lg:h-80 dark:text-white"
value={value}
onChange={onChange}
onScroll={handleScroll}
@@ -239,7 +239,7 @@ function AddPrompt({
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
{t('modals.prompts.addPrompt')}
</p>
<p className="mb-6 text-sm text-[#6B6B6B] dark:text-[#9A9AA0]">
<p className="dark:text-muted-foreground mb-6 text-sm text-[#6B6B6B]">
{t('modals.prompts.addDescription')}
</p>
<div>
@@ -251,7 +251,7 @@ function AddPrompt({
textSize="medium"
value={newPromptName}
onChange={(e) => setNewPromptName(e.target.value)}
labelBgClassName="bg-white dark:bg-[#26272E]"
labelBgClassName="bg-card"
borderVariant="thick"
/>
@@ -266,7 +266,7 @@ function AddPrompt({
htmlFor="new-prompt-content"
className={`absolute z-20 select-none ${
newPromptContent ? '-top-2.5 left-3 text-xs' : ''
} text-gray-4000 pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden bg-white px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs dark:bg-[#26272E] dark:text-gray-400`}
} text-muted-foreground bg-card pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`}
>
{t('modals.prompts.promptText')}
</label>
@@ -278,7 +278,7 @@ function AddPrompt({
<span className="font-bold">
{t('modals.prompts.variablesLabel')}
</span>
<span className="text-xs text-[10px] font-medium text-gray-500">
<span className="text-muted-foreground text-xs text-[10px] font-medium">
{t('modals.prompts.variablesDescription')}
</span>
</p>
@@ -326,7 +326,6 @@ function AddPrompt({
placeholder={t('modals.prompts.systemVariablesDropdownLabel')}
size="w-[140px] sm:w-[185px]"
rounded="3xl"
border="border"
contentSize="text-[12px] sm:text-[14px]"
/>
@@ -371,7 +370,6 @@ function AddPrompt({
placeholder="Tool Variables"
size="w-[140px] sm:w-[171px]"
rounded="3xl"
border="border"
contentSize="text-[12px] sm:text-[14px]"
/>
</div>
@@ -387,7 +385,7 @@ function AddPrompt({
<img
src={BookIcon}
alt=""
className="flex h-4 w-3 flex-shrink-0 items-center justify-center"
className="flex h-4 w-3 shrink-0 items-center justify-center"
aria-hidden="true"
/>
<span className="text-[14px] font-bold">
@@ -448,7 +446,7 @@ function EditPrompt({
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
{t('modals.prompts.editPrompt')}
</p>
<p className="mb-6 text-sm text-[#6B6B6B] dark:text-[#9A9AA0]">
<p className="dark:text-muted-foreground mb-6 text-sm text-[#6B6B6B]">
{t('modals.prompts.editDescription')}
</p>
<div>
@@ -460,7 +458,7 @@ function EditPrompt({
textSize="medium"
value={editPromptName}
onChange={(e) => setEditPromptName(e.target.value)}
labelBgClassName="bg-white dark:bg-[#26272E]"
labelBgClassName="bg-card"
borderVariant="thick"
/>
@@ -475,7 +473,7 @@ function EditPrompt({
htmlFor="edit-prompt-content"
className={`absolute z-20 select-none ${
editPromptContent ? '-top-2.5 left-3 text-xs' : ''
} text-gray-4000 pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden bg-white px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs dark:bg-[#26272E] dark:text-gray-400`}
} text-muted-foreground bg-card pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`}
>
{t('modals.prompts.promptText')}
</label>
@@ -487,7 +485,7 @@ function EditPrompt({
<span className="font-bold">
{t('modals.prompts.variablesLabel')}
</span>
<span className="text-xs text-[10px] font-medium text-gray-500">
<span className="text-muted-foreground text-xs text-[10px] font-medium">
{t('modals.prompts.variablesDescription')}
</span>
</p>
@@ -535,7 +533,6 @@ function EditPrompt({
placeholder={t('modals.prompts.systemVariablesDropdownLabel')}
size="w-[140px] sm:w-[185px]"
rounded="3xl"
border="border"
contentSize="text-[12px] sm:text-[14px]"
/>
@@ -580,7 +577,6 @@ function EditPrompt({
placeholder="Tool Variables"
size="w-[140px] sm:w-[171px]"
rounded="3xl"
border="border"
contentSize="text-[12px] sm:text-[14px]"
/>
</div>
@@ -596,7 +592,7 @@ function EditPrompt({
<img
src={BookIcon}
alt=""
className="flex h-4 w-3 flex-shrink-0 items-center justify-center"
className="flex h-4 w-3 shrink-0 items-center justify-center"
aria-hidden="true"
/>
<span className="text-[14px] font-bold">
@@ -763,7 +759,7 @@ export default function PromptsModal({
setNewPromptContent('');
}
}}
className="mx-4 mt-16 w-[95vw] max-w-[650px] rounded-2xl bg-white px-4 py-4 sm:px-6 sm:py-6 md:max-w-[860px] md:px-8 md:py-6 lg:max-w-[980px] dark:bg-[#1E1E2A]"
className="bg-card dark:bg-card mx-4 mt-16 w-[95vw] max-w-[650px] rounded-2xl px-4 py-4 sm:px-6 sm:py-6 md:max-w-[860px] md:px-8 md:py-6 lg:max-w-[980px]"
contentClassName="!overflow-visible"
>
{view}

View File

@@ -174,12 +174,15 @@ export default function Analytics({ agentId }: AnalyticsProps) {
fetchFeedbackData(id, filter?.value);
}, [agentId, feedbackFilter]);
return (
<div className="mt-12">
<div className="mt-8">
<p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.analytics.subtitle')}
</p>
{/* Messages Analytics */}
<div className="mt-8 flex w-full flex-col gap-3 [@media(min-width:1080px)]:flex-row">
<div className="border-silver dark:border-silver/40 h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5 [@media(min-width:1080px)]:w-1/2">
<div className="mt-4 flex w-full flex-col gap-3 [@media(min-width:1080px)]:flex-row">
<div className="border-border dark:border-border h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5 [@media(min-width:1080px)]:w-1/2">
<div className="flex flex-row items-center justify-start gap-3">
<p className="text-jet dark:text-bright-gray font-bold">
<p className="text-foreground dark:text-foreground font-bold">
{t('settings.analytics.messages')}
</p>
<Dropdown
@@ -191,7 +194,6 @@ export default function Analytics({ agentId }: AnalyticsProps) {
}}
selectedValue={messagesFilter ?? null}
rounded="3xl"
border="border"
contentSize="text-sm"
/>
</div>
@@ -225,9 +227,9 @@ export default function Analytics({ agentId }: AnalyticsProps) {
</div>
{/* Token Usage Analytics */}
<div className="border-silver dark:border-silver/40 h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5 [@media(min-width:1080px)]:w-1/2">
<div className="border-border dark:border-border h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5 [@media(min-width:1080px)]:w-1/2">
<div className="flex flex-row items-center justify-start gap-3">
<p className="text-jet dark:text-bright-gray font-bold">
<p className="text-foreground dark:text-foreground font-bold">
{t('settings.analytics.tokenUsage')}
</p>
<Dropdown
@@ -239,7 +241,6 @@ export default function Analytics({ agentId }: AnalyticsProps) {
}}
selectedValue={tokenUsageFilter ?? null}
rounded="3xl"
border="border"
contentSize="text-sm"
/>
</div>
@@ -275,9 +276,9 @@ export default function Analytics({ agentId }: AnalyticsProps) {
{/* Feedback Analytics */}
<div className="mt-8 flex w-full flex-col gap-3">
<div className="border-silver dark:border-silver/40 h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5">
<div className="border-border dark:border-border h-[345px] w-full overflow-hidden rounded-2xl border px-6 py-5">
<div className="flex flex-row items-center justify-start gap-3">
<p className="text-jet dark:text-bright-gray font-bold">
<p className="text-foreground dark:text-foreground font-bold">
{t('settings.analytics.userFeedback')}
</p>
<Dropdown
@@ -289,7 +290,6 @@ export default function Analytics({ agentId }: AnalyticsProps) {
}}
selectedValue={feedbackFilter ?? null}
rounded="3xl"
border="border"
contentSize="text-sm"
/>
</div>

View File

@@ -55,8 +55,7 @@ export default function General() {
changeLanguage(selectedLanguage?.value);
}, [selectedLanguage, changeLanguage]);
return (
<div className="mt-12 flex flex-col gap-4">
{' '}
<div className="mt-8 flex flex-col gap-6">
<div className="flex flex-col gap-4">
<Prompts
prompts={prompts}
@@ -65,11 +64,11 @@ export default function General() {
dispatch(setPrompt({ name: name, id: id, type: type }))
}
setPrompts={(newPrompts) => dispatch(setPrompts(newPrompts))}
dropdownProps={{ size: 'w-56', rounded: '3xl', border: 'border' }}
dropdownProps={{ size: 'w-56', rounded: '3xl' }}
/>
</div>
<div className="flex flex-col gap-4">
<label className="text-jet dark:text-bright-gray text-base font-medium">
<label className="text-foreground dark:text-foreground text-base font-medium">
{t('settings.general.chunks')}
</label>
<Dropdown
@@ -78,12 +77,10 @@ export default function General() {
onSelect={(value: string) => dispatch(setChunks(value))}
size="w-56"
rounded="3xl"
border="border"
/>
</div>
<div className="flex flex-col gap-4">
{' '}
<label className="text-jet dark:text-bright-gray text-base font-medium">
<label className="text-foreground dark:text-foreground text-base font-medium">
{t('settings.general.selectTheme')}
</label>
<Dropdown
@@ -97,11 +94,10 @@ export default function General() {
}}
size="w-56"
rounded="3xl"
border="border"
/>
</div>
<div className="flex flex-col gap-4">
<label className="text-jet dark:text-bright-gray text-base font-medium">
<label className="text-foreground dark:text-foreground text-base font-medium">
{t('settings.general.selectLanguage')}
</label>
<Dropdown
@@ -115,14 +111,13 @@ export default function General() {
}}
size="w-56"
rounded="3xl"
border="border"
/>
</div>
<hr className="border-silver dark:border-silver/40 my-4 w-[calc(min(665px,100%))] border-t" />
<hr className="border-border dark:border-border my-4 w-[calc(min(665px,100%))] border-t" />
<div className="flex flex-col gap-2">
<button
title={t('settings.general.deleteAllLabel')}
className="border-rosso-corsa text-rosso-corsa hover:bg-rosso-corsa flex w-fit cursor-pointer items-center justify-between rounded-3xl border border-solid bg-transparent px-5 py-3 text-sm font-medium tracking-[0.015em] transition-colors hover:font-bold hover:tracking-normal hover:text-white"
className="border-destructive text-destructive hover:bg-destructive flex w-fit cursor-pointer items-center justify-between rounded-3xl border border-solid bg-transparent px-5 py-3 text-sm font-medium tracking-[0.015em] transition-colors hover:font-bold hover:tracking-normal hover:text-white"
onClick={() => dispatch(setModalStateDeleteConv('ACTIVE'))}
>
{t('settings.general.deleteAllBtn')}

View File

@@ -16,6 +16,7 @@ type LogsProps = {
};
export default function Logs({ agentId, tableHeader }: LogsProps) {
const { t } = useTranslation();
const token = useSelector(selectToken);
const [logsByPage, setLogsByPage] = useState<Record<number, LogData[]>>({});
const [page, setPage] = useState(1);
@@ -56,8 +57,11 @@ export default function Logs({ agentId, tableHeader }: LogsProps) {
if (hasMore) fetchLogs();
}, [page, agentId]);
return (
<div className="mt-12">
<div className="mt-8">
<div className="mt-8">
<p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.logs.subtitle')}
</p>
<div>
<LogsTable
logs={logs}
setPage={setPage}
@@ -113,9 +117,9 @@ function LogsTable({ logs, setPage, loading, tableHeader }: LogsTableProps) {
}, []);
return (
<div className="logs-table border-light-silver h-[55vh] w-full overflow-hidden rounded-xl border bg-white dark:border-transparent dark:bg-black">
<div className="dark:bg-eerie-black-2 flex h-8 flex-col items-start justify-center bg-black/10">
<p className="dark:text-gray-6000 px-3 text-xs">
<div className="logs-table border-border bg-card h-[55vh] w-full overflow-hidden rounded-xl border dark:bg-black">
<div className="flex h-8 flex-col items-start justify-center bg-black/10 dark:bg-white/5">
<p className="text-muted-foreground px-3 text-xs">
{tableHeader ? tableHeader : t('settings.logs.tableHeader')}
</p>
</div>
@@ -164,11 +168,11 @@ function Log({
const { id, action, timestamp, ...filteredLog } = log;
return (
<div className="group dark:hover:bg-dark-charcoal w-full rounded-xl bg-transparent hover:bg-[#F9F9F9]">
<div className="group dark:hover:bg-accent hover:bg-muted w-full rounded-xl bg-transparent">
<div
onClick={() => onToggle(log.id)}
className={`flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 text-gray-900 ${
isOpen ? 'rounded-t-xl bg-[#F1F1F1] dark:bg-[#1B1B1B]' : ''
className={`text-foreground flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 ${
isOpen ? 'dark:bg-background rounded-t-xl bg-[#F1F1F1]' : ''
}`}
>
<img
@@ -177,10 +181,10 @@ function Log({
className={`mt-[3px] h-3 w-3 transition duration-300 ${isOpen ? 'rotate-90' : ''}`}
/>
<span className="flex flex-row gap-2">
<h2 className="dark:text-bright-gray text-xs text-black/60">{`${log.timestamp}`}</h2>
<h2 className="text-xs text-[#913400] dark:text-[#DF5200]">{`[${log.action}]`}</h2>
<h2 className="dark:text-foreground text-xs text-black/60">{`${log.timestamp}`}</h2>
<h2 className="text-xs text-[#913400] dark:text-orange-500">{`[${log.action}]`}</h2>
<h2
className={`max-w-72 text-xs ${logLevelColor[log.level]} break-words`}
className={`max-w-72 text-xs ${logLevelColor[log.level]} wrap-break-word`}
>
{`${log.question}`.length > 250
? `${log.question.substring(0, 250)}...`
@@ -189,9 +193,9 @@ function Log({
</span>
</div>
{isOpen && (
<div className="rounded-b-xl bg-[#F1F1F1] px-4 py-3 dark:bg-[#1B1B1B]">
<div className="dark:bg-background rounded-b-xl bg-[#F1F1F1] px-4 py-3">
<div className="scrollbar-overlay overflow-y-auto">
<pre className="px-2 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-gray-700 dark:text-gray-400">
<pre className="px-2 font-mono text-xs leading-relaxed wrap-break-word whitespace-pre-wrap text-gray-700 dark:text-gray-400">
{JSON.stringify(filteredLog, null, 2)}
</pre>
</div>

View File

@@ -3,8 +3,7 @@ import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import userService from '../api/services/userService';
import SearchableDropdown from '../components/SearchableDropdown';
import { DropdownProps } from '../components/types/Dropdown.types';
import Dropdown, { DropdownProps } from '../components/Dropdown';
import ConfirmationModal from '../modals/ConfirmationModal';
import { ActiveState, PromptProps } from '../models/misc';
import { selectToken } from '../preferences/preferenceSlice';
@@ -23,7 +22,7 @@ export default function Prompts({
onSelectPrompt,
setPrompts,
title,
titleClassName = 'dark:text-bright-gray font-medium',
titleClassName = 'dark:text-foreground font-medium',
dropdownProps = {},
showAddButton = true,
}: ExtendedPromptProps) {
@@ -186,8 +185,9 @@ export default function Prompts({
<p className={titleClassName}>
{title ? title : t('settings.general.prompt')}
</p>
<div className="flex flex-row flex-wrap items-baseline justify-start gap-6">
<SearchableDropdown
<div className="flex flex-row flex-wrap items-end justify-start gap-6">
<Dropdown
searchable
options={prompts.map((prompt: any) =>
typeof prompt === 'string'
? { name: prompt, id: prompt, type: '' }
@@ -218,7 +218,7 @@ export default function Prompts({
/>
{showAddButton && (
<button
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue h-10 w-20 rounded-3xl border border-solid text-sm transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 w-20 rounded-3xl border border-solid py-3 text-sm transition-colors hover:text-white"
onClick={() => {
setModalType('ADD');
setModalState('ACTIVE');

View File

@@ -8,6 +8,7 @@ import EyeView from '../assets/eye-view.svg';
import NoFilesIcon from '../assets/no-files.svg';
import NoFilesDarkIcon from '../assets/no-files-dark.svg';
import Trash from '../assets/red-trash.svg';
import SearchIcon from '../assets/search.svg';
import SyncIcon from '../assets/sync.svg';
import ThreeDots from '../assets/three-dots.svg';
import CalendarIcon from '../assets/calendar.svg';
@@ -361,17 +362,20 @@ export default function Sources({
) : (
<div className="mt-8 flex w-full max-w-full flex-col overflow-hidden">
<div className="relative flex grow flex-col">
<div className="mb-6">
<h2 className="text-sonic-silver text-base font-medium">
{t('settings.sources.title')}
</h2>
</div>
<p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.sources.subtitle')}
</p>
<div className="mb-6 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div className="w-full sm:w-auto">
<label htmlFor="document-search-input" className="sr-only">
{t('settings.sources.searchPlaceholder')}
</label>
<div className="relative w-[280px]">
<div className="relative w-full max-w-md">
<img
src={SearchIcon}
alt=""
className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40"
/>
<input
maxLength={256}
placeholder={t('settings.sources.searchPlaceholder')}
@@ -383,12 +387,12 @@ export default function Sources({
setSearchTerm(e.target.value);
setCurrentPage(1);
}}
className="border-silver dark:border-silver/40 text-jet dark:text-bright-gray focus:border-silver dark:focus:border-silver/60 h-[32px] w-full rounded-full border bg-transparent px-3 text-sm outline-none placeholder:text-gray-400 dark:placeholder:text-gray-500"
className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/>
</div>
</div>
<button
className="bg-purple-30 hover:bg-violets-are-blue flex h-[38px] min-w-[108px] items-center justify-center rounded-full px-4 text-[14px] whitespace-normal text-white"
className="bg-primary hover:bg-primary/90 flex h-11 min-w-[108px] items-center justify-center rounded-full px-4 text-sm whitespace-normal text-white"
title={t('settings.sources.addSource')}
onClick={() => {
setIsOnboarding(false);
@@ -422,7 +426,7 @@ export default function Sources({
return (
<div key={docId} className="relative">
<div
className={`flex h-[130px] w-full flex-col rounded-2xl bg-[#F9F9F9] p-3 transition-all duration-200 dark:bg-[#383838] ${
className={`bg-muted dark:bg-accent flex h-[130px] w-full flex-col rounded-2xl p-3 transition-all duration-200 ${
activeMenuId === docId || syncMenuState.docId === docId
? 'scale-[1.05]'
: 'hover:scale-[1.05]'
@@ -431,7 +435,7 @@ export default function Sources({
<div className="w-full flex-1">
<div className="flex w-full items-center justify-between gap-2">
<h3
className="font-inter dark:text-bright-gray line-clamp-3 text-[13px] leading-[18px] font-semibold break-words text-[#18181B]"
className="font-inter dark:text-foreground text-foreground line-clamp-3 text-[13px] leading-[18px] font-semibold wrap-break-word"
title={document.name}
>
{document.name}
@@ -472,7 +476,7 @@ export default function Sources({
e.stopPropagation();
handleMenuClick(e, docId);
}}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md transition-colors hover:bg-[#EBEBEB] dark:hover:bg-[#26272E]"
className="dark:hover:bg-muted inline-flex h-[35px] w-6 shrink-0 items-center justify-center rounded-md transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')}
data-testid={`menu-button-${docId}`}
>
@@ -491,19 +495,15 @@ export default function Sources({
<img
src={CalendarIcon}
alt=""
className="h-[14px] w-[14px]"
className="h-3.5 w-3.5"
/>
<span className="font-inter text-[12px] leading-[18px] font-[500] text-[#848484] dark:text-[#848484]">
<span className="font-inter text-muted-foreground text-[12px] leading-[18px] font-medium">
{document.date ? formatDate(document.date) : ''}
</span>
</div>
<div className="flex items-center gap-2">
<img
src={DiscIcon}
alt=""
className="h-[14px] w-[14px]"
/>
<span className="font-inter text-[12px] leading-[18px] font-[500] text-[#848484] dark:text-[#848484]">
<img src={DiscIcon} alt="" className="h-3.5 w-3.5" />
<span className="font-inter text-muted-foreground text-[12px] leading-[18px] font-medium">
{document.tokens
? formatTokens(+document.tokens)
: ''}

View File

@@ -330,9 +330,9 @@ export default function ToolConfig({
return (
<div className="scrollbar-overlay mt-8 flex flex-col gap-4">
<div className="mb-4 flex items-center justify-between">
<div className="text-eerie-black dark:text-bright-gray flex items-center gap-3 text-sm">
<div className="text-foreground dark:text-foreground flex items-center gap-3 text-sm">
<button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
onClick={handleBackClick}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
@@ -340,7 +340,7 @@ export default function ToolConfig({
<p className="mt-px">{t('settings.tools.backToAllTools')}</p>
</div>
<button
className="bg-purple-30 hover:bg-violets-are-blue rounded-full px-3 py-2 text-xs text-nowrap text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50 sm:px-4 sm:py-2"
className="bg-primary hover:bg-primary/90 rounded-full px-3 py-2 text-xs text-nowrap text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50 sm:px-4 sm:py-2"
onClick={handleSaveChanges}
disabled={!hasUnsavedChanges || saving}
>
@@ -353,7 +353,7 @@ export default function ToolConfig({
</div>
)}
<div className="mt-1">
<p className="text-eerie-black dark:text-bright-gray text-sm font-semibold">
<p className="text-foreground dark:text-foreground text-sm font-semibold">
{t('settings.tools.customName')}
</p>
<div className="relative mt-4 w-full max-w-96">
@@ -370,7 +370,7 @@ export default function ToolConfig({
{tool.name !== 'api_tool' &&
Object.keys(configRequirements).length > 0 && (
<div>
<p className="text-eerie-black dark:text-bright-gray mb-4 text-sm font-semibold">
<p className="text-foreground dark:text-foreground mb-4 text-sm font-semibold">
{t('settings.tools.authentication')}
</p>
<div className="max-w-96">
@@ -391,20 +391,20 @@ export default function ToolConfig({
<div className="flex flex-col gap-4">
<div className="mx-0 my-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40"></div>
<div className="flex w-full flex-row items-center justify-between gap-2">
<p className="text-eerie-black dark:text-bright-gray text-base font-semibold">
<p className="text-foreground dark:text-foreground text-base font-semibold">
{t('settings.tools.actions')}
</p>
{tool.name === 'api_tool' && (
<div className="flex gap-2">
<button
onClick={() => setImportModalState('ACTIVE')}
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue rounded-full border border-solid px-5 py-1 text-sm transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 rounded-full border border-solid px-5 py-1 text-sm transition-colors hover:text-white"
>
{t('settings.tools.importSpec')}
</button>
<button
onClick={() => setActionModalState('ACTIVE')}
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue rounded-full border border-solid px-5 py-1 text-sm transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 rounded-full border border-solid px-5 py-1 text-sm transition-colors hover:text-white"
>
{t('settings.tools.addAction')}
</button>
@@ -434,26 +434,24 @@ export default function ToolConfig({
{'actions' in tool && tool.actions && tool.actions.length > 0 ? (
<>
<div className="relative">
<svg
className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
>
<circle cx="11" cy="11" r="8" />
<path strokeLinecap="round" d="m21 21-4.35-4.35" />
</svg>
<input
type="text"
value={userActionsSearch}
onChange={(e) => setUserActionsSearch(e.target.value)}
placeholder={t('settings.tools.searchActions')}
className="border-silver dark:border-silver/40 dark:bg-raisin-black w-full rounded-full border px-4 py-2 pl-10 text-sm outline-none focus:border-purple-500 dark:text-white dark:placeholder-gray-500"
className="border-border text-foreground placeholder:text-muted-foreground h-10 w-full rounded-full border bg-transparent pr-4 pl-10 text-sm outline-none"
/>
<svg
className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</div>
{filteredUserActions.length === 0 && userActionsSearch && (
@@ -467,10 +465,10 @@ export default function ToolConfig({
return (
<div
key={originalIndex}
className="border-silver dark:border-silver/40 w-full rounded-xl border"
className="border-border dark:border-border w-full rounded-xl border"
>
<div
className={`border-silver dark:border-silver/40 flex cursor-pointer flex-wrap items-center justify-between ${isExpanded ? 'rounded-t-xl border-b' : 'rounded-xl'} bg-[#F9F9F9] px-4 py-3 dark:bg-[#28292D]`}
className={`border-border dark:border-border flex cursor-pointer flex-wrap items-center justify-between ${isExpanded ? 'rounded-t-xl border-b' : 'rounded-xl'} bg-muted px-4 py-3`}
onClick={() => toggleUserActionExpand(originalIndex)}
>
<div className="flex items-center gap-3">
@@ -479,7 +477,7 @@ export default function ToolConfig({
alt="expand"
className={`h-4 w-4 opacity-60 transition-transform duration-200 ${isExpanded ? 'rotate-90' : ''}`}
/>
<p className="text-eerie-black dark:text-bright-gray font-semibold">
<p className="text-foreground dark:text-foreground font-semibold">
{action.name}
</p>
{action.description && (
@@ -588,7 +586,7 @@ export default function ToolConfig({
<input
key={uniqueKey}
value={param[1].description}
className="border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onChange={(e) => {
setTool({
...tool,
@@ -626,7 +624,7 @@ export default function ToolConfig({
value={param[1].value}
key={uniqueKey}
disabled={param[1].filled_by_llm}
className={`border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden ${param[1].filled_by_llm ? 'opacity-50' : ''}`}
className={`border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden ${param[1].filled_by_llm ? 'opacity-50' : ''}`}
onChange={(e) => {
setTool({
...tool,
@@ -855,26 +853,24 @@ function APIToolConfig({
return (
<div className="scrollbar-overlay flex flex-col gap-4">
<div className="relative">
<svg
className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
>
<circle cx="11" cy="11" r="8" />
<path strokeLinecap="round" d="m21 21-4.35-4.35" />
</svg>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder={t('settings.tools.searchActions')}
className="border-silver dark:border-silver/40 dark:bg-raisin-black w-full rounded-full border px-4 py-2 pl-10 text-sm outline-none focus:border-purple-500 dark:text-white dark:placeholder-gray-500"
className="border-border text-foreground placeholder:text-muted-foreground h-10 w-full rounded-full border bg-transparent pr-4 pl-10 text-sm outline-none"
/>
<svg
className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</div>
{filteredActions.length === 0 && searchQuery && (
@@ -889,10 +885,10 @@ function APIToolConfig({
return (
<div
key={actionIndex}
className="border-silver dark:border-silver/40 w-full rounded-xl border"
className="border-border dark:border-border w-full rounded-xl border"
>
<div
className={`border-silver dark:border-silver/40 flex cursor-pointer flex-wrap items-center justify-between ${isExpanded ? 'rounded-t-xl border-b' : 'rounded-xl'} bg-[#F9F9F9] px-4 py-3 dark:bg-[#28292D]`}
className={`border-border dark:border-border flex cursor-pointer flex-wrap items-center justify-between ${isExpanded ? 'rounded-t-xl border-b' : 'rounded-xl'} bg-muted px-4 py-3`}
onClick={() => toggleActionExpand(actionName)}
>
<div className="flex items-center gap-3">
@@ -906,7 +902,7 @@ function APIToolConfig({
>
{action.method}
</span>
<p className="text-eerie-black dark:text-bright-gray font-semibold">
<p className="text-foreground dark:text-foreground font-semibold">
{action.name}
</p>
{action.description && (
@@ -969,7 +965,7 @@ function APIToolConfig({
</div>
<div className="mt-4 px-5 py-2">
<div className="relative w-full">
<span className="text-gray-4000 dark:bg-raisin-black dark:text-silver absolute -top-2 left-5 z-10 bg-white px-2 text-xs">
<span className="text-muted-foreground bg-card absolute -top-2 left-5 z-10 px-2 text-xs">
{t('settings.tools.method')}
</span>
<Dropdown
@@ -1011,7 +1007,6 @@ function APIToolConfig({
}}
size="w-56"
rounded="3xl"
border="border"
/>
</div>
</div>
@@ -1049,7 +1044,7 @@ function APIToolConfig({
action.method === 'OPTIONS') && (
<div className="mt-4 px-5 py-2">
<div className="relative w-full">
<span className="text-gray-4000 dark:bg-raisin-black dark:text-silver absolute -top-2 left-5 z-10 bg-white px-2 text-xs">
<span className="text-muted-foreground bg-card absolute -top-2 left-5 z-10 px-2 text-xs">
{t('settings.tools.bodyContentType')}
</span>
<Dropdown
@@ -1091,10 +1086,9 @@ function APIToolConfig({
}}
size="w-56"
rounded="3xl"
border="border"
/>
</div>
<p className="text-eerie-black dark:text-bright-gray mt-2 text-xs opacity-60">
<p className="text-foreground dark:text-foreground mt-2 text-xs opacity-60">
{action.body_content_type === 'multipart/form-data' &&
'For APIs requiring multipart format. File uploads not supported through LLM.'}
{action.body_content_type ===
@@ -1346,7 +1340,7 @@ function APIActionTable({
<div className="flex flex-row items-center justify-between gap-2">
<input
value={newPropertyKey}
className="border-silver dark:border-silver/40 flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onChange={(e) => setNewPropertyKey(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
@@ -1376,7 +1370,7 @@ function APIActionTable({
) : (
<input
value={key}
className="border-silver dark:border-silver/40 flex w-full min-w-[175.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[175.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onFocus={() => handleRenamePropertyStart(section, key)}
readOnly
/>
@@ -1392,7 +1386,7 @@ function APIActionTable({
e.target.value as 'string' | 'integer',
)
}
className="border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
>
<option value="string">string</option>
<option value="integer">integer</option>
@@ -1420,7 +1414,7 @@ function APIActionTable({
<td className="w-10">
<input
value={param.description}
className="border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onChange={(e) =>
handlePropertyChange(
section,
@@ -1438,7 +1432,7 @@ function APIActionTable({
onChange={(e) =>
handlePropertyChange(section, key, 'value', e.target.value)
}
className={`border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden ${param.filled_by_llm ? 'opacity-50' : ''}`}
className={`border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden ${param.filled_by_llm ? 'opacity-50' : ''}`}
></input>
</td>
<td
@@ -1448,7 +1442,7 @@ function APIActionTable({
maxWidth: '50px',
padding: '0',
}}
className="border-silver dark:border-silver/40 border-b"
className="border-border dark:border-border border-b"
>
<button
onClick={() => handlePorpertyDelete(section, key)}
@@ -1472,7 +1466,7 @@ function APIActionTable({
}
}}
placeholder={t('settings.tools.propertyName')}
className="border-silver dark:border-silver/40 flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
/>
</td>
<td>
@@ -1481,7 +1475,7 @@ function APIActionTable({
onChange={(e) =>
setNewPropertyType(e.target.value as 'string' | 'integer')
}
className="border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
>
<option value="string">string</option>
<option value="integer">integer</option>
@@ -1490,7 +1484,7 @@ function APIActionTable({
<td colSpan={3} className="text-right">
<button
onClick={handleAddProperty}
className="bg-purple-30 hover:bg-violets-are-blue mr-1 rounded-full px-5 py-1 text-sm text-white"
className="bg-primary hover:bg-primary/90 mr-1 rounded-full px-5 py-1 text-sm text-white"
>
{t('settings.tools.add')}
</button>
@@ -1515,7 +1509,7 @@ function APIActionTable({
<td colSpan={5}>
<button
onClick={() => handleAddPropertyStart(section)}
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue flex items-start rounded-full border border-solid px-5 py-1 text-sm text-nowrap transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 flex items-start rounded-full border border-solid px-5 py-1 text-sm text-nowrap transition-colors hover:text-white"
>
{t('settings.tools.addNew')}
</button>
@@ -1546,7 +1540,7 @@ function APIActionTable({
<div className="flex flex-row items-center justify-between gap-2">
<input
value={newPropertyKey}
className="border-silver dark:border-silver/40 flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onChange={(e) => setNewPropertyKey(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
@@ -1576,7 +1570,7 @@ function APIActionTable({
) : (
<input
value={key}
className="border-silver dark:border-silver/40 flex w-full min-w-[175.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[175.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onFocus={() => handleRenamePropertyStart('headers', key)}
readOnly
/>
@@ -1594,13 +1588,13 @@ function APIActionTable({
)
}
placeholder="e.g., application/json"
className="border-silver dark:border-silver/40 w-full rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border w-full rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
/>
</td>
<td>
<input
value={param.description}
className="border-silver dark:border-silver/40 rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
onChange={(e) =>
handlePropertyChange(
'headers',
@@ -1618,7 +1612,7 @@ function APIActionTable({
maxWidth: '50px',
padding: '0',
}}
className="border-silver dark:border-silver/40 border-b"
className="border-border dark:border-border border-b"
>
<button
onClick={() => handlePorpertyDelete('headers', key)}
@@ -1642,13 +1636,13 @@ function APIActionTable({
}
}}
placeholder={t('settings.tools.propertyName')}
className="border-silver dark:border-silver/40 flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
className="border-border dark:border-border flex w-full min-w-[130.5px] items-start rounded-lg border bg-transparent px-2 py-1 text-sm outline-hidden"
/>
</td>
<td colSpan={2} className="text-right">
<button
onClick={handleAddProperty}
className="bg-purple-30 hover:bg-violets-are-blue mr-1 rounded-full px-5 py-1 text-sm text-white"
className="bg-primary hover:bg-primary/90 mr-1 rounded-full px-5 py-1 text-sm text-white"
>
{t('settings.tools.add')}
</button>
@@ -1673,7 +1667,7 @@ function APIActionTable({
<td colSpan={3}>
<button
onClick={() => handleAddPropertyStart('headers')}
className="border-violets-are-blue text-violets-are-blue hover:bg-violets-are-blue flex items-start rounded-full border border-solid px-5 py-1 text-sm text-nowrap transition-colors hover:text-white"
className="border-primary text-primary hover:bg-primary/90 flex items-start rounded-full border border-solid px-5 py-1 text-sm text-nowrap transition-colors hover:text-white"
>
{t('settings.tools.addNew')}
</button>
@@ -1695,19 +1689,19 @@ function APIActionTable({
return (
<div className="scrollbar-overlay flex flex-col gap-6">
<div>
<h3 className="text-eerie-black dark:text-bright-gray mb-1 text-base font-normal">
<h3 className="text-foreground dark:text-foreground mb-1 text-base font-normal">
{t('settings.tools.headers')}
</h3>
<table className="table-default">
<thead>
<tr>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.name')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.value')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.description')}
</th>
<th
@@ -1724,25 +1718,25 @@ function APIActionTable({
</table>
</div>
<div>
<h3 className="text-eerie-black dark:text-bright-gray mb-1 text-base font-normal">
<h3 className="text-foreground dark:text-foreground mb-1 text-base font-normal">
{t('settings.tools.queryParameters')}
</h3>
<table className="table-default">
<thead>
<tr>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.name')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.type')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.filledByLLM')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.description')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.value')}
</th>
<th
@@ -1759,25 +1753,25 @@ function APIActionTable({
</table>
</div>
<div className="mb-6">
<h3 className="text-eerie-black dark:text-bright-gray mb-1 text-base font-normal">
<h3 className="text-foreground dark:text-foreground mb-1 text-base font-normal">
{t('settings.tools.body')}
</h3>
<table className="table-default">
<thead>
<tr>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.name')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.type')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.filledByLLM')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.description')}
</th>
<th className="text-eerie-black dark:text-bright-gray px-2 py-1 text-left text-sm font-normal">
<th className="text-foreground dark:text-foreground px-2 py-1 text-left text-sm font-normal">
{t('settings.tools.value')}
</th>
<th

View File

@@ -7,9 +7,9 @@ import userService from '../api/services/userService';
import Edit from '../assets/edit.svg';
import NoFilesDarkIcon from '../assets/no-files-dark.svg';
import NoFilesIcon from '../assets/no-files.svg';
import SearchIcon from '../assets/search.svg';
import ThreeDotsIcon from '../assets/three-dots.svg';
import ContextMenu, { MenuOption } from '../components/ContextMenu';
import Input from '../components/Input';
import Spinner from '../components/Spinner';
import ToggleSwitch from '../components/ToggleSwitch';
import { useDarkTheme } from '../hooks';
@@ -210,9 +210,17 @@ export default function Tools() {
) : (
<div className="mt-8">
<div className="relative flex flex-col">
<p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.tools.subtitle')}
</p>
<div className="my-3 flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="w-full sm:w-auto">
<Input
<div className="relative w-full max-w-md">
<img
src={SearchIcon}
alt=""
className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40"
/>
<input
maxLength={256}
placeholder={t('settings.tools.searchPlaceholder')}
name="Document-search-input"
@@ -220,11 +228,11 @@ export default function Tools() {
id="tool-search-input"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
borderVariant="thin"
className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/>
</div>
<button
className="bg-purple-30 hover:bg-violets-are-blue flex h-8 min-w-[108px] items-center justify-center rounded-full px-4 text-sm whitespace-normal text-white"
className="bg-primary hover:bg-primary/90 flex h-11 min-w-[108px] items-center justify-center rounded-full px-4 text-sm whitespace-normal text-white"
onClick={() => {
setAddToolModalState('ACTIVE');
}}
@@ -232,7 +240,7 @@ export default function Tools() {
{t('settings.tools.addTool')}
</button>
</div>
<div className="border-light-silver dark:border-dim-gray mt-5 mb-8 border-b" />
<div className="border-border dark:border-border mt-5 mb-8 border-b" />
{loading ? (
<div className="grid grid-cols-2 gap-6 lg:grid-cols-3">
<div className="col-span-2 mt-24 flex h-32 items-center justify-center lg:col-span-3">
@@ -253,101 +261,117 @@ export default function Tools() {
</p>
</div>
) : (
userTools
.filter((tool) =>
(() => {
const filtered = userTools.filter((tool) =>
(tool.customName || tool.displayName)
.toLowerCase()
.includes(searchTerm.toLowerCase()),
)
.map((tool, index) => (
<div
key={index}
className="relative flex h-52 w-[300px] flex-col justify-between overflow-hidden rounded-2xl bg-[#F5F5F5] p-6 hover:bg-[#ECECEC] dark:bg-[#383838] dark:hover:bg-[#303030]"
>
<div
ref={menuRefs.current[tool.id]}
onClick={(e) => {
e.stopPropagation();
setActiveMenuId(
activeMenuId === tool.id ? null : tool.id,
);
}}
className="absolute top-4 right-4 z-10 cursor-pointer"
>
<img
src={ThreeDotsIcon}
alt={t('settings.tools.settingsIconAlt')}
className="h-[19px] w-[19px]"
/>
<ContextMenu
isOpen={activeMenuId === tool.id}
setIsOpen={(isOpen) => {
setActiveMenuId(isOpen ? tool.id : null);
}}
options={getMenuOptions(tool)}
anchorRef={menuRefs.current[tool.id]}
position="bottom-right"
offset={{ x: 0, y: 0 }}
/>
</div>
<div className="w-full">
<div className="flex w-full items-center gap-2 px-1">
<img
src={`/toolIcons/tool_${tool.name}.svg`}
alt={`${tool.displayName} icon`}
className="h-6 w-6"
/>
{tool.name === 'mcp_tool' &&
mcpStatuses[tool.id] && (
<span
className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium leading-none ${
mcpStatuses[tool.id] === 'connected'
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
: mcpStatuses[tool.id] === 'needs_auth'
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300'
: 'bg-gray-100 text-gray-600 dark:bg-gray-700/40 dark:text-gray-300'
}`}
>
{mcpStatuses[tool.id] === 'connected'
? t('settings.tools.authStatus.connected')
: mcpStatuses[tool.id] === 'needs_auth'
? t('settings.tools.authStatus.needsAuth')
: t(
'settings.tools.authStatus.configured',
)}
</span>
)}
</div>
<div className="mt-[9px]">
<p
title={tool.customName || tool.displayName}
className="text-raisin-black-light dark:text-bright-gray truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{tool.customName || tool.displayName}
</p>
<p
className="text-old-silver dark:text-sonic-silver-light mt-1 line-clamp-4 max-h-24 overflow-hidden px-1 text-[12px] leading-relaxed break-all"
title={tool.description}
>
{tool.description}
</p>
</div>
</div>
<div className="absolute right-4 bottom-4">
<ToggleSwitch
checked={tool.status}
onChange={(checked) =>
updateToolStatus(tool.id, checked)
}
size="small"
id={`toolToggle-${index}`}
ariaLabel={t('settings.tools.toggleToolAria', {
toolName: tool.customName || tool.displayName,
})}
/>
</div>
);
return filtered.length === 0 ? (
<div className="flex w-full flex-col items-center justify-center py-12">
<img
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
alt={t('settings.tools.noToolsFound')}
className="mx-auto mb-6 h-32 w-32"
/>
<p className="text-center text-lg text-gray-500 dark:text-gray-400">
{t('settings.tools.noToolsFound')}
</p>
</div>
))
) : (
filtered.map((tool, index) => (
<div
key={index}
className="bg-muted hover:bg-accent relative flex h-52 w-[300px] flex-col justify-between overflow-hidden rounded-2xl p-6"
>
<div
ref={menuRefs.current[tool.id]}
onClick={(e) => {
e.stopPropagation();
setActiveMenuId(
activeMenuId === tool.id ? null : tool.id,
);
}}
className="absolute top-4 right-4 z-10 cursor-pointer"
>
<img
src={ThreeDotsIcon}
alt={t('settings.tools.settingsIconAlt')}
className="h-[19px] w-[19px]"
/>
<ContextMenu
isOpen={activeMenuId === tool.id}
setIsOpen={(isOpen) => {
setActiveMenuId(isOpen ? tool.id : null);
}}
options={getMenuOptions(tool)}
anchorRef={menuRefs.current[tool.id]}
position="bottom-right"
offset={{ x: 0, y: 0 }}
/>
</div>
<div className="w-full">
<div className="flex w-full items-center gap-2 px-1">
<img
src={`/toolIcons/tool_${tool.name}.svg`}
alt={`${tool.displayName} icon`}
className="h-6 w-6"
/>
{tool.name === 'mcp_tool' &&
mcpStatuses[tool.id] && (
<span
className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] leading-none font-medium ${
mcpStatuses[tool.id] === 'connected'
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
: mcpStatuses[tool.id] === 'needs_auth'
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300'
: 'bg-gray-100 text-gray-600 dark:bg-gray-700/40 dark:text-gray-300'
}`}
>
{mcpStatuses[tool.id] === 'connected'
? t('settings.tools.authStatus.connected')
: mcpStatuses[tool.id] === 'needs_auth'
? t(
'settings.tools.authStatus.needsAuth',
)
: t(
'settings.tools.authStatus.configured',
)}
</span>
)}
</div>
<div className="mt-[9px]">
<p
title={tool.customName || tool.displayName}
className="text-foreground dark:text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{tool.customName || tool.displayName}
</p>
<p
className="text-muted-foreground mt-1 line-clamp-4 max-h-24 overflow-hidden px-1 text-[12px] leading-relaxed break-all"
title={tool.description}
>
{tool.description}
</p>
</div>
</div>
<div className="absolute right-4 bottom-4">
<ToggleSwitch
checked={tool.status}
onChange={(checked) =>
updateToolStatus(tool.id, checked)
}
size="small"
id={`toolToggle-${index}`}
ariaLabel={t('settings.tools.toggleToolAria', {
toolName: tool.customName || tool.displayName,
})}
/>
</div>
</div>
))
);
})()
)}
</div>
)}

View File

@@ -92,7 +92,7 @@ export default function Settings() {
return (
<div className="h-full overflow-auto p-4 md:p-12">
<p className="text-eerie-black dark:text-bright-gray text-2xl font-bold">
<p className="text-foreground dark:text-foreground text-2xl font-bold">
{t('settings.label')}
</p>
<SettingsBar

View File

@@ -78,4 +78,4 @@ export default store;
// TODO : use https://redux-toolkit.js.org/tutorials/typescript#define-typed-hooks everywere instead of direct useDispatch
// TODO : streamline async state management
// TODO : streamline async state management

Some files were not shown because too many files have changed in this diff Show More