update: bili-toy

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent 5c951f4940
commit d3f47dd7e9
17 changed files with 1212 additions and 201 deletions
+2
View File
@@ -7,6 +7,7 @@
"dev": "bunx --bun vite",
"dev:prod": "bunx --bun vite --mode production",
"build": "bunx --bun vite build",
"build:bili": "bunx --bun vite build --config vite.config.bili.ts",
"preview": "bunx --bun vite preview",
"lint": "bunx --bun eslint",
"test": "bunx --bun vitest"
@@ -15,6 +16,7 @@
"@remake/data": "workspace:*",
"@remake/hooks": "workspace:*",
"@remake/vitex": "workspace:*",
"@remake/thirdparty-bili-toy": "workspace:*",
"jotai": "^2.20.2",
"react": "^19.2.8",
"react-dom": "^19.2.8",
+6 -4
View File
@@ -2,7 +2,7 @@ import { useEffect, useCallback, useTransition } from 'react'
import { atom, useAtom } from 'jotai'
import { useConfigInject, useProfileInject, useRawProfile } from '@remake/hooks'
import { useUniqueInject, useUnique } from '@remake/hooks'
import { get, set } from '@/storage'
import { init, get, set } from '@/storage'
import { config } from '@/config'
const initedAtom = atom(false)
@@ -15,7 +15,8 @@ export const useInit = () => {
const loader = useCallback(async () => {
if (inited) return
configInject(config)
const { profile, unique } = await get(['profile', 'unique'])
await init()
const profile = await get('profile')
const parsed = profile ? JSON.parse(profile) || {} : {}
profileInject({
...parsed,
@@ -24,6 +25,7 @@ export const useInit = () => {
events: new Set(parsed.events || []),
talents: new Set(parsed.talents || []),
})
const unique = await get('unique')
if (unique) uniqueInject(JSON.parse(unique))
setInited(true)
}, [inited, configInject, profileInject, uniqueInject, setInited])
@@ -46,14 +48,14 @@ export const useWatcher = () => {
talents: Array.from(profile.talents),
})
saveProfile(async () => {
await set({ profile: str })
await set('profile', str)
})
}, [inited, profile, saveProfile])
useEffect(() => {
if (!inited || !unique) return
const str = JSON.stringify(unique)
saveUnique(async () => {
await set({ unique: str })
await set('unique', str)
})
}, [inited, unique, saveUnique])
+15
View File
@@ -0,0 +1,15 @@
import { test, expect, describe } from 'vitest'
import { talents, achievements, events } from '@remake/data'
describe('Bili Toy Cloud Save Core', () => {
test('maxSizeProfile should pass ToyCloudSaveCore constraints', () => {
const json = JSON.stringify({
times: 999999,
locked: Array.from(talents.keys()),
talents: Array.from(talents.keys()),
achievements: Array.from(achievements.keys()),
events: Array.from(events.keys()),
})
expect(json.length).toBeLessThan((48 * 960 * 3) / 4)
})
})
+23
View File
@@ -0,0 +1,23 @@
import * as biliToy from '@remake/thirdparty-bili-toy'
import * as local from './local'
interface Storage {
init(): Promise<void>
get(key: string): Promise<string | null>
set(key: string, value: string): Promise<boolean>
}
const storage = {} as Storage
if (import.meta.env.VITE_CHANNEL === 'bili') {
storage.init = biliToy.init
storage.get = biliToy.get
storage.set = biliToy.set
} else {
storage.init = async () => {}
storage.get = local.get
storage.set = local.set
}
export const init = storage.init
export const get = storage.get
export const set = storage.set
@@ -28,15 +28,12 @@ if (localStorage.getItem('version') !== '3.0.0') {
}
localStorage.setItem('version', '3.0.0')
}
export async function get<Key extends string>(keys: Key[]) {
return Object.fromEntries(keys.map(k => [k, localStorage.getItem(k)])) as {
[K in Key]: string | null
}
export async function get(key: string) {
return localStorage.getItem(key)
}
export async function set<Key extends string>(data: Record<Key, string>) {
for (const key in data) {
localStorage.setItem(key, data[key])
}
export async function set(key: string, value: string) {
localStorage.setItem(key, value)
return true
}
+9
View File
@@ -115,6 +115,15 @@ input {
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
}
input[type="number"] {
-moz-appearance: textfield;
appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0; /* 移除某些浏览器下的默认留白 */
}
}
@media (max-width: 32rem) { :root { font-size: 2.88vw; } }
@media screen and (orientation: portrait) and (pointer: coarse) {
+33
View File
@@ -0,0 +1,33 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
const dataSplitRule = {
test: /[\\/]packages[\\/]data[\\/]|@remake\/data/,
priority: 40,
name(id: string) {
const name = id.split(/[\/\\]/).pop()!
const baseName = name.substring(0, name.lastIndexOf('.'))
if (baseName && baseName !== 'index') return `data-${baseName}`
return null
},
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: { tsconfigPaths: true },
define: { 'import.meta.env.VITE_CHANNEL': '"bili"' },
base: './',
build: {
outDir: 'dist/bili/remake',
chunkSizeWarningLimit: 1500,
rolldownOptions: {
output: {
codeSplitting: {
minSize: 1024,
groups: [dataSplitRule],
},
},
},
},
})
+1
View File
@@ -16,6 +16,7 @@ const dataSplitRule = {
export default defineConfig({
plugins: [react()],
resolve: { tsconfigPaths: true },
base: './',
build: {
chunkSizeWarningLimit: 1500,
rolldownOptions: {