add ElementBadge component, use in gw event pages
This commit is contained in:
parent
6f0870e37f
commit
00813ddd58
4 changed files with 81 additions and 199 deletions
72
src/lib/components/ui/ElementBadge.svelte
Normal file
72
src/lib/components/ui/ElementBadge.svelte
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ELEMENT_LABELS, ELEMENT_CSS_CLASSES } from '$lib/utils/gw'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
element: number
|
||||||
|
size?: 'small' | 'medium'
|
||||||
|
}
|
||||||
|
|
||||||
|
let { element, size = 'small' }: Props = $props()
|
||||||
|
|
||||||
|
const label = $derived(ELEMENT_LABELS[element] ?? 'Unknown')
|
||||||
|
const cssClass = $derived(ELEMENT_CSS_CLASSES[element] ?? 'null')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="element-badge element-{cssClass}" class:medium={size === 'medium'}>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '$src/themes/layout' as layout;
|
||||||
|
@use '$src/themes/typography' as typography;
|
||||||
|
|
||||||
|
.element-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: layout.$item-corner-small;
|
||||||
|
font-size: typography.$font-small;
|
||||||
|
font-weight: typography.$medium;
|
||||||
|
|
||||||
|
&.medium {
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: typography.$font-regular;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-null {
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-fire {
|
||||||
|
background: #fee2e2;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-water {
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-earth {
|
||||||
|
background: #fef3c7;
|
||||||
|
color: #d97706;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-wind {
|
||||||
|
background: #d1fae5;
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-light {
|
||||||
|
background: #fef9c3;
|
||||||
|
color: #ca8a04;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.element-dark {
|
||||||
|
background: #ede9fe;
|
||||||
|
color: #7c3aed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
import Input from '$lib/components/ui/Input.svelte'
|
import Input from '$lib/components/ui/Input.svelte'
|
||||||
import CrewHeader from '$lib/components/crew/CrewHeader.svelte'
|
import CrewHeader from '$lib/components/crew/CrewHeader.svelte'
|
||||||
import { formatDateJST } from '$lib/utils/date'
|
import { formatDateJST } from '$lib/utils/date'
|
||||||
|
import { formatScore } from '$lib/utils/gw'
|
||||||
|
import ElementBadge from '$lib/components/ui/ElementBadge.svelte'
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -39,28 +41,6 @@
|
||||||
staleTime: 1000 * 60 * 5
|
staleTime: 1000 * 60 * 5
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Element labels (matches GranblueEnums::ELEMENTS)
|
|
||||||
const elementLabels: Record<number, string> = {
|
|
||||||
0: 'Null',
|
|
||||||
1: 'Wind',
|
|
||||||
2: 'Fire',
|
|
||||||
3: 'Water',
|
|
||||||
4: 'Earth',
|
|
||||||
5: 'Dark',
|
|
||||||
6: 'Light'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Element colors for badges
|
|
||||||
const elementColors: Record<number, string> = {
|
|
||||||
0: 'null',
|
|
||||||
1: 'wind',
|
|
||||||
2: 'fire',
|
|
||||||
3: 'water',
|
|
||||||
4: 'earth',
|
|
||||||
5: 'dark',
|
|
||||||
6: 'light'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mutations
|
// Mutations
|
||||||
const createCrewMutation = useCreateCrew()
|
const createCrewMutation = useCreateCrew()
|
||||||
const updateCrewMutation = useUpdateCrew()
|
const updateCrewMutation = useUpdateCrew()
|
||||||
|
|
@ -160,11 +140,6 @@
|
||||||
settingsError = null
|
settingsError = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for formatting scores with commas
|
|
||||||
function formatScore(score: number): string {
|
|
||||||
return score.toLocaleString()
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEventStatus(status: string, startDate: string): string {
|
function formatEventStatus(status: string, startDate: string): string {
|
||||||
if (status === 'upcoming') {
|
if (status === 'upcoming') {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|
@ -283,9 +258,7 @@
|
||||||
<li class="event-item" onclick={() => goto(`/crew/events/${event.eventNumber}`)}>
|
<li class="event-item" onclick={() => goto(`/crew/events/${event.eventNumber}`)}>
|
||||||
<div class="event-info">
|
<div class="event-info">
|
||||||
<span class="event-number">{event.eventNumber}</span>
|
<span class="event-number">{event.eventNumber}</span>
|
||||||
<span class="element-badge element-{elementColors[event.element]}">
|
<ElementBadge element={event.element} />
|
||||||
{elementLabels[event.element] ?? 'Unknown'}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="event-dates">
|
<span class="event-dates">
|
||||||
{formatDateJST(event.startDate)} – {formatDateJST(event.endDate)}
|
{formatDateJST(event.startDate)} – {formatDateJST(event.endDate)}
|
||||||
|
|
@ -660,49 +633,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-badge {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: layout.$item-corner-small;
|
|
||||||
font-size: typography.$font-small;
|
|
||||||
font-weight: typography.$medium;
|
|
||||||
|
|
||||||
&.element-null {
|
|
||||||
background: rgba(0, 0, 0, 0.04);
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-fire {
|
|
||||||
background: #fee2e2;
|
|
||||||
color: #dc2626;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-water {
|
|
||||||
background: #dbeafe;
|
|
||||||
color: #2563eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-earth {
|
|
||||||
background: #fef3c7;
|
|
||||||
color: #d97706;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-wind {
|
|
||||||
background: #d1fae5;
|
|
||||||
color: #059669;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-light {
|
|
||||||
background: #fef9c3;
|
|
||||||
color: #ca8a04;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-dark {
|
|
||||||
background: #ede9fe;
|
|
||||||
color: #7c3aed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
import { gwAdapter } from '$lib/api/adapters/gw.adapter'
|
import { gwAdapter } from '$lib/api/adapters/gw.adapter'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import { formatDateJST } from '$lib/utils/date'
|
import { formatDateJST } from '$lib/utils/date'
|
||||||
|
import { ELEMENT_LABELS } from '$lib/utils/gw'
|
||||||
|
import ElementBadge from '$lib/components/ui/ElementBadge.svelte'
|
||||||
import type { GwEvent } from '$lib/types/api/gw'
|
import type { GwEvent } from '$lib/types/api/gw'
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
||||||
|
|
@ -27,28 +29,6 @@
|
||||||
staleTime: 1000 * 60 * 5
|
staleTime: 1000 * 60 * 5
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Element labels (matches GranblueEnums::ELEMENTS)
|
|
||||||
const elementLabels: Record<number, string> = {
|
|
||||||
0: 'Null',
|
|
||||||
1: 'Wind',
|
|
||||||
2: 'Fire',
|
|
||||||
3: 'Water',
|
|
||||||
4: 'Earth',
|
|
||||||
5: 'Dark',
|
|
||||||
6: 'Light'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Element colors for badges
|
|
||||||
const elementColors: Record<number, string> = {
|
|
||||||
0: 'null',
|
|
||||||
1: 'wind',
|
|
||||||
2: 'fire',
|
|
||||||
3: 'water',
|
|
||||||
4: 'earth',
|
|
||||||
5: 'dark',
|
|
||||||
6: 'light'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter events by search
|
// Filter events by search
|
||||||
const filteredEvents = $derived.by(() => {
|
const filteredEvents = $derived.by(() => {
|
||||||
const events = eventsQuery.data ?? []
|
const events = eventsQuery.data ?? []
|
||||||
|
|
@ -58,7 +38,7 @@
|
||||||
return events.filter(
|
return events.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
String(e.eventNumber).includes(term) ||
|
String(e.eventNumber).includes(term) ||
|
||||||
elementLabels[e.element]?.toLowerCase().includes(term)
|
ELEMENT_LABELS[e.element]?.toLowerCase().includes(term)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -110,9 +90,7 @@
|
||||||
<span class="event-number">{event.eventNumber}</span>
|
<span class="event-number">{event.eventNumber}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="col-element">
|
<td class="col-element">
|
||||||
<span class="element-badge element-{elementColors[event.element]}">
|
<ElementBadge element={event.element} />
|
||||||
{elementLabels[event.element] ?? 'Unknown'}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="col-dates">
|
<td class="col-dates">
|
||||||
<span class="dates">
|
<span class="dates">
|
||||||
|
|
@ -260,44 +238,6 @@
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-badge {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: typography.$font-small;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
&.element-fire {
|
|
||||||
background: #fee2e2;
|
|
||||||
color: #dc2626;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-water {
|
|
||||||
background: #dbeafe;
|
|
||||||
color: #2563eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-earth {
|
|
||||||
background: #fef3c7;
|
|
||||||
color: #d97706;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-wind {
|
|
||||||
background: #d1fae5;
|
|
||||||
color: #059669;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-light {
|
|
||||||
background: #fef9c3;
|
|
||||||
color: #ca8a04;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-dark {
|
|
||||||
background: #ede9fe;
|
|
||||||
color: #7c3aed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dates {
|
.dates {
|
||||||
font-size: typography.$font-small;
|
font-size: typography.$font-small;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
import DetailItem from '$lib/components/ui/DetailItem.svelte'
|
import DetailItem from '$lib/components/ui/DetailItem.svelte'
|
||||||
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
||||||
import { formatDateJST, formatDateLongJST } from '$lib/utils/date'
|
import { formatDateJST, formatDateLongJST } from '$lib/utils/date'
|
||||||
|
import ElementBadge from '$lib/components/ui/ElementBadge.svelte'
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -32,27 +33,6 @@
|
||||||
const userRole = $derived(data.role || 0)
|
const userRole = $derived(data.role || 0)
|
||||||
const canEdit = $derived(userRole >= 7)
|
const canEdit = $derived(userRole >= 7)
|
||||||
|
|
||||||
// Element labels and colors (matches GranblueEnums::ELEMENTS)
|
|
||||||
const elementLabels: Record<number, string> = {
|
|
||||||
0: 'Null',
|
|
||||||
1: 'Wind',
|
|
||||||
2: 'Fire',
|
|
||||||
3: 'Water',
|
|
||||||
4: 'Earth',
|
|
||||||
5: 'Dark',
|
|
||||||
6: 'Light'
|
|
||||||
}
|
|
||||||
|
|
||||||
const elementColors: Record<number, string> = {
|
|
||||||
0: 'null',
|
|
||||||
1: 'wind',
|
|
||||||
2: 'fire',
|
|
||||||
3: 'water',
|
|
||||||
4: 'earth',
|
|
||||||
5: 'dark',
|
|
||||||
6: 'light'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Navigate to edit
|
// Navigate to edit
|
||||||
function handleEdit() {
|
function handleEdit() {
|
||||||
goto(`/database/gw-events/${eventId}/edit`)
|
goto(`/database/gw-events/${eventId}/edit`)
|
||||||
|
|
@ -90,9 +70,7 @@
|
||||||
<DetailsContainer title="Event Details">
|
<DetailsContainer title="Event Details">
|
||||||
<DetailItem label="Event Number" value={`#${event.eventNumber}`} />
|
<DetailItem label="Event Number" value={`#${event.eventNumber}`} />
|
||||||
<DetailItem label="Element">
|
<DetailItem label="Element">
|
||||||
<span class="element-badge element-{elementColors[event.element]}">
|
<ElementBadge element={event.element} />
|
||||||
{elementLabels[event.element] ?? 'Unknown'}
|
|
||||||
</span>
|
|
||||||
</DetailItem>
|
</DetailItem>
|
||||||
<DetailItem label="Start Date" value={formatDateLongJST(event.startDate)} />
|
<DetailItem label="Start Date" value={formatDateLongJST(event.startDate)} />
|
||||||
<DetailItem label="End Date" value={formatDateLongJST(event.endDate)} />
|
<DetailItem label="End Date" value={formatDateLongJST(event.endDate)} />
|
||||||
|
|
@ -159,42 +137,4 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-badge {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: typography.$font-small;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
&.element-fire {
|
|
||||||
background: #fee2e2;
|
|
||||||
color: #dc2626;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-water {
|
|
||||||
background: #dbeafe;
|
|
||||||
color: #2563eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-earth {
|
|
||||||
background: #fef3c7;
|
|
||||||
color: #d97706;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-wind {
|
|
||||||
background: #d1fae5;
|
|
||||||
color: #059669;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-light {
|
|
||||||
background: #fef9c3;
|
|
||||||
color: #ca8a04;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.element-dark {
|
|
||||||
background: #ede9fe;
|
|
||||||
color: #7c3aed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue