dsh-niuma 0.1.1 → 0.2.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/CHANGELOG.md +51 -0
- package/README.md +7 -0
- package/docs/preview-light-dark.png +0 -0
- package/lib/client.js +948 -259
- package/lib/client.js.map +2 -2
- package/lib/index.js +48 -118
- package/package.json +3 -8
- package/src/client/index.js +716 -208
- package/src/core.mjs +101 -0
- package/src/holidays.mjs +90 -10
package/lib/client.js
CHANGED
|
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
var import_react = __toESM(require("react"), 1);
|
|
39
39
|
|
|
40
40
|
// src/holidays.mjs
|
|
41
|
-
var
|
|
41
|
+
var OFFICIAL_HOLIDAYS_2026 = Object.freeze([
|
|
42
42
|
// 元旦:1月1日(周四)至3日(周六)
|
|
43
43
|
"2026-01-01",
|
|
44
44
|
"2026-01-02",
|
|
@@ -80,7 +80,7 @@ var DEFAULT_HOLIDAYS = Object.freeze([
|
|
|
80
80
|
"2026-10-06",
|
|
81
81
|
"2026-10-07"
|
|
82
82
|
]);
|
|
83
|
-
var
|
|
83
|
+
var OFFICIAL_EXTRA_WORKDAYS_2026 = Object.freeze([
|
|
84
84
|
"2026-01-04",
|
|
85
85
|
// 元旦调休:周日上班
|
|
86
86
|
"2026-02-14",
|
|
@@ -94,11 +94,88 @@ var DEFAULT_EXTRA_WORKDAYS = Object.freeze([
|
|
|
94
94
|
"2026-10-10"
|
|
95
95
|
// 国庆调休:周六上班
|
|
96
96
|
]);
|
|
97
|
+
var HOLIDAY_BLOCKS = Object.freeze([
|
|
98
|
+
{ id: "newYear", year: 2026, from: "2026-01-01", to: "2026-01-03", days: 3, estimated: false },
|
|
99
|
+
{ id: "spring", year: 2026, from: "2026-02-15", to: "2026-02-23", days: 9, estimated: false },
|
|
100
|
+
{ id: "qingming", year: 2026, from: "2026-04-04", to: "2026-04-06", days: 3, estimated: false },
|
|
101
|
+
{ id: "labour", year: 2026, from: "2026-05-01", to: "2026-05-05", days: 5, estimated: false },
|
|
102
|
+
{ id: "dragon", year: 2026, from: "2026-06-19", to: "2026-06-21", days: 3, estimated: false },
|
|
103
|
+
{ id: "midAutumn", year: 2026, from: "2026-09-25", to: "2026-09-27", days: 3, estimated: false },
|
|
104
|
+
{ id: "national", year: 2026, from: "2026-10-01", to: "2026-10-07", days: 7, estimated: false }
|
|
105
|
+
]);
|
|
97
106
|
var HOLIDAY_SOURCE = Object.freeze({
|
|
98
107
|
year: 2026,
|
|
108
|
+
estimated: false,
|
|
99
109
|
title: "\u56FD\u52A1\u9662\u529E\u516C\u5385\u5173\u4E8E2026\u5E74\u90E8\u5206\u8282\u5047\u65E5\u5B89\u6392\u7684\u901A\u77E5\uFF08\u56FD\u529E\u53D1\u660E\u7535\u30142025\u30157\u53F7\uFF09",
|
|
100
110
|
url: "https://www.gov.cn/zhengce/content/202511/content_7047090.htm"
|
|
101
111
|
});
|
|
112
|
+
var ESTIMATED_HOLIDAYS_2027 = Object.freeze([
|
|
113
|
+
"2027-01-01",
|
|
114
|
+
"2027-01-02",
|
|
115
|
+
"2027-01-03",
|
|
116
|
+
"2027-02-05",
|
|
117
|
+
"2027-02-06",
|
|
118
|
+
"2027-02-07",
|
|
119
|
+
"2027-02-08",
|
|
120
|
+
"2027-02-09",
|
|
121
|
+
"2027-02-10",
|
|
122
|
+
"2027-02-11",
|
|
123
|
+
"2027-02-12",
|
|
124
|
+
"2027-02-13",
|
|
125
|
+
"2027-04-03",
|
|
126
|
+
"2027-04-04",
|
|
127
|
+
"2027-04-05",
|
|
128
|
+
"2027-05-01",
|
|
129
|
+
"2027-05-02",
|
|
130
|
+
"2027-05-03",
|
|
131
|
+
"2027-05-04",
|
|
132
|
+
"2027-05-05",
|
|
133
|
+
"2027-06-09",
|
|
134
|
+
"2027-09-15",
|
|
135
|
+
"2027-10-01",
|
|
136
|
+
"2027-10-02",
|
|
137
|
+
"2027-10-03",
|
|
138
|
+
"2027-10-04",
|
|
139
|
+
"2027-10-05",
|
|
140
|
+
"2027-10-06",
|
|
141
|
+
"2027-10-07"
|
|
142
|
+
]);
|
|
143
|
+
var ESTIMATED_EXTRA_WORKDAYS_2027 = Object.freeze([
|
|
144
|
+
"2027-01-31",
|
|
145
|
+
// 春节调休:周日上班(预估)
|
|
146
|
+
"2027-02-14",
|
|
147
|
+
// 春节调休:周日上班(预估)
|
|
148
|
+
"2027-05-08",
|
|
149
|
+
// 劳动节调休:周六上班(预估)
|
|
150
|
+
"2027-09-26",
|
|
151
|
+
// 国庆调休:周日上班(预估)
|
|
152
|
+
"2027-10-09"
|
|
153
|
+
// 国庆调休:周六上班(预估)
|
|
154
|
+
]);
|
|
155
|
+
var HOLIDAY_BLOCKS_2027_ESTIMATED = Object.freeze([
|
|
156
|
+
{ id: "newYear", year: 2027, from: "2027-01-01", to: "2027-01-03", days: 3, estimated: true },
|
|
157
|
+
{ id: "spring", year: 2027, from: "2027-02-05", to: "2027-02-13", days: 9, estimated: true },
|
|
158
|
+
{ id: "qingming", year: 2027, from: "2027-04-03", to: "2027-04-05", days: 3, estimated: true },
|
|
159
|
+
{ id: "labour", year: 2027, from: "2027-05-01", to: "2027-05-05", days: 5, estimated: true },
|
|
160
|
+
{ id: "dragon", year: 2027, from: "2027-06-09", to: "2027-06-09", days: 1, estimated: true },
|
|
161
|
+
{ id: "midAutumn", year: 2027, from: "2027-09-15", to: "2027-09-15", days: 1, estimated: true },
|
|
162
|
+
{ id: "national", year: 2027, from: "2027-10-01", to: "2027-10-07", days: 7, estimated: true }
|
|
163
|
+
]);
|
|
164
|
+
var HOLIDAY_ESTIMATE_2027 = Object.freeze({
|
|
165
|
+
year: 2027,
|
|
166
|
+
estimated: true,
|
|
167
|
+
announced: false,
|
|
168
|
+
title: "2027 \u5E74\u653E\u5047\u5B89\u6392\uFF08\u9884\u4F30\uFF0C\u5B98\u65B9\u5C1A\u672A\u516C\u5E03\uFF09",
|
|
169
|
+
note: "\u5B98\u65B9\u901A\u77E5\u901A\u5E38\u5728\u524D\u4E00\u5E74 11 \u6708\u521D\u53D1\u5E03\uFF1B\u4EE5\u4E0B\u4E3A\u6309 2024 \u5E74\u4FEE\u8BA2\u7684\u300A\u5168\u56FD\u5E74\u8282\u53CA\u7EAA\u5FF5\u65E5\u653E\u5047\u529E\u6CD5\u300B\u4E0E\u5F80\u5E74\u60EF\u4F8B\u63A8\u7B97\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF0C\u8BF7\u4EE5\u56FD\u52A1\u9662\u901A\u77E5\u4E3A\u51C6\u3002",
|
|
170
|
+
basis: [
|
|
171
|
+
"\u6625\u8282\u81EA\u9664\u5915\u8D77\u653E\u5047\u8C03\u4F11\uFF0C\u4E00\u822C\u8FDE\u4F11 8\u20139 \u5929",
|
|
172
|
+
"\u56FD\u5E86 7 \u5929\u3001\u52B3\u52A8\u8282 5 \u5929",
|
|
173
|
+
"\u5143\u65E6 / \u6E05\u660E / \u7AEF\u5348 / \u4E2D\u79CB\u5404 1 \u5929\u6CD5\u5B9A\u5047\uFF0C\u9047\u5468\u672B\u987A\u8FDE"
|
|
174
|
+
],
|
|
175
|
+
url: "https://www.gov.cn/zhengce/xxgk/"
|
|
176
|
+
});
|
|
177
|
+
var DEFAULT_HOLIDAYS = Object.freeze([...OFFICIAL_HOLIDAYS_2026, ...ESTIMATED_HOLIDAYS_2027]);
|
|
178
|
+
var DEFAULT_EXTRA_WORKDAYS = Object.freeze([...OFFICIAL_EXTRA_WORKDAYS_2026, ...ESTIMATED_EXTRA_WORKDAYS_2027]);
|
|
102
179
|
|
|
103
180
|
// src/core.mjs
|
|
104
181
|
var DEFAULTS = Object.freeze({
|
|
@@ -307,6 +384,13 @@ function earnedToday(config, now) {
|
|
|
307
384
|
const monthEarned = earnedThisMonth(config, key, date, todayEarned, rates);
|
|
308
385
|
const secondsToStart = workday && nowSec < startSec ? startSec - nowSec : 0;
|
|
309
386
|
const secondsToEnd = workday && nowSec < endSec ? endSec - nowSec : 0;
|
|
387
|
+
const monthWorkdays = rates.monthlyWorkdays;
|
|
388
|
+
let monthWorkdaysDone = 0;
|
|
389
|
+
for (let day = 1; day < date.getDate(); day += 1) {
|
|
390
|
+
if (isWorkday(dateKeyOf(new Date(date.getFullYear(), date.getMonth(), day)), config)) monthWorkdaysDone += 1;
|
|
391
|
+
}
|
|
392
|
+
if (workday && status === "off") monthWorkdaysDone += 1;
|
|
393
|
+
const monthWorkdaysLeft = Math.max(0, monthWorkdays - monthWorkdaysDone);
|
|
310
394
|
return {
|
|
311
395
|
dateKey: key,
|
|
312
396
|
isWorkday: workday,
|
|
@@ -317,6 +401,9 @@ function earnedToday(config, now) {
|
|
|
317
401
|
todayTarget,
|
|
318
402
|
todayProgress,
|
|
319
403
|
monthEarned,
|
|
404
|
+
monthWorkdays,
|
|
405
|
+
monthWorkdaysDone,
|
|
406
|
+
monthWorkdaysLeft,
|
|
320
407
|
secondsToStart,
|
|
321
408
|
secondsToEnd,
|
|
322
409
|
rates
|
|
@@ -359,6 +446,68 @@ function formatDuration(seconds) {
|
|
|
359
446
|
if (minutes > 0) return `${minutes}\u5206 ${rest}\u79D2`;
|
|
360
447
|
return `${rest}\u79D2`;
|
|
361
448
|
}
|
|
449
|
+
function holidayDaysInMonth(year, monthIndex, config) {
|
|
450
|
+
const prefix = `${year}-${String(monthIndex + 1).padStart(2, "0")}-`;
|
|
451
|
+
return (config.holidays ?? DEFAULTS.holidays).filter((key) => key.startsWith(prefix)).length;
|
|
452
|
+
}
|
|
453
|
+
function monthSummary(config, year, monthIndex) {
|
|
454
|
+
const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
|
|
455
|
+
const workdays = workdaysInMonth(year, monthIndex, config);
|
|
456
|
+
const holidayDays = holidayDaysInMonth(year, monthIndex, config);
|
|
457
|
+
const monthlySalary = Number(config.monthlySalary) || 0;
|
|
458
|
+
const paidMinutes = paidMinutesPerDay(config);
|
|
459
|
+
const paidHours = paidMinutes / 60;
|
|
460
|
+
const dailyWage = workdays > 0 ? monthlySalary / workdays : 0;
|
|
461
|
+
const hourlyWage = paidHours > 0 ? dailyWage / paidHours : 0;
|
|
462
|
+
return {
|
|
463
|
+
year,
|
|
464
|
+
monthIndex,
|
|
465
|
+
month: monthIndex + 1,
|
|
466
|
+
daysInMonth,
|
|
467
|
+
workdays,
|
|
468
|
+
holidayDays,
|
|
469
|
+
restDays: daysInMonth - workdays,
|
|
470
|
+
monthlySalary,
|
|
471
|
+
paidMinutes,
|
|
472
|
+
paidHours,
|
|
473
|
+
dailyWage,
|
|
474
|
+
hourlyWage,
|
|
475
|
+
minuteWage: hourlyWage / 60,
|
|
476
|
+
secondWage: hourlyWage / 3600
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function yearSummary(config, year) {
|
|
480
|
+
const months = Array.from({ length: 12 }, (_, monthIndex) => monthSummary(config, year, monthIndex));
|
|
481
|
+
const totalWorkdays = months.reduce((sum, item) => sum + item.workdays, 0);
|
|
482
|
+
const totalHolidayDays = months.reduce((sum, item) => sum + item.holidayDays, 0);
|
|
483
|
+
const monthlySalary = Number(config.monthlySalary) || 0;
|
|
484
|
+
const annualIncome = monthlySalary * 12;
|
|
485
|
+
const paidMinutes = paidMinutesPerDay(config);
|
|
486
|
+
const paidHours = paidMinutes / 60;
|
|
487
|
+
const averageDailyWage = totalWorkdays > 0 ? annualIncome / totalWorkdays : 0;
|
|
488
|
+
const averageHourlyWage = paidHours > 0 ? averageDailyWage / paidHours : 0;
|
|
489
|
+
const maxHolidayMonth = months.reduce((best, item) => {
|
|
490
|
+
if (item.holidayDays !== best.holidayDays) return item.holidayDays > best.holidayDays ? item : best;
|
|
491
|
+
if (item.workdays !== best.workdays) return item.workdays < best.workdays ? item : best;
|
|
492
|
+
return item.month < best.month ? item : best;
|
|
493
|
+
}, months[0]);
|
|
494
|
+
return {
|
|
495
|
+
year,
|
|
496
|
+
months,
|
|
497
|
+
totalWorkdays,
|
|
498
|
+
totalHolidayDays,
|
|
499
|
+
paidMinutes,
|
|
500
|
+
paidHours,
|
|
501
|
+
monthlySalary,
|
|
502
|
+
annualIncome,
|
|
503
|
+
averageMonthlyWage: monthlySalary,
|
|
504
|
+
averageDailyWage,
|
|
505
|
+
averageHourlyWage,
|
|
506
|
+
averageMinuteWage: averageHourlyWage / 60,
|
|
507
|
+
averageSecondWage: averageHourlyWage / 3600,
|
|
508
|
+
maxHolidayMonth
|
|
509
|
+
};
|
|
510
|
+
}
|
|
362
511
|
|
|
363
512
|
// src/client/index.js
|
|
364
513
|
var PKG_NAME = true ? "dsh-niuma" : "dsh-niuma";
|
|
@@ -388,6 +537,15 @@ var CARD = {
|
|
|
388
537
|
boxSizing: "border-box"
|
|
389
538
|
};
|
|
390
539
|
var NUM = { fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" };
|
|
540
|
+
var GOLD = {
|
|
541
|
+
color: "#D9A441",
|
|
542
|
+
backgroundImage: "linear-gradient(180deg, #FFE9A8 0%, #F2C14E 40%, #D79A2B 72%, #B87A16 100%)",
|
|
543
|
+
WebkitBackgroundClip: "text",
|
|
544
|
+
backgroundClip: "text",
|
|
545
|
+
WebkitTextFillColor: "transparent",
|
|
546
|
+
textShadow: "0 1px 0 rgba(0,0,0,.05)"
|
|
547
|
+
};
|
|
548
|
+
var GOLD_TINT = "#E7B84D";
|
|
391
549
|
var STATUS_META = {
|
|
392
550
|
rest: { key: "statusRest", color: C.label3 },
|
|
393
551
|
before: { key: "statusBefore", color: C.warn },
|
|
@@ -423,28 +581,75 @@ var zh = {
|
|
|
423
581
|
"paidHoursPerDay": "\u65E5\u6709\u6548\u5DE5\u65F6",
|
|
424
582
|
"todayTarget": "\u4ECA\u65E5\u76EE\u6807",
|
|
425
583
|
"monthEarned": "\u672C\u6708\u5DF2\u8D5A",
|
|
426
|
-
"
|
|
584
|
+
"monthWorkedDays": "\u672C\u6708\u5DF2\u5DE5\u4F5C",
|
|
585
|
+
"monthRemainingDays": "\u5269\u4F59\u5DE5\u4F5C\u65E5",
|
|
427
586
|
"holidaySourceLink": "\u56FD\u52A1\u9662\u529E\u516C\u5385 2026 \u5E74\u8282\u5047\u65E5\u5B89\u6392",
|
|
428
587
|
"configLoading": "\u6B63\u5728\u8BFB\u53D6\u8BBE\u7F6E\u2026",
|
|
429
588
|
"configFailed": "\u8BBE\u7F6E\u8BFB\u53D6\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C",
|
|
430
589
|
"retry": "\u91CD\u8BD5",
|
|
431
590
|
"settings": "\u8BBE\u7F6E",
|
|
432
591
|
"settingsHint": "\u6539\u5B8C\u70B9\u300C\u4FDD\u5B58\u300D\u751F\u6548\uFF1B\u683C\u5F0F\u4E0D\u5BF9\u4F1A\u5728\u4E0B\u65B9\u7EA2\u5B57\u63D0\u793A\uFF0C\u4E0D\u5F71\u54CD\u8BA1\u65F6\u3002",
|
|
433
|
-
"salaryField": "\u5B9E\u6536\u6708\u85AA
|
|
592
|
+
"salaryField": "\u5B9E\u6536\u6708\u85AA",
|
|
593
|
+
"groupSalary": "\u5DE5\u8D44",
|
|
594
|
+
"groupWorkTime": "\u5DE5\u4F5C\u65F6\u95F4",
|
|
595
|
+
"groupLunch": "\u5348\u4F11",
|
|
596
|
+
"salaryUnit": "\u5143 / \u6708",
|
|
434
597
|
"workStartField": "\u4E0A\u73ED\u65F6\u95F4",
|
|
435
598
|
"workEndField": "\u4E0B\u73ED\u65F6\u95F4",
|
|
436
599
|
"lunchEnabledField": "\u542F\u7528\u5348\u4F11",
|
|
600
|
+
"lunchEnabledShort": "\u542F\u7528",
|
|
437
601
|
"lunchStartField": "\u5348\u4F11\u5F00\u59CB",
|
|
438
602
|
"lunchEndField": "\u5348\u4F11\u7ED3\u675F",
|
|
439
603
|
"lunchPaidField": "\u5348\u4F11\u7B97\u5DE5\u65F6",
|
|
440
|
-
"
|
|
441
|
-
"
|
|
604
|
+
"lunchPaidShort": "\u7B97\u5DE5\u65F6",
|
|
605
|
+
"holidaysCardTitle": "\u8282\u5047\u65E5\u5B89\u6392",
|
|
606
|
+
"holidays2026Label": "2026 \u5E74\uFF08\u5B98\u65B9\uFF09",
|
|
607
|
+
"holidays2027Label": "2027 \u5E74\uFF08\u9884\u4F30\uFF09",
|
|
608
|
+
"holidayEstimateTag": "\u9884\u4F30",
|
|
609
|
+
"holidayEstimateNote": "\u5B98\u65B9\u5C1A\u672A\u516C\u5E03\uFF0C\u4EE5\u4E0A\u4E3A\u6309\u89C4\u5219\u4E0E\u60EF\u4F8B\u63A8\u7B97\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF0C\u4EE5\u56FD\u52A1\u9662\u901A\u77E5\u4E3A\u51C6\u3002",
|
|
610
|
+
"holidayEstimateShort": "2027 \u4E3A\u9884\u4F30\u503C",
|
|
611
|
+
"settingsDataNote": "\u8282\u5047\u65E5\u4E0E\u8C03\u4F11\u6570\u636E\u89C1\u4E0A\u65B9\u300C\u8282\u5047\u65E5\u5B89\u6392\u300D\u5361\u7247\uFF082027 \u5E74\u4E3A\u9884\u4F30\u503C\uFF0C\u4E0D\u53EF\u5728\u672C\u9875\u7F16\u8F91\uFF09\u3002",
|
|
612
|
+
"holidaysCardSub": "\u6CD5\u5B9A\u5047\u65E5 {days} \u5929 \xB7 \u8C03\u4F11\u4E0A\u73ED {extra} \u5929",
|
|
613
|
+
"holidaysDaysShort": "{days} \u5929",
|
|
614
|
+
"holidaysExtraNote": "\u8C03\u4F11\u4E0A\u73ED\u65E5 {extra} \u5929\uFF08\u5468\u672B\u8865\u73ED\uFF0C\u6309\u5DE5\u4F5C\u65E5\u8BA1\uFF09",
|
|
615
|
+
"holidayNewYear": "\u5143\u65E6",
|
|
616
|
+
"holidaySpring": "\u6625\u8282",
|
|
617
|
+
"holidayQingming": "\u6E05\u660E",
|
|
618
|
+
"holidayLabour": "\u52B3\u52A8\u8282",
|
|
619
|
+
"holidayDragon": "\u7AEF\u5348",
|
|
620
|
+
"holidayMidAutumn": "\u4E2D\u79CB",
|
|
621
|
+
"holidayNational": "\u56FD\u5E86",
|
|
442
622
|
"save": "\u4FDD\u5B58",
|
|
443
623
|
"saving": "\u4FDD\u5B58\u4E2D\u2026",
|
|
444
624
|
"saved": "\u5DF2\u4FDD\u5B58",
|
|
445
625
|
"saveFailed": "\u4FDD\u5B58\u5931\u8D25\uFF1A",
|
|
446
626
|
"dayUnit": "\u5929",
|
|
447
|
-
"hourUnit": "\u5C0F\u65F6"
|
|
627
|
+
"hourUnit": "\u5C0F\u65F6",
|
|
628
|
+
"minuteUnit": "\u5206\u949F",
|
|
629
|
+
"viewLabel": "\u67E5\u770B",
|
|
630
|
+
"viewCurrent": "\u672C\u6708",
|
|
631
|
+
"viewYear": "\u5168\u5E74\u5E73\u5747",
|
|
632
|
+
"monthUnit": "\u6708",
|
|
633
|
+
"holidayShort": "\u5047",
|
|
634
|
+
"currentHint": "\u6309\u6BCF\u6708 {days} \u4E2A\u5DE5\u4F5C\u65E5\u3001\u6BCF\u5929 {hours} \u5C0F\u65F6\u8BA1",
|
|
635
|
+
"monthHint": "{year} \u5E74 {month} \u6708 \xB7 \u5DE5\u4F5C\u65E5 {workdays} \u5929 \xB7 \u6CD5\u5B9A\u5047\u65E5 {holidays} \u5929",
|
|
636
|
+
"yearHint": "{year} \u5168\u5E74 \xB7 {workdays} \u4E2A\u5DE5\u4F5C\u65E5 \xB7 \u6309\u5E74\u6536\u5165\u6298\u7B97",
|
|
637
|
+
"viewOnlyHint": "\u4EC5\u6362\u7B97\uFF0C\u4E0D\u5F71\u54CD\u4ECA\u65E5\u8BA1\u6570\u5668",
|
|
638
|
+
"yearWorkdays": "\u5168\u5E74\u5DE5\u4F5C\u65E5",
|
|
639
|
+
"yearIncome": "\u5168\u5E74\u6536\u5165",
|
|
640
|
+
"averageDaily": "\u5E73\u5747\u65E5\u85AA",
|
|
641
|
+
"averageHourly": "\u5E73\u5747\u65F6\u85AA",
|
|
642
|
+
"averageMinute": "\u5E73\u5747\u5206\u85AA",
|
|
643
|
+
"averageSecond": "\u5E73\u5747\u79D2\u85AA",
|
|
644
|
+
"monthWorkdaysCard": "\u5DE5\u4F5C\u65E5",
|
|
645
|
+
"maxHolidayBadge": "\u5168\u5E74\u5047\u65E5\u6700\u591A",
|
|
646
|
+
"maxHolidayNote": "\u5168\u5E74\u5047\u65E5\u6700\u591A\uFF1A{month} \u6708\uFF08\u6CD5\u5B9A\u5047\u65E5 {days} \u5929\uFF09",
|
|
647
|
+
"maxHolidayThis": "\u5168\u5E74\u5047\u65E5\u6700\u591A\u7684\u6708\u4EFD\uFF08\u6CD5\u5B9A\u5047\u65E5 {days} \u5929\uFF09",
|
|
648
|
+
"sectionRates": "\u5DE5\u8D44\u6362\u7B97",
|
|
649
|
+
"sectionRatesHint": "\u6309\u6BCF\u6708 {days} \u4E2A\u5DE5\u4F5C\u65E5\u3001\u6BCF\u5929 {hours} \u5C0F\u65F6\u8BA1",
|
|
650
|
+
"sectionDetail": "\u4ECA\u65E5\u53E3\u5F84\u660E\u7EC6",
|
|
651
|
+
"restHint": "\u4ECA\u5929\u4F11\u606F\uFF0C\u597D\u597D\u8EBA\u5E73",
|
|
652
|
+
"liveNow": "\u5B9E\u65F6"
|
|
448
653
|
};
|
|
449
654
|
var en = {
|
|
450
655
|
"nav": "Niuma",
|
|
@@ -474,38 +679,82 @@ var en = {
|
|
|
474
679
|
"paidHoursPerDay": "Paid hours / day",
|
|
475
680
|
"todayTarget": "Today's target",
|
|
476
681
|
"monthEarned": "Earned this month",
|
|
477
|
-
"
|
|
682
|
+
"monthWorkedDays": "Worked this month",
|
|
683
|
+
"monthRemainingDays": "Workdays left",
|
|
478
684
|
"holidaySourceLink": "State Council 2026 holiday schedule",
|
|
479
685
|
"configLoading": "Loading settings\u2026",
|
|
480
686
|
"configFailed": "Failed to load settings, using defaults",
|
|
481
687
|
"retry": "Retry",
|
|
482
688
|
"settings": "Settings",
|
|
483
689
|
"settingsHint": "Click Save to apply. Invalid input is shown in red below; the ticker keeps running.",
|
|
484
|
-
"salaryField": "Net monthly salary
|
|
690
|
+
"salaryField": "Net monthly salary",
|
|
691
|
+
"groupSalary": "Salary",
|
|
692
|
+
"groupWorkTime": "Working hours",
|
|
693
|
+
"groupLunch": "Lunch break",
|
|
694
|
+
"salaryUnit": "CNY / month",
|
|
485
695
|
"workStartField": "Work start",
|
|
486
696
|
"workEndField": "Work end",
|
|
487
697
|
"lunchEnabledField": "Enable lunch break",
|
|
698
|
+
"lunchEnabledShort": "On",
|
|
488
699
|
"lunchStartField": "Lunch start",
|
|
489
700
|
"lunchEndField": "Lunch end",
|
|
490
701
|
"lunchPaidField": "Lunch is paid",
|
|
491
|
-
"
|
|
492
|
-
"
|
|
702
|
+
"lunchPaidShort": "Paid",
|
|
703
|
+
"holidaysCardTitle": "Holiday calendar",
|
|
704
|
+
"holidays2026Label": "2026 (official)",
|
|
705
|
+
"holidays2027Label": "2027 (estimated)",
|
|
706
|
+
"holidayEstimateTag": "estimate",
|
|
707
|
+
"holidayEstimateNote": "Not announced officially yet \u2014 estimated from the rules and past practice, for reference only.",
|
|
708
|
+
"holidayEstimateShort": "2027 is estimated",
|
|
709
|
+
"settingsDataNote": "Holiday data lives in the calendar card above (2027 values are estimates and not editable here).",
|
|
710
|
+
"holidaysCardSub": "{days} statutory days \xB7 {extra} make-up workdays",
|
|
711
|
+
"holidaysDaysShort": "{days} d",
|
|
712
|
+
"holidaysExtraNote": "{extra} make-up workdays (weekend shifts, counted as workdays)",
|
|
713
|
+
"holidayNewYear": "New Year's Day",
|
|
714
|
+
"holidaySpring": "Spring Festival",
|
|
715
|
+
"holidayQingming": "Qingming",
|
|
716
|
+
"holidayLabour": "Labour Day",
|
|
717
|
+
"holidayDragon": "Dragon Boat",
|
|
718
|
+
"holidayMidAutumn": "Mid-Autumn",
|
|
719
|
+
"holidayNational": "National Day",
|
|
493
720
|
"save": "Save",
|
|
494
721
|
"saving": "Saving\u2026",
|
|
495
722
|
"saved": "Saved",
|
|
496
723
|
"saveFailed": "Save failed: ",
|
|
497
724
|
"dayUnit": "d",
|
|
498
|
-
"hourUnit": "h"
|
|
725
|
+
"hourUnit": "h",
|
|
726
|
+
"minuteUnit": "min",
|
|
727
|
+
"viewLabel": "View",
|
|
728
|
+
"viewCurrent": "This month",
|
|
729
|
+
"viewYear": "Year average",
|
|
730
|
+
"monthUnit": "M",
|
|
731
|
+
"holidayShort": "hol.",
|
|
732
|
+
"currentHint": "{days} workdays / month \xB7 {hours} h / day",
|
|
733
|
+
"monthHint": "{year}-{month} \xB7 {workdays} workdays \xB7 {holidays} statutory holidays",
|
|
734
|
+
"yearHint": "{year} \xB7 {workdays} workdays \xB7 averaged over the year",
|
|
735
|
+
"viewOnlyHint": "Conversion only \u2014 today's ticker is unaffected",
|
|
736
|
+
"yearWorkdays": "Workdays / year",
|
|
737
|
+
"yearIncome": "Annual income",
|
|
738
|
+
"averageDaily": "Avg per day",
|
|
739
|
+
"averageHourly": "Avg per hour",
|
|
740
|
+
"averageMinute": "Avg per minute",
|
|
741
|
+
"averageSecond": "Avg per second",
|
|
742
|
+
"monthWorkdaysCard": "Workdays",
|
|
743
|
+
"maxHolidayBadge": "Most holidays",
|
|
744
|
+
"maxHolidayNote": "Most holidays: month {month} ({days} statutory days)",
|
|
745
|
+
"maxHolidayThis": "The month with the most holidays ({days} statutory days)",
|
|
746
|
+
"sectionRates": "Pay rates",
|
|
747
|
+
"sectionRatesHint": "{days} workdays / month \xB7 {hours} h / day",
|
|
748
|
+
"sectionDetail": "Today's basis",
|
|
749
|
+
"restHint": "Day off \u2014 enjoy it",
|
|
750
|
+
"liveNow": "LIVE"
|
|
499
751
|
};
|
|
500
752
|
var fallbackTranslate = (key) => zh[key] != null ? zh[key] : key;
|
|
501
|
-
var money = (value, digits = 2) =>
|
|
753
|
+
var money = (value, digits = 2) => `${formatMoney(value, digits)} \u5143`;
|
|
502
754
|
function trimNumber(value, digits = 2) {
|
|
503
755
|
const fixed = Number(value || 0).toFixed(digits);
|
|
504
756
|
return fixed.replace(/\.?0+$/, "") || "0";
|
|
505
757
|
}
|
|
506
|
-
function splitDateLines(text) {
|
|
507
|
-
return String(text == null ? "" : text).split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
508
|
-
}
|
|
509
758
|
function formFromConfig(config) {
|
|
510
759
|
return {
|
|
511
760
|
monthlySalary: String(config.monthlySalary == null ? "" : config.monthlySalary),
|
|
@@ -514,9 +763,7 @@ function formFromConfig(config) {
|
|
|
514
763
|
lunchEnabled: config.lunchEnabled !== false,
|
|
515
764
|
lunchStart: String(config.lunchStart == null ? "" : config.lunchStart),
|
|
516
765
|
lunchEnd: String(config.lunchEnd == null ? "" : config.lunchEnd),
|
|
517
|
-
lunchPaid: config.lunchPaid === true
|
|
518
|
-
holidaysText: (config.holidays || []).join("\n"),
|
|
519
|
-
extraWorkdaysText: (config.extraWorkdays || []).join("\n")
|
|
766
|
+
lunchPaid: config.lunchPaid === true
|
|
520
767
|
};
|
|
521
768
|
}
|
|
522
769
|
function patchFromForm(form) {
|
|
@@ -528,9 +775,7 @@ function patchFromForm(form) {
|
|
|
528
775
|
lunchEnabled: Boolean(form.lunchEnabled),
|
|
529
776
|
lunchStart: String(form.lunchStart || "").trim(),
|
|
530
777
|
lunchEnd: String(form.lunchEnd || "").trim(),
|
|
531
|
-
lunchPaid: Boolean(form.lunchPaid)
|
|
532
|
-
holidays: splitDateLines(form.holidaysText),
|
|
533
|
-
extraWorkdays: splitDateLines(form.extraWorkdaysText)
|
|
778
|
+
lunchPaid: Boolean(form.lunchPaid)
|
|
534
779
|
};
|
|
535
780
|
}
|
|
536
781
|
function useRemoteConfig() {
|
|
@@ -600,49 +845,110 @@ function NiumaIcon(props) {
|
|
|
600
845
|
import_react.default.createElement("path", { key: "c", d: "M4 8h.01M12 8h.01" })
|
|
601
846
|
]);
|
|
602
847
|
}
|
|
848
|
+
var PANEL_CSS = `
|
|
849
|
+
@keyframes niumaPulse { 0%,100% { opacity: .95; transform: scale(1); } 50% { opacity: .3; transform: scale(.68); } }
|
|
850
|
+
@media (prefers-reduced-motion: reduce) { .niuma-live-dot { animation: none !important; } }
|
|
851
|
+
`;
|
|
852
|
+
function StyleTag() {
|
|
853
|
+
return import_react.default.createElement("style", null, PANEL_CSS);
|
|
854
|
+
}
|
|
603
855
|
function StatusBadge(props) {
|
|
604
856
|
const t = props.t;
|
|
605
857
|
const meta = STATUS_META[props.status] || STATUS_META.rest;
|
|
858
|
+
const live = props.status === "working";
|
|
606
859
|
return import_react.default.createElement("span", {
|
|
607
860
|
style: {
|
|
608
861
|
display: "inline-flex",
|
|
609
862
|
alignItems: "center",
|
|
610
863
|
gap: 6,
|
|
611
|
-
padding: "
|
|
864
|
+
padding: "4px 11px 4px 9px",
|
|
612
865
|
borderRadius: 999,
|
|
613
866
|
fontSize: 12,
|
|
614
867
|
fontWeight: 600,
|
|
615
868
|
lineHeight: 1.5,
|
|
616
869
|
color: meta.color,
|
|
617
|
-
border: `1px solid ${meta.color}`,
|
|
618
|
-
background:
|
|
870
|
+
border: `1px solid color-mix(in srgb, ${meta.color} 42%, transparent)`,
|
|
871
|
+
background: `color-mix(in srgb, ${meta.color} 12%, transparent)`,
|
|
619
872
|
whiteSpace: "nowrap"
|
|
620
873
|
}
|
|
621
874
|
}, [
|
|
622
875
|
import_react.default.createElement("i", {
|
|
623
876
|
key: "dot",
|
|
877
|
+
className: live ? "niuma-live-dot" : void 0,
|
|
624
878
|
style: { width: 6, height: 6, borderRadius: "50%", background: meta.color, display: "inline-block" }
|
|
625
879
|
}),
|
|
626
880
|
t(meta.key)
|
|
627
881
|
]);
|
|
628
882
|
}
|
|
883
|
+
function SectionTitle(props) {
|
|
884
|
+
return import_react.default.createElement("div", {
|
|
885
|
+
style: {
|
|
886
|
+
display: "flex",
|
|
887
|
+
alignItems: "baseline",
|
|
888
|
+
justifyContent: "space-between",
|
|
889
|
+
gap: 8,
|
|
890
|
+
flexWrap: "wrap",
|
|
891
|
+
margin: "2px 1px -1px"
|
|
892
|
+
}
|
|
893
|
+
}, [
|
|
894
|
+
import_react.default.createElement("span", {
|
|
895
|
+
key: "t",
|
|
896
|
+
style: { fontSize: 12.5, fontWeight: 700, color: C.label2, letterSpacing: ".2px" }
|
|
897
|
+
}, props.title),
|
|
898
|
+
props.hint ? import_react.default.createElement("span", { key: "h", style: { fontSize: 10.5, color: C.label3, ...NUM } }, props.hint) : null
|
|
899
|
+
]);
|
|
900
|
+
}
|
|
629
901
|
function HeroCard(props) {
|
|
630
902
|
const t = props.t;
|
|
631
903
|
const snap = props.snap;
|
|
632
|
-
|
|
904
|
+
const rates = snap.rates;
|
|
905
|
+
const progress = Math.max(0, Math.min(1, Number(snap.todayProgress) || 0));
|
|
906
|
+
const percentText = `${(progress * 100).toFixed(1)}%`;
|
|
907
|
+
const live = snap.status === "working";
|
|
908
|
+
const rest = snap.status === "rest";
|
|
909
|
+
const heroBackground = "linear-gradient(135deg, color-mix(in srgb, " + C.brand + " 17%, " + C.layer1 + ") 0%, " + C.layer1 + " 58%, " + C.layer1 + " 100%)";
|
|
910
|
+
return import_react.default.createElement("div", {
|
|
911
|
+
style: {
|
|
912
|
+
position: "relative",
|
|
913
|
+
overflow: "hidden",
|
|
914
|
+
borderRadius: 18,
|
|
915
|
+
padding: "16px 18px 14px",
|
|
916
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 34%, ${C.border1})`,
|
|
917
|
+
background: heroBackground,
|
|
918
|
+
boxShadow: "0 12px 30px rgba(0,0,0,.10)",
|
|
919
|
+
boxSizing: "border-box",
|
|
920
|
+
minWidth: 0
|
|
921
|
+
}
|
|
922
|
+
}, [
|
|
633
923
|
import_react.default.createElement("div", {
|
|
634
|
-
key: "
|
|
924
|
+
key: "glow",
|
|
925
|
+
"aria-hidden": "true",
|
|
635
926
|
style: {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
927
|
+
position: "absolute",
|
|
928
|
+
right: -52,
|
|
929
|
+
top: -72,
|
|
930
|
+
width: 188,
|
|
931
|
+
height: 188,
|
|
932
|
+
borderRadius: "50%",
|
|
933
|
+
background: `radial-gradient(circle, color-mix(in srgb, ${GOLD_TINT} 30%, transparent) 0%, transparent 68%)`,
|
|
934
|
+
pointerEvents: "none"
|
|
643
935
|
}
|
|
936
|
+
}),
|
|
937
|
+
import_react.default.createElement("div", {
|
|
938
|
+
key: "head",
|
|
939
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, flexWrap: "wrap" }
|
|
644
940
|
}, [
|
|
645
|
-
import_react.default.createElement("span", {
|
|
941
|
+
import_react.default.createElement("span", {
|
|
942
|
+
key: "a",
|
|
943
|
+
style: { display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12.5, fontWeight: 600, color: C.label2 }
|
|
944
|
+
}, [
|
|
945
|
+
live ? import_react.default.createElement("i", {
|
|
946
|
+
key: "dot",
|
|
947
|
+
className: "niuma-live-dot",
|
|
948
|
+
style: { width: 7, height: 7, borderRadius: "50%", background: C.ok, display: "inline-block" }
|
|
949
|
+
}) : null,
|
|
950
|
+
t("earnedToday")
|
|
951
|
+
]),
|
|
646
952
|
import_react.default.createElement(
|
|
647
953
|
"span",
|
|
648
954
|
{ key: "b", style: { fontSize: 11, color: C.label3, ...NUM } },
|
|
@@ -651,65 +957,61 @@ function HeroCard(props) {
|
|
|
651
957
|
]),
|
|
652
958
|
import_react.default.createElement("div", {
|
|
653
959
|
key: "amt",
|
|
654
|
-
style: { display: "flex", alignItems: "baseline", gap:
|
|
960
|
+
style: { display: "flex", alignItems: "baseline", gap: 7, marginTop: 4, flexWrap: "wrap" }
|
|
655
961
|
}, [
|
|
656
|
-
import_react.default.createElement("span", {
|
|
657
|
-
key: "cur",
|
|
658
|
-
style: { fontSize: 22, fontWeight: 700, color: C.label2, ...NUM }
|
|
659
|
-
}, "\xA5"),
|
|
660
962
|
import_react.default.createElement("span", {
|
|
661
963
|
key: "val",
|
|
662
964
|
style: {
|
|
663
|
-
fontSize:
|
|
664
|
-
lineHeight: 1.
|
|
665
|
-
fontWeight:
|
|
666
|
-
letterSpacing: "
|
|
667
|
-
|
|
668
|
-
...NUM
|
|
965
|
+
fontSize: 46,
|
|
966
|
+
lineHeight: 1.12,
|
|
967
|
+
fontWeight: 800,
|
|
968
|
+
letterSpacing: "-1.2px",
|
|
969
|
+
...GOLD,
|
|
970
|
+
...NUM,
|
|
971
|
+
...rest ? { opacity: 0.62 } : {}
|
|
669
972
|
}
|
|
670
|
-
}, formatMoney(snap.todayEarned, 4))
|
|
973
|
+
}, formatMoney(snap.todayEarned, 4)),
|
|
974
|
+
import_react.default.createElement("span", {
|
|
975
|
+
key: "unit",
|
|
976
|
+
style: { fontSize: 18, fontWeight: 700, color: C.label2, ...NUM }
|
|
977
|
+
}, "\u5143")
|
|
671
978
|
]),
|
|
672
979
|
import_react.default.createElement("div", {
|
|
673
|
-
key: "
|
|
674
|
-
style: {
|
|
675
|
-
}, `${t("perSecond")} ${money(snap.rates.secondWage, 4)}`)
|
|
676
|
-
]);
|
|
677
|
-
}
|
|
678
|
-
function ProgressCard(props) {
|
|
679
|
-
const t = props.t;
|
|
680
|
-
const snap = props.snap;
|
|
681
|
-
const progress = Math.max(0, Math.min(1, Number(snap.todayProgress) || 0));
|
|
682
|
-
const percentText = `${(progress * 100).toFixed(1)}%`;
|
|
683
|
-
const countdownChip = (key, label, seconds) => import_react.default.createElement("div", {
|
|
684
|
-
key,
|
|
685
|
-
style: { ...CARD, flex: "1 1 130px", minWidth: 118, padding: "8px 10px" }
|
|
686
|
-
}, [
|
|
687
|
-
import_react.default.createElement("div", { key: "l", style: { fontSize: 11, color: C.label3 } }, label),
|
|
688
|
-
import_react.default.createElement("div", {
|
|
689
|
-
key: "v",
|
|
690
|
-
style: { fontSize: 14, fontWeight: 650, color: C.label, marginTop: 2, ...NUM }
|
|
691
|
-
}, Number(seconds) > 0 ? formatDuration(seconds) : "\u2014")
|
|
692
|
-
]);
|
|
693
|
-
return import_react.default.createElement("div", { style: CARD }, [
|
|
694
|
-
import_react.default.createElement("div", {
|
|
695
|
-
key: "top",
|
|
696
|
-
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, flexWrap: "wrap" }
|
|
980
|
+
key: "chips",
|
|
981
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, marginTop: 5, flexWrap: "wrap" }
|
|
697
982
|
}, [
|
|
698
|
-
import_react.default.createElement("span", { key: "l", style: { fontSize: 12, color: C.label2 } }, t("todayProgress")),
|
|
699
983
|
import_react.default.createElement("span", {
|
|
700
|
-
key: "
|
|
701
|
-
style: {
|
|
702
|
-
|
|
984
|
+
key: "per",
|
|
985
|
+
style: {
|
|
986
|
+
display: "inline-flex",
|
|
987
|
+
alignItems: "center",
|
|
988
|
+
gap: 4,
|
|
989
|
+
fontSize: 11.5,
|
|
990
|
+
fontWeight: 600,
|
|
991
|
+
color: C.label2,
|
|
992
|
+
background: `color-mix(in srgb, ${C.brand} 11%, transparent)`,
|
|
993
|
+
border: `1px solid color-mix(in srgb, ${C.brand} 22%, transparent)`,
|
|
994
|
+
borderRadius: 999,
|
|
995
|
+
padding: "2px 9px",
|
|
996
|
+
...NUM
|
|
997
|
+
}
|
|
998
|
+
}, `${t("perSecond")} +${money(rates.secondWage, 4)}`),
|
|
999
|
+
import_react.default.createElement(
|
|
1000
|
+
"span",
|
|
1001
|
+
{ key: "target", style: { fontSize: 11, color: C.label3, ...NUM } },
|
|
1002
|
+
rest ? t("restHint") : `${t("todayTarget")} ${money(snap.todayTarget, 2)}`
|
|
1003
|
+
)
|
|
1004
|
+
]),
|
|
1005
|
+
import_react.default.createElement("div", {
|
|
1006
|
+
key: "progTop",
|
|
1007
|
+
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, marginTop: 13, flexWrap: "wrap" }
|
|
1008
|
+
}, [
|
|
1009
|
+
import_react.default.createElement("span", { key: "l", style: { fontSize: 11.5, color: C.label3 } }, t("todayProgress")),
|
|
1010
|
+
import_react.default.createElement("span", { key: "p", style: { fontSize: 12.5, fontWeight: 700, color: C.brand, ...NUM } }, percentText)
|
|
703
1011
|
]),
|
|
704
1012
|
import_react.default.createElement("div", {
|
|
705
1013
|
key: "bar",
|
|
706
|
-
style: {
|
|
707
|
-
marginTop: 6,
|
|
708
|
-
height: 8,
|
|
709
|
-
borderRadius: 999,
|
|
710
|
-
background: C.layer2,
|
|
711
|
-
overflow: "hidden"
|
|
712
|
-
}
|
|
1014
|
+
style: { marginTop: 5, height: 9, borderRadius: 999, background: `color-mix(in srgb, ${C.label} 9%, transparent)`, overflow: "hidden" }
|
|
713
1015
|
}, [
|
|
714
1016
|
import_react.default.createElement("div", {
|
|
715
1017
|
key: "fill",
|
|
@@ -717,31 +1019,60 @@ function ProgressCard(props) {
|
|
|
717
1019
|
width: `${(progress * 100).toFixed(2)}%`,
|
|
718
1020
|
height: "100%",
|
|
719
1021
|
borderRadius: 999,
|
|
720
|
-
background: C.brand,
|
|
721
|
-
transition: "width .
|
|
1022
|
+
background: `linear-gradient(90deg, ${C.brand} 0%, color-mix(in srgb, ${C.brand} 55%, ${C.ok}) 100%)`,
|
|
1023
|
+
transition: "width .35s linear"
|
|
722
1024
|
}
|
|
723
1025
|
})
|
|
724
1026
|
]),
|
|
725
1027
|
import_react.default.createElement("div", {
|
|
726
|
-
key: "
|
|
727
|
-
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, marginTop: 5, flexWrap: "wrap", fontSize:
|
|
1028
|
+
key: "progNum",
|
|
1029
|
+
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, marginTop: 5, flexWrap: "wrap", fontSize: 10.5, color: C.label3 }
|
|
728
1030
|
}, [
|
|
729
1031
|
import_react.default.createElement("span", { key: "a" }, t("progressOfTarget")),
|
|
730
1032
|
import_react.default.createElement(
|
|
731
1033
|
"span",
|
|
732
|
-
{ key: "b", style: { ...NUM } },
|
|
1034
|
+
{ key: "b", style: { color: C.label2, fontWeight: 600, ...NUM } },
|
|
733
1035
|
`${money(snap.todayEarned, 2)} / ${money(snap.todayTarget, 2)}`
|
|
734
1036
|
)
|
|
735
|
-
]),
|
|
736
|
-
import_react.default.createElement("div", {
|
|
737
|
-
key: "cd",
|
|
738
|
-
style: { display: "flex", flexWrap: "wrap", gap: 8, marginTop: 8 }
|
|
739
|
-
}, [
|
|
740
|
-
countdownChip("start", t("toStart"), snap.secondsToStart),
|
|
741
|
-
countdownChip("end", t("toEnd"), snap.secondsToEnd)
|
|
742
1037
|
])
|
|
743
1038
|
]);
|
|
744
1039
|
}
|
|
1040
|
+
function CountdownRow(props) {
|
|
1041
|
+
const t = props.t;
|
|
1042
|
+
const snap = props.snap;
|
|
1043
|
+
const chip = (key, label, value, accent) => import_react.default.createElement("div", {
|
|
1044
|
+
key,
|
|
1045
|
+
style: {
|
|
1046
|
+
flex: "1 1 120px",
|
|
1047
|
+
minWidth: 116,
|
|
1048
|
+
display: "flex",
|
|
1049
|
+
alignItems: "baseline",
|
|
1050
|
+
justifyContent: "space-between",
|
|
1051
|
+
gap: 8,
|
|
1052
|
+
padding: "9px 12px",
|
|
1053
|
+
borderRadius: 12,
|
|
1054
|
+
background: accent ? `color-mix(in srgb, ${GOLD_TINT} 9%, ${C.layer1})` : C.layer1,
|
|
1055
|
+
border: `1px solid ${accent ? `color-mix(in srgb, ${GOLD_TINT} 38%, ${C.border1})` : C.border1}`,
|
|
1056
|
+
boxSizing: "border-box"
|
|
1057
|
+
}
|
|
1058
|
+
}, [
|
|
1059
|
+
import_react.default.createElement("span", {
|
|
1060
|
+
key: "l",
|
|
1061
|
+
style: { fontSize: 11, color: accent ? C.label2 : C.label3, whiteSpace: "nowrap" }
|
|
1062
|
+
}, label),
|
|
1063
|
+
import_react.default.createElement("span", {
|
|
1064
|
+
key: "v",
|
|
1065
|
+
style: { fontSize: 13.5, fontWeight: 700, color: C.label, ...NUM }
|
|
1066
|
+
}, value)
|
|
1067
|
+
]);
|
|
1068
|
+
return import_react.default.createElement("div", {
|
|
1069
|
+
style: { display: "flex", flexWrap: "wrap", gap: 9 }
|
|
1070
|
+
}, [
|
|
1071
|
+
chip("start", t("toStart"), Number(snap.secondsToStart) > 0 ? formatDuration(snap.secondsToStart) : "\u2014"),
|
|
1072
|
+
chip("end", t("toEnd"), Number(snap.secondsToEnd) > 0 ? formatDuration(snap.secondsToEnd) : "\u2014"),
|
|
1073
|
+
chip("month", t("monthEarned"), money(snap.monthEarned, 2), true)
|
|
1074
|
+
]);
|
|
1075
|
+
}
|
|
745
1076
|
var RATE_CARDS = [
|
|
746
1077
|
{ key: "secondWage", label: "secondWage", digits: 4 },
|
|
747
1078
|
{ key: "minuteWage", label: "minuteWage", digits: 4 },
|
|
@@ -751,65 +1082,247 @@ var RATE_CARDS = [
|
|
|
751
1082
|
{ key: "monthlyWage", label: "monthlyWage", digits: 2 }
|
|
752
1083
|
];
|
|
753
1084
|
function RatesGrid(props) {
|
|
754
|
-
const
|
|
755
|
-
const rates = props.rates;
|
|
1085
|
+
const cards = Array.isArray(props.cards) ? props.cards : [];
|
|
756
1086
|
return import_react.default.createElement("div", {
|
|
757
1087
|
style: { display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 8 }
|
|
758
|
-
},
|
|
759
|
-
|
|
760
|
-
"
|
|
761
|
-
|
|
1088
|
+
}, cards.map((card, index) => {
|
|
1089
|
+
const accent = card.accent === true;
|
|
1090
|
+
return import_react.default.createElement("div", {
|
|
1091
|
+
key: card.key,
|
|
1092
|
+
"data-stat": `stat-${index}`,
|
|
1093
|
+
style: {
|
|
1094
|
+
...CARD,
|
|
1095
|
+
padding: "10px 11px",
|
|
1096
|
+
borderRadius: 12,
|
|
1097
|
+
...accent ? {
|
|
1098
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 46%, ${C.border1})`,
|
|
1099
|
+
background: `color-mix(in srgb, ${GOLD_TINT} 9%, ${C.layer1})`
|
|
1100
|
+
} : {}
|
|
1101
|
+
}
|
|
1102
|
+
}, [
|
|
1103
|
+
import_react.default.createElement("div", {
|
|
1104
|
+
key: "l",
|
|
1105
|
+
style: { fontSize: 11, color: accent ? C.label2 : C.label3, fontWeight: accent ? 600 : 400 }
|
|
1106
|
+
}, card.label),
|
|
1107
|
+
import_react.default.createElement("div", {
|
|
1108
|
+
key: "v",
|
|
1109
|
+
style: {
|
|
1110
|
+
fontSize: 15.5,
|
|
1111
|
+
fontWeight: 700,
|
|
1112
|
+
letterSpacing: "-.2px",
|
|
1113
|
+
color: accent ? C.label : C.label,
|
|
1114
|
+
marginTop: 2,
|
|
1115
|
+
...NUM
|
|
1116
|
+
}
|
|
1117
|
+
}, card.value)
|
|
1118
|
+
]);
|
|
1119
|
+
}));
|
|
1120
|
+
}
|
|
1121
|
+
function PeriodSelect(props) {
|
|
1122
|
+
const t = props.t;
|
|
1123
|
+
const year = props.year;
|
|
1124
|
+
const months = props.months;
|
|
1125
|
+
const style = {
|
|
1126
|
+
appearance: "none",
|
|
1127
|
+
WebkitAppearance: "none",
|
|
1128
|
+
border: `1px solid ${C.border}`,
|
|
1129
|
+
background: C.layer2,
|
|
1130
|
+
color: C.label,
|
|
1131
|
+
borderRadius: 8,
|
|
1132
|
+
padding: "4px 9px",
|
|
1133
|
+
fontSize: 12,
|
|
1134
|
+
fontWeight: 600,
|
|
1135
|
+
cursor: "pointer",
|
|
1136
|
+
outline: "none",
|
|
1137
|
+
maxWidth: 220
|
|
1138
|
+
};
|
|
1139
|
+
return import_react.default.createElement("select", {
|
|
1140
|
+
value: props.value,
|
|
1141
|
+
"aria-label": t("viewLabel"),
|
|
1142
|
+
onChange: (event) => props.onChange(event.target.value),
|
|
1143
|
+
style
|
|
762
1144
|
}, [
|
|
763
|
-
import_react.default.createElement("
|
|
764
|
-
import_react.default.createElement("
|
|
765
|
-
key:
|
|
766
|
-
|
|
767
|
-
},
|
|
768
|
-
|
|
1145
|
+
import_react.default.createElement("option", { key: "current", value: "current" }, t("viewCurrent")),
|
|
1146
|
+
...months.map((month) => import_react.default.createElement("option", {
|
|
1147
|
+
key: `m${month.month}`,
|
|
1148
|
+
value: `m${month.month}`
|
|
1149
|
+
}, `${month.month}${t("monthUnit")} \xB7 ${month.workdays}${t("dayUnit")} \xB7 ${t("holidayShort")}${month.holidayDays}`)),
|
|
1150
|
+
import_react.default.createElement("option", { key: "year", value: "year" }, `${year} ${t("viewYear")}`)
|
|
1151
|
+
]);
|
|
769
1152
|
}
|
|
770
1153
|
function DetailsFooter(props) {
|
|
771
1154
|
const t = props.t;
|
|
772
1155
|
const snap = props.snap;
|
|
773
1156
|
const rates = snap.rates;
|
|
774
|
-
const source = props.holidaySource || HOLIDAY_SOURCE;
|
|
775
1157
|
const items = [
|
|
776
1158
|
{ key: "salary", label: t("monthlySalaryLabel"), value: money(rates.monthlySalary, 2) },
|
|
777
1159
|
{ key: "workdays", label: t("workdaysThisMonth"), value: `${rates.monthlyWorkdays}${t("dayUnit")}` },
|
|
778
1160
|
{ key: "hours", label: t("paidHoursPerDay"), value: `${trimNumber(rates.paidHours, 2)}${t("hourUnit")}` },
|
|
779
1161
|
{ key: "target", label: t("todayTarget"), value: money(snap.todayTarget, 2) },
|
|
780
|
-
{ key: "month", label: t("monthEarned"), value: money(snap.monthEarned, 2) }
|
|
1162
|
+
{ key: "month", label: t("monthEarned"), value: money(snap.monthEarned, 2) },
|
|
1163
|
+
{ key: "worked", label: t("monthWorkedDays"), value: `${snap.monthWorkdaysDone}${t("dayUnit")}` },
|
|
1164
|
+
{ key: "left", label: t("monthRemainingDays"), value: `${snap.monthWorkdaysLeft}${t("dayUnit")}` }
|
|
781
1165
|
];
|
|
782
1166
|
return import_react.default.createElement("div", {
|
|
783
|
-
style: {
|
|
1167
|
+
style: {
|
|
1168
|
+
background: C.layer1,
|
|
1169
|
+
border: `1px solid ${C.border1}`,
|
|
1170
|
+
borderRadius: 12,
|
|
1171
|
+
padding: "10px 12px",
|
|
1172
|
+
fontSize: 11,
|
|
1173
|
+
color: C.label3,
|
|
1174
|
+
lineHeight: 1.6
|
|
1175
|
+
}
|
|
784
1176
|
}, [
|
|
785
1177
|
import_react.default.createElement("div", {
|
|
786
1178
|
key: "items",
|
|
787
|
-
style: { display: "
|
|
788
|
-
}, items.map((item) => import_react.default.createElement("
|
|
1179
|
+
style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(118px, 1fr))", gap: "7px 12px" }
|
|
1180
|
+
}, items.map((item) => import_react.default.createElement("div", {
|
|
789
1181
|
key: item.key,
|
|
790
|
-
style: {
|
|
1182
|
+
style: { minWidth: 0 }
|
|
791
1183
|
}, [
|
|
792
|
-
import_react.default.createElement("
|
|
793
|
-
import_react.default.createElement("
|
|
1184
|
+
import_react.default.createElement("div", { key: "l", style: { fontSize: 10.5, color: C.label3 } }, item.label),
|
|
1185
|
+
import_react.default.createElement("div", {
|
|
794
1186
|
key: "v",
|
|
795
|
-
style: {
|
|
1187
|
+
style: { fontSize: 13, fontWeight: 650, color: C.label2, ...NUM }
|
|
796
1188
|
}, item.value)
|
|
1189
|
+
])))
|
|
1190
|
+
]);
|
|
1191
|
+
}
|
|
1192
|
+
var HOLIDAY_LABEL_KEYS = {
|
|
1193
|
+
newYear: "holidayNewYear",
|
|
1194
|
+
spring: "holidaySpring",
|
|
1195
|
+
qingming: "holidayQingming",
|
|
1196
|
+
labour: "holidayLabour",
|
|
1197
|
+
dragon: "holidayDragon",
|
|
1198
|
+
midAutumn: "holidayMidAutumn",
|
|
1199
|
+
national: "holidayNational"
|
|
1200
|
+
};
|
|
1201
|
+
function HolidaysCard(props) {
|
|
1202
|
+
const t = props.t;
|
|
1203
|
+
const source = props.holidaySource || HOLIDAY_SOURCE;
|
|
1204
|
+
const extra = Array.isArray(props.extraWorkdays) ? props.extraWorkdays : [];
|
|
1205
|
+
const countYear = (year) => extra.filter((key) => String(key).startsWith(`${year}-`)).length;
|
|
1206
|
+
const shortDate = (key) => key.slice(5).replace("-", "/");
|
|
1207
|
+
const sections = [
|
|
1208
|
+
{
|
|
1209
|
+
key: "official",
|
|
1210
|
+
label: t("holidays2026Label"),
|
|
1211
|
+
blocks: HOLIDAY_BLOCKS,
|
|
1212
|
+
estimated: false,
|
|
1213
|
+
extraCount: countYear(2026),
|
|
1214
|
+
tag: null
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
key: "estimate",
|
|
1218
|
+
label: t("holidays2027Label"),
|
|
1219
|
+
blocks: HOLIDAY_BLOCKS_2027_ESTIMATED,
|
|
1220
|
+
estimated: true,
|
|
1221
|
+
extraCount: countYear(2027),
|
|
1222
|
+
tag: t("holidayEstimateTag")
|
|
1223
|
+
}
|
|
1224
|
+
];
|
|
1225
|
+
const sumDays = (blocks) => blocks.reduce((sum, block) => sum + block.days, 0);
|
|
1226
|
+
const renderSection = (section) => import_react.default.createElement("div", { key: section.key, style: { marginTop: section.key === "official" ? 8 : 12 } }, [
|
|
1227
|
+
import_react.default.createElement("div", {
|
|
1228
|
+
key: "head",
|
|
1229
|
+
style: { display: "flex", alignItems: "baseline", flexWrap: "wrap", gap: 8 }
|
|
1230
|
+
}, [
|
|
1231
|
+
import_react.default.createElement("span", { key: "l", style: { fontSize: 11.5, fontWeight: 700, color: C.label2 } }, section.label),
|
|
1232
|
+
section.tag ? import_react.default.createElement("span", {
|
|
1233
|
+
key: "tag",
|
|
1234
|
+
style: {
|
|
1235
|
+
fontSize: 9.5,
|
|
1236
|
+
fontWeight: 700,
|
|
1237
|
+
color: C.label2,
|
|
1238
|
+
border: `1px dashed color-mix(in srgb, ${GOLD_TINT} 60%, transparent)`,
|
|
1239
|
+
borderRadius: 999,
|
|
1240
|
+
padding: "0 6px",
|
|
1241
|
+
lineHeight: 1.6
|
|
1242
|
+
}
|
|
1243
|
+
}, section.tag) : null,
|
|
1244
|
+
import_react.default.createElement(
|
|
1245
|
+
"span",
|
|
1246
|
+
{ key: "s", style: { marginLeft: "auto", fontSize: 10, color: C.label3, ...NUM } },
|
|
1247
|
+
t("holidaysCardSub").replace("{days}", String(sumDays(section.blocks))).replace("{extra}", String(section.extraCount))
|
|
1248
|
+
)
|
|
1249
|
+
]),
|
|
1250
|
+
import_react.default.createElement("div", {
|
|
1251
|
+
key: "grid",
|
|
1252
|
+
style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(118px, 1fr))", gap: 7, marginTop: 6 }
|
|
1253
|
+
}, section.blocks.map((block) => import_react.default.createElement("div", {
|
|
1254
|
+
key: block.id,
|
|
1255
|
+
style: {
|
|
1256
|
+
border: section.estimated ? `1px dashed color-mix(in srgb, ${GOLD_TINT} 40%, ${C.border1})` : `1px solid ${C.border1}`,
|
|
1257
|
+
borderRadius: 9,
|
|
1258
|
+
padding: "6px 8px",
|
|
1259
|
+
background: `color-mix(in srgb, ${GOLD_TINT} ${section.estimated ? 3 : 6}%, transparent)`
|
|
1260
|
+
}
|
|
1261
|
+
}, [
|
|
1262
|
+
import_react.default.createElement("div", {
|
|
1263
|
+
key: "row",
|
|
1264
|
+
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 6 }
|
|
1265
|
+
}, [
|
|
1266
|
+
import_react.default.createElement(
|
|
1267
|
+
"span",
|
|
1268
|
+
{ key: "n", style: { fontSize: 11.5, fontWeight: 650, color: C.label } },
|
|
1269
|
+
t(HOLIDAY_LABEL_KEYS[block.id])
|
|
1270
|
+
),
|
|
1271
|
+
import_react.default.createElement("span", {
|
|
1272
|
+
key: "d",
|
|
1273
|
+
style: {
|
|
1274
|
+
fontSize: 10,
|
|
1275
|
+
fontWeight: 700,
|
|
1276
|
+
color: C.label2,
|
|
1277
|
+
background: `color-mix(in srgb, ${GOLD_TINT} 16%, transparent)`,
|
|
1278
|
+
borderRadius: 999,
|
|
1279
|
+
padding: "0 6px",
|
|
1280
|
+
...NUM
|
|
1281
|
+
}
|
|
1282
|
+
}, t("holidaysDaysShort").replace("{days}", String(block.days)))
|
|
1283
|
+
]),
|
|
1284
|
+
import_react.default.createElement(
|
|
1285
|
+
"div",
|
|
1286
|
+
{ key: "r", style: { fontSize: 10, color: C.label3, marginTop: 2, ...NUM } },
|
|
1287
|
+
`${shortDate(block.from)} \u2013 ${shortDate(block.to)}`
|
|
1288
|
+
)
|
|
797
1289
|
]))),
|
|
1290
|
+
section.estimated ? import_react.default.createElement("div", {
|
|
1291
|
+
key: "est-note",
|
|
1292
|
+
style: { marginTop: 6, fontSize: 10.5, color: C.label3, lineHeight: 1.5 }
|
|
1293
|
+
}, `\u26A0 ${t("holidayEstimateNote")}`) : null
|
|
1294
|
+
]);
|
|
1295
|
+
return import_react.default.createElement("div", {
|
|
1296
|
+
style: {
|
|
1297
|
+
background: C.layer1,
|
|
1298
|
+
border: `1px solid ${C.border1}`,
|
|
1299
|
+
borderRadius: 12,
|
|
1300
|
+
padding: "10px 12px"
|
|
1301
|
+
}
|
|
1302
|
+
}, [
|
|
798
1303
|
import_react.default.createElement("div", {
|
|
799
|
-
key: "
|
|
800
|
-
style: { display: "flex",
|
|
1304
|
+
key: "title",
|
|
1305
|
+
style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, flexWrap: "wrap" }
|
|
801
1306
|
}, [
|
|
802
|
-
import_react.default.createElement(
|
|
1307
|
+
import_react.default.createElement(
|
|
1308
|
+
"span",
|
|
1309
|
+
{ key: "t", style: { fontSize: 12.5, fontWeight: 700, color: C.label2, letterSpacing: ".2px" } },
|
|
1310
|
+
t("holidaysCardTitle")
|
|
1311
|
+
),
|
|
803
1312
|
import_react.default.createElement("a", {
|
|
804
1313
|
key: "a",
|
|
805
1314
|
href: source.url,
|
|
806
1315
|
target: "_blank",
|
|
807
1316
|
rel: "noreferrer",
|
|
808
1317
|
title: source.title,
|
|
809
|
-
style: { color: C.brand, textDecoration: "
|
|
810
|
-
}, `${source.year}
|
|
811
|
-
|
|
812
|
-
|
|
1318
|
+
style: { fontSize: 10.5, color: C.brand, textDecoration: "none", fontWeight: 600 }
|
|
1319
|
+
}, `${source.year} ${t("holidaySourceLink")} \u2197`)
|
|
1320
|
+
]),
|
|
1321
|
+
sections.map(renderSection),
|
|
1322
|
+
import_react.default.createElement("div", {
|
|
1323
|
+
key: "foot",
|
|
1324
|
+
style: { marginTop: 8, fontSize: 10.5, color: C.label3 }
|
|
1325
|
+
}, t("holidaysExtraNote").replace("{extra}", String(extra.length)))
|
|
813
1326
|
]);
|
|
814
1327
|
}
|
|
815
1328
|
function SettingsSection(props) {
|
|
@@ -819,104 +1332,147 @@ function SettingsSection(props) {
|
|
|
819
1332
|
const setCheck = props.setCheck;
|
|
820
1333
|
const save = props.save;
|
|
821
1334
|
const onSave = props.onSave;
|
|
1335
|
+
const rowStyle = {
|
|
1336
|
+
display: "flex",
|
|
1337
|
+
alignItems: "center",
|
|
1338
|
+
gap: 10,
|
|
1339
|
+
minHeight: 33,
|
|
1340
|
+
padding: "2px 0",
|
|
1341
|
+
borderTop: `1px solid ${C.border1}`
|
|
1342
|
+
};
|
|
1343
|
+
const rowKeyStyle = { width: 62, flex: "0 0 62px", fontSize: 11.5, color: C.label3 };
|
|
1344
|
+
const rowValStyle = { display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap", minWidth: 0 };
|
|
822
1345
|
const inputStyle = {
|
|
823
|
-
width: "100%",
|
|
824
1346
|
boxSizing: "border-box",
|
|
825
|
-
|
|
826
|
-
|
|
1347
|
+
width: 88,
|
|
1348
|
+
minHeight: 28,
|
|
1349
|
+
padding: "4px 8px",
|
|
1350
|
+
borderRadius: 7,
|
|
827
1351
|
border: `1px solid ${C.border}`,
|
|
828
1352
|
background: C.layer2,
|
|
829
1353
|
color: C.label,
|
|
830
|
-
fontSize:
|
|
1354
|
+
fontSize: 12.5,
|
|
831
1355
|
fontVariantNumeric: "tabular-nums",
|
|
832
1356
|
outline: "none"
|
|
833
1357
|
};
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1358
|
+
const selectStyle = {
|
|
1359
|
+
boxSizing: "border-box",
|
|
1360
|
+
width: 48,
|
|
1361
|
+
minHeight: 28,
|
|
1362
|
+
padding: "4px 2px 4px 6px",
|
|
1363
|
+
borderRadius: 7,
|
|
1364
|
+
border: `1px solid ${C.border}`,
|
|
1365
|
+
background: C.layer2,
|
|
1366
|
+
color: C.label,
|
|
1367
|
+
fontSize: 12.5,
|
|
1368
|
+
fontVariantNumeric: "tabular-nums",
|
|
1369
|
+
outline: "none",
|
|
1370
|
+
cursor: "pointer"
|
|
1371
|
+
};
|
|
1372
|
+
const unitStyle = { fontSize: 10.5, color: C.label3, whiteSpace: "nowrap" };
|
|
1373
|
+
const dashStyle = { fontSize: 11, color: C.label3, margin: "0 1px" };
|
|
1374
|
+
const HOUR_OPTIONS = Array.from({ length: 24 }, (_, i) => String(i).padStart(2, "0"));
|
|
1375
|
+
const MINUTE_OPTIONS = Array.from({ length: 60 }, (_, i) => String(i).padStart(2, "0"));
|
|
1376
|
+
const row = (key, label, values) => import_react.default.createElement("div", { key, style: rowStyle }, [
|
|
1377
|
+
import_react.default.createElement("span", { key: "k", style: rowKeyStyle }, label),
|
|
1378
|
+
import_react.default.createElement("div", { key: "v", style: rowValStyle }, values)
|
|
1379
|
+
]);
|
|
1380
|
+
const timeSelects = (field, label, disabled = false) => {
|
|
1381
|
+
const [rawHour = "00", rawMinute = "00"] = String(form[field] || "00:00").split(":");
|
|
1382
|
+
const hour = HOUR_OPTIONS.includes(rawHour) ? rawHour : "00";
|
|
1383
|
+
const minute = MINUTE_OPTIONS.includes(rawMinute) ? rawMinute : "00";
|
|
1384
|
+
const commit = (nextHour, nextMinute) => setField(field, `${nextHour}:${nextMinute}`);
|
|
1385
|
+
const style = { ...selectStyle, opacity: disabled ? 0.45 : 1, cursor: disabled ? "default" : "pointer" };
|
|
1386
|
+
return import_react.default.createElement("span", { key: field, style: { display: "inline-flex", alignItems: "center", gap: 2 } }, [
|
|
1387
|
+
import_react.default.createElement("select", {
|
|
1388
|
+
key: "h",
|
|
1389
|
+
value: hour,
|
|
1390
|
+
disabled,
|
|
1391
|
+
"aria-label": `${label} ${t("hourUnit")}`,
|
|
1392
|
+
onChange: (event) => commit(event.target.value, minute),
|
|
1393
|
+
style
|
|
1394
|
+
}, HOUR_OPTIONS.map((value) => import_react.default.createElement("option", { key: value, value }, value))),
|
|
1395
|
+
import_react.default.createElement("span", { key: "c", style: { color: C.label3, fontWeight: 700, fontSize: 12 } }, ":"),
|
|
1396
|
+
import_react.default.createElement("select", {
|
|
1397
|
+
key: "m",
|
|
1398
|
+
value: minute,
|
|
1399
|
+
disabled,
|
|
1400
|
+
"aria-label": `${label} ${t("minuteUnit")}`,
|
|
1401
|
+
onChange: (event) => commit(hour, event.target.value),
|
|
1402
|
+
style
|
|
1403
|
+
}, MINUTE_OPTIONS.map((value) => import_react.default.createElement("option", { key: value, value }, value)))
|
|
1404
|
+
]);
|
|
1405
|
+
};
|
|
1406
|
+
const timeRange = (startField, endField, label, disabled) => import_react.default.createElement("span", {
|
|
1407
|
+
key: `${startField}-${endField}`,
|
|
1408
|
+
style: { display: "inline-flex", alignItems: "center", gap: 2 }
|
|
838
1409
|
}, [
|
|
839
|
-
|
|
840
|
-
import_react.default.createElement("
|
|
841
|
-
|
|
842
|
-
type: "text",
|
|
843
|
-
value: form[field],
|
|
844
|
-
placeholder: placeholder || "HH:mm",
|
|
845
|
-
onChange: (event) => setField(field, event.target.value),
|
|
846
|
-
style: inputStyle
|
|
847
|
-
})
|
|
1410
|
+
timeSelects(startField, label, disabled),
|
|
1411
|
+
import_react.default.createElement("span", { key: "dash", style: dashStyle }, "\u2013"),
|
|
1412
|
+
timeSelects(endField, label, disabled)
|
|
848
1413
|
]);
|
|
849
|
-
const
|
|
1414
|
+
const toggle = (field, labelKey, disabled) => import_react.default.createElement("label", {
|
|
850
1415
|
key: field,
|
|
851
1416
|
style: {
|
|
852
|
-
display: "flex",
|
|
1417
|
+
display: "inline-flex",
|
|
853
1418
|
alignItems: "center",
|
|
854
|
-
gap:
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1419
|
+
gap: 5,
|
|
1420
|
+
padding: "2px 6px",
|
|
1421
|
+
borderRadius: 8,
|
|
1422
|
+
border: `1px solid ${C.border1}`,
|
|
1423
|
+
background: C.layer2,
|
|
1424
|
+
fontSize: 10.5,
|
|
1425
|
+
color: disabled ? C.label3 : C.label2,
|
|
1426
|
+
whiteSpace: "nowrap",
|
|
1427
|
+
cursor: disabled ? "default" : "pointer",
|
|
1428
|
+
opacity: disabled ? 0.55 : 1
|
|
860
1429
|
}
|
|
861
1430
|
}, [
|
|
862
1431
|
import_react.default.createElement("input", {
|
|
863
1432
|
key: "i",
|
|
864
1433
|
type: "checkbox",
|
|
865
1434
|
checked: Boolean(form[field]),
|
|
866
|
-
|
|
1435
|
+
disabled,
|
|
1436
|
+
onChange: (event) => setCheck(field, event.target.checked),
|
|
1437
|
+
style: { accentColor: GOLD_TINT, width: 13, height: 13, margin: 0, cursor: "inherit" }
|
|
867
1438
|
}),
|
|
868
1439
|
import_react.default.createElement("span", { key: "l" }, t(labelKey))
|
|
869
1440
|
]);
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
1441
|
+
const lunchDisabled = !form.lunchEnabled;
|
|
1442
|
+
return import_react.default.createElement("details", {
|
|
1443
|
+
open: true,
|
|
1444
|
+
style: { background: C.layer1, border: `1px solid ${C.border1}`, borderRadius: 12, padding: "10px 12px" }
|
|
873
1445
|
}, [
|
|
874
|
-
import_react.default.createElement("span", { key: "l", style: labelStyle }, t(labelKey)),
|
|
875
|
-
import_react.default.createElement("textarea", {
|
|
876
|
-
key: "i",
|
|
877
|
-
rows: 4,
|
|
878
|
-
value: form[field],
|
|
879
|
-
spellCheck: false,
|
|
880
|
-
onChange: (event) => setField(field, event.target.value),
|
|
881
|
-
style: {
|
|
882
|
-
...inputStyle,
|
|
883
|
-
resize: "vertical",
|
|
884
|
-
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
885
|
-
lineHeight: 1.5
|
|
886
|
-
}
|
|
887
|
-
})
|
|
888
|
-
]);
|
|
889
|
-
return import_react.default.createElement("details", { style: { ...CARD, padding: "10px 12px" } }, [
|
|
890
1446
|
import_react.default.createElement("summary", {
|
|
891
1447
|
key: "sum",
|
|
892
|
-
style: { cursor: "pointer", fontSize:
|
|
1448
|
+
style: { cursor: "pointer", fontSize: 12.5, fontWeight: 650, color: C.label, userSelect: "none" }
|
|
893
1449
|
}, t("settings")),
|
|
894
|
-
import_react.default.createElement("div", {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1450
|
+
import_react.default.createElement("div", { key: "body", style: { marginTop: 7 } }, [
|
|
1451
|
+
row("salary", t("salaryField"), [
|
|
1452
|
+
import_react.default.createElement("input", {
|
|
1453
|
+
key: "i",
|
|
1454
|
+
type: "text",
|
|
1455
|
+
inputMode: "decimal",
|
|
1456
|
+
value: form.monthlySalary,
|
|
1457
|
+
placeholder: "10000",
|
|
1458
|
+
onChange: (event) => setField("monthlySalary", event.target.value),
|
|
1459
|
+
style: inputStyle
|
|
1460
|
+
}),
|
|
1461
|
+
import_react.default.createElement("span", { key: "u", style: unitStyle }, t("salaryUnit"))
|
|
1462
|
+
]),
|
|
1463
|
+
row("worktime", t("groupWorkTime"), [
|
|
1464
|
+
timeRange("workStart", "workEnd", t("groupWorkTime"), false)
|
|
1465
|
+
]),
|
|
1466
|
+
row("lunch", t("groupLunch"), [
|
|
1467
|
+
// 时间在前、两个开关在后(放到行尾)
|
|
1468
|
+
timeRange("lunchStart", "lunchEnd", t("groupLunch"), lunchDisabled),
|
|
1469
|
+
toggle("lunchEnabled", "lunchEnabledShort", false),
|
|
1470
|
+
toggle("lunchPaid", "lunchPaidShort", lunchDisabled)
|
|
1471
|
+
])
|
|
916
1472
|
]),
|
|
917
1473
|
import_react.default.createElement("div", {
|
|
918
1474
|
key: "actions",
|
|
919
|
-
style: { display: "flex", alignItems: "center", gap: 10,
|
|
1475
|
+
style: { display: "flex", alignItems: "center", gap: 10, marginTop: 7, paddingTop: 7, borderTop: `1px solid ${C.border1}` }
|
|
920
1476
|
}, [
|
|
921
1477
|
import_react.default.createElement("button", {
|
|
922
1478
|
key: "save",
|
|
@@ -924,20 +1480,24 @@ function SettingsSection(props) {
|
|
|
924
1480
|
onClick: onSave,
|
|
925
1481
|
disabled: save.status === "saving",
|
|
926
1482
|
style: {
|
|
927
|
-
border: `1px solid ${
|
|
928
|
-
color:
|
|
929
|
-
background: "
|
|
1483
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 72%, rgba(0,0,0,.18))`,
|
|
1484
|
+
color: "#3A2A05",
|
|
1485
|
+
background: save.status === "saving" ? `color-mix(in srgb, ${GOLD_TINT} 52%, #fff)` : "linear-gradient(180deg, #F8DC86 0%, #EFC258 52%, #D99D2C 100%)",
|
|
930
1486
|
borderRadius: 8,
|
|
931
|
-
padding: "
|
|
932
|
-
fontSize:
|
|
933
|
-
fontWeight:
|
|
934
|
-
|
|
1487
|
+
padding: "5px 16px",
|
|
1488
|
+
fontSize: 12.5,
|
|
1489
|
+
fontWeight: 700,
|
|
1490
|
+
letterSpacing: ".3px",
|
|
1491
|
+
cursor: save.status === "saving" ? "default" : "pointer",
|
|
1492
|
+
opacity: save.status === "saving" ? 0.72 : 1,
|
|
1493
|
+
boxShadow: `0 2px 9px color-mix(in srgb, ${GOLD_TINT} 34%, transparent), inset 0 1px 0 rgba(255,255,255,.45)`,
|
|
1494
|
+
textShadow: "0 1px 0 rgba(255,255,255,.28)"
|
|
935
1495
|
}
|
|
936
1496
|
}, save.status === "saving" ? t("saving") : t("save")),
|
|
937
|
-
save.status === "ok" ? import_react.default.createElement("span", { key: "ok", style: { fontSize:
|
|
1497
|
+
save.status === "ok" ? import_react.default.createElement("span", { key: "ok", style: { fontSize: 11.5, color: C.ok } }, save.message || t("saved")) : null,
|
|
938
1498
|
save.status === "error" ? import_react.default.createElement("span", {
|
|
939
1499
|
key: "err",
|
|
940
|
-
style: { fontSize:
|
|
1500
|
+
style: { fontSize: 11.5, color: C.error, flex: "1 1 200px", whiteSpace: "pre-wrap" }
|
|
941
1501
|
}, `${t("saveFailed")}${save.errors.join("\uFF1B")}`) : null
|
|
942
1502
|
])
|
|
943
1503
|
]);
|
|
@@ -959,6 +1519,48 @@ function NiumaPanel(props) {
|
|
|
959
1519
|
const snap = import_react.default.useMemo(() => earnedToday(cfg, now), [cfg, now]);
|
|
960
1520
|
const rates = snap && snap.rates ? snap.rates : computeRates(cfg, snap && snap.dateKey);
|
|
961
1521
|
const baseForm = import_react.default.useMemo(() => formFromConfig(cfg), [cfg]);
|
|
1522
|
+
const viewYear = Number(String(snap && snap.dateKey ? snap.dateKey : "").slice(0, 4)) || (/* @__PURE__ */ new Date()).getFullYear();
|
|
1523
|
+
const yearEstimated = viewYear === HOLIDAY_ESTIMATE_2027.year;
|
|
1524
|
+
const yearData = import_react.default.useMemo(() => yearSummary(cfg, viewYear), [cfg, viewYear]);
|
|
1525
|
+
const [view, setView] = import_react.default.useState("current");
|
|
1526
|
+
const selectedMonth = view.startsWith("m") ? yearData.months[Number(view.slice(1)) - 1] : null;
|
|
1527
|
+
const maxHolidayMonth = yearData.maxHolidayMonth;
|
|
1528
|
+
const maxHolidayText = t("maxHolidayNote").replace("{month}", String(maxHolidayMonth.month)).replace("{days}", String(maxHolidayMonth.holidayDays));
|
|
1529
|
+
let viewCards;
|
|
1530
|
+
let viewHint;
|
|
1531
|
+
let viewNote;
|
|
1532
|
+
if (view === "year") {
|
|
1533
|
+
viewCards = [
|
|
1534
|
+
{ key: "avgSecond", label: t("averageSecond"), value: money(yearData.averageSecondWage, 4), accent: true },
|
|
1535
|
+
{ key: "avgMinute", label: t("averageMinute"), value: money(yearData.averageMinuteWage, 4) },
|
|
1536
|
+
{ key: "avgHourly", label: t("averageHourly"), value: money(yearData.averageHourlyWage, 2) },
|
|
1537
|
+
{ key: "avgDaily", label: t("averageDaily"), value: money(yearData.averageDailyWage, 2) },
|
|
1538
|
+
{ key: "yearWorkdays", label: t("yearWorkdays"), value: `${yearData.totalWorkdays}${t("dayUnit")}` },
|
|
1539
|
+
{ key: "yearIncome", label: t("yearIncome"), value: money(yearData.annualIncome, 2) }
|
|
1540
|
+
];
|
|
1541
|
+
viewHint = `${t("yearHint").replace("{year}", String(viewYear)).replace("{workdays}", String(yearData.totalWorkdays))} \xB7 ${t("viewOnlyHint")}` + (yearEstimated ? ` \xB7 ${t("holidayEstimateShort")}` : "");
|
|
1542
|
+
viewNote = yearEstimated ? t("holidayEstimateNote") : maxHolidayText;
|
|
1543
|
+
} else if (selectedMonth) {
|
|
1544
|
+
viewCards = [
|
|
1545
|
+
{ key: "secondWage", label: t("secondWage"), value: money(selectedMonth.secondWage, 4), accent: true },
|
|
1546
|
+
{ key: "minuteWage", label: t("minuteWage"), value: money(selectedMonth.minuteWage, 4) },
|
|
1547
|
+
{ key: "hourlyWage", label: t("hourlyWage"), value: money(selectedMonth.hourlyWage, 2) },
|
|
1548
|
+
{ key: "dailyWage", label: t("dailyWage"), value: money(selectedMonth.dailyWage, 2) },
|
|
1549
|
+
{ key: "monthlyWage", label: t("monthlyWage"), value: money(selectedMonth.monthlySalary, 2) },
|
|
1550
|
+
{ key: "monthWorkdays", label: t("monthWorkdaysCard"), value: `${selectedMonth.workdays}${t("dayUnit")}` }
|
|
1551
|
+
];
|
|
1552
|
+
viewHint = `${t("monthHint").replace("{year}", String(viewYear)).replace("{month}", String(selectedMonth.month)).replace("{workdays}", String(selectedMonth.workdays)).replace("{holidays}", String(selectedMonth.holidayDays))} \xB7 ${t("viewOnlyHint")}` + (yearEstimated ? ` \xB7 ${t("holidayEstimateShort")}` : "");
|
|
1553
|
+
viewNote = yearEstimated ? t("holidayEstimateNote") : selectedMonth.month === maxHolidayMonth.month ? `\u2605 ${t("maxHolidayThis").replace("{days}", String(maxHolidayMonth.holidayDays))}` : maxHolidayText;
|
|
1554
|
+
} else {
|
|
1555
|
+
viewCards = RATE_CARDS.map((spec) => ({
|
|
1556
|
+
key: spec.key,
|
|
1557
|
+
label: t(spec.label),
|
|
1558
|
+
value: money(rates[spec.key], spec.digits),
|
|
1559
|
+
accent: spec.key === "secondWage"
|
|
1560
|
+
}));
|
|
1561
|
+
viewHint = t("currentHint").replace("{days}", String(rates.monthlyWorkdays)).replace("{hours}", trimNumber(rates.paidHours, 2));
|
|
1562
|
+
viewNote = maxHolidayText;
|
|
1563
|
+
}
|
|
962
1564
|
const [draft, setDraft] = import_react.default.useState(null);
|
|
963
1565
|
const [save, setSave] = import_react.default.useState({ status: "idle", errors: [], message: "" });
|
|
964
1566
|
const form = draft || baseForm;
|
|
@@ -1011,79 +1613,166 @@ function NiumaPanel(props) {
|
|
|
1011
1613
|
} : remote.status === "loading" ? { color: C.label3, text: t("configLoading"), retry: false } : null;
|
|
1012
1614
|
return import_react.default.createElement("div", {
|
|
1013
1615
|
style: {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1616
|
+
// DSH 的 main slot 给的是定高容器:插件必须自己当滚动容器,否则展开设置后底部会被裁掉。
|
|
1617
|
+
// 注意:这里用 block + 内层 flex 的写法 —— 如果根直接 display:flex,子项会在定高容器里
|
|
1618
|
+
// 被 flex-shrink 压扁(展开设置时整张主卡高度被压缩、内容被 overflow 裁掉)。
|
|
1619
|
+
height: "100%",
|
|
1620
|
+
width: "100%",
|
|
1621
|
+
overflowY: "auto",
|
|
1622
|
+
overflowX: "hidden",
|
|
1623
|
+
overscrollBehavior: "contain",
|
|
1624
|
+
scrollbarGutter: "stable",
|
|
1625
|
+
boxSizing: "border-box",
|
|
1019
1626
|
fontSize: 13,
|
|
1020
1627
|
lineHeight: 1.45,
|
|
1021
1628
|
color: C.label,
|
|
1022
1629
|
fontFamily: "inherit"
|
|
1023
1630
|
}
|
|
1024
1631
|
}, [
|
|
1025
|
-
|
|
1632
|
+
import_react.default.createElement(StyleTag, { key: "css" }),
|
|
1026
1633
|
import_react.default.createElement("div", {
|
|
1027
|
-
key: "
|
|
1028
|
-
style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }
|
|
1029
|
-
}, [
|
|
1030
|
-
import_react.default.createElement("div", { key: "tt", style: { marginRight: "auto", minWidth: 0 } }, [
|
|
1031
|
-
import_react.default.createElement("div", {
|
|
1032
|
-
key: "t",
|
|
1033
|
-
style: { fontSize: 16, fontWeight: 700, color: C.label }
|
|
1034
|
-
}, t("title")),
|
|
1035
|
-
import_react.default.createElement("div", {
|
|
1036
|
-
key: "s",
|
|
1037
|
-
style: { fontSize: 11, color: C.label3 }
|
|
1038
|
-
}, t("subtitle"))
|
|
1039
|
-
]),
|
|
1040
|
-
import_react.default.createElement(StatusBadge, { key: "badge", t, status: snap.status })
|
|
1041
|
-
]),
|
|
1042
|
-
// 配置读取状态
|
|
1043
|
-
banner ? import_react.default.createElement("div", {
|
|
1044
|
-
key: "banner",
|
|
1634
|
+
key: "inner",
|
|
1045
1635
|
style: {
|
|
1046
1636
|
display: "flex",
|
|
1047
|
-
|
|
1048
|
-
gap:
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
padding: "
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
background: C.layer1
|
|
1637
|
+
flexDirection: "column",
|
|
1638
|
+
gap: 11,
|
|
1639
|
+
width: "100%",
|
|
1640
|
+
maxWidth: 820,
|
|
1641
|
+
margin: "0 auto",
|
|
1642
|
+
padding: "16px 18px 40px",
|
|
1643
|
+
boxSizing: "border-box",
|
|
1644
|
+
minWidth: 0
|
|
1056
1645
|
}
|
|
1057
1646
|
}, [
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
key: "
|
|
1061
|
-
|
|
1062
|
-
|
|
1647
|
+
// 品牌头:图标块 + 标题/副标题 + 状态徽标
|
|
1648
|
+
import_react.default.createElement("div", {
|
|
1649
|
+
key: "head",
|
|
1650
|
+
style: { display: "flex", alignItems: "center", gap: 11, flexWrap: "wrap" }
|
|
1651
|
+
}, [
|
|
1652
|
+
import_react.default.createElement("div", {
|
|
1653
|
+
key: "icon",
|
|
1654
|
+
style: {
|
|
1655
|
+
width: 38,
|
|
1656
|
+
height: 38,
|
|
1657
|
+
borderRadius: 12,
|
|
1658
|
+
flex: "0 0 auto",
|
|
1659
|
+
display: "grid",
|
|
1660
|
+
placeItems: "center",
|
|
1661
|
+
color: C.brand,
|
|
1662
|
+
background: `color-mix(in srgb, ${C.brand} 13%, transparent)`,
|
|
1663
|
+
border: `1px solid color-mix(in srgb, ${C.brand} 26%, transparent)`
|
|
1664
|
+
}
|
|
1665
|
+
}, import_react.default.createElement(NiumaIcon, { size: 21 })),
|
|
1666
|
+
import_react.default.createElement("div", { key: "tt", style: { marginRight: "auto", minWidth: 0 } }, [
|
|
1667
|
+
import_react.default.createElement("div", {
|
|
1668
|
+
key: "t",
|
|
1669
|
+
style: { fontSize: 17.5, fontWeight: 800, letterSpacing: "-.3px", color: C.label }
|
|
1670
|
+
}, t("title")),
|
|
1671
|
+
import_react.default.createElement("div", {
|
|
1672
|
+
key: "s",
|
|
1673
|
+
style: { fontSize: 11, color: C.label3, marginTop: 1 }
|
|
1674
|
+
}, t("subtitle"))
|
|
1675
|
+
]),
|
|
1676
|
+
import_react.default.createElement(StatusBadge, { key: "badge", t, status: snap.status })
|
|
1677
|
+
]),
|
|
1678
|
+
// 配置读取状态
|
|
1679
|
+
banner ? import_react.default.createElement("div", {
|
|
1680
|
+
key: "banner",
|
|
1063
1681
|
style: {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
padding: "2px 10px",
|
|
1682
|
+
display: "flex",
|
|
1683
|
+
alignItems: "center",
|
|
1684
|
+
gap: 8,
|
|
1685
|
+
flexWrap: "wrap",
|
|
1069
1686
|
fontSize: 12,
|
|
1070
|
-
|
|
1687
|
+
color: banner.color,
|
|
1688
|
+
padding: "6px 10px",
|
|
1689
|
+
borderRadius: 9,
|
|
1690
|
+
border: `1px solid color-mix(in srgb, ${banner.color} 45%, transparent)`,
|
|
1691
|
+
background: `color-mix(in srgb, ${banner.color} 10%, transparent)`
|
|
1071
1692
|
}
|
|
1072
|
-
},
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1693
|
+
}, [
|
|
1694
|
+
import_react.default.createElement("span", { key: "txt", style: { flex: "1 1 160px" } }, banner.text),
|
|
1695
|
+
banner.retry ? import_react.default.createElement("button", {
|
|
1696
|
+
key: "retry",
|
|
1697
|
+
type: "button",
|
|
1698
|
+
onClick: remote.refresh,
|
|
1699
|
+
style: {
|
|
1700
|
+
border: `1px solid ${banner.color}`,
|
|
1701
|
+
color: banner.color,
|
|
1702
|
+
background: "transparent",
|
|
1703
|
+
borderRadius: 6,
|
|
1704
|
+
padding: "2px 10px",
|
|
1705
|
+
fontSize: 12,
|
|
1706
|
+
cursor: "pointer"
|
|
1707
|
+
}
|
|
1708
|
+
}, t("retry")) : null
|
|
1709
|
+
]) : null,
|
|
1710
|
+
import_react.default.createElement(HeroCard, { key: "hero", t, snap }),
|
|
1711
|
+
import_react.default.createElement(CountdownRow, { key: "countdown", t, snap }),
|
|
1712
|
+
import_react.default.createElement("div", {
|
|
1713
|
+
key: "ratesHead",
|
|
1714
|
+
style: {
|
|
1715
|
+
display: "flex",
|
|
1716
|
+
alignItems: "center",
|
|
1717
|
+
justifyContent: "space-between",
|
|
1718
|
+
gap: 8,
|
|
1719
|
+
flexWrap: "wrap",
|
|
1720
|
+
margin: "2px 1px -1px"
|
|
1721
|
+
}
|
|
1722
|
+
}, [
|
|
1723
|
+
import_react.default.createElement("span", {
|
|
1724
|
+
key: "t",
|
|
1725
|
+
style: { fontSize: 12.5, fontWeight: 700, color: C.label2, letterSpacing: ".2px" }
|
|
1726
|
+
}, t("sectionRates")),
|
|
1727
|
+
import_react.default.createElement(PeriodSelect, {
|
|
1728
|
+
key: "period",
|
|
1729
|
+
t,
|
|
1730
|
+
value: view,
|
|
1731
|
+
onChange: setView,
|
|
1732
|
+
year: viewYear,
|
|
1733
|
+
months: yearData.months
|
|
1734
|
+
})
|
|
1735
|
+
]),
|
|
1736
|
+
import_react.default.createElement("div", {
|
|
1737
|
+
key: "ratesHint",
|
|
1738
|
+
style: { fontSize: 10.5, color: C.label3, ...NUM }
|
|
1739
|
+
}, viewHint),
|
|
1740
|
+
import_react.default.createElement(RatesGrid, { key: "rates", cards: viewCards }),
|
|
1741
|
+
viewNote ? import_react.default.createElement("div", {
|
|
1742
|
+
key: "ratesNote",
|
|
1743
|
+
style: { fontSize: 10.5, color: C.label3, display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }
|
|
1744
|
+
}, [
|
|
1745
|
+
import_react.default.createElement("span", {
|
|
1746
|
+
key: "badge",
|
|
1747
|
+
style: {
|
|
1748
|
+
color: C.label2,
|
|
1749
|
+
fontWeight: 600,
|
|
1750
|
+
background: `color-mix(in srgb, ${GOLD_TINT} 14%, transparent)`,
|
|
1751
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 32%, transparent)`,
|
|
1752
|
+
borderRadius: 999,
|
|
1753
|
+
padding: "1px 8px"
|
|
1754
|
+
}
|
|
1755
|
+
}, t("maxHolidayBadge")),
|
|
1756
|
+
import_react.default.createElement("span", { key: "txt" }, viewNote)
|
|
1757
|
+
]) : null,
|
|
1758
|
+
import_react.default.createElement(SectionTitle, { key: "detailTitle", title: t("sectionDetail") }),
|
|
1759
|
+
import_react.default.createElement(DetailsFooter, { key: "footer", t, snap, holidaySource }),
|
|
1760
|
+
import_react.default.createElement(HolidaysCard, {
|
|
1761
|
+
key: "holidays",
|
|
1762
|
+
t,
|
|
1763
|
+
holidaySource,
|
|
1764
|
+
extraWorkdays: cfg.extraWorkdays
|
|
1765
|
+
}),
|
|
1766
|
+
import_react.default.createElement(SettingsSection, {
|
|
1767
|
+
key: "settings",
|
|
1768
|
+
t,
|
|
1769
|
+
form,
|
|
1770
|
+
setField,
|
|
1771
|
+
setCheck,
|
|
1772
|
+
save,
|
|
1773
|
+
onSave
|
|
1774
|
+
})
|
|
1775
|
+
])
|
|
1087
1776
|
]);
|
|
1088
1777
|
}
|
|
1089
1778
|
var inject = ["slots", "locale"];
|