Skip to content

Commit

Permalink
feat: add horoscopes
Browse files Browse the repository at this point in the history
  • Loading branch information
SylarLong committed Nov 2, 2023
1 parent 8cfd27f commit 5384767
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 14 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"dependencies": {
"classnames": "^2.3.2",
"iztro": "^2.0.2",
"iztro-hook": "^1.2.1"
"iztro-hook": "^1.2.1",
"lunar-lite": "^0.0.3"
},
"resolutions": {
"jackspeak": "2.1.1"
Expand Down
1 change: 1 addition & 0 deletions src/Izpalace/Izpalace.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
justify-content: center;
display: flex;
gap: 3px;
height: 17px;
}

.iztro-palace-fate .iztro-palace-decadal-active {
Expand Down
47 changes: 44 additions & 3 deletions src/IzpalaceCenter/IzpalaceCenter.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,54 @@
width: 100%;
height: 100%;
}
.iztro-center-palace ul {
.iztro-center-palace ul.basic-info {
margin: 10px;
padding: 0;
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 20px;
}
.iztro-center-palace li {
.iztro-center-palace ul.basic-info li {
list-style: none;
}
.iztro-center-palace .center-title {
padding: 5px 0;
margin: 0;
font-size: var(--iztro-star-font-size-big);
font-weight: bold;
text-align: center;
border-bottom: 1px dashed var(--iztro-color-border);
}

.horo-buttons {
margin: 10px;
font-size: var(--iztro-star-font-size-small);
display: flex;
justify-content: space-around;
}
.horo-buttons .center-button {
display: block;
text-align: center;
padding: 5px;
border: 1px solid var(--iztro-color-border);
cursor: pointer;
transition: all 0.25s ease-in-out;
color: var(--iztro-color-text);
user-select: none;
}
.horo-buttons .center-button:not(.disabled):hover {
color: var(--iztro-color-major);
background-color: var(--iztro-color-border);
}
.horo-buttons .center-button.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.horo-buttons .center-horo-hour {
display: flex;
align-items: center;
}

.iztro-copyright {
position: absolute;
bottom: 3px;
Expand All @@ -23,7 +64,7 @@

#palace-line {
stroke: var(--iztro-color-awesome);
stroke-opacity: 0.5;
opacity: 0.6;
transition: all 0.25s ease-in-out;
}
#palace-line.decadal {
Expand Down
233 changes: 229 additions & 4 deletions src/IzpalaceCenter/IzpalaceCenter.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import classNames from "classnames";
import React, { useMemo } from "react";
import React, { useCallback, useMemo } from "react";
import FunctionalAstrolabe from "iztro/lib/astro/FunctionalAstrolabe";
import { Item, ItemProps } from "./Item";
import "./IzpalaceCenter.css";
import { Line } from "./Line";
import { fixEarthlyBranchIndex } from "iztro/lib/utils";
import { Scope } from "iztro/lib/data/types";
import FunctionalHoroscope from "iztro/lib/astro/FunctionalHoroscope";
import { normalizeDateStr, solar2lunar } from "lunar-lite";
import { t } from "iztro/lib/i18n";
import { CHINESE_TIME } from "iztro/lib/data";

const MIN_DATETIME = new Date(1990, 0, 31).getTime();
const MAX_DATETIME = new Date(2101, 0, 1).getTime();

type IzpalaceCenterProps = {
astrolabe?: FunctionalAstrolabe;
horoscope?: FunctionalHoroscope;
horoscopeDate?: string | Date;
horoscopeHour?: number;
arrowIndex?: number;
arrowScope?: Scope;
setHoroscopeDate?: React.Dispatch<
React.SetStateAction<string | Date | undefined>
>;
setHoroscopeHour?: React.Dispatch<React.SetStateAction<number | undefined>>;
};

export const IzpalaceCenter = ({
astrolabe,
horoscope,
arrowIndex,
arrowScope,
horoscopeDate = new Date(),
horoscopeHour = 0,
setHoroscopeDate,
setHoroscopeHour,
}: IzpalaceCenterProps) => {
const records: ItemProps[] = useMemo(
() => [
{
title: "五行局:",
content: astrolabe?.fiveElementsClass,
},
{
title: "年龄(虚岁):",
content: `${horoscope?.age.nominalAge} 岁`,
},
{
title: "四柱:",
content: astrolabe?.chineseDate,
Expand Down Expand Up @@ -61,7 +88,115 @@ export const IzpalaceCenter = ({
content: astrolabe?.earthlyBranchOfBodyPalace,
},
],
[astrolabe]
[astrolabe, horoscope]
);

const horoDate = useMemo(() => {
const dateStr = horoscopeDate ?? new Date();
const [year, month, date] = normalizeDateStr(dateStr);
const dt = new Date(year, month - 1, date);

return {
solar: `${year}-${month}-${date}`,
lunar: solar2lunar(dateStr).toString(true),
prevDecadalDisabled: dt.setFullYear(dt.getFullYear() - 1),
};
}, [horoscopeDate]);

const onHoroscopeButtonClicked = (scope: Scope, value: number) => {
if (!astrolabe?.solarDate) {
return true;
}

const [year, month, date] = normalizeDateStr(horoscopeDate);
const dt = new Date(year, month - 1, date);
const [birthYear, birthMonth, birthDate] = normalizeDateStr(
astrolabe.solarDate
);
const birthday = new Date(birthYear, birthMonth - 1, birthDate);
let hour = horoscopeHour;

switch (scope) {
case "hourly":
hour = horoscopeHour + value;

if (horoscopeHour + value > 11) {
// 如果大于亥时,则加一天,时辰变为早子时
dt.setDate(dt.getDate() + 1);
hour = 0;
} else if (horoscopeHour + value < 0) {
// 如果小于早子时,则减一天,时辰变为亥时
dt.setDate(dt.getDate() - 1);
hour = 11;
}
break;
case "daily":
dt.setDate(dt.getDate() + value);
break;
case "monthly":
dt.setMonth(dt.getMonth() + value);
break;
case "yearly":
case "decadal":
dt.setFullYear(dt.getFullYear() + value);
break;
}

if (
dt.getTime() > MIN_DATETIME &&
dt.getTime() < MAX_DATETIME &&
dt.getTime() >= birthday.getTime()
) {
setHoroscopeDate?.(dt);
setHoroscopeHour?.(hour);
}
};

const shouldBeDisabled = useCallback(
(dateStr: string | Date, scope: Scope, value: number) => {
if (!astrolabe?.solarDate) {
return true;
}

const [year, month, date] = normalizeDateStr(dateStr);
const dt = new Date(year, month - 1, date);
const [birthYear, birthMonth, birthDate] = normalizeDateStr(
astrolabe.solarDate
);
const birthday = new Date(birthYear, birthMonth - 1, birthDate);

switch (scope) {
case "hourly":
if (horoscopeHour + value > 11) {
dt.setDate(dt.getDate() + 1);
} else if (horoscopeHour + value < 0) {
dt.setDate(dt.getDate() - 1);
}

break;
case "daily":
dt.setDate(dt.getDate() + value);
break;
case "monthly":
dt.setMonth(dt.getMonth() + value);
break;
case "yearly":
case "decadal":
dt.setFullYear(dt.getFullYear() + value);
break;
}

if (
dt.getTime() >= MAX_DATETIME ||
dt.getTime() <= MIN_DATETIME ||
dt.getTime() < birthday.getTime()
) {
return true;
}

return false;
},
[horoscopeHour, astrolabe]
);

return (
Expand All @@ -75,12 +210,102 @@ export const IzpalaceCenter = ({
}
/>
)}

<ul>
<h3 className="center-title">基本信息</h3>
<ul className="basic-info">
{records.map((rec, idx) => (
<Item key={idx} {...rec} />
))}
</ul>
<h3 className="center-title">运限信息</h3>
<ul className="basic-info">
<Item title="农历:" content={horoDate.lunar} />
<Item title="阳历:" content={horoDate.solar} />
</ul>
<div className="horo-buttons">
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "yearly", -10),
})}
onClick={() => onHoroscopeButtonClicked("yearly", -10)}
>
◀限
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "yearly", -1),
})}
onClick={() => onHoroscopeButtonClicked("yearly", -1)}
>
◀年
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "monthly", -1),
})}
onClick={() => onHoroscopeButtonClicked("monthly", -1)}
>
◀月
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "daily", -1),
})}
onClick={() => onHoroscopeButtonClicked("daily", -1)}
>
◀日
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "hourly", -1),
})}
onClick={() => onHoroscopeButtonClicked("hourly", -1)}
>
◀时
</span>
<span className="center-horo-hour">
{t(CHINESE_TIME[horoscopeHour])}
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "hourly", 1),
})}
onClick={() => onHoroscopeButtonClicked("hourly", 1)}
>
时►
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "daily", 1),
})}
onClick={() => onHoroscopeButtonClicked("daily", 1)}
>
日►
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "monthly", 1),
})}
onClick={() => onHoroscopeButtonClicked("monthly", 1)}
>
月►
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "yearly", 1),
})}
onClick={() => onHoroscopeButtonClicked("yearly", 1)}
>
年►
</span>
<span
className={classNames("center-button", {
disabled: shouldBeDisabled(horoDate.solar, "yearly", 10),
})}
onClick={() => onHoroscopeButtonClicked("yearly", 10)}
>
限►
</span>
</div>
<a
className="iztro-copyright"
href="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/sylarlong/iztro"
Expand Down
Loading

0 comments on commit 5384767

Please sign in to comment.