update: character

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent ad4e83fc47
commit f4204601ee
22 changed files with 495 additions and 101 deletions
-8
View File
@@ -109,14 +109,6 @@
}
}
}
> div {
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
gap: 0.5rem;
button { flex: 1 0; }
}
> ul.talent-list {
display: flex;
flex-direction: column;
+1 -1
View File
@@ -103,7 +103,7 @@ export function Alloc() {
</li>
))}
</ul>
<div>
<div className="controls">
<button className="info" onClick={() => random()}>
</button>
+90 -1
View File
@@ -1 +1,90 @@
.screen.chara {}
.screen.chara {
gap: 1rem;
> .chara-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
> .character {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 0.0625rem solid var(--base-text-color);
box-sizing: border-box;
cursor: pointer;
> .generator > ul > li { text-align: center; }
> .name {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
height: 2rem;
}
&.selected {
border: 0.0625rem solid var(--color-primary);
> .name {
background-color: var(--color-primary);
color: var(--base-background-color);
}
> .chara-details {
height: auto;
padding: 0.5rem;
}
}
}
}
.chara-details {
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
border-top: 0.0625rem solid var(--base-text-color);
box-sizing: border-box;
height: 0;
padding: 0 0.5rem;
overflow-y: hidden;
transition: all 0.3s ease-in-out;
interpolate-size: allow-keywords;
> ul.talent-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
> 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;
color: var(--grade-color);
span {
display: flex;
justify-content: center;
align-items: center;
border: 0.0625rem solid var(--grade-color);
box-sizing: border-box;
height: 2rem;
&:first-child {
border-bottom: none;
}
}
.name {
color: var(--base-background-color);
background-color: var(--grade-color);
}
&.charm { order: 1 }
&.intelligence { order: 2 }
&.strength { order: 3 }
&.money { order: 4 }
}
}
}
}
+120 -1
View File
@@ -1,7 +1,126 @@
import { useCharaPuller, useCharaPicker, convertProps } from '@remake/hooks'
import { useUnique, useUniqueGenerator, useCharaStart } from '@remake/hooks'
import type { BaseChara } from '@remake/hooks'
import { TalentComponent } from '@/components/Talent'
import { judgeGradeByValue } from '@/config'
import { characters } from '@remake/data'
import { properties } from '@/display'
import { keys } from '@remake/vitex'
import './Chara.css'
function Details({ detail }: { detail: BaseChara }) {
const props = convertProps(detail.property)
return (
<div className="chara-details">
<ul className="properties">
{keys(props).map(key => (
<li
key={key}
className={`property ${key} grade-${judgeGradeByValue(key, props[key])}`}
>
<span>{properties[key]}</span>
<span className="font-mono">{props[key]}</span>
</li>
))}
</ul>
<ul className="talent-list">
{detail.talent.map(id => (
<li key={id}>
<TalentComponent id={id} />
</li>
))}
</ul>
</div>
)
}
interface UniqueProps {
selected?: boolean
picker?: () => void
}
function Unique({ selected, picker }: UniqueProps) {
const [unique, generator] = useUniqueGenerator()
return (
<li
className={`character ${selected ? 'selected' : ''}`}
onClick={picker}
>
<span className="name"></span>
{unique && <Details detail={unique} />}
{!unique && (
<div className="chara-details generator">
<ul>
<li>6000</li>
<li> </li>
<li></li>
</ul>
<button
className="primary focus"
onClick={() => generator()}
>
</button>
</div>
)}
</li>
)
}
interface CharacterProps {
id: number
selected?: boolean
picker?: (id: number) => void
}
function Character({ id, selected, picker }: CharacterProps) {
const character = characters.get(id)!
return (
<li
className={`character ${selected ? 'selected' : ''}`}
onClick={() => picker?.(id)}
>
<span className="name">{character.name}</span>
<Details detail={character} />
</li>
)
}
export function Chara() {
return <div className="screen chara"></div>
const u = useUnique()
const [{ unique, characters }, puller] = useCharaPuller()
const [picked, picker] = useCharaPicker()
const start = useCharaStart()
const ready = picked && (picked.type === 'unique' ? !!u : true)
return (
<div className="screen chara">
<ul className="chara-list">
{unique && (
<Unique
selected={picked?.type === 'unique'}
picker={() => picker.unique()}
/>
)}
{characters.map(id => (
<Character
key={id}
id={id}
selected={picked?.id === id}
picker={id => picker.chara(id)}
/>
))}
</ul>
<div className="controls">
<button className="info" onClick={puller}>
</button>
<button
className={ready ? 'primary' : 'error'}
onClick={ready ? () => start(picked!) : undefined}
>
</button>
</div>
</div>
)
}
export default Chara
-9
View File
@@ -1,9 +0,0 @@
export function Loading() {
return (
<div className="screen loading">
<h2>...</h2>
</div>
)
}
export default Loading
+6 -6
View File
@@ -1,4 +1,4 @@
import { useState, useRef } from 'react'
import { useState, useRef, useCallback } from 'react'
import { useLayoutEffect, useEffect } from 'react'
import { useNext, useGotoSummary, type Log } from '@remake/hooks'
import { useJudge } from '@/hooks/judge'
@@ -100,12 +100,12 @@ function Prop({ prop, value, grade }: PropProps) {
useEffect(() => {
const prev = prevRef.current
if (value === prev) return
const startValue = prevRef.current
prevRef.current = value
setTrend(value > prev ? 'up' : 'down')
setFlip(f => (f + 1) % 2)
let startTimestamp: number | null = null
const duration = 400
const startValue = displayValue
let end = false
const step = (timestamp: number) => {
if (!startTimestamp) startTimestamp = timestamp
@@ -150,18 +150,18 @@ export function Play() {
const logRef = useRef<HTMLUListElement>(null)
const autoRef = useRef(0)
const gotoSummary = useGotoSummary()
const handleNext = () => {
const handleNext = useCallback(() => {
if (ended) return
const achievements = next()
// TODO: Show achievements
console.debug('Achievements:', achievements)
}
const handleGotoSummary = () => {
}, [ended, next])
const handleGotoSummary = useCallback(() => {
if (!ended) return
const achievements = gotoSummary()
// TODO: Show achievements
console.debug('Achievements:', achievements)
}
}, [ended, gotoSummary])
useLayoutEffect(() => {
requestAnimationFrame(() => {
if (!logRef.current) return
+1 -1
View File
@@ -38,7 +38,7 @@ function TalentList({ picked, picker }: TalentListProps) {
}
hasInitialized.current = true
}
}, [picked, picker])
}, [profile.locked, talents, picked, picker])
return (
<ul className="talent-list">