feat(brand): apply 森林AI identity
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# SenlinAI Acro React
|
||||
# 森林AI Web 客户端
|
||||
|
||||
SenlinAI primary web client built with React, TypeScript, Vite, and Arco Design.
|
||||
森林AI主 Web 客户端,使用 React、TypeScript、Vite 和 Arco Design 构建。
|
||||
|
||||
This app is the active web client under `apps/web_v1`.
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/senlinai-icon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>web_v1</title>
|
||||
<meta name="application-name" content="森林AI" />
|
||||
<meta name="description" content="森林AI 私有化项目工作台" />
|
||||
<title>森林AI</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 731 B |
10
apps/web_v1/public/senlinai-icon.svg
Normal file
10
apps/web_v1/public/senlinai-icon.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
|
||||
<title>森林AI 图标</title>
|
||||
<rect x="4" y="4" width="120" height="120" rx="28" fill="#165DFF"/>
|
||||
<path d="M64 23C43 23 27 40 27 61c0 13 7 24 17 30h40c10-6 17-17 17-30 0-21-16-38-37-38Z" fill="#F4F8FF"/>
|
||||
<path d="M64 99V65M64 76 47 61M64 82l18-16M64 68l12-13" fill="none" stroke="#F4F8FF" stroke-linecap="round" stroke-linejoin="round" stroke-width="10"/>
|
||||
<path d="M42 58c6-15 29-22 45-7M39 69c12-11 38-13 50 2M48 78c9-5 24-6 33-1" fill="none" stroke="#165DFF" stroke-linecap="round" stroke-width="5"/>
|
||||
<circle cx="47" cy="61" r="6" fill="#14B8A6"/>
|
||||
<circle cx="76" cy="55" r="6" fill="#60A5FA"/>
|
||||
<circle cx="82" cy="66" r="6" fill="#A7F3D0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 731 B |
@@ -25,6 +25,23 @@ const requiredFiles = [
|
||||
|
||||
const failures = requiredFiles.filter((file) => !existsSync(file)).map((file) => `missing ${file}`)
|
||||
|
||||
const html = readFileSync('index.html', 'utf8')
|
||||
if (!html.includes('<html lang="zh-CN">')) failures.push('index language must be zh-CN')
|
||||
if (!html.includes('<title>森林AI</title>')) failures.push('document title must be 森林AI')
|
||||
if (!html.includes('href="/senlinai-icon.svg"')) failures.push('favicon must use /senlinai-icon.svg')
|
||||
if (!existsSync('public/senlinai-icon.svg')) failures.push('missing public/senlinai-icon.svg')
|
||||
|
||||
for (const file of ['src/pages/login.tsx', 'src/pages/projects/project-topbar.tsx', 'src/pages/projects/project-rail.tsx']) {
|
||||
const source = readFileSync(file, 'utf8')
|
||||
if (!source.includes('/senlinai-icon.svg')) failures.push(`${file} must use the brand icon`)
|
||||
}
|
||||
|
||||
for (const forbidden of ['森林Agent', 'SenlinAI Workbench']) {
|
||||
for (const file of requiredFiles.filter((name) => name.endsWith('.tsx'))) {
|
||||
if (readFileSync(file, 'utf8').includes(forbidden)) failures.push(`${file} contains legacy product name ${forbidden}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (existsSync('src/App.tsx')) {
|
||||
failures.push('legacy src/App.tsx should be removed after page split')
|
||||
}
|
||||
|
||||
@@ -113,23 +113,23 @@
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.brand-symbol {
|
||||
.brand-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
background: var(--senlin-primary);
|
||||
color: white;
|
||||
font-weight: 800;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.brand-lockup.large .brand-symbol {
|
||||
.brand-lockup.large .brand-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
border-radius: 12px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.rail-brand-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
|
||||
@@ -38,8 +38,8 @@ export function LoginPage({ onLogin }: { onLogin: (input: { server: string; emai
|
||||
<Card className="login-card" bordered>
|
||||
<div className="login-brand-panel">
|
||||
<div className="brand-lockup large">
|
||||
<span className="brand-symbol">S</span>
|
||||
<Title heading={2}>森林Agent</Title>
|
||||
<img className="brand-icon" src="/senlinai-icon.svg" alt="" aria-hidden="true" />
|
||||
<Title heading={2}>森林AI</Title>
|
||||
</div>
|
||||
<Text className="login-slogan">私有部署 · 安全可控的智能协作平台</Text>
|
||||
<Text type="secondary">知识沉淀 · 团队协作 · AI Agent</Text>
|
||||
@@ -51,7 +51,7 @@ export function LoginPage({ onLogin }: { onLogin: (input: { server: string; emai
|
||||
</div>
|
||||
|
||||
<div className="login-form-panel">
|
||||
<Title heading={4}>登录到您的 SenlinAI</Title>
|
||||
<Title heading={4}>登录到您的森林AI</Title>
|
||||
<Text type="secondary">连接私有工作台</Text>
|
||||
<Form layout="vertical" className="login-form">
|
||||
<Form.Item label="服务器地址(IP 或域名优先)">
|
||||
@@ -81,7 +81,7 @@ export function LoginPage({ onLogin }: { onLogin: (input: { server: string; emai
|
||||
<div className="login-value-panel">
|
||||
<Title heading={3}>安全 · 专注 · 高效</Title>
|
||||
<Paragraph>
|
||||
SenlinAI 是面向知识工作者与内部团队的私有部署工作台,帮助团队在统一空间中收集信息、整理知识、协同决策。
|
||||
森林AI 是面向知识工作者与内部团队的私有部署工作台,帮助团队在统一空间中收集信息、整理知识、协同决策。
|
||||
</Paragraph>
|
||||
<ValuePoint icon={<IconSafe />} title="私有部署,数据自有" desc="所有数据与模型运行在您的环境中,安全可控。" />
|
||||
<ValuePoint icon={<IconBook />} title="知识沉淀,结构清晰" desc="从收集到整理,形成可复用的团队知识库。" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CSSProperties } from 'react'
|
||||
import { Badge, Button, Layout, Space } from '@arco-design/web-react'
|
||||
import { IconCompass, IconDashboard, IconPlus } from '@arco-design/web-react/icon'
|
||||
import { IconCompass, IconPlus } from '@arco-design/web-react/icon'
|
||||
import type { Project, WorkbenchView } from './project-types'
|
||||
|
||||
const { Sider } = Layout
|
||||
@@ -26,10 +26,10 @@ export function ProjectRail({
|
||||
<Sider className="project-rail" width={96}>
|
||||
<Button
|
||||
className={activeView === 'workspace' ? 'dashboard-button active' : 'dashboard-button'}
|
||||
icon={<IconDashboard />}
|
||||
icon={<img className="brand-icon rail-brand-icon" src="/senlinai-icon.svg" alt="" aria-hidden="true" />}
|
||||
onClick={onSelectWorkspace}
|
||||
aria-label="工作台"
|
||||
title="工作台"
|
||||
aria-label="森林AI 工作台"
|
||||
title="森林AI 工作台"
|
||||
/>
|
||||
<Button
|
||||
className={activeView === 'workspace-explore' ? 'dashboard-button active' : 'dashboard-button'}
|
||||
|
||||
@@ -11,8 +11,8 @@ export function ProjectTopbar({ theme, onToggleTheme }: { theme: Theme; onToggle
|
||||
return (
|
||||
<Header className="topbar">
|
||||
<div className="brand-lockup">
|
||||
<span className="brand-symbol">S</span>
|
||||
<Text className="brand-name">SenlinAI</Text>
|
||||
<img className="brand-icon" src="/senlinai-icon.svg" alt="" aria-hidden="true" />
|
||||
<Text className="brand-name">森林AI</Text>
|
||||
</div>
|
||||
<div className="global-search" role="search">
|
||||
<Input size="large" prefix={<IconSearch />} placeholder="搜索项目、频道、文档、任务、联系人..." />
|
||||
|
||||
Reference in New Issue
Block a user