Add number formatter web component to profile stats (#242)

在个人资料模块中,使用自定义元素 `<number-formatter>` 来格式化显示的数字,使其更易读。该组件将大数字转换为简写形式(如 1K, 1M, 1B),提升用户体验。

```release-note
优化个人资料小部件的数值显示
```
This commit is contained in:
Anye
2025-11-06 22:44:29 +08:00
committed by GitHub
parent c44c5bd40e
commit 78ea35d202
3 changed files with 58 additions and 11 deletions

View File

@@ -0,0 +1,44 @@
export default class NumberFormatterElement extends HTMLElement {
static get observedAttributes() {
return ["value"];
}
constructor() {
super();
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
render() {
const value = this.getAttribute("value");
if (value === null) {
this.textContent = "0";
return;
}
const num = parseInt(value, 10);
if (isNaN(num)) {
this.textContent = value;
return;
}
this.textContent = this.formatNumber(num);
}
formatNumber(num: number): string {
const formatter = new Intl.NumberFormat("en-US", {
notation: "compact",
compactDisplay: "short",
maximumFractionDigits: 1,
});
return formatter.format(num);
}
}
customElements.define("number-formatter", NumberFormatterElement);

View File

@@ -7,6 +7,7 @@ import colorSchemeSwitcher from "./alpine-data/color-scheme-switcher";
import upvote from "./alpine-data/upvote";
import share from "./alpine-data/share";
import uiPermission from "./alpine-data/ui-permission";
import "./components/number-formatter";
window.Alpine = Alpine;

View File

@@ -18,35 +18,37 @@
</div>
<div class="grid grid-cols-4 gap-5">
<div class="inline-flex flex-col items-center">
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100" th:text="${stats.post}"></span>
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100">
<number-formatter th:attr="value=${stats.post}" />
</span>
<span
class="text-xs font-light text-gray-600 dark:text-slate-300"
th:text="#{widget.profile.postCount.label}"
></span>
</div>
<div class="inline-flex flex-col items-center">
<span
class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100"
th:text="${stats.category}"
></span>
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100">
<number-formatter th:attr="value=${stats.category}" />
</span>
<span
class="text-xs font-light text-gray-600 dark:text-slate-300"
th:text="#{widget.profile.categoryCount.label}"
></span>
</div>
<div class="inline-flex flex-col items-center">
<span
class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100"
th:text="${stats.comment}"
></span>
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100">
<number-formatter th:attr="value=${stats.comment}" />
</span>
<span
class="text-xs font-light text-gray-600 dark:text-slate-300"
th:text="#{widget.profile.commentCount.label}"
></span>
</div>
<div class="inline-flex flex-col items-center">
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100" th:text="${stats.visit}"></span
><span
<span class="text-xl font-medium tabular-nums text-gray-900 dark:text-slate-100">
<number-formatter th:attr="value=${stats.visit}" />
</span>
<span
class="text-xs font-light text-gray-600 dark:text-slate-300"
th:text="#{widget.profile.visitCount.label}"
></span>