161 lines
3.3 KiB
Svelte
161 lines
3.3 KiB
Svelte
<script lang="ts">
|
|
/**
|
|
* RaidGroupItem - Displays a single raid group with header and its raids
|
|
*
|
|
* Shows the group name as a header and lists all raids underneath.
|
|
* Each raid shows an icon, name, level, and selected state.
|
|
*/
|
|
import type { RaidGroupFull, RaidFull } from '$lib/types/api/raid'
|
|
import { getRaidImage } from '$lib/utils/images'
|
|
import Icon from '$lib/components/Icon.svelte'
|
|
|
|
interface Props {
|
|
group: RaidGroupFull
|
|
selectedRaidId?: string
|
|
onSelect: (raid: RaidFull) => void
|
|
}
|
|
|
|
let { group, selectedRaidId, onSelect }: Props = $props()
|
|
|
|
function getRaidName(raid: RaidFull): string {
|
|
if (typeof raid.name === 'string') return raid.name
|
|
return raid.name?.en || raid.name?.ja || 'Unknown Raid'
|
|
}
|
|
|
|
function getGroupName(group: RaidGroupFull): string {
|
|
if (typeof group.name === 'string') return group.name
|
|
return group.name?.en || group.name?.ja || 'Unknown Group'
|
|
}
|
|
</script>
|
|
|
|
<div class="raid-group">
|
|
<div class="group-header">
|
|
<span class="group-name">{getGroupName(group)}</span>
|
|
{#if group.extra}
|
|
<span class="ex-badge">EX</span>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="raid-list">
|
|
{#each group.raids as raid (raid.id)}
|
|
{@const isSelected = raid.id === selectedRaidId}
|
|
<button
|
|
type="button"
|
|
class="raid-item"
|
|
class:selected={isSelected}
|
|
onclick={() => onSelect(raid)}
|
|
>
|
|
<img src={getRaidImage(raid.slug)} alt="" class="raid-icon" />
|
|
<div class="raid-info">
|
|
<span class="raid-name">{getRaidName(raid)}</span>
|
|
{#if raid.level}
|
|
<span class="raid-level">Lv. {raid.level}</span>
|
|
{/if}
|
|
</div>
|
|
{#if isSelected}
|
|
<Icon name="check" size={16} class="check-icon" />
|
|
{/if}
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
@use '$src/themes/spacing' as *;
|
|
@use '$src/themes/typography' as *;
|
|
@use '$src/themes/layout' as *;
|
|
@use '$src/themes/effects' as *;
|
|
@use '$src/themes/colors' as *;
|
|
|
|
.raid-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.group-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $unit;
|
|
padding: $unit $unit-2x;
|
|
background: $grey-90;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
.group-name {
|
|
font-size: $font-small;
|
|
font-weight: $medium;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.ex-badge {
|
|
font-size: $font-tiny;
|
|
font-weight: $bold;
|
|
color: $light-text-30;
|
|
background: rgba($light-bg-10, 0.2);
|
|
padding: 1px 4px;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.raid-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: $unit;
|
|
}
|
|
|
|
.raid-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $unit-2x;
|
|
padding: $unit $unit-2x $unit $unit;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: $card-corner;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
@include smooth-transition($duration-quick, background-color);
|
|
|
|
&:hover {
|
|
background: var(--button-bg);
|
|
}
|
|
|
|
&.selected {
|
|
background: var(--button-bg);
|
|
}
|
|
}
|
|
|
|
.raid-icon {
|
|
height: 60px;
|
|
width: auto;
|
|
border-radius: $item-corner;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.raid-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.raid-name {
|
|
font-size: $font-regular;
|
|
font-weight: $medium;
|
|
color: var(--text-primary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.raid-level {
|
|
font-size: $font-small;
|
|
color: var(--text-tertiary);
|
|
}
|
|
|
|
:global(.check-icon) {
|
|
color: var(--text-secondary);
|
|
flex-shrink: 0;
|
|
}
|
|
</style>
|