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
17,994 changes: 17,994 additions & 0 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 @@ -101,6 +101,9 @@
"react-dom": "19.2.1",
"react-hotkeys-hook": "^4.6.1",
"react-icons": "^5.5.0",
"react-i18next": "^15.4.1",
"i18next": "^25.1.3",
"i18next-browser-languagedetector": "^8.0.5",
"react-zoom-pan-pinch": "^3.7.0",
"remark-breaks": "^4.0.0",
"remark-gfm": "^4.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useTheme } from "next-themes"
import { useState, useEffect, useCallback, useMemo } from "react"
import { IconSpinner } from "../../../icons"
import { useAtom, useSetAtom } from "jotai"
import { useTranslation } from "react-i18next"
import { motion, AnimatePresence } from "motion/react"
import { cn } from "../../../lib/utils"
import {
Expand Down Expand Up @@ -128,6 +129,7 @@ function ThemePreviewBox({
}

export function AgentsAppearanceTab() {
const { t, i18n } = useTranslation()
const { resolvedTheme, setTheme: setNextTheme } = useTheme()
const [mounted, setMounted] = useState(false)
const isNarrowScreen = useIsNarrowScreen()
Expand Down Expand Up @@ -382,9 +384,9 @@ export function AgentsAppearanceTab() {
{/* Header - hidden on narrow screens since it's in the navigation bar */}
{!isNarrowScreen && (
<div className="flex flex-col space-y-1.5 text-center sm:text-left">
<h3 className="text-sm font-semibold text-foreground">Appearance</h3>
<h3 className="text-sm font-semibold text-foreground">{t('settings.appearance.title')}</h3>
<p className="text-xs text-muted-foreground">
Customize the look and feel of the interface
{t('settings.appearance.themeDescription')}
</p>
</div>
)}
Expand All @@ -395,10 +397,10 @@ export function AgentsAppearanceTab() {
<div className="flex items-center justify-between p-4">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
Interface theme
{t('settings.appearance.theme')}
</span>
<span className="text-xs text-muted-foreground">
Select or customize your interface color scheme
{t('settings.appearance.themeDescription')}
</span>
</div>

Expand All @@ -417,7 +419,7 @@ export function AgentsAppearanceTab() {
: (systemLightTheme ?? null)
}
/>
<span className="text-xs truncate">System preference</span>
<span className="text-xs truncate">{t('settings.appearance.system')}</span>
</>
) : (
<>
Expand Down Expand Up @@ -516,10 +518,10 @@ export function AgentsAppearanceTab() {
<div className="flex items-center justify-between p-4 border-t border-border">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
Light
{t('settings.appearance.light')}
</span>
<span className="text-xs text-muted-foreground">
Theme to use for light system appearance
{t('settings.appearance.lightDescription')}
</span>
</div>

Expand Down Expand Up @@ -552,10 +554,10 @@ export function AgentsAppearanceTab() {
<div className="flex items-center justify-between p-4 border-t border-border">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
Dark
{t('settings.appearance.dark')}
</span>
<span className="text-xs text-muted-foreground">
Theme to use for dark system appearance
{t('settings.appearance.darkDescription')}
</span>
</div>

Expand Down Expand Up @@ -594,10 +596,10 @@ export function AgentsAppearanceTab() {
<div className="flex items-center justify-between p-4">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
Workspace icon
{t('settings.appearance.workspaceIcon')}
</span>
<span className="text-xs text-muted-foreground">
Show project icon in the sidebar workspace list
{t('settings.appearance.workspaceIconDescription')}
</span>
</div>
<Switch
Expand All @@ -608,10 +610,10 @@ export function AgentsAppearanceTab() {
<div className="flex items-center justify-between p-4 border-t border-border">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
Always expand to-do list
{t('settings.appearance.alwaysExpandTodoList')}
</span>
<span className="text-xs text-muted-foreground">
Show the full to-do list instead of compact view
{t('settings.appearance.alwaysExpandTodoListDescription')}
</span>
</div>
<Switch
Expand All @@ -620,6 +622,38 @@ export function AgentsAppearanceTab() {
/>
</div>
</div>

{/* Language Section */}
<div className="bg-background rounded-lg border border-border overflow-hidden">
<div className="flex items-center justify-between p-4">
<div className="flex flex-col space-y-1">
<span className="text-sm font-medium text-foreground">
{t('settings.appearance.language')}
</span>
<span className="text-xs text-muted-foreground">
{t('settings.appearance.languageDescription')}
</span>
</div>

<Select
value={i18n.language}
onValueChange={(value) => {
i18n.changeLanguage(value)
localStorage.setItem('i18nextLng', value)
}}
>
<SelectTrigger className="w-auto px-2">
<span className="text-xs">
{i18n.language === 'zh-CN' ? '简体中文' : 'English'}
</span>
</SelectTrigger>
<SelectContent>
<SelectItem value="en">English</SelectItem>
<SelectItem value="zh-CN">简体中文</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
)
}
108 changes: 55 additions & 53 deletions src/renderer/features/onboarding/billing-method-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useSetAtom } from "jotai"
import { Check } from "lucide-react"
import { useMemo, useState } from "react"
import { useTranslation } from "react-i18next"

import {
ClaudeCodeIcon,
Expand All @@ -29,53 +30,54 @@ type BillingOption = {
icon: React.ReactNode
}

const billingOptions: BillingOption[] = [
{
id: "claude-subscription",
method: "claude-subscription",
group: "claude-code",
title: "Claude Pro/Max",
subtitle: "Use your Claude subscription for unlimited access.",
recommended: true,
icon: <ClaudeCodeIcon className="w-5 h-5" />,
},
{
id: "api-key",
method: "api-key",
group: "claude-code",
title: "Anthropic API Key",
subtitle: "Pay-as-you-go with your own API key.",
icon: <KeyFilledIcon className="w-5 h-5" />,
},
{
id: "custom-model",
method: "custom-model",
group: "claude-code",
title: "Custom Model",
subtitle: "Use a custom base URL and model.",
icon: <SettingsFilledIcon className="w-5 h-5" />,
},
{
id: "codex-subscription",
method: "codex-subscription",
group: "codex",
title: "Codex Subscription",
subtitle: "Use your Codex ChatGPT login.",
recommended: true,
icon: <CodexIcon className="w-5 h-5" />,
},
{
id: "codex-api-key",
method: "codex-api-key",
group: "codex",
title: "API Key",
subtitle: "Use an app-managed OpenAI API key for Codex.",
icon: <KeyFilledIcon className="w-5 h-5" />,
},
]

export function BillingMethodPage() {
const { t } = useTranslation()
const setBillingMethod = useSetAtom(billingMethodAtom)

const billingOptions: BillingOption[] = useMemo(() => [
{
id: "claude-subscription",
method: "claude-subscription",
group: "claude-code",
title: t('onboarding.billingMethod.claudePro'),
subtitle: t('onboarding.billingMethod.claudeProSubtitle'),
recommended: true,
icon: <ClaudeCodeIcon className="w-5 h-5" />,
},
{
id: "api-key",
method: "api-key",
group: "claude-code",
title: t('onboarding.billingMethod.apiKey'),
subtitle: t('onboarding.billingMethod.apiKeySubtitle'),
icon: <KeyFilledIcon className="w-5 h-5" />,
},
{
id: "custom-model",
method: "custom-model",
group: "claude-code",
title: t('onboarding.billingMethod.customModel'),
subtitle: t('onboarding.billingMethod.customModelSubtitle'),
icon: <SettingsFilledIcon className="w-5 h-5" />,
},
{
id: "codex-subscription",
method: "codex-subscription",
group: "codex",
title: t('onboarding.billingMethod.codexSubscription'),
subtitle: t('onboarding.billingMethod.codexSubscriptionSubtitle'),
recommended: true,
icon: <CodexIcon className="w-5 h-5" />,
},
{
id: "codex-api-key",
method: "codex-api-key",
group: "codex",
title: t('onboarding.billingMethod.codexApiKey'),
subtitle: t('onboarding.billingMethod.codexApiKeySubtitle'),
icon: <KeyFilledIcon className="w-5 h-5" />,
},
], [t])
const setCodexOnboardingCompleted = useSetAtom(codexOnboardingCompletedAtom)
const [selectedGroup, setSelectedGroup] =
useState<BillingOptionGroup>("claude-code")
Expand All @@ -84,13 +86,13 @@ export function BillingMethodPage() {

const visibleOptions = useMemo(
() => billingOptions.filter((option) => option.group === selectedGroup),
[selectedGroup],
[selectedGroup, billingOptions],
)

const selectedOption = useMemo(() => {
const found = billingOptions.find((option) => option.id === selectedOptionId)
return found || billingOptions[0]
}, [selectedOptionId])
}, [selectedOptionId, billingOptions])

const handleContinue = () => {
if (
Expand All @@ -116,10 +118,10 @@ export function BillingMethodPage() {
{/* Header */}
<div className="text-center space-y-1">
<h1 className="text-base font-semibold tracking-tight">
Connect AI Provider
{t('onboarding.billingMethod.title')}
</h1>
<p className="text-sm text-muted-foreground">
Choose how you'd like to connect your provider.
{t('onboarding.billingMethod.subtitle')}
</p>
</div>

Expand All @@ -137,7 +139,7 @@ export function BillingMethodPage() {
: "text-muted-foreground hover:text-foreground",
)}
>
Claude Code
{t('onboarding.billingMethod.claudeCode')}
</button>
<button
type="button"
Expand All @@ -152,7 +154,7 @@ export function BillingMethodPage() {
: "text-muted-foreground hover:text-foreground",
)}
>
Codex
{t('onboarding.billingMethod.codex')}
</button>
</div>

Expand Down Expand Up @@ -198,7 +200,7 @@ export function BillingMethodPage() {
<span className="text-sm font-medium">{option.title}</span>
{option.recommended && (
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded bg-muted text-muted-foreground">
Recommended
{t('onboarding.billingMethod.recommended')}
</span>
)}
</div>
Expand All @@ -216,7 +218,7 @@ export function BillingMethodPage() {
onClick={handleContinue}
className="w-full h-8 px-3 bg-primary text-primary-foreground rounded-lg text-sm font-medium transition-[background-color,transform] duration-150 hover:bg-primary/90 active:scale-[0.97] shadow-[0_0_0_0.5px_rgb(23,23,23),inset_0_0_0_1px_rgba(255,255,255,0.14)] dark:shadow-[0_0_0_0.5px_rgb(23,23,23),inset_0_0_0_1px_rgba(255,255,255,0.14)] flex items-center justify-center"
>
Continue
{t('common.continue')}
</button>
</div>
</div>
Expand Down
Loading