lichta 1.0.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +30 -233
- package/index.d.ts +1 -0
- package/index.js +3 -0
- package/package.json +32 -104
- package/dist/components/Calendar.svelte +0 -437
- package/dist/components/Calendar.svelte.d.ts +0 -33
- package/dist/components/Formatter.svelte +0 -57
- package/dist/components/Formatter.svelte.d.ts +0 -8
- package/dist/constants/earthly-branches.d.ts +0 -31
- package/dist/constants/earthly-branches.js +0 -42
- package/dist/constants/five-elements.d.ts +0 -9
- package/dist/constants/five-elements.js +0 -9
- package/dist/constants/heavenly-stems.d.ts +0 -19
- package/dist/constants/heavenly-stems.js +0 -24
- package/dist/constants/i18n.d.ts +0 -59
- package/dist/constants/i18n.js +0 -65
- package/dist/core/feng-shui.d.ts +0 -55
- package/dist/core/feng-shui.js +0 -116
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -4
- package/dist/core/lunar.d.ts +0 -73
- package/dist/core/lunar.js +0 -335
- package/dist/core/types.d.ts +0 -17
- package/dist/core/types.js +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -14
- package/dist/utils/format.d.ts +0 -74
- package/dist/utils/format.js +0 -169
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -2
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { LichTa } from '../core/lunar.js';
|
|
3
|
-
import { getYearDetails } from '../core/feng-shui.js';
|
|
4
|
-
import type { LunarDate } from '../core/types.js';
|
|
5
|
-
import type { Snippet } from 'svelte';
|
|
6
|
-
|
|
7
|
-
import type { Locale } from '../constants/i18n.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Dữ liệu cho mỗi ô ngày trong lưới lịch
|
|
11
|
-
*/
|
|
12
|
-
interface DayCellData {
|
|
13
|
-
solar: Date;
|
|
14
|
-
lunar: LunarDate;
|
|
15
|
-
isToday: boolean;
|
|
16
|
-
isSelected: boolean;
|
|
17
|
-
isCurrentMonth: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface Props {
|
|
21
|
-
/** Tháng hiển thị (1-12). Mặc định: tháng hiện tại */
|
|
22
|
-
month?: number;
|
|
23
|
-
/** Năm hiển thị. Mặc định: năm hiện tại */
|
|
24
|
-
year?: number;
|
|
25
|
-
/** Ngày được chọn */
|
|
26
|
-
selectedDate?: Date | null;
|
|
27
|
-
/** Callback khi chọn ngày */
|
|
28
|
-
onSelect?: (date: Date, lunar: LunarDate) => void;
|
|
29
|
-
/** Hiển thị ngày âm lịch bên dưới ngày dương */
|
|
30
|
-
showLunar?: boolean;
|
|
31
|
-
/** Locale (vi | en | ja | ko) */
|
|
32
|
-
locale?: Locale;
|
|
33
|
-
/** Custom snippet cho mỗi ô ngày */
|
|
34
|
-
dayCell?: Snippet<[DayCellData]>;
|
|
35
|
-
children?: Snippet;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let {
|
|
39
|
-
month = new Date().getMonth() + 1,
|
|
40
|
-
year = new Date().getFullYear(),
|
|
41
|
-
selectedDate = null,
|
|
42
|
-
onSelect,
|
|
43
|
-
showLunar = true,
|
|
44
|
-
locale = 'vi',
|
|
45
|
-
dayCell,
|
|
46
|
-
children,
|
|
47
|
-
}: Props = $props();
|
|
48
|
-
|
|
49
|
-
// State nội bộ cho navigation (khởi tạo từ props hoặc giá trị mặc định)
|
|
50
|
-
let currentMonth = $state(month ?? new Date().getMonth() + 1);
|
|
51
|
-
let currentYear = $state(year ?? new Date().getFullYear());
|
|
52
|
-
|
|
53
|
-
// Tên thứ trong tuần
|
|
54
|
-
const weekDayLabels = $derived(
|
|
55
|
-
locale === 'vi'
|
|
56
|
-
? ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7']
|
|
57
|
-
: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
// Tên tháng hiển thị
|
|
61
|
-
const monthNames = [
|
|
62
|
-
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
|
|
63
|
-
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
// Can Chi năm hiển thị
|
|
67
|
-
let yearInfo = $derived(getYearDetails(currentYear));
|
|
68
|
-
|
|
69
|
-
// Ngày hôm nay
|
|
70
|
-
const today = new Date();
|
|
71
|
-
const todayStr = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
|
|
72
|
-
|
|
73
|
-
// Tính grid lịch 6x7 = 42 ô
|
|
74
|
-
let calendarGrid = $derived.by((): DayCellData[] => {
|
|
75
|
-
const grid: DayCellData[] = [];
|
|
76
|
-
|
|
77
|
-
// Ngày đầu tiên của tháng
|
|
78
|
-
const firstDay = new Date(currentYear, currentMonth - 1, 1);
|
|
79
|
-
// Thứ của ngày đầu tiên (0=CN, 1=T2, ...)
|
|
80
|
-
const startDayOfWeek = firstDay.getDay();
|
|
81
|
-
// Số ngày trong tháng
|
|
82
|
-
const daysInMonth = new Date(currentYear, currentMonth, 0).getDate();
|
|
83
|
-
|
|
84
|
-
// Padding ngày tháng trước
|
|
85
|
-
const prevMonthDays = new Date(currentYear, currentMonth - 1, 0).getDate();
|
|
86
|
-
for (let i = startDayOfWeek - 1; i >= 0; i--) {
|
|
87
|
-
const d = prevMonthDays - i;
|
|
88
|
-
const m = currentMonth - 1 <= 0 ? 12 : currentMonth - 1;
|
|
89
|
-
const y = currentMonth - 1 <= 0 ? currentYear - 1 : currentYear;
|
|
90
|
-
const solar = new Date(y, m - 1, d);
|
|
91
|
-
const lunar = LichTa.toLunar(d, m, y);
|
|
92
|
-
const dateStr = `${y}-${m}-${d}`;
|
|
93
|
-
const selStr = selectedDate
|
|
94
|
-
? `${selectedDate.getFullYear()}-${selectedDate.getMonth() + 1}-${selectedDate.getDate()}`
|
|
95
|
-
: '';
|
|
96
|
-
|
|
97
|
-
grid.push({
|
|
98
|
-
solar,
|
|
99
|
-
lunar,
|
|
100
|
-
isToday: dateStr === todayStr,
|
|
101
|
-
isSelected: dateStr === selStr,
|
|
102
|
-
isCurrentMonth: false,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Ngày trong tháng hiện tại
|
|
107
|
-
for (let d = 1; d <= daysInMonth; d++) {
|
|
108
|
-
const solar = new Date(currentYear, currentMonth - 1, d);
|
|
109
|
-
const lunar = LichTa.toLunar(d, currentMonth, currentYear);
|
|
110
|
-
const dateStr = `${currentYear}-${currentMonth}-${d}`;
|
|
111
|
-
const selStr = selectedDate
|
|
112
|
-
? `${selectedDate.getFullYear()}-${selectedDate.getMonth() + 1}-${selectedDate.getDate()}`
|
|
113
|
-
: '';
|
|
114
|
-
|
|
115
|
-
grid.push({
|
|
116
|
-
solar,
|
|
117
|
-
lunar,
|
|
118
|
-
isToday: dateStr === todayStr,
|
|
119
|
-
isSelected: dateStr === selStr,
|
|
120
|
-
isCurrentMonth: true,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Padding ngày tháng sau
|
|
125
|
-
const remaining = 42 - grid.length;
|
|
126
|
-
for (let d = 1; d <= remaining; d++) {
|
|
127
|
-
const m = currentMonth + 1 > 12 ? 1 : currentMonth + 1;
|
|
128
|
-
const y = currentMonth + 1 > 12 ? currentYear + 1 : currentYear;
|
|
129
|
-
const solar = new Date(y, m - 1, d);
|
|
130
|
-
const lunar = LichTa.toLunar(d, m, y);
|
|
131
|
-
const dateStr = `${y}-${m}-${d}`;
|
|
132
|
-
const selStr = selectedDate
|
|
133
|
-
? `${selectedDate.getFullYear()}-${selectedDate.getMonth() + 1}-${selectedDate.getDate()}`
|
|
134
|
-
: '';
|
|
135
|
-
|
|
136
|
-
grid.push({
|
|
137
|
-
solar,
|
|
138
|
-
lunar,
|
|
139
|
-
isToday: dateStr === todayStr,
|
|
140
|
-
isSelected: dateStr === selStr,
|
|
141
|
-
isCurrentMonth: false,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return grid;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Navigation
|
|
149
|
-
function prevMonth() {
|
|
150
|
-
if (currentMonth === 1) {
|
|
151
|
-
currentMonth = 12;
|
|
152
|
-
currentYear -= 1;
|
|
153
|
-
} else {
|
|
154
|
-
currentMonth -= 1;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function nextMonth() {
|
|
159
|
-
if (currentMonth === 12) {
|
|
160
|
-
currentMonth = 1;
|
|
161
|
-
currentYear += 1;
|
|
162
|
-
} else {
|
|
163
|
-
currentMonth += 1;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function handleDayClick(cell: DayCellData) {
|
|
168
|
-
onSelect?.(cell.solar, cell.lunar);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function handleKeydown(event: KeyboardEvent, cell: DayCellData) {
|
|
172
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
173
|
-
event.preventDefault();
|
|
174
|
-
handleDayClick(cell);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
</script>
|
|
178
|
-
|
|
179
|
-
<div class="lich-ta-calendar">
|
|
180
|
-
<!-- Header: Navigation + Tháng/Năm -->
|
|
181
|
-
<div class="lich-ta-calendar-header">
|
|
182
|
-
<button class="lich-ta-calendar-nav" onclick={prevMonth} aria-label="Tháng trước">◀</button>
|
|
183
|
-
<div class="lich-ta-calendar-title">
|
|
184
|
-
<span class="lich-ta-calendar-month-year">
|
|
185
|
-
{monthNames[currentMonth - 1]}, {currentYear}
|
|
186
|
-
</span>
|
|
187
|
-
<span class="lich-ta-calendar-canchi">
|
|
188
|
-
{yearInfo.can} {yearInfo.chi}
|
|
189
|
-
</span>
|
|
190
|
-
</div>
|
|
191
|
-
<button class="lich-ta-calendar-nav" onclick={nextMonth} aria-label="Tháng sau">▶</button>
|
|
192
|
-
</div>
|
|
193
|
-
|
|
194
|
-
<!-- Tên thứ -->
|
|
195
|
-
<div class="lich-ta-calendar-weekdays">
|
|
196
|
-
{#each weekDayLabels as label}
|
|
197
|
-
<div class="lich-ta-calendar-weekday">{label}</div>
|
|
198
|
-
{/each}
|
|
199
|
-
</div>
|
|
200
|
-
|
|
201
|
-
<!-- Grid ngày -->
|
|
202
|
-
<div class="lich-ta-calendar-grid">
|
|
203
|
-
{#each calendarGrid as cell}
|
|
204
|
-
{#if dayCell}
|
|
205
|
-
{@render dayCell(cell)}
|
|
206
|
-
{:else}
|
|
207
|
-
<button
|
|
208
|
-
class="lich-ta-calendar-day"
|
|
209
|
-
class:is-today={cell.isToday}
|
|
210
|
-
class:is-selected={cell.isSelected}
|
|
211
|
-
class:is-other-month={!cell.isCurrentMonth}
|
|
212
|
-
class:is-first-lunar={cell.lunar.day === 1}
|
|
213
|
-
onclick={() => handleDayClick(cell)}
|
|
214
|
-
onkeydown={(e) => handleKeydown(e, cell)}
|
|
215
|
-
tabindex={cell.isCurrentMonth ? 0 : -1}
|
|
216
|
-
>
|
|
217
|
-
<span class="solar-day">{cell.solar.getDate()}</span>
|
|
218
|
-
{#if showLunar}
|
|
219
|
-
<span class="lunar-day">
|
|
220
|
-
{#if cell.lunar.day === 1}
|
|
221
|
-
{cell.lunar.day}/{cell.lunar.month}{cell.lunar.isLeap ? '*' : ''}
|
|
222
|
-
{:else}
|
|
223
|
-
{cell.lunar.day}
|
|
224
|
-
{/if}
|
|
225
|
-
</span>
|
|
226
|
-
{/if}
|
|
227
|
-
</button>
|
|
228
|
-
{/if}
|
|
229
|
-
{/each}
|
|
230
|
-
</div>
|
|
231
|
-
|
|
232
|
-
<!-- Slot cho nội dung tùy chỉnh bên dưới lịch -->
|
|
233
|
-
{#if children}
|
|
234
|
-
<div class="lich-ta-calendar-footer">
|
|
235
|
-
{@render children()}
|
|
236
|
-
</div>
|
|
237
|
-
{/if}
|
|
238
|
-
</div>
|
|
239
|
-
|
|
240
|
-
<style>
|
|
241
|
-
.lich-ta-calendar {
|
|
242
|
-
--lichta-primary: #d4a373;
|
|
243
|
-
--lichta-primary-light: #f5e6d3;
|
|
244
|
-
--lichta-bg: #fffcf7;
|
|
245
|
-
--lichta-surface: #ffffff;
|
|
246
|
-
--lichta-text: #2c1810;
|
|
247
|
-
--lichta-text-muted: #8b7355;
|
|
248
|
-
--lichta-text-dim: #c4b5a0;
|
|
249
|
-
--lichta-border: #e8ddd0;
|
|
250
|
-
--lichta-today-bg: #d4a373;
|
|
251
|
-
--lichta-today-text: #ffffff;
|
|
252
|
-
--lichta-selected-bg: #a0522d;
|
|
253
|
-
--lichta-selected-text: #ffffff;
|
|
254
|
-
--lichta-hover-bg: #f5e6d3;
|
|
255
|
-
--lichta-lunar-text: #b08968;
|
|
256
|
-
--lichta-first-lunar: #c2185b;
|
|
257
|
-
--lichta-radius: 8px;
|
|
258
|
-
--lichta-font: inherit;
|
|
259
|
-
|
|
260
|
-
font-family: var(--lichta-font);
|
|
261
|
-
background: var(--lichta-bg);
|
|
262
|
-
border: 1px solid var(--lichta-border);
|
|
263
|
-
border-radius: calc(var(--lichta-radius) * 2);
|
|
264
|
-
padding: 16px;
|
|
265
|
-
max-width: 420px;
|
|
266
|
-
width: 100%;
|
|
267
|
-
box-sizing: border-box;
|
|
268
|
-
user-select: none;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/* Header */
|
|
272
|
-
.lich-ta-calendar-header {
|
|
273
|
-
display: flex;
|
|
274
|
-
align-items: center;
|
|
275
|
-
justify-content: space-between;
|
|
276
|
-
margin-bottom: 16px;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
.lich-ta-calendar-nav {
|
|
280
|
-
background: none;
|
|
281
|
-
border: 1px solid var(--lichta-border);
|
|
282
|
-
border-radius: var(--lichta-radius);
|
|
283
|
-
width: 36px;
|
|
284
|
-
height: 36px;
|
|
285
|
-
display: flex;
|
|
286
|
-
align-items: center;
|
|
287
|
-
justify-content: center;
|
|
288
|
-
cursor: pointer;
|
|
289
|
-
color: var(--lichta-text);
|
|
290
|
-
font-size: 0.85rem;
|
|
291
|
-
transition: all 0.15s ease;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
.lich-ta-calendar-nav:hover {
|
|
295
|
-
background: var(--lichta-hover-bg);
|
|
296
|
-
border-color: var(--lichta-primary);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
.lich-ta-calendar-title {
|
|
300
|
-
text-align: center;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
.lich-ta-calendar-month-year {
|
|
304
|
-
display: block;
|
|
305
|
-
font-size: 1.1rem;
|
|
306
|
-
font-weight: 600;
|
|
307
|
-
color: var(--lichta-text);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.lich-ta-calendar-canchi {
|
|
311
|
-
display: block;
|
|
312
|
-
font-size: 0.8rem;
|
|
313
|
-
color: var(--lichta-text-muted);
|
|
314
|
-
margin-top: 2px;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/* Weekdays */
|
|
318
|
-
.lich-ta-calendar-weekdays {
|
|
319
|
-
display: grid;
|
|
320
|
-
grid-template-columns: repeat(7, 1fr);
|
|
321
|
-
margin-bottom: 4px;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.lich-ta-calendar-weekday {
|
|
325
|
-
text-align: center;
|
|
326
|
-
font-size: 0.75rem;
|
|
327
|
-
font-weight: 600;
|
|
328
|
-
color: var(--lichta-text-muted);
|
|
329
|
-
padding: 6px 0;
|
|
330
|
-
text-transform: uppercase;
|
|
331
|
-
letter-spacing: 0.05em;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/* Grid */
|
|
335
|
-
.lich-ta-calendar-grid {
|
|
336
|
-
display: grid;
|
|
337
|
-
grid-template-columns: repeat(7, 1fr);
|
|
338
|
-
gap: 2px;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
.lich-ta-calendar-day {
|
|
342
|
-
display: flex;
|
|
343
|
-
flex-direction: column;
|
|
344
|
-
align-items: center;
|
|
345
|
-
justify-content: center;
|
|
346
|
-
padding: 6px 2px;
|
|
347
|
-
min-height: 48px;
|
|
348
|
-
border: none;
|
|
349
|
-
border-radius: var(--lichta-radius);
|
|
350
|
-
background: transparent;
|
|
351
|
-
cursor: pointer;
|
|
352
|
-
transition: all 0.15s ease;
|
|
353
|
-
font-family: inherit;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
.lich-ta-calendar-day:hover {
|
|
357
|
-
background: var(--lichta-hover-bg);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
.lich-ta-calendar-day:focus-visible {
|
|
361
|
-
outline: 2px solid var(--lichta-primary);
|
|
362
|
-
outline-offset: 1px;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
.solar-day {
|
|
366
|
-
font-size: 0.95rem;
|
|
367
|
-
font-weight: 500;
|
|
368
|
-
color: var(--lichta-text);
|
|
369
|
-
line-height: 1.2;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
.lunar-day {
|
|
373
|
-
font-size: 0.65rem;
|
|
374
|
-
color: var(--lichta-lunar-text);
|
|
375
|
-
line-height: 1.2;
|
|
376
|
-
margin-top: 1px;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/* States */
|
|
380
|
-
.is-other-month .solar-day {
|
|
381
|
-
color: var(--lichta-text-dim);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
.is-other-month .lunar-day {
|
|
385
|
-
color: var(--lichta-text-dim);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
.is-today {
|
|
389
|
-
background: var(--lichta-today-bg);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
.is-today .solar-day {
|
|
393
|
-
color: var(--lichta-today-text);
|
|
394
|
-
font-weight: 700;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
.is-today .lunar-day {
|
|
398
|
-
color: var(--lichta-today-text);
|
|
399
|
-
opacity: 0.85;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
.is-today:hover {
|
|
403
|
-
background: var(--lichta-today-bg);
|
|
404
|
-
opacity: 0.9;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
.is-selected {
|
|
408
|
-
background: var(--lichta-selected-bg);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
.is-selected .solar-day {
|
|
412
|
-
color: var(--lichta-selected-text);
|
|
413
|
-
font-weight: 700;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.is-selected .lunar-day {
|
|
417
|
-
color: var(--lichta-selected-text);
|
|
418
|
-
opacity: 0.85;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
.is-first-lunar .lunar-day {
|
|
422
|
-
color: var(--lichta-first-lunar);
|
|
423
|
-
font-weight: 600;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
.is-today.is-first-lunar .lunar-day,
|
|
427
|
-
.is-selected.is-first-lunar .lunar-day {
|
|
428
|
-
color: var(--lichta-today-text);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/* Footer */
|
|
432
|
-
.lich-ta-calendar-footer {
|
|
433
|
-
margin-top: 12px;
|
|
434
|
-
padding-top: 12px;
|
|
435
|
-
border-top: 1px solid var(--lichta-border);
|
|
436
|
-
}
|
|
437
|
-
</style>
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { LunarDate } from '../core/types.js';
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { Locale } from '../constants/i18n.js';
|
|
4
|
-
/**
|
|
5
|
-
* Dữ liệu cho mỗi ô ngày trong lưới lịch
|
|
6
|
-
*/
|
|
7
|
-
interface DayCellData {
|
|
8
|
-
solar: Date;
|
|
9
|
-
lunar: LunarDate;
|
|
10
|
-
isToday: boolean;
|
|
11
|
-
isSelected: boolean;
|
|
12
|
-
isCurrentMonth: boolean;
|
|
13
|
-
}
|
|
14
|
-
interface Props {
|
|
15
|
-
/** Tháng hiển thị (1-12). Mặc định: tháng hiện tại */
|
|
16
|
-
month?: number;
|
|
17
|
-
/** Năm hiển thị. Mặc định: năm hiện tại */
|
|
18
|
-
year?: number;
|
|
19
|
-
/** Ngày được chọn */
|
|
20
|
-
selectedDate?: Date | null;
|
|
21
|
-
/** Callback khi chọn ngày */
|
|
22
|
-
onSelect?: (date: Date, lunar: LunarDate) => void;
|
|
23
|
-
/** Hiển thị ngày âm lịch bên dưới ngày dương */
|
|
24
|
-
showLunar?: boolean;
|
|
25
|
-
/** Locale (vi | en | ja | ko) */
|
|
26
|
-
locale?: Locale;
|
|
27
|
-
/** Custom snippet cho mỗi ô ngày */
|
|
28
|
-
dayCell?: Snippet<[DayCellData]>;
|
|
29
|
-
children?: Snippet;
|
|
30
|
-
}
|
|
31
|
-
declare const Calendar: import("svelte").Component<Props, {}, "">;
|
|
32
|
-
type Calendar = ReturnType<typeof Calendar>;
|
|
33
|
-
export default Calendar;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { LichTa } from '../core/lunar.js';
|
|
3
|
-
import type { LunarDate } from '../core/types.js';
|
|
4
|
-
import type { Snippet } from 'svelte';
|
|
5
|
-
|
|
6
|
-
// Props nhận vào từ consumer ứng dụng
|
|
7
|
-
interface Props {
|
|
8
|
-
date?: Date;
|
|
9
|
-
children?: Snippet;
|
|
10
|
-
}
|
|
11
|
-
let { date = new Date(), children }: Props = $props();
|
|
12
|
-
|
|
13
|
-
// Khai báo biến reactive tự động tính toán lại khi `date` thay đổi
|
|
14
|
-
let lunar: LunarDate = $derived.by(() => {
|
|
15
|
-
const d = date.getDate();
|
|
16
|
-
const m = date.getMonth() + 1; // Tháng trong JS tính từ 0
|
|
17
|
-
const y = date.getFullYear();
|
|
18
|
-
return LichTa.toLunar(d, m, y);
|
|
19
|
-
});
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<div class="lich-ta-formatter">
|
|
23
|
-
<div class="lunar-display-banner">
|
|
24
|
-
<span class="lunar-date">Ngày {lunar.day} tháng {lunar.month} (Âm lịch)</span>
|
|
25
|
-
<span class="can-chi-details">Năm {lunar.yearCanChi}</span>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<div class="control-slot-wrapper">
|
|
29
|
-
{@render children?.()}
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<style>
|
|
34
|
-
.lich-ta-formatter {
|
|
35
|
-
display: block;
|
|
36
|
-
width: 100%;
|
|
37
|
-
box-sizing: border-box;
|
|
38
|
-
}
|
|
39
|
-
.lunar-display-banner {
|
|
40
|
-
padding: 12px;
|
|
41
|
-
background-color: #fcfaf7;
|
|
42
|
-
border-left: 4px solid #d4a373;
|
|
43
|
-
margin-bottom: 16px;
|
|
44
|
-
}
|
|
45
|
-
.lunar-date {
|
|
46
|
-
display: block;
|
|
47
|
-
font-weight: bold;
|
|
48
|
-
font-size: 1.1rem;
|
|
49
|
-
color: #1a1a1a;
|
|
50
|
-
}
|
|
51
|
-
.can-chi-details {
|
|
52
|
-
display: block;
|
|
53
|
-
font-size: 0.9rem;
|
|
54
|
-
color: #666666;
|
|
55
|
-
margin-top: 4px;
|
|
56
|
-
}
|
|
57
|
-
</style>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Earthly Branches (Địa Chi - 12 con giáp)
|
|
3
|
-
* Tý | Rat (Chuột)
|
|
4
|
-
* Sửu | Ox (Trâu)
|
|
5
|
-
* Dần | Tiger (Cọp)
|
|
6
|
-
* Mão | Rabbit (Thỏ)
|
|
7
|
-
* Thìn | Dragon (Rồng)
|
|
8
|
-
* Tỵ | Snake (Rắn)
|
|
9
|
-
* Ngọ | Horse (Ngựa)
|
|
10
|
-
* Mùi | Goat (Dê)
|
|
11
|
-
* Thân | Monkey (Khỉ)
|
|
12
|
-
* Dậu | Rooster (Gà)
|
|
13
|
-
* Tuất | Dog (Chó)
|
|
14
|
-
* Hợi | Pig (Heo)
|
|
15
|
-
*/
|
|
16
|
-
export declare const EARTHLY_BRANCHES: readonly ["Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi"];
|
|
17
|
-
/**
|
|
18
|
-
* Tính trọng số của Địa Chi (dùng để tính Ngũ Hành)
|
|
19
|
-
* Chu kỳ lặp lại sau mỗi 6 Chi (index % 6)
|
|
20
|
-
*/
|
|
21
|
-
export declare function getBranchWeight(index: number): number;
|
|
22
|
-
/**
|
|
23
|
-
* Tính Dương - Âm (Yin - Yang) cho Địa Chi
|
|
24
|
-
* Index: 0 -> 1 (Dương) | 1 -> 0 (Âm) | ...
|
|
25
|
-
*/
|
|
26
|
-
export declare function getBranchYinYang(index: number): 1 | 0;
|
|
27
|
-
/**
|
|
28
|
-
* Tính Ngũ Hành cho Địa Chi
|
|
29
|
-
* Tý: 1 (Thủy Dương), Sửu: 12 (Thổ Âm), Dần: 3 (Mộc Dương), ...
|
|
30
|
-
*/
|
|
31
|
-
export declare function getBranchElement(index: number): number;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Earthly Branches (Địa Chi - 12 con giáp)
|
|
3
|
-
* Tý | Rat (Chuột)
|
|
4
|
-
* Sửu | Ox (Trâu)
|
|
5
|
-
* Dần | Tiger (Cọp)
|
|
6
|
-
* Mão | Rabbit (Thỏ)
|
|
7
|
-
* Thìn | Dragon (Rồng)
|
|
8
|
-
* Tỵ | Snake (Rắn)
|
|
9
|
-
* Ngọ | Horse (Ngựa)
|
|
10
|
-
* Mùi | Goat (Dê)
|
|
11
|
-
* Thân | Monkey (Khỉ)
|
|
12
|
-
* Dậu | Rooster (Gà)
|
|
13
|
-
* Tuất | Dog (Chó)
|
|
14
|
-
* Hợi | Pig (Heo)
|
|
15
|
-
*/
|
|
16
|
-
export const EARTHLY_BRANCHES = [
|
|
17
|
-
'Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ',
|
|
18
|
-
'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'
|
|
19
|
-
];
|
|
20
|
-
/**
|
|
21
|
-
* Tính trọng số của Địa Chi (dùng để tính Ngũ Hành)
|
|
22
|
-
* Chu kỳ lặp lại sau mỗi 6 Chi (index % 6)
|
|
23
|
-
*/
|
|
24
|
-
export function getBranchWeight(index) {
|
|
25
|
-
const normalizedIndex = index % 6;
|
|
26
|
-
return Math.floor(normalizedIndex / 2);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Tính Dương - Âm (Yin - Yang) cho Địa Chi
|
|
30
|
-
* Index: 0 -> 1 (Dương) | 1 -> 0 (Âm) | ...
|
|
31
|
-
*/
|
|
32
|
-
export function getBranchYinYang(index) {
|
|
33
|
-
return (index % 2 === 0) ? 1 : 0;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Tính Ngũ Hành cho Địa Chi
|
|
37
|
-
* Tý: 1 (Thủy Dương), Sửu: 12 (Thổ Âm), Dần: 3 (Mộc Dương), ...
|
|
38
|
-
*/
|
|
39
|
-
export function getBranchElement(index) {
|
|
40
|
-
const weight = Math.floor(index / 2) + 1;
|
|
41
|
-
return weight === 5 ? 1 : weight;
|
|
42
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Heavenly Stems (Thiên Can)
|
|
3
|
-
* Giáp (Dương) | Wood
|
|
4
|
-
* Ất (Âm) | Wood
|
|
5
|
-
* Bính (Dương) | Fire
|
|
6
|
-
* Đinh (Âm) | Fire
|
|
7
|
-
* Mậu (Dương) | Earth
|
|
8
|
-
* Kỷ (Âm) | Earth
|
|
9
|
-
* Canh (Dương) | Metal
|
|
10
|
-
* Tân (Âm) | Metal
|
|
11
|
-
* Nhâm (Dương) | Water
|
|
12
|
-
* Quý (Âm) | Water
|
|
13
|
-
*/
|
|
14
|
-
export declare const HEAVENLY_STEMS: readonly ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"];
|
|
15
|
-
/**
|
|
16
|
-
* Tính trọng số của Thiên Can (dùng để tính Ngũ Hành)
|
|
17
|
-
* Index: 0, 1 -> 1 | 2, 3 -> 2 | ... | 8, 9 -> 5
|
|
18
|
-
*/
|
|
19
|
-
export declare function getStemWeight(index: number): number;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Heavenly Stems (Thiên Can)
|
|
3
|
-
* Giáp (Dương) | Wood
|
|
4
|
-
* Ất (Âm) | Wood
|
|
5
|
-
* Bính (Dương) | Fire
|
|
6
|
-
* Đinh (Âm) | Fire
|
|
7
|
-
* Mậu (Dương) | Earth
|
|
8
|
-
* Kỷ (Âm) | Earth
|
|
9
|
-
* Canh (Dương) | Metal
|
|
10
|
-
* Tân (Âm) | Metal
|
|
11
|
-
* Nhâm (Dương) | Water
|
|
12
|
-
* Quý (Âm) | Water
|
|
13
|
-
*/
|
|
14
|
-
export const HEAVENLY_STEMS = [
|
|
15
|
-
'Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu',
|
|
16
|
-
'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'
|
|
17
|
-
];
|
|
18
|
-
/**
|
|
19
|
-
* Tính trọng số của Thiên Can (dùng để tính Ngũ Hành)
|
|
20
|
-
* Index: 0, 1 -> 1 | 2, 3 -> 2 | ... | 8, 9 -> 5
|
|
21
|
-
*/
|
|
22
|
-
export function getStemWeight(index) {
|
|
23
|
-
return Math.floor(index / 2) + 1;
|
|
24
|
-
}
|