UI and Translation Improvements (#889)

* Update translations from Weblate

* Translated using Weblate (German)

Currently translated at 100.0% (979 of 979 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (979 of 979 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sk/

* Added translation using Weblate (Ukrainian)

* Bump version to 0.11.0 and enhance hero section responsiveness in adventure details

* Update Django version to 5.2.7 in requirements

* feature added hu translation (#885)

* feature added hu translation

* Update dependencies and add Hungarian translation support

---------

Co-authored-by: Petrekanics Máté <mate.petrekanics@webcapital.hu>
Co-authored-by: Sean Morley <mail@seanmorley.com>

* Fix "back" FR traduction (#858)

Co-authored-by: Sean Morley <98704938+seanmorley15@users.noreply.github.com>

---------

Co-authored-by: Alex <div@alexe.at>
Co-authored-by: fantastron27 <fantastron27@gmail.com>
Co-authored-by: Максим Горпиніч <gorpinicmaksim0@gmail.com>
Co-authored-by: petrekanics <75931275+petrekanics@users.noreply.github.com>
Co-authored-by: Petrekanics Máté <mate.petrekanics@webcapital.hu>
Co-authored-by: Sebastien Laithier <kirby@hyrule.ovh>
This commit is contained in:
Sean Morley
2025-10-11 16:52:22 -04:00
committed by GitHub
parent 8a0f7310b0
commit a8d3a29991
13 changed files with 4333 additions and 3271 deletions

View File

@@ -1,4 +1,4 @@
Django==5.2.6 Django==5.2.7
djangorestframework>=3.15.2 djangorestframework>=3.15.2
django-allauth==0.63.3 django-allauth==0.63.3
drf-yasg==1.21.4 drf-yasg==1.21.4

View File

@@ -1,6 +1,6 @@
{ {
"name": "adventurelog-frontend", "name": "adventurelog-frontend",
"version": "0.10.0", "version": "0.11.0",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"django": "cd .. && cd backend/server && python3 manage.py runserver", "django": "cd .. && cd backend/server && python3 manage.py runserver",
@@ -12,43 +12,43 @@
"format": "prettier --write ." "format": "prettier --write ."
}, },
"devDependencies": { "devDependencies": {
"@event-calendar/core": "^3.7.1", "@event-calendar/core": "^3.12.0",
"@event-calendar/day-grid": "^3.7.1", "@event-calendar/day-grid": "^3.12.0",
"@event-calendar/interaction": "^3.12.0", "@event-calendar/interaction": "^3.12.0",
"@event-calendar/time-grid": "^3.7.1", "@event-calendar/time-grid": "^3.12.0",
"@iconify-json/mdi": "^1.1.67", "@iconify-json/mdi": "^1.2.3",
"@sveltejs/adapter-node": "^5.2.0", "@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/adapter-vercel": "^5.4.1", "@sveltejs/adapter-vercel": "^5.7.0",
"@sveltejs/kit": "^2.8.3", "@sveltejs/kit": "^2.20.7",
"@sveltejs/vite-plugin-svelte": "^3.1.1", "@sveltejs/vite-plugin-svelte": "^3.1.2",
"@tailwindcss/typography": "^0.5.13", "@tailwindcss/typography": "^0.5.16",
"@types/node": "^22.5.4", "@types/node": "^22.15.2",
"@types/qrcode": "^1.5.5", "@types/qrcode": "^1.5.5",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.21",
"daisyui": "^4.12.6", "daisyui": "^4.12.24",
"postcss": "^8.4.38", "postcss": "^8.5.3",
"prettier": "^3.3.2", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.2.5", "prettier-plugin-svelte": "^3.3.3",
"svelte": "^4.2.19", "svelte": "^4.2.19",
"svelte-check": "^3.8.1", "svelte-check": "^3.8.6",
"tailwindcss": "^3.4.4", "tailwindcss": "^3.4.17",
"tslib": "^2.6.3", "tslib": "^2.8.1",
"typescript": "^5.5.2", "typescript": "^5.8.3",
"unplugin-icons": "^0.19.0", "unplugin-icons": "^0.19.3",
"vite": "^5.4.19" "vite": "^5.4.19"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@lukulent/svelte-umami": "^0.0.3", "@lukulent/svelte-umami": "^0.0.3",
"dompurify": "^3.2.4", "dompurify": "^3.2.5",
"emoji-picker-element": "^1.26.0", "emoji-picker-element": "^1.26.3",
"gsap": "^3.12.7", "gsap": "^3.12.7",
"luxon": "^3.6.1", "luxon": "^3.6.1",
"marked": "^15.0.4", "marked": "^15.0.11",
"psl": "^1.15.0", "psl": "^1.15.0",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"svelte-i18n": "^4.0.1", "svelte-i18n": "^4.0.1",
"svelte-maplibre": "^0.9.8" "svelte-maplibre": "^0.9.14"
}, },
"overrides": { "overrides": {
"esbuild": "^0.25.9" "esbuild": "^0.25.9"

View File

@@ -15,10 +15,10 @@ importers:
specifier: ^0.0.3 specifier: ^0.0.3
version: 0.0.3(svelte@4.2.19) version: 0.0.3(svelte@4.2.19)
dompurify: dompurify:
specifier: ^3.2.4 specifier: ^3.2.5
version: 3.2.5 version: 3.2.5
emoji-picker-element: emoji-picker-element:
specifier: ^1.26.0 specifier: ^1.26.3
version: 1.26.3 version: 1.26.3
gsap: gsap:
specifier: ^3.12.7 specifier: ^3.12.7
@@ -27,7 +27,7 @@ importers:
specifier: ^3.6.1 specifier: ^3.6.1
version: 3.6.1 version: 3.6.1
marked: marked:
specifier: ^15.0.4 specifier: ^15.0.11
version: 15.0.11 version: 15.0.11
psl: psl:
specifier: ^1.15.0 specifier: ^1.15.0
@@ -39,77 +39,77 @@ importers:
specifier: ^4.0.1 specifier: ^4.0.1
version: 4.0.1(svelte@4.2.19) version: 4.0.1(svelte@4.2.19)
svelte-maplibre: svelte-maplibre:
specifier: ^0.9.8 specifier: ^0.9.14
version: 0.9.14(svelte@4.2.19) version: 0.9.14(svelte@4.2.19)
devDependencies: devDependencies:
'@event-calendar/core': '@event-calendar/core':
specifier: ^3.7.1 specifier: ^3.12.0
version: 3.12.0 version: 3.12.0
'@event-calendar/day-grid': '@event-calendar/day-grid':
specifier: ^3.7.1 specifier: ^3.12.0
version: 3.12.0 version: 3.12.0
'@event-calendar/interaction': '@event-calendar/interaction':
specifier: ^3.12.0 specifier: ^3.12.0
version: 3.12.0 version: 3.12.0
'@event-calendar/time-grid': '@event-calendar/time-grid':
specifier: ^3.7.1 specifier: ^3.12.0
version: 3.12.0 version: 3.12.0
'@iconify-json/mdi': '@iconify-json/mdi':
specifier: ^1.1.67 specifier: ^1.2.3
version: 1.2.3 version: 1.2.3
'@sveltejs/adapter-node': '@sveltejs/adapter-node':
specifier: ^5.2.0 specifier: ^5.2.12
version: 5.2.12(@sveltejs/kit@2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2))) version: 5.2.12(@sveltejs/kit@2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))
'@sveltejs/adapter-vercel': '@sveltejs/adapter-vercel':
specifier: ^5.4.1 specifier: ^5.7.0
version: 5.7.0(@sveltejs/kit@2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(rollup@4.40.2) version: 5.7.0(@sveltejs/kit@2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(rollup@4.40.2)
'@sveltejs/kit': '@sveltejs/kit':
specifier: ^2.8.3 specifier: ^2.20.7
version: 2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)) version: 2.20.7(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)))(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2))
'@sveltejs/vite-plugin-svelte': '@sveltejs/vite-plugin-svelte':
specifier: ^3.1.1 specifier: ^3.1.2
version: 3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2)) version: 3.1.2(svelte@4.2.19)(vite@5.4.19(@types/node@22.15.2))
'@tailwindcss/typography': '@tailwindcss/typography':
specifier: ^0.5.13 specifier: ^0.5.16
version: 0.5.16(tailwindcss@3.4.17) version: 0.5.16(tailwindcss@3.4.17)
'@types/node': '@types/node':
specifier: ^22.5.4 specifier: ^22.15.2
version: 22.15.2 version: 22.15.2
'@types/qrcode': '@types/qrcode':
specifier: ^1.5.5 specifier: ^1.5.5
version: 1.5.5 version: 1.5.5
autoprefixer: autoprefixer:
specifier: ^10.4.19 specifier: ^10.4.21
version: 10.4.21(postcss@8.5.3) version: 10.4.21(postcss@8.5.3)
daisyui: daisyui:
specifier: ^4.12.6 specifier: ^4.12.24
version: 4.12.24(postcss@8.5.3) version: 4.12.24(postcss@8.5.3)
postcss: postcss:
specifier: ^8.4.38 specifier: ^8.5.3
version: 8.5.3 version: 8.5.3
prettier: prettier:
specifier: ^3.3.2 specifier: ^3.5.3
version: 3.5.3 version: 3.5.3
prettier-plugin-svelte: prettier-plugin-svelte:
specifier: ^3.2.5 specifier: ^3.3.3
version: 3.3.3(prettier@3.5.3)(svelte@4.2.19) version: 3.3.3(prettier@3.5.3)(svelte@4.2.19)
svelte: svelte:
specifier: ^4.2.19 specifier: ^4.2.19
version: 4.2.19 version: 4.2.19
svelte-check: svelte-check:
specifier: ^3.8.1 specifier: ^3.8.6
version: 3.8.6(postcss-load-config@4.0.2(postcss@8.5.3))(postcss@8.5.3)(svelte@4.2.19) version: 3.8.6(postcss-load-config@4.0.2(postcss@8.5.3))(postcss@8.5.3)(svelte@4.2.19)
tailwindcss: tailwindcss:
specifier: ^3.4.4 specifier: ^3.4.17
version: 3.4.17 version: 3.4.17
tslib: tslib:
specifier: ^2.6.3 specifier: ^2.8.1
version: 2.8.1 version: 2.8.1
typescript: typescript:
specifier: ^5.5.2 specifier: ^5.8.3
version: 5.8.3 version: 5.8.3
unplugin-icons: unplugin-icons:
specifier: ^0.19.0 specifier: ^0.19.3
version: 0.19.3 version: 0.19.3
vite: vite:
specifier: ^5.4.19 specifier: ^5.4.19
@@ -733,8 +733,8 @@ packages:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'} engines: {node: '>=6'}
caniuse-lite@1.0.30001715: caniuse-lite@1.0.30001750:
resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==}
chokidar@3.6.0: chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
@@ -2376,7 +2376,7 @@ snapshots:
autoprefixer@10.4.21(postcss@8.5.3): autoprefixer@10.4.21(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
caniuse-lite: 1.0.30001715 caniuse-lite: 1.0.30001750
fraction.js: 4.3.7 fraction.js: 4.3.7
normalize-range: 0.1.2 normalize-range: 0.1.2
picocolors: 1.1.1 picocolors: 1.1.1
@@ -2408,7 +2408,7 @@ snapshots:
browserslist@4.24.4: browserslist@4.24.4:
dependencies: dependencies:
caniuse-lite: 1.0.30001715 caniuse-lite: 1.0.30001750
electron-to-chromium: 1.5.143 electron-to-chromium: 1.5.143
node-releases: 2.0.19 node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4) update-browserslist-db: 1.1.3(browserslist@4.24.4)
@@ -2419,7 +2419,7 @@ snapshots:
camelcase@5.3.1: {} camelcase@5.3.1: {}
caniuse-lite@1.0.30001715: {} caniuse-lite@1.0.30001750: {}
chokidar@3.6.0: chokidar@3.6.0:
dependencies: dependencies:

View File

@@ -65,7 +65,8 @@
ar: 'العربية', ar: 'العربية',
'pt-br': 'Português (Brasil)', 'pt-br': 'Português (Brasil)',
sk: 'Slovenský', sk: 'Slovenský',
tr: 'Türkçe' tr: 'Türkçe',
hu: 'Magyar'
}; };
const submitLocaleChange = (event: Event) => { const submitLocaleChange = (event: Event) => {

View File

@@ -1,4 +1,4 @@
export let appVersion = 'v0.11.0-main-09212025'; export let appVersion = 'v0.11.0-main-10112025';
export let versionChangelog = 'https://github.com/seanmorley15/AdventureLog/releases/tag/v0.11.0'; export let versionChangelog = 'https://github.com/seanmorley15/AdventureLog/releases/tag/v0.11.0';
export let appTitle = 'AdventureLog'; export let appTitle = 'AdventureLog';
export let copyrightYear = '2023-2025'; export let copyrightYear = '2023-2025';

File diff suppressed because it is too large Load Diff

View File

@@ -290,7 +290,7 @@
"average_cadence": "Cadence moyenne", "average_cadence": "Cadence moyenne",
"average_speed": "Vitesse moyenne", "average_speed": "Vitesse moyenne",
"avg_speed": "Vitesse moyenne", "avg_speed": "Vitesse moyenne",
"back": "Dos", "back": "Retour",
"cadence": "Cadence", "cadence": "Cadence",
"calories": "Calories", "calories": "Calories",
"click_map": "Cliquez sur la carte pour sélectionner un emplacement", "click_map": "Cliquez sur la carte pour sélectionner un emplacement",

1041
frontend/src/locales/hu.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{}

View File

@@ -22,6 +22,7 @@
register('pt-br', () => import('../locales/pt-br.json')); register('pt-br', () => import('../locales/pt-br.json'));
register('sk', () => import('../locales/sk.json')); register('sk', () => import('../locales/sk.json'));
register('tr', () => import('../locales/tr.json')); register('tr', () => import('../locales/tr.json'));
register('hu', () => import('../locales/hu.json'));
let locales = [ let locales = [
'en', 'en',
@@ -40,7 +41,8 @@
'ar', 'ar',
'pt-br', 'pt-br',
'sk', 'sk',
'tr' 'tr',
'hu'
]; ];
if (browser) { if (browser) {

View File

@@ -173,8 +173,12 @@
<!-- Hero Section --> <!-- Hero Section -->
<div class="relative"> <div class="relative">
{#if adventure.images && adventure.images.length > 0} <div
<div class="hero min-h-[60vh] relative overflow-hidden"> class="hero min-h-[60vh] relative overflow-hidden"
class:min-h-[30vh]={!adventure.images || adventure.images.length === 0}
>
<!-- Background: Images or Gradient -->
{#if adventure.images && adventure.images.length > 0}
<div class="hero-overlay bg-gradient-to-t from-black/70 via-black/20 to-transparent"></div> <div class="hero-overlay bg-gradient-to-t from-black/70 via-black/20 to-transparent"></div>
{#each adventure.images as image, i} {#each adventure.images as image, i}
<div <div
@@ -191,137 +195,129 @@
</button> </button>
</div> </div>
{/each} {/each}
{:else}
<div class="absolute inset-0 bg-gradient-to-br from-primary/20 to-secondary/20"></div>
{/if}
<div class="hero-content relative z-10 text-center text-white"> <!-- Content -->
<div class="max-w-4xl"> <div
<h1 class="text-6xl font-bold mb-4 drop-shadow-lg">{adventure.name}</h1> class="hero-content relative z-10 text-center"
class:text-white={adventure.images?.length > 0}
>
<div class="max-w-4xl">
<h1 class="text-6xl font-bold mb-4 drop-shadow-lg">{adventure.name}</h1>
<!-- Rating --> <!-- Rating -->
{#if adventure.rating !== undefined && adventure.rating !== null} {#if adventure.rating !== undefined && adventure.rating !== null}
<div class="flex justify-center mb-6"> <div class="flex justify-center mb-6">
<div class="rating rating-lg"> <div class="rating rating-lg">
{#each Array.from({ length: 5 }, (_, i) => i + 1) as star} {#each Array.from({ length: 5 }, (_, i) => i + 1) as star}
<input <input
type="radio" type="radio"
name="rating-hero" name="rating-hero"
class="mask mask-star-2 bg-warning" class="mask mask-star-2 bg-warning"
checked={star <= adventure.rating} checked={star <= adventure.rating}
disabled disabled
/> />
{/each} {/each}
</div> </div>
</div>
{/if}
<!-- Quick Info Badges -->
<div class="flex flex-wrap justify-center gap-4 mb-6">
<a
href="/locations?types={adventure.category?.name}"
class="badge badge-lg badge-primary font-semibold px-4 py-3 cursor-pointer hover:brightness-110 transition-all"
>
{adventure.category?.display_name}
{adventure.category?.icon}
</a>
{#if adventure.location}
<div class="badge badge-lg badge-secondary font-semibold px-4 py-3">
📍 {adventure.location}
</div> </div>
{/if} {/if}
{#if adventure.visits.length > 0}
<!-- Quick Info Cards --> <div class="badge badge-lg badge-accent font-semibold px-4 py-3">
<div class="flex flex-wrap justify-center gap-4 mb-6"> 🎯 {adventure.visits.length}
<div class="badge badge-lg badge-primary font-semibold px-4 py-3"> {adventure.visits.length === 1 ? $t('adventures.visit') : $t('adventures.visits')}
{adventure.category?.display_name}
{adventure.category?.icon}
</div> </div>
{#if adventure.location} {/if}
<div class="badge badge-lg badge-secondary font-semibold px-4 py-3"> {#if adventure.is_visited}
📍 {adventure.location} <div class="badge badge-lg badge-success font-semibold px-4 py-3">
{$t('adventures.visited')}
</div>
{:else}
<div class="badge badge-lg badge-warning font-semibold px-4 py-3">
{$t('adventures.not_visited')}
</div>
{/if}
{#if adventure.trails && adventure.trails.length > 0}
<div class="badge badge-lg badge-info font-semibold px-4 py-3">
🥾 {adventure.trails.length} Trail{adventure.trails.length === 1 ? '' : 's'}
</div>
{/if}
</div>
<!-- Image Navigation (only shown when multiple images exist) -->
{#if adventure.images && adventure.images.length > 1}
<div class="w-full max-w-md mx-auto">
<!-- Navigation arrows and current position -->
<div class="flex items-center justify-center gap-4 mb-3">
<button
on:click={() =>
goToSlide(currentSlide > 0 ? currentSlide - 1 : adventure.images.length - 1)}
class="btn btn-circle btn-sm btn-primary"
aria-label={$t('adventures.previous_image')}
>
</button>
<div class="text-sm font-medium bg-black/50 px-3 py-1 rounded-full">
{currentSlide + 1} / {adventure.images.length}
</div> </div>
{/if}
{#if adventure.visits.length > 0} <button
<div class="badge badge-lg badge-accent font-semibold px-4 py-3"> on:click={() =>
🎯 {adventure.visits.length} goToSlide(currentSlide < adventure.images.length - 1 ? currentSlide + 1 : 0)}
{adventure.visits.length === 1 ? $t('adventures.visit') : $t('adventures.visits')} class="btn btn-circle btn-sm btn-primary"
aria-label={$t('adventures.next_image')}
>
</button>
</div>
<!-- Dot navigation -->
{#if adventure.images.length <= 12}
<div class="flex justify-center gap-2 flex-wrap">
{#each adventure.images as _, i}
<button
on:click={() => goToSlide(i)}
class="btn btn-circle btn-xs transition-all duration-200"
class:btn-primary={i === currentSlide}
class:btn-outline={i !== currentSlide}
class:opacity-50={i !== currentSlide}
>
{i + 1}
</button>
{/each}
</div> </div>
{/if} {:else}
{#if adventure.trails && adventure.trails.length > 0} <div class="relative">
<div class="badge badge-lg badge-info font-semibold px-4 py-3"> <div
🥾 {adventure.trails.length} Trail{adventure.trails.length === 1 ? '' : 's'} class="absolute left-0 top-0 bottom-2 w-4 bg-gradient-to-r from-black/30 to-transparent pointer-events-none"
></div>
<div
class="absolute right-0 top-0 bottom-2 w-4 bg-gradient-to-l from-black/30 to-transparent pointer-events-none"
></div>
</div> </div>
{/if} {/if}
</div> </div>
{/if}
<!-- Image Navigation -->
{#if adventure.images.length > 1}
<div class="w-full max-w-md mx-auto">
<!-- Navigation arrows and current position indicator -->
<div class="flex items-center justify-center gap-4 mb-3">
<button
on:click={() =>
goToSlide(currentSlide > 0 ? currentSlide - 1 : adventure.images.length - 1)}
class="btn btn-circle btn-sm btn-primary"
aria-label={$t('adventures.previous_image')}
>
</button>
<div class="text-sm font-medium bg-black/50 px-3 py-1 rounded-full">
{currentSlide + 1} / {adventure.images.length}
</div>
<button
on:click={() =>
goToSlide(currentSlide < adventure.images.length - 1 ? currentSlide + 1 : 0)}
class="btn btn-circle btn-sm btn-primary"
aria-label={$t('adventures.next_image')}
>
</button>
</div>
<!-- Scrollable dot navigation for many images -->
{#if adventure.images.length <= 12}
<!-- Show all dots for 12 or fewer images -->
<div class="flex justify-center gap-2 flex-wrap">
{#each adventure.images as _, i}
<button
on:click={() => goToSlide(i)}
class="btn btn-circle btn-xs transition-all duration-200"
class:btn-primary={i === currentSlide}
class:btn-outline={i !== currentSlide}
class:opacity-50={i !== currentSlide}
>
{i + 1}
</button>
{/each}
</div>
{:else}
<!-- Scrollable navigation for many images -->
<div class="relative">
<div
class="absolute left-0 top-0 bottom-2 w-4 bg-gradient-to-r from-black/30 to-transparent pointer-events-none"
></div>
<div
class="absolute right-0 top-0 bottom-2 w-4 bg-gradient-to-l from-black/30 to-transparent pointer-events-none"
></div>
</div>
{/if}
</div>
{/if}
</div>
</div> </div>
</div> </div>
{:else} </div>
<!-- No image hero -->
<div class="hero min-h-[40vh] bg-gradient-to-br from-primary/20 to-secondary/20">
<div class="hero-content text-center">
<div class="max-w-4xl">
<h1 class="text-6xl font-bold mb-6">{adventure.name}</h1>
{#if adventure.rating !== undefined && adventure.rating !== null}
<div class="flex justify-center mb-6">
<div class="rating rating-lg">
{#each Array.from({ length: 5 }, (_, i) => i + 1) as star}
<input
type="radio"
name="rating-hero-no-img"
class="mask mask-star-2 bg-warning"
checked={star <= adventure.rating}
disabled
/>
{/each}
</div>
</div>
{/if}
</div>
</div>
</div>
{/if}
</div> </div>
<!-- Main Content --> <!-- Main Content -->
@@ -841,7 +837,7 @@
{/if} {/if}
<!-- Additional Images --> <!-- Additional Images -->
{#if adventure.images && adventure.images.length > 1} {#if adventure.images}
<div class="card bg-base-200 shadow-xl"> <div class="card bg-base-200 shadow-xl">
<div class="card-body"> <div class="card-body">
<h3 class="card-title text-lg mb-4">🖼️ {$t('adventures.images')}</h3> <h3 class="card-title text-lg mb-4">🖼️ {$t('adventures.images')}</h3>