feat: add DailyFruitHint component and integrate it into the daily fruit page
Build Docker Image / build (push) Successful in 1m32s
Build Docker Image / build (push) Successful in 1m32s
This commit is contained in:
@@ -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>
|
||||
@@ -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}
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
"hints": {
|
||||
"origin": "Origin",
|
||||
"devilFruit": "Devil fruit",
|
||||
"fruitKind": "Fruit type",
|
||||
"affiliation": "Affiliation",
|
||||
"unknown": "Unknown",
|
||||
"none": "None",
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
"hints": {
|
||||
"origin": "Origine",
|
||||
"devilFruit": "Fruit du demon",
|
||||
"fruitKind": "Type du fruit",
|
||||
"affiliation": "Affiliation",
|
||||
"unknown": "Inconnue",
|
||||
"none": "Aucun",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user