@ramathibodi/nuxt-commons 0.1.64 → 0.1.65
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/dist/module.json
CHANGED
|
@@ -45,6 +45,7 @@ watch(() => alert?.hasAlert(), (hasAlert) => {
|
|
|
45
45
|
elevation="2"
|
|
46
46
|
theme="dark"
|
|
47
47
|
variant="flat"
|
|
48
|
+
v-bind="currentItem.alertIcon ? { icon: currentItem.alertIcon } : {}"
|
|
48
49
|
@click:close="renewAlert()"
|
|
49
50
|
>
|
|
50
51
|
{{ currentItem.statusCode ? currentItem.statusCode + ' ' : '' }} {{ currentItem.message }} {{ !isEmpty(currentItem.data) ? currentItem.data : '' }}
|
|
@@ -2,39 +2,142 @@
|
|
|
2
2
|
import { DateTime } from "luxon";
|
|
3
3
|
import { computed } from "vue";
|
|
4
4
|
|
|
5
|
-
type
|
|
5
|
+
type Unit = 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds';
|
|
6
|
+
type Locale = 'th' | 'en' | 'en-US' | 'th-TH';
|
|
6
7
|
|
|
7
8
|
interface Props {
|
|
8
9
|
modelValue: DateTime;
|
|
9
10
|
endDate?: DateTime;
|
|
10
11
|
locale?: Locale;
|
|
11
|
-
|
|
12
|
+
showSuffix?: boolean;
|
|
13
|
+
units?: Unit[];
|
|
14
|
+
zeroBase?: boolean; // true = start at 0, false = start at 1 (inclusive)
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
const props = withDefaults(defineProps<Props>(), {
|
|
15
|
-
locale:
|
|
18
|
+
locale: 'th',
|
|
19
|
+
showSuffix: true,
|
|
16
20
|
zeroBase: true,
|
|
17
21
|
});
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
// Fallback map: map complex locale (e.g., en-US) to base (e.g., en)
|
|
24
|
+
const normalizeLocale = (locale: Locale): 'en' | 'th' => {
|
|
25
|
+
if (locale.startsWith('en')) return 'en';
|
|
26
|
+
if (locale.startsWith('th')) return 'th';
|
|
27
|
+
return 'th'; // default fallback
|
|
28
|
+
};
|
|
21
29
|
|
|
22
|
-
const
|
|
23
|
-
|
|
30
|
+
const labelsEnPlural: Record<Unit, string> = {
|
|
31
|
+
years: 'years',
|
|
32
|
+
months: 'months',
|
|
33
|
+
days: 'days',
|
|
34
|
+
hours: 'hours',
|
|
35
|
+
minutes: 'minutes',
|
|
36
|
+
seconds: 'seconds',
|
|
37
|
+
};
|
|
38
|
+
const labelsEnSingular: Record<Unit, string> = {
|
|
39
|
+
years: 'year',
|
|
40
|
+
months: 'month',
|
|
41
|
+
days: 'day',
|
|
42
|
+
hours: 'hour',
|
|
43
|
+
minutes: 'minute',
|
|
44
|
+
seconds: 'second',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const localizedLabels: Record<'en' | 'th', Record<Unit, string>> = {
|
|
48
|
+
en: labelsEnPlural, // จะสลับเป็น singular ตามค่าจริงตอน render
|
|
49
|
+
th: {
|
|
50
|
+
years: 'ปี',
|
|
51
|
+
months: 'เดือน',
|
|
52
|
+
days: 'วัน',
|
|
53
|
+
hours: 'ชั่วโมง',
|
|
54
|
+
minutes: 'นาที',
|
|
55
|
+
seconds: 'วินาที',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const localizedSuffix: Record<'en' | 'th', string> = {
|
|
60
|
+
en: 'ago',
|
|
61
|
+
th: 'ที่ผ่านมา',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const outputText = computed(() => {
|
|
65
|
+
const base = props.endDate ?? DateTime.now(); // ใช้ endDate ถ้ามี ไม่งั้น now
|
|
24
66
|
const baseLocale = normalizeLocale(props.locale);
|
|
25
67
|
|
|
26
|
-
|
|
68
|
+
const units: Unit[] = props.units?.length
|
|
69
|
+
? props.units
|
|
70
|
+
: ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];
|
|
71
|
+
|
|
72
|
+
const diffObj = base.diff(props.modelValue, units).toObject();
|
|
73
|
+
|
|
74
|
+
// helper: คืน label ตาม singular/plural (เฉพาะ en)
|
|
75
|
+
const labelFor = (unit: Unit, value: number) => {
|
|
76
|
+
if (baseLocale === 'en') {
|
|
77
|
+
return value === 1 ? labelsEnSingular[unit] : labelsEnPlural[unit];
|
|
78
|
+
}
|
|
79
|
+
return localizedLabels[baseLocale][unit];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ---------- โหมด single unit ----------
|
|
83
|
+
if (!props.units) {
|
|
84
|
+
const foundUnit = units.find((unit) => (diffObj[unit] ?? 0) >= 1);
|
|
85
|
+
if (foundUnit) {
|
|
86
|
+
const raw = Math.floor(diffObj[foundUnit] ?? 0); // >= 1
|
|
87
|
+
const value = props.zeroBase ? raw : raw + 1; // inclusive (+1)
|
|
88
|
+
const label = labelFor(foundUnit, value);
|
|
89
|
+
const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
|
|
90
|
+
return `${value} ${label}${suffix ? ` ${suffix}` : ''}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ถ้าไม่มีหน่วยใด >= 1 ให้ใช้หน่วยเล็กสุด
|
|
94
|
+
const lastUnit = units.at(-1)!;
|
|
95
|
+
const raw = Math.max(0, Math.floor(diffObj[lastUnit] ?? 0));
|
|
96
|
+
const value = props.zeroBase ? raw : 1; // inclusive: อย่างน้อย 1
|
|
97
|
+
const label = labelFor(lastUnit, value);
|
|
98
|
+
const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
|
|
99
|
+
return `${value} ${label}${suffix ? ` ${suffix}` : ''}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------- โหมด multi-unit ----------
|
|
103
|
+
// เก็บค่าแบบตัวเลขก่อน แล้วค่อยเรนเดอร์
|
|
104
|
+
const values = units.map((unit) => ({
|
|
105
|
+
unit,
|
|
106
|
+
raw: Math.max(0, Math.floor(diffObj[unit] ?? 0)),
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
// เลือกหน่วยที่เล็กที่สุด
|
|
110
|
+
const smallest = values[values.length - 1];
|
|
111
|
+
|
|
112
|
+
// ถ้ามีค่าอย่างน้อยหนึ่งหน่วย > 0 และเป็น inclusive (zeroBase=false) => +1 ที่หน่วยเล็กสุด
|
|
113
|
+
const anyPositive = values.some((v) => v.raw > 0);
|
|
114
|
+
const adjusted = values.map((v, idx) => {
|
|
115
|
+
if (!props.zeroBase && anyPositive && idx === values.length - 1) {
|
|
116
|
+
return { ...v, raw: v.raw + 1 };
|
|
117
|
+
}
|
|
118
|
+
return v;
|
|
119
|
+
});
|
|
27
120
|
|
|
28
|
-
|
|
121
|
+
// สร้างข้อความจากหน่วยที่มีค่า > 0
|
|
122
|
+
const parts = adjusted
|
|
123
|
+
.filter((v) => v.raw > 0)
|
|
124
|
+
.map((v) => `${v.raw} ${labelFor(v.unit, v.raw)}`);
|
|
29
125
|
|
|
30
|
-
|
|
31
|
-
|
|
126
|
+
// หากทั้งหมดเป็น 0:
|
|
127
|
+
if (parts.length === 0) {
|
|
128
|
+
const minValue = props.zeroBase ? 0 : 1;
|
|
129
|
+
const label = labelFor(smallest.unit, minValue);
|
|
130
|
+
const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
|
|
131
|
+
return `${minValue} ${label}${suffix ? ` ${suffix}` : ''}`;
|
|
32
132
|
}
|
|
33
133
|
|
|
34
|
-
|
|
134
|
+
const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
|
|
135
|
+
return `${parts.join(' ')}${suffix ? ` ${suffix}` : ''}`;
|
|
35
136
|
});
|
|
36
137
|
</script>
|
|
37
138
|
|
|
38
139
|
<template>
|
|
39
|
-
<span>
|
|
140
|
+
<span>
|
|
141
|
+
<i v-if="props.zeroBase" class="mdi mdi-clock-time-twelve-outline" aria-hidden="true" ></i>
|
|
142
|
+
{{ outputText }}</span>
|
|
40
143
|
</template>
|