Studio: polish update banner layout and sidebar icons (#6266)
Polishes the in-app update notification banners and the sidebar account menu. Update banners (web and llama.cpp): - Add a download icon next to the title, aligned with the title text. - Even out the action row so the buttons share balanced padding and equal spacing. - Let the row wrap on narrow viewports so Copy command is never clipped under overflow-hidden. Sidebar: - Use the setting-07 cog for the profile button and the Settings menu item. - Use the sun-03 icon for the Light Mode menu item. - Slightly enlarge the profile cog. Frontend only. Build and typecheck pass.
This commit is contained in:
parent
31439d9eed
commit
e017248616
4 changed files with 76 additions and 54 deletions
|
|
@ -259,7 +259,7 @@ function TauriWrapper({ children }: { children: ReactNode }) {
|
|||
<>
|
||||
{children}
|
||||
<DownloadManagerPanel />
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-2rem)] max-w-[340px] flex-col items-stretch gap-2">
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-2rem)] max-w-[400px] flex-col items-stretch gap-2">
|
||||
<WebUpdateBanner
|
||||
positioned={false}
|
||||
enabled={!WEB_UPDATE_HIDDEN_ROUTES.has(pathname)}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ import {
|
|||
PowerIcon,
|
||||
PencilEdit02Icon,
|
||||
LayoutAlignLeftIcon,
|
||||
Settings02Icon,
|
||||
Setting07Icon,
|
||||
Sun03Icon,
|
||||
TestTube01Icon,
|
||||
ZapIcon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
|
|
@ -82,7 +83,7 @@ import {
|
|||
} from "@/components/ui/tooltip";
|
||||
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { ChevronDown, ChevronsUpDown, MoreHorizontalIcon, Moon, Sun } from "lucide-react";
|
||||
import { ChevronDown, MoreHorizontalIcon, Moon } from "lucide-react";
|
||||
import { Link, useNavigate, useRouterState } from "@tanstack/react-router";
|
||||
import {
|
||||
archiveChatItem,
|
||||
|
|
@ -1209,7 +1210,12 @@ export function AppSidebar() {
|
|||
<span className="truncate font-heading text-[13.5px] tracking-[0.025em] dark:tracking-[0.04em] font-semibold text-nav-fg">{displayTitle}</span>
|
||||
<span className="truncate text-[11.5px] tracking-nav text-muted-foreground">Unsloth</span>
|
||||
</div>
|
||||
<ChevronsUpDown strokeWidth={1.25} className="ml-auto size-4 text-muted-foreground group-data-[collapsible=icon]:hidden" />
|
||||
{/* settings cog (replaces the up/down chevron) */}
|
||||
<HugeiconsIcon
|
||||
icon={Setting07Icon}
|
||||
strokeWidth={1.5}
|
||||
className="ml-auto !size-[18px] text-muted-foreground group-data-[collapsible=icon]:hidden"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
|
|
@ -1222,7 +1228,7 @@ export function AppSidebar() {
|
|||
<DropdownMenuItem
|
||||
onSelect={() => useSettingsDialogStore.getState().openDialog()}
|
||||
>
|
||||
<HugeiconsIcon icon={Settings02Icon} strokeWidth={1.75} className="size-icon" />
|
||||
<HugeiconsIcon icon={Setting07Icon} strokeWidth={1.75} className="size-icon" />
|
||||
<span>{t("shell.navigation.settings")}</span>
|
||||
<DropdownMenuShortcut>⌘,</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -1239,7 +1245,7 @@ export function AppSidebar() {
|
|||
ref={anchorRef as React.Ref<HTMLDivElement>}
|
||||
onSelect={(e) => { e.preventDefault(); toggleTheme(); }}
|
||||
>
|
||||
{isDark ? <Sun strokeWidth={1.75} className="size-icon" /> : <Moon strokeWidth={1.75} className="size-icon" />}
|
||||
{isDark ? <HugeiconsIcon icon={Sun03Icon} strokeWidth={1.75} className="size-icon" /> : <Moon strokeWidth={1.75} className="size-icon" />}
|
||||
<span>
|
||||
{isDark
|
||||
? t("shell.navigation.lightMode")
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useLlamaUpdateCheck } from "@/hooks/use-llama-update-check";
|
|||
import { useShowLlamaUpdateBanner } from "@/hooks/use-llama-update-pref";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Download } from "lucide-react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { type ReactElement, useEffect, useRef, useState } from "react";
|
||||
|
||||
|
|
@ -132,12 +133,12 @@ export function LlamaUpdateBanner({
|
|||
transition={{ duration: 0.35, ease: EASE_OUT_QUART }}
|
||||
className={cn(
|
||||
positioned
|
||||
? "fixed bottom-4 right-4 z-[9998] w-[calc(100vw-2rem)] max-w-[340px]"
|
||||
? "fixed bottom-4 right-4 z-[9998] w-[calc(100vw-2rem)] max-w-[400px]"
|
||||
: "pointer-events-auto w-full",
|
||||
)}
|
||||
data-testid="llama-update-banner"
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-[24px] bg-white px-4 pb-[22px] pl-6 pt-5 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:bg-card dark:shadow-[0_8px_28px_-6px_rgba(0,0,0,0.28)]">
|
||||
<div className="relative overflow-hidden rounded-[24px] bg-white px-5 pb-4 pt-5 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:bg-card dark:shadow-[0_8px_28px_-6px_rgba(0,0,0,0.28)]">
|
||||
{applying ? null : (
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -163,16 +164,23 @@ export function LlamaUpdateBanner({
|
|||
</button>
|
||||
)}
|
||||
|
||||
<div className="min-w-0 pr-6">
|
||||
<p className="font-heading text-base font-medium text-foreground">
|
||||
{applying ? "Updating llama.cpp..." : "New llama.cpp version"}
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{status?.installed_tag ?? "unknown"} →{" "}
|
||||
<span className="font-medium text-foreground">
|
||||
{status?.latest_tag ?? ""}
|
||||
</span>
|
||||
</p>
|
||||
<div className="flex min-w-0 items-start gap-4 pr-6">
|
||||
<Download
|
||||
aria-hidden="true"
|
||||
className="mt-1 size-5 shrink-0 text-foreground"
|
||||
strokeWidth={1.75}
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<p className="font-heading text-base font-medium text-foreground">
|
||||
{applying ? "Updating llama.cpp..." : "New llama.cpp version"}
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{status?.installed_tag ?? "unknown"} →{" "}
|
||||
<span className="font-medium text-foreground">
|
||||
{status?.latest_tag ?? ""}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{applying ? (
|
||||
|
|
@ -195,24 +203,25 @@ export function LlamaUpdateBanner({
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-3 flex items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
className="h-auto rounded-full px-3.5 py-2 text-[13px]"
|
||||
onClick={handleUpdate}
|
||||
data-testid="llama-update-button"
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
<div className="mt-4 flex flex-wrap items-center justify-between gap-y-2">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-2.5 py-2 text-[13px] text-muted-foreground hover:text-foreground"
|
||||
className="-ml-2 h-auto rounded-full px-2.5 py-2 text-[13px] font-medium text-foreground"
|
||||
onClick={snooze}
|
||||
data-testid="llama-update-snooze-button"
|
||||
>
|
||||
Remind me later
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
// ml offsets the pill's filled edge so visual gaps stay equal
|
||||
className="ml-2.5 h-auto rounded-full px-3.5 py-2 text-[13px]"
|
||||
onClick={handleUpdate}
|
||||
data-testid="llama-update-button"
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { useWebUpdateCheck } from "@/hooks/use-web-update-check";
|
|||
import { isTauri } from "@/lib/api-base";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Download } from "lucide-react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { type ReactElement, useEffect, useRef, useState } from "react";
|
||||
|
||||
|
|
@ -78,12 +79,12 @@ export function WebUpdateBanner({
|
|||
transition={{ duration: 0.35, ease: EASE_OUT_QUART }}
|
||||
className={cn(
|
||||
positioned
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-2rem)] max-w-[340px]"
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-2rem)] max-w-[400px]"
|
||||
: "pointer-events-auto w-full",
|
||||
)}
|
||||
data-testid="web-update-banner"
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-[24px] bg-white px-4 pb-[22px] pl-6 pt-5 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:bg-card dark:shadow-[0_8px_28px_-6px_rgba(0,0,0,0.28)]">
|
||||
<div className="relative overflow-hidden rounded-[24px] bg-white px-5 pb-4 pt-5 shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] dark:bg-card dark:shadow-[0_8px_28px_-6px_rgba(0,0,0,0.28)]">
|
||||
<button
|
||||
type="button"
|
||||
onClick={dismiss}
|
||||
|
|
@ -107,47 +108,53 @@ export function WebUpdateBanner({
|
|||
</svg>
|
||||
</button>
|
||||
|
||||
<div className="min-w-0 pr-6">
|
||||
<p className="font-heading text-base font-medium text-foreground">
|
||||
New Unsloth version
|
||||
</p>
|
||||
<div className="mt-0.5 flex items-center justify-between gap-3">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<div className="flex min-w-0 items-start gap-4 pr-6">
|
||||
<Download
|
||||
aria-hidden="true"
|
||||
className="mt-1 size-5 shrink-0 text-foreground"
|
||||
strokeWidth={1.75}
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<p className="font-heading text-base font-medium text-foreground">
|
||||
New Unsloth version
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{status.currentVersion} →{" "}
|
||||
<span className="font-medium text-foreground">
|
||||
{status.latestVersion}
|
||||
</span>
|
||||
</p>
|
||||
<a
|
||||
href={RELEASE_NOTES_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="shrink-0 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
|
||||
data-testid="web-update-release-notes-link"
|
||||
>
|
||||
Release notes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
className="h-auto rounded-full px-3.5 py-2 text-[13px]"
|
||||
onClick={handleCopyCommand}
|
||||
data-testid="web-update-copy-button"
|
||||
<div className="mt-4 flex flex-wrap items-center justify-between gap-y-2">
|
||||
<a
|
||||
href={RELEASE_NOTES_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="-ml-2 whitespace-nowrap rounded-full px-2.5 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted"
|
||||
data-testid="web-update-release-notes-link"
|
||||
>
|
||||
{copied ? "Copied" : "Copy command"}
|
||||
</Button>
|
||||
Release notes
|
||||
</a>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-2.5 py-2 text-[13px] text-muted-foreground hover:text-foreground"
|
||||
className="h-auto rounded-full px-2.5 py-2 text-[13px] font-medium text-foreground"
|
||||
onClick={snooze}
|
||||
data-testid="web-update-snooze-button"
|
||||
>
|
||||
Remind me later
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
// ml offsets the pill's filled edge so visual gaps stay equal
|
||||
className="ml-2.5 h-auto rounded-full px-3.5 py-2 text-[13px]"
|
||||
onClick={handleCopyCommand}
|
||||
data-testid="web-update-copy-button"
|
||||
>
|
||||
{copied ? "Copied" : "Copy command"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue