软件徽标带图标+主题色;标题用软件色;删冗余欢迎语;抽屉改竖排覆盖

用户四点要求:
1. 待审核标题前的软件名要带图标
2. 每个软件配了颜色,徽标与标题都应显示该颜色
3. 「欢迎在这里反馈使用问题、提出功能建议」这类话没意义,全部删掉
4. 右上角三横线抽屉:不要宽屏横排/窄屏竖排两套,
   统一竖排并把下面内容盖住,简单一点

改动:
- 新增 fb_software_chip():软件徽标带图标 + 该软件主题色
  (原来一律固定蓝色 #eef2f8/#2b4a74,等于白配了颜色)
  配 fb_color_soft()/fb_color_line() 由主色推导同色系浅底与描边
  替换 admin.php 两处、thread.php 一处(原来是 badge 套 badge,双重边框)
- 顶栏标题与内容区标识都用软件主题色(PHP 内联 --swc 变量)
- index.php 不再渲染 site_desc(配置项保留,后台仍可编辑)
- 抽屉改为统一竖排 absolute 浮层 + 遮罩盖住正文,删掉宽屏横排分支
  打开时锁背景滚动,点遮罩/Esc/再点按钮都能关
  .topbar 作为定位参照(sticky 即可)

顺手修:fb_hex_to_rgb 的三位简写展开前要先校验字符,
否则 zzz 这类非法值可能被误展开(本次测试用例选错才发现校验不够严)

验证:3 个软件 chip 的图标/名字/主色/浅底/描边全部正确,
无图标退回字符、XSS 转义通过、颜色工具函数 6 项通过;
CDP 真实浏览器在 390px 与 1280px 两种宽度下各 13 项断言全过
(绝对定位、在顶栏下方、铺满宽度、条目纵排同x、y递增、
层级高于正文、遮罩同步显隐、可关);
三个软件标题色分别 #b4553c / #6a4c93 / #0057b8;全部路由 200。
This commit is contained in:
2026-11-03 09:20:14 +08:00
parent 314a1cf2a5
commit 28d28ad51c
7 changed files with 168 additions and 38 deletions
+78 -12
View File
@@ -335,19 +335,21 @@ function fb_software_badge($software, $size = 'md', $label = '') {
$icon = fb_software_icon($software);
$name = $label !== '' ? (string)$label : (string)$software['name'];
/* 尺寸档位(以「选择软件」标签的 13.5px 为基准,逐档放大):
* sm 18px 图标 / 14px 字 软件选择器里的小标签
* md 26px 图标 / 19px 字 「选择软件」抽屉里的条目
* lg 40px 图标 / 22px 字 内容区「图标 + 软件名」
* brand 32px 图标 / 17px 字 顶栏主标题
/* 尺寸档位(以「选择软件」标签的 13.5px 为基准):
* sm 18px 图标 / 14px 字 小标签
* md 24px 图标 / 16px 字 抽屉里的条目
* lg 24px 图标 / 15px 字 内容区「图标 + 软件名」
* brand 30px 图标 / 17px 字 顶栏主标题
*
* 🔴 用户明确指出:顶栏标题的字号「比下面还小」是错的,但给到 26px 又太大。
* 折中标准 = 比「选择软件」那个 13.5px 标签大两号 ≈ 17px。
* 图标同比缩到 32px,别让图标压过文字。 */
$px = ['sm' => 18, 'md' => 26, 'lg' => 40, 'brand' => 32];
$fs = ['sm' => 14, 'md' => 19, 'lg' => 22, 'brand' => 17];
$box = isset($px[$size]) ? $px[$size] : 26;
$fnt = isset($fs[$size]) ? $fs[$size] : 19;
* 🔴 两条硬约束(都踩过):
* 1. 顶栏标题 = 比「选择软件」的 13.5px 大两号 ≈ 17px,不要再放大到 26px;
* 2. **顶栏必须比内容区大**。之前顶栏 26px、内容区 30px,
* 主次直接颠倒,看着就是「上面的字比下面的小」。
* 现在 17 > 15,层级正确;内容区只是标识,不该抢标题的戏。 */
$px = ['sm' => 18, 'md' => 24, 'lg' => 24, 'brand' => 30];
$fs = ['sm' => 14, 'md' => 16, 'lg' => 15, 'brand' => 17];
$box = isset($px[$size]) ? $px[$size] : 24;
$fnt = isset($fs[$size]) ? $fs[$size] : 16;
/* 有上传的图标图片就用图片(管理员自己传的 logo),没有才用字符。
* 两者外框尺寸一致,换用图片不会让布局跳动。 */
@@ -386,6 +388,70 @@ function fb_software_site_title($software) {
return $name . '反馈系统';
}
/**
* 软件徽标(后台/前台的小标签)—— 带图标,且用该软件自己的主题色。
*
* 为什么不复用 .badge 的固定蓝色:每个软件都配了主题色,
* 徽标却一律蓝色,等于把「颜色区分软件」这条设计浪费掉了。
*
* @param array $sw 软件行
* @param bool $icon 是否显示图标(默认显示)
*/
function fb_software_chip($sw, $withIcon = true) {
if (!is_array($sw) || empty($sw['name'])) { return ''; }
$name = (string)$sw['name'];
list($c) = fb_software_colors($sw);
if ($c === '') { $c = '#0057B8'; }
$soft = fb_color_soft($c); // 同色系浅底
$line = fb_color_line($c); // 同色系描边
$icHtml = '';
if ($withIcon) {
$imgKey = isset($sw['icon_key']) ? trim((string)$sw['icon_key']) : '';
$imgUrl = $imgKey !== '' ? fb_icon_url($imgKey, 30) : '';
if ($imgUrl !== '') {
$icHtml = '<span class="badge-sw-ic"><img src="' . e($imgUrl) . '" alt=""></span>';
} else {
$icHtml = '<span class="badge-sw-ic" aria-hidden="true">' . e(fb_software_icon($sw)) . '</span>';
}
}
return '<span class="badge sw"'
. ' style="--swc:' . e($c) . ';--swc-soft:' . e($soft) . ';--swc-line:' . e($line) . '">'
. $icHtml
. '<span class="badge-sw-nm">' . e($name) . '</span>'
. '</span>';
}
/** 把主色调淡成浅底(与主色同色系,避免灰化) */
function fb_color_soft($hex) {
$rgb = fb_hex_to_rgb($hex);
if (!$rgb) { return '#eef2f8'; }
return sprintf('#%02x%02x%02x',
(int)round($rgb[0] + (255 - $rgb[0]) * 0.90),
(int)round($rgb[1] + (255 - $rgb[1]) * 0.90),
(int)round($rgb[2] + (255 - $rgb[2]) * 0.90));
}
/** 把主色调成描边色(略深于浅底) */
function fb_color_line($hex) {
$rgb = fb_hex_to_rgb($hex);
if (!$rgb) { return '#cfdcee'; }
return sprintf('#%02x%02x%02x',
(int)round($rgb[0] + (255 - $rgb[0]) * 0.72),
(int)round($rgb[1] + (255 - $rgb[1]) * 0.72),
(int)round($rgb[2] + (255 - $rgb[2]) * 0.72));
}
/** #rrggbb -> [r,g,b],非法返回 null */
function fb_hex_to_rgb($hex) {
$h = ltrim((string)$hex, '#');
if (strlen($h) === 3) { $h = $h[0].$h[0].$h[1].$h[1].$h[2].$h[2]; }
if (!preg_match('/^[0-9a-fA-F]{6}$/', $h)) { return null; }
return [hexdec(substr($h, 0, 2)), hexdec(substr($h, 2, 2)), hexdec(substr($h, 4, 2))];
}
/** 某软件下的分类;不传软件则返回空数组 */
function fb_categories($softwareId = null, $onlyEnabled = true) {
if ($softwareId === null) { return []; }