chore(branding): 更新登录与首页标题资源及部署配置
Some checks failed
CI / build (push) Successful in 2m18s
Deploy To Server / deploy (push) Failing after 2s

引入新的 logo-title 资源并替换登录页与首页左上角标题展示,统一相关样式细节;同时补充 Docker 与 Gitea 部署配置,便于服务器端自动化构建发布。

Made-with: Cursor
This commit is contained in:
2026-04-25 23:19:52 +08:00
parent 6e8acef10f
commit 20aeb94f6e
8 changed files with 109 additions and 13 deletions

10
.dockerignore Normal file
View File

@@ -0,0 +1,10 @@
.git
.gitignore
node_modules
dist
.idea
.vscode
.cursor
*.log
Dockerfile*
docker-compose*.yml

View File

@@ -0,0 +1,43 @@
name: Deploy To Server
on:
push:
branches: [main, master]
workflow_dispatch:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy over SSH
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
DEPLOY_SSH_KNOWN_HOSTS: ${{ secrets.DEPLOY_SSH_KNOWN_HOSTS }}
DEPLOY_WORKDIR: ${{ secrets.DEPLOY_WORKDIR }}
run: |
set -eu
mkdir -p ~/.ssh
chmod 700 ~/.ssh
printf '%s\n' "$DEPLOY_SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
printf '%s\n' "$DEPLOY_SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
SSH_PORT="${DEPLOY_PORT:-22}"
REMOTE_DIR="${DEPLOY_WORKDIR:-/opt/chat-one-web}"
ssh -p "$SSH_PORT" "$DEPLOY_USER@$DEPLOY_HOST" <<EOF
set -eu
cd "$REMOTE_DIR"
git pull --ff-only
docker compose up -d --build
docker image prune -f
EOF

24
Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
# syntax=docker/dockerfile:1
FROM node:20-alpine AS builder
WORKDIR /app
# 先复制依赖清单,利用 Docker layer cache
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# 再复制源码并构建
COPY . .
RUN yarn build
FROM nginx:1.27-alpine AS runner
WORKDIR /usr/share/nginx/html
# 覆盖默认站点配置,启用 SPA 回退与缓存策略
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 仅拷贝构建产物,减小镜像体积
COPY --from=builder /app/dist ./
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

12
docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
version: "3.9"
services:
chat-one-web:
build:
context: .
dockerfile: Dockerfile
image: chat-one-web:latest
container_name: chat-one-web
restart: unless-stopped
ports:
- "80:80"

BIN
src/assets/logo-title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -12,7 +12,6 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
theme={{ theme={{
algorithm: theme.defaultAlgorithm, algorithm: theme.defaultAlgorithm,
token: { token: {
colorPrimary: "#4A90E2",
colorBgBase: "#F7F7F8", colorBgBase: "#F7F7F8",
colorBgContainer: "#FFFFFF", colorBgContainer: "#FFFFFF",
colorBorder: "#E9E9EB", colorBorder: "#E9E9EB",

View File

@@ -39,6 +39,7 @@ import {
import type { MenuProps } from "antd"; import type { MenuProps } from "antd";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import logoSrc from "../assets/logo.png"; import logoSrc from "../assets/logo.png";
import logoTitleSrc from "../assets/logo-title.png";
import { ACCESS_TOKEN_KEY, SessionExpiredError, USER_KEY, logout } from "../api/auth"; import { ACCESS_TOKEN_KEY, SessionExpiredError, USER_KEY, logout } from "../api/auth";
import { import {
createChatSession, createChatSession,
@@ -99,6 +100,7 @@ const DEEP_THINK_STORAGE_KEY = "chatone-deep-think-enabled";
const SMART_SEARCH_STORAGE_KEY = "chatone-smart-search-enabled"; const SMART_SEARCH_STORAGE_KEY = "chatone-smart-search-enabled";
const SELECTED_MODEL_STORAGE_KEY = "chatone-selected-model"; const SELECTED_MODEL_STORAGE_KEY = "chatone-selected-model";
const LOGO_SRC = logoSrc; const LOGO_SRC = logoSrc;
const TITLE_SRC = logoTitleSrc;
/** 展示名与请求 model 字段;需与后端实际支持的模型 id 一致 */ /** 展示名与请求 model 字段;需与后端实际支持的模型 id 一致 */
const DEFAULT_QWEN_MODEL = "qwen3.6-plus"; const DEFAULT_QWEN_MODEL = "qwen3.6-plus";
@@ -745,9 +747,12 @@ export default function HomePage() {
decoding="async" decoding="async"
/> />
{!collapsed && ( {!collapsed && (
<Typography.Title level={5} className="!m-0 !truncate !text-[15px] !font-semibold"> <img
ChatOne src={TITLE_SRC}
</Typography.Title> alt="chatone"
className="h-7 w-auto max-w-[170px] object-contain object-left"
decoding="async"
/>
)} )}
</div> </div>
{sidebarContent} {sidebarContent}

View File

@@ -1,7 +1,8 @@
import { Button, Input, Typography, message } from "antd"; import { Button, Input, message } from "antd";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import logoSrc from "../assets/logo.png"; import logoSrc from "../assets/logo.png";
import logoTitleSrc from "../assets/logo-title.png";
import { import {
ACCESS_TOKEN_KEY, ACCESS_TOKEN_KEY,
persistTokens, persistTokens,
@@ -14,6 +15,7 @@ import { tw } from "../utils/tw";
/** 发送验证码成功后,按钮冷却秒数 */ /** 发送验证码成功后,按钮冷却秒数 */
const SMS_RESEND_COOLDOWN_SEC = 60; const SMS_RESEND_COOLDOWN_SEC = 60;
const LOGO_SRC = logoSrc; const LOGO_SRC = logoSrc;
const LOGIN_TITLE_SRC = logoTitleSrc;
/** 短信验证码登录页:校验本地 token、发送验证码、提交登录 */ /** 短信验证码登录页:校验本地 token、发送验证码、提交登录 */
export default function LoginPage() { export default function LoginPage() {
@@ -127,18 +129,19 @@ export default function LoginPage() {
> >
{contextHolder} {contextHolder}
<section className="w-[325px] -translate-y-6"> <section className="w-[325px] -translate-y-6">
<div className="mb-7 flex items-center justify-center gap-2"> <div className="mb-7 flex items-center justify-center">
<img <img
src={LOGO_SRC} src={LOGO_SRC}
alt="ChatOne Logo" alt="ChatOne Logo"
width={28} className="h-10 w-10 shrink-0 object-contain"
height={28} decoding="async"
className="h-7 w-7 object-contain" />
<img
src={LOGIN_TITLE_SRC}
alt="chatone"
className="h-auto w-[150px] object-contain object-left"
decoding="async" decoding="async"
/> />
<Typography.Title level={3} className="mb-0! leading-none text-[#355ad9]">
ChatOne
</Typography.Title>
</div> </div>
<div className="space-y-5"> <div className="space-y-5">
@@ -201,7 +204,7 @@ export default function LoginPage() {
onClick={() => { onClick={() => {
void onLogin(); void onLogin();
}} }}
className="mt-1 h-[42px] rounded-full border-0 bg-[#3b5ff7]" className="mt-1 h-[42px] rounded-full border-0"
> >
</Button> </Button>