From 9b351e612cd456a782e9a6f57a5c9f5f419a7b34 Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Fri, 15 May 2026 13:11:07 +0800 Subject: [PATCH] feat(ui): improve header layout and add theme preset selector - Update Header with better user menu and navigation layout - Add ThemePresetSelector component for theme customization - Refine ChannelSidebar with improved visual hierarchy --- src/components/layout/ChannelSidebar.tsx | 7 ++- src/components/layout/Header.tsx | 22 ++++++--- src/components/theme/ThemePresetSelector.tsx | 51 ++++++++++++++++++++ 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/components/layout/ChannelSidebar.tsx b/src/components/layout/ChannelSidebar.tsx index 9a586dd..f6bbdcb 100644 --- a/src/components/layout/ChannelSidebar.tsx +++ b/src/components/layout/ChannelSidebar.tsx @@ -5,6 +5,8 @@ import {useProjectInfo} from "@/hooks/useProjectInfo"; import {Hash, PanelLeftClose, Plus, Search, Settings} from "lucide-react"; import {CHANNEL_SIDEBAR} from "@/css/layout/styles"; import {ProjectCreateMenuModal} from "@/app/project"; +import { isProjectAdminRole } from "@/lib/project-permissions"; +import { openGlobalSearch } from "@/components/search/global-search-events"; const NAV_ITEMS = [ { @@ -60,7 +62,7 @@ export const ChannelSidebar = memo(function ChannelSidebar({onCollapse}: Channel const isSettingsActive = isActive("settings"); - const showSettings = projectInfo?.role === "Owner" || projectInfo?.role === "Admin"; + const showSettings = isProjectAdminRole(projectInfo?.role); const uncategorizedRooms = useMemo( () => rooms.filter((r) => !r.isMuted && !r.category), @@ -98,9 +100,10 @@ export const ChannelSidebar = memo(function ChannelSidebar({onCollapse}: Channel
diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 90a915f..1829707 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -5,6 +5,8 @@ import { useProjectLayout } from "@/app/project/layout"; import { useProjectsQuery } from "@/hooks/useProjectsQuery"; import { useOptionalRoom } from "@/contexts/room"; import { RoomSettingsModal } from "@/app/project/channel/RoomSettingsModal"; +import { isProjectAdminRole } from "@/lib/project-permissions"; +import { openGlobalSearch } from "@/components/search/global-search-events"; import { DropdownMenu, DropdownMenuTrigger, @@ -42,15 +44,18 @@ const ME_NAV_SIBLINGS: BreadcrumbSibling[] = [ { label: "Invitations", path: "/me/invitations" }, ]; -function getProjectNavSiblings(projectName: string): BreadcrumbSibling[] { - return [ +function getProjectNavSiblings(projectName: string, showSettings: boolean): BreadcrumbSibling[] { + const items = [ { label: "Repository", path: `/${projectName}/repos` }, { label: "Issues", path: `/${projectName}/issues` }, { label: "Skills", path: `/${projectName}/skills` }, { label: "Board", path: `/${projectName}/board` }, { label: "Chat", path: `/${projectName}/chat` }, - { label: "Settings", path: `/${projectName}/settings` }, ]; + if (showSettings) { + items.push({ label: "Settings", path: `/${projectName}/settings` }); + } + return items; } function getRepoTabSiblings(repoBasePath: string): BreadcrumbSibling[] { @@ -67,6 +72,7 @@ function getRepoTabSiblings(repoBasePath: string): BreadcrumbSibling[] { function getSegmentSiblings( segment: BreadcrumbSegment, projects: Array<{ name: string; display_name: string }>, + canManageProject = false, ): BreadcrumbSibling[] | null { if (segment.isLast) return null; @@ -86,7 +92,7 @@ function getSegmentSiblings( if (depth === 2) { if (parts[0] === "me") return ME_NAV_SIBLINGS; - return getProjectNavSiblings(parts[0]); + return getProjectNavSiblings(parts[0], canManageProject); } if (depth >= 3 && parts[1] === "repo") { @@ -168,9 +174,10 @@ const TOOLBAR_ICONS = [ export const Header = memo(function Header() { const location = useLocation(); const { segments, projects } = useBreadcrumbs(); - const { isProjectMember, showMembers, setShowMembers } = useProjectLayout(); + const { isProjectMember, projectInfo, showMembers, setShowMembers } = useProjectLayout(); const [showSettings, setShowSettings] = useState(false); const roomContext = useOptionalRoom(); + const canManageProject = isProjectAdminRole(projectInfo?.role); const handleCopy = useCallback((e: React.MouseEvent, text: string) => { e.preventDefault(); @@ -195,7 +202,7 @@ export const Header = memo(function Header() { {segments.map((segment, idx) => { - const siblings = getSegmentSiblings(segment, projects); + const siblings = getSegmentSiblings(segment, projects, canManageProject); return ( @@ -297,9 +304,10 @@ export const Header = memo(function Header() { {TOOLBAR_ICONS.map((icon, i) => (