Skip to content

Commit 3beecf1

Browse files
committed
feat(dasha-timeline): antara and sookshma demo cards, date column granularity per period length
1 parent a20ca8a commit 3beecf1

10 files changed

Lines changed: 471 additions & 109 deletions

File tree

apps/docs/components-manifest.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -403,15 +403,28 @@ window.ROXY_UI_DEMOS = [
403403
body: ${JSON.stringify({ date: PERSON1.date, time: PERSON1.time, latitude: PERSON1.latitude, longitude: PERSON1.longitude }, null, 2).replace(/\n/g, '\n ')},
404404
});`,
405405
}),
406-
// No dasha-antara / dasha-sookshma cards yet, deliberately. Their samples come
407-
// from `scripts/refresh-samples.ts` via @roxyapi/sdk, and the published SDK
408-
// regenerates from the live spec on its OWN pipeline, so it does not know a
409-
// brand new operation for a while. A card with no sample renders an empty
410-
// state, which is worse than no card. @roxyapi/sdk 1.2.50 does expose both
411-
// operations, but bunfig.toml sets minimumReleaseAge = 3 days, so it cannot be
412-
// installed here until 2026-07-29 and refresh-samples cannot capture them
413-
// before that. Do not bypass that guard for a demo card. Full sequence:
414-
// CLAUDE.md, "Binding a new endpoint to an EXISTING component", step 8.
406+
entry({
407+
id: 'dasha-antara',
408+
tag: 'roxy-dasha-timeline',
409+
heading: 'Pratyantardashas',
410+
seoLine: 'Pratyantardashas within an antardasha, the third Vimshottari level',
411+
attrs: ' period="antara"',
412+
sdkCall: ` const { data } = await roxy.vedicAstrology.getPratyantardashas({
413+
path: { mahadasha: 'venus', antardasha: 'saturn' },
414+
body: ${JSON.stringify({ date: PERSON1.date, time: PERSON1.time, latitude: PERSON1.latitude, longitude: PERSON1.longitude }, null, 2).replace(/\n/g, '\n ')},
415+
});`,
416+
}),
417+
entry({
418+
id: 'dasha-sookshma',
419+
tag: 'roxy-dasha-timeline',
420+
heading: 'Sookshma dashas',
421+
seoLine: 'Sookshma dashas, day level timing at the fourth Vimshottari level',
422+
attrs: ' period="sookshma"',
423+
sdkCall: ` const { data } = await roxy.vedicAstrology.getSookshmaDashas({
424+
path: { mahadasha: 'venus', antardasha: 'saturn', pratyantardasha: 'mercury' },
425+
body: ${JSON.stringify({ date: PERSON1.date, time: PERSON1.time, latitude: PERSON1.latitude, longitude: PERSON1.longitude }, null, 2).replace(/\n/g, '\n ')},
426+
});`,
427+
}),
415428
entry({
416429
id: 'guna',
417430
tag: 'roxy-guna-milan',
26.9 KB
Loading
27.9 KB
Loading

apps/docs/sample-data.js

Lines changed: 296 additions & 87 deletions
Large diffs are not rendered by default.

bun.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bunfig.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,11 @@ preload = ["./packages/ui/tests/setup.ts"]
33

44
[install]
55
exact = false
6+
# Third-party packages must soak for three days before we will install them. This
7+
# repo ships a CDN bundle that executes in other people's browsers, so a poisoned
8+
# transitive release here reaches end users, not just our build. Keep this.
69
minimumReleaseAge = 259200
10+
# Our OWN package is exempt: it is published from our CI via npm Trusted Publishing
11+
# (OIDC) with provenance, so the soak window buys nothing and would otherwise block
12+
# the demo and samples for three days every time the API gains an endpoint.
13+
minimumReleaseAgeExcludes = ["@roxyapi/sdk"]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"@hey-api/openapi-ts": "0.99.0",
4646
"@lit-labs/rollup-plugin-minify-html-literals": "^0.2.0",
4747
"@playwright/test": "^1.61.1",
48-
"@roxyapi/sdk": "^1.2.45",
48+
"@roxyapi/sdk": "^1.2.50",
4949
"@types/bun": "^1.3.14",
5050
"@types/node": "^26.1.1",
5151
"@types/react": "^19.2.17",

packages/ui/src/components/dasha-timeline.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ export class RoxyDashaTimeline extends RoxyDataElement<DashaData> {
314314
${
315315
periods.length > 0
316316
? html`<div class="timeline" role="list">
317-
${periods.map((p) => this.renderBar(p, maxYears))}
317+
${periods.map((p) => this.renderBar(p, maxYears, grainFor(maxYears)))}
318318
</div>`
319319
: nothing
320320
}`
@@ -562,7 +562,7 @@ export class RoxyDashaTimeline extends RoxyDataElement<DashaData> {
562562
return (now - start) / (end - start);
563563
}
564564

565-
private renderBar(p: DashaPeriod, max: number) {
565+
private renderBar(p: DashaPeriod, max: number, grain: DateGrain) {
566566
const years = p.durationYears;
567567
const width = max > 0 ? (years / max) * 100 : 0;
568568
const current = this.isCurrent(p);
@@ -589,16 +589,44 @@ export class RoxyDashaTimeline extends RoxyDataElement<DashaData> {
589589
}
590590
</span>
591591
<span class="dates">
592-
${p.startDate ? formatYear(p.startDate) : ''}
593-
${p.endDate ? html`- ${formatYear(p.endDate)}` : ''}
592+
${p.startDate ? formatBoundary(p.startDate, grain) : ''}
593+
${p.endDate ? html`- ${formatBoundary(p.endDate, grain)}` : ''}
594594
</span>
595595
</div>`;
596596
}
597597
}
598598

599-
function formatYear(s: string): string {
600-
const m = s.match(/^(\d{4})/);
601-
return m ? m[1] : s;
599+
/**
600+
* How precise the bar date column has to be, chosen from the LONGEST period in
601+
* the set.
602+
*
603+
* A Mahadasha spans years, so a bare year reads cleanly and keeps the column
604+
* narrow. A Sookshma spans days: printed as a year, every one of the nine rows
605+
* reads "1990 - 1990" and the column carries no information at exactly the level
606+
* a reader opened the drill-down to see.
607+
*/
608+
type DateGrain = 'year' | 'month' | 'day';
609+
610+
const DAYS_PER_YEAR = 365.25;
611+
612+
function grainFor(maxYears: number): DateGrain {
613+
if (maxYears >= 2) return 'year';
614+
if (maxYears >= 60 / DAYS_PER_YEAR) return 'month';
615+
return 'day';
616+
}
617+
618+
/** One end of a bar, at the chosen granularity. Day grain drops the year: these rows sit under a parent line that already states it, and the column is only 8rem wide. */
619+
function formatBoundary(s: string, grain: DateGrain): string {
620+
if (grain === 'year') {
621+
const m = s.match(/^(\d{4})/);
622+
return m ? m[1] : s;
623+
}
624+
const d = new Date(s);
625+
if (Number.isNaN(d.getTime())) return s;
626+
const month = d.toLocaleString('en', { month: 'short' });
627+
return grain === 'month'
628+
? `${month} ${d.getFullYear()}`
629+
: `${d.getDate()} ${month}`;
602630
}
603631

604632
declare global {

packages/ui/tests/components.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,3 +2017,80 @@ describe('every tablist governs a real tabpanel', () => {
20172017
});
20182018
}
20192019
});
2020+
2021+
/**
2022+
* The bar date column has to stay informative at every level. Printed as a bare
2023+
* year, a sookshma list renders nine identical "1990 - 1990" rows, which is the
2024+
* column carrying no information at exactly the level the reader drilled to.
2025+
*/
2026+
describe('roxy-dasha-timeline date column adapts to the period length', () => {
2027+
async function mount(data: unknown, period: string) {
2028+
const el = document.createElement('roxy-dasha-timeline') as HTMLElement & {
2029+
data?: unknown;
2030+
period?: string;
2031+
};
2032+
el.period = period;
2033+
document.body.appendChild(el);
2034+
el.data = data;
2035+
await settled(el);
2036+
return el;
2037+
}
2038+
const dateCells = (el: Element) =>
2039+
[...(el.shadowRoot?.querySelectorAll('.dates') ?? [])].map(
2040+
(n) => n.textContent?.replace(/\s+/g, ' ').trim() ?? '',
2041+
);
2042+
2043+
test('mahadashas keep bare years', async () => {
2044+
const el = await mount(
2045+
{
2046+
mahadashas: [
2047+
{
2048+
planet: 'Ketu',
2049+
startDate: '1990-01-15T00:00:00',
2050+
endDate: '1997-01-15T00:00:00',
2051+
durationYears: 7,
2052+
},
2053+
{
2054+
planet: 'Venus',
2055+
startDate: '1997-01-15T00:00:00',
2056+
endDate: '2017-01-15T00:00:00',
2057+
durationYears: 20,
2058+
},
2059+
],
2060+
},
2061+
'major',
2062+
);
2063+
expect(dateCells(el)[0]).toBe('1990 - 1997');
2064+
el.remove();
2065+
});
2066+
2067+
test('day-long sookshma periods do not all collapse to one repeated year', async () => {
2068+
const el = await mount(
2069+
{
2070+
pratyantardashaLord: 'Mercury',
2071+
pratyantardashaPeriod: { planet: 'Mercury', durationYears: 0.45 },
2072+
sookshmaDashas: [
2073+
{
2074+
planet: 'Mercury',
2075+
startDate: '1990-01-19T00:00:00',
2076+
endDate: '1990-02-02T00:00:00',
2077+
durationYears: 0.04,
2078+
},
2079+
{
2080+
planet: 'Ketu',
2081+
startDate: '1990-02-02T00:00:00',
2082+
endDate: '1990-02-08T00:00:00',
2083+
durationYears: 0.017,
2084+
},
2085+
],
2086+
},
2087+
'sookshma',
2088+
);
2089+
const cells = dateCells(el);
2090+
expect(cells[0]).not.toBe('1990 - 1990');
2091+
// Distinct rows must read distinctly.
2092+
expect(cells[0]).not.toBe(cells[1]);
2093+
expect(cells[0]).toContain('Jan');
2094+
el.remove();
2095+
});
2096+
});

scripts/refresh-samples.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,34 @@ async function main() {
198198
},
199199
}),
200200
),
201+
// The two deeper levels share the sub layout but carry a different parent
202+
// shape and level label, so a shared sample would never exercise them.
203+
run('dasha-antara', () =>
204+
roxy.vedicAstrology.getPratyantardashas({
205+
path: { mahadasha: 'Venus', antardasha: 'Saturn' },
206+
body: {
207+
date: PERSON1.date,
208+
time: PERSON1.time,
209+
latitude: PERSON1.latitude,
210+
longitude: PERSON1.longitude,
211+
},
212+
}),
213+
),
214+
run('dasha-sookshma', () =>
215+
roxy.vedicAstrology.getSookshmaDashas({
216+
path: {
217+
mahadasha: 'Venus',
218+
antardasha: 'Saturn',
219+
pratyantardasha: 'Mercury',
220+
},
221+
body: {
222+
date: PERSON1.date,
223+
time: PERSON1.time,
224+
latitude: PERSON1.latitude,
225+
longitude: PERSON1.longitude,
226+
},
227+
}),
228+
),
201229
run('dosha', () =>
202230
roxy.vedicAstrology.checkManglikDosha({
203231
body: {

0 commit comments

Comments
 (0)