Studio: clearer check mark and even plus-menu hover padding (#6253)
* Studio: use a clearer check mark for the app-wide tick Route every check mark through a shared tick-icon module with a plain tick geometry, sized slightly larger than the stock icon so it reads clearly in menus. No Pro icon assets are vendored. * Studio: even out plus-menu hover padding on all sides Trim the plus-menu side gutter to 9px so it matches the 0.5rem top/bottom padding, and drop the container radius to 21px to keep corners concentric. * Studio: bake the tick fallback stroke at 1.5 to match the icon set --------- Co-authored-by: shimmyshimmer <info@unsloth.ai>
This commit is contained in:
parent
99704ffe47
commit
587e59ca83
23 changed files with 60 additions and 28 deletions
|
|
@ -8,7 +8,8 @@ import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
|||
import { preprocessLaTeX } from "@/lib/latex";
|
||||
import { openLink } from "@/lib/open-link";
|
||||
import { INTERNAL, useAuiState, useMessagePartText } from "@assistant-ui/react";
|
||||
import { Copy01Icon, Download01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { Copy01Icon, Download01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { createMathPlugin } from "@streamdown/math";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ import { applyQwenThinkingParams } from "@/features/chat/utils/qwen-params";
|
|||
import { isTauri } from "@/lib/api-base";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
ActionBarMorePrimitive,
|
||||
|
|
@ -115,7 +116,6 @@ import {
|
|||
Image03Icon,
|
||||
McpServerIcon,
|
||||
PencilRulerIcon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
import { Checkbox as CheckboxPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
function Checkbox({
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ import {
|
|||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
} from "@/components/ui/input-group";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
ArrowDown01Icon,
|
||||
Cancel01Icon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ import {
|
|||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { InputGroup, InputGroupAddon } from "@/components/ui/input-group";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Search01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Search01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
function Command({
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
import { ContextMenu as ContextMenuPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowRight01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { ArrowRight01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
function ContextMenu({
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ import {
|
|||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Copy01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Copy01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowRight01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { ArrowRight01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
function DropdownMenu({
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
import { Menubar as MenubarPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowRight01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { ArrowRight01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
||||
function Menubar({
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ import { Select as SelectPrimitive } from "radix-ui";
|
|||
import type * as React from "react";
|
||||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useDialogPortalContainer } from "@/components/ui/dialog";
|
||||
import {
|
||||
ArrowDown01Icon,
|
||||
ArrowUp01Icon,
|
||||
Tick02Icon,
|
||||
UnfoldMoreIcon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import {
|
|||
import {
|
||||
ArrowDown01Icon,
|
||||
Folder01Icon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import type { ReactElement } from "react";
|
||||
import type { ProjectRecord } from "../types";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { McpServerIcon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { McpServerIcon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { XIcon } from "lucide-react";
|
||||
import { type FC, useCallback, useEffect, useState } from "react";
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
thinkToggleAriaLabel,
|
||||
} from "@/components/assistant-ui/think-aria-label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
|
@ -46,7 +47,6 @@ import {
|
|||
Image03Icon,
|
||||
McpServerIcon,
|
||||
PencilRulerIcon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import {
|
|||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowDown01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { ArrowDown01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import {
|
||||
type KeyboardEvent,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from "@/features/hub/hooks/use-hub-model-search";
|
||||
import { useOnlineStatus } from "@/features/hub/hooks/use-online-status";
|
||||
import { formatBytes, formatRelativeShort } from "@/features/hub/lib/format";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn, formatCompact } from "@/lib/utils";
|
||||
import { confirmExternalLink } from "../stores/external-link-confirm";
|
||||
import { useHfTokenStore } from "@/features/hub/stores/hf-token-store";
|
||||
|
|
@ -30,7 +31,6 @@ import {
|
|||
PackageIcon,
|
||||
RamMemoryIcon,
|
||||
Share05Icon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import type { IconSvgElement } from "@hugeicons/react";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import {
|
|||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Copy01Icon,
|
||||
FolderSearchIcon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import type { MouseEvent } from "react";
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { XIcon } from "lucide-react";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { FileDatabaseIcon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { FileDatabaseIcon } from "@hugeicons/core-free-icons";
|
||||
import { type FC, useCallback, useEffect, useState } from "react";
|
||||
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ import {
|
|||
DocumentAttachmentIcon,
|
||||
PlusSignIcon,
|
||||
Search01Icon,
|
||||
Tick02Icon,
|
||||
Upload01Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import {
|
||||
useCallback,
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { useT } from "@/i18n";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Copy01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Copy01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useState } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { useT } from "@/i18n";
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
ArrowUpRight01Icon,
|
||||
Copy01Icon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { Tick02Icon } from "@/lib/tick-icon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { useT } from "@/i18n";
|
||||
import {
|
||||
ArrowUpRight01Icon,
|
||||
Copy01Icon,
|
||||
Tick02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useMemo, useState } from "react";
|
||||
|
|
|
|||
|
|
@ -1313,16 +1313,16 @@
|
|||
|
||||
/* Soft elevation; [data-slot] outranks the component ring-1, dropping the border. */
|
||||
.unsloth-plus-menu[data-slot] {
|
||||
/* Concentric with the item hover boxes, like Gemini: container radius =
|
||||
item radius (12px) + side gutter (10px), so the curves run parallel.
|
||||
/* Concentric with the item hover boxes: container radius =
|
||||
item radius (12px) + side gutter (9px), so the curves run parallel.
|
||||
!important beats the global 14px dropdown radius. */
|
||||
border-radius: 22px !important;
|
||||
border-radius: 21px !important;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
/* Side gutter so item hover boxes sit inset from the menu edge, like
|
||||
Gemini's menus (more breathing room than a hairline gutter). */
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
/* Side gutter ~matches the 0.5rem top/bottom padding so the hover box
|
||||
sits evenly inset on all four sides. */
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
|
|
|
|||
22
studio/frontend/src/lib/tick-icon.ts
Normal file
22
studio/frontend/src/lib/tick-icon.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import type { IconSvgElement } from "@hugeicons/react";
|
||||
|
||||
// App-wide check mark. Plain tick geometry, sized a touch larger
|
||||
// than the stock icon so it reads clearly in menus.
|
||||
export const Tick02Icon: IconSvgElement = [
|
||||
[
|
||||
"path",
|
||||
{
|
||||
d: "M4.477 13.299L9.008 17.829L19.123 7.714",
|
||||
stroke: "currentColor",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
// Fallback weight, matching the icon set; call sites with a
|
||||
// strokeWidth prop override this.
|
||||
strokeWidth: "1.5",
|
||||
key: "0",
|
||||
},
|
||||
],
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue