3 Commits
v0.1.1 ... main

Author SHA1 Message Date
64d3359981 fix(web): 窄屏顶栏右侧溢出 — flex 自动最小尺寸 + vw 限宽两处误算
两个原因叠加导致顶栏横向溢出:

1. "webui4frpc" 是不可断行单词,.sb-brand-text 没给 min-width:0 +
   overflow:hidden,其 flex 自动最小尺寸就等于 min-content(≈85px),
   顶栏因此拿不出空间给右侧身份区,超出部分溢出。现给品牌文字整条链路
   加可收缩约束,标题用 ellipsis 截断。

2. .sb-identity 用 max-width:42vw / .id-name 用 14vw 限宽:vw 含垂直
   滚动条宽度,比实际可用内容宽度大;且 max-width 只封顶盒子,内部
   flex:0 0 auto 的角色徽标与退出按钮仍会把它撑开。改为全链路
   min-width:0 + overflow:hidden,由 flex 自行分配(.sb-foot 也从
   flex:0 0 auto 改 0 1 auto,允许被压缩)。

另加 .sidebar { overflow-x: hidden } 作兜底,任何子项算错都不再产生
横向滚动条;≤380px 隐藏角色徽标(它不可收缩,"超级管理员"≈70px)。

验证:tsc --noEmit 通过、npm run build 通过、产物 CSS 已确认规则生效;
三节点部署 0.1.2 后环正常(cycle 推进、pending=0、topo=5)。
2026-09-03 08:50:23 +08:00
0559cc55bd fix(web): 窄屏底部导航栏错位到顶部 — 顶栏 backdrop-filter 创建了包含块
.sb-nav 用 position:fixed;bottom:0 想贴视口底部,但父元素 .sidebar 带
backdrop-filter。backdrop-filter 与 transform/filter 同理,会为后代的
position:fixed 创建【包含块】—— 于是 bottom:0 变成相对顶栏下沿定位而不是
视口,tab bar 贴在顶栏正下方,看起来就是固定在屏幕顶部。

窄屏下关掉顶栏的 backdrop-filter,改用近实色底
color-mix(var(--w4f-card-solid) 92%, transparent);玻璃模糊保留在
.sb-nav 自身(元素自己的 backdrop-filter 不影响自己的定位)。

顺带 bump 到 0.1.2(version 包 / release.sh / build_installers.sh /
rpm spec + changelog / README 安装示例文件名)。

验证:tsc --noEmit 通过、npm run build 通过;产物 CSS 中确认 720px 段的
.sidebar 已含 backdrop-filter:none;三节点部署后 /status 报告 0.1.2,
环正常(cycle 推进、pending=0、5 条转发 frpc 进程与 topology 归属一致)。
2026-09-03 08:45:22 +08:00
609f0df517 chore: upload_assets.py 默认包含原生安装包
默认文件筛选原来只匹配 tar.gz/zip/SHA256SUMS,deb/rpm/pkg/setup.exe
必须逐个显式传参才会上传(v0.1.0 与 v0.1.1 都是分两趟传的)。
改为按发布产物后缀白名单筛选;用 -setup.exe 而非裸 .exe,避免误收
bin/ 下的裸二进制。
2026-09-03 07:30:53 +08:00
7 changed files with 71 additions and 25 deletions

View File

@ -79,7 +79,7 @@ cd web && npm run build && rm -rf internal/httpapi/dist && cp -r web/dist intern
### Linux (Debian / Ubuntu) ### Linux (Debian / Ubuntu)
```bash ```bash
sudo dpkg -i webui4frpc-0.1.1-linux-amd64.deb # 或 linux-arm64.deb sudo dpkg -i webui4frpc-0.1.2-linux-amd64.deb # 或 linux-arm64.deb
sudo nano /etc/webui4frpc/webui4frpc.env # 改掉默认密码 sudo nano /etc/webui4frpc/webui4frpc.env # 改掉默认密码
sudo systemctl restart webui4frpc sudo systemctl restart webui4frpc
``` ```
@ -87,7 +87,7 @@ sudo systemctl restart webui4frpc
### Linux (RHEL / Fedora / openEuler / 默认 / 龙蜥) ### Linux (RHEL / Fedora / openEuler / 默认 / 龙蜥)
```bash ```bash
sudo rpm -i webui4frpc-0.1.1-linux-x86_64.rpm sudo rpm -i webui4frpc-0.1.2-linux-x86_64.rpm
sudo vi /etc/webui4frpc/webui4frpc.env sudo vi /etc/webui4frpc/webui4frpc.env
sudo systemctl enable --now webui4frpc sudo systemctl enable --now webui4frpc
``` ```
@ -97,7 +97,7 @@ sudo systemctl enable --now webui4frpc
### Windows ### Windows
双击 `webui4frpc-0.1.1-windows-amd64-setup.exe`ARM 设备用 `windows-arm64-setup.exe`)。 双击 `webui4frpc-0.1.2-windows-amd64-setup.exe`ARM 设备用 `windows-arm64-setup.exe`)。
安装向导会询问监听地址与管理员凭据,完成后: 安装向导会询问监听地址与管理员凭据,完成后:
- 程序装到 `C:\Program Files\webui4frpc` - 程序装到 `C:\Program Files\webui4frpc`
@ -107,8 +107,8 @@ sudo systemctl enable --now webui4frpc
### macOS ### macOS
```bash ```bash
sudo installer -pkg webui4frpc-0.1.1-darwin-arm64.pkg -target / # Apple Silicon sudo installer -pkg webui4frpc-0.1.2-darwin-arm64.pkg -target / # Apple Silicon
sudo installer -pkg webui4frpc-0.1.1-darwin-amd64.pkg -target / # Intel sudo installer -pkg webui4frpc-0.1.2-darwin-amd64.pkg -target / # Intel
``` ```
或直接双击 `.pkg` 走图形安装器。安装后 launchd 开机自启,配置在 或直接双击 `.pkg` 走图形安装器。安装后 launchd 开机自启,配置在
@ -126,7 +126,7 @@ sudo launchctl kickstart -k system/com.jianfeeeee.webui4frpc
不想装服务只想跑一下,用对应的 `.tar.gz` / `.zip`,解压即用: 不想装服务只想跑一下,用对应的 `.tar.gz` / `.zip`,解压即用:
```bash ```bash
tar xzf webui4frpc-0.1.1-linux-amd64.tar.gz tar xzf webui4frpc-0.1.2-linux-amd64.tar.gz
./webui4frpc -addr 127.0.0.1:7500 -user admin -password 你的密码 -workdir ./data ./webui4frpc -addr 127.0.0.1:7500 -user admin -password 你的密码 -workdir ./data
``` ```

View File

@ -2,11 +2,11 @@
// //
// Value is overridable at build time so release artifacts carry the real tag: // Value is overridable at build time so release artifacts carry the real tag:
// //
// go build -ldflags="-X webui4frpc/internal/version.Version=0.1.1" ./cmd/webui4frpc // go build -ldflags="-X webui4frpc/internal/version.Version=0.1.2" ./cmd/webui4frpc
// //
// Kept in its own package because both cmd/ and internal/httpapi report it // Kept in its own package because both cmd/ and internal/httpapi report it
// (main can't be imported, and httpapi must not depend on cmd). // (main can't be imported, and httpapi must not depend on cmd).
package version package version
// Version is the running build's semantic version, without a leading "v". // Version is the running build's semantic version, without a leading "v".
var Version = "0.1.1" var Version = "0.1.2"

View File

@ -1,5 +1,5 @@
Name: webui4frpc Name: webui4frpc
Version: %{?_w4f_version}%{!?_w4f_version:0.1.1} Version: %{?_w4f_version}%{!?_w4f_version:0.1.2}
Release: 1%{?dist} Release: 1%{?dist}
Summary: Visual frpc controller with token-ring cluster Summary: Visual frpc controller with token-ring cluster
License: MIT License: MIT
@ -67,6 +67,11 @@ fi
%doc %{_docdir}/webui4frpc/README.md %doc %{_docdir}/webui4frpc/README.md
%changelog %changelog
* Wed Sep 03 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.2-1
- 修复窄屏底部导航栏错位到顶部:顶栏的 backdrop-filter 会为
position:fixed 后代创建包含块,使 tab bar bottom:0 相对顶栏而
非视口定位。窄屏下关掉顶栏模糊,改用近实色底。
* Wed Sep 02 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.1-1 * Wed Sep 02 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.1-1
- 修复令牌环冻结:心跳到达时复活被误判 offline 的前驱; - 修复令牌环冻结:心跳到达时复活被误判 offline 的前驱;
全环无可达后继时保留 inflight leader 超时重发令牌。 全环无可达后继时保留 inflight leader 超时重发令牌。

View File

@ -12,7 +12,7 @@
# 在 release.sh 流程内被调用;依赖 dist/artifacts/<version>/bin/<os>-<arch>/ 下的二进制。 # 在 release.sh 流程内被调用;依赖 dist/artifacts/<version>/bin/<os>-<arch>/ 下的二进制。
set -euo pipefail set -euo pipefail
VERSION="${1:-0.1.1}" VERSION="${1:-0.1.2}"
VERSION="${VERSION#v}" VERSION="${VERSION#v}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/dist/artifacts/$VERSION" OUT="$ROOT/dist/artifacts/$VERSION"

View File

@ -3,7 +3,7 @@
# webui4frpc 多平台发布脚本 # webui4frpc 多平台发布脚本
# #
# 用法: # 用法:
# ./scripts/release.sh [version] # 默认 version=0.1.1 # ./scripts/release.sh [version] # 默认 version=0.1.2
# #
# 行为: # 行为:
# 1. 构建前端 (web/dist) 并同步到 internal/httpapi/dist (go:embed 用) # 1. 构建前端 (web/dist) 并同步到 internal/httpapi/dist (go:embed 用)
@ -19,7 +19,7 @@
# NO_BUILD_FRONTEND 设为 1 跳过前端构建 (用现有 dist) # NO_BUILD_FRONTEND 设为 1 跳过前端构建 (用现有 dist)
set -euo pipefail set -euo pipefail
VERSION="${1:-0.1.1}" VERSION="${1:-0.1.2}"
VERSION="${VERSION#v}" # 去掉可能的前导 v VERSION="${VERSION#v}" # 去掉可能的前导 v
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/dist/artifacts/$VERSION" OUT="$ROOT/dist/artifacts/$VERSION"

View File

@ -2,7 +2,8 @@
"""上传 release 资产到 gitcode两步取签名 URL → PUT 到 OBS """上传 release 资产到 gitcode两步取签名 URL → PUT 到 OBS
用法: upload_assets.py <version> <token> [file...] 用法: upload_assets.py <version> <token> [file...]
不传 file 时上传该版本目录下所有 tar.gz/zip 与 SHA256SUMS。 不传 file 时上传该版本目录下全部发布产物:
tar.gz / zip / deb / rpm / pkg / -setup.exe / SHA256SUMS
""" """
import json import json
import os import os
@ -38,6 +39,19 @@ def put_file(url: str, headers: dict, path: str) -> tuple[int, str]:
return e.code, e.read().decode("utf-8", "replace")[:300] return e.code, e.read().decode("utf-8", "replace")[:300]
# 发布产物后缀:免安装包 + 原生安装包。
# 注意 -setup.exe 而不是裸 .exe避开 bin/ 里的裸二进制。
ARTIFACT_SUFFIXES = (
".tar.gz", ".zip", # 免安装
".deb", ".rpm", ".pkg", # linux / macOS 安装包
"-setup.exe", # windows 安装器
)
def is_artifact(name: str) -> bool:
return name == "SHA256SUMS" or name.endswith(ARTIFACT_SUFFIXES)
def main() -> int: def main() -> int:
if len(sys.argv) < 3: if len(sys.argv) < 3:
print(__doc__) print(__doc__)
@ -47,10 +61,7 @@ def main() -> int:
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"dist", "artifacts", version, "dist", "artifacts", version,
) )
files = sys.argv[3:] or sorted( files = sys.argv[3:] or sorted(f for f in os.listdir(outdir) if is_artifact(f))
f for f in os.listdir(outdir)
if f.endswith((".tar.gz", ".zip")) or f == "SHA256SUMS"
)
failed = 0 failed = 0
for name in files: for name in files:
path = os.path.join(outdir, name) path = os.path.join(outdir, name)

View File

@ -384,16 +384,37 @@ const currentLabel = computed(() => nav.value.find((n) => n.key === view.value)?
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 10px 12px; padding: 10px 12px;
overflow: visible; overflow: hidden;
/* 兵家必争:任何子项算错都不得弄出横向滚动条 */
overflow-x: hidden;
border-right: none; border-right: none;
border-bottom: 1px solid var(--w4f-line); border-bottom: 1px solid var(--w4f-line);
padding-top: max(10px, env(safe-area-inset-top)); padding-top: max(10px, env(safe-area-inset-top));
/* 关键backdrop-filter 会为 position:fixed 后代创建【包含块】
(与 transform/filter 同理)。若保留它,下面 .sb-nav 的
bottom:0 就是相对这条顶栏定位而非视口,底部 tab bar 会贴在
顶栏下沿、看起来固定在屏幕顶部。因此窄屏必须关掉顶栏的玻璃
模糊,改用接近实色的底,模糊效果留在 .sb-nav 自己身上
(元素自身的 backdrop-filter 不影响它自己的定位)。 */
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: color-mix(in srgb, var(--w4f-card-solid) 92%, transparent);
} }
.sb-brand { .sb-brand {
padding: 0; padding: 0;
gap: 8px; gap: 8px;
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
overflow: hidden;
}
/* 品牌文字必须可收缩“webui4frpc”是不可断行单词不给 min-width:0
+ overflow:hidden 的话它的 flex 自动最小尺寸等于 min-content≨85px
顶栏就拿不出空间给右侧身份区,溢出为横向滚动。 */
.sb-brand-text { min-width: 0; overflow: hidden; }
.sb-brand-text b {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.sb-logo { width: 30px; height: 30px; border-radius: 10px; } .sb-logo { width: 30px; height: 30px; border-radius: 10px; }
.sb-brand-text b { font-size: 14.5px; } .sb-brand-text b { font-size: 14.5px; }
@ -442,23 +463,30 @@ const currentLabel = computed(() => nav.value.find((n) => n.key === view.value)?
box-shadow: none; box-shadow: none;
} }
/* 身份与主题折进顶条右侧 */ /* 身份与主题折进顶条右侧
不再用 vw 限宽vw 含垂直滚动条宽度,会比实际可用内容宽大;而且
max-width 只封顶盒子,内部 flex:0 0 auto 的徒章/按钮仍会撑出去。
改为全链路可收缩min-width:0 + overflow:hidden由 flex 自行分配。 */
.sb-foot { .sb-foot {
margin-top: 0; margin-top: 0;
padding-top: 0; padding-top: 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
flex: 0 0 auto; flex: 0 1 auto;
min-width: 0;
} }
.sb-identity { .sb-identity {
margin-bottom: 0; margin-bottom: 0;
padding: 5px 8px; padding: 5px 8px;
font-size: 11.5px; font-size: 11.5px;
max-width: 42vw; flex: 0 1 auto;
min-width: 0;
max-width: none;
overflow: hidden;
} }
.sb-identity .id-name { max-width: 14vw; } .sb-identity .id-name { min-width: 0; max-width: none; }
.sb-theme { margin-bottom: 0; } .sb-theme { margin-bottom: 0; flex: 0 0 auto; }
.sb-theme .sw { width: 22px; height: 22px; border-radius: 7px; } .sb-theme .sw { width: 22px; height: 22px; border-radius: 7px; }
.main { height: auto; flex: 1; min-height: 0; } .main { height: auto; flex: 1; min-height: 0; }
@ -470,10 +498,12 @@ const currentLabel = computed(() => nav.value.find((n) => n.key === view.value)?
} }
} }
/* 极窄(≤ 380pxiPhone SE / 小屏安卓):进一步压缩顶条 */ /* 极窄(≤ 380pxiPhone SE / 小屏安卓):进一步压缩顶条
角色徒章是 flex:0 0 auto 不可收缩的“超级管理员”≨70px极窄下隐去
用户名与退出按钮保留。 */
@media (max-width: 380px) { @media (max-width: 380px) {
.sb-brand-text b { font-size: 13px; } .sb-brand-text b { font-size: 13px; }
.sb-identity { max-width: 38vw; padding: 4px 7px; } .sb-identity { padding: 4px 7px; }
.sb-identity .id-level { display: none; } .sb-identity .id-level { display: none; }
.sb-i { font-size: 9.5px; } .sb-i { font-size: 9.5px; }
.content { padding-left: 10px; padding-right: 10px; } .content { padding-left: 10px; padding-right: 10px; }