搭出前端骨架和入站列表
设计基调定为:层次靠底色和一像素描边而不是投影,一屏最多两层容器,间距给足。 tokens.css 顶部写了这三条规则,后面的组件都是它们的推论。 入站列表把两套写法合并成一张表:老式顶层端口字段(mixed-port 这些)和 listeners 数组。 只画 listeners 的话,一台只用 mixed-port 的机器打开会是空板,而那个端口正在跑—— 这等于对用户撒谎。合并逻辑在 shared/inbounds.ts,带 10 个测试。 后端顺带能提供打包后的静态文件了,一个进程就能跑起来。
This commit is contained in:
+20
-1
@@ -42,12 +42,31 @@ function applyFailureStatus(stage: string): number {
|
||||
return 500 // write / reload:服务端或内核的问题
|
||||
}
|
||||
|
||||
/** 打包后的前端。开发时前端由 Vite 提供并把 /api 转发过来,走不到这里。 */
|
||||
const WEB_DIST = new URL('../web-dist/', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1')
|
||||
|
||||
/**
|
||||
* 静态文件不需要令牌——它们只是一个空壳,所有数据都要带令牌才拿得到。
|
||||
* 单页应用的路由由前端接管,所以找不到的路径一律回 index.html。
|
||||
*/
|
||||
async function serveStatic(path: string): Promise<Response> {
|
||||
const target = Bun.file(WEB_DIST + (path === '/' ? 'index.html' : path.slice(1)))
|
||||
if (await target.exists()) return new Response(target)
|
||||
|
||||
const shell = Bun.file(`${WEB_DIST}index.html`)
|
||||
if (await shell.exists()) return new Response(shell)
|
||||
return new Response('前端还没打包。先运行 bun run build,或者开发时用 bun run dev:web。', {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
||||
})
|
||||
}
|
||||
|
||||
export function createRouter(env: Env, token: string) {
|
||||
return async function handle(req: Request): Promise<Response> {
|
||||
const url = new URL(req.url)
|
||||
const path = url.pathname
|
||||
|
||||
if (!path.startsWith('/api/')) return json({ error: '没有这个接口' }, 404)
|
||||
if (!path.startsWith('/api/')) return serveStatic(path)
|
||||
|
||||
if (!tokenMatches(token, tokenFromRequest(req))) {
|
||||
return json({ error: '令牌不对。它在配置文件旁边的 .patchbay-token 里。' }, 401)
|
||||
|
||||
Reference in New Issue
Block a user