feat(branding): 启用新版 SVG logo 并在 README 头部展示

- 新增 assets/logo.svg 作为项目默认 logo(512x512 深色圆角底 + 渐变 S 标)
- 前端 favicon 与组件兜底 logo 由 logo.png 切换为 frontend/public/logo.svg
- 三个 README(EN/CN/JA)头部新增居中 logo 与标题布局
- 删除旧 logo.png 及多余的 lobe 变体 SVG
This commit is contained in:
shaw
2026-07-20 16:06:59 +08:00
parent 2e5973b165
commit fa402b909a
13 changed files with 84 additions and 14 deletions
+4 -2
View File
@@ -1,7 +1,9 @@
# Sub2API
<div align="center">
<img src="assets/logo.svg" alt="Sub2API Logo" width="128" />
# Sub2API
[![Go](https://img.shields.io/badge/Go-1.25.7-00ADD8.svg)](https://golang.org/)
[![Vue](https://img.shields.io/badge/Vue-3.4+-4FC08D.svg)](https://vuejs.org/)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15+-336791.svg)](https://www.postgresql.org/)
+4 -2
View File
@@ -1,7 +1,9 @@
# Sub2API
<div align="center">
<img src="assets/logo.svg" alt="Sub2API Logo" width="128" />
# Sub2API
[![Go](https://img.shields.io/badge/Go-1.25.7-00ADD8.svg)](https://golang.org/)
[![Vue](https://img.shields.io/badge/Vue-3.4+-4FC08D.svg)](https://vuejs.org/)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15+-336791.svg)](https://www.postgresql.org/)
+4 -2
View File
@@ -1,7 +1,9 @@
# Sub2API
<div align="center">
<img src="assets/logo.svg" alt="Sub2API Logo" width="128" />
# Sub2API
[![Go](https://img.shields.io/badge/Go-1.25.7-00ADD8.svg)](https://golang.org/)
[![Vue](https://img.shields.io/badge/Vue-3.4+-4FC08D.svg)](https://vuejs.org/)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15+-336791.svg)](https://www.postgresql.org/)
+32
View File
@@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title desc">
<title id="title">Sub2API</title>
<desc id="desc">An interlocking S symbol representing subscription routing into APIs.</desc>
<defs>
<linearGradient id="s2a-bg" x1="72" y1="44" x2="442" y2="478" gradientUnits="userSpaceOnUse">
<stop stop-color="#142B56"/>
<stop offset=".52" stop-color="#0A1A39"/>
<stop offset="1" stop-color="#061127"/>
</linearGradient>
<radialGradient id="s2a-ambient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(168 92) rotate(51) scale(342 382)">
<stop stop-color="#3E68B0" stop-opacity=".28"/>
<stop offset="1" stop-color="#3E68B0" stop-opacity="0"/>
</radialGradient>
<linearGradient id="s2a-brand" x1="4" y1="4" x2="20" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#79F4BD"/>
<stop offset=".48" stop-color="#39D9E7"/>
<stop offset="1" stop-color="#3875F6"/>
</linearGradient>
<filter id="s2a-shadow" x="-25%" y="-25%" width="150%" height="165%" color-interpolation-filters="sRGB">
<feDropShadow dx="0" dy=".55" stdDeviation=".65" flood-color="#020817" flood-opacity=".34"/>
</filter>
</defs>
<rect x="16" y="16" width="480" height="480" rx="120" fill="url(#s2a-bg)"/>
<rect x="16" y="16" width="480" height="480" rx="120" fill="url(#s2a-ambient)"/>
<rect x="16.75" y="16.75" width="478.5" height="478.5" rx="119.25" fill="none" stroke="#A5BFFF" stroke-opacity=".16" stroke-width="1.5"/>
<g transform="translate(52 52) scale(17)" fill="none" stroke="url(#s2a-brand)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.7" filter="url(#s2a-shadow)">
<path d="m19.25 7.65-2.55-3.2a1.33 1.33 0 0 0-1.03-.5H8.58c-.34 0-.67.13-.91.37L4.15 7.65c-.93.88-.6 1.52.65 2.3l9.55 5.97"/>
<path d="m4.75 16.35 2.55 3.2c.25.31.63.5 1.03.5h7.09c.34 0 .67-.13.91-.37l3.52-3.33c.93-.88.6-1.52-.65-2.3L9.65 8.08"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+1 -1
View File
@@ -2,7 +2,7 @@
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/logo.png" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sub2API - AI API Gateway</title>
</head>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

+32
View File
@@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title desc">
<title id="title">Sub2API</title>
<desc id="desc">An interlocking S symbol representing subscription routing into APIs.</desc>
<defs>
<linearGradient id="s2a-bg" x1="72" y1="44" x2="442" y2="478" gradientUnits="userSpaceOnUse">
<stop stop-color="#142B56"/>
<stop offset=".52" stop-color="#0A1A39"/>
<stop offset="1" stop-color="#061127"/>
</linearGradient>
<radialGradient id="s2a-ambient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(168 92) rotate(51) scale(342 382)">
<stop stop-color="#3E68B0" stop-opacity=".28"/>
<stop offset="1" stop-color="#3E68B0" stop-opacity="0"/>
</radialGradient>
<linearGradient id="s2a-brand" x1="4" y1="4" x2="20" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#79F4BD"/>
<stop offset=".48" stop-color="#39D9E7"/>
<stop offset="1" stop-color="#3875F6"/>
</linearGradient>
<filter id="s2a-shadow" x="-25%" y="-25%" width="150%" height="165%" color-interpolation-filters="sRGB">
<feDropShadow dx="0" dy=".55" stdDeviation=".65" flood-color="#020817" flood-opacity=".34"/>
</filter>
</defs>
<rect x="16" y="16" width="480" height="480" rx="120" fill="url(#s2a-bg)"/>
<rect x="16" y="16" width="480" height="480" rx="120" fill="url(#s2a-ambient)"/>
<rect x="16.75" y="16.75" width="478.5" height="478.5" rx="119.25" fill="none" stroke="#A5BFFF" stroke-opacity=".16" stroke-width="1.5"/>
<g transform="translate(52 52) scale(17)" fill="none" stroke="url(#s2a-brand)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.7" filter="url(#s2a-shadow)">
<path d="m19.25 7.65-2.55-3.2a1.33 1.33 0 0 0-1.03-.5H8.58c-.34 0-.67.13-.91.37L4.15 7.65c-.93.88-.6 1.52.65 2.3l9.55 5.97"/>
<path d="m4.75 16.35 2.55 3.2c.25.31.63.5 1.03.5h7.09c.34 0 .67-.13.91-.37l3.52-3.33c.93-.88.6-1.52-.65-2.3L9.65 8.08"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -14,7 +14,7 @@
class="sidebar-logo flex h-9 w-9 items-center justify-center overflow-hidden rounded-xl shadow-glow transition-opacity hover:opacity-80"
@click="handleMenuItemClick(homePath)"
>
<img v-if="settingsLoaded" :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<img v-if="settingsLoaded" :src="siteLogo || '/logo.svg'" alt="Logo" class="h-full w-full object-contain" />
</router-link>
<div class="sidebar-brand" :class="{ 'sidebar-brand-collapsed': sidebarCollapsed }" :aria-hidden="sidebarCollapsed ? 'true' : 'false'">
<router-link
@@ -33,7 +33,7 @@
<div
class="mb-4 inline-flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl shadow-lg shadow-primary-500/30"
>
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<img :src="siteLogo || '/logo.svg'" alt="Logo" class="h-full w-full object-contain" />
</div>
<h1 class="text-gradient mb-2 text-3xl font-bold">
{{ siteName }}
@@ -3,7 +3,7 @@ import { updateFavicon } from '@/utils/branding'
describe('updateFavicon', () => {
beforeEach(() => {
document.head.innerHTML = '<link rel="icon" href="/logo.png">'
document.head.innerHTML = '<link rel="icon" href="/logo.svg">'
})
it('replaces the default favicon with the configured logo', () => {
@@ -17,6 +17,6 @@ describe('updateFavicon', () => {
updateFavicon('javascript:alert(1)')
const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
expect(link?.getAttribute('href')).toBe('/logo.png')
expect(link?.getAttribute('href')).toBe('/logo.svg')
})
})
+1 -1
View File
@@ -42,7 +42,7 @@
<!-- Logo -->
<div class="flex items-center">
<div class="h-10 w-10 overflow-hidden rounded-xl shadow-md">
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<img :src="siteLogo || '/logo.svg'" alt="Logo" class="h-full w-full object-contain" />
</div>
</div>
+1 -1
View File
@@ -5,7 +5,7 @@
<nav class="mx-auto flex max-w-6xl items-center justify-between">
<router-link to="/home" class="flex items-center gap-3">
<div class="h-10 w-10 overflow-hidden rounded-xl shadow-md">
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<img :src="siteLogo || '/logo.svg'" alt="Logo" class="h-full w-full object-contain" />
</div>
<span class="text-lg font-semibold tracking-tight text-gray-900 dark:text-white">{{ siteName }}</span>
</router-link>
@@ -5,7 +5,7 @@
<RouterLink to="/home" class="flex min-w-0 items-center gap-3">
<template v-if="settings">
<span class="flex h-10 w-10 flex-shrink-0 items-center justify-center overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-200 dark:bg-dark-800 dark:ring-dark-700">
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<img :src="siteLogo || '/logo.svg'" alt="Logo" class="h-full w-full object-contain" />
</span>
<span class="truncate text-base font-semibold text-gray-950 dark:text-white">
{{ siteName }}