仪表盘和订阅详情的操作按钮改 text-button,公网 IP 带旗帜

检测公网 IP、重启内核、订阅详情右上三个按钮都去掉边框,hover 出浅底。
检测结果由国家代码换成旗帜 emoji 加 IP;Windows 的系统字体没有旗帜
字形,浏览器会退回显示两个字母,和原来的效果一致。
This commit is contained in:
2026-08-12 13:17:21 +08:00
parent a40bd6a01b
commit 129a76696b
4 changed files with 62 additions and 22 deletions
+14 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'bun:test'
import { formatAgo, formatBytes } from './format.ts'
import { flagEmoji, formatAgo, formatBytes } from './format.ts'
describe('流量数字', () => {
it('零和不满 1KB 的按字节显示,不带小数', () => {
@@ -29,6 +29,19 @@ describe('流量数字', () => {
})
})
describe('旗帜 emoji', () => {
it('两位国家代码转成区域指示符对,大小写都认', () => {
expect(flagEmoji('JP')).toBe('🇯🇵')
expect(flagEmoji('us')).toBe('🇺🇸')
})
it('不像国家代码的输入原样返回', () => {
expect(flagEmoji('')).toBe('')
expect(flagEmoji('USA')).toBe('USA')
expect(flagEmoji('1X')).toBe('1X')
})
})
describe('相对时间', () => {
const now = new Date('2026-08-12T12:00:00Z')
const ago = (ms: number) => new Date(now.getTime() - ms)
+11
View File
@@ -33,6 +33,17 @@ export function formatAgo(at: Date, now: Date): string {
return `${String(at.getFullYear())}-${p(at.getMonth() + 1)}-${p(at.getDate())}`
}
/**
* 两位国家代码转成旗帜 emoji(区域指示符对)。不像国家代码的输入原样返回,
* 显示端至少还有字母可看。注意 Windows 的系统字体没有旗帜字形,浏览器会
* 把区域指示符退回显示成两个字母。
*/
export function flagEmoji(countryCode: string): string {
const code = countryCode.trim().toUpperCase()
if (!/^[A-Z]{2}$/.test(code)) return countryCode
return String.fromCodePoint(...[...code].map((ch) => 0x1f1e6 + (ch.codePointAt(0) ?? 65) - 65))
}
/** 运行时长。一小时内说分钟,一天内说时分,再长说天和小时;秒级抖动没有信息量。 */
export function formatUptime(seconds: number): string {
if (!Number.isFinite(seconds) || seconds < 0) return '—'