+
+
+
+ 分析完成(耗时 {{ duration }}s)
+
+
+ 试运行
+
+
+ {{ ACTION_LABELS[decision.action] }}
+
+
+ {{ decision.direction === "long" ? "做多" : "做空" }}
+
+
+ 置信度{{ CONFIDENCE_LABELS[decision.confidence] }}
+
+ {{ formatTime(analysis.started_at) }}
+
+
+ 结论{{ decision.summary }}
+
+
+ 触发:{{ analysis.reasons.join(";") }} · {{ analysis.model }}{{ analysis.reasoning_effort ? ` / ${analysis.reasoning_effort}` : "" }}
+ · token {{ analysis.usage?.input_tokens.toLocaleString() }} / {{ analysis.usage?.output_tokens.toLocaleString() }}
+
-
+
最近一次分析 #{{ latest.id }}({{ formatTime(latest.started_at) }}):
{{ latest.decision?.summary }}
@@ -115,54 +138,144 @@ const ladder = computed(() => sizing.value?.entry && entryRow.value
查看
-
- 限价单有效至{{ formatTime(analysis.valid_until, "MM-DD HH:mm") }}(剩 {{ countdown(analysis.valid_until) }})
- 入场{{ formatTime(analysis.first_fill_at, "MM-DD HH:mm") }}
- 最晚平仓{{ formatTime(analysis.close_deadline, "MM-DD HH:mm") }}(剩 {{ countdown(analysis.close_deadline) }})
-
-
- 结果{{ CLOSE_REASON_LABELS[analysis.close_reason ?? ""] ?? analysis.close_reason }},净盈亏 {{ analysis.result.net }} USDT(手续费 {{ analysis.result.commission }})
-
-
为什么{{ decision.reasons }}
-
-
-
-
{{ long ? "支撑区" : "压力区" }}{{ sizing.setup.zone_low }} – {{ sizing.setup.zone_high }} · {{ decision.setup.basis }}
+
+
+
+
+ 限价单有效至
-
- 限价{{ long ? "做多" : "做空" }}{{ sizing.entry.price }} × {{ sizing.entry.quantity }},已成交 {{ filled("entry", 0) }}{{ entryRow?.avg_price ? `,均价 ${entryRow.avg_price}` : "" }}
- (名义 {{ sizing.entry.notional }} USDT,{{ sizing.entry.leverage }} 倍交易资金)
-
-
- 止损{{ currentStop ?? sizing.entry.stop }}(初始 {{ sizing.entry.stop }},距挂单价 {{ sizing.entry.stop_pct }}%;区间远端外 0.5×ATR(5m)、距挂单价至少 1×ATR(5m),止盈 1 后移到保本价)
-
-
-
止损亏损{{ sizing.entry.risk_at_stop }} USDT(交易资金的 {{ sizing.entry.risk_pct }}%){{ sizing.entry.capped_by_leverage ? ",受 3 倍上限限制" : "" }}
+
+
+ {{ formatTime(analysis.valid_until, "MM-DD HH:mm") }}
+
+
+ 剩 {{ countdown(analysis.valid_until) }}
+
+
+
+ -
-
-
-
- 止盈 {{ row.leg + 1 }}
-
-
-
-
-
-
-
+
+
+ 入场
+
+
+ {{ formatTime(analysis.first_fill_at, "MM-DD HH:mm") }}
+
+
+
+
+ 最晚平仓
+
+
+
+ {{ formatTime(analysis.close_deadline, "MM-DD HH:mm") }}
+
+
+ 剩 {{ countdown(analysis.close_deadline) }}
+
+
+
+ -
+
+
+
+
+ 结果{{ CLOSE_REASON_LABELS[analysis.close_reason ?? ""] ?? analysis.close_reason }},净盈亏
+ {{ analysis.result.net }} USDT(手续费 {{ analysis.result.commission }})
+
+
+
+ 为什么
+
+
+ {{ decision.reasons }}
+
+
+
+
+
+
+
+ {{ long ? "支撑区" : "压力区" }}
+ {{ sizing.setup.zone_low }} – {{ sizing.setup.zone_high }}
+ {{ decision.setup.basis }}
+
+
+ 限价{{ long ? "做多" : "做空" }}
+ {{ sizing.entry.price }} × {{ sizing.entry.quantity }}
+ 已成交 {{ filled("entry", 0) }}{{ entryRow?.avg_price ? `,均价 ${entryRow.avg_price}` : "" }}
+
+
+ 名义价值
+ {{ sizing.entry.notional }} USDT
+ {{ sizing.entry.leverage }} 倍交易资金
+
+
+ 止损
+ {{ currentStop ?? sizing.entry.stop }}
+ 初始 {{ sizing.entry.stop }},距挂单价 {{ sizing.entry.stop_pct }}%;区间远端外 0.5×ATR(5m)、距挂单价至少 1×ATR(5m),止盈 1 后移到保本价
+
+
+ 止损亏损
+ {{ sizing.entry.risk_at_stop }} USDT
+ 交易资金的 {{ sizing.entry.risk_pct }}%{{ sizing.entry.capped_by_leverage ? ",受 3 倍上限限制" : "" }}
+
+
+
+
+ 分批止盈
+
+
+
+
+ 止盈 {{ row.leg + 1 }}
+
+
+
+
+
+
+
+
+ 已成交 {{ row.filled }}
+
+
+ 挂单中
+
+ -
+
+
+
+
-
-
重新判断
-
+
+
+ 重新判断
+
+
· {{ condition(c) }}:{{ c.basis }}
-
风险{{ decision.risks }}
-
-
+
+
+ 风险
+
+
+ {{ decision.risks }}
+
+
+
+
diff --git a/web/src/pages/trading/index.vue b/web/src/pages/trading/index.vue
index 5342aed..aae45f2 100644
--- a/web/src/pages/trading/index.vue
+++ b/web/src/pages/trading/index.vue
@@ -1,6 +1,7 @@
-
+
-
-
-
- 引擎在线
-
-
- 引擎离线
-
-
- {{ status.running ? "交易中" : "已停止" }}
-
+
+
+
+
+
+
+ 交易引擎
+
+
+ {{ engineText }}
+
+
+
- {{ status.running ? "停止" : "开始行情交易" }}
+ {{ status.running ? "停止行情交易" : "开始行情交易" }}
-
-
交易资金
-
- {{ money(status.capital_usdt) }} USDT
-
- (权益不足,按 {{ money(status.effective_capital) }})
-
-
-
未设置
-
- 设置
-
+
+
+
+
+
+ 交易资金
+
+
+
+
+
+ {{ money(status.capital_usdt) }}USDT
+
+
+ 未设置
+
+
+ 权益不足,按 {{ money(status.effective_capital!) }}
+
-
-
账户权益{{ money(account?.margin_balance) }} USDT
+
+
+ 账户权益
+
+
+ {{ money(account?.margin_balance) }}USDT
+
-
-
可用{{ money(account?.available_balance) }} USDT
+
+
+ 可用余额
+
+
+ {{ money(account?.available_balance) }}USDT
+
-
-
未实现盈亏
-
{{ money(account?.unrealized_pnl) }}
+
+
+ 未实现盈亏
+
+
+ {{ money(account?.unrealized_pnl) }}USDT
+
-
-
今日分析{{ status.today.analyses }} / {{ status.today.limit }}
-
token{{ status.today.input_tokens.toLocaleString() }} / {{ status.today.output_tokens.toLocaleString() }}
+
+
+
+
+
+ 今日分析
+ {{ status.today.analyses }} / {{ status.today.limit }}
+
+
+
+ token 入 {{ status.today.input_tokens.toLocaleString() }} / 出 {{ status.today.output_tokens.toLocaleString() }}
+
+
-
-
-
-
-
-
-
+
+
+
+ 模型
+
+
+
+
+
+ 思考强度
+
+
+
+
+
+
还没有填写币安模拟盘 key,请先到「环境变量」页填写。
@@ -311,165 +366,195 @@ onBeforeUnmount(() => clearInterval(timer))
-
-
-
-
-
- {{ row.side === "LONG" ? "多" : "空" }}
-
-
-
-
-
- {{ num(row.amount) }}
-
-
-
-
- {{ num(row.entry_price) }}
-
-
-
-
- {{ Number(row.break_even_price).toFixed(2) }}
-
-
-
-
- {{ Number(row.mark_price).toFixed(2) }}
-
-
-
-
- {{ money(row.unrealized_pnl) }}
-
-
-
-
- {{ Number(row.liquidation_price) ? Number(row.liquidation_price).toFixed(2) : "-" }}
-
-
-
-
- {{ row.leverage }}x {{ row.margin_type === "ISOLATED" ? "逐仓" : "全仓" }}
-
-
-
-
- {{ exitPrices(row as SnapshotPosition).stop }} / {{ exitPrices(row as SnapshotPosition).target }}
-
-
-
-
- {{ closeCountdown(row.symbol) }}
-
-
-
-
-
-
-
-
- 交易币种
-
- 新增
-
-
-
-
-
-
{{ s.symbol }}
-
- {{ symbolState(s).label }}
-
+
+
+ 持仓({{ positions.length }})
+
+
+
+
+
+ {{ row.symbol }}
-
-
-
-
+
+
+
+
+
+ {{ row.side === "LONG" ? "↑ 多" : "↓ 空" }}
+
+
+
+
+
+ {{ num(row.amount) }}
+
+
+
+
+ {{ num(row.entry_price) }}
+
+
+
+
+ {{ Number(row.break_even_price).toFixed(2) }}
+
+
+
+
+ {{ Number(row.mark_price).toFixed(2) }}
+
+
+
+
+ {{ money(row.unrealized_pnl) }}
+
+
+
+
+ {{ Number(row.liquidation_price) ? Number(row.liquidation_price).toFixed(2) : "-" }}
+
+
+
+
+
+ {{ row.leverage }}x {{ row.margin_type === "ISOLATED" ? "逐仓" : "全仓" }}
+
+
+
+
+
+ {{ exitPrices(row as SnapshotPosition).stop }}
+
+
+
+
+ {{ exitPrices(row as SnapshotPosition).target }}
+
+
+
+
+
+ {{ closeCountdown(row.symbol) }}
+
+
+
+
+
-
-
-
-
-
-
-
- 当前挂单
-
-
-
-
- {{ row.type }}
-
- 条件单
-
-
-
-
-
- {{ row.side === "BUY" ? "买" : "卖" }}{{ row.reduce_only ? "(只减仓)" : "" }}
-
-
-
-
-
- {{ row.quantity === "全部持仓" ? row.quantity : num(row.quantity) }}
-
-
-
-
- {{ isOwnOrder(row.client_id) ? "本程序" : "手动" }}
-
-
-
-
- {{ formatTime(new Date(row.time).toISOString(), "MM-DD HH:mm:ss") }}
-
-
-
-
-
-
-
- 时间线
-
-
-
-
- {{ e.symbol ?? "账户" }}
-
- {{ e.message }}
-
- 查看分析
-
-
-
-
-
- 加载更早的事件
+
+
+
+
+
+ 交易币种
+
+ 新增币种
+
+
+
+
+ {{ s.symbol }}
+
+ {{ symbolState(s).label }}
+
+
+
+
+ {{ positionOf(s.symbol)!.leverage }}x {{ positionOf(s.symbol)!.side === "LONG" ? "多" : "空" }} · {{ num(positionOf(s.symbol)!.amount) }}
+
+
+
+ 删除
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 当前挂单({{ symbolOrders.length }})
+
+
+
+
+ {{ o.side === "BUY" ? "买" : "卖" }} · {{ o.type }}
+
+ {{ formatTime(new Date(o.time).toISOString(), "MM-DD HH:mm:ss") }}
+
+
+ {{ o.quantity === "全部持仓" ? o.quantity : num(o.quantity) }}
+ @ {{ o.priceText }}
+
+
+
+ 条件单
+
+
+ 只减仓
+
+ 来源:{{ isOwnOrder(o.client_id) ? "本程序" : "手动" }}
+
+
+
+
+
+
+
+ 时间线
+
+
+
+
+
+ {{ formatTime(e.created_at) }}
+
+ {{ e.level.toUpperCase() }}
+
+
+ {{ e.symbol ?? "账户" }}
+
+
+
+ {{ e.message }}
+
+ 查看分析
+
+
+
+
+
+
+ 加载更早的事件
+
+
+
@@ -478,12 +563,53 @@ onBeforeUnmount(() => clearInterval(timer))
diff --git a/web/src/styles/index.css b/web/src/styles/index.css
index bdb84f4..a3d37cb 100644
--- a/web/src/styles/index.css
+++ b/web/src/styles/index.css
@@ -1,3 +1,82 @@
+/* 浅色主题(Stitch「Daylight」稿):色值只在这里定义,页面里用 Element 变量或 UnoCSS 色板类 */
+:root {
+ --ap-font-sans:
+ "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
+ --ap-font-mono:
+ "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Consolas, "PingFang SC", "Microsoft YaHei",
+ monospace;
+
+ --el-font-family: var(--ap-font-sans);
+ --el-border-radius-base: 4px;
+
+ --el-color-primary: #006194;
+ --el-color-success: #16a34a;
+ --el-color-warning: #d97706;
+ --el-color-danger: #dc2626;
+ --el-color-error: #dc2626;
+ --el-color-info: #64748b;
+
+ --el-text-color-primary: #0f172a;
+ --el-text-color-regular: #334155;
+ --el-text-color-secondary: #64748b;
+ --el-text-color-placeholder: #94a3b8;
+ --el-border-color: #e2e8f0;
+ --el-border-color-light: #e2e8f0;
+ --el-border-color-lighter: #f1f5f9;
+ --el-border-color-extra-light: #f8fafc;
+ --el-border-color-dark: #cbd5e1;
+ --el-border-color-darker: #94a3b8;
+ --el-fill-color: #f1f5f9;
+ --el-fill-color-light: #f8fafc;
+ --el-fill-color-lighter: #f8fafc;
+ --el-fill-color-extra-light: #fcfdfe;
+ --el-fill-color-dark: #e2e8f0;
+ --el-fill-color-darker: #cbd5e1;
+ --el-bg-color-page: #f8fafc;
+ --el-box-shadow-lighter: 0 1px 3px 0 rgb(15 23 42 / 3%), 0 1px 2px -1px rgb(15 23 42 / 2%);
+ --el-box-shadow-light: 0 4px 6px -1px rgb(15 23 42 / 5%), 0 2px 4px -2px rgb(15 23 42 / 3%);
+}
+
+/* Element 的深浅档按与白色、黑色的混合比例生成,与它的 SCSS 算法一致 */
+:root {
+ --el-color-primary-light-3: color-mix(in srgb, var(--el-color-primary), white 30%);
+ --el-color-primary-light-5: color-mix(in srgb, var(--el-color-primary), white 50%);
+ --el-color-primary-light-7: color-mix(in srgb, var(--el-color-primary), white 70%);
+ --el-color-primary-light-8: color-mix(in srgb, var(--el-color-primary), white 80%);
+ --el-color-primary-light-9: color-mix(in srgb, var(--el-color-primary), white 90%);
+ --el-color-primary-dark-2: color-mix(in srgb, var(--el-color-primary), black 20%);
+ --el-color-success-light-3: color-mix(in srgb, var(--el-color-success), white 30%);
+ --el-color-success-light-5: color-mix(in srgb, var(--el-color-success), white 50%);
+ --el-color-success-light-7: color-mix(in srgb, var(--el-color-success), white 70%);
+ --el-color-success-light-8: color-mix(in srgb, var(--el-color-success), white 80%);
+ --el-color-success-light-9: color-mix(in srgb, var(--el-color-success), white 90%);
+ --el-color-success-dark-2: color-mix(in srgb, var(--el-color-success), black 20%);
+ --el-color-warning-light-3: color-mix(in srgb, var(--el-color-warning), white 30%);
+ --el-color-warning-light-5: color-mix(in srgb, var(--el-color-warning), white 50%);
+ --el-color-warning-light-7: color-mix(in srgb, var(--el-color-warning), white 70%);
+ --el-color-warning-light-8: color-mix(in srgb, var(--el-color-warning), white 80%);
+ --el-color-warning-light-9: color-mix(in srgb, var(--el-color-warning), white 90%);
+ --el-color-warning-dark-2: color-mix(in srgb, var(--el-color-warning), black 20%);
+ --el-color-danger-light-3: color-mix(in srgb, var(--el-color-danger), white 30%);
+ --el-color-danger-light-5: color-mix(in srgb, var(--el-color-danger), white 50%);
+ --el-color-danger-light-7: color-mix(in srgb, var(--el-color-danger), white 70%);
+ --el-color-danger-light-8: color-mix(in srgb, var(--el-color-danger), white 80%);
+ --el-color-danger-light-9: color-mix(in srgb, var(--el-color-danger), white 90%);
+ --el-color-danger-dark-2: color-mix(in srgb, var(--el-color-danger), black 20%);
+ --el-color-error-light-3: color-mix(in srgb, var(--el-color-error), white 30%);
+ --el-color-error-light-5: color-mix(in srgb, var(--el-color-error), white 50%);
+ --el-color-error-light-7: color-mix(in srgb, var(--el-color-error), white 70%);
+ --el-color-error-light-8: color-mix(in srgb, var(--el-color-error), white 80%);
+ --el-color-error-light-9: color-mix(in srgb, var(--el-color-error), white 90%);
+ --el-color-error-dark-2: color-mix(in srgb, var(--el-color-error), black 20%);
+ --el-color-info-light-3: color-mix(in srgb, var(--el-color-info), white 30%);
+ --el-color-info-light-5: color-mix(in srgb, var(--el-color-info), white 50%);
+ --el-color-info-light-7: color-mix(in srgb, var(--el-color-info), white 70%);
+ --el-color-info-light-8: color-mix(in srgb, var(--el-color-info), white 80%);
+ --el-color-info-light-9: color-mix(in srgb, var(--el-color-info), white 90%);
+ --el-color-info-dark-2: color-mix(in srgb, var(--el-color-info), black 20%);
+}
+
html,
body,
#app {
@@ -6,7 +85,48 @@ body,
}
body {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
+ color: var(--el-text-color-regular);
+ font-family: var(--ap-font-sans);
+ font-variant-numeric: tabular-nums;
+ background: var(--el-bg-color-page);
+ -webkit-font-smoothing: antialiased;
+}
+
+::-webkit-scrollbar {
+ width: 5px;
+ height: 5px;
+}
+::-webkit-scrollbar-thumb {
+ border-radius: 4px;
+ background: var(--el-border-color-dark);
+}
+::-webkit-scrollbar-thumb:hover {
+ background: var(--el-border-color-darker);
+}
+
+/* 面板:白底、细边框、8px 圆角,头部是带分隔线的标题条 */
+.el-card {
+ --el-card-border-radius: 8px;
+ --el-card-padding: 12px;
+}
+.el-card.is-never-shadow {
+ box-shadow: var(--el-box-shadow-lighter);
+}
+.el-card__header {
+ padding: 10px 12px;
+ color: var(--el-text-color-primary);
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.el-table {
+ --el-table-header-bg-color: var(--el-fill-color-light);
+ --el-table-header-text-color: var(--el-text-color-secondary);
+ --el-table-row-hover-bg-color: var(--el-fill-color-light);
+}
+.el-table th.el-table__cell {
+ font-size: 12px;
+ font-weight: 600;
}
/* Markdown 渲染(Chat 回复、skill 预览、CONTEXT.md 预览) */
@@ -75,3 +195,7 @@ body {
padding: 0.3em 0.6em;
border: 1px solid var(--el-border-color);
}
+.markdown-body th {
+ color: var(--el-text-color-primary);
+ background: var(--el-fill-color-light);
+}
diff --git a/web/types/components.d.ts b/web/types/components.d.ts
index 49b94af..20712dc 100644
--- a/web/types/components.d.ts
+++ b/web/types/components.d.ts
@@ -12,36 +12,40 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
ElAlert: typeof import('element-plus/es')['ElAlert']
- ElAside: typeof import('element-plus/es')['ElAside']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
+ ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
+ ElCollapse: typeof import('element-plus/es')['ElCollapse']
+ ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
- ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
+ ElDropdown: typeof import('element-plus/es')['ElDropdown']
+ ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+ ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+ ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
- ElHeader: typeof import('element-plus/es')['ElHeader']
+ ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
- ElMain: typeof import('element-plus/es')['ElMain']
- ElMenu: typeof import('element-plus/es')['ElMenu']
- ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElOptionGroup: typeof import('element-plus/es')['ElOptionGroup']
+ ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+ ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSelectV2: typeof import('element-plus/es')['ElSelectV2']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
@@ -51,11 +55,13 @@ declare module 'vue' {
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
+ ElTree: typeof import('element-plus/es')['ElTree']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
+ SkillTree: typeof import('./../src/components/SkillTree.vue')['default']
+ SkillVersionDrawer: typeof import('./../src/components/SkillVersionDrawer.vue')['default']
}
export interface GlobalDirectives {
- vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}
diff --git a/web/uno.config.ts b/web/uno.config.ts
index 35c8f2d..268270e 100644
--- a/web/uno.config.ts
+++ b/web/uno.config.ts
@@ -13,6 +13,13 @@ export default defineConfig({
important: "#app"
})
],
+ // 字体栈定义在 styles/index.css,Element Plus 与 UnoCSS 共用
+ theme: {
+ fontFamily: {
+ sans: "var(--ap-font-sans)",
+ mono: "var(--ap-font-mono)"
+ }
+ },
// 自定义规则
rules: [],
// 自定义快捷方式
@@ -20,6 +27,7 @@ export default defineConfig({
"wh-full": "w-full h-full",
"flex-center": "flex justify-center items-center",
"flex-x-center": "flex justify-center",
- "flex-y-center": "flex items-center"
+ "flex-y-center": "flex items-center",
+ "num": "font-mono tabular-nums"
}
})