Sync source to CNB / Sync Git ref (push) Canceled after 0s
从 Axolotl 1.9.7 移植皮肤编辑器的盔甲/盔甲纹饰预览功能, 让玩家在皮肤选择页可试穿盔甲并调整纹饰。 新增: - 前端组件 ArmorTrimTab / SkinListSkeleton 及 skin-armor-preview helper - packages/ui 组件 ArmorPreviewControls / ArmorTrimPanel - packages/ui armor 预览 composable(armor-preview-assets/types、use-armor-preview) - packages/ui webgl 盔甲渲染(armor-geometry / armor-preview-object / armor-rendering) - packages/ui/src/assets/minecraft-armor 盔甲素材 改动: - SkinPreviewRenderer 增加 armorPreview/armorControls props、 armorConfig model 与 useArmorPreview 集成 - Skins.vue 增加盔甲 tab、状态逻辑与模板接入 - 补齐 skin/composables/utils 的导出 适配说明:ArmorPreviewControls 原版依赖 reka-ui 的 popover, Starlight 无该依赖且只用 external 模式,故改写为 external-only, 去除 reka-ui 与 overlays.css 依赖。
48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
import {
|
|
ARMOR_SLOTS,
|
|
ARMOR_TRIM_MATERIALS,
|
|
ARMOR_TRIM_PATTERNS,
|
|
armorMaterialsForSlot,
|
|
type ArmorPreviewConfig,
|
|
createDefaultArmorPreviewConfig,
|
|
} from '@modrinth/ui'
|
|
|
|
const STORAGE_KEY = 'axolotl:skin-armor-preview'
|
|
|
|
function includes<T extends string>(values: readonly T[], value: unknown): value is T {
|
|
return typeof value === 'string' && values.some((item) => item === value)
|
|
}
|
|
|
|
export function loadSkinArmorPreview(): ArmorPreviewConfig {
|
|
const config = createDefaultArmorPreviewConfig()
|
|
try {
|
|
const saved = JSON.parse(globalThis.localStorage?.getItem(STORAGE_KEY) ?? 'null')
|
|
if (!saved || typeof saved !== 'object' || Array.isArray(saved)) return config
|
|
|
|
for (const slot of ARMOR_SLOTS) {
|
|
const piece = saved[slot]
|
|
if (!piece || typeof piece !== 'object' || Array.isArray(piece)) continue
|
|
if (piece.material === null || includes(armorMaterialsForSlot(slot), piece.material)) {
|
|
config[slot].material = piece.material
|
|
}
|
|
if (piece.trimPattern === null || includes(ARMOR_TRIM_PATTERNS, piece.trimPattern)) {
|
|
config[slot].trimPattern = piece.trimPattern
|
|
}
|
|
if (includes(ARMOR_TRIM_MATERIALS, piece.trimMaterial)) {
|
|
config[slot].trimMaterial = piece.trimMaterial
|
|
}
|
|
}
|
|
} catch {
|
|
// Invalid or unavailable local storage falls back to a fresh preview.
|
|
}
|
|
return config
|
|
}
|
|
|
|
export function saveSkinArmorPreview(config: ArmorPreviewConfig): void {
|
|
try {
|
|
globalThis.localStorage?.setItem(STORAGE_KEY, JSON.stringify(config))
|
|
} catch {
|
|
// The preview remains usable when local storage is unavailable.
|
|
}
|
|
}
|