Skip to content
Merged
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
77 changes: 77 additions & 0 deletions src/renderer/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,83 @@
}
}

/* Provider ZenMux promotion banner */
.provider-ad-banner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 14px;
border: 1px solid rgba(22, 119, 255, 0.22);
border-radius: 12px;
background:
linear-gradient(135deg, rgba(22, 119, 255, 0.1), rgba(114, 46, 209, 0.08)),
#ffffff;
box-shadow: 0 6px 18px rgba(22, 119, 255, 0.08);
}

.provider-ad-banner__content {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
flex-wrap: wrap;
}

.provider-ad-banner__brand {
color: #0958d9;
font-weight: 600;
}

.provider-ad-banner__text {
color: #5a6072;
}

.provider-ad-banner__link {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
min-height: 30px;
padding: 3px 12px;
border: 1px solid rgba(22, 119, 255, 0.28);
border-radius: 999px;
color: #0958d9;
font-weight: 500;
line-height: 1.4;
text-decoration: none;
background: rgba(255, 255, 255, 0.72);
box-shadow: none;
transition:
border-color 0.2s ease,
color 0.2s ease,
background 0.2s ease;
}

.provider-ad-banner__link:hover,
.provider-ad-banner__link:focus {
color: #1677ff;
text-decoration: none;
border-color: rgba(22, 119, 255, 0.45);
background: rgba(22, 119, 255, 0.08);
}

.provider-ad-banner__link:focus-visible {
outline: 3px solid rgba(22, 119, 255, 0.22);
outline-offset: 2px;
}

@media (max-width: 720px) {
.provider-ad-banner {
align-items: flex-start;
flex-direction: column;
}

.provider-ad-banner__link {
width: 100%;
}
}

/* Settings Tabs - tab栏固定,内容区域滚动 */
.settings-tabs .ant-tabs-content-holder {
flex: 1 1 auto;
Expand Down
20 changes: 20 additions & 0 deletions src/renderer/components/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,26 @@ const Provider: React.FC<ProviderProps> = ({
</Flex>
</div>

<div className="provider-ad-banner">
<div className="provider-ad-banner__content">
<Typography.Text className="provider-ad-banner__brand">
{t('ad_banner.title')}
</Typography.Text>
<Typography.Text className="provider-ad-banner__text">
{t('ad_banner.description')}
</Typography.Text>
</div>
<a
className="provider-ad-banner__link"
href="https://zenmux.ai/invite/9H70CU"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LOW] Hardcoded external referral link

The advertisement link is a hardcoded URL that may need to be updated in the future. Consider extracting it to a configuration file or environment variable.

Suggestion: Move the referral link to a config file (e.g., public/constants.js) or an environment variable to ease future updates.

Risk: If the referral link changes, the banner will point to an invalid or unintended destination until the code is patched.

Confidence: 0.90

[From SubAgent: general]

target="_blank"
rel="noreferrer"
aria-label={t('ad_banner.cta_aria')}
>
{t('ad_banner.cta')}
</a>
</div>

<Divider variant="dashed" dashed plain={true}>
{t('model_config.title')}
</Divider>
Expand Down
24 changes: 24 additions & 0 deletions src/renderer/components/__tests__/Provider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ vi.mock('react-i18next', () => ({
'model_config.id_placeholder': 'Model ID',
'model_config.add_button': 'Add Model',
'model_config.warning': 'Warning: Make sure the model ID matches the provider API',
'ad_banner.title': 'ZenMux: reliable enterprise-grade LLM API service',
'ad_banner.description': 'Get an extra 5–8% bonus on your first top-up',
'ad_banner.cta': 'Get it now',
'ad_banner.cta_aria': 'Get ZenMux enterprise-grade LLM API service',
'actions.delete_provider': 'Delete Provider',
'messages.update_success': 'Updated successfully',
'messages.update_failed': 'Update failed',
Expand Down Expand Up @@ -160,6 +164,26 @@ describe('Provider', () => {
expect(screen.getByText(/Protocol:.*openai/)).toBeInTheDocument()
})
})

it('should display ZenMux ad banner with external link', async () => {
render(
<Wrapper>
<Provider providerId={1} />
</Wrapper>
)

await waitFor(() => {
expect(screen.getByText('ZenMux: reliable enterprise-grade LLM API service')).toBeInTheDocument()
})

expect(screen.getByText('Get an extra 5–8% bonus on your first top-up')).toBeInTheDocument()
const adLink = screen.getByRole('link', {
name: 'Get ZenMux enterprise-grade LLM API service'
})
expect(adLink).toHaveAttribute('href', 'https://zenmux.ai/invite/9H70CU')
expect(adLink).toHaveAttribute('target', '_blank')
expect(adLink).toHaveAttribute('rel', 'noreferrer')
})
})

describe('API Key Input', () => {
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/ar-SA/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "إضافة نموذج",
"warning": "ملاحظة: يرجى إضافة نماذج تدعم التعرف على الرؤية والتأكد من صحة معرف النموذج، وإلا لن يعمل النموذج بشكل صحيح!"
},
"ad_banner": {
"title": "ZenMux: خدمة API موثوقة لنماذج اللغة الكبيرة على مستوى المؤسسات",
"description": "احصل على هدية إضافية بنسبة 5–8% عند أول شحن",
"cta": "احصل عليها",
"cta_aria": "احصل على خدمة API المؤسسية لنماذج اللغة الكبيرة ZenMux"
},
"actions": {
"delete_provider": "حذف المزود",
"delete_model_title": "حذف",
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/en-US/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "Add Model",
"warning": "Note: Please add models that support vision recognition and ensure the Model ID is correct, otherwise the model will not work properly!"
},
"ad_banner": {
"title": "ZenMux: reliable enterprise-grade LLM API service",
"description": "Get an extra 5–8% bonus on your first top-up",
"cta": "Get it now",
"cta_aria": "Get ZenMux enterprise-grade LLM API service"
},
"actions": {
"delete_provider": "Delete Provider",
"delete_model_title": "Delete",
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/fa-IR/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "افزودن مدل",
"warning": "توجه: لطفاً مدل‌هایی که از تشخیص تصویر پشتیبانی می‌کنند اضافه کنید و مطمئن شوید که شناسه مدل صحیح است. در غیر این صورت مدل به درستی کار نخواهد کرد!"
},
"ad_banner": {
"title": "ZenMux: سرویس API قابل اعتماد مدل‌های زبانی بزرگ در سطح سازمانی",
"description": "برای اولین شارژ 5 تا 8٪ هدیه اضافه دریافت کنید",
"cta": "دریافت کنید",
"cta_aria": "دریافت سرویس API سازمانی مدل‌های زبانی بزرگ ZenMux"
},
"actions": {
"delete_provider": "حذف ارائه‌دهنده",
"delete_model_title": "حذف",
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/ja-JP/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "モデルを追加",
"warning": "注意: 視覚認識に対応しているモデルを追加し、モデルIDが正確であることを確認してください。さもなければモデルは正常に動作しません!"
},
"ad_banner": {
"title": "ZenMux:信頼できるエンタープライズ向け大規模モデルAPIサービス",
"description": "初回チャージで5~8%の追加特典をプレゼント",
"cta": "今すぐ入手",
"cta_aria": "ZenMux のエンタープライズ向け大規模モデルAPIサービスを入手"
},
"actions": {
"delete_provider": "プロバイダーを削除",
"delete_model_title": "削除",
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/ru-RU/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "Добавить модель",
"warning": "Примечание: Пожалуйста, добавьте модели, поддерживающие визуальное распознавание, и убедитесь, что ID модели указан правильно. В противном случае модель не будет работать должным образом!"
},
"ad_banner": {
"title": "ZenMux: надежный корпоративный API-сервис больших моделей",
"description": "Получите дополнительный бонус 5–8% при первом пополнении",
"cta": "Получить",
"cta_aria": "Получить корпоративный API-сервис больших моделей ZenMux"
},
"actions": {
"delete_provider": "Удалить провайдера",
"delete_model_title": "Удалить",
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/locales/zh-CN/provider.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
"add_button": "添加模型",
"warning": "注意:请添加支持视觉识别的模型,并确保模型ID正确,否则模型将无法正常使用!"
},
"ad_banner": {
"title": "ZenMux:可靠的企业级大模型API服务",
"description": "首充可获5~8%额外赠送",
"cta": "点击获取",
"cta_aria": "点击获取 ZenMux 企业级大模型API服务"
},
"actions": {
"delete_provider": "删除服务商",
"delete_model_title": "删除",
Expand Down
Loading