Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions components/character-sheet-sections/armor-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,27 @@ export function ArmorSection({ onOpenArmorModal }: ArmorSectionProps) {

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target
const hasCustomArmorContent = !!(formData.armorName || formData.armorBaseScore || formData.armorThreshold || formData.armorFeature || value)
const nextSelection = hasCustomArmorContent
? { mode: "custom" as const, id: formData.armorName || undefined }
: { mode: "none" as const }

if (name === 'armorThreshold') {
// 使用新的护甲阈值更新函数,自动计算伤害阈值
setSheetData({ armorSelection: nextSelection })
updateArmorThresholdWithDamage(value)
} else if (name === 'armorBaseScore') {
// 使用新的护甲值更新函数,同步更新属性栏的护甲值
setSheetData({ armorSelection: nextSelection })
updateArmorBaseScore(value)
} else {
setSheetData((prev) => ({ ...prev, [name]: value }))
setSheetData((prev) => ({
...prev,
[name]: value,
armorSelection: (prev.armorName || prev.armorBaseScore || prev.armorThreshold || prev.armorFeature || value)
? { mode: "custom", id: prev.armorName || undefined }
: { mode: "none" },
}))
}
}

Expand All @@ -36,7 +49,11 @@ export function ArmorSection({ onOpenArmorModal }: ArmorSectionProps) {
}

const handleNameChange = (value: string) => {
setSheetData((prev) => ({ ...prev, armorName: value }))
setSheetData((prev) => ({
...prev,
armorName: value,
armorSelection: value ? { mode: "custom", id: value } : { mode: "none" },
}))
}

const handleNameSubmit = () => {
Expand Down
5 changes: 4 additions & 1 deletion components/character-sheet-sections/attributes-section.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client"

import type { SheetData, AttributeValue } from "@/lib/sheet-data"
import { getDisplayedAttributeValue } from "@/lib/preset-equipment"
import { useSheetStore } from "@/lib/sheet-store";

export function AttributesSection() {
Expand Down Expand Up @@ -91,7 +92,9 @@ export function AttributesSection() {
function isAttributeValue(val: unknown): val is AttributeValue {
return val !== undefined && typeof val === "object" && val !== null && "checked" in val && "value" in val;
}
return isAttributeValue(attrValue) ? attrValue.value : "";
return isAttributeValue(attrValue)
? getDisplayedAttributeValue(formData, attr.key as keyof Pick<SheetData, "agility" | "strength" | "finesse" | "instinct" | "presence" | "knowledge">, attrValue.value)
: "";
})()}
onChange={(e) => handleAttributeValueChange(attr.key as keyof SheetData, e.target.value)}
className="w-16 text-center bg-transparent border-b border-gray-400 focus:outline-none text-lg font-bold text-gray-800 print-empty-hide"
Expand Down
98 changes: 69 additions & 29 deletions components/character-sheet-sections/weapon-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,47 @@

import type React from "react"
import { useState } from "react"
import { useSheetStore } from "@/lib/sheet-store"
import { ContentEditableField } from "@/components/ui/content-editable-field"
import { useSheetStore } from "@/lib/sheet-store"

interface WeaponSectionProps {
isPrimary?: boolean
fieldPrefix: string
onOpenWeaponModal: (fieldName: string, slotType: "primary" | "secondary" | "inventory") => void;
onOpenWeaponModal: (fieldName: string, slotType: "primary" | "secondary" | "inventory") => void
}

type WeaponFieldSet =
| {
selection: "primaryWeaponSelection"
name: "primaryWeaponName"
trait: "primaryWeaponTrait"
damage: "primaryWeaponDamage"
feature: "primaryWeaponFeature"
}
| {
selection: "secondaryWeaponSelection"
name: "secondaryWeaponName"
trait: "secondaryWeaponTrait"
damage: "secondaryWeaponDamage"
feature: "secondaryWeaponFeature"
}

function getWeaponFields(fieldPrefix: string): WeaponFieldSet {
return fieldPrefix === "primaryWeapon"
? {
selection: "primaryWeaponSelection",
name: "primaryWeaponName",
trait: "primaryWeaponTrait",
damage: "primaryWeaponDamage",
feature: "primaryWeaponFeature",
}
: {
selection: "secondaryWeaponSelection",
name: "secondaryWeaponName",
trait: "secondaryWeaponTrait",
damage: "secondaryWeaponDamage",
feature: "secondaryWeaponFeature",
}
}

export function WeaponSection({
Expand All @@ -18,40 +52,46 @@ export function WeaponSection({
}: WeaponSectionProps) {
const { sheetData: formData, setSheetData } = useSheetStore()
const [isEditingName, setIsEditingName] = useState(false)
const weaponFields = getWeaponFields(fieldPrefix)

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target
setSheetData((prev) => ({ ...prev, [name]: value }))
}

const openWeaponModal = (fieldName: string, slotType: "primary" | "secondary" | "inventory") => {
onOpenWeaponModal(fieldName, slotType)
}
const currentName = formData[weaponFields.name] || ""
const hasCustomWeaponContent = !!(
currentName ||
formData[weaponFields.trait] ||
formData[weaponFields.damage] ||
formData[weaponFields.feature] ||
value
)

const handleEditName = () => {
setIsEditingName(true)
setSheetData((prev) => ({
...prev,
[name]: value,
[weaponFields.selection]: hasCustomWeaponContent
? { mode: "custom", id: currentName || undefined }
: { mode: "none" },
}))
}

const handleNameChange = (value: string) => {
setSheetData((prev) => ({ ...prev, [nameField]: value }))
setSheetData((prev) => ({
...prev,
[weaponFields.name]: value,
[weaponFields.selection]: value ? { mode: "custom", id: value } : { mode: "none" },
}))
}

const handleNameSubmit = () => {
setIsEditingName(false)
}

const handleNameKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
if (e.key === "Enter") {
handleNameSubmit()
}
}


const nameField = `${fieldPrefix}Name`
const traitField = `${fieldPrefix}Trait`
const damageField = `${fieldPrefix}Damage`
const featureField = `${fieldPrefix}Feature`

return (
<div className="mb-2.5">
<h4 className="font-bold text-[10px] bg-gray-800 text-white p-1 rounded-t-md">
Expand All @@ -63,7 +103,7 @@ export function WeaponSection({
{isEditingName ? (
<input
type="text"
value={(formData as any)[nameField] || ""}
value={formData[weaponFields.name] || ""}
onChange={(e) => handleNameChange(e.target.value)}
onKeyDown={handleNameKeyDown}
onBlur={handleNameSubmit}
Expand All @@ -74,15 +114,15 @@ export function WeaponSection({
<div className="group flex w-full border border-gray-400 rounded h-6 bg-white overflow-hidden">
<button
type="button"
onClick={() => openWeaponModal(nameField, isPrimary ? "primary" : "secondary")}
onClick={() => onOpenWeaponModal(weaponFields.name, isPrimary ? "primary" : "secondary")}
className="flex-1 text-sm text-left px-2 py-0.5 hover:bg-gray-50 focus:outline-none"
>
{(formData as any)[nameField] || <span className="print:hidden">选择武器</span>}
{formData[weaponFields.name] || <span className="print:hidden">选择武器</span>}
</button>
<div className="w-px bg-gray-300 hidden group-hover:block"></div>
<div className="w-px bg-gray-300 hidden group-hover:block" />
<button
type="button"
onClick={handleEditName}
onClick={() => setIsEditingName(true)}
className="w-8 hidden group-hover:flex items-center justify-center hover:bg-gray-50 focus:outline-none print:hidden"
title="编辑名称"
>
Expand All @@ -97,8 +137,8 @@ export function WeaponSection({
<label className="text-[8px] text-gray-600">基本信息</label>
<input
type="text"
name={traitField}
value={(formData as any)[traitField] || ""}
name={weaponFields.trait}
value={formData[weaponFields.trait] || ""}
onChange={handleInputChange}
className="w-full border-b border-gray-400 focus:outline-none print-empty-hide text-sm"
/>
Expand All @@ -107,17 +147,17 @@ export function WeaponSection({
<label className="text-[8px] text-gray-600">伤害骰</label>
<input
type="text"
name={damageField}
value={(formData as any)[damageField] || ""}
name={weaponFields.damage}
value={formData[weaponFields.damage] || ""}
onChange={handleInputChange}
className="w-full border-b border-gray-400 focus:outline-none print-empty-hide text-sm"
/>
</div>
</div>
<div className="mt-1">
<ContentEditableField
name={featureField}
value={(formData as any)[featureField] || ""}
name={weaponFields.feature}
value={formData[weaponFields.feature] || ""}
onChange={handleInputChange}
placeholder=""
maxLines={2}
Expand Down
Loading