Studio: unify shadows, backgrounds and dark mode consistency in chat UI (#6116)
* Studio: refine chat UI shadow, background and sidebar divider - Give both chat composers a Gemini style drop shadow with a short transition, and add a visible shadow in dark mode. - Set the main chat surface to a soft off white (#fbfbfc) in light mode so the white composer reads as a card; dark mode is unchanged. - Remove the divider line between the side menu and the page. * Studio: lighten chat background to #fcfcfd * Studio: make dark mode composer shadow visible * Studio: drop composer shadow in dark mode * Studio: unify all light mode shadows on the chatbox shadow * Studio: unify dark mode surface colors and make hover states visible * Studio: fix barely visible dark mode hover in account and plus menus * Studio: lift settings dialog off the page background in dark mode * Studio: drop greeting periods and restyle projects page to match the chatbox * Studio: chatbox shadow on search dialog, grey sort pill on projects * Studio: slimmer sidebar profile row, borderless login card * Studio: match select popups to their trigger, taller profile hover target * Studio: bigger projects search pill with the original chatbox glow * Studio: keep select trigger shape while open * Studio: center and narrow the projects search pill like Gemini * Studio: borderless export card with the chatbox shadow * Studio: chatbox shadow for selectable pills, warmer composer, search pill tweaks * Studio: one warm background token for every page, softer search glow * Studio: keep off white depth when warming the page background * Studio: distinct sidebar surface from the page background * Studio: white sidebar on the warm page background * Studio: soften projects search shadow * Studio: nudge the chat zero state up 5px * Studio: darker dark mode page background, 28.5vh welcome offset * Studio: dark mode shadows match the chatbox geometry, borderless recipes empty state * Studio: revert dark mode shadows, desaturate dark recipe cards * Studio: lift dark recipe cards, no hover shadow in dark * Studio: drop the pale hover halo on recipe cards * Studio: lighter dark recipe text, flat dark menus, flush select popups * Studio: page-bg shadow on model selector, flush popovers and dropdowns * Studio: zero menu offsets so dropdowns sit flush against triggers * Studio: one 14px radius for list menus and sidebar buttons * Studio: 14px buttons, pill hover shapes, narrower slider inputs * Studio: pill buttons, keep profile row rectangular * Studio: pill Save and Delete, small gap under account menu * Studio: skinnier dropdown popups, larger account menu gap * Studio: dropdown popups slightly wider than their trigger * Restore light mode sidebar separator line * Size panel number input pills to their content * Lighten light mode page background * Pure white composer, nudge page background whiter * Use inline ch width for panel number pills * Fix panel number pills at uniform 4ch width --------- Co-authored-by: Daniel Han <danielhanchen@gmail.com>
This commit is contained in:
parent
f41617ad9f
commit
f542ffb023
29 changed files with 181 additions and 140 deletions
|
|
@ -223,7 +223,7 @@ function NavItem({
|
|||
onClick={onClick}
|
||||
isActive={active}
|
||||
data-tour={dataTour}
|
||||
className="sidebar-nav-btn h-[33px] rounded-[11px] gap-[8.5px] px-2.5 font-medium group-data-[collapsible=icon]:!w-[32px] group-data-[collapsible=icon]:!rounded-[10px] group-data-[collapsible=icon]:mx-auto"
|
||||
className="sidebar-nav-btn h-[33px] rounded-full gap-[8.5px] px-2.5 font-medium group-data-[collapsible=icon]:!w-[32px] group-data-[collapsible=icon]:!rounded-full group-data-[collapsible=icon]:mx-auto"
|
||||
>
|
||||
<HugeiconsIcon icon={icon} strokeWidth={1.75} className="size-icon! shrink-0 group-hover/menu-button:animate-icon-pop" />
|
||||
<span className="text-[14.5px] leading-[19px] tracking-nav">{label}</span>
|
||||
|
|
@ -597,7 +597,7 @@ export function AppSidebar() {
|
|||
? "sidebar-row-action group-hover/project-chat-item:opacity-100 group-hover/project-chat-item:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto"
|
||||
: "sidebar-row-action group-hover/recent-item:opacity-100 group-hover/recent-item:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto";
|
||||
const buttonClass = cn(
|
||||
"sidebar-nav-btn h-[33px] cursor-pointer rounded-[11px] pr-4 text-[14.5px] leading-[19px] tracking-nav font-medium",
|
||||
"sidebar-nav-btn h-[33px] cursor-pointer rounded-full pr-4 text-[14.5px] leading-[19px] tracking-nav font-medium",
|
||||
variant === "project" ? "pl-[37px]" : "pl-2.5",
|
||||
variant === "project"
|
||||
? "group-hover/project-chat-item:pr-8 group-has-[.sidebar-row-action[data-state=open]]/project-chat-item:pr-8"
|
||||
|
|
@ -647,7 +647,7 @@ export function AppSidebar() {
|
|||
<DropdownMenuContent
|
||||
side="bottom"
|
||||
align="start"
|
||||
sideOffset={6}
|
||||
sideOffset={0}
|
||||
className="unsloth-plus-menu menu-flat-destructive w-52"
|
||||
>
|
||||
<DropdownMenuItem onSelect={() => openRenameChat(item)}>
|
||||
|
|
@ -660,7 +660,7 @@ export function AppSidebar() {
|
|||
<span>Move to project</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent
|
||||
sideOffset={8}
|
||||
sideOffset={0}
|
||||
alignOffset={-4}
|
||||
className="unsloth-plus-menu w-52"
|
||||
>
|
||||
|
|
@ -827,7 +827,7 @@ export function AppSidebar() {
|
|||
)}
|
||||
</SidebarHeader>
|
||||
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-2 pt-[9px] pb-px shrink-0">
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-1.5 pt-[9px] pb-px shrink-0">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
|
|
@ -867,7 +867,7 @@ export function AppSidebar() {
|
|||
scrolled && "is-scrolled",
|
||||
)}
|
||||
>
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-2 py-0 shrink-0">
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-1.5 py-0 shrink-0">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
|
|
@ -918,7 +918,7 @@ export function AppSidebar() {
|
|||
</CollapsibleTrigger>
|
||||
</SidebarGroupLabel>
|
||||
<CollapsibleContent>
|
||||
<SidebarGroupContent className="px-2">
|
||||
<SidebarGroupContent className="px-1.5">
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
icon={TestTubeOutlineIcon}
|
||||
|
|
@ -1025,7 +1025,7 @@ export function AppSidebar() {
|
|||
</div>
|
||||
</SidebarGroupLabel>
|
||||
<CollapsibleContent>
|
||||
<SidebarGroupContent className="px-2">
|
||||
<SidebarGroupContent className="px-1.5">
|
||||
<SidebarMenu>
|
||||
{recentChatItems.map((item) =>
|
||||
renderChatSidebarItem(item, "recent"),
|
||||
|
|
@ -1065,7 +1065,7 @@ export function AppSidebar() {
|
|||
>
|
||||
<SidebarMenuButton
|
||||
isActive={isActiveRun}
|
||||
className="sidebar-nav-btn h-auto flex-col items-start gap-0.5 py-[5px] rounded-[11px] pl-2.5 pr-7 text-[14.5px] tracking-nav font-medium"
|
||||
className="sidebar-nav-btn h-auto flex-col items-start gap-0.5 py-[5px] rounded-full pl-2.5 pr-7 text-[14.5px] tracking-nav font-medium"
|
||||
onClick={() => {
|
||||
setSelectedHistoryRunId(run.id);
|
||||
closeMobileIfOpen();
|
||||
|
|
@ -1106,8 +1106,8 @@ export function AppSidebar() {
|
|||
<DropdownMenuContent
|
||||
side="bottom"
|
||||
align="end"
|
||||
sideOffset={4}
|
||||
className="app-user-menu menu-soft-surface menu-flat-destructive ring-0 w-44 py-2 font-heading rounded-[14px] border-0"
|
||||
sideOffset={0}
|
||||
className="app-user-menu menu-soft-surface menu-flat-destructive ring-0 w-44 py-2 font-heading rounded-full border-0"
|
||||
>
|
||||
<DropdownMenuItem onSelect={() => openRenameRun(run)}>
|
||||
<HugeiconsIcon icon={Edit03Icon} strokeWidth={1.75} className="size-icon" />
|
||||
|
|
@ -1154,7 +1154,7 @@ export function AppSidebar() {
|
|||
<SidebarMenuButton
|
||||
size="lg"
|
||||
aria-label={t("shell.accountMenu", { name: displayTitle })}
|
||||
className="sidebar-nav-btn !h-[44px] gap-[9px] px-2 py-[3px] rounded-[14px]"
|
||||
className="sidebar-nav-btn !h-[44px] -my-[3px] gap-[9px] px-2 py-[3px] rounded-[14px]"
|
||||
>
|
||||
<div className="flex shrink-0 items-center">
|
||||
<UserAvatar
|
||||
|
|
@ -1174,7 +1174,7 @@ export function AppSidebar() {
|
|||
<DropdownMenuContent
|
||||
side="top"
|
||||
align="center"
|
||||
sideOffset={6}
|
||||
sideOffset={8}
|
||||
className="app-user-menu menu-soft-surface-up ring-0 w-[16rem] px-1.5 py-2.5 font-heading rounded-[20px] border-0"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
|
|
|
|||
|
|
@ -740,8 +740,8 @@ function buildWelcome(hour: number, name: string): Welcome {
|
|||
// Use the name on ~a third of lines (only direct salutations where it reads
|
||||
// naturally); the rest stay name-free so greetings don't feel repetitive.
|
||||
const base: Welcome[] = [
|
||||
g(name ? `Good to see you, ${name}.` : "Good to see you.", "large sloth wave.png"),
|
||||
g("Ready when you are.", "large sloth thumbs.png"),
|
||||
g(name ? `Good to see you, ${name}` : "Good to see you", "large sloth wave.png"),
|
||||
g("Ready when you are", "large sloth thumbs.png"),
|
||||
DEFAULT_WELCOME,
|
||||
g("How can I help?", "sloth sir large.png"),
|
||||
];
|
||||
|
|
@ -785,7 +785,7 @@ const ThreadWelcome: FC<{
|
|||
|
||||
return (
|
||||
<div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
|
||||
<div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-start pt-[28vh]">
|
||||
<div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-start pt-[28.5vh]">
|
||||
<div className="aui-thread-welcome-message flex w-full flex-col justify-center gap-9 px-4">
|
||||
{/* Center the greeting (sloth + title) over the composer. */}
|
||||
<div className="flex flex-row items-center justify-center gap-[15px]">
|
||||
|
|
@ -2131,7 +2131,7 @@ const ComposerToolsMenu: FC<{ side?: "top" | "bottom" }> = ({
|
|||
<DropdownMenuContent
|
||||
side={side}
|
||||
align="start"
|
||||
sideOffset={2}
|
||||
sideOffset={0}
|
||||
avoidCollisions={true}
|
||||
className="unsloth-plus-menu w-[212px]"
|
||||
// Don't refocus the + on close; restored focus showed a stray ring.
|
||||
|
|
@ -2655,7 +2655,7 @@ const AssistantActionBar: FC = () => {
|
|||
side="bottom"
|
||||
align="start"
|
||||
onCloseAutoFocus={(e) => e.preventDefault()}
|
||||
className="aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md [--radius:1.1rem] bg-popover p-1 text-popover-foreground shadow-[0_2px_8px_-2px_rgba(27,27,31,0.16)] dark:shadow-none"
|
||||
className="aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md [--radius:1.1rem] bg-popover p-1 text-popover-foreground shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:shadow-none"
|
||||
>
|
||||
<ActionBarPrimitive.ExportMarkdown asChild={true}>
|
||||
<ActionBarMorePrimitive.Item className="aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type * as React from "react";
|
|||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const buttonVariants = cva(
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none cursor-pointer",
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-full border border-transparent text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none cursor-pointer",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ function ComboboxInput({
|
|||
function ComboboxContent({
|
||||
className,
|
||||
side = "bottom",
|
||||
sideOffset = 6,
|
||||
sideOffset = 0,
|
||||
align = "start",
|
||||
alignOffset = 0,
|
||||
anchor,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ function DropdownMenuTrigger({
|
|||
function DropdownMenuContent({
|
||||
className,
|
||||
align = "start",
|
||||
sideOffset = 4,
|
||||
sideOffset = 0,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||
return (
|
||||
|
|
@ -46,7 +46,7 @@ function DropdownMenuContent({
|
|||
sideOffset={sideOffset}
|
||||
align={align}
|
||||
className={cn(
|
||||
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 bg-popover text-popover-foreground min-w-48 rounded-lg p-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden",
|
||||
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 bg-popover text-popover-foreground min-w-48 rounded-lg p-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-[calc(var(--radix-dropdown-menu-trigger-width)_+_6px)] data-[align=start]:-translate-x-[3px] data-[align=end]:translate-x-[3px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -78,7 +78,7 @@ function DropdownMenuItem({
|
|||
data-inset={inset}
|
||||
data-variant={variant}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-lg px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-full px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -96,7 +96,7 @@ function DropdownMenuCheckboxItem({
|
|||
<DropdownMenuPrimitive.CheckboxItem
|
||||
data-slot="dropdown-menu-checkbox-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-lg py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-full py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
|
|
@ -135,7 +135,7 @@ function DropdownMenuRadioItem({
|
|||
<DropdownMenuPrimitive.RadioItem
|
||||
data-slot="dropdown-menu-radio-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-lg py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-full py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -221,7 +221,7 @@ function DropdownMenuSubTrigger({
|
|||
data-slot="dropdown-menu-sub-trigger"
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-lg px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-full px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 flex cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ function MenubarContent({
|
|||
className,
|
||||
align = "start",
|
||||
alignOffset = -4,
|
||||
sideOffset = 8,
|
||||
sideOffset = 0,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Content>) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function PopoverTrigger({
|
|||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
sideOffset = 0,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ function SelectTrigger({
|
|||
children,
|
||||
icon,
|
||||
iconClassName,
|
||||
animateRadius = true,
|
||||
/* Off by default: the radius morph matched the old item-aligned popup
|
||||
that overlaid the trigger; popper menus drop below it instead. */
|
||||
animateRadius = false,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default";
|
||||
|
|
@ -111,7 +113,7 @@ function SelectTrigger({
|
|||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "item-aligned",
|
||||
position = "popper",
|
||||
align = "center",
|
||||
container,
|
||||
...props
|
||||
|
|
@ -125,9 +127,8 @@ function SelectContent({
|
|||
data-slot="select-content"
|
||||
data-align-trigger={position === "item-aligned"}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 min-w-36 rounded-xl p-1 corner-squircle duration-100 relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto ",
|
||||
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",
|
||||
"bg-popover text-popover-foreground font-heading data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 min-w-36 rounded-xl p-1 corner-squircle duration-100 relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto ",
|
||||
// No popper translate offset: the menu sits flush against the trigger.
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
|
|
@ -172,7 +173,7 @@ function SelectItem({
|
|||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl corner-squircle py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-full py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -305,9 +305,8 @@ function Sidebar({
|
|||
data-sidebar="sidebar"
|
||||
data-slot="sidebar-inner"
|
||||
className={cn(
|
||||
"bg-sidebar flex size-full flex-col overflow-hidden border-r border-sidebar-border",
|
||||
"bg-sidebar flex size-full flex-col overflow-hidden border-r border-sidebar-border dark:border-r-0",
|
||||
"group-data-[variant=floating]:ring-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1",
|
||||
hasPinMode && "ring-1 ring-sidebar-border/60",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function LoginPage() {
|
|||
length="70vh"
|
||||
style={{ opacity: 0.4 }}
|
||||
/>
|
||||
<Card className="relative z-10 w-full max-w-sm px-5 py-6 shadow-border ring-1 ring-border sm:px-6 sm:py-8">
|
||||
<Card className="relative z-10 w-full max-w-sm px-5 py-6 shadow-border ring-0 sm:px-6 sm:py-8">
|
||||
<AuthForm mode="login" />
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ function ProjectLanding({
|
|||
: { compare: item.id, project: projectId },
|
||||
});
|
||||
}}
|
||||
className="group flex min-h-[58px] w-full items-center gap-4 rounded-[10px] px-4 py-2 text-left transition-colors hover:bg-nav-surface-hover"
|
||||
className="group flex min-h-[58px] w-full items-center gap-4 rounded-full px-4 py-2 text-left transition-colors hover:bg-nav-surface-hover"
|
||||
>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-[15px] font-semibold leading-5 text-foreground">
|
||||
|
|
|
|||
|
|
@ -187,12 +187,16 @@ function NumericValueInput({
|
|||
}
|
||||
};
|
||||
|
||||
const displayed = focused ? draft : (displayValue ?? String(value));
|
||||
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
size={sizeAttr}
|
||||
value={focused ? draft : (displayValue ?? String(value))}
|
||||
/* Fixed 4ch pill; grows only when a longer value would clip. */
|
||||
style={{ width: `calc(${Math.max(displayed.length, 4)}ch + 18px)` }}
|
||||
value={displayed}
|
||||
aria-label={ariaLabel}
|
||||
onFocus={(e) => {
|
||||
cancelBlurCommitRef.current = false;
|
||||
|
|
@ -263,7 +267,7 @@ function ParamSlider({
|
|||
onChange={onChange}
|
||||
displayValue={displayValue}
|
||||
ariaLabel={label}
|
||||
size={valueSize ?? 6}
|
||||
size={valueSize ?? 4}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
|
|
@ -837,7 +841,7 @@ export function ChatSettingsPanel({
|
|||
animateRadius={false}
|
||||
icon={ArrowDown01Icon}
|
||||
iconClassName="size-3.5"
|
||||
className="grid h-7 w-[60px] min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.07] px-2 py-0 text-[13px]! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0"
|
||||
className="grid h-7 w-[60px] min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.1] px-2 py-0 text-[13px]! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0"
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
|
@ -877,7 +881,7 @@ export function ChatSettingsPanel({
|
|||
animateRadius={false}
|
||||
icon={ArrowDown01Icon}
|
||||
iconClassName="size-3.5"
|
||||
className="grid h-7 w-[120px] min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.07] px-2 py-0 text-[13px]! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0"
|
||||
className="grid h-7 w-[120px] min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.1] px-2 py-0 text-[13px]! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0"
|
||||
data-test-id="speculative-type-select"
|
||||
>
|
||||
<SelectValue />
|
||||
|
|
@ -928,7 +932,7 @@ export function ChatSettingsPanel({
|
|||
}}
|
||||
data-test-id="spec-draft-n-max-input"
|
||||
aria-label="Speculative decoding draft tokens"
|
||||
className="h-7 w-[72px] rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.07] px-2 py-0 text-[13px] font-medium text-nav-fg outline-none focus-visible:ring-0"
|
||||
className="h-7 w-[72px] rounded-[10px] border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.1] px-2 py-0 text-[13px] font-medium text-nav-fg outline-none focus-visible:ring-0"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -1058,7 +1062,7 @@ export function ChatSettingsPanel({
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="start"
|
||||
sideOffset={6}
|
||||
sideOffset={0}
|
||||
className="menu-soft-surface ring-0 border-0 rounded-lg p-1.5"
|
||||
>
|
||||
{presets.map((p, index) => (
|
||||
|
|
@ -1092,7 +1096,7 @@ export function ChatSettingsPanel({
|
|||
variant={presetSaveState.isSaveReady ? "default" : "outline"}
|
||||
size="sm"
|
||||
className={cn(
|
||||
"h-9 w-full rounded-[10px] text-[13px] font-medium tracking-nav",
|
||||
"h-9 w-full rounded-full text-[13px] font-medium tracking-nav",
|
||||
presetSaveState.isSaveReady &&
|
||||
"bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
)}
|
||||
|
|
@ -1107,7 +1111,7 @@ export function ChatSettingsPanel({
|
|||
disabled={!(settingsHydrated && activeCustomPreset)}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-9 w-full rounded-[10px] text-[13px] font-medium tracking-nav text-muted-foreground"
|
||||
className="h-9 w-full rounded-full text-[13px] font-medium tracking-nav text-muted-foreground"
|
||||
title={
|
||||
activeCustomPreset
|
||||
? activeBuiltinPreset
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export function ChatSearchDialog() {
|
|||
<CommandDialog
|
||||
open={isOpen}
|
||||
onOpenChange={setOpen}
|
||||
className="chat-search-surface corner-squircle top-[25%] w-[635px] max-w-[calc(100%-2rem)] gap-0 p-0 sm:max-w-[635px]"
|
||||
className="chat-search-surface corner-squircle top-[25%] w-[635px] max-w-[calc(100%-2rem)] gap-0 p-0 ring-0 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:shadow-none sm:max-w-[635px]"
|
||||
overlayClassName="bg-transparent"
|
||||
>
|
||||
<Command className="rounded-4xl p-0" filter={chatSearchFilter}>
|
||||
|
|
@ -117,7 +117,7 @@ export function ChatSearchDialog() {
|
|||
});
|
||||
close();
|
||||
}}
|
||||
className="relative flex cursor-pointer select-none items-center gap-3 rounded-lg px-3 py-2.5 text-sm outline-hidden data-selected:bg-muted data-selected:text-foreground"
|
||||
className="relative flex cursor-pointer select-none items-center gap-3 rounded-full px-3 py-2.5 text-sm outline-hidden data-selected:bg-muted data-selected:text-foreground"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={Message01Icon}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export function ProjectSwitcher({
|
|||
<DropdownMenuContent
|
||||
side="bottom"
|
||||
align="start"
|
||||
sideOffset={6}
|
||||
sideOffset={0}
|
||||
className="app-user-menu menu-soft-surface ring-0 min-w-56 max-w-72 max-h-72 py-2 font-heading rounded-[14px] border-0"
|
||||
>
|
||||
{showLoadingRow ? (
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ export function McpComposerButton({
|
|||
<DropdownMenuContent
|
||||
side={side}
|
||||
align="start"
|
||||
sideOffset={2}
|
||||
sideOffset={0}
|
||||
avoidCollisions={true}
|
||||
className="unsloth-plus-menu mcp-menu w-[232px]"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ export function ProjectsPage() {
|
|||
value={sortMode}
|
||||
onValueChange={(v) => setSortMode(v as SortMode)}
|
||||
>
|
||||
<SelectTrigger className="h-9 w-[130px]">
|
||||
<SelectTrigger className="h-9 w-[130px] rounded-full border-none bg-muted shadow-none dark:bg-card">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -324,15 +324,15 @@ export function ProjectsPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-6">
|
||||
<span className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
|
||||
<div className="relative mx-auto mt-10 w-full max-w-[720px]">
|
||||
<span className="pointer-events-none absolute left-5 top-1/2 -translate-y-1/2 text-muted-foreground">
|
||||
<HugeiconsIcon icon={Search01Icon} strokeWidth={1.75} className="size-icon" />
|
||||
</span>
|
||||
<Input
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Search projects..."
|
||||
className="h-11 pl-10"
|
||||
className="h-14 rounded-full border-none bg-background pl-13 pr-5 shadow-[0_0_20px_0_rgba(0,0,0,0.07)] dark:bg-card dark:shadow-none"
|
||||
aria-label="Search projects"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -342,7 +342,7 @@ export function ProjectsPage() {
|
|||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="min-h-[160px] rounded-[14px] border border-border/70 bg-card p-5"
|
||||
className="min-h-[160px] rounded-[14px] bg-card p-5 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:shadow-none"
|
||||
>
|
||||
<Skeleton className="h-5 w-2/3 rounded-[6px]" />
|
||||
<Skeleton className="mt-3 h-4 w-full rounded-[6px]" />
|
||||
|
|
@ -361,7 +361,7 @@ export function ProjectsPage() {
|
|||
{projects.length === 0 && (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mt-2"
|
||||
className="mt-2 border-none bg-background shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:bg-card dark:shadow-none"
|
||||
onClick={() => {
|
||||
setNameDraft("");
|
||||
setCreating(true);
|
||||
|
|
@ -402,7 +402,7 @@ export function ProjectsPage() {
|
|||
openProject(project.id);
|
||||
}
|
||||
}}
|
||||
className="group/project-card relative flex min-h-[160px] cursor-pointer flex-col rounded-[14px] border border-border/70 bg-card p-5 text-left transition-colors hover:border-border hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
className="group/project-card relative flex min-h-[160px] cursor-pointer flex-col rounded-[14px] bg-card p-5 text-left shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] transition-colors hover:bg-accent/40 dark:shadow-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<h2 className="truncate pr-2 text-[16px] font-semibold text-foreground">
|
||||
|
|
@ -422,7 +422,7 @@ export function ProjectsPage() {
|
|||
<DropdownMenuContent
|
||||
side="bottom"
|
||||
align="end"
|
||||
sideOffset={4}
|
||||
sideOffset={0}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
className="app-user-menu menu-soft-surface menu-flat-destructive ring-0 w-44 py-2 font-heading rounded-[14px] border-0"
|
||||
|
|
|
|||
|
|
@ -1270,7 +1270,7 @@ export function SharedComposer({
|
|||
<DropdownMenuContent
|
||||
side="top"
|
||||
align="start"
|
||||
sideOffset={2}
|
||||
sideOffset={0}
|
||||
avoidCollisions={true}
|
||||
className="unsloth-plus-menu w-[212px]"
|
||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Easy",
|
||||
learningBadges: ["Seed Dataset", "LLM Text", "Prompting"],
|
||||
surfaceClassName:
|
||||
"from-emerald-500/15 via-green-500/5 to-transparent dark:from-emerald-400/30 dark:via-green-400/14 dark:to-emerald-950/16",
|
||||
"from-emerald-500/15 via-green-500/5 to-transparent dark:from-emerald-400/20 dark:via-green-400/10 dark:to-emerald-950/16",
|
||||
shineColor: [
|
||||
"rgb(16 185 129 / 0.45)",
|
||||
"rgb(34 197 94 / 0.4)",
|
||||
|
|
@ -91,7 +91,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Easy",
|
||||
learningBadges: ["Unstructured", "LLM Text"],
|
||||
surfaceClassName:
|
||||
"from-violet-500/15 via-fuchsia-500/5 to-transparent dark:from-violet-400/30 dark:via-fuchsia-400/14 dark:to-violet-950/16",
|
||||
"from-violet-500/15 via-fuchsia-500/5 to-transparent dark:from-violet-400/20 dark:via-fuchsia-400/10 dark:to-violet-950/16",
|
||||
shineColor: [
|
||||
"rgb(139 92 246 / 0.45)",
|
||||
"rgb(217 70 239 / 0.4)",
|
||||
|
|
@ -107,7 +107,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Starter",
|
||||
learningBadges: ["Vision", "LLM Text", "Image Context"],
|
||||
surfaceClassName:
|
||||
"from-lime-500/15 via-emerald-500/5 to-transparent dark:from-lime-400/30 dark:via-emerald-400/14 dark:to-lime-950/16",
|
||||
"from-lime-500/15 via-emerald-500/5 to-transparent dark:from-lime-400/20 dark:via-emerald-400/10 dark:to-lime-950/16",
|
||||
shineColor: [
|
||||
"rgb(132 204 22 / 0.45)",
|
||||
"rgb(16 185 129 / 0.4)",
|
||||
|
|
@ -123,7 +123,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Intermediate",
|
||||
learningBadges: ["LLM Judge", "LLM Code", "Subcategory", "Category"],
|
||||
surfaceClassName:
|
||||
"from-amber-500/15 via-orange-500/5 to-transparent dark:from-amber-400/30 dark:via-orange-400/14 dark:to-amber-950/16",
|
||||
"from-amber-500/15 via-orange-500/5 to-transparent dark:from-amber-400/20 dark:via-orange-400/10 dark:to-amber-950/16",
|
||||
shineColor: [
|
||||
"rgb(245 158 11 / 0.45)",
|
||||
"rgb(249 115 22 / 0.4)",
|
||||
|
|
@ -139,7 +139,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Intermediate",
|
||||
learningBadges: ["LLM Code", "Prompting", "Drop Columns"],
|
||||
surfaceClassName:
|
||||
"from-blue-500/15 via-indigo-500/5 to-transparent dark:from-blue-400/30 dark:via-indigo-400/14 dark:to-blue-950/16",
|
||||
"from-blue-500/15 via-indigo-500/5 to-transparent dark:from-blue-400/20 dark:via-indigo-400/10 dark:to-blue-950/16",
|
||||
shineColor: [
|
||||
"rgb(59 130 246 / 0.45)",
|
||||
"rgb(99 102 241 / 0.4)",
|
||||
|
|
@ -155,7 +155,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Advanced",
|
||||
learningBadges: ["Structured LLM", "Expression", "Jinja"],
|
||||
surfaceClassName:
|
||||
"from-cyan-500/15 via-sky-500/5 to-transparent dark:from-cyan-400/30 dark:via-sky-400/14 dark:to-cyan-950/16",
|
||||
"from-cyan-500/15 via-sky-500/5 to-transparent dark:from-cyan-400/20 dark:via-sky-400/10 dark:to-cyan-950/16",
|
||||
shineColor: [
|
||||
"rgb(6 182 212 / 0.45)",
|
||||
"rgb(56 189 248 / 0.4)",
|
||||
|
|
@ -171,7 +171,7 @@ const TEMPLATE_CARDS: TemplateCard[] = [
|
|||
difficulty: "Intermediate",
|
||||
learningBadges: ["GitHub", "LLM Text", "Structured LLM"],
|
||||
surfaceClassName:
|
||||
"from-slate-500/15 via-zinc-500/5 to-transparent dark:from-slate-400/30 dark:via-zinc-400/14 dark:to-slate-950/16",
|
||||
"from-slate-500/15 via-zinc-500/5 to-transparent dark:from-slate-400/20 dark:via-zinc-400/10 dark:to-slate-950/16",
|
||||
shineColor: [
|
||||
"rgb(71 85 105 / 0.45)",
|
||||
"rgb(100 116 139 / 0.4)",
|
||||
|
|
@ -241,7 +241,7 @@ function LearningRecipeCards({
|
|||
type="button"
|
||||
disabled={isDisabled}
|
||||
onClick={() => onSelect(template)}
|
||||
className={`group shadow-border relative overflow-hidden rounded-2xl bg-gradient-to-br text-left transition-transform ${template.surfaceClassName} enabled:cursor-pointer enabled:hover:-translate-y-0.5 enabled:hover:shadow-md disabled:cursor-not-allowed disabled:opacity-70`}
|
||||
className={`group shadow-border relative overflow-hidden rounded-2xl bg-gradient-to-br dark:bg-white/[0.05] text-left transition-transform ${template.surfaceClassName} enabled:cursor-pointer enabled:hover:-translate-y-0.5 disabled:cursor-not-allowed disabled:opacity-70`}
|
||||
>
|
||||
<ShineBorder
|
||||
borderWidth={1.2}
|
||||
|
|
@ -267,7 +267,7 @@ function LearningRecipeCards({
|
|||
<p className="line-clamp-2 text-sm font-semibold leading-tight text-foreground">
|
||||
{template.title}
|
||||
</p>
|
||||
<p className="line-clamp-2 text-xs text-muted-foreground">
|
||||
<p className="line-clamp-2 text-xs text-muted-foreground dark:text-zinc-300">
|
||||
{template.description}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -280,7 +280,7 @@ function LearningRecipeCards({
|
|||
<Badge
|
||||
key={`${template.title}-${badge}`}
|
||||
variant="outline"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px]"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px] dark:text-zinc-300"
|
||||
>
|
||||
{badge}
|
||||
</Badge>
|
||||
|
|
@ -288,7 +288,7 @@ function LearningRecipeCards({
|
|||
{extraLearningBadgeCount > 0 ? (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px]"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px] dark:text-zinc-300"
|
||||
>
|
||||
+{extraLearningBadgeCount}
|
||||
</Badge>
|
||||
|
|
@ -296,7 +296,7 @@ function LearningRecipeCards({
|
|||
{isReady ? null : (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px]"
|
||||
className="h-5 shrink-0 px-1.5 text-[10px] dark:text-zinc-300"
|
||||
>
|
||||
Soon
|
||||
</Badge>
|
||||
|
|
@ -449,7 +449,7 @@ export function DataRecipesPage(): ReactElement {
|
|||
</p>
|
||||
</div>
|
||||
) : recipes.length === 0 ? (
|
||||
<Empty className="mt-8 border border-dashed border-border/70">
|
||||
<Empty className="mt-8 border border-dashed border-border/70 dark:border-none">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<HugeiconsIcon icon={CookBookIcon} className="size-5" />
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ export function ExportPage() {
|
|||
description="Select source, method, and quantization"
|
||||
accent="emerald"
|
||||
featured={true}
|
||||
className="shadow-border ring-1 ring-border"
|
||||
className="ring-0 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:shadow-none"
|
||||
>
|
||||
{/* Loading / error states */}
|
||||
{loadingCheckpoints && (
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export function NetworkErrorState({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={RefreshIcon}
|
||||
|
|
@ -113,7 +113,7 @@ export function DiscoverFetchMoreState({
|
|||
type="button"
|
||||
onClick={onFetchMore}
|
||||
disabled={isLoadingMore}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={RefreshIcon}
|
||||
|
|
@ -191,7 +191,7 @@ export function InventoryErrorState({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-[10px] bg-transparent px-3 text-[12px] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
<HugeiconsIcon icon={RefreshIcon} strokeWidth={1.75} className="size-3.5" />
|
||||
Try again
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ export function GgufDownloadCard({
|
|||
e.preventDefault();
|
||||
setOpen((o) => !o);
|
||||
}}
|
||||
className="hub-menu-trigger flex h-9 min-w-0 flex-1 cursor-pointer items-center gap-2.5 rounded-[12px] px-3 text-left transition-colors hover:bg-foreground/[0.04] data-[state=open]:bg-foreground/[0.06] dark:hover:bg-white/[0.04] dark:data-[state=open]:bg-white/[0.06]"
|
||||
className="hub-menu-trigger flex h-9 min-w-0 flex-1 cursor-pointer items-center gap-2.5 rounded-[12px] px-3 text-left transition-colors hover:bg-foreground/[0.04] data-[state=open]:bg-foreground/[0.06] dark:hover:bg-white/[0.1] dark:data-[state=open]:bg-white/[0.06]"
|
||||
>
|
||||
{selected ? (
|
||||
<QuantBadge
|
||||
|
|
@ -723,7 +723,7 @@ export function GgufDownloadCard({
|
|||
<PopoverContent
|
||||
align="start"
|
||||
side="bottom"
|
||||
sideOffset={8}
|
||||
sideOffset={0}
|
||||
avoidCollisions={false}
|
||||
className="hub-menu-instant menu-soft-surface w-[var(--radix-popover-trigger-width)] min-w-[200px] gap-0 overflow-hidden p-0 py-2 ring-0"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ export function HubOptionMenu<T extends string>({
|
|||
<PopoverContent
|
||||
align={align}
|
||||
side="bottom"
|
||||
sideOffset={8}
|
||||
sideOffset={0}
|
||||
collisionPadding={12}
|
||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||
className={cn(
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ export function LocalOnDeviceCard({
|
|||
<PopoverContent
|
||||
align="start"
|
||||
side="bottom"
|
||||
sideOffset={8}
|
||||
sideOffset={0}
|
||||
avoidCollisions={false}
|
||||
className="hub-menu-instant menu-soft-surface w-[var(--radix-popover-trigger-width)] min-w-[220px] gap-0 overflow-hidden p-0 py-2 ring-0"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ function DownloadRow({ jobKey }: { jobKey: string }) {
|
|||
}
|
||||
className={cn(
|
||||
"inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-[7px] text-muted-foreground transition-colors",
|
||||
"hover:bg-foreground/[0.06] hover:text-foreground disabled:cursor-default disabled:opacity-50 dark:hover:bg-white/[0.06]",
|
||||
"hover:bg-foreground/[0.06] hover:text-foreground disabled:cursor-default disabled:opacity-50 dark:hover:bg-white/[0.1]",
|
||||
)}
|
||||
>
|
||||
<HugeiconsIcon
|
||||
|
|
@ -234,7 +234,7 @@ export function DownloadManagerPanel() {
|
|||
type="button"
|
||||
aria-label="Collapse downloads"
|
||||
onClick={() => setCollapsed(true)}
|
||||
className="inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-[7px] text-muted-foreground transition-colors hover:bg-foreground/[0.06] hover:text-foreground dark:hover:bg-white/[0.06]"
|
||||
className="inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-[7px] text-muted-foreground transition-colors hover:bg-foreground/[0.06] hover:text-foreground dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={ArrowDown01Icon}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export function ProfilePersonalizationPanel() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="absolute right-0 bottom-0 -translate-x-[15.625%] -translate-y-[15.625%] flex size-8 items-center justify-center rounded-full border border-border bg-background text-foreground shadow-[0_2px_8px_-2px_rgba(27,27,31,0.16)] transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
||||
className="absolute right-0 bottom-0 -translate-x-[15.625%] -translate-y-[15.625%] flex size-8 items-center justify-center rounded-full border border-border bg-background text-foreground shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
||||
aria-label={t("settings.profile.changePicture")}
|
||||
>
|
||||
<HugeiconsIcon icon={Camera01Icon} className="size-3.5" strokeWidth={2} />
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ export function LocalRecipeModelSelector({
|
|||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="start"
|
||||
sideOffset={6}
|
||||
sideOffset={0}
|
||||
className="menu-soft-surface nodrag nowheel gap-0 overflow-hidden p-0"
|
||||
style={{
|
||||
width:
|
||||
|
|
|
|||
|
|
@ -155,18 +155,18 @@ export function SettingsDialog() {
|
|||
type="button"
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={cn(
|
||||
"relative flex h-[32px] items-center gap-2.5 rounded-[11px] pl-3 pr-2.5 text-[14.5px] leading-[19px] tracking-nav font-medium transition-colors",
|
||||
"relative flex h-[32px] items-center gap-2.5 rounded-full pl-3 pr-2.5 text-[14.5px] leading-[19px] tracking-nav font-medium transition-colors",
|
||||
"max-sm:shrink-0",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
||||
active
|
||||
? "text-black dark:text-white"
|
||||
: "text-[#383835] dark:text-[#c7c7c4] hover:bg-[#ececec] dark:hover:bg-[#2d2f33] hover:text-black dark:hover:text-white",
|
||||
: "text-[#383835] dark:text-[#c7c7c4] hover:bg-[#ececec] dark:hover:bg-[#3a3d43] hover:text-black dark:hover:text-white",
|
||||
)}
|
||||
>
|
||||
{active && (
|
||||
<motion.span
|
||||
layoutId="settings-active-pill"
|
||||
className="absolute inset-0 rounded-[11px] bg-[#ececec] dark:bg-[#2d2f33]"
|
||||
className="absolute inset-0 rounded-full bg-[#ececec] dark:bg-[#3a3d43]"
|
||||
transition={
|
||||
reduced
|
||||
? { duration: 0 }
|
||||
|
|
@ -202,7 +202,7 @@ export function SettingsDialog() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={closeDialog}
|
||||
className="absolute top-3 right-3 z-10 flex size-7 items-center justify-center rounded-full text-[#383835] dark:text-[#c7c7c4] transition-colors hover:bg-[#ececec] dark:hover:bg-[#2d2f33] hover:text-black dark:hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
className="absolute top-3 right-3 z-10 flex size-7 items-center justify-center rounded-full text-[#383835] dark:text-[#c7c7c4] transition-colors hover:bg-[#ececec] dark:hover:bg-[#3a3d43] hover:text-black dark:hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
aria-label={t("settings.dialog.closeAriaLabel")}
|
||||
>
|
||||
<HugeiconsIcon icon={Cancel01Icon} className="size-4" />
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ export function GuidedTour({
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
className="text-foreground/60 hover:text-foreground hover:bg-black/[0.05] dark:text-zinc-300/70 dark:hover:text-zinc-100 dark:hover:bg-white/[0.08]"
|
||||
className="text-foreground/60 hover:text-foreground hover:bg-black/[0.05] dark:text-zinc-300/70 dark:hover:text-zinc-100 dark:hover:bg-white/[0.1]"
|
||||
onClick={() => requestClose("skip")}
|
||||
aria-label="Skip tour"
|
||||
>
|
||||
|
|
@ -343,7 +343,7 @@ export function GuidedTour({
|
|||
<div className="mt-5 flex items-center justify-between gap-3">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-foreground/60 hover:text-foreground hover:bg-black/[0.05] dark:text-zinc-300/70 dark:hover:text-zinc-100 dark:hover:bg-white/[0.08]"
|
||||
className="text-foreground/60 hover:text-foreground hover:bg-black/[0.05] dark:text-zinc-300/70 dark:hover:text-zinc-100 dark:hover:bg-white/[0.1]"
|
||||
onClick={() => requestClose("skip")}
|
||||
>
|
||||
Skip
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@
|
|||
--ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
|
||||
--background: oklch(1 0 0);
|
||||
/* Slightly warm off white; every page (and the chat surface) shares it. */
|
||||
--background: #fefefd;
|
||||
--foreground: oklch(0.2686 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.1281 0.0179 169.2764);
|
||||
|
|
@ -137,9 +138,9 @@
|
|||
--chart-4: oklch(0.6926 0.1112 346.5775);
|
||||
--chart-5: oklch(0.7497 0.1003 85.0057);
|
||||
--radius: 1.1rem;
|
||||
/* Match the page background so the sidebar reads as one surface with the
|
||||
content; the faint --sidebar-border on its right edge is the separator. */
|
||||
--sidebar: oklch(1 0 0);
|
||||
/* White sidebar against the warm off-white page; the tone difference is
|
||||
the separator now that the right-edge divider is gone. */
|
||||
--sidebar: #ffffff;
|
||||
--sidebar-foreground: oklch(0.1281 0.0179 169.2764);
|
||||
--sidebar-primary: #17b88b;
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
|
|
@ -233,7 +234,8 @@
|
|||
/* Exact palette from apps/studio/index_chat.html mockup. Using hex so the
|
||||
rendered surface matches the mockup pixel-for-pixel — OKLCH conversion
|
||||
drifted ~3% darker and shifted the neutral hue. */
|
||||
--background: #1f2023;
|
||||
/* Slightly darker than --sidebar so the sidebar reads as its own surface. */
|
||||
--background: #1a1b1e;
|
||||
--foreground: #ececee;
|
||||
--card: #2d2e32;
|
||||
--card-foreground: #ececee;
|
||||
|
|
@ -245,7 +247,8 @@
|
|||
--secondary-foreground: #ececee;
|
||||
--muted: #2e3035;
|
||||
--muted-foreground: #999999;
|
||||
--accent: #2e3035;
|
||||
/* One step lighter than --popover so menu item hover reads clearly. */
|
||||
--accent: #3a3d43;
|
||||
--accent-foreground: #ececee;
|
||||
--destructive: oklch(0.6368 0.2078 25.3313);
|
||||
/* --border / --input one step lighter than --muted so outlines and form
|
||||
|
|
@ -259,14 +262,14 @@
|
|||
--chart-3: oklch(0.7554 0.1285 197.339);
|
||||
--chart-4: oklch(0.7503 0.1199 346.7805);
|
||||
--chart-5: oklch(0.799 0.1196 84.6633);
|
||||
/* Match the page background (dark); --sidebar-border is the right-edge separator. */
|
||||
/* A step lighter than --background; the tone difference is the separator. */
|
||||
--sidebar: #1f2023;
|
||||
--sidebar-foreground: #ececee;
|
||||
--sidebar-primary: #17b88b;
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: #2f2f31;
|
||||
--sidebar-accent: #2e3035;
|
||||
--sidebar-accent-foreground: #ececee;
|
||||
--sidebar-border: #2d2d2f;
|
||||
--sidebar-border: #2d2e32;
|
||||
--sidebar-ring: #17b88b;
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
/* Match light's radius so every rounded-* element is the same in both themes. */
|
||||
|
|
@ -293,7 +296,7 @@
|
|||
|
||||
--nav-fg: #c7c7c4;
|
||||
--nav-fg-muted: #96979b;
|
||||
--nav-surface-hover: #2e2e30;
|
||||
--nav-surface-hover: #2e3035;
|
||||
--nav-icon-idle: #5c5c5c;
|
||||
--nav-beta-border: #3a3c3f;
|
||||
--panel-surface-hover: #3a3c42;
|
||||
|
|
@ -305,7 +308,7 @@
|
|||
--panel-surface: var(--background);
|
||||
--panel-surface-fg: var(--foreground);
|
||||
--panel-input-surface: #2a2b2e;
|
||||
--panel-input-surface-hover: #2e3033;
|
||||
--panel-input-surface-hover: #34373c;
|
||||
/* Soft neutral gray for muted text and sliders. Pure-ish #ababab
|
||||
reads as quiet on the dark panel without going colored. */
|
||||
--panel-surface-fg-muted: #ababab;
|
||||
|
|
@ -618,7 +621,7 @@
|
|||
prompt button, and the chat-template textarea so all three read
|
||||
as one quiet gray family, matching the focused-edit-number tint. */
|
||||
.panel-input-group {
|
||||
@apply !h-9 min-h-9 min-w-0 items-stretch gap-0 rounded-[10px] pr-0 transition-colors focus-within:ring-0 focus-within:shadow-none;
|
||||
@apply !h-9 min-h-9 min-w-0 items-stretch gap-0 rounded-[14px] pr-0 transition-colors focus-within:ring-0 focus-within:shadow-none;
|
||||
border: 0 !important;
|
||||
background-color: var(--panel-input-surface);
|
||||
}
|
||||
|
|
@ -714,13 +717,12 @@
|
|||
/* Inline numeric input — used for slider values and Context Length.
|
||||
Designed to read as *editable text* rather than a pill button so
|
||||
it doesn't mirror the Select/dropdown components on the panel.
|
||||
Default: transparent box, no border, no ring, sized by the
|
||||
`size` HTML attribute (each consumer picks 6 / 8 / etc. chars).
|
||||
Hover/focus: very light bg fade-in to signal editability — just
|
||||
enough to read as interactive, not enough to compete with the
|
||||
slider row's quiet aesthetic. */
|
||||
Default: transparent box, no border, no ring; the component sets
|
||||
an inline width that hugs the value. Hover/focus: very light bg
|
||||
fade-in, just enough to read as interactive without competing
|
||||
with the slider row's quiet aesthetic. */
|
||||
.panel-number-input {
|
||||
@apply h-7 rounded-md border-0 bg-transparent px-1.5 text-right text-[13px]! font-medium tabular-nums text-nav-fg shadow-none transition-colors hover:bg-black/[0.04] focus:bg-black/[0.05] focus-visible:ring-0! focus-visible:outline-none md:text-[13px]!;
|
||||
@apply h-7 min-w-8 shrink-0 rounded-full border-0 bg-transparent px-2 text-right text-[13px]! font-medium tabular-nums text-nav-fg shadow-none transition-colors hover:bg-black/[0.04] focus:bg-black/[0.05] focus-visible:ring-0! focus-visible:outline-none md:text-[13px]!;
|
||||
}
|
||||
.dark .panel-number-input {
|
||||
@apply hover:bg-white/[0.04] focus:bg-white/[0.06];
|
||||
|
|
@ -779,7 +781,7 @@
|
|||
height: 36px;
|
||||
padding: 0 0.75rem !important;
|
||||
gap: 9.5px !important;
|
||||
border-radius: 12px;
|
||||
border-radius: 9999px;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
|
|
@ -805,6 +807,9 @@
|
|||
.dark .app-user-menu [data-slot="dropdown-menu-item"]:focus,
|
||||
.dark .app-user-menu [data-slot="dropdown-menu-sub-trigger"]:focus,
|
||||
.dark .app-user-menu [data-slot="dropdown-menu-sub-trigger"][data-state="open"] {
|
||||
/* --nav-surface-hover is tuned for the page bg; on the lighter menu
|
||||
surface it is invisible, so use the menu hover token instead. */
|
||||
background-color: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
.app-user-menu [data-slot="dropdown-menu-item"]:focus *,
|
||||
|
|
@ -837,14 +842,15 @@
|
|||
|
||||
/* Elevated surface shadow (use ring-* for borders) */
|
||||
.shadow-border {
|
||||
--tw-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 4px 16px var(--tw-shadow-color);
|
||||
/* Chatbox shadow; dark mode drops it. */
|
||||
--tw-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
--tw-shadow-colored: 0 2px 8px -2px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.dark .shadow-border {
|
||||
--tw-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Settings dialog: no shadow in dark mode. */
|
||||
|
|
@ -852,6 +858,12 @@
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Lift the dialog off the page bg; halfway to --card keeps the inner
|
||||
bg-muted / bg-background fills readable. */
|
||||
.dark .settings-surface {
|
||||
background-color: color-mix(in srgb, var(--background) 50%, var(--card));
|
||||
}
|
||||
|
||||
/* App-wide: every clickable control shows the hand cursor. Disabled ones
|
||||
(native :disabled, aria-disabled, Radix data-disabled) keep the default. */
|
||||
button:not(:disabled):not([aria-disabled="true"]),
|
||||
|
|
@ -893,7 +905,7 @@
|
|||
both themes; rounded-4xl here and on the inner Command follow this. */
|
||||
--radius: 0.625rem;
|
||||
/* Match the chat box: soft elevation in light, none in dark. */
|
||||
box-shadow: 0 2px 8px -2px rgba(27, 27, 31, 0.16);
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.dark .chat-search-surface {
|
||||
|
|
@ -902,25 +914,29 @@
|
|||
|
||||
.menu-soft-surface,
|
||||
.menu-soft-surface-up {
|
||||
/* Light: chatbox shadow geometry. */
|
||||
--menu-soft-edge: rgba(0, 0, 0, 0.14);
|
||||
--menu-soft-shadow: rgba(0, 0, 0, 0.18);
|
||||
--menu-soft-offset-y: 8px;
|
||||
--menu-soft-blur: 28px;
|
||||
--menu-soft-spread: -6px;
|
||||
--menu-soft-shadow: rgba(0, 0, 0, 0.16);
|
||||
--menu-soft-offset-y: 2px;
|
||||
--menu-soft-blur: 8px;
|
||||
--menu-soft-spread: -2px;
|
||||
@apply bg-popover text-popover-foreground;
|
||||
box-shadow:
|
||||
inset 0 0 0 1px var(--menu-soft-edge),
|
||||
0 var(--menu-soft-offset-y) var(--menu-soft-blur)
|
||||
var(--menu-soft-spread) var(--menu-soft-shadow);
|
||||
}
|
||||
.menu-soft-surface-up {
|
||||
--menu-soft-offset-y: -6px;
|
||||
--menu-soft-spread: -8px;
|
||||
}
|
||||
.dark .menu-soft-surface,
|
||||
.dark .menu-soft-surface-up {
|
||||
--menu-soft-edge: rgba(255, 255, 255, 0.07);
|
||||
--menu-soft-shadow: rgba(0, 0, 0, 0.28);
|
||||
--menu-soft-offset-y: 8px;
|
||||
--menu-soft-blur: 28px;
|
||||
--menu-soft-spread: -6px;
|
||||
}
|
||||
.dark .menu-soft-surface-up {
|
||||
--menu-soft-offset-y: -6px;
|
||||
--menu-soft-spread: -8px;
|
||||
}
|
||||
|
||||
/* Model selector: drop the inset edge ring, keep the soft drop shadow.
|
||||
|
|
@ -935,6 +951,15 @@
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* List menus: one radius in both themes, slightly tighter than --radius-lg
|
||||
and matching the sidebar buttons. !important beats per-menu rounded-*. */
|
||||
[data-slot="dropdown-menu-content"],
|
||||
[data-slot="dropdown-menu-sub-content"],
|
||||
[data-slot="select-content"],
|
||||
[data-slot="combobox-content"] {
|
||||
border-radius: 14px !important;
|
||||
}
|
||||
|
||||
/* Every dropdown/menu/select/popover: borderless, chatbox shadow in light,
|
||||
none in dark. !important so it also overrides the bespoke menu shadows. */
|
||||
[data-slot="dropdown-menu-content"],
|
||||
|
|
@ -942,7 +967,7 @@
|
|||
[data-slot="select-content"],
|
||||
[data-slot="combobox-content"],
|
||||
[data-slot="popover-content"] {
|
||||
box-shadow: 0 2px 8px -2px rgba(27, 27, 31, 0.16) !important;
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16) !important;
|
||||
}
|
||||
/* Dark: keep the chat-box dropdown shadow so menus don't merge into a
|
||||
same-color surface (e.g. a menu overlapping the composer). */
|
||||
|
|
@ -954,6 +979,15 @@
|
|||
box-shadow: 0 4px 14px var(--background) !important;
|
||||
}
|
||||
|
||||
/* Model selector: shadow in the page-bg color so it lifts off the
|
||||
composer it overlaps (chatbox geometry). Account menu stays flat. */
|
||||
.dark .unsloth-model-selector-menu {
|
||||
box-shadow: 0 2px 8px -2px var(--background) !important;
|
||||
}
|
||||
.dark .app-user-menu.menu-soft-surface-up {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* Context menus (chat, run, project): drop the inset edge ring, keep the soft shadow. */
|
||||
.app-user-menu.menu-soft-surface {
|
||||
box-shadow: 0 var(--menu-soft-offset-y) var(--menu-soft-blur)
|
||||
|
|
@ -962,7 +996,7 @@
|
|||
|
||||
/* Account menu: drop the inset edge ring and use the composer's soft shadow. */
|
||||
.app-user-menu.menu-soft-surface-up {
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.09);
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
.dark .app-user-menu.menu-soft-surface-up {
|
||||
box-shadow: 0 8px 28px -6px rgba(0, 0, 0, 0.28);
|
||||
|
|
@ -972,16 +1006,19 @@
|
|||
@apply relative flex w-full flex-col rounded-[32px] bg-background dark:bg-card px-1 pt-2 outline-none transition-shadow;
|
||||
font-family: var(--font-sans);
|
||||
background-clip: padding-box;
|
||||
box-shadow: 0 2px 8px -2px rgba(27, 27, 31, 0.16);
|
||||
background-color: #ffffff;
|
||||
/* Gemini-style composer shadow. */
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
transition: box-shadow 0.1s;
|
||||
}
|
||||
|
||||
.dark .chat-composer-surface {
|
||||
background-color: #2a2a2c;
|
||||
background-color: var(--card);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.composer-pill-btn {
|
||||
@apply flex cursor-pointer items-center gap-1.5 rounded-full py-1.5 pl-2 pr-2.5 text-[14px] font-medium text-muted-foreground/70 transition-colors hover:bg-primary/10 dark:hover:bg-white/[0.08] disabled:cursor-not-allowed disabled:opacity-40;
|
||||
@apply flex cursor-pointer items-center gap-1.5 rounded-full py-1.5 pl-2 pr-2.5 text-[14px] font-medium text-muted-foreground/70 transition-colors hover:bg-primary/10 dark:hover:bg-white/[0.1] disabled:cursor-not-allowed disabled:opacity-40;
|
||||
}
|
||||
|
||||
/* Icon-only (compact) pills drop their label, so make the button a square
|
||||
|
|
@ -1058,16 +1095,18 @@
|
|||
@apply relative flex w-full flex-col rounded-[32px] bg-background dark:bg-card px-3 py-3 outline-none transition-shadow;
|
||||
font-family: var(--font-sans);
|
||||
background-clip: padding-box;
|
||||
/* Gemini search pill: soft, centered shadow, no downward offset. */
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.09);
|
||||
background-color: #ffffff;
|
||||
/* Gemini-style composer shadow. */
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
transition: box-shadow 0.1s;
|
||||
}
|
||||
|
||||
.unsloth-composer-surface:focus-within {
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.09);
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.dark .unsloth-composer-surface {
|
||||
background-color: #2a2a2c;
|
||||
background-color: var(--card);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
|
@ -1177,7 +1216,7 @@
|
|||
/* Right-side Thinking pill (toggle or dropdown). pl-2 matches the left
|
||||
pills so the hover X is not pushed in too far. */
|
||||
.unsloth-thinking-pill {
|
||||
@apply inline-flex shrink-0 cursor-pointer items-center gap-1 rounded-full py-1.5 pl-2 pr-2.5 text-[14px] font-medium text-muted-foreground transition-colors hover:bg-primary/10 dark:hover:bg-white/[0.08] disabled:cursor-not-allowed disabled:opacity-40;
|
||||
@apply inline-flex shrink-0 cursor-pointer items-center gap-1 rounded-full py-1.5 pl-2 pr-2.5 text-[14px] font-medium text-muted-foreground transition-colors hover:bg-primary/10 dark:hover:bg-white/[0.1] disabled:cursor-not-allowed disabled:opacity-40;
|
||||
/* Reserve a text line so the icon-only (inactive) pill matches the
|
||||
text pills' height instead of collapsing to the icon. */
|
||||
min-height: calc(1lh + 0.75rem);
|
||||
|
|
@ -1206,9 +1245,7 @@
|
|||
border-radius: 18px;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
box-shadow:
|
||||
0 1px 2px oklch(0 0 0 / 0.04),
|
||||
0 6px 18px oklch(0 0 0 / 0.08);
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
/* MCP menu is wider (232px), so nudge the radius up so it reads as round as
|
||||
|
|
@ -1218,7 +1255,7 @@
|
|||
}
|
||||
|
||||
.dark .unsloth-plus-menu[data-slot] {
|
||||
background-color: #2a2a2c;
|
||||
background-color: var(--card);
|
||||
/* Shadow tinted to the page bg so it blends, not a dark halo. */
|
||||
box-shadow: 0 4px 14px var(--background);
|
||||
}
|
||||
|
|
@ -1257,7 +1294,7 @@
|
|||
[data-slot="dropdown-menu-item"],
|
||||
[data-slot="dropdown-menu-sub-trigger"]
|
||||
):is(:hover, :focus, :focus-visible, [data-highlighted], [data-state="open"]) {
|
||||
background-color: rgba(255, 255, 255, 0.08) !important;
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Hover tints only the background; the item and every descendant (text, icons,
|
||||
|
|
@ -1302,7 +1339,7 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
.artifact-panel-shell {
|
||||
box-shadow: 0 2px 8px -2px rgba(27, 27, 31, 0.16);
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.dark .artifact-panel-shell {
|
||||
|
|
@ -1634,7 +1671,7 @@
|
|||
!important because Sonner injects its base rules at runtime. */
|
||||
[data-sonner-toast][data-styled='true'] {
|
||||
padding: 12px 18px !important;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08) !important;
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16) !important;
|
||||
}
|
||||
|
||||
[data-sonner-toast][data-styled='true']:has([data-close-button]):not(:has([data-cancel])) {
|
||||
|
|
@ -1671,7 +1708,7 @@
|
|||
|
||||
/* Boost shadow on dark surfaces; mirrors .shadow-border / .menu-soft-surface pattern. */
|
||||
.dark [data-sonner-toast][data-styled='true'] {
|
||||
background-color: #2a2a2c !important;
|
||||
background-color: var(--card) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
|
|
@ -1923,7 +1960,7 @@
|
|||
|
||||
/* Keep the (borderless) close button blended with the dark toast surface. */
|
||||
.dark [data-sonner-toast][data-styled="true"] [data-close-button] {
|
||||
background: #2a2a2c !important;
|
||||
background: var(--card) !important;
|
||||
}
|
||||
|
||||
[data-sonner-toast][data-styled="true"] [data-close-button] svg {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue