piclets / src /lib /components /Scanner /ScanResult.svelte
Fraser's picture
ScanResult: drop emoji + subtitle, show headline only
bf0af04
Raw History Blame Contribute Delete
5.8 kB
<script lang="ts">
import type { ScanResult } from '$lib/types';
import { TYPE_DATA, PicletType } from '$lib/types/picletTypes';
import { rarityToTier } from '$lib/utils/rarity';
interface Props {
result: ScanResult;
onReset: () => void;
}
let { result, onReset }: Props = $props();
const monster = $derived(result.monster);
const tier = $derived(monster ? rarityToTier(monster.rarity) : 'low');
const typeColor = $derived(
monster ? TYPE_DATA[monster.type as PicletType]?.color ?? '#6c757d' : '#6c757d',
);
const typeLogoPath = $derived(monster ? `/classes/${monster.type}.png` : '');
</script>
{#if result.success && monster}
<div class="result-container">
<div class="success-header">
<h2>
{#if result.status === 'new'}
You Discovered {monster.name}!
{:else}
{monster.name} was already discovered by {monster.discoverer.username}
{/if}
</h2>
</div>
<div class="piclet-preview" style="--type-color: {typeColor}">
<div class="image-wrapper">
<div
class="logo-watermark"
style="background-image: url('{typeLogoPath}')"
></div>
<img src={monster.image_url} alt={monster.name} class="piclet-image" />
</div>
<div class="info">
<h3>{monster.name}</h3>
<div class="badges">
<span class="type-badge" style="background-color: {typeColor}">
{monster.type}
</span>
<span class="rarity-badge tier-{tier}">
{tier} · {monster.rarity}
</span>
</div>
<p class="description">{monster.description}</p>
<div class="stats">
<span>📏 {monster.height_m} m</span>
<span>⚖️ {monster.weight_kg} kg</span>
</div>
</div>
</div>
<div class="action-buttons">
<button class="action-button primary" onclick={onReset}>
Scan Another
</button>
</div>
</div>
{:else}
<div class="result-container">
<div class="error-header">
<div class="error-icon">⚠️</div>
<h2>Scan Failed</h2>
<p class="error-message">{result.error ?? 'Something went wrong.'}</p>
</div>
<div class="action-buttons">
<button class="action-button primary" onclick={onReset}>
Try Again
</button>
</div>
</div>
{/if}
<style>
.result-container {
max-width: 500px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.success-header,
.error-header {
margin-bottom: 2rem;
}
.success-icon,
.error-icon {
font-size: 3rem;
margin-bottom: 1rem;
}
.success-header h2,
.error-header h2 {
color: #333;
margin: 0 0 1rem;
font-size: 1.8rem;
font-weight: 600;
}
.success-message,
.error-message {
color: #666;
font-size: 1.1rem;
margin: 0;
}
.success-message strong {
color: #333;
font-weight: 600;
}
.piclet-preview {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
margin: 2rem 0;
border: 2px solid var(--type-color, #007bff);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.image-wrapper {
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(
135deg,
color-mix(in srgb, var(--type-color) 12%, white) 0%,
rgba(255, 255, 255, 0.9) 100%
);
}
.logo-watermark {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
height: 80%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
opacity: 0.08;
pointer-events: none;
}
.piclet-image {
width: 240px;
height: 240px;
object-fit: contain;
position: relative;
z-index: 1;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15));
}
.info {
width: 100%;
padding: 1rem 1.5rem 1.5rem;
text-align: left;
}
.info h3 {
margin: 0 0 0.5rem;
font-size: 1.4rem;
font-weight: 700;
color: #1a1a1a;
text-align: center;
}
.badges {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.type-badge {
padding: 4px 12px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
color: white;
}
.rarity-badge {
padding: 4px 12px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
color: white;
}
.rarity-badge.tier-low { background: #6c757d; }
.rarity-badge.tier-medium { background: #28a745; }
.rarity-badge.tier-high { background: #fd7e14; }
.rarity-badge.tier-legendary { background: #dc3545; }
.description {
font-size: 0.95rem;
color: #555;
line-height: 1.5;
margin: 0 0 0.75rem;
}
.stats {
display: flex;
justify-content: center;
gap: 1.5rem;
font-size: 0.875rem;
color: #888;
}
.action-buttons {
display: flex;
justify-content: center;
margin-top: 2rem;
}
.action-button {
padding: 0.875rem 2rem;
border: none;
border-radius: 12px;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s ease;
min-width: 160px;
}
.action-button.primary {
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
color: white;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
.action-button.primary:hover {
background: linear-gradient(135deg, #2563eb, #1e40af);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4);
}
.action-button.primary:active {
transform: translateY(0);
}
</style>