feat(chart): 星盘改用行星符号与颜色,度数进行星表
北印星盘(星盘页 / 校正右栏 / 我的报告共用 VedicChartSvg)宫内不再画 「水 19°」「罗逆 29°」这类显示文本——一宫三颗星就叠三行、字号压到 8。 改成九个彩色符号横排,每行最多 3 个;逆行是符号下方一道同色横线, 第 1 宫加 As 小标,盘下方两行图例。度数、星宿、顺逆下沉到星盘页的 行星表,列从四列扩到八列,首行是上升,度数精确到分。 - 符号字体:vendored 的 9 字形 Noto Sans Symbols 子集(OFL,1.5 KB), 经 next/font/local 挂成 --font-planet-glyphs;♀ ♂ 带 U+FE0E 防 iOS 画成表情。构建镜像不能联网,所以必须自带,与 Inter 同一条理由。 - 颜色:--color-planet-* 九个 token,:root 与两个深色块各一份。只用于 认星不表吉凶,罗计共用中性灰。挂 is-* 修饰类而非行内 style——报告 文档的标记合同禁止渲染结果出现 style=,星盘不做例外。 - 数据来源:toNorthIndianChart() 加结构化 occupantGlyphs(星盘页与 markdown fence 走这条);校正与报告两条路线的模型只有引擎 / golden 显示文本,按首字解析,解析由测试锁住。 - 星宿沿用引擎返回名:仓库无中文宿名表,印度 27 宿与中国二十八宿不是 同一套,不自造对照。 tsc 0 错,lint 0 error,npm test 3471→3484 条、36 红与基线逐条相同, / 仍 Static,首屏 JS gzip +0.29%。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
84b293fb47
commit
5a1dcbd2a1
@@ -7,3 +7,17 @@ export function formatCoord(latitude: number, longitude: number): string {
|
||||
export function formatDegree(degree: number): string {
|
||||
return `${Math.min(29.9, Math.max(0, degree)).toFixed(1)}°`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Degrees and arc-minutes inside the sign, e.g. `15°02′`.
|
||||
*
|
||||
* The planet table is the only place the chart page still states a position, so
|
||||
* it does not round to whole degrees the way the chart labels used to: 29°59′
|
||||
* and 0°01′ are a sign apart and must not both read as "30°".
|
||||
*/
|
||||
export function formatDegreeMinutes(degree: number): string {
|
||||
const clamped = Math.min(29.9999, Math.max(0, degree));
|
||||
const whole = Math.floor(clamped);
|
||||
const minutes = Math.min(59, Math.floor((clamped - whole) * 60));
|
||||
return `${whole}°${String(minutes).padStart(2, "0")}′`;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,88 @@
|
||||
"use client";
|
||||
|
||||
import { VedicChartSvg } from "@/components/personal-report/vedic-chart-svg";
|
||||
import type { ChartViewOk } from "@/lib/chart-view-contract";
|
||||
import type {
|
||||
ChartViewAscendantRow,
|
||||
ChartViewOk,
|
||||
ChartViewPlanetRow,
|
||||
} from "@/lib/chart-view-contract";
|
||||
import { CHART_VIEW_COPY, VARGA_CHIP_ORDER } from "@/lib/chart-view-labels";
|
||||
import { formatDegree } from "./chart-format";
|
||||
import {
|
||||
ASCENDANT_COLOR_CLASS,
|
||||
ASCENDANT_MARK,
|
||||
PLANET_ABBR,
|
||||
PLANET_COLOR_CLASS,
|
||||
PLANET_GLYPH,
|
||||
planetGlyphKey,
|
||||
} from "@/lib/planet-glyphs";
|
||||
import { formatDegreeMinutes } from "./chart-format";
|
||||
import { ChartParamTable } from "./chart-param-table";
|
||||
|
||||
/** The same coloured symbol the chart draws, so a row and a house read as one body. */
|
||||
function BodyGlyph({ name }: { name: string }) {
|
||||
const key = planetGlyphKey(name);
|
||||
if (!key) return <span className="chart-page-planet-glyph">—</span>;
|
||||
return (
|
||||
<span className={`chart-page-planet-glyph ${PLANET_COLOR_CLASS[key]}`}>
|
||||
{PLANET_GLYPH[key]}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function PlanetCell({ name, label, abbr }: { name: string | null; label: string; abbr: string }) {
|
||||
return (
|
||||
<>
|
||||
{name === null ? (
|
||||
<span className={`chart-page-planet-glyph ${ASCENDANT_COLOR_CLASS}`}>
|
||||
{ASCENDANT_MARK}
|
||||
</span>
|
||||
) : <BodyGlyph name={name} />}
|
||||
{" "}
|
||||
{label}
|
||||
{" "}
|
||||
<span className="chart-page-planet-abbr">{abbr}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PlanetRow({ row }: { row: ChartViewPlanetRow }) {
|
||||
const key = planetGlyphKey(row.name);
|
||||
return (
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<PlanetCell name={row.name} label={row.label} abbr={key ? PLANET_ABBR[key] : "—"} />
|
||||
</th>
|
||||
<td className="chart-page-planet-num">{row.signLabel} {formatDegreeMinutes(row.degreeInSign)}</td>
|
||||
<td className="chart-page-planet-mid">{row.retrograde ? "逆" : "顺"}</td>
|
||||
<td className="chart-page-planet-mid">{row.house}宫</td>
|
||||
<td>{row.nakshatra}</td>
|
||||
<td className="chart-page-planet-mid"><BodyGlyph name={row.nakshatraLord} /></td>
|
||||
<td className="chart-page-planet-mid chart-page-planet-num">{row.pada}</td>
|
||||
<td>{row.status}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/** The ascendant is a chart point: the engine returns no nakshatra for it. */
|
||||
function AscendantRow({ row }: { row: ChartViewAscendantRow }) {
|
||||
return (
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<PlanetCell name={null} label={row.label} abbr={row.abbr} />
|
||||
</th>
|
||||
<td className="chart-page-planet-num">{row.signLabel} {formatDegreeMinutes(row.degreeInSign)}</td>
|
||||
<td className="chart-page-planet-mid">顺</td>
|
||||
<td className="chart-page-planet-mid">{row.house}宫</td>
|
||||
<td>{row.nakshatra ?? "—"}</td>
|
||||
<td className="chart-page-planet-mid">
|
||||
{row.nakshatraLord ? <BodyGlyph name={row.nakshatraLord} /> : "—"}
|
||||
</td>
|
||||
<td className="chart-page-planet-mid chart-page-planet-num">{row.pada ?? "—"}</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export function ChartVedicTab({
|
||||
view,
|
||||
vargaId,
|
||||
@@ -53,25 +130,27 @@ export function ChartVedicTab({
|
||||
chart can and cannot be read for. */}
|
||||
<p className="chart-page-boundary">{view.vedic.boundary}</p>
|
||||
</div>
|
||||
{/* Everything the chart stopped drawing lands here: the chart carries
|
||||
symbols, this table carries the numbers behind them. */}
|
||||
<div className="chart-page-planet-table-wrap">
|
||||
<table className="chart-page-planet-table">
|
||||
<caption>{varga.id} · {varga.meaning}</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">星体</th>
|
||||
<th scope="col">星座与度数</th>
|
||||
<th scope="col">行星</th>
|
||||
<th scope="col">黄道经度</th>
|
||||
<th scope="col">速度</th>
|
||||
<th scope="col">宫位</th>
|
||||
<th scope="col">星宿</th>
|
||||
<th scope="col">宿主</th>
|
||||
<th scope="col">pada</th>
|
||||
<th scope="col">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{view.vedic.ascendant && <AscendantRow row={view.vedic.ascendant} />}
|
||||
{view.vedic.planets.map((planet) => (
|
||||
<tr key={planet.name}>
|
||||
<th scope="row">{planet.label}</th>
|
||||
<td>{planet.signLabel} {formatDegree(planet.degreeInSign)}</td>
|
||||
<td>{planet.house}</td>
|
||||
<td>{planet.status}</td>
|
||||
</tr>
|
||||
<PlanetRow key={planet.name} row={planet} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user