update: hooks, web

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent 2f91709d1e
commit 322f775796
67 changed files with 2339 additions and 2243 deletions
+50
View File
@@ -0,0 +1,50 @@
ul.replaced {
display: flex;
flex-direction: column;
gap: 0.5rem;
li {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
padding: 0;
.talent {
width: 100%;
}
}
li:not(:first-child) {
position: relative;
&::before {
content: '';
position: absolute;
display: block;
box-sizing: border-box;
border: 0.0625rem solid var(--base-text-color);
border-left: none;
right: 0;
top: -1rem;
margin-right: -1rem;
width: 0.625rem;
height: 1.5rem;
}
&::after {
content: '';
position: absolute;
display: block;
box-sizing: border-box;
border: 0.0625rem solid var(--base-text-color);
border-right: none;
border-bottom: none;
right: 0;
top: 0.5rem;
margin-right: -0.6875rem;
margin-top: -0.03125rem;
width: 0.375rem;
height: 0.375rem;
transform: rotate(-45deg);
transform-origin: 0 0;
}
}
}
+29
View File
@@ -0,0 +1,29 @@
import type { Talent } from '@remake/data/talent'
import TalentComponent from './Talent'
import talents from '@remake/data/talent'
import './Replaced.css'
export interface TalentProps {
id: Talent['id']
chains?: Talent['id'][]
}
export function Replaced({ id, chains }: TalentProps) {
return (
<ul className="replaced">
<li>
<TalentComponent id={id} selected={true} />
</li>
{chains?.map(id => {
const talent = talents.get(id)
if (!talent) return null
return (
<li key={id}>
<TalentComponent id={id} selected={false} />
</li>
)
})}
</ul>
)
}
export default Replaced
+41
View File
@@ -0,0 +1,41 @@
.talent {
--color: var(--grade-color);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 1rem;
line-height: 2rem;
gap: 1rem;
color: var(--color);
background: var(--background, var(--base-background-color));
cursor: pointer;
user-select: none;
border: 0.0625rem solid var(--grade-color);
transition: all 0.2s ease-in-out;
&.talent-grade-0 { --grade-color: var(--color-grade-0); }
&.talent-grade-1 { --grade-color: var(--color-grade-1); }
&.talent-grade-2 { --grade-color: var(--color-grade-2); }
&.talent-grade-3 { --grade-color: var(--color-grade-3); }
&.selected {
--color: var(--base-background-color);
--background: var(--grade-color);
&:hover { --background: oklch(from var(--grade-color) calc(l + 0.1) c h); }
}
&:hover { --background: oklch(from var(--grade-color) calc(l + 0.5) c h); }
.talent-description {
color: oklch(from var(--color) calc(l + 0.1) c h);
font-size: 0.6rem;
align-self: flex-end;
user-select: none;
&::before { content: '['; margin-right: 0.125rem; }
&::after { content: ']'; margin-left: 0.125rem; }
&::before, &::after { color: var(--color); }
}
}
html[data-theme='dark'] {
.talent{
&:hover {--background: oklch(from var(--grade-color) calc(l - 0.5) c h);}
&.selected:hover { --background: oklch(from var(--grade-color) calc(l - 0.1) c h);}
.talent-description { color: oklch(from var(--color) calc(l - 0.2) c h); }
}
}
+22
View File
@@ -0,0 +1,22 @@
import type { Talent } from '@remake/data/talent'
import talents from '@remake/data/talent'
import cx from 'classnames'
import './Talent.css'
export interface TalentProps {
id: Talent['id']
selected: boolean
}
export function TalentComponent({ id, selected }: TalentProps) {
const talent = talents.get(id)
if (!talent) return null
const grade = talent?.grade ?? 0
return (
<div className={cx('talent', `talent-grade-${grade}`, { selected })}>
<span className="talent-name">{talent.name}</span>
<span className="talent-description">{talent.description}</span>
</div>
)
}
export default TalentComponent
+46
View File
@@ -0,0 +1,46 @@
.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 {
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: center;
.sun-center, .sun-beams, .mask-cutter-group {
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1);
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); }
}
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;
}
}
+66
View File
@@ -0,0 +1,66 @@
import { useState, useEffect } from 'react'
import './ThemeToggle.css'
export function ThemeToggle() {
const [isDark, setIsDark] = useState(
() => matchMedia('(prefers-color-scheme: dark)').matches,
)
useEffect(() => {
document.documentElement.dataset.theme = isDark ? 'dark' : 'light'
}, [isDark])
return (
<button
className="theme-toggle-btn"
onClick={() => setIsDark(!isDark)}
aria-label="Toggle theme"
>
<svg
className="theme-svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<defs>
<mask id="ios-fail-proof-mask">
<rect
x="0"
y="0"
width="24"
height="24"
fill="#ffffff"
/>
<g className="mask-cutter-group">
<circle cx="18" cy="5" r="7" fill="#000000" />
</g>
</mask>
</defs>
<circle
className="sun-center"
cx="12"
cy="12"
r="5"
mask="url(#ios-fail-proof-mask)"
/>
<g className="sun-beams">
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</g>
</svg>
</button>
)
}
export default ThemeToggle