优化管理前端 || Optimize management front-end#3603
Conversation
| // oxlint-disable-next-line func-names | ||
| module.exports = function () { | ||
| return (ctx) => { | ||
| const uiBasePath = getUiBasePath(ctx.path); |
There was a problem hiding this comment.
想知道这部分的修改是为什么?是想要创建后台的本地开发环境吗?
There was a problem hiding this comment.
开发的时候应该直接 pnpm run admin:dev 启动就可以了,不用这个这么麻烦吧?
这里面比较多的代码写的比较 for devlopment 不太适合放到 production 逻辑里来。
| })} | ||
| > | ||
| {React.createElement(Icons[social])} | ||
| <img |
There was a problem hiding this comment.
需要将 Icon SVG 通过 React Component 的形式引入,因为 hover 的时候有一个颜色的变化,这个通过 img 引入是没办法做到的。
| @@ -0,0 +1,7 @@ | |||
| export const uiBase = /\/ui(?:\/|$)/u.test(location.pathname) ? '/ui' : ''; | |||
|
|
|||
| export const getUiPath = (path = '') => { | |||
There was a problem hiding this comment.
get,不过我看你是不是移除了这个逻辑了已经?看最新的 commit 里面没有这个方法了。
There was a problem hiding this comment.
Pull request overview
This PR focuses on improving Waline’s admin UI appearance and robustness by refactoring the admin header styling/layout, making /ui path handling less hard-coded, and adjusting how admin assets (JS/CSS/icons) and avatars are resolved.
Changes:
- Refactor admin header UI and switch admin styles from SCSS entry to a CSS import bundle.
- Introduce utilities for
/uipath generation and social icon URL resolution; replace SVG-as-React-component icons with<img>assets. - Update server dashboard middleware to optionally serve a local admin bundle and adjust default avatar URL generation.
Reviewed changes
Copilot reviewed 14 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/server/src/service/avatar.js | Switch default avatar URL template to a different Gravatar mirror with query params. |
| packages/server/src/middleware/dashboard.js | Add local admin bundle detection/serving and dynamic /ui base path extraction. |
| packages/admin/src/utils/ui.js | Add getUiPath helper to avoid hard-coded /ui in navigation. |
| packages/admin/src/utils/socialIcon.js | Add helper to map OAuth provider names to local SVG asset URLs. |
| packages/admin/src/style/style.css | Adjust nav hover/focus selectors and remove a border rule. |
| packages/admin/src/style/index.css | New CSS entry file to import normalize/base/grid/custom styles. |
| packages/admin/src/style/custom.css | New large custom stylesheet for updated admin UI theme and layout. |
| packages/admin/src/pages/user/index.jsx | Replace icon components with social icon <img> rendering. |
| packages/admin/src/pages/profile/index.jsx | Use buildAvatar for profile avatar and replace icon components with <img>. |
| packages/admin/src/pages/manage-comments/utils.js | Update buildAvatar behavior to avoid using SVG data URLs and align default mirror URL. |
| packages/admin/src/pages/login/index.jsx | Use captcha hook import and replace icon components with social icon <img> rendering. |
| packages/admin/src/index.jsx | Switch style entry to CSS and add body/container classes for new styling. |
| packages/admin/src/img/weibo.svg | Add SVG asset for Weibo icon. |
| packages/admin/src/img/twitter.svg | Add SVG asset for Twitter icon. |
| packages/admin/src/img/qq.svg | Add SVG asset for QQ icon. |
| packages/admin/src/img/oidc.svg | Add SVG asset for OIDC icon. |
| packages/admin/src/img/huawei.svg | Add SVG asset for Huawei icon. |
| packages/admin/src/img/google.svg | Add SVG asset for Google icon. |
| packages/admin/src/img/github.svg | Add SVG asset for GitHub icon. |
| packages/admin/src/img/facebook.svg | Add SVG asset for Facebook icon. |
| packages/admin/src/components/icon/index.js | Remove old SVGR-based icon exports. |
| packages/admin/src/components/Header.jsx | Refactor header markup, use getUiPath, and render user avatar with buildAvatar. |
| error.log | Adds a local runtime log file (should not be committed). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .upgrade-tips { | ||
| padding: 0 10px; | ||
| border-bottom: 1px solid rgb(212 167 44 / 40%); | ||
|
|
||
| background: #fff8c5; | ||
| color: #24292f; | ||
|
|
||
| line-height: 36px; | ||
| } | ||
|
|
| case 'huawei': | ||
| return new URL('../img/huawei.svg', import.meta.url).href; | ||
| default: | ||
| return ''; |
| background: var(--wa-surface-soft); | ||
| } | ||
|
|
||
| @media (width <= 960px) { |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| /> | ||
| )); | ||
|
|
||
| export const getSocialIcon = (social) => { |
There was a problem hiding this comment.
感觉你这么改之后,和我原来 components/icon/index.js 里的逻辑就是一致的了,没什么改造的必要了?
There was a problem hiding this comment.
改之前的代码在我的电脑上开发时浏览器会把图标当作JS加载,好像打包后不会
There was a problem hiding this comment.
感觉你这么改之后,和我原来 components/icon/index.js 里的逻辑就是一致的了,没什么改造的必要了?
我现在改成了components/icon/index.jsx,和以前的逻辑差不多,但开发时SVG不会被作为JS加载
There was a problem hiding this comment.
嗯嗯,好的,之前引入的方式会有什么问题么,我比较倾向于使用 import 的形式直接将 svg 文件加载成 React 组件。
There was a problem hiding this comment.
嗯嗯,好的,之前引入的方式会有什么问题么,我比较倾向于使用 import 的形式直接将 svg 文件加载成 React 组件。
我改成直接在components/icon/index.jsx中定义常量了
There was a problem hiding this comment.
嗯嗯,好的,之前引入的方式会有什么问题么,我比较倾向于使用 import 的形式直接将 svg 文件加载成 React 组件。
import的话开发时会被当作JS加载,改成定义常量可以避免这个问题
There was a problem hiding this comment.
常量不也是 JS 吗?
现在在开发时浏览器请求的components/icon/index.jsx如下
const React = __vite__cjsImport0_react;
const _jsxDEV = __vite__cjsImport1_react_jsxDevRuntime["jsxDEV"];
const _Fragment = __vite__cjsImport1_react_jsxDevRuntime["Fragment"];
import __vite__cjsImport0_react from "/node_modules/.vite/deps/react.js?v=34ec03ef";
var _jsxFileName = "/Users/zhangjiahui/waline/packages/admin/src/components/icon/index.jsx";
import __vite__cjsImport1_react_jsxDevRuntime from "/node_modules/.vite/deps/react_jsx-dev-runtime.js?v=34ec03ef";
const createSvg = (viewBox, children) => function SocialIcon(props) {
return /* @__PURE__ */
_jsxDEV("svg", {
viewBox,
xmlns: "http://www.w3.org/2000/svg",
...props,
children
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 7
}, this);
}
;
export const github = createSvg("0 0 1024 1024", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M512 0C229.12 0 0 229.12 0 512c0 226.56 146.56 417.92 350.08 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-.64-52.48-.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-.64-33.92 40.32-.64 69.12 37.12 78.72 52.48 46.08 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.04-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28 43.52 0 87.04 5.76 128 17.28 97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-.64 123.52-.64 140.8 0 13.44 9.6 29.44 35.2 24.32C877.44 929.92 1024 737.92 1024 512 1024 229.12 794.88 0 512 0z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 13,
columnNumber: 3
}, this));
export const twitter = createSvg("126.444 2.281 589 589", /* @__PURE__ */
_jsxDEV(_Fragment, {
children: [/* @__PURE__ */
_jsxDEV("circle", {
cx: "420.944",
cy: "296.781",
r: "294.5",
fill: "currentColor"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 21,
columnNumber: 5
}, this), /* @__PURE__ */
_jsxDEV("path", {
fill: "#fff",
d: "M609.773 179.634c-13.891 6.164-28.811 10.331-44.498 12.204 16.01-9.587 28.275-24.779 34.066-42.86a154.78 154.78 0 0 1-49.209 18.801c-14.125-15.056-34.267-24.456-56.551-24.456-42.773 0-77.462 34.675-77.462 77.473 0 6.064.683 11.98 1.996 17.66-64.389-3.236-121.474-34.079-159.684-80.945-6.672 11.446-10.491 24.754-10.491 38.953 0 26.875 13.679 50.587 34.464 64.477a77.122 77.122 0 0 1-35.097-9.686v.979c0 37.54 26.701 68.842 62.145 75.961-6.511 1.784-13.344 2.716-20.413 2.716-4.998 0-9.847-.473-14.584-1.364 9.859 30.769 38.471 53.166 72.363 53.799-26.515 20.785-59.925 33.175-96.212 33.175-6.25 0-12.427-.373-18.491-1.104 34.291 21.988 75.006 34.824 118.759 34.824 142.496 0 220.428-118.052 220.428-220.428 0-3.361-.074-6.697-.236-10.021a157.855 157.855 0 0 0 38.707-40.158z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 22,
columnNumber: 5
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 20,
columnNumber: 3
}, this));
export const facebook = createSvg("0 0 32 32", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 23.9861 5.85096 30.6053 13.5 31.8056V20.625H9.43751V16H13.5V12.475C13.5 8.465 15.8887 6.25001 19.5434 6.25001C21.294 6.25001 23.125 6.5625 23.125 6.5625V10.5H21.1074C19.1198 10.5 18.5 11.7334 18.5 12.9987V16H22.9375L22.2281 20.625H18.5V31.8056C26.149 30.6053 32 23.9861 32 16"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 30,
columnNumber: 3
}, this));
export const weibo = createSvg("0 0 24 24", /* @__PURE__ */
_jsxDEV(_Fragment, {
children: [/* @__PURE__ */
_jsxDEV("circle", {
cx: "12",
cy: "12",
r: "12",
fill: "currentColor"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 38,
columnNumber: 5
}, this), /* @__PURE__ */
_jsxDEV("path", {
fill: "#fff",
d: "M19.3945 9.4904c.0639.8284-.0762 1.821-.6232 1.8696-.8928.0798-.4271-.9037-.4154-1.4957.0327-1.7159-1.4321-2.9081-2.8669-2.9081-.4065 0-1.3506.2755-1.2052-.5817.0654-.378.3856-.3727.7062-.4154 2.4131-.3218 4.235 1.3382 4.4045 3.5313Zm-3.947 1.9944c1.0374.5676 2.2838.8502 2.0771 2.5346-.0495.4036-.2938.9429-.5399 1.2873-1.7536 2.4548-7.0427 3.4866-10.3456 1.6208-1.1077-.6261-2.254-1.5417-2.0771-3.3659.1522-1.5699 1.2078-2.786 2.2437-3.8219.9882-.9888 2.0303-1.7624 3.4483-2.1189 1.5384-.3868 1.9932.8958 1.5787 2.1604.8911-.0598 2.7795-1.0545 3.6147-.083.3683.4288.2273 1.1954 0 1.7873Zm-1.1219 3.9883c.3324-.3768.6665-.9511.6644-1.62-.0044-2.0648-2.6055-2.8275-4.6529-2.6591-1.1198.0918-1.8731.3282-2.6591.7895-.6414.3765-1.3921.9891-1.5787 1.9108-.4201 2.0727 1.8343 3.0468 3.4898 3.1575 1.9123.1285 3.8269-.5468 4.7359-1.5787Zm3.0327-5.9827c.0871.6326-.0939 1.1807-.4569 1.2049-.6052.0403-.3789-.4145-.4157-.9555-.023-.3332-.2991-.718-.5402-.831-.4728-.2214-1.2049.1613-1.2049-.4984 0-.4898.4248-.4389.665-.4572 1.0518-.0798 1.8296.6453 1.9527 1.5372ZM12.4976 13.6453c.8852 2.6753-3.7268 3.9193-4.5702 1.6202-.5643-1.5375.7907-2.7604 2.2019-2.9081 1.2049-.1261 2.1023.4883 2.3683 1.2879Zm-2.119 1.87c.1878.325.6197.0916.5817-.166-.0443-.2987-.5848-.2545-.5817.166Zm-.748 1.4128c.7754-.1846.8796-1.645-.2908-1.3712-1.084.2296-.8939 1.6287.2908 1.3712Z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 39,
columnNumber: 5
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 37,
columnNumber: 3
}, this));
export const qq = createSvg("0 0 1024 1024", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M512 1024C794.77 1024 1024 794.77 1024 512C1024 229.23 794.77 0 512 0C229.23 0 0 229.23 0 512C0 794.77 229.23 1024 512 1024ZM718.383 488.193C734.622 528.473 746.254 557.323 756.601 590.562C783.163 676.031 774.57 711.422 767.929 712.281C753.867 714 713.163 647.906 713.163 647.906C713.163 686.109 693.476 736.031 650.82 772.125C671.367 778.453 717.773 795.562 706.757 814.156C697.851 829.234 553.476 823.766 511.835 819.078C470.195 823.766 325.82 829.234 316.913 814.156C305.898 795.484 352.226 778.453 372.851 772.125C330.195 736.109 310.507 686.188 310.507 647.906C310.507 647.906 269.804 714 255.742 712.281C249.179 711.5 240.585 676.109 267.148 590.562C277.556 556.997 289.209 528.143 305.627 487.496C308.926 479.326 312.419 470.679 316.132 461.422C312.382 318.688 371.367 199 511.835 199C650.742 199 711.054 316.344 707.617 461.422C711.425 470.936 715.003 479.812 718.383 488.193Z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 47,
columnNumber: 3
}, this));
export const oidc = createSvg("0 0 48 48", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M24 0C10.75 0 0 10.75 0 24s10.75 24 24 24 24-10.75 24-24S37.25 0 24 0Zm6.05 24.76 2.87-1.74c-1.21-.76-2.64-1.28-4.23-1.66-.3-.09-.6-.16-.91-.22v14.96l-4.53 2.27v-2.95h0c-8.69-.76-14.36-4.99-14.36-10.13s5.52-9.14 12.85-10.05c0 0 .62-.08 1.51-.14v-6.13l4.53-2.27v8.47c.56.07.91.14.91.14 2.87.45 5.44 1.36 7.48 2.64l2.19-1.44.76 6.8-9.07-1.51Z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 54,
columnNumber: 3
}, this));
export const google = createSvg("0 0 48 48", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5Zm22.98 15.05c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65ZM10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19ZM24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48Z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 61,
columnNumber: 3
}, this));
export const huawei = createSvg("0 0 1024 1024", /* @__PURE__ */
_jsxDEV("path", {
fill: "currentColor",
d: "M844.8 608c-25.6 51.2-70.4 64-70.4 64-19.2 6.4-38.4 6.4-38.4 6.4H576c89.6-64 268.8-160 268.8-160 19.2 51.2 0 89.6 0 89.6M691.2 768c-32-6.4-89.6-51.2-108.8-64l211.2 6.4C742.4 787.2 691.2 768 691.2 768m-128-108.8q-9.6-9.6 0 0c76.8-179.2 192-313.6 192-313.6s57.6 57.6 57.6 115.2c0 44.8-32 70.4-32 70.4-64 44.8-185.6 108.8-217.6 128m-32-19.2c-32-307.2 32-384 32-384 19.2 0 32 6.4 32 6.4 57.6 12.8 70.4 64 70.4 64 12.8 25.6 0 64 0 64C646.4 473.6 556.8 608 531.2 640c6.4 0 0 0 0 0m-38.4 0c-25.6-32-115.2-166.4-134.4-249.6 0 0-12.8-32 0-64 0 0 12.8-51.2 70.4-64 0 0 25.6-6.4 32-6.4 0 0 64 76.8 32 384m-25.6 12.8s0 6.4 0 0q-9.6 9.6 0 0c-32-12.8-160-76.8-211.2-128 0 0-32-25.6-32-70.4-12.8-51.2 51.2-108.8 51.2-108.8S384 480 467.2 652.8M448 678.4s0 6.4 0 0H288s-19.2 0-38.4-6.4c0 0-44.8-12.8-64-64 0 0-19.2-38.4-6.4-89.6-6.4 0 172.8 96 268.8 160m-6.4 25.6c-19.2 12.8-83.2 57.6-108.8 64-38.4 12.8-76.8-19.2-102.4-64z"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 68,
columnNumber: 3
}, this));sourceMappingURL略,现在会变成直接通过函数计算得出常量值,之前会import SVG文件
| .npmrc | ||
|
|
||
| data/* | ||
| *.sqlite No newline at end of file |
There was a problem hiding this comment.
咱应该不太能直接 ignore *.sqlite,因为 waline 在 assets/ 下提供了个默认的 sqlite 文件需要被 git 管理起来,建议就先忽略 data/* ?
|
不介意的话我今天再迭代下这个 PR 帮助它进行合入。 If you don’t mind, I will iterate on this PR today to help it get merged. |
好的 |
概述
美化 Waline 的管理前端
详情
重构了管理后端的顶栏。移除了硬编码的
/ui前缀,引入getUiPath工具函数来动态计算基础路径,使管理前端更稳定。将原先的分散代理合并为统一的/api代理,切换样式引入方式(从.scss改为原生的.css)。其他
akismet和mathjax服务中的部分插件加载与函数命名规范问题。截图
Overview
Beautify Waline’s admin front-end
Details
Refactored the top bar of the admin backend. The hard-coded
/uiprefix is removed, and thegetUiPathutility function is introduced to dynamically calculate the base path, making the management front-end more stable. Merge the original distributed agents into a unified/apiagent, and switch the style import method (from.scssto native.css).Others
akismetandmathjaxservices.Screenshot