From 8f5be58f9bc5eb2af826f5ff88e1d8ec9da64008 Mon Sep 17 00:00:00 2001 From: vvzvlad Date: Thu, 18 Jun 2026 17:50:42 +0300 Subject: [PATCH] feat(ai-chat): move AI chat icon into the global top bar Move the AI-chat toggle icon (IconSparkles) from the page header menu into the global top bar, placed next to the notifications icon. The "AI chat enabled" gate (workspace.settings.ai.chat) is preserved, and the icon style is aligned with the neighbouring notifications icon (subtle, size sm). As a result the entry point is now available on all routes instead of only on page routes. - app-header.tsx: render the gated AI-chat ActionIcon before NotificationPopover; wire it to aiChatWindowOpenAtom. - page-header-menu.tsx: remove the old AI icon block and its now-unused imports/locals. --- .../components/layouts/global/app-header.tsx | 24 ++++++++++++++++++- .../components/header/page-header-menu.tsx | 20 +--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/apps/client/src/components/layouts/global/app-header.tsx b/apps/client/src/components/layouts/global/app-header.tsx index dd829f9b..cd30c321 100644 --- a/apps/client/src/components/layouts/global/app-header.tsx +++ b/apps/client/src/components/layouts/global/app-header.tsx @@ -1,19 +1,23 @@ import { + ActionIcon, Box, Group, Text, Tooltip, } from "@mantine/core"; +import { IconSparkles } from "@tabler/icons-react"; import classes from "./app-header.module.css"; import { BrandLogo } from "@/components/ui/brand-logo"; import TopMenu from "@/components/layouts/global/top-menu.tsx"; import { Link } from "react-router-dom"; import APP_ROUTE from "@/lib/app-route.ts"; -import { useAtom } from "jotai"; +import { useAtom, useSetAtom } from "jotai"; import { desktopSidebarAtom, mobileSidebarAtom, } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts"; +import { aiChatWindowOpenAtom } from "@/features/ai-chat/atoms/ai-chat-atom.ts"; +import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts"; import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts"; import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx"; import { useTranslation } from "react-i18next"; @@ -38,6 +42,11 @@ export function AppHeader() { const [desktopOpened] = useAtom(desktopSidebarAtom); const toggleDesktop = useToggleSidebar(desktopSidebarAtom); + const [workspace] = useAtom(workspaceAtom); + const setAiChatWindowOpen = useSetAtom(aiChatWindowOpenAtom); + // AI chat entry point: only shown when the workspace enables it (A7 gate). + const aiChatEnabled = workspace?.settings?.ai?.chat === true; + const items = links.map((link) => ( {t(link.label)} @@ -105,6 +114,19 @@ export function AppHeader() { + {aiChatEnabled && ( + + setAiChatWindowOpen((v) => !v)} + > + + + + )} diff --git a/apps/client/src/features/page/components/header/page-header-menu.tsx b/apps/client/src/features/page/components/header/page-header-menu.tsx index c802bc44..38281b86 100644 --- a/apps/client/src/features/page/components/header/page-header-menu.tsx +++ b/apps/client/src/features/page/components/header/page-header-menu.tsx @@ -12,7 +12,6 @@ import { IconMarkdown, IconMessage, IconPrinter, - IconSparkles, IconStar, IconStarFilled, IconTrash, @@ -20,8 +19,7 @@ import { } from "@tabler/icons-react"; import React, { useEffect, useRef, useState } from "react"; import { useAsideTriggerProps } from "@/hooks/use-toggle-aside.tsx"; -import { useAtom, useAtomValue, useSetAtom } from "jotai"; -import { aiChatWindowOpenAtom } from "@/features/ai-chat/atoms/ai-chat-atom.ts"; +import { useAtom, useAtomValue } from "jotai"; import { historyAtoms } from "@/features/page-history/atoms/history-atoms.ts"; import { useDisclosure, useHotkeys } from "@mantine/hooks"; import { useClipboard } from "@/hooks/use-clipboard"; @@ -65,7 +63,6 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) { const { t } = useTranslation(); const commentsTriggerProps = useAsideTriggerProps("comments"); const tocTriggerProps = useAsideTriggerProps("toc"); - const setAiChatWindowOpen = useSetAtom(aiChatWindowOpenAtom); const { pageSlug } = useParams(); const { data: page } = usePageQuery({ pageId: extractPageSlugId(pageSlug), @@ -74,8 +71,6 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) { const [workspace] = useAtom(workspaceAtom); // Community public-sharing entry point (replaces the removed EE PageShareModal) const workspaceSharingDisabled = workspace?.settings?.sharing?.disabled === true; - // AI chat entry point: only shown when the workspace enables it (A7 gate). - const aiChatEnabled = workspace?.settings?.ai?.chat === true; useHotkeys( [ @@ -132,19 +127,6 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) { - {aiChatEnabled && ( - - setAiChatWindowOpen((v) => !v)} - > - - - - )} - );