Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
718 changes: 662 additions & 56 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,14 @@
"diff": "^8.0.2",
"framer-motion": "^12.0.0-alpha.1",
"html2canvas": "^1.4.1",
"i18next": "^25.8.8",
"i18next-browser-languagedetector": "^8.2.1",
"lucide-react": "^0.468.0",
"posthog-js": "^1.258.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-i18next": "^16.5.4",
"react-markdown": "^9.0.3",
"react-syntax-highlighter": "^15.6.1",
"recharts": "^2.14.1",
Expand Down
18 changes: 12 additions & 6 deletions src/components/CustomTitlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { motion } from 'framer-motion';
import { Settings, Minus, Square, X, Bot, BarChart3, FileText, Network, Info, MoreVertical } from 'lucide-react';
import { getCurrentWindow } from '@tauri-apps/api/window';
import { TooltipProvider, TooltipSimple } from '@/components/ui/tooltip-modern';
import { useTranslation } from 'react-i18next';
import { LanguageSwitcher } from './LanguageSwitcher';

interface CustomTitlebarProps {
onSettingsClick?: () => void;
Expand All @@ -21,6 +23,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
onMCPClick,
onInfoClick
}) => {
const { t } = useTranslation();
const [isHovered, setIsHovered] = useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -140,7 +143,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
{/* Primary actions group */}
<div className="flex items-center gap-1">
{onAgentsClick && (
<TooltipSimple content="Agents" side="bottom">
<TooltipSimple content={t("titlebar.agents")} side="bottom">
<motion.button
onClick={onAgentsClick}
whileTap={{ scale: 0.97 }}
Expand All @@ -153,7 +156,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
)}

{onUsageClick && (
<TooltipSimple content="Usage Dashboard" side="bottom">
<TooltipSimple content={t("titlebar.usageDashboard")} side="bottom">
<motion.button
onClick={onUsageClick}
whileTap={{ scale: 0.97 }}
Expand All @@ -172,7 +175,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
{/* Secondary actions group */}
<div className="flex items-center gap-1">
{onSettingsClick && (
<TooltipSimple content="Settings" side="bottom">
<TooltipSimple content={t("titlebar.settings")} side="bottom">
<motion.button
onClick={onSettingsClick}
whileTap={{ scale: 0.97 }}
Expand All @@ -184,9 +187,12 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
</TooltipSimple>
)}

{/* Language Switcher */}
<LanguageSwitcher className="tauri-no-drag" />

{/* Dropdown menu for additional options */}
<div className="relative" ref={dropdownRef}>
<TooltipSimple content="More options" side="bottom">
<TooltipSimple content={t("titlebar.moreOptions")} side="bottom">
<motion.button
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
whileTap={{ scale: 0.97 }}
Expand Down Expand Up @@ -222,7 +228,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
className="w-full px-4 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground transition-colors flex items-center gap-3"
>
<Network size={14} />
<span>MCP Servers</span>
<span>{t("titlebar.mcpServers")}</span>
</button>
)}

Expand All @@ -235,7 +241,7 @@ export const CustomTitlebar: React.FC<CustomTitlebarProps> = ({
className="w-full px-4 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground transition-colors flex items-center gap-3"
>
<Info size={14} />
<span>About</span>
<span>{t("titlebar.about")}</span>
</button>
)}
</div>
Expand Down
62 changes: 62 additions & 0 deletions src/components/LanguageSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Globe } from "lucide-react";

const LANGUAGES = [
{ code: "en", label: "English" },
{ code: "zh-CN", label: "简体中文" },
] as const;

interface LanguageSwitcherProps {
className?: string;
}

export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ className }) => {
const { i18n, t } = useTranslation();
const [open, setOpen] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null);

React.useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
setOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);

const handleChange = (code: string) => {
i18n.changeLanguage(code);
setOpen(false);
};

return (
<div className={`relative ${className || ""}`} ref={ref}>
<button
onClick={() => setOpen(!open)}
className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors"
title={t("titlebar.language")}
>
<Globe size={16} />
</button>
{open && (
<div className="absolute right-0 mt-2 w-36 bg-popover border border-border rounded-lg shadow-lg z-[250]">
<div className="py-1">
{LANGUAGES.map((lang) => (
<button
key={lang.code}
onClick={() => handleChange(lang.code)}
className={`w-full px-4 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground transition-colors ${
i18n.language === lang.code ? "bg-accent/50 font-medium" : ""
}`}
>
{lang.label}
</button>
))}
</div>
</div>
)}
</div>
);
};
24 changes: 13 additions & 11 deletions src/components/ProjectList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { motion } from "framer-motion";
import {
import {
FolderOpen,
ChevronLeft,
ChevronRight
Expand All @@ -9,6 +9,7 @@ import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import type { Project } from "@/lib/api";
import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next";

interface ProjectListProps {
/**
Expand Down Expand Up @@ -89,6 +90,7 @@ export const ProjectList: React.FC<ProjectListProps> = ({
onOpenProject,
className,
}) => {
const { t } = useTranslation();
const [showAll, setShowAll] = useState(false);
const [currentPage, setCurrentPage] = useState(1);

Expand Down Expand Up @@ -118,9 +120,9 @@ export const ProjectList: React.FC<ProjectListProps> = ({
<div className="p-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">Projects</h1>
<h1 className="text-3xl font-bold">{t("projects.title")}</h1>
<p className="mt-1 text-body-small text-muted-foreground">
Select a project to start working with Claude Code
{t("projects.subtitle")}
</p>
</div>
<motion.div
Expand All @@ -133,7 +135,7 @@ export const ProjectList: React.FC<ProjectListProps> = ({
className="flex items-center gap-2"
>
<FolderOpen className="h-4 w-4" />
Open Project
{t("projects.openProject")}
</Button>
</motion.div>
</div>
Expand All @@ -145,20 +147,20 @@ export const ProjectList: React.FC<ProjectListProps> = ({
{displayedProjects.length > 0 ? (
<Card className="p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-heading-4">Recent Projects</h2>
<h2 className="text-heading-4">{t("projects.recentProjects")}</h2>
{!showAll ? (
<button
onClick={handleViewAll}
className="text-caption text-muted-foreground hover:text-foreground transition-colors"
>
View all ({projects.length})
{t("projects.viewAll", { count: projects.length })}
</button>
) : (
<button
<button
onClick={handleViewLess}
className="text-caption text-muted-foreground hover:text-foreground transition-colors"
>
View less
{t("projects.viewLess")}
</button>
)}
</div>
Expand Down Expand Up @@ -245,9 +247,9 @@ export const ProjectList: React.FC<ProjectListProps> = ({
<div className="w-16 h-16 bg-primary/10 rounded-lg flex items-center justify-center mb-4">
<FolderOpen className="h-8 w-8 text-primary" />
</div>
<h3 className="text-heading-3 mb-2">No recent projects</h3>
<h3 className="text-heading-3 mb-2">{t("projects.noProjects")}</h3>
<p className="text-body-small text-muted-foreground mb-6">
Open a project to get started with Claude Code
{t("projects.noProjectsDesc")}
</p>
<motion.div
whileTap={{ scale: 0.97 }}
Expand All @@ -259,7 +261,7 @@ export const ProjectList: React.FC<ProjectListProps> = ({
className="flex items-center gap-2"
>
<FolderOpen className="h-4 w-4" />
Open Your First Project
{t("projects.openFirstProject")}
</Button>
</motion.div>
</div>
Expand Down
Loading