Skip to content

Commit 1fd5f7e

Browse files
committed
update
1 parent 56a0be8 commit 1fd5f7e

File tree

12 files changed

+227
-118
lines changed

12 files changed

+227
-118
lines changed

src/data/data.json

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,24 @@
118118
"ja": "君の残る命は:"
119119
}
120120
},
121+
{
122+
"id": "UI_DEATH",
123+
"lang": {
124+
"en": "You can live to {MM}/{DD}/{YYYY} ",
125+
"zh": "你可以活到{YYYY}年{MM}月{DD}日",
126+
"zh-HK": "你可以活到{YYYY}年{MM}月{DD}日",
127+
"ja": "君は{YYYY}年{MM}月{DD}日まで生きられます"
128+
}
129+
},
130+
{
131+
"id": "UI_PERCENT_BEFORE",
132+
"lang": {
133+
"en": "You are better than {percent}% of people",
134+
"zh": "你击败{percent}%的人",
135+
"zh-HK": "你擊敗{percent}%的人",
136+
"ja": "君は {pe​​rcent}% の人に勝ちました"
137+
}
138+
},
121139
{
122140
"id": "UI_C/R",
123141
"lang": {
@@ -5045,9 +5063,21 @@
50455063
"altDilution": {
50465064
"key": "altDilution",
50475065
"value": 30
5066+
},
5067+
"lifeStd": {
5068+
"key": "lifeStd",
5069+
"value": 10
5070+
},
5071+
"year": {
5072+
"key": "year",
5073+
"value": 31536000
5074+
},
5075+
"month": {
5076+
"key": "month",
5077+
"value": 2628000
50485078
}
50495079
}
50505080
},
5051-
"version": "2025-02-15T13:34:27.581Z",
5052-
"timestamp": "2025-02-15T13:34:27.581Z"
5081+
"version": "2025-02-16T07:49:48.605Z",
5082+
"timestamp": "2025-02-16T07:49:48.605Z"
50535083
}

src/data/data.xlsx

634 Bytes
Binary file not shown.

src/data/index.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { data, version } from '@/data/data.json'
22
import { database } from '@/database'
3-
import { zoneRandom } from '@/utils'
3+
import { zoneRandom, cdf } from '@/utils'
44

55
export { version }
66

@@ -309,3 +309,32 @@ export function getBaseLife(country: Country, age: Age, sex: Sex) {
309309
? getConfig('lifeBaseRandom')
310310
: averageValue - ageValue
311311
}
312+
313+
export function getLifeSeconds(life: number) {
314+
return life * getConfig('year')
315+
}
316+
317+
export function calcLife(seconds: number) {
318+
const YEAR = getConfig('year')
319+
const MONTH = getConfig('month')
320+
321+
const Y = Math.floor(seconds / YEAR)
322+
const M = Math.floor((seconds - Y * YEAR) / MONTH)
323+
const D = Math.floor((seconds - Y * YEAR - M * MONTH) / 86400)
324+
const h = Math.floor((seconds / 3600) % 24)
325+
const m = Math.floor((seconds / 60) % 60)
326+
const s = Math.floor(seconds % 60)
327+
return { Y, M, D, h, m, s }
328+
}
329+
330+
export function percentBefore(
331+
life: number,
332+
country: Country,
333+
age: Age,
334+
sex: Sex
335+
) {
336+
const x = life + age.value
337+
const mean = country.life[sex.value]
338+
const std = getConfig('lifeStd')
339+
return (cdf(x, mean, std) * 100).toFixed(2).replace(/\.00$/, '')
340+
}

src/hooks/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
export { useLanguage } from './useLanguage'
2-
export { useTimeFormat } from './useTimeFormat'
1+
export { useLanguage, languages } from './useLanguage'
32
export type { FormatData } from './useLanguage'
3+
4+
export { useCountdown } from './useCountdown'

src/hooks/useCountdown.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useState, useEffect } from 'react'
2+
import { fill0, callNow } from '@/utils'
3+
import { getLifeSeconds, calcLife } from '@/data'
4+
import type { FormatData } from './useLanguage'
5+
export interface Time extends FormatData {
6+
YY: string
7+
MM: string
8+
DD: string
9+
hh: string
10+
mm: string
11+
ss: string
12+
}
13+
14+
export type Return = [
15+
Time,
16+
setTime: (time: number) => void,
17+
setStart: (pass: number) => void
18+
]
19+
export function useCountdown(time: number, start: number): Return {
20+
const [mt, setTime] = useState(time)
21+
const [ms, setStart] = useState(start)
22+
const [seconds, setSeconds] = useState(0)
23+
const [data, setData] = useState<Time>({
24+
YY: '00',
25+
MM: '00',
26+
DD: '00',
27+
hh: '00',
28+
mm: '00',
29+
ss: '00',
30+
})
31+
useEffect(() => {
32+
const life = calcLife(seconds)
33+
setData({
34+
YY: fill0(life.Y),
35+
MM: fill0(life.M),
36+
DD: fill0(life.D),
37+
hh: fill0(life.h),
38+
mm: fill0(life.m),
39+
ss: fill0(life.s),
40+
})
41+
}, [seconds])
42+
useEffect(() => {
43+
const interval = setInterval(
44+
callNow(() => {
45+
const passed = Math.floor((Date.now() - ms) / 1000)
46+
const life = getLifeSeconds(mt)
47+
setSeconds(Math.max(life - passed, 0))
48+
}),
49+
1000
50+
)
51+
return () => clearInterval(interval)
52+
}, [mt, ms])
53+
return [data, setTime, setStart]
54+
}
55+
56+
export default useCountdown

src/hooks/useLanguage.tsx

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import { useState, useEffect } from 'react'
1+
import { useState } from 'react'
22
import { query } from '@/data'
33

4-
type MapData = Map<string, Map<string | number, string>>
4+
const i18n = new Map()
5+
for (const { id: key, lang: langs } of query('i18n')) {
6+
for (const [lang, value] of Object.entries(langs)) {
7+
if (!i18n.has(lang)) i18n.set(lang, new Map())
8+
i18n.get(lang)?.set(key, value)
9+
}
10+
}
11+
12+
export const languages = Array.from(i18n.keys())
513
export interface FormatData {
614
[key: string]: string | number
715
}
@@ -12,40 +20,23 @@ function format(template: string, formatData: FormatData) {
1220
}
1321

1422
function getLanguageFallback() {
15-
const fallback = []
16-
const userSettings = localStorage.getItem('language')
17-
if (userSettings) fallback.push(userSettings)
23+
const setting = localStorage.getItem('language')
24+
if (setting && i18n.has(setting)) return setting
1825
const nav = navigator.language
1926
if (nav) {
20-
fallback.push(nav)
21-
fallback.push(nav.split('-')[0])
27+
if (i18n.has(nav)) return nav
28+
const lang = nav.split('-')[0]
29+
if (i18n.has(lang)) return lang
2230
}
23-
fallback.push('en')
24-
return fallback
31+
return 'en'
32+
}
33+
function saveLanguage(language: string) {
34+
localStorage.setItem('language', language)
35+
return language
2536
}
2637

2738
export function useLanguage() {
28-
const [language, setLanguage] = useState('')
29-
const [i18n, setI18n] = useState<MapData | null>(null)
30-
const [languages, setLanguages] = useState<string[]>([])
31-
useEffect(() => {
32-
const i18n = new Map()
33-
for (const { id: key, lang: langs } of query('i18n')) {
34-
for (const [lang, value] of Object.entries(langs)) {
35-
if (!i18n.has(lang)) i18n.set(lang, new Map())
36-
i18n.get(lang)?.set(key, value)
37-
}
38-
}
39-
setI18n(i18n)
40-
setLanguages(Array.from(i18n.keys()))
41-
const fallback = getLanguageFallback()
42-
for (const lang of fallback) {
43-
if (i18n.has(lang)) {
44-
setLanguage(lang)
45-
return
46-
}
47-
}
48-
}, [])
39+
const [language, setLanguage] = useState(getLanguageFallback())
4940
return {
5041
t: (key: string | number, formatData?: FormatData) => {
5142
const template = i18n?.get(language)?.get(key) || key
@@ -55,10 +46,8 @@ export function useLanguage() {
5546
return format(template, formatData)
5647
},
5748
setLanguage: (lang: string) => {
58-
localStorage.setItem('language', lang)
59-
setLanguage(lang)
49+
setLanguage(saveLanguage(lang))
6050
},
61-
languages,
6251
}
6352
}
6453

src/hooks/useTimeFormat.tsx

Lines changed: 0 additions & 55 deletions
This file was deleted.

src/index.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ body {
2121
display: flex;
2222
place-items: center;
2323
min-height: 100vh;
24+
white-space: pre-wrap;
2425
}
2526

2627
ul {

src/pages/OptionsPage.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect } from 'react'
2-
import { useLanguage } from '@/hooks'
2+
import { useLanguage, languages as langs } from '@/hooks'
33
import { query, type Country, type Age, type Sex, type Base } from '@/data'
44
import { Choose } from '@/components/Choose'
55
import { type Options } from './ResultPage'
@@ -15,10 +15,6 @@ export interface OptionPageProps {
1515
onStart?: (options: Options) => void
1616
}
1717

18-
interface Language extends Base {
19-
value: string
20-
}
21-
2218
interface Choosed<T extends Base> {
2319
choosed: true
2420
value: T['value']
@@ -33,21 +29,17 @@ interface UnChoosed {
3329
type ChooseResult<T extends Base> = Choosed<T> | UnChoosed
3430

3531
export function OptionPage({ onStart }: OptionPageProps) {
36-
const { t, setLanguage, languages: langs } = useLanguage()
32+
const { t, setLanguage } = useLanguage()
3733
const [countrys, setCountrys] = useState<Country[]>([])
3834
const [ages, setAges] = useState<Age[]>([])
3935
const [sexs, setSexs] = useState<Sex[]>([])
40-
const [languages, setLanguages] = useState<Language[]>([])
36+
4137
useEffect(() => {
4238
setCountrys(query('country'))
4339
setAges(query('age'))
4440
setSexs(query('sex'))
4541
}, [])
4642

47-
useEffect(() => {
48-
setLanguages(langs.map(value => ({ value })))
49-
}, [langs])
50-
5143
const [country, setCountry] = useState<ChooseResult<Country>>({
5244
value: 'UI_C/R',
5345
choosed: false,
@@ -114,7 +106,7 @@ export function OptionPage({ onStart }: OptionPageProps) {
114106
case 'language':
115107
return (
116108
<Choose
117-
list={languages}
109+
list={langs.map(value => ({ value }))}
118110
onChoose={item => {
119111
setLanguage(item.value)
120112
setChoose('')

src/pages/ResultPage.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
}
2222

2323
.timer{
24-
font-size: 60px;
24+
font-size: 80px;
25+
max-width: 100vw;
2526
display: flex;
2627
flex-direction: column;
2728
text-align: center;
@@ -84,6 +85,10 @@
8485
font-family: Consolas, 'Courier New', Courier, monospace;
8586
font-weight: 900;
8687
}
88+
.addition {
89+
font-size: 0.3em;
90+
text-align: left;
91+
}
8792
}
8893

8994
.achivements {

0 commit comments

Comments
 (0)