auto-redistribute skill levels when artifact level changes
This commit is contained in:
parent
f34f2c4dc9
commit
f55303039c
3 changed files with 272 additions and 119 deletions
|
|
@ -4,20 +4,19 @@
|
|||
import type {
|
||||
ArtifactInstance,
|
||||
ArtifactSkillInstance,
|
||||
ArtifactSkill,
|
||||
ArtifactGrade
|
||||
ArtifactSkill
|
||||
} from '$lib/types/api/artifact'
|
||||
import { isQuirkArtifact, getSkillGroupForSlot } from '$lib/types/api/artifact'
|
||||
import { createQuery } from '@tanstack/svelte-query'
|
||||
import { artifactQueries } from '$lib/api/queries/artifact.queries'
|
||||
import { usePaneStack, type PaneConfig, type ElementType } from '$lib/stores/paneStack.svelte'
|
||||
import { usePaneStack, type PaneConfig } from '$lib/stores/paneStack.svelte'
|
||||
import DetailsSection from '$lib/components/sidebar/details/DetailsSection.svelte'
|
||||
import DetailRow from '$lib/components/sidebar/details/DetailRow.svelte'
|
||||
import Select from '$lib/components/ui/Select.svelte'
|
||||
import Slider from '$lib/components/ui/Slider.svelte'
|
||||
import Input from '$lib/components/ui/Input.svelte'
|
||||
import ArtifactSkillRow from './ArtifactSkillRow.svelte'
|
||||
import ArtifactModifierList from './ArtifactModifierList.svelte'
|
||||
import ArtifactGradeDisplay from './ArtifactGradeDisplay.svelte'
|
||||
import ProficiencyLabel from '$lib/components/labels/ProficiencyLabel.svelte'
|
||||
|
||||
interface Props {
|
||||
/** The artifact instance being edited */
|
||||
|
|
@ -34,10 +33,63 @@
|
|||
const paneStack = usePaneStack()
|
||||
|
||||
// Local state for edits
|
||||
// Use type assertion since this pane is used with CollectionArtifact which has nickname
|
||||
let nickname = $state((artifact as { nickname?: string }).nickname ?? '')
|
||||
let element = $state(artifact.element)
|
||||
let level = $state(artifact.level)
|
||||
let proficiency = $state(artifact.proficiency)
|
||||
let skills = $state<(ArtifactSkillInstance | null)[]>([...artifact.skills])
|
||||
let skills = $state<(ArtifactSkillInstance | null)[]>(initializeSkillLevels([...artifact.skills]))
|
||||
|
||||
// Initialize skill levels to meet the constraint (artifact.level + 3)
|
||||
// This handles cases where imported data has incorrect skill levels
|
||||
function initializeSkillLevels(
|
||||
inputSkills: (ArtifactSkillInstance | null)[]
|
||||
): (ArtifactSkillInstance | null)[] {
|
||||
// Skip for quirk artifacts
|
||||
if (artifact.artifact?.rarity === 'quirk') return inputSkills
|
||||
|
||||
const targetSum = artifact.level + 3
|
||||
const currentSum = inputSkills.reduce((sum, s) => sum + (s?.level ?? 0), 0)
|
||||
const diff = targetSum - currentSum
|
||||
|
||||
if (diff === 0) return inputSkills
|
||||
|
||||
// Need to adjust skill levels
|
||||
const adjusted = [...inputSkills]
|
||||
|
||||
if (diff > 0) {
|
||||
// Need to add points
|
||||
let remaining = diff
|
||||
for (let i = 0; i < 4 && remaining > 0; i++) {
|
||||
const skill = adjusted[i]
|
||||
if (skill) {
|
||||
const canAdd = Math.min(5 - skill.level, remaining)
|
||||
if (canAdd > 0) {
|
||||
adjusted[i] = { ...skill, level: skill.level + canAdd }
|
||||
remaining -= canAdd
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Need to remove points
|
||||
let remaining = Math.abs(diff)
|
||||
const indices = [0, 1, 2, 3]
|
||||
.filter((i) => adjusted[i] !== null)
|
||||
.sort((a, b) => (adjusted[b]?.level ?? 0) - (adjusted[a]?.level ?? 0))
|
||||
|
||||
for (const i of indices) {
|
||||
if (remaining <= 0) break
|
||||
const skill = adjusted[i]
|
||||
if (skill && skill.level > 1) {
|
||||
const canRemove = Math.min(skill.level - 1, remaining)
|
||||
adjusted[i] = { ...skill, level: skill.level - canRemove }
|
||||
remaining -= canRemove
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return adjusted
|
||||
}
|
||||
|
||||
// Derived values
|
||||
const artifactData = $derived(artifact.artifact)
|
||||
|
|
@ -66,6 +118,7 @@
|
|||
]
|
||||
|
||||
// Convert numeric element to ElementType string
|
||||
type ElementType = 'wind' | 'fire' | 'water' | 'earth' | 'dark' | 'light'
|
||||
const elementTypeMap: Record<number, ElementType> = {
|
||||
1: 'wind',
|
||||
2: 'fire',
|
||||
|
|
@ -74,7 +127,7 @@
|
|||
5: 'dark',
|
||||
6: 'light'
|
||||
}
|
||||
const elementType = $derived(elementTypeMap[element] ?? undefined)
|
||||
const elementType = $derived(elementTypeMap[element])
|
||||
|
||||
// Level options (1-5 for standard, fixed at 1 for quirk)
|
||||
const levelOptions = $derived(
|
||||
|
|
@ -103,13 +156,6 @@
|
|||
{ value: 10, label: 'Katana' }
|
||||
]
|
||||
|
||||
// Get proficiency display name
|
||||
function getProficiencyName(profValue: number | null | undefined): string {
|
||||
if (!profValue) return '—'
|
||||
const option = proficiencyOptions.find((o) => o.value === profValue)
|
||||
return option?.label ?? '—'
|
||||
}
|
||||
|
||||
// Push modifier selection pane for a specific slot
|
||||
function handleSelectModifier(slot: number) {
|
||||
const config: PaneConfig = {
|
||||
|
|
@ -119,6 +165,7 @@
|
|||
props: {
|
||||
slot,
|
||||
selectedModifier: skills[slot - 1]?.modifier,
|
||||
element: elementType,
|
||||
onSelect: (skill: ArtifactSkill) => handleModifierSelected(slot, skill)
|
||||
}
|
||||
}
|
||||
|
|
@ -139,10 +186,10 @@
|
|||
}
|
||||
|
||||
skills = newSkills
|
||||
notifyUpdate()
|
||||
|
||||
// Pop back to the edit pane
|
||||
// Pop back to the edit pane BEFORE notifying, so the header update targets the right pane
|
||||
paneStack.pop()
|
||||
notifyUpdate()
|
||||
}
|
||||
|
||||
// Handle skill updates from skill row
|
||||
|
|
@ -164,13 +211,64 @@
|
|||
notifyUpdate()
|
||||
}
|
||||
|
||||
// Handle level change
|
||||
// Handle level change - redistributes skill levels to maintain constraint
|
||||
function handleLevelChange(newLevel: number | undefined) {
|
||||
if (newLevel === undefined) return
|
||||
|
||||
const oldBudget = level + 3
|
||||
const newBudget = newLevel + 3
|
||||
const budgetDiff = newBudget - oldBudget
|
||||
|
||||
level = newLevel
|
||||
|
||||
// If budget increased, distribute extra points to skills
|
||||
// If budget decreased, remove points from skills (starting from highest)
|
||||
if (budgetDiff !== 0 && !isQuirk) {
|
||||
redistributeSkillLevels(budgetDiff)
|
||||
}
|
||||
|
||||
notifyUpdate()
|
||||
}
|
||||
|
||||
// Redistribute skill levels when artifact level changes
|
||||
function redistributeSkillLevels(budgetDiff: number) {
|
||||
const newSkills = [...skills]
|
||||
let remaining = budgetDiff
|
||||
|
||||
if (remaining > 0) {
|
||||
// Add points: distribute to skills that can accept more (max 5)
|
||||
for (let i = 0; i < 4 && remaining > 0; i++) {
|
||||
const skill = newSkills[i]
|
||||
if (skill) {
|
||||
const canAdd = Math.min(5 - skill.level, remaining)
|
||||
if (canAdd > 0) {
|
||||
newSkills[i] = { ...skill, level: skill.level + canAdd }
|
||||
remaining -= canAdd
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove points: take from skills with highest levels first
|
||||
remaining = Math.abs(remaining)
|
||||
// Sort indices by skill level descending
|
||||
const indices = [0, 1, 2, 3]
|
||||
.filter((i) => newSkills[i] !== null)
|
||||
.sort((a, b) => (newSkills[b]?.level ?? 0) - (newSkills[a]?.level ?? 0))
|
||||
|
||||
for (const i of indices) {
|
||||
if (remaining <= 0) break
|
||||
const skill = newSkills[i]
|
||||
if (skill && skill.level > 1) {
|
||||
const canRemove = Math.min(skill.level - 1, remaining)
|
||||
newSkills[i] = { ...skill, level: skill.level - canRemove }
|
||||
remaining -= canRemove
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skills = newSkills
|
||||
}
|
||||
|
||||
// Handle proficiency change
|
||||
function handleProficiencyChange(newProficiency: number | undefined) {
|
||||
if (newProficiency === undefined) return
|
||||
|
|
@ -178,11 +276,19 @@
|
|||
notifyUpdate()
|
||||
}
|
||||
|
||||
// Handle nickname change
|
||||
function handleNicknameChange(event: Event) {
|
||||
const target = event.target as HTMLInputElement
|
||||
nickname = target.value
|
||||
notifyUpdate()
|
||||
}
|
||||
|
||||
// Notify parent of updates
|
||||
function notifyUpdate() {
|
||||
if (!onUpdate) return
|
||||
|
||||
const updates: Partial<ArtifactInstance> = {
|
||||
nickname: nickname.trim() || undefined,
|
||||
element,
|
||||
level,
|
||||
skills: [...skills]
|
||||
|
|
@ -194,17 +300,28 @@
|
|||
|
||||
onUpdate(updates)
|
||||
}
|
||||
|
||||
// Current grade (from artifact or could be recalculated)
|
||||
const currentGrade: ArtifactGrade = $derived(artifact.grade)
|
||||
</script>
|
||||
|
||||
<div class="artifact-edit-pane">
|
||||
<DetailsSection title="Base Properties">
|
||||
<DetailsSection title="Basic Info">
|
||||
<DetailRow label="Nickname" noHover>
|
||||
{#if disabled}
|
||||
<span>{nickname || '—'}</span>
|
||||
{:else}
|
||||
<Input
|
||||
class="nickname-input"
|
||||
value={nickname}
|
||||
oninput={handleNicknameChange}
|
||||
placeholder="Optional nickname"
|
||||
maxLength={50}
|
||||
contained
|
||||
/>
|
||||
{/if}
|
||||
</DetailRow>
|
||||
{#if canChangeProficiency}
|
||||
<DetailRow label="Proficiency" noHover>
|
||||
{#if disabled}
|
||||
<span>{getProficiencyName(proficiency)}</span>
|
||||
<ProficiencyLabel {proficiency} size="medium" />
|
||||
{:else}
|
||||
<Select
|
||||
options={proficiencyOptions}
|
||||
|
|
@ -218,7 +335,9 @@
|
|||
{/if}
|
||||
</DetailRow>
|
||||
{:else}
|
||||
<DetailRow label="Proficiency" value={getProficiencyName(artifactData.proficiency)} />
|
||||
<DetailRow label="Proficiency" noHover>
|
||||
<ProficiencyLabel proficiency={artifactData.proficiency} size="medium" />
|
||||
</DetailRow>
|
||||
{/if}
|
||||
|
||||
<DetailRow label="Element" noHover>
|
||||
|
|
@ -244,18 +363,13 @@
|
|||
{#if disabled || isQuirk}
|
||||
<span>{level}</span>
|
||||
{:else}
|
||||
<div class="level-slider">
|
||||
<Slider
|
||||
value={level}
|
||||
onValueChange={handleLevelChange}
|
||||
min={1}
|
||||
max={5}
|
||||
step={1}
|
||||
element={elementType}
|
||||
{disabled}
|
||||
/>
|
||||
<span class="level-value">{level}</span>
|
||||
</div>
|
||||
<Select
|
||||
options={levelOptions}
|
||||
value={level}
|
||||
onValueChange={handleLevelChange}
|
||||
contained
|
||||
{disabled}
|
||||
/>
|
||||
{/if}
|
||||
</DetailRow>
|
||||
</DetailsSection>
|
||||
|
|
@ -267,6 +381,8 @@
|
|||
<ArtifactSkillRow
|
||||
{slot}
|
||||
skill={skills[slot - 1] ?? null}
|
||||
allSkills={skills}
|
||||
artifactLevel={level}
|
||||
availableSkills={getSkillsForSlot(slot)}
|
||||
onSelectModifier={() => handleSelectModifier(slot)}
|
||||
onUpdateSkill={(update) => handleUpdateSkill(slot, update)}
|
||||
|
|
@ -276,12 +392,6 @@
|
|||
</div>
|
||||
</DetailsSection>
|
||||
{/if}
|
||||
|
||||
<DetailsSection title="Grade">
|
||||
<div class="grade-section">
|
||||
<ArtifactGradeDisplay grade={currentGrade} />
|
||||
</div>
|
||||
</DetailsSection>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -298,7 +408,15 @@
|
|||
}
|
||||
|
||||
:global(.artifact-edit-pane .select.medium) {
|
||||
min-width: 120px;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
:global(.nickname-input) {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
:global(.nickname-input input) {
|
||||
padding: spacing.$unit spacing.$unit-4x spacing.$unit calc(spacing.$unit * 1.5) !important;
|
||||
}
|
||||
|
||||
.element-display {
|
||||
|
|
@ -314,28 +432,9 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.level-slider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: spacing.$unit;
|
||||
flex: 1;
|
||||
|
||||
.level-value {
|
||||
font-size: typography.$font-regular;
|
||||
font-weight: typography.$medium;
|
||||
min-width: spacing.$unit-2x;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.skills-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: spacing.$unit;
|
||||
padding: 0 spacing.$unit;
|
||||
}
|
||||
|
||||
.grade-section {
|
||||
padding: spacing.$unit;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
interface Props {
|
||||
artifact: CollectionArtifact
|
||||
/** Called when artifact is saved, with the updated artifact data */
|
||||
onSaved?: (updatedArtifact: CollectionArtifact) => void
|
||||
}
|
||||
|
||||
let { artifact }: Props = $props()
|
||||
let { artifact, onSaved }: Props = $props()
|
||||
|
||||
const paneStack = usePaneStack()
|
||||
|
||||
|
|
@ -49,20 +51,40 @@
|
|||
function handleSave() {
|
||||
if (!pendingUpdates) return
|
||||
|
||||
const input = {
|
||||
nickname: pendingUpdates.nickname,
|
||||
element: pendingUpdates.element,
|
||||
level: pendingUpdates.level,
|
||||
proficiency: pendingUpdates.proficiency,
|
||||
skill1: pendingUpdates.skills?.[0] ?? undefined,
|
||||
skill2: pendingUpdates.skills?.[1] ?? undefined,
|
||||
skill3: pendingUpdates.skills?.[2] ?? undefined,
|
||||
skill4: pendingUpdates.skills?.[3] ?? undefined
|
||||
}
|
||||
|
||||
// Debug: Log what we're sending
|
||||
const skillLevelSum = [input.skill1, input.skill2, input.skill3, input.skill4]
|
||||
.filter(Boolean)
|
||||
.reduce((sum, s) => sum + (s?.level ?? 0), 0)
|
||||
const expectedSum = (input.level ?? artifact.level) + 3
|
||||
console.log('[CollectionArtifactEditPane] Saving artifact:', {
|
||||
id: artifact.id,
|
||||
input,
|
||||
skillLevelSum,
|
||||
expectedSum,
|
||||
constraintMet: skillLevelSum === expectedSum
|
||||
})
|
||||
|
||||
updateMutation.mutate({
|
||||
id: artifact.id,
|
||||
input: {
|
||||
element: pendingUpdates.element,
|
||||
level: pendingUpdates.level,
|
||||
proficiency: pendingUpdates.proficiency,
|
||||
skill1: pendingUpdates.skills?.[0] ?? undefined,
|
||||
skill2: pendingUpdates.skills?.[1] ?? undefined,
|
||||
skill3: pendingUpdates.skills?.[2] ?? undefined,
|
||||
skill4: pendingUpdates.skills?.[3] ?? undefined
|
||||
}
|
||||
input
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
onSuccess: (updatedArtifact) => {
|
||||
onSaved?.(updatedArtifact)
|
||||
paneStack.pop()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('[CollectionArtifactEditPane] Save failed:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -78,9 +100,9 @@
|
|||
return () => sidebar.clearAction()
|
||||
})
|
||||
|
||||
// Reactively update header when state changes
|
||||
// Reactively update header when state changes or when returning from sub-pane
|
||||
$effect(() => {
|
||||
const _ = [hasChanges, updateMutation.isPending]
|
||||
const _ = [hasChanges, updateMutation.isPending, paneStack.panes.length]
|
||||
untrack(() => updateHeader())
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,12 @@
|
|||
* 5. Configure skills (for standard artifacts only, uses pane stack)
|
||||
*/
|
||||
import { onMount, untrack } from 'svelte'
|
||||
import type { Artifact, ArtifactSkill, ArtifactSkillInstance, CollectionArtifactInput } from '$lib/types/api/artifact'
|
||||
import type {
|
||||
Artifact,
|
||||
ArtifactSkill,
|
||||
ArtifactSkillInstance,
|
||||
CollectionArtifactInput
|
||||
} from '$lib/types/api/artifact'
|
||||
import { isQuirkArtifact, getSkillGroupForSlot } from '$lib/types/api/artifact'
|
||||
import { createQuery } from '@tanstack/svelte-query'
|
||||
import { artifactQueries } from '$lib/api/queries/artifact.queries'
|
||||
|
|
@ -22,7 +27,6 @@
|
|||
import DetailsSection from '$lib/components/sidebar/details/DetailsSection.svelte'
|
||||
import DetailRow from '$lib/components/sidebar/details/DetailRow.svelte'
|
||||
import Select from '$lib/components/ui/Select.svelte'
|
||||
import Slider from '$lib/components/ui/Slider.svelte'
|
||||
import Input from '$lib/components/ui/Input.svelte'
|
||||
import ArtifactSkillRow from '$lib/components/artifact/ArtifactSkillRow.svelte'
|
||||
import ArtifactModifierList from '$lib/components/artifact/ArtifactModifierList.svelte'
|
||||
|
|
@ -63,7 +67,7 @@
|
|||
3: '#5cb7ec', // Water - blue
|
||||
4: '#ec985c', // Earth - orange/brown
|
||||
5: '#c65cec', // Dark - purple
|
||||
6: '#c59c0c' // Light - gold/yellow
|
||||
6: '#c59c0c' // Light - gold/yellow
|
||||
}
|
||||
|
||||
// Proficiency options - matches database enum values
|
||||
|
|
@ -94,7 +98,7 @@
|
|||
// Standard artifacts have a fixed proficiency, quirk artifacts match any proficiency
|
||||
const filteredArtifacts = $derived.by(() => {
|
||||
if (!artifactsQuery.data || proficiency === undefined) return []
|
||||
return artifactsQuery.data.filter(a => {
|
||||
return artifactsQuery.data.filter((a) => {
|
||||
// Quirk artifacts have null proficiency - they work with any proficiency
|
||||
if (a.proficiency === null) return true
|
||||
// Standard artifacts match their fixed proficiency
|
||||
|
|
@ -104,16 +108,14 @@
|
|||
|
||||
// Build artifact options for dropdown (filtered by proficiency)
|
||||
const artifactOptions = $derived.by(() => {
|
||||
return filteredArtifacts.map(a => ({
|
||||
return filteredArtifacts.map((a) => ({
|
||||
value: a.id,
|
||||
label: typeof a.name === 'string' ? a.name : (a.name.en || a.name.ja || '—')
|
||||
label: typeof a.name === 'string' ? a.name : a.name.en || a.name.ja || '—'
|
||||
}))
|
||||
})
|
||||
|
||||
// Selected artifact data
|
||||
const selectedArtifact = $derived(
|
||||
artifactsQuery.data?.find(a => a.id === selectedArtifactId)
|
||||
)
|
||||
const selectedArtifact = $derived(artifactsQuery.data?.find((a) => a.id === selectedArtifactId))
|
||||
const isQuirk = $derived(selectedArtifact ? isQuirkArtifact(selectedArtifact) : false)
|
||||
|
||||
// Level options (1-5 for standard, fixed at 1 for quirk)
|
||||
|
|
@ -145,6 +147,7 @@
|
|||
props: {
|
||||
slot,
|
||||
selectedModifier: skills[slot - 1]?.modifier,
|
||||
element: elementType,
|
||||
onSelect: (skill: ArtifactSkill) => handleModifierSelected(slot, skill)
|
||||
}
|
||||
}
|
||||
|
|
@ -195,17 +198,69 @@
|
|||
// Reset skills when artifact changes
|
||||
skills = [null, null, null, null]
|
||||
// Reset level for quirk
|
||||
const artifact = artifactsQuery.data?.find(a => a.id === newArtifactId)
|
||||
const artifact = artifactsQuery.data?.find((a) => a.id === newArtifactId)
|
||||
if (artifact && isQuirkArtifact(artifact)) {
|
||||
level = 1
|
||||
}
|
||||
}
|
||||
|
||||
// Handle level change - redistributes skill levels to maintain constraint
|
||||
function handleLevelChange(newLevel: number | undefined) {
|
||||
if (newLevel === undefined) return
|
||||
|
||||
const oldBudget = level + 3
|
||||
const newBudget = newLevel + 3
|
||||
const budgetDiff = newBudget - oldBudget
|
||||
|
||||
level = newLevel
|
||||
|
||||
// If budget changed and we have skills, redistribute levels
|
||||
if (budgetDiff !== 0 && !isQuirk) {
|
||||
redistributeSkillLevels(budgetDiff)
|
||||
}
|
||||
}
|
||||
|
||||
// Redistribute skill levels when artifact level changes
|
||||
function redistributeSkillLevels(budgetDiff: number) {
|
||||
const newSkills = [...skills]
|
||||
let remaining = budgetDiff
|
||||
|
||||
if (remaining > 0) {
|
||||
// Add points: distribute to skills that can accept more (max 5)
|
||||
for (let i = 0; i < 4 && remaining > 0; i++) {
|
||||
const skill = newSkills[i]
|
||||
if (skill) {
|
||||
const canAdd = Math.min(5 - skill.level, remaining)
|
||||
if (canAdd > 0) {
|
||||
newSkills[i] = { ...skill, level: skill.level + canAdd }
|
||||
remaining -= canAdd
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove points: take from skills with highest levels first
|
||||
remaining = Math.abs(remaining)
|
||||
const indices = [0, 1, 2, 3]
|
||||
.filter((i) => newSkills[i] !== null)
|
||||
.sort((a, b) => (newSkills[b]?.level ?? 0) - (newSkills[a]?.level ?? 0))
|
||||
|
||||
for (const i of indices) {
|
||||
if (remaining <= 0) break
|
||||
const skill = newSkills[i]
|
||||
if (skill && skill.level > 1) {
|
||||
const canRemove = Math.min(skill.level - 1, remaining)
|
||||
newSkills[i] = { ...skill, level: skill.level - canRemove }
|
||||
remaining -= canRemove
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skills = newSkills
|
||||
}
|
||||
|
||||
// Validate form
|
||||
const isValid = $derived(
|
||||
proficiency !== undefined &&
|
||||
element !== undefined &&
|
||||
selectedArtifactId !== undefined
|
||||
proficiency !== undefined && element !== undefined && selectedArtifactId !== undefined
|
||||
)
|
||||
|
||||
// Convert numeric element to ElementType string for button styling
|
||||
|
|
@ -324,26 +379,17 @@
|
|||
{#if isQuirk}
|
||||
<span>1</span>
|
||||
{:else}
|
||||
<div class="level-slider">
|
||||
<Slider
|
||||
value={level}
|
||||
onValueChange={(v) => (level = v)}
|
||||
min={1}
|
||||
max={5}
|
||||
step={1}
|
||||
element={elementType}
|
||||
/>
|
||||
<span class="level-value">{level}</span>
|
||||
</div>
|
||||
<Select
|
||||
options={levelOptions}
|
||||
value={level}
|
||||
onValueChange={handleLevelChange}
|
||||
contained
|
||||
/>
|
||||
{/if}
|
||||
</DetailRow>
|
||||
|
||||
<DetailRow label="Nickname" noHover>
|
||||
<Input
|
||||
bind:value={nickname}
|
||||
placeholder="Optional nickname"
|
||||
maxLength={50}
|
||||
/>
|
||||
<Input bind:value={nickname} placeholder="Optional nickname" maxLength={50} />
|
||||
</DetailRow>
|
||||
</DetailsSection>
|
||||
|
||||
|
|
@ -354,6 +400,8 @@
|
|||
<ArtifactSkillRow
|
||||
{slot}
|
||||
skill={skills[slot - 1] ?? null}
|
||||
allSkills={skills}
|
||||
artifactLevel={level}
|
||||
availableSkills={getSkillsForSlot(slot)}
|
||||
onSelectModifier={() => handleSelectModifier(slot)}
|
||||
onUpdateSkill={(update) => handleUpdateSkill(slot, update)}
|
||||
|
|
@ -364,7 +412,6 @@
|
|||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -404,24 +451,9 @@
|
|||
color: colors.$error;
|
||||
}
|
||||
|
||||
.level-slider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: spacing.$unit;
|
||||
flex: 1;
|
||||
|
||||
.level-value {
|
||||
font-size: typography.$font-regular;
|
||||
font-weight: typography.$medium;
|
||||
min-width: spacing.$unit-2x;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.skills-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: spacing.$unit;
|
||||
padding: 0 spacing.$unit;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue