mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-18 20:39:36 +02:00
Merge pull request #678 from seanmorley15/development
feat: add CollectionAllView component for unified display of adventur…
This commit is contained in:
commit
3306b799df
14 changed files with 681 additions and 118 deletions
551
frontend/src/lib/components/CollectionAllView.svelte
Normal file
551
frontend/src/lib/components/CollectionAllView.svelte
Normal file
|
@ -0,0 +1,551 @@
|
|||
<script lang="ts">
|
||||
import type {
|
||||
Adventure,
|
||||
Transportation,
|
||||
Lodging,
|
||||
Note,
|
||||
Checklist,
|
||||
User,
|
||||
Collection
|
||||
} from '$lib/types';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
// Icons
|
||||
import Adventures from '~icons/mdi/map-marker-path';
|
||||
import TransportationIcon from '~icons/mdi/car';
|
||||
import Hotel from '~icons/mdi/hotel';
|
||||
import NoteIcon from '~icons/mdi/note-text';
|
||||
import ChecklistIcon from '~icons/mdi/check-box-outline';
|
||||
import Search from '~icons/mdi/magnify';
|
||||
import Clear from '~icons/mdi/close';
|
||||
import Filter from '~icons/mdi/filter-variant';
|
||||
|
||||
// Component imports
|
||||
import AdventureCard from './AdventureCard.svelte';
|
||||
import TransportationCard from './TransportationCard.svelte';
|
||||
import LodgingCard from './LodgingCard.svelte';
|
||||
import NoteCard from './NoteCard.svelte';
|
||||
import ChecklistCard from './ChecklistCard.svelte';
|
||||
|
||||
// Props
|
||||
export let adventures: Adventure[] = [];
|
||||
export let transportations: Transportation[] = [];
|
||||
export let lodging: Lodging[] = [];
|
||||
export let notes: Note[] = [];
|
||||
export let checklists: Checklist[] = [];
|
||||
export let user: User | null;
|
||||
export let collection: Collection;
|
||||
|
||||
// State
|
||||
let searchQuery: string = '';
|
||||
let filterOption: string = 'all';
|
||||
let sortOption: string = 'name_asc';
|
||||
|
||||
// Filtered arrays
|
||||
let filteredAdventures: Adventure[] = [];
|
||||
let filteredTransportations: Transportation[] = [];
|
||||
let filteredLodging: Lodging[] = [];
|
||||
let filteredNotes: Note[] = [];
|
||||
let filteredChecklists: Checklist[] = [];
|
||||
|
||||
// Helper function to sort items
|
||||
function sortItems(items: any[], sortOption: string) {
|
||||
const sorted = [...items];
|
||||
|
||||
switch (sortOption) {
|
||||
case 'name_asc':
|
||||
return sorted.sort((a, b) =>
|
||||
(a.name || a.title || '').localeCompare(b.name || b.title || '')
|
||||
);
|
||||
case 'name_desc':
|
||||
return sorted.sort((a, b) =>
|
||||
(b.name || b.title || '').localeCompare(a.name || a.title || '')
|
||||
);
|
||||
case 'date_newest':
|
||||
return sorted.sort(
|
||||
(a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime()
|
||||
);
|
||||
case 'date_oldest':
|
||||
return sorted.sort(
|
||||
(a, b) => new Date(a.created_at || 0).getTime() - new Date(b.created_at || 0).getTime()
|
||||
);
|
||||
case 'visited_first':
|
||||
return sorted.sort((a, b) => {
|
||||
const aVisited = a.visits && a.visits.length > 0;
|
||||
const bVisited = b.visits && b.visits.length > 0;
|
||||
if (aVisited && !bVisited) return -1;
|
||||
if (!aVisited && bVisited) return 1;
|
||||
return 0;
|
||||
});
|
||||
case 'unvisited_first':
|
||||
return sorted.sort((a, b) => {
|
||||
const aVisited = a.visits && a.visits.length > 0;
|
||||
const bVisited = b.visits && b.visits.length > 0;
|
||||
if (!aVisited && bVisited) return -1;
|
||||
if (aVisited && !bVisited) return 1;
|
||||
return 0;
|
||||
});
|
||||
default:
|
||||
return sorted;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all filters function
|
||||
function clearAllFilters() {
|
||||
searchQuery = '';
|
||||
filterOption = 'all';
|
||||
sortOption = 'name_asc';
|
||||
}
|
||||
|
||||
// Reactive statements for filtering and sorting
|
||||
$: {
|
||||
// Filter adventures
|
||||
let filtered = adventures;
|
||||
if (searchQuery !== '') {
|
||||
filtered = filtered.filter((adventure) => {
|
||||
const nameMatch =
|
||||
adventure.name?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const locationMatch =
|
||||
adventure.location?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const descriptionMatch =
|
||||
adventure.description?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
return nameMatch || locationMatch || descriptionMatch;
|
||||
});
|
||||
}
|
||||
|
||||
filteredAdventures = sortItems(filtered, sortOption);
|
||||
}
|
||||
|
||||
$: {
|
||||
// Filter transportations
|
||||
let filtered = transportations;
|
||||
if (searchQuery !== '') {
|
||||
filtered = filtered.filter((transport) => {
|
||||
const nameMatch =
|
||||
transport.name?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const fromMatch =
|
||||
transport.from_location?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const toMatch =
|
||||
transport.to_location?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
return nameMatch || fromMatch || toMatch;
|
||||
});
|
||||
}
|
||||
|
||||
filteredTransportations = sortItems(filtered, sortOption);
|
||||
}
|
||||
|
||||
$: {
|
||||
// Filter lodging
|
||||
let filtered = lodging;
|
||||
if (searchQuery !== '') {
|
||||
filtered = filtered.filter((hotel) => {
|
||||
const nameMatch = hotel.name?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const locationMatch =
|
||||
hotel.location?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
return nameMatch || locationMatch;
|
||||
});
|
||||
}
|
||||
|
||||
filteredLodging = sortItems(filtered, sortOption);
|
||||
}
|
||||
|
||||
$: {
|
||||
// Filter notes
|
||||
let filtered = notes;
|
||||
if (searchQuery !== '') {
|
||||
filtered = filtered.filter((note) => {
|
||||
const titleMatch = note.name?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
const contentMatch =
|
||||
note.content?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
return titleMatch || contentMatch;
|
||||
});
|
||||
}
|
||||
|
||||
filteredNotes = sortItems(filtered, sortOption);
|
||||
}
|
||||
|
||||
$: {
|
||||
// Filter checklists
|
||||
let filtered = checklists;
|
||||
if (searchQuery !== '') {
|
||||
filtered = filtered.filter((checklist) => {
|
||||
const titleMatch =
|
||||
checklist.name?.toLowerCase().includes(searchQuery.toLowerCase()) || false;
|
||||
return titleMatch;
|
||||
});
|
||||
}
|
||||
|
||||
filteredChecklists = sortItems(filtered, sortOption);
|
||||
}
|
||||
|
||||
// Calculate total items
|
||||
$: totalItems =
|
||||
filteredAdventures.length +
|
||||
filteredTransportations.length +
|
||||
filteredLodging.length +
|
||||
filteredNotes.length +
|
||||
filteredChecklists.length;
|
||||
|
||||
// Event handlers
|
||||
function handleEditAdventure(event: { detail: any }) {
|
||||
dispatch('editAdventure', event.detail);
|
||||
}
|
||||
|
||||
function handleDeleteAdventure(event: { detail: any }) {
|
||||
dispatch('deleteAdventure', event.detail);
|
||||
}
|
||||
|
||||
function handleEditTransportation(event: { detail: any }) {
|
||||
dispatch('editTransportation', event.detail);
|
||||
}
|
||||
|
||||
function handleDeleteTransportation(event: { detail: any }) {
|
||||
dispatch('deleteTransportation', event.detail);
|
||||
}
|
||||
|
||||
function handleEditLodging(event: { detail: any }) {
|
||||
dispatch('editLodging', event.detail);
|
||||
}
|
||||
|
||||
function handleDeleteLodging(event: { detail: any }) {
|
||||
dispatch('deleteLodging', event.detail);
|
||||
}
|
||||
|
||||
function handleEditNote(event: { detail: any }) {
|
||||
dispatch('editNote', event.detail);
|
||||
}
|
||||
|
||||
function handleDeleteNote(event: { detail: any }) {
|
||||
dispatch('deleteNote', event.detail);
|
||||
}
|
||||
|
||||
function handleEditChecklist(event: { detail: any }) {
|
||||
dispatch('editChecklist', event.detail);
|
||||
}
|
||||
|
||||
function handleDeleteChecklist(event: { detail: any }) {
|
||||
dispatch('deleteChecklist', event.detail);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Search and Filter Controls -->
|
||||
<div
|
||||
class="bg-base-100/90 backdrop-blur-lg border border-base-300/50 rounded-2xl p-6 mx-4 mb-6 shadow-lg mt-4"
|
||||
>
|
||||
<!-- Header with Stats -->
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 bg-primary/10 rounded-xl">
|
||||
<Adventures class="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-primary">
|
||||
{$t('adventures.collection_contents')}
|
||||
</h2>
|
||||
<p class="text-sm text-base-content/60">
|
||||
{totalItems}
|
||||
{$t('worldtravel.total_items')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div class="hidden md:flex items-center gap-2">
|
||||
<div class="stats stats-horizontal bg-base-200/50 border border-base-300/50">
|
||||
<div class="stat py-2 px-3">
|
||||
<div class="stat-title text-xs">{$t('navbar.adventures')}</div>
|
||||
<div class="stat-value text-sm text-info">{adventures.length}</div>
|
||||
</div>
|
||||
<div class="stat py-2 px-3">
|
||||
<div class="stat-title text-xs">{$t('adventures.transportations')}</div>
|
||||
<div class="stat-value text-sm text-warning">{transportations.length}</div>
|
||||
</div>
|
||||
<div class="stat py-2 px-3">
|
||||
<div class="stat-title text-xs">{$t('adventures.lodging')}</div>
|
||||
<div class="stat-value text-sm text-success">{lodging.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="flex flex-col lg:flex-row items-stretch lg:items-center gap-4 mb-4">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<Search class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-base-content/40" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="{$t('navbar.search')} {$t('adventures.name_location')}..."
|
||||
class="input input-bordered w-full pl-10 pr-10 bg-base-100/80"
|
||||
bind:value={searchQuery}
|
||||
/>
|
||||
{#if searchQuery.length > 0}
|
||||
<button
|
||||
class="absolute right-3 top-1/2 -translate-y-1/2 text-base-content/40 hover:text-base-content"
|
||||
on:click={() => (searchQuery = '')}
|
||||
>
|
||||
<Clear class="w-4 h-4" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if searchQuery || filterOption !== 'all' || sortOption !== 'name_asc'}
|
||||
<button class="btn btn-ghost btn-sm gap-1" on:click={clearAllFilters}>
|
||||
<Clear class="w-3 h-3" />
|
||||
{$t('worldtravel.clear_all')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Sort Labels (Mobile Friendly) -->
|
||||
<div class="flex flex-wrap gap-2 mb-4">
|
||||
<div class="badge badge-outline gap-1">
|
||||
<Filter class="w-3 h-3" />
|
||||
{$t('adventures.sort')}:
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<button
|
||||
class="badge {sortOption === 'name_asc'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'name_asc')}
|
||||
>
|
||||
A-Z
|
||||
</button>
|
||||
<button
|
||||
class="badge {sortOption === 'name_desc'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'name_desc')}
|
||||
>
|
||||
Z-A
|
||||
</button>
|
||||
<button
|
||||
class="badge {sortOption === 'date_newest'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'date_newest')}
|
||||
>
|
||||
{$t('worldtravel.newest_first')}
|
||||
</button>
|
||||
<button
|
||||
class="badge {sortOption === 'date_oldest'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'date_oldest')}
|
||||
>
|
||||
{$t('worldtravel.oldest_first')}
|
||||
</button>
|
||||
<button
|
||||
class="badge {sortOption === 'visited_first'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'visited_first')}
|
||||
>
|
||||
{$t('worldtravel.visited_first')}
|
||||
</button>
|
||||
<button
|
||||
class="badge {sortOption === 'unvisited_first'
|
||||
? 'badge-primary'
|
||||
: 'badge-ghost'} cursor-pointer hover:badge-primary"
|
||||
on:click={() => (sortOption = 'unvisited_first')}
|
||||
>
|
||||
{$t('worldtravel.unvisited_first')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Tabs -->
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-2">
|
||||
<span class="text-sm font-medium text-base-content/60">
|
||||
{$t('adventures.show')}:
|
||||
</span>
|
||||
|
||||
<!-- Scrollable container on mobile -->
|
||||
<div class="w-full overflow-x-auto">
|
||||
<div class="tabs tabs-boxed bg-base-200 flex-nowrap flex sm:flex-wrap w-max sm:w-auto">
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'all' ? 'tab-active' : ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'all')}
|
||||
>
|
||||
<Adventures class="w-3 h-3" />
|
||||
{$t('adventures.all')}
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'adventures'
|
||||
? 'tab-active'
|
||||
: ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'adventures')}
|
||||
>
|
||||
<Adventures class="w-3 h-3" />
|
||||
{$t('navbar.adventures')}
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'transportation'
|
||||
? 'tab-active'
|
||||
: ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'transportation')}
|
||||
>
|
||||
<TransportationIcon class="w-3 h-3" />
|
||||
{$t('adventures.transportations')}
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'lodging'
|
||||
? 'tab-active'
|
||||
: ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'lodging')}
|
||||
>
|
||||
<Hotel class="w-3 h-3" />
|
||||
{$t('adventures.lodging')}
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'notes' ? 'tab-active' : ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'notes')}
|
||||
>
|
||||
<NoteIcon class="w-3 h-3" />
|
||||
{$t('adventures.notes')}
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-sm gap-2 {filterOption === 'checklists'
|
||||
? 'tab-active'
|
||||
: ''} whitespace-nowrap"
|
||||
on:click={() => (filterOption = 'checklists')}
|
||||
>
|
||||
<ChecklistIcon class="w-3 h-3" />
|
||||
{$t('adventures.checklists')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Adventures Section -->
|
||||
{#if (filterOption === 'all' || filterOption === 'adventures') && filteredAdventures.length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mx-4 mb-4">
|
||||
<h1 class="text-3xl font-bold text-primary">
|
||||
{$t('adventures.linked_adventures')}
|
||||
</h1>
|
||||
<div class="badge badge-primary badge-lg">{filteredAdventures.length}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mx-4">
|
||||
{#each filteredAdventures as adventure}
|
||||
<AdventureCard
|
||||
{user}
|
||||
on:edit={handleEditAdventure}
|
||||
on:delete={handleDeleteAdventure}
|
||||
{adventure}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Transportation Section -->
|
||||
{#if (filterOption === 'all' || filterOption === 'transportation') && filteredTransportations.length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mx-4 mb-4">
|
||||
<h1 class="text-3xl font-bold bg-clip-text text-primary">
|
||||
{$t('adventures.transportations')}
|
||||
</h1>
|
||||
<div class="badge badge-warning badge-lg">{filteredTransportations.length}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mx-4">
|
||||
{#each filteredTransportations as transportation}
|
||||
<TransportationCard
|
||||
{transportation}
|
||||
{user}
|
||||
on:delete={handleDeleteTransportation}
|
||||
on:edit={handleEditTransportation}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Lodging Section -->
|
||||
{#if (filterOption === 'all' || filterOption === 'lodging') && filteredLodging.length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mx-4 mb-4">
|
||||
<h1 class="text-3xl font-bold bg-clip-text text-primary">
|
||||
{$t('adventures.lodging')}
|
||||
</h1>
|
||||
<div class="badge badge-success badge-lg">{filteredLodging.length}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mx-4">
|
||||
{#each filteredLodging as hotel}
|
||||
<LodgingCard
|
||||
lodging={hotel}
|
||||
{user}
|
||||
on:delete={handleDeleteLodging}
|
||||
on:edit={handleEditLodging}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Notes Section -->
|
||||
{#if (filterOption === 'all' || filterOption === 'notes') && filteredNotes.length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mx-4 mb-4">
|
||||
<h1 class="text-3xl font-bold bg-clip-text text-primary">
|
||||
{$t('adventures.notes')}
|
||||
</h1>
|
||||
<div class="badge badge-info badge-lg">{filteredNotes.length}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mx-4">
|
||||
{#each filteredNotes as note}
|
||||
<NoteCard
|
||||
{note}
|
||||
{user}
|
||||
on:edit={handleEditNote}
|
||||
on:delete={handleDeleteNote}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Checklists Section -->
|
||||
{#if (filterOption === 'all' || filterOption === 'checklists') && filteredChecklists.length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mx-4 mb-4">
|
||||
<h1 class="text-3xl font-bold bg-clip-text text-primary">
|
||||
{$t('adventures.checklists')}
|
||||
</h1>
|
||||
<div class="badge badge-secondary badge-lg">{filteredChecklists.length}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mx-4">
|
||||
{#each filteredChecklists as checklist}
|
||||
<ChecklistCard
|
||||
{checklist}
|
||||
{user}
|
||||
on:delete={handleDeleteChecklist}
|
||||
on:edit={handleEditChecklist}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Empty State -->
|
||||
{#if totalItems === 0}
|
||||
<div class="hero min-h-96">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<Clear class="w-16 h-16 text-base-content/30 mb-4" />
|
||||
<h1 class="text-3xl font-bold text-base-content/70">
|
||||
{$t('immich.no_items_found')}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "Sind Sie sicher, dass Sie diese Sammlung löschen möchten? \nDiese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"done": "Erledigt",
|
||||
"loading_adventures": "Ladeabenteuer ...",
|
||||
"name_location": "Name, Ort"
|
||||
"name_location": "Name, Ort",
|
||||
"collection_contents": "Sammelinhalt"
|
||||
},
|
||||
"home": {
|
||||
"desc_1": "Entdecken, planen und erkunden Sie mühelos",
|
||||
|
@ -371,7 +372,12 @@
|
|||
"show_map_labels": "Kartenbezeichnungen anzeigen",
|
||||
"total_cities": "Gesamtstädte",
|
||||
"total_countries": "Gesamtländer",
|
||||
"total_regions": "Gesamtregionen"
|
||||
"total_regions": "Gesamtregionen",
|
||||
"newest_first": "Neuester zuerst",
|
||||
"oldest_first": "Älteste zuerst",
|
||||
"unvisited_first": "Zuerst nicht besucht",
|
||||
"visited_first": "Zuerst besucht",
|
||||
"total_items": "Gesamtartikel"
|
||||
},
|
||||
"settings": {
|
||||
"account_settings": "Benutzerkonto",
|
||||
|
|
|
@ -220,6 +220,7 @@
|
|||
"no_adventures_to_recommendations": "No adventures found. Add at least one adventure to get recommendations.",
|
||||
"display_name": "Display Name",
|
||||
"adventure_not_found": "There are no adventures to display. Add some using the plus button at the bottom right or try changing filters!",
|
||||
"collection_contents": "Collection Contents",
|
||||
"no_adventures_found": "No adventures found",
|
||||
"no_adventures_message": "Start documenting your adventures and planning new ones. Every journey has a story worth telling.",
|
||||
"mark_visited": "Mark Visited",
|
||||
|
@ -337,6 +338,7 @@
|
|||
"filter_by_region": "Filter by Region",
|
||||
"all_regions": "All Regions",
|
||||
"clear_all_filters": "Clear All Filters",
|
||||
"total_items": "Total Items",
|
||||
"filter_by": "Filter by",
|
||||
"interactive_map": "Interactive Map",
|
||||
"no_regions_found": "No regions found",
|
||||
|
@ -346,7 +348,11 @@
|
|||
"show_map_labels": "Show Map Labels",
|
||||
"hide_map_labels": "Hide Map Labels",
|
||||
"total_cities": "Total Cities",
|
||||
"region_completed": "Region completed"
|
||||
"region_completed": "Region completed",
|
||||
"newest_first": "Newest First",
|
||||
"oldest_first": "Oldest First",
|
||||
"visited_first": "Visited First",
|
||||
"unvisited_first": "Unvisited First"
|
||||
},
|
||||
"auth": {
|
||||
"username": "Username",
|
||||
|
|
|
@ -295,7 +295,8 @@
|
|||
"delete_collection_warning": "¿Estás seguro de que quieres eliminar esta colección? \nEsta acción no se puede deshacer.",
|
||||
"done": "Hecho",
|
||||
"loading_adventures": "Cargando aventuras ...",
|
||||
"name_location": "Nombre, ubicación"
|
||||
"name_location": "Nombre, ubicación",
|
||||
"collection_contents": "Contenido de la colección"
|
||||
},
|
||||
"worldtravel": {
|
||||
"all": "Todo",
|
||||
|
@ -346,7 +347,12 @@
|
|||
"show_map_labels": "Mostrar etiquetas de mapa",
|
||||
"total_regions": "Total de regiones",
|
||||
"region_completed": "Región completada",
|
||||
"total_cities": "Ciudades totales"
|
||||
"total_cities": "Ciudades totales",
|
||||
"newest_first": "El primero primero",
|
||||
"oldest_first": "El más antiguo primero",
|
||||
"unvisited_first": "Primero no visitado",
|
||||
"visited_first": "Visitado primero",
|
||||
"total_items": "Total de artículos"
|
||||
},
|
||||
"auth": {
|
||||
"forgot_password": "¿Has olvidado tu contraseña?",
|
||||
|
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "Êtes-vous sûr de vouloir supprimer cette collection? \nCette action ne peut pas être annulée.",
|
||||
"done": "Fait",
|
||||
"loading_adventures": "Chargement des aventures ...",
|
||||
"name_location": "nom, emplacement"
|
||||
"name_location": "nom, emplacement",
|
||||
"collection_contents": "Contenu de la collection"
|
||||
},
|
||||
"home": {
|
||||
"desc_1": "Découvrez, planifiez et explorez en toute simplicité",
|
||||
|
@ -371,7 +372,12 @@
|
|||
"show_map_labels": "Afficher les étiquettes de carte",
|
||||
"total_cities": "Total des villes",
|
||||
"total_countries": "Total des pays",
|
||||
"total_regions": "Régions totales"
|
||||
"total_regions": "Régions totales",
|
||||
"newest_first": "Le plus récent premier",
|
||||
"oldest_first": "Le plus ancien premier",
|
||||
"unvisited_first": "Sans visité d'abord",
|
||||
"visited_first": "Visité en premier",
|
||||
"total_items": "Total des articles"
|
||||
},
|
||||
"settings": {
|
||||
"account_settings": "Paramètres du compte utilisateur",
|
||||
|
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "Sei sicuro di voler eliminare questa collezione? \nQuesta azione non può essere annullata.",
|
||||
"done": "Fatto",
|
||||
"loading_adventures": "Caricamento di avventure ...",
|
||||
"name_location": "Nome, posizione"
|
||||
"name_location": "Nome, posizione",
|
||||
"collection_contents": "Contenuto di raccolta"
|
||||
},
|
||||
"home": {
|
||||
"desc_1": "Scopri, pianifica ed esplora con facilità",
|
||||
|
@ -371,7 +372,12 @@
|
|||
"show_map_labels": "Mostra etichette mappe",
|
||||
"total_cities": "Città totali",
|
||||
"total_countries": "Paesi totali",
|
||||
"total_regions": "Regioni totali"
|
||||
"total_regions": "Regioni totali",
|
||||
"newest_first": "Primo il più recente",
|
||||
"oldest_first": "Prima più antico",
|
||||
"unvisited_first": "Non visitato per primo",
|
||||
"visited_first": "Visitato per primo",
|
||||
"total_items": "Articoli totali"
|
||||
},
|
||||
"settings": {
|
||||
"account_settings": "Impostazioni dell'account utente",
|
||||
|
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "이 컬렉션을 삭제 하시겠습니까? \n이 조치는 취소 할 수 없습니다.",
|
||||
"done": "완료",
|
||||
"loading_adventures": "적재 모험 ...",
|
||||
"name_location": "이름, 위치"
|
||||
"name_location": "이름, 위치",
|
||||
"collection_contents": "수집 내용"
|
||||
},
|
||||
"auth": {
|
||||
"confirm_password": "비밀번호 확인",
|
||||
|
@ -663,7 +664,12 @@
|
|||
"show_map_labels": "지도 레이블 표시",
|
||||
"total_cities": "총 도시",
|
||||
"total_countries": "총 국가",
|
||||
"total_regions": "총 지역"
|
||||
"total_regions": "총 지역",
|
||||
"newest_first": "최신 첫 번째",
|
||||
"oldest_first": "가장 오래된 첫 번째",
|
||||
"unvisited_first": "먼저 방문하지 않습니다",
|
||||
"visited_first": "먼저 방문했습니다",
|
||||
"total_items": "총 항목"
|
||||
},
|
||||
"lodging": {
|
||||
"apartment": "아파트",
|
||||
|
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "Weet u zeker dat u deze collectie wilt verwijderen? \nDeze actie kan niet ongedaan worden gemaakt.",
|
||||
"done": "Klaar",
|
||||
"loading_adventures": "Adventuren laden ...",
|
||||
"name_location": "naam, locatie"
|
||||
"name_location": "naam, locatie",
|
||||
"collection_contents": "Verzamelingsinhoud"
|
||||
},
|
||||
"home": {
|
||||
"desc_1": "Ontdek, plan en verken met gemak",
|
||||
|
@ -371,7 +372,12 @@
|
|||
"show_map_labels": "Toon kaartlabels",
|
||||
"total_cities": "Totale steden",
|
||||
"total_countries": "Totale landen",
|
||||
"total_regions": "Totaal aantal regio's"
|
||||
"total_regions": "Totaal aantal regio's",
|
||||
"newest_first": "Nieuwste eerste",
|
||||
"oldest_first": "Oudste eerste",
|
||||
"unvisited_first": "Eerst niet bezocht",
|
||||
"visited_first": "Eerst bezocht",
|
||||
"total_items": "Totale items"
|
||||
},
|
||||
"settings": {
|
||||
"account_settings": "Gebruikersaccount instellingen",
|
||||
|
|
|
@ -295,7 +295,8 @@
|
|||
"delete_collection_warning": "Er du sikker på at du vil slette denne samlingen? \nDenne handlingen kan ikke angres.",
|
||||
"done": "Ferdig",
|
||||
"loading_adventures": "Laster opp eventyr ...",
|
||||
"name_location": "Navn, plassering"
|
||||
"name_location": "Navn, plassering",
|
||||
"collection_contents": "Samlingsinnhold"
|
||||
},
|
||||
"worldtravel": {
|
||||
"country_list": "Liste over land",
|
||||
|
@ -346,7 +347,12 @@
|
|||
"show_map_labels": "Vis kartetiketter",
|
||||
"total_cities": "Totalt byer",
|
||||
"total_countries": "Totalt land",
|
||||
"total_regions": "Totale regioner"
|
||||
"total_regions": "Totale regioner",
|
||||
"newest_first": "Nyeste først",
|
||||
"oldest_first": "Eldste først",
|
||||
"unvisited_first": "Uvisitert først",
|
||||
"visited_first": "Besøkte først",
|
||||
"total_items": "Totalt gjenstander"
|
||||
},
|
||||
"auth": {
|
||||
"username": "Brukernavn",
|
||||
|
|
|
@ -295,7 +295,8 @@
|
|||
"done": "Zrobione",
|
||||
"loading_adventures": "Ładowanie przygód ...",
|
||||
"name_location": "Nazwa, lokalizacja",
|
||||
"delete_collection_warning": "Czy na pewno chcesz usunąć tę kolekcję? \nTego działania nie można cofnąć."
|
||||
"delete_collection_warning": "Czy na pewno chcesz usunąć tę kolekcję? \nTego działania nie można cofnąć.",
|
||||
"collection_contents": "Zawartość kolekcji"
|
||||
},
|
||||
"worldtravel": {
|
||||
"country_list": "Lista krajów",
|
||||
|
@ -346,7 +347,12 @@
|
|||
"total_countries": "Kraje ogółem",
|
||||
"total_regions": "Regiony ogółem",
|
||||
"all_regions": "Wszystkie regiony",
|
||||
"cities_in": "Miasta w"
|
||||
"cities_in": "Miasta w",
|
||||
"newest_first": "Najnowszy pierwszy",
|
||||
"oldest_first": "Najstarszy pierwszy",
|
||||
"unvisited_first": "Najpierw niewidziane",
|
||||
"visited_first": "Odwiedziłem pierwszy",
|
||||
"total_items": "Całkowite przedmioty"
|
||||
},
|
||||
"auth": {
|
||||
"username": "Nazwa użytkownika",
|
||||
|
|
|
@ -295,7 +295,8 @@
|
|||
"delete_collection_warning": "Вы уверены, что хотите удалить эту коллекцию? \nЭто действие не может быть отменено.",
|
||||
"done": "Сделанный",
|
||||
"loading_adventures": "Загрузка приключений ...",
|
||||
"name_location": "имя, местоположение"
|
||||
"name_location": "имя, местоположение",
|
||||
"collection_contents": "Содержание коллекции"
|
||||
},
|
||||
"worldtravel": {
|
||||
"country_list": "Список стран",
|
||||
|
@ -346,7 +347,12 @@
|
|||
"show_map_labels": "Показать этикетки карты",
|
||||
"total_cities": "Общие города",
|
||||
"total_countries": "Всего стран",
|
||||
"total_regions": "Общие регионы"
|
||||
"total_regions": "Общие регионы",
|
||||
"newest_first": "Новейший первый",
|
||||
"oldest_first": "Сначала старейший",
|
||||
"unvisited_first": "Не заселяется первым",
|
||||
"visited_first": "Посетил первым",
|
||||
"total_items": "Общие предметы"
|
||||
},
|
||||
"auth": {
|
||||
"username": "Имя пользователя",
|
||||
|
|
|
@ -243,7 +243,8 @@
|
|||
"delete_collection_warning": "Är du säker på att du vill ta bort den här samlingen? \nDenna åtgärd kan inte ångras.",
|
||||
"done": "Gjort",
|
||||
"loading_adventures": "Laddar äventyr ...",
|
||||
"name_location": "namn, plats"
|
||||
"name_location": "namn, plats",
|
||||
"collection_contents": "Insamlingsinnehåll"
|
||||
},
|
||||
"home": {
|
||||
"desc_1": "Upptäck, planera och utforska med lätthet",
|
||||
|
@ -346,7 +347,12 @@
|
|||
"show_map_labels": "Visa kartetiketter",
|
||||
"total_cities": "Totala städer",
|
||||
"total_countries": "Totala länder",
|
||||
"total_regions": "Totala regioner"
|
||||
"total_regions": "Totala regioner",
|
||||
"newest_first": "Nyaste första",
|
||||
"oldest_first": "Äldsta först",
|
||||
"unvisited_first": "Oöverträffad först",
|
||||
"visited_first": "Besökt först",
|
||||
"total_items": "Totala artiklar"
|
||||
},
|
||||
"auth": {
|
||||
"confirm_password": "Bekräfta lösenord",
|
||||
|
|
|
@ -295,7 +295,8 @@
|
|||
"delete_collection_warning": "您确定要删除此系列吗?\n该动作不能撤消。",
|
||||
"done": "完毕",
|
||||
"loading_adventures": "加载冒险...",
|
||||
"name_location": "名称,位置"
|
||||
"name_location": "名称,位置",
|
||||
"collection_contents": "收集内容"
|
||||
},
|
||||
"auth": {
|
||||
"forgot_password": "忘记密码?",
|
||||
|
@ -368,7 +369,12 @@
|
|||
"show_map": "显示地图",
|
||||
"show_map_labels": "显示地图标签",
|
||||
"total_cities": "总城市",
|
||||
"total_countries": "总国家"
|
||||
"total_countries": "总国家",
|
||||
"newest_first": "最新的第一",
|
||||
"oldest_first": "最古老的第一",
|
||||
"unvisited_first": "首先未访问",
|
||||
"visited_first": "首先访问",
|
||||
"total_items": "总项目"
|
||||
},
|
||||
"users": {
|
||||
"no_users_found": "未找到已公开个人资料的用户。"
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import LodgingModal from '$lib/components/LodgingModal.svelte';
|
||||
import LodgingCard from '$lib/components/LodgingCard.svelte';
|
||||
import CollectionAllView from '$lib/components/CollectionAllView.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
console.log(data);
|
||||
|
@ -651,7 +652,7 @@
|
|||
{#if data.user && data.user.uuid && (data.user.uuid == collection.user_id || (collection.shared_with && collection.shared_with.includes(data.user.uuid))) && !collection.is_archived}
|
||||
<div class="fixed bottom-4 right-4 z-[999]">
|
||||
<div class="flex flex-row items-center justify-center gap-4">
|
||||
<div class="dropdown dropdown-top dropdown-end">
|
||||
<div class="dropdown dropdown-top dropdown-end z-[999]">
|
||||
<div tabindex="0" role="button" class="btn m-1 size-16 btn-primary">
|
||||
<Plus class="w-8 h-8" />
|
||||
</div>
|
||||
|
@ -844,100 +845,39 @@
|
|||
{/if}
|
||||
|
||||
{#if currentView == 'all'}
|
||||
{#if adventures.length > 0}
|
||||
<h1 class="text-center font-bold text-4xl mt-4 mb-2">{$t('adventures.linked_adventures')}</h1>
|
||||
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each adventures as adventure}
|
||||
<AdventureCard
|
||||
user={data.user}
|
||||
on:edit={editAdventure}
|
||||
on:delete={deleteAdventure}
|
||||
{adventure}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if transportations.length > 0}
|
||||
<h1 class="text-center font-bold text-4xl mt-4 mb-4">{$t('adventures.transportations')}</h1>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each transportations as transportation}
|
||||
<TransportationCard
|
||||
{transportation}
|
||||
user={data?.user}
|
||||
on:delete={(event) => {
|
||||
transportations = transportations.filter((t) => t.id != event.detail);
|
||||
}}
|
||||
on:edit={editTransportation}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if lodging.length > 0}
|
||||
<h1 class="text-center font-bold text-4xl mt-4 mb-4">{$t('adventures.lodging')}</h1>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each lodging as hotel}
|
||||
<LodgingCard
|
||||
lodging={hotel}
|
||||
user={data?.user}
|
||||
on:delete={(event) => {
|
||||
lodging = lodging.filter((t) => t.id != event.detail);
|
||||
}}
|
||||
on:edit={editLodging}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if notes.length > 0}
|
||||
<h1 class="text-center font-bold text-4xl mt-4 mb-4">{$t('adventures.notes')}</h1>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each notes as note}
|
||||
<NoteCard
|
||||
{note}
|
||||
user={data.user || null}
|
||||
on:edit={(event) => {
|
||||
noteToEdit = event.detail;
|
||||
isNoteModalOpen = true;
|
||||
}}
|
||||
on:delete={(event) => {
|
||||
notes = notes.filter((n) => n.id != event.detail);
|
||||
}}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if checklists.length > 0}
|
||||
<h1 class="text-center font-bold text-4xl mt-4 mb-4">{$t('adventures.checklists')}</h1>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each checklists as checklist}
|
||||
<ChecklistCard
|
||||
{checklist}
|
||||
user={data.user || null}
|
||||
on:delete={(event) => {
|
||||
checklists = checklists.filter((n) => n.id != event.detail);
|
||||
}}
|
||||
on:edit={(event) => {
|
||||
checklistToEdit = event.detail;
|
||||
isShowingChecklistModal = true;
|
||||
}}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- if none found -->
|
||||
{#if adventures.length == 0 && transportations.length == 0 && notes.length == 0 && checklists.length == 0 && lodging.length == 0}
|
||||
<NotFound error={undefined} />
|
||||
{/if}
|
||||
<CollectionAllView
|
||||
{adventures}
|
||||
{transportations}
|
||||
{lodging}
|
||||
{notes}
|
||||
{checklists}
|
||||
user={data.user}
|
||||
{collection}
|
||||
on:editAdventure={editAdventure}
|
||||
on:deleteAdventure={deleteAdventure}
|
||||
on:editTransportation={editTransportation}
|
||||
on:deleteTransportation={(event) => {
|
||||
transportations = transportations.filter((t) => t.id != event.detail);
|
||||
}}
|
||||
on:editLodging={editLodging}
|
||||
on:deleteLodging={(event) => {
|
||||
lodging = lodging.filter((t) => t.id != event.detail);
|
||||
}}
|
||||
on:editNote={(event) => {
|
||||
noteToEdit = event.detail;
|
||||
isNoteModalOpen = true;
|
||||
}}
|
||||
on:deleteNote={(event) => {
|
||||
notes = notes.filter((n) => n.id != event.detail);
|
||||
}}
|
||||
on:editChecklist={(event) => {
|
||||
checklistToEdit = event.detail;
|
||||
isShowingChecklistModal = true;
|
||||
}}
|
||||
on:deleteChecklist={(event) => {
|
||||
checklists = checklists.filter((n) => n.id != event.detail);
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if collection.start_date && collection.end_date}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue