import { css, html, LitElement, nothing } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import type {
GetBasicPanchangResponse,
GetDetailedPanchangResponse,
} from '../types/index.js';
import { baseStyles } from '../utils/base-styles.js';
import { formatDate, formatTime, formatTimeRange } from '../utils/format.js';
type PanchangData = GetBasicPanchangResponse | GetDetailedPanchangResponse;
type PanchangTime = GetDetailedPanchangResponse['rahuKaal'];
/** Panchang table for /vedic-astrology/panchang/{basic,detailed}. */
@customElement('roxy-panchang-table')
export class RoxyPanchangTable extends LitElement {
static styles = [
baseStyles,
css`
.wrap {
border: 1px solid var(--roxy-border, #e4e4e7);
border-radius: var(--roxy-radius-md, 8px);
background: var(--roxy-bg, #fff);
overflow: hidden;
box-shadow: var(--roxy-shadow-sm);
}
.head {
padding: var(--roxy-space-md, 1rem);
border-bottom: 1px solid var(--roxy-border, #e4e4e7);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--roxy-space-sm, 0.5rem);
}
.title {
margin: 0;
font-size: var(--roxy-text-lg, 1.125rem);
font-weight: var(--roxy-weight-bold, 600);
}
.date {
color: var(--roxy-muted, #71717a);
font-size: var(--roxy-text-sm, 0.875rem);
}
table {
width: 100%;
border-collapse: collapse;
font-size: var(--roxy-text-sm, 0.875rem);
}
tbody tr:nth-child(odd) {
background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 24%, transparent);
}
th,
td {
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
text-align: left;
vertical-align: top;
}
th {
color: var(--roxy-muted, #71717a);
font-weight: var(--roxy-weight-bold, 600);
width: 38%;
text-transform: capitalize;
}
td {
color: var(--roxy-fg, #0a0a0a);
font-variant-numeric: tabular-nums;
}
.section {
border-top: 1px solid var(--roxy-border, #e4e4e7);
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
font-size: var(--roxy-text-xs, 0.75rem);
color: var(--roxy-muted, #71717a);
font-weight: var(--roxy-weight-bold, 600);
text-transform: uppercase;
letter-spacing: 0.06em;
}
`,
];
@property({ attribute: false })
data: PanchangData | null = null;
@property({ type: String, reflect: true })
detail: 'basic' | 'detailed' = 'detailed';
render() {
const d = this.data;
if (!d)
return html`
No panchang data
`;
const detailed = 'sunrise' in d ? d : null;
const fivefold: Array<[string, string]> = [
['Tithi', this.formatPart(d.tithi)],
['Nakshatra', this.formatPart(d.nakshatra)],
['Yoga', this.formatPart(d.yoga)],
['Karana', this.formatPart(d.karana)],
];
if (detailed) fivefold.push(['Vara', this.formatPart(detailed.vara)]);
const muhurtas: Array<[string, PanchangTime | undefined]> = detailed
? [
['Brahma Muhurta', detailed.brahmaMuhurta],
['Abhijit Muhurta', detailed.abhijitMuhurta],
['Vijaya Muhurta', detailed.vijayaMuhurta],
['Godhuli Muhurta', detailed.godhuliMuhurta],
['Nishita Muhurta', detailed.nishitaMuhurta],
['Pratah Sandhya', detailed.pratahSandhya],
['Sayahna Sandhya', detailed.sayahnaSandhya],
]
: [];
const inauspicious: Array<[string, PanchangTime | undefined]> = detailed
? [
['Rahu Kaal', detailed.rahuKaal],
['Yamaganda', detailed.yamaganda],
['Gulika', detailed.gulika],
]
: [];
return html`
Panchang
${detailed ? formatDate(detailed.date) : ''}
${fivefold.map(
([k, v]) => html`
| ${k} |
${v} |
`,
)}
${
detailed?.sunrise
? html`
| Sunrise |
${formatTime(detailed.sunrise)} |
`
: nothing
}
${
detailed?.sunset
? html`
| Sunset |
${formatTime(detailed.sunset)} |
`
: nothing
}
${
detailed?.moonrise
? html`
| Moonrise |
${formatTime(detailed.moonrise)} |
`
: nothing
}
${
detailed?.moonset
? html`
| Moonset |
${formatTime(detailed.moonset)} |
`
: nothing
}
${
this.detail === 'detailed' &&
(muhurtas.some((m) => !!m[1]) || inauspicious.some((m) => !!m[1]))
? html`
Auspicious muhurtas
${muhurtas
.filter(([, v]) => !!v)
.map(
([k, v]) => html`
| ${k} |
${formatTimeRange(v)} |
`,
)}
Inauspicious periods
${inauspicious
.filter(([, v]) => !!v)
.map(
([k, v]) => html`
| ${k} |
${formatTimeRange(v)} |
`,
)}
`
: nothing
}
`;
}
private formatPart(v: unknown): string {
if (!v) return '';
if (typeof v === 'string') return v;
if (typeof v === 'object') {
const obj = v as {
name?: string;
lord?: string;
phase?: string;
end?: string;
};
const parts = [
obj.name,
obj.lord ? `(${obj.lord})` : '',
obj.phase,
].filter(Boolean);
return parts.join(' ');
}
return String(v);
}
}
declare global {
interface HTMLElementTagNameMap {
'roxy-panchang-table': RoxyPanchangTable;
}
}