Files
horse/zenno/src/lib/Skill.svelte
T
zephyr 1cfabb18f5
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
zenno: fix type error on fake data
2026-09-22 22:31:12 -04:00

104 lines
2.8 KiB
Svelte

<script lang="ts">
import {
ABILITY_SCALE_NAME,
ABILITY_TYPE_FORMAT,
DURATION_SCALE_NAME,
Target,
TARGET_FORMAT,
tenThousandths,
type Ability,
type Skill,
} from './data/skill';
import SkillIcon from './SkillIcon.svelte';
interface Props {
skill: Skill | null | undefined;
mention?: boolean;
}
const ZERO_SKILL: Skill = {
skill_id: 0,
name: 'Skill data is loading...',
description: 'Skill data is still loading, or else something went wrong.',
group_skills: [],
group: 0,
rarity: 1,
group_rate: 1,
wit_check: false,
activations: [],
tags: [],
icon_id: 0,
};
let { mention, skill }: Props = $props();
function splitCond(c: string): string[] {
return c.replaceAll('&', ' & ').split('@');
}
const s = $derived(skill ?? ZERO_SKILL);
const activationClass = $derived(s.activations.length === 1 ? null : 'block my-2 border rounded-md');
const spanClass = $derived(mention ? 'italic' : 'font-bold');
</script>
{#snippet condition(disj: string[])}
{#each disj as conj, i (conj)}
<span class="-mb-1 block font-mono text-sm">{conj}</span>
{#if i !== disj.length - 1}
<span class="text-xs italic">or</span>
{/if}
{/each}
{/snippet}
{#snippet abilities(abils: Ability[])}
{#each abils as a, i (i)}
<span class="block text-sm">
{ABILITY_TYPE_FORMAT[a.type](a.value)}
{ABILITY_SCALE_NAME[a.value_usage]}
{#if a.target && a.target !== Target.Self}
{TARGET_FORMAT[a.target](a.target_value)}
{/if}
</span>
{/each}
{/snippet}
<span class="group relative inline-block hyphens-none">
<span
class="skill-tip invisible absolute bottom-4 -left-1/2 flex min-w-80 flex-col rounded-lg border px-2 pt-2 text-center opacity-0 shadow-lg transition-all group-hover:visible group-hover:bottom-6 group-hover:opacity-100"
role="tooltip"
>
<span class="block text-xl">
<SkillIcon icon_id={skill?.icon_id} size={32} class="inline" />
{s.name}
</span>
<span class="block border-b py-1 hyphens-auto">
{s.description}
</span>
{#each s.activations as act, i (i)}
<span class={activationClass}>
{#if act.precondition}
<span class="block border-b py-1">
<span class="text-xs italic">Precondition</span>
{@render condition(splitCond(act.precondition))}
</span>
{/if}
<span class="block border-b py-1">
{@render condition(splitCond(act.condition))}
</span>
<span class="block py-1">
{@render abilities(act.abilities)}
{#if act.duration != null && act.duration > 0}
<span class="block text-sm">
for {tenThousandths(act.duration)}s
{DURATION_SCALE_NAME[act.dur_scale]}
</span>
{/if}
</span>
</span>
{/each}
</span>
<SkillIcon icon_id={skill?.icon_id} size={16} class="inline max-h-lh align-text-bottom" />
<span class={[spanClass, 'cursor-pointer']}>{s.name}</span>
</span>