diff --git a/apps/web/index.html b/apps/web/index.html
index 1622230..62b1729 100644
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -6,6 +6,8 @@
+
+
+
{talent.name}
{talent.description}
diff --git a/apps/web/src/components/ThemeToggle.css b/apps/web/src/components/ThemeToggle.css
index f927128..834e305 100644
--- a/apps/web/src/components/ThemeToggle.css
+++ b/apps/web/src/components/ThemeToggle.css
@@ -1,24 +1,5 @@
-.theme-toggle-btn {
- background: transparent;
- border: none;
- cursor: pointer;
- padding: 0.25rem;
- border-radius: 50%;
- position: fixed;
- top: 0.5rem;
- right: 0.5rem;
- width: 2.5rem;
- height: 2.5rem;
- display: flex;
- align-items: center;
- justify-content: center;
- -webkit-tap-highlight-color: transparent;
- transition: background-color 0.3s;
- --hover-color: rgba(0, 0, 0, 0.05);
- &:hover { background-color: var(--hover-color);}
-}
-
.theme-svg {
+ --svg-color: oklch(from var(--text-color, var(--base-text-color)) calc(l + 0.2) c h);
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: center;
.sun-center, .sun-beams, .mask-cutter-group {
@@ -26,21 +7,19 @@
transform-origin: center;
}
.mask-cutter-group { transform: translate(0.75rem, -0.75rem); }
- .sun-center { fill: oklch(from var(--base-text-color) calc(l + 0.2) c h); }
- .sun-beams { stroke: oklch(from var(--base-text-color) calc(l + 0.2) c h); }
+ .sun-center {
+ transition: fill 0.2s ease-in-out;
+ fill: var(--svg-color);
+ }
+ .sun-beams {
+ transition: stroke 0.2s ease-in-out;
+ stroke: var(--svg-color);
+ }
}
html[data-theme='dark'] {
- .theme-toggle-btn { --hover-color: rgba(255, 255, 255, 0.1); }
.mask-cutter-group { transform: translate(0, 0); }
.theme-svg { transform: rotate(375deg); }
- .sun-center {
- transform: scale(1.5);
- fill: #fbbf24;
- }
- .sun-beams {
- opacity: 0;
- transform: scale(0.6);
- stroke: #fbbf24;
- }
+ .sun-center { transform: scale(1.5); }
+ .sun-beams { opacity: 0; transform: scale(0.6); }
}
diff --git a/apps/web/src/components/ThemeToggle.tsx b/apps/web/src/components/ThemeToggle.tsx
index 6a2f199..39269ea 100644
--- a/apps/web/src/components/ThemeToggle.tsx
+++ b/apps/web/src/components/ThemeToggle.tsx
@@ -1,13 +1,31 @@
import { useState, useEffect } from 'react'
import './ThemeToggle.css'
+export const updateThemeColor = () => {
+ let metas = document.querySelectorAll('meta[name="theme-color"]')
+ if (!metas.length) return
+ const element = document.body
+ const end = Date.now() + 300
+ const update = () => {
+ const { backgroundColor } = getComputedStyle(element)
+ metas.forEach(meta => meta.setAttribute('content', backgroundColor))
+ if (Date.now() < end) requestAnimationFrame(update)
+ }
+ requestAnimationFrame(update)
+}
+
export function ThemeToggle() {
- const [isDark, setIsDark] = useState(
- () => matchMedia('(prefers-color-scheme: dark)').matches,
- )
+ const [isDark, setIsDark] = useState(() => {
+ const storedTheme = localStorage.getItem('theme')
+ if (storedTheme === 'dark') return true
+ if (storedTheme === 'light') return false
+ return matchMedia('(prefers-color-scheme: dark)').matches
+ })
useEffect(() => {
document.documentElement.dataset.theme = isDark ? 'dark' : 'light'
+ updateThemeColor()
+ localStorage.setItem('theme', isDark ? 'dark' : 'light')
}, [isDark])
return (
diff --git a/apps/web/src/config.ts b/apps/web/src/config.ts
index 33efc52..215e829 100644
--- a/apps/web/src/config.ts
+++ b/apps/web/src/config.ts
@@ -1,59 +1,84 @@
import type { Config } from '@remake/hooks'
-import type { TalentGrade } from '@remake/data/talent'
-
-function gadm(grade: TalentGrade, value: number) {
- return new Map([[grade, { mode: 'multiply', value }]])
-}
-
-export const AdditonMap = {
- times: [
- { value: 0, additions: new Map() },
- { value: 10, additions: gadm(2, 2) },
- { value: 30, additions: gadm(2, 3) },
- { value: 50, additions: gadm(2, 4) },
- { value: 70, additions: gadm(2, 5) },
- { value: 100, additions: gadm(2, 6) },
- ],
- achievements: [
- { value: 0, additions: new Map() },
- { value: 10, additions: gadm(3, 2) },
- { value: 30, additions: gadm(3, 3) },
- { value: 50, additions: gadm(3, 4) },
- { value: 70, additions: gadm(3, 5) },
- { value: 100, additions: gadm(3, 6) },
- ],
-}
+export const AutoInterval = 500
+export const ModeLimit = 10
+export const PickLimit = 3
export const BasePoints = 20
+export const AllocLimit = 10
+export const DefaultSpirit = 5
+export const PullCount = 10
+export const PullRateBase: Config['pull']['rate']['base'] = new Map([
+ [0, 889],
+ [1, 100],
+ [2, 10],
+ [3, 1],
+])
+
+export const JudgeMap = {
+ age: [0, 1, 10, 18, 40, 60, 70, 80, 90, 95, 100, 500],
+ summary: [0, 41, 50, 60, 80, 100, 110, 120],
+ times: [0, 10, 30, 50, 70, 100],
+ achievements: [0, 10, 30, 50, 70, 100],
+ charm: [0, 1, 2, 4, 7, 9, 11],
+ money: [0, 1, 2, 4, 7, 9, 11],
+ spirit: [0, 1, 2, 4, 7, 9, 11],
+ intelligence: [0, 1, 2, 4, 7, 9, 11, 21, 131, 501],
+ strength: [0, 1, 2, 4, 7, 9, 11, 21, 101, 401, 1001, 2001],
+ talent: [0, 0.3, 0.6, 0.9],
+ event: [0, 0.2, 0.4, 0.6],
+}
+export type Judges = keyof typeof JudgeMap
+export function judge(key: Judges, value: number) {
+ const arr = JudgeMap[key]
+ for (let i = arr.length - 1; i >= 0; i--) {
+ if (value >= arr[i]!) return i
+ }
+ return 0
+}
+
+export const JudgeGradeMap = {
+ age: [0, 5, 7, 9],
+ summary: [0, 4, 5, 6],
+ times: [0, 1, 3, 5],
+ achievements: [0, 1, 3, 5],
+ charm: [0, 4, 5, 6],
+ money: [0, 4, 5, 6],
+ spirit: [0, 4, 5, 6],
+ intelligence: [0, 4, 5, 6],
+ strength: [0, 4, 5, 6],
+ talent: [0, 1, 2, 3],
+ event: [0, 1, 2, 3],
+}
+export function judgeGrade(key: Judges, level: number) {
+ const arr = JudgeGradeMap[key]
+ for (let i = arr.length - 1; i >= 0; i--) {
+ if (level >= arr[i]!) return i
+ }
+ return 0
+}
+
+export const PullRateAdditions: Config['pull']['rate']['additions'] = {
+ times: value => {
+ const level = judge('times', value)
+ return new Map([[2, { mode: 'multiply', value: level + 1 } as const]])
+ },
+ achievements: value => {
+ const level = judge('achievements', value.size)
+ return new Map([[3, { mode: 'multiply', value: level + 1 } as const]])
+ },
+}
export const config: Config = {
- mode: 10,
- pick: 3,
+ mode: ModeLimit,
+ pick: PickLimit,
points: BasePoints,
- allocate: 10,
- spirit: 5,
+ allocate: AllocLimit,
+ spirit: DefaultSpirit,
pull: {
- count: 10,
+ count: PullCount,
rate: {
- base: new Map([
- [0, 889],
- [1, 100],
- [2, 10],
- [3, 1],
- ]),
- additions: {
- times: value => {
- for (const item of AdditonMap.times.reverse())
- if (value >= item.value) return item.additions
- return new Map()
- },
- achievements: value => {
- const size = value.size
- for (const item of AdditonMap.achievements.reverse())
- if (size >= item.value) return item.additions
- return new Map()
- },
- },
+ base: PullRateBase,
+ additions: PullRateAdditions,
},
},
}
diff --git a/apps/web/src/containers/Alloc.css b/apps/web/src/containers/Alloc.css
index 094dfc5..220d63e 100644
--- a/apps/web/src/containers/Alloc.css
+++ b/apps/web/src/containers/Alloc.css
@@ -8,21 +8,23 @@
.allocation-input {
display: flex;
gap: 0;
+ height: 2rem;
border: 0.0625rem solid var(--base-text-color);
box-sizing: border-box;
width: 100%;
button {
+ flex: 1 0;
padding: 0;
margin: 0;
- width: 2rem;
- height: 2rem;
+ height: 100%;
border: none;
text-align: center;
}
input {
- flex: 1;
- height: 2rem;
+ flex: 1 0;
+ height: 100%;
width: 2rem;
+ font-weight: bold;
}
}
.points-detail {
@@ -42,7 +44,8 @@
li {
display: flex;
justify-content: space-between;
- line-height: 2rem;
+ align-items: center;
+ height: 2rem;
padding: 0 0.5rem;
gap: 0.5rem;
}
@@ -72,9 +75,11 @@
height: 2rem;
border: 0.0625rem solid var(--base-text-color);
border-bottom: none;
- text-align: center;
- line-height: 2rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
box-sizing: border-box;
+ font-weight: bold;
}
}
> li.left {
@@ -87,10 +92,9 @@
> button {
flex: 1;
font-size: 1rem;
- line-height: 2rem;
+ height: 2rem;
width: 6rem;
padding: 0;
- box-sizing: border-box;
}
}
}
diff --git a/apps/web/src/containers/Alloc.tsx b/apps/web/src/containers/Alloc.tsx
index 88cfc01..0e02c63 100644
--- a/apps/web/src/containers/Alloc.tsx
+++ b/apps/web/src/containers/Alloc.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react'
import { useAllocator, usePointRandomizer, useLeftPoints } from '@remake/hooks'
-import { usePicked, useReplaced } from '@remake/hooks'
+import { usePicked, useReplaced, useStart } from '@remake/hooks'
import type { AdditionalPoint } from '@remake/hooks'
import { properties } from '@/display'
import { keys } from '@remake/vitex'
@@ -59,9 +59,12 @@ export function Alloc() {
const left = useLeftPoints()
const [allocation, allocator] = useAllocator()
const random = usePointRandomizer()
+ const start = useStart()
const [showDetail, setShowDetail] = useState(false)
const handleNext = () => {
- // navigate('/life')
+ const achievements = start()
+ // TODO: Show achievements
+ console.log('Achievements', achievements)
}
return (
@@ -97,7 +100,7 @@ export function Alloc() {
-
diff --git a/apps/web/src/containers/Home.css b/apps/web/src/containers/Home.css
index 1d5b552..c4c8340 100644
--- a/apps/web/src/containers/Home.css
+++ b/apps/web/src/containers/Home.css
@@ -8,10 +8,22 @@
h1 {
font-size: 4rem;
margin: 0;
+ font-weight: bold;
}
h2 {
font-size: 2rem;
margin: 0;
}
}
-}
+ .theme-toggle-btn {
+ display: flex;
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 0.25rem;
+ cursor: pointer;
+ align-items: center;
+ justify-content: center;
+ -webkit-tap-highlight-color: transparent;
+ transition: background-color 0.3s;
+ }
+}
\ No newline at end of file
diff --git a/apps/web/src/containers/Home.tsx b/apps/web/src/containers/Home.tsx
index 3aae358..1093dca 100644
--- a/apps/web/src/containers/Home.tsx
+++ b/apps/web/src/containers/Home.tsx
@@ -1,4 +1,5 @@
import { useRemake } from '@remake/hooks'
+import { ThemeToggle } from '@/components/ThemeToggle'
import './Home.css'
export default function Home() {
@@ -12,6 +13,7 @@ export default function Home() {
立即重开
+
)
}
diff --git a/apps/web/src/containers/Play.css b/apps/web/src/containers/Play.css
new file mode 100644
index 0000000..f532056
--- /dev/null
+++ b/apps/web/src/containers/Play.css
@@ -0,0 +1,114 @@
+.screen.play {
+ height: calc(100dvh - 2rem);
+ gap: 1rem;
+ > ul.properties {
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ width: 100%;
+ font-weight: bold;
+ > li {
+ display: flex;
+ flex-direction: column;
+ flex: 1 0;
+ justify-content: space-between;
+ text-align: center;
+ min-width: 6rem;
+ user-select: none;
+ span {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid var(--base-text-color);
+ box-sizing: border-box;
+ height: 2rem;
+ &:first-child {
+ border-bottom: none;
+ }
+ }
+ .value {
+ color: var(--color-primary);
+ font-size: 1.25rem;
+ font-weight: bold;
+ }
+ &.charm { order: 1 }
+ &.intelligence { order: 2 }
+ &.strength { order: 3 }
+ &.money { order: 4 }
+ &.spirit { order: 5 }
+ }
+ }
+ > ul.logs {
+ display: flex;
+ flex-direction: column;
+ flex: 1 0;
+ gap: 0.5rem;
+ padding: 0 0.5rem;
+ min-width: 32rem;
+ max-width: 100%;
+ height: 100%;
+ border: 0.0625rem solid var(--base-text-color);
+ box-sizing: border-box;
+ > li.log {
+ display: flex;
+ flex-direction: row;
+ line-height: 2rem;
+ gap: 0.5rem;
+ width: 100%;
+ user-select: none;
+ cursor: pointer;
+ > .age {
+ flex-shrink: 0;
+ width: 3rem;
+ height: 2rem;
+ text-align: right;
+ color: var(--color-primary);
+ font-weight: bold;
+ /* border-bottom: 0.0625rem solid var(--base-text-color); */
+ box-sizing: border-box;
+ }
+ > .content {
+ position: relative;
+ &::before {
+ content: '';
+ position: absolute;
+ left: -0.5rem;
+ bottom: 0;
+ height: calc(100% - 2rem);
+ width: calc(100% + 0.5rem);
+ border: 0.0625rem solid var(--base-text-color);
+ border-top: none;
+ border-right: none;
+ box-sizing: border-box;
+ pointer-events: none;
+ }
+ .tag, .name {
+ font-weight: bold;
+ }
+ }
+ }
+ >li:last-child {
+ margin-bottom: 2rem;
+ }
+ }
+ ul.log-inner {
+ > li {
+ color: var(--grade-color);
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ }
+ }
+ .controls {
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ width: 100%;
+ > button {
+ flex: 1 0;
+ min-width: 6rem;
+ font-size: 1.25rem;
+ height: 2.5rem;
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/web/src/containers/Play.tsx b/apps/web/src/containers/Play.tsx
index bc1ece9..88a5ee2 100644
--- a/apps/web/src/containers/Play.tsx
+++ b/apps/web/src/containers/Play.tsx
@@ -1,3 +1,151 @@
-export default function Life() {
- return <>>
+import { useState, useRef } from 'react'
+import { useLayoutEffect, useEffect } from 'react'
+import { useNext, useGotoSummary } from '@remake/hooks'
+import type { Log } from '@remake/hooks'
+import { properties } from '@/display'
+import { keys } from '@remake/vitex'
+import { achievements, events, talents } from '@remake/data'
+import { AutoInterval } from '@/config'
+import './Play.css'
+
+function LogTalent({ id }: { id: number }) {
+ const { name, description, grade } = talents.get(id)!
+ return (
+