diff --git a/windows/tauri/src/features/layout/components/main-layout.tsx b/windows/tauri/src/features/layout/components/main-layout.tsx index 74f6de62..22b7125e 100644 --- a/windows/tauri/src/features/layout/components/main-layout.tsx +++ b/windows/tauri/src/features/layout/components/main-layout.tsx @@ -30,6 +30,7 @@ import { MainSidebar, SidebarActivityRail, } from "./sidebar/main-sidebar"; +import { PluginActivityRail } from "./plugin-activity-rail"; import { WelcomeScreen } from "./welcome-screen"; const CommandPalette = lazy(() => import("@/features/command-palette/components/command-palette")); @@ -75,19 +76,14 @@ export function MainLayout() { usePaneKeyboard(); const isSidebarVisible = useUIState((state) => state.isSidebarVisible); - const activityRailExpanded = useSettingsStore((state) => state.settings.activityRailExpanded); - const activityRailWidth = useSettingsStore((state) => state.settings.activityRailWidth); const sidebarWidth = useSettingsStore((state) => state.settings.sidebarWidth); const showStatusBar = useSettingsStore((state) => state.settings.showStatusBar); const isDatabaseConnectionVisible = useUIState((state) => state.isDatabaseConnectionVisible); const setIsDatabaseConnectionVisible = useUIState( (state) => state.setIsDatabaseConnectionVisible, ); - const renderedActivityRailWidth = activityRailExpanded - ? activityRailWidth - : COLLAPSED_ACTIVITY_RAIL_WIDTH; const leftPaneReservedWidth = - renderedActivityRailWidth + (isSidebarVisible ? sidebarWidth : 0); + COLLAPSED_ACTIVITY_RAIL_WIDTH + (isSidebarVisible ? sidebarWidth : 0); const vimRelativeLineNumbers = useSettingsStore((state) => state.settings.vimRelativeLineNumbers); const relativeLineNumbers = useVimStore.use.relativeLineNumbers(); const { setRelativeLineNumbers } = useVimStore.use.actions(); @@ -271,7 +267,7 @@ export function MainLayout() { className="flex flex-1 flex-row overflow-hidden pr-(--lithe-workbench-gap)" style={{ minHeight: 0 }} > - + + {terminalWidthMode === "full" && deferredSurfacesReady && ( diff --git a/windows/tauri/src/features/layout/components/plugin-activity-rail.tsx b/windows/tauri/src/features/layout/components/plugin-activity-rail.tsx new file mode 100644 index 00000000..22bc5680 --- /dev/null +++ b/windows/tauri/src/features/layout/components/plugin-activity-rail.tsx @@ -0,0 +1,28 @@ +import { useState } from "react"; +import { PuzzlePieceIcon } from "@/ui/icons"; +import Tooltip from "@/ui/tooltip"; + +export function PluginActivityRail() { + const [selected, setSelected] = useState(false); + + return ( + + ); +} diff --git a/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx b/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx index 6bb8c5fd..9168ef4b 100644 --- a/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx +++ b/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx @@ -35,8 +35,7 @@ import { useWorkspaceTabsStore, type ProjectTab, } from "@/features/window/stores/workspace-tabs.store"; -import { SidebarListItem, SidebarPanel } from "@/ui/sidebar"; -import Tooltip from "@/ui/tooltip"; +import { SidebarPanel } from "@/ui/sidebar"; import { cn } from "@/utils/cn"; import { ContextMenu, @@ -77,7 +76,7 @@ interface SidebarActivityRailProps { expanded?: boolean; } -export const COLLAPSED_ACTIVITY_RAIL_WIDTH = 40; +export const COLLAPSED_ACTIVITY_RAIL_WIDTH = 38; const DEFAULT_ACTIVITY_RAIL_WIDTH = 160; const MIN_ACTIVITY_RAIL_WIDTH = 140; const MAX_ACTIVITY_RAIL_WIDTH = 320; @@ -197,10 +196,7 @@ export const SidebarActivityRail = memo(({ expanded = false }: SidebarActivityRa icon: , }, ], - [ - coreFeatures.git, - coreFeatures.search, - ], + [coreFeatures.git, coreFeatures.search], ); const setActivityRailItemVisible = useCallback( @@ -761,53 +757,49 @@ export const SidebarActivityRail = memo(({ expanded = false }: SidebarActivityRa ); }); -export const MainSidebar = memo( - ({ activeView, isGitActive }: MainSidebarProps) => { - const uiGitViewActive = useUIState((state) => state.isGitViewActive); - const uiActiveSidebarView = useUIState((state) => state.activeSidebarView); - const isGitViewActive = isGitActive ?? uiGitViewActive; - const activeSidebarView = activeView ?? uiActiveSidebarView; - - const handleFileSelect = useFileSystemStore.use.handleFileSelect?.(); - const rootFolderPath = useFileSystemStore.use.rootFolderPath?.(); - - const coreFeatures = useSettingsStore((state) => state.settings.coreFeatures); - const activePaneId: SidebarView = isGitViewActive - ? "git" - : activeSidebarView; - const allPaneEntries: SidebarPaneEntry[] = [ - ...(coreFeatures.git - ? [ - { - id: "git" as const, - content: ( - - ), - }, - ] - : []), - { - id: "files", - content: , - }, - ]; - const paneEntries = allPaneEntries; - const activePane = (() => { - const requestedIndex = paneEntries.findIndex((pane) => pane.id === activePaneId); - if (requestedIndex >= 0) return paneEntries[requestedIndex]; - - return paneEntries[0] ?? null; - })(); - return ( -
- -
{activePane?.content ?? null}
-
-
- ); - }, -); +export const MainSidebar = memo(({ activeView, isGitActive }: MainSidebarProps) => { + const uiGitViewActive = useUIState((state) => state.isGitViewActive); + const uiActiveSidebarView = useUIState((state) => state.activeSidebarView); + const isGitViewActive = isGitActive ?? uiGitViewActive; + const activeSidebarView = activeView ?? uiActiveSidebarView; + + const handleFileSelect = useFileSystemStore.use.handleFileSelect?.(); + const rootFolderPath = useFileSystemStore.use.rootFolderPath?.(); + + const coreFeatures = useSettingsStore((state) => state.settings.coreFeatures); + const activePaneId: SidebarView = isGitViewActive ? "git" : activeSidebarView; + const allPaneEntries: SidebarPaneEntry[] = [ + ...(coreFeatures.git + ? [ + { + id: "git" as const, + content: ( + + ), + }, + ] + : []), + { + id: "files", + content: , + }, + ]; + const paneEntries = allPaneEntries; + const activePane = (() => { + const requestedIndex = paneEntries.findIndex((pane) => pane.id === activePaneId); + if (requestedIndex >= 0) return paneEntries[requestedIndex]; + + return paneEntries[0] ?? null; + })(); + return ( +
+ +
{activePane?.content ?? null}
+
+
+ ); +}); diff --git a/windows/tauri/src/features/layout/components/welcome-screen.tsx b/windows/tauri/src/features/layout/components/welcome-screen.tsx index 92f5b777..2ce7e5a5 100644 --- a/windows/tauri/src/features/layout/components/welcome-screen.tsx +++ b/windows/tauri/src/features/layout/components/welcome-screen.tsx @@ -1,80 +1,121 @@ -import { useMemo, useState } from "react"; -import { useRecentFoldersStore } from "@/features/file-system/stores/recent-folders.store"; +import { getVersion } from "@tauri-apps/api/app"; +import { useEffect, useMemo, useState } from "react"; import { useFileSystemStore } from "@/features/file-system/stores/file-system.store"; +import { useRecentFoldersStore } from "@/features/file-system/stores/recent-folders.store"; import { useUIState } from "@/features/window/stores/ui-state.store"; import { useTranslation } from "@/i18n/locale-provider"; import { Button } from "@/ui/button"; import { + ArrowClockwiseIcon, + FolderIcon, FolderOpenIcon, - GitBranchIcon, GearIcon, + GitBranchIcon, MagnifyingGlassIcon, XIcon, } from "@/ui/icons"; +const projectColors = [ + "bg-emerald-500/80", + "bg-blue-500/85", + "bg-orange-500/85", + "bg-cyan-500/80", + "bg-violet-500/80", +]; + +function projectInitials(name: string) { + const words = name.split(/[^\p{L}\p{N}]+/u).filter(Boolean); + const initials = words + .slice(0, 2) + .map((word) => word[0]) + .join(""); + return (initials || "LI").toUpperCase(); +} + +function colorForProject(path: string) { + const hash = Array.from(path).reduce((value, character) => value + character.charCodeAt(0), 0); + return projectColors[hash % projectColors.length]; +} + export function WelcomeScreen() { const { t } = useTranslation(); const [query, setQuery] = useState(""); + const [appVersion, setAppVersion] = useState(""); const recentFolders = useRecentFoldersStore((state) => state.recentFolders); const openRecentFolder = useRecentFoldersStore((state) => state.actions.openRecentFolder); const removeFromRecents = useRecentFoldersStore((state) => state.actions.removeFromRecents); const handleOpenFolder = useFileSystemStore((state) => state.handleOpenFolder); const setIsProjectPickerVisible = useUIState((state) => state.setIsProjectPickerVisible); - const setIsSettingsDialogVisible = useUIState((state) => state.setIsSettingsDialogVisible); + const openSettingsDialog = useUIState((state) => state.openSettingsDialog); + + useEffect(() => { + void getVersion() + .then(setAppVersion) + .catch(() => setAppVersion("")); + }, []); const visibleRecentFolders = useMemo(() => { - const normalizedQuery = query.trim().toLowerCase(); + const normalizedQuery = query.trim().toLocaleLowerCase(); const sortedFolders = [...recentFolders].sort( (left, right) => (right.lastOpenedAt ?? 0) - (left.lastOpenedAt ?? 0), ); if (!normalizedQuery) return sortedFolders; - - return sortedFolders.filter((folder) => { - return ( - folder.name.toLowerCase().includes(normalizedQuery) || - folder.path.toLowerCase().includes(normalizedQuery) - ); - }); + return sortedFolders.filter( + (folder) => + folder.name.toLocaleLowerCase().includes(normalizedQuery) || + folder.path.toLocaleLowerCase().includes(normalizedQuery), + ); }, [query, recentFolders]); return (
-