feat: add DailyFruitHint component and integrate it into the daily fruit page
Build Docker Image / build (push) Successful in 1m32s

This commit is contained in:
2026-06-23 19:57:24 +02:00
parent 2d9cd43def
commit 42c4c7e20c
5 changed files with 79 additions and 12 deletions
+59
View File
@@ -0,0 +1,59 @@
<script lang="ts">
import type { CharacterWithRelations } from '$lib/server/daily-character.js';
import type { DevilFruit } from '$lib/server/db/schema';
import { t } from '$lib/i18n';
interface $$Props {
dailyFruit: DevilFruit | null;
selectedCharacters?: CharacterWithRelations[];
}
export let dailyFruit: $$Props['dailyFruit'];
export let selectedCharacters: NonNullable<$$Props['selectedCharacters']> = [];
let showFruitTypeHint = false;
$: isFruitTypeAvailable = selectedCharacters.length >= 3;
$: guessesBeforeUnlock = Math.max(0, 3 - selectedCharacters.length);
$: if (!isFruitTypeAvailable) {
showFruitTypeHint = false;
}
</script>
<svelte:head>
<style>
@keyframes hint-unlock {
0% {
box-shadow: 0 0 0 rgba(251, 146, 60, 0);
}
50% {
box-shadow: 0 0 20px rgba(251, 146, 60, 0.8);
}
100% {
box-shadow: 0 0 0 rgba(251, 146, 60, 0);
}
}
.hint-unlocking {
animation: hint-unlock 0.6s ease-out;
}
</style>
</svelte:head>
<div class="rounded-3xl border border-white/10 bg-white/5 p-6 shadow-[0_24px_60px_rgba(0,0,0,0.45)] backdrop-blur">
<button
type="button"
class="flex w-full flex-col items-center justify-center rounded-2xl border border-white/10 px-3 py-4 transition-colors hover:bg-slate-900/80 {isFruitTypeAvailable ? 'bg-slate-950/60' : 'cursor-not-allowed bg-slate-950/30 opacity-50 hover:bg-slate-950/30'}"
disabled={!isFruitTypeAvailable}
onclick={() => (showFruitTypeHint = !showFruitTypeHint)}
>
<p class="text-sm font-medium text-amber-100">{$t.game.components.hints.fruitKind}</p>
{#if showFruitTypeHint}
<p class="mt-2 text-xs font-semibold text-white">{dailyFruit?.type || $t.game.components.hints.unknown}</p>
{:else if guessesBeforeUnlock > 0}
<p class="mt-2 text-xs text-slate-400">{guessesBeforeUnlock} {$t.game.components.hints.beforeUnlock}</p>
{:else}
<p class="mt-2 text-xs text-slate-400">{$t.game.components.hints.available}</p>
{/if}
</button>
</div>
+9 -9
View File
@@ -13,9 +13,9 @@
let showHintAffiliation = false;
// Hint availability - indices are available after a certain number of guesses
$: isOriginAvailable = selectedCharacters.length >= 5;
$: isFruitAvailable = selectedCharacters.length >= 10;
$: isAffiliationAvailable = selectedCharacters.length >= 15;
$: isOriginAvailable = selectedCharacters.length >= 3;
$: isFruitAvailable = selectedCharacters.length >= 6;
$: isAffiliationAvailable = selectedCharacters.length >= 9;
$: isFrench = $language === 'fr';
function getDisplayOrigin(character: CharacterWithRelations): string | null {
@@ -57,8 +57,8 @@
<p class="text-sm font-medium text-amber-100">{$t.game.components.hints.origin}</p>
{#if showHintOrigin}
<p class="mt-2 text-xs text-white font-semibold">{getDisplayOrigin(dailyCharacter) || $t.game.components.hints.unknown}</p>
{:else if Math.max(0, 5 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 5 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else if Math.max(0, 3 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 3 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else}
<p class="mt-2 text-xs text-slate-400">{$t.game.components.hints.available}</p>
{/if}
@@ -72,8 +72,8 @@
<p class="text-sm font-medium text-amber-100">{$t.game.components.hints.devilFruit}</p>
{#if showHintFruit}
<p class="mt-2 text-xs text-white font-semibold">{dailyCharacter.devilFruitName || $t.game.components.hints.none}</p>
{:else if Math.max(0, 10 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 10 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else if Math.max(0, 6 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 6 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else}
<p class="mt-2 text-xs text-slate-400">{$t.game.components.hints.available}</p>
{/if}
@@ -87,8 +87,8 @@
<p class="text-sm font-medium text-amber-100">{$t.game.components.hints.affiliation}</p>
{#if showHintAffiliation}
<p class="mt-2 text-xs text-white font-semibold">{isFrench && dailyCharacter.frAffiliation ? dailyCharacter.frAffiliation : dailyCharacter.affiliation || $t.game.components.hints.unknown}</p>
{:else if Math.max(0, 15 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 15 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else if Math.max(0, 9 - selectedCharacters.length) > 0}
<p class="mt-2 text-xs text-slate-400">{Math.max(0, 9 - selectedCharacters.length)} {$t.game.components.hints.beforeUnlock}</p>
{:else}
<p class="mt-2 text-xs text-slate-400">{$t.game.components.hints.available}</p>
{/if}
+1
View File
@@ -160,6 +160,7 @@
"hints": {
"origin": "Origin",
"devilFruit": "Devil fruit",
"fruitKind": "Fruit type",
"affiliation": "Affiliation",
"unknown": "Unknown",
"none": "None",
+1
View File
@@ -160,6 +160,7 @@
"hints": {
"origin": "Origine",
"devilFruit": "Fruit du demon",
"fruitKind": "Type du fruit",
"affiliation": "Affiliation",
"unknown": "Inconnue",
"none": "Aucun",
+9 -3
View File
@@ -1,7 +1,8 @@
<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import { onMount } from 'svelte';
import YesterdayCharacter from '$lib/components/YesterdayCharacter.svelte';
import CharacterSearchInput from '$lib/components/CharacterSearchInput.svelte';
import DailyFruitHint from '$lib/components/DailyFruitHint.svelte';
import SimpleGuessHistory from '$lib/components/SimpleGuessHistory.svelte';
import WinPanel from '$lib/components/WinPanel.svelte';
import type { CharacterWithRelations } from '$lib/server/daily-character.js';
@@ -43,8 +44,6 @@
isLoaded = true;
});
onDestroy(() => {});
$: if (isLoaded && selectedCharacters) {
const ids = selectedCharacters.map(char => char.id);
localStorage.setItem('dailyFruitHistory', JSON.stringify(ids));
@@ -121,6 +120,13 @@
<p class="mt-2 text-center text-xl font-bold text-amber-50 sm:text-2xl">{dailyFruit?.name}</p>
</div>
<section class="mt-6">
<DailyFruitHint
dailyFruit={dailyFruit}
{selectedCharacters}
/>
</section>
<section class="mt-6 grid gap-6">
{#if hasWon}
<WinPanel