1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-22 06:19:38 +02:00

Add i18n support for transportation, notes, checklist, and collection components

This commit is contained in:
Sean Morley 2024-11-03 22:55:38 -05:00
parent c0aaec1436
commit 3df124b250
11 changed files with 305 additions and 213 deletions

View file

@ -3,6 +3,7 @@
import type { Checklist, Collection, User } from '$lib/types'; import type { Checklist, Collection, User } from '$lib/types';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { t } from 'svelte-i18n';
import Launch from '~icons/mdi/launch'; import Launch from '~icons/mdi/launch';
import TrashCan from '~icons/mdi/trash-can'; import TrashCan from '~icons/mdi/trash-can';
@ -21,10 +22,10 @@
method: 'DELETE' method: 'DELETE'
}); });
if (res.ok) { if (res.ok) {
addToast('success', 'Checklist deleted successfully'); addToast('success', $t('checklist.checklist_deleted'));
dispatch('delete', checklist.id); dispatch('delete', checklist.id);
} else { } else {
addToast('Failed to delete checklist', 'error'); addToast($t('checklist.checklist_delete_error'), 'error');
} }
} }
</script> </script>
@ -38,9 +39,12 @@
{checklist.name} {checklist.name}
</h2> </h2>
</div> </div>
<div class="badge badge-primary">Checklist</div> <div class="badge badge-primary">{$t('adventures.checklist')}</div>
{#if checklist.items.length > 0} {#if checklist.items.length > 0}
<p>{checklist.items.length} {checklist.items.length > 1 ? 'Items' : 'Item'}</p> <p>
{checklist.items.length}
{checklist.items.length > 1 ? $t('checklist.items') : $t('checklist.item')}
</p>
{/if} {/if}
{#if checklist.date && checklist.date !== ''} {#if checklist.date && checklist.date !== ''}
<div class="inline-flex items-center"> <div class="inline-flex items-center">
@ -49,11 +53,8 @@
</div> </div>
{/if} {/if}
<div class="card-actions justify-end"> <div class="card-actions justify-end">
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
><Launch class="w-6 h-6" />Open Details</button
> -->
<button class="btn btn-neutral-200 mb-2" on:click={editChecklist}> <button class="btn btn-neutral-200 mb-2" on:click={editChecklist}>
<Launch class="w-6 h-6" />Open <Launch class="w-6 h-6" />{$t('notes.open')}
</button> </button>
{#if checklist.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))} {#if checklist.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<button <button

View file

@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import { isValidUrl } from '$lib';
import type { Collection, Checklist, User, ChecklistItem } from '$lib/types'; import type { Collection, Checklist, User, ChecklistItem } from '$lib/types';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { onMount } from 'svelte'; import { onMount } from 'svelte';
let modal: HTMLDialogElement; let modal: HTMLDialogElement;
import { t } from 'svelte-i18n';
export let checklist: Checklist | null = null; export let checklist: Checklist | null = null;
export let collection: Collection; export let collection: Collection;
@ -21,11 +21,11 @@
function addItem() { function addItem() {
if (newItem.trim() == '') { if (newItem.trim() == '') {
warning = 'Item cannot be empty'; warning = $t('checklist.item_cannot_be_empty');
return; return;
} }
if (newChecklist.items.find((item) => item.name.trim() == newItem)) { if (newChecklist.items.find((item) => item.name.trim() == newItem)) {
warning = 'Item already exists'; warning = $t('checklist.item_already_exists');
return; return;
} }
items = [ items = [
@ -130,15 +130,15 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg mb-2">Checklist Editor</h3> <h3 class="font-bold text-lg mb-2">{$t('checklist.checklist_editor')}</h3>
{#if initialName} {#if initialName}
<p class="font-semibold text-md mb-2">Editing checklist {initialName}</p> <p class="font-semibold text-md mb-2">{$t('checklist.editing_checklist')} {initialName}</p>
{/if} {/if}
{#if (checklist && user?.pk == checklist?.user_id) || (user && collection && collection.shared_with.includes(user.uuid)) || !checklist} {#if (checklist && user?.pk == checklist?.user_id) || (user && collection && collection.shared_with.includes(user.uuid)) || !checklist}
<form on:submit|preventDefault> <form on:submit|preventDefault>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="name">Name</label> <label for="name">{$t('adventures.name')}</label>
<input <input
type="text" type="text"
id="name" id="name"
@ -147,7 +147,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Date</label> <label for="content">{$t('adventures.date')}</label>
<input <input
type="date" type="date"
id="date" id="date"
@ -163,7 +163,7 @@
<input <input
type="text" type="text"
id="new_item" id="new_item"
placeholder="New Item" placeholder={$t('checklist.new_item')}
name="new_item" name="new_item"
bind:value={newItem} bind:value={newItem}
class="input input-bordered w-full max-w-xs mt-1" class="input input-bordered w-full max-w-xs mt-1"
@ -179,12 +179,12 @@
class="btn btn-sm btn-primary absolute right-0 mt-2.5 mr-4" class="btn btn-sm btn-primary absolute right-0 mt-2.5 mr-4"
on:click={addItem} on:click={addItem}
> >
Add {$t('adventures.add')}
</button> </button>
</div> </div>
{#if items.length > 0} {#if items.length > 0}
<div class="divider"></div> <div class="divider"></div>
<h2 class=" text-xl font-semibold mb-4 -mt-3">Items</h2> <h2 class=" text-xl font-semibold mb-4 -mt-3">{$t('checklist.items')}</h2>
{/if} {/if}
{#each items as item, i} {#each items as item, i}
@ -202,7 +202,7 @@
class="btn btn-sm btn-error absolute right-0 mt-2.5 mr-4" class="btn btn-sm btn-error absolute right-0 mt-2.5 mr-4"
on:click={() => removeItem(i)} on:click={() => removeItem(i)}
> >
Remove {$t('adventures.remove')}
</button> </button>
</div> </div>
{/each} {/each}
@ -226,8 +226,8 @@
</div> </div>
{/if} {/if}
<button class="btn btn-primary mr-1" on:click={save}>Save</button> <button class="btn btn-primary mr-1" on:click={save}>{$t('notes.save')}</button>
<button class="btn btn-neutral" on:click={close}>Close</button> <button class="btn btn-neutral" on:click={close}>{$t('about.close')}</button>
{#if collection.is_public} {#if collection.is_public}
<div role="alert" class="alert mt-4"> <div role="alert" class="alert mt-4">
@ -244,14 +244,14 @@
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path> ></path>
</svg> </svg>
<span>This checklist is public because it is in a public collection.</span> <span>{$t('checklist.checklist_public')}</span>
</div> </div>
{/if} {/if}
</form> </form>
{:else} {:else}
<form> <form>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="name">Name</label> <label for="name">{$t('adventures.name')}</label>
<input <input
type="text" type="text"
id="name" id="name"
@ -261,7 +261,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Date</label> <label for="content">{$t('adventures.date')}</label>
<input <input
type="date" type="date"
id="date" id="date"
@ -276,7 +276,7 @@
{#if items.length > 0} {#if items.length > 0}
<div class="divider"></div> <div class="divider"></div>
<h2 class=" text-xl font-semibold mb-4 -mt-3">Items</h2> <h2 class=" text-xl font-semibold mb-4 -mt-3">{$t('checklist.items')}</h2>
{/if} {/if}
{#each items as item, i} {#each items as item, i}
@ -299,7 +299,7 @@
</div> </div>
{/each} {/each}
<button class="btn btn-neutral" on:click={close}>Close</button> <button class="btn btn-neutral" on:click={close}>{$t('about.close')}</button>
</form> </form>
{/if} {/if}
</div> </div>

View file

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
export let collectionToEdit: Collection; export let collectionToEdit: Collection;
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { Adventure, Collection } from '$lib/types'; import type { Collection } from '$lib/types';
import { t } from 'svelte-i18n';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
@ -41,17 +42,17 @@
if (collectionToEdit.end_date && collectionToEdit.start_date) { if (collectionToEdit.end_date && collectionToEdit.start_date) {
if (new Date(collectionToEdit.start_date) > new Date(collectionToEdit.end_date)) { if (new Date(collectionToEdit.start_date) > new Date(collectionToEdit.end_date)) {
addToast('error', 'Start date must be before end date'); addToast('error', $t('adventures.start_before_end_error'));
return; return;
} }
} }
if (collectionToEdit.end_date && !collectionToEdit.start_date) { if (collectionToEdit.end_date && !collectionToEdit.start_date) {
addToast('error', 'Please provide a start date'); addToast('error', $t('adventures.no_start_date'));
return; return;
} }
if (collectionToEdit.start_date && !collectionToEdit.end_date) { if (collectionToEdit.start_date && !collectionToEdit.end_date) {
addToast('error', 'Please provide an end date'); addToast('error', $t('adventures.no_end_date'));
return; return;
} }
@ -66,12 +67,12 @@
console.log(data); console.log(data);
if (data) { if (data) {
addToast('success', 'Adventure edited successfully!'); addToast('success', $t('collection.collection_edit_success'));
dispatch('saveEdit', collectionToEdit); dispatch('saveEdit', collectionToEdit);
close(); close();
} else { } else {
addToast('warning', 'Error editing adventure'); addToast('warning', $t('collection.error_editing_collection'));
console.log('Error editing adventure'); console.log('Error editing collection');
} }
} }
} }
@ -81,7 +82,7 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">Edit Collection: {originalName}</h3> <h3 class="font-bold text-lg">{$t('adventures.edit_collection')}: {originalName}</h3>
<div <div
class="modal-action items-center" class="modal-action items-center"
style="display: flex; flex-direction: column; align-items: center; width: 100%;" style="display: flex; flex-direction: column; align-items: center; width: 100%;"
@ -97,7 +98,7 @@
bind:value={collectionToEdit.id} bind:value={collectionToEdit.id}
class="input input-bordered w-full max-w-xs mt-1" class="input input-bordered w-full max-w-xs mt-1"
/> />
<label for="name">Name</label><br /> <label for="name">{$t('adventures.name')}</label><br />
<input <input
type="text" type="text"
name="name" name="name"
@ -107,7 +108,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="date">Description <Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label <label for="date"
>{$t('adventures.description')}
<Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br /> ><br />
<div class="flex"> <div class="flex">
<input <input
@ -127,7 +130,8 @@
> --> > -->
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="start_date">Start Date <Calendar class="inline-block mb-1 w-6 h-6" /></label <label for="start_date"
>{$t('adventures.start_date')} <Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="date" type="date"
@ -138,8 +142,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="end_date">End Date <Calendar class="inline-block mb-1 w-6 h-6" /></label><br <label for="end_date"
/> >{$t('adventures.end_date')} <Calendar class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="date" type="date"
id="end_date" id="end_date"
@ -149,7 +154,7 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="end_date">Link </label><br /> <label for="end_date">{$t('adventures.link')} </label><br />
<input <input
type="url" type="url"
id="link" id="link"
@ -160,8 +165,9 @@
</div> </div>
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="is_public">Public <Earth class="inline-block -mt-1 mb-1 w-6 h-6" /></label><br <label for="is_public"
/> >{$t('adventures.public')} <Earth class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br />
<input <input
type="checkbox" type="checkbox"
class="toggle toggle-primary" class="toggle toggle-primary"
@ -173,7 +179,7 @@
{#if collectionToEdit.is_public} {#if collectionToEdit.is_public}
<div class="bg-neutral p-4 rounded-md shadow-sm"> <div class="bg-neutral p-4 rounded-md shadow-sm">
<p class=" font-semibold">Share this Adventure!</p> <p class=" font-semibold">{$t('adventures.share_adventure')}</p>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<p class="text-card-foreground font-mono"> <p class="text-card-foreground font-mono">
{window.location.origin}/collections/{collectionToEdit.id} {window.location.origin}/collections/{collectionToEdit.id}
@ -187,7 +193,7 @@
}} }}
class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2" class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2"
> >
Copy Link {$t('adventures.copy_link')}
</button> </button>
</div> </div>
</div> </div>
@ -195,7 +201,7 @@
<button type="submit" class="btn btn-primary mr-4 mt-4" on:click={submit}>Edit</button> <button type="submit" class="btn btn-primary mr-4 mt-4" on:click={submit}>Edit</button>
<!-- if there is a button in form, it will close the modal --> <!-- if there is a button in form, it will close the modal -->
<button class="btn mt-4" on:click={close}>Close</button> <button class="btn mt-4" on:click={close}>{$t('about.close')}</button>
</form> </form>
<div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div> <div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div>
</div> </div>

View file

@ -6,6 +6,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
let modal: HTMLDialogElement; let modal: HTMLDialogElement;
import { t } from 'svelte-i18n';
console.log(transportationToEdit.id); console.log(transportationToEdit.id);
@ -64,7 +65,7 @@
transportationToEdit.date && transportationToEdit.date &&
transportationToEdit.date > transportationToEdit.end_date transportationToEdit.date > transportationToEdit.end_date
) { ) {
addToast('error', 'End date cannot be before start date'); addToast('error', $t('adventures.start_before_end_error'));
return; return;
} }
// make sure end_date has a start_date // make sure end_date has a start_date
@ -83,11 +84,11 @@
transportationToEdit = result; transportationToEdit = result;
addToast('success', 'Transportation edited successfully!'); addToast('success', $t('transportation.transportation_edit_success'));
dispatch('saveEdit', transportationToEdit); dispatch('saveEdit', transportationToEdit);
close(); close();
} else { } else {
addToast('error', 'Error editing transportaion'); addToast('error', $t('transportation.error_editing_transportation'));
} }
} }
</script> </script>
@ -96,7 +97,7 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">Edit Transportation: {originalName}</h3> <h3 class="font-bold text-lg">{$t('transportation.edit_transportation')}: {originalName}</h3>
<div <div
class="modal-action items-center" class="modal-action items-center"
style="display: flex; flex-direction: column; align-items: center; width: 100%;" style="display: flex; flex-direction: column; align-items: center; width: 100%;"
@ -122,26 +123,28 @@
class="input input-bordered w-full max-w-xs mt-1" class="input input-bordered w-full max-w-xs mt-1"
/> />
<div class="mb-2"> <div class="mb-2">
<label for="type">Type <PlaneCar class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="type"
>{$t('transportation.type')} <PlaneCar class="inline-block mb-1 w-6 h-6" /></label
><br />
<select <select
class="select select-bordered w-full max-w-xs" class="select select-bordered w-full max-w-xs"
name="type" name="type"
id="type" id="type"
bind:value={transportationToEdit.type} bind:value={transportationToEdit.type}
> >
<option disabled selected>Transport Type</option> <option disabled selected>{$t('transportation.type')}</option>
<option value="car">Car</option> <option value="car">{$t('transportation.modes.car')}</option>
<option value="plane">Plane</option> <option value="plane">{$t('transportation.modes.plane')}</option>
<option value="train">Train</option> <option value="train">{$t('transportation.modes.train')}</option>
<option value="bus">Bus</option> <option value="bus">{$t('transportation.modes.bus')}</option>
<option value="boat">Boat</option> <option value="boat">{$t('transportation.modes.boat')}</option>
<option value="bike">Bike</option> <option value="bike">{$t('transportation.modes.bike')}</option>
<option value="walking">Walking</option> <option value="walking">{$t('transportation.modes.walking')}</option>
<option value="other">Other</option> <option value="other">{$t('transportation.modes.other')}</option>
</select> </select>
</div> </div>
<label for="name">Name</label><br /> <label for="name">{$t('adventures.name')}</label><br />
<input <input
type="text" type="text"
name="name" name="name"
@ -151,7 +154,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="date">Description <Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label <label for="date"
>{$t('adventures.description')}
<Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br /> ><br />
<div class="flex"> <div class="flex">
<input <input
@ -164,9 +169,10 @@
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="start_date" <label for="start_date"
>{transportationToEdit.date ? 'Start ' : ''}Date & Time <Calendar >{transportationToEdit.date ? `${$t('transportation.start')} ` : ''}{$t(
class="inline-block mb-1 w-6 h-6" 'transportation.date_and_time'
/></label )}
<Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="datetime-local" type="datetime-local"
@ -181,7 +187,8 @@
{#if transportationToEdit.date} {#if transportationToEdit.date}
<div class="mb-2"> <div class="mb-2">
<label for="end_date" <label for="end_date"
>End Date & Time <Calendar class="inline-block mb-1 w-6 h-6" /></label >{$t('transportation.end_date_time')}
<Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="datetime-local" type="datetime-local"
@ -195,7 +202,9 @@
</div> </div>
{/if} {/if}
<div class="mb-2"> <div class="mb-2">
<label for="rating">Rating <Star class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="rating"
>{$t('adventures.rating')} <Star class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="number" type="number"
max="5" max="5"
@ -207,7 +216,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="rating">Link <LinkVariant class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="rating"
>{$t('adventures.link')} <LinkVariant class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="url" type="url"
id="link" id="link"
@ -220,7 +231,8 @@
{#if transportationToEdit.type == 'plane'} {#if transportationToEdit.type == 'plane'}
<div class="mb-2"> <div class="mb-2">
<label for="flight_number" <label for="flight_number"
>Flight Number <Airplane class="inline-block mb-1 w-6 h-6" /></label >{$t('transportation.flight_number')}
<Airplane class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -232,7 +244,9 @@
</div> </div>
{/if} {/if}
<div class="mb-2"> <div class="mb-2">
<label for="rating">From Location <MapMarker class="inline-block mb-1 w-6 h-6" /></label <label for="rating"
>{$t('transportation.from_location')}
<MapMarker class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -243,7 +257,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="rating">To Location <MapMarker class="inline-block mb-1 w-6 h-6" /></label <label for="rating"
>{$t('transportation.to_location')}
<MapMarker class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -255,9 +271,9 @@
</div> </div>
</div> </div>
<button type="submit" class="btn btn-primary mr-4 mt-4">Edit</button> <button type="submit" class="btn btn-primary mr-4 mt-4">{$t('transportation.edit')}</button>
<!-- if there is a button in form, it will close the modal --> <!-- if there is a button in form, it will close the modal -->
<button class="btn mt-4" on:click={close}>Close</button> <button class="btn mt-4" on:click={close}>{$t('about.close')}</button>
</form> </form>
<div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div> <div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div>
</div> </div>

View file

@ -2,7 +2,7 @@
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { Adventure, Collection } from '$lib/types'; import type { Adventure, Collection } from '$lib/types';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { enhance } from '$app/forms'; import { t } from 'svelte-i18n';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
import Calendar from '~icons/mdi/calendar'; import Calendar from '~icons/mdi/calendar';
@ -45,18 +45,18 @@
// make sure that start_date is before end_date // make sure that start_date is before end_date
if (new Date(newCollection.start_date ?? '') > new Date(newCollection.end_date ?? '')) { if (new Date(newCollection.start_date ?? '') > new Date(newCollection.end_date ?? '')) {
addToast('error', 'Start date must be before end date'); addToast('error', $t('adventures.start_before_end_error'));
return; return;
} }
// make sure end date has a start date // make sure end date has a start date
if (newCollection.end_date && !newCollection.start_date) { if (newCollection.end_date && !newCollection.start_date) {
addToast('error', 'Please provide a start date'); addToast('error', $t('adventures.no_start_date'));
return; return;
} }
if (newCollection.start_date && !newCollection.end_date) { if (newCollection.start_date && !newCollection.end_date) {
addToast('error', 'Please provide an end date'); addToast('error', $t('adventures.no_end_date'));
return; return;
} }
@ -80,10 +80,10 @@
newCollection.user_id = user_id; newCollection.user_id = user_id;
console.log(newCollection); console.log(newCollection);
dispatch('create', newCollection); dispatch('create', newCollection);
addToast('success', 'Collection created successfully!'); addToast('success', $t('collection.collection_created'));
close(); close();
} else { } else {
addToast('error', 'Error creating collection'); addToast('error', $t('collection.error_creating_collection'));
} }
} }
} }
@ -95,7 +95,7 @@
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">New Collection</h3> <h3 class="font-bold text-lg">{$t('collection.new_collection')}</h3>
<div <div
class="modal-action items-center" class="modal-action items-center"
style="display: flex; flex-direction: column; align-items: center; width: 100%;" style="display: flex; flex-direction: column; align-items: center; width: 100%;"
@ -107,7 +107,7 @@
action="/collections?/create" action="/collections?/create"
> >
<div class="mb-2"> <div class="mb-2">
<label for="name">Name</label><br /> <label for="name">{$t('adventures.name')}</label><br />
<input <input
type="text" type="text"
id="name" id="name"
@ -119,7 +119,9 @@
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="description" <label for="description"
>Description<iconify-icon icon="mdi:notebook" class="text-lg ml-1 -mb-0.5" >$t('adventures.description')<iconify-icon
icon="mdi:notebook"
class="text-lg ml-1 -mb-0.5"
></iconify-icon></label ></iconify-icon></label
><br /> ><br />
<div class="flex"> <div class="flex">
@ -132,7 +134,8 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="start_date">Start Date <Calendar class="inline-block mb-1 w-6 h-6" /></label <label for="start_date"
>{$t('adventures.start_date')} <Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="date" type="date"
@ -143,8 +146,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="end_date">End Date <Calendar class="inline-block mb-1 w-6 h-6" /></label><br <label for="end_date"
/> >{$t('adventures.end_date')} <Calendar class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="date" type="date"
id="end_date" id="end_date"
@ -154,7 +158,7 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="end_date">Link </label><br /> <label for="end_date">{$t('adventures.link')} </label><br />
<input <input
type="url" type="url"
id="link" id="link"
@ -164,8 +168,10 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<button type="submit" class="btn btn-primary mr-4 mt-4">Create</button> <button type="submit" class="btn btn-primary mr-4 mt-4">
<button type="button" class="btn mt-4" on:click={close}>Close</button> {$t('collection.create')}
</button>
<button type="button" class="btn mt-4" on:click={close}>{$t('about.close')}</button>
</div> </div>
</div> </div>
</form> </form>

View file

@ -1,27 +1,11 @@
<script lang="ts"> <script lang="ts">
// let newTransportation: Transportation = {
// id:NaN,
// user_id: NaN,
// type: '',
// name: '',
// description: null,
// rating: NaN,
// link: null,
// date: null,
// flight_number: null,
// from_location: null,
// to_location: null,
// is_public: false,
// collection: null,
// created_at: '',
// updated_at: ''
// };
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { Collection, Transportation } from '$lib/types'; import type { Collection, Transportation } from '$lib/types';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
let modal: HTMLDialogElement; let modal: HTMLDialogElement;
import { t } from 'svelte-i18n';
export let collection: Collection; export let collection: Collection;
@ -74,7 +58,7 @@
// make sure there is a start date if there is an end date // make sure there is a start date if there is an end date
if (formData.get('end_date') && !formData.get('date')) { if (formData.get('end_date') && !formData.get('date')) {
addToast('error', 'Please provide a start date'); addToast('error', $t('transportation.provide_start_date'));
return; return;
} }
@ -86,11 +70,11 @@
if (response.ok) { if (response.ok) {
const result = await response.json(); const result = await response.json();
addToast('success', 'Transportation added successfully!'); addToast('success', $t('transportation.transportation_added'));
dispatch('add', result); dispatch('add', result);
close(); close();
} else { } else {
addToast('error', 'Error editing transportation'); addToast('error', $t('transportation.error_editing_transportation'));
} }
} }
</script> </script>
@ -99,22 +83,13 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">New Transportation</h3> <h3 class="font-bold text-lg">{$t('transportation.new_transportation')}</h3>
<div <div
class="modal-action items-center" class="modal-action items-center"
style="display: flex; flex-direction: column; align-items: center; width: 100%;" style="display: flex; flex-direction: column; align-items: center; width: 100%;"
> >
<form method="post" style="width: 100%;" on:submit={handleSubmit}> <form method="post" style="width: 100%;" on:submit={handleSubmit}>
<div class="mb-2"> <div class="mb-2">
<!-- <input
type="text"
id="id"
name="id"
hidden
readonly
bind:value={newTransportation.id}
class="input input-bordered w-full max-w-xs mt-1"
/> -->
<input <input
type="text" type="text"
id="collection" id="collection"
@ -134,26 +109,28 @@
class="input input-bordered w-full max-w-xs mt-1" class="input input-bordered w-full max-w-xs mt-1"
/> />
<div class="mb-2"> <div class="mb-2">
<label for="type">Type <PlaneCar class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="type"
>{$t('transportation.type')} <PlaneCar class="inline-block mb-1 w-6 h-6" /></label
><br />
<select <select
class="select select-bordered w-full max-w-xs" class="select select-bordered w-full max-w-xs"
name="type" name="type"
id="type" id="type"
bind:value={type} bind:value={type}
> >
<option disabled selected>Transport Type</option> <option disabled selected>{$t('transportation.type')}</option>
<option value="car">Car</option> <option value="car">{$t('transportation.modes.car')}</option>
<option value="plane">Plane</option> <option value="plane">{$t('transportation.modes.plane')}</option>
<option value="train">Train</option> <option value="train">{$t('transportation.modes.train')}</option>
<option value="bus">Bus</option> <option value="bus">{$t('transportation.modes.bus')}</option>
<option value="boat">Boat</option> <option value="boat">{$t('transportation.modes.boat')}</option>
<option value="bike">Bike</option> <option value="bike">{$t('transportation.modes.bike')}</option>
<option value="walking">Walking</option> <option value="walking">{$t('transportation.modes.walking')}</option>
<option value="other">Other</option> <option value="other">{$t('transportation.modes.other')}</option>
</select> </select>
</div> </div>
<label for="name">Name</label><br /> <label for="name">{$t('adventures.name')}</label><br />
<input <input
type="text" type="text"
name="name" name="name"
@ -162,7 +139,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="date">Description <Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label <label for="date"
>{$t('adventures.description')}
<Notebook class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br /> ><br />
<div class="flex"> <div class="flex">
<input <input
@ -174,7 +153,8 @@
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="start_date" <label for="start_date"
>Start Date & Time <Calendar class="inline-block mb-1 w-6 h-6" /></label >{$t('transportation.date_time')}
<Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="datetime-local" type="datetime-local"
@ -188,7 +168,8 @@
<div class="mb-2"> <div class="mb-2">
<label for="end_date" <label for="end_date"
>End Date & Time <Calendar class="inline-block mb-1 w-6 h-6" /></label >{$t('transportation.end_date_time')}
<Calendar class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="datetime-local" type="datetime-local"
@ -201,7 +182,9 @@
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="rating">Rating <Star class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="rating"
>{$t('adventures.rating')} <Star class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="number" type="number"
max="5" max="5"
@ -212,7 +195,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="rating">Link <LinkVariant class="inline-block mb-1 w-6 h-6" /></label><br /> <label for="rating"
>{$t('adventures.link')} <LinkVariant class="inline-block mb-1 w-6 h-6" /></label
><br />
<input <input
type="url" type="url"
id="link" id="link"
@ -224,7 +209,8 @@
{#if type == 'plane'} {#if type == 'plane'}
<div class="mb-2"> <div class="mb-2">
<label for="flight_number" <label for="flight_number"
>Flight Number <Airplane class="inline-block mb-1 w-6 h-6" /></label >{$t('transportation.flight_number')}
<Airplane class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -235,7 +221,9 @@
</div> </div>
{/if} {/if}
<div class="mb-2"> <div class="mb-2">
<label for="rating">From Location <MapMarker class="inline-block mb-1 w-6 h-6" /></label <label for="rating"
>{$t('transportation.from_location')}
<MapMarker class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -245,7 +233,9 @@
/> />
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label for="rating">To Location <MapMarker class="inline-block mb-1 w-6 h-6" /></label <label for="rating"
>{$t('transportation.to_location')}
<MapMarker class="inline-block mb-1 w-6 h-6" /></label
><br /> ><br />
<input <input
type="text" type="text"
@ -256,9 +246,9 @@
</div> </div>
</div> </div>
<button type="submit" class="btn btn-primary mr-4 mt-4">Edit</button> <button type="submit" class="btn btn-primary mr-4 mt-4">{$t('transportation.edit')}</button>
<!-- if there is a button in form, it will close the modal --> <!-- if there is a button in form, it will close the modal -->
<button class="btn mt-4" on:click={close}>Close</button> <button class="btn mt-4" on:click={close}>{$t('about.close')}</button>
</form> </form>
<div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div> <div class="flex items-center justify-center flex-wrap gap-4 mt-4"></div>
</div> </div>

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation'; import { t } from 'svelte-i18n';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
import type { Collection, Note, User } from '$lib/types'; import type { Collection, Note, User } from '$lib/types';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
@ -22,10 +22,10 @@
method: 'DELETE' method: 'DELETE'
}); });
if (res.ok) { if (res.ok) {
addToast('success', 'Note deleted successfully'); addToast('success', $t('notes.note_deleted'));
dispatch('delete', note.id); dispatch('delete', note.id);
} else { } else {
addToast('Failed to delete note', 'error'); addToast($t('notes.note_delete_error'), 'error');
} }
} }
</script> </script>
@ -39,9 +39,12 @@
{note.name} {note.name}
</h2> </h2>
</div> </div>
<div class="badge badge-primary">Note</div> <div class="badge badge-primary">{$t('adventures.note')}</div>
{#if note.links && note.links.length > 0} {#if note.links && note.links.length > 0}
<p>{note.links.length} {note.links.length > 1 ? 'Links' : 'Link'}</p> <p>
{note.links.length}
{note.links.length > 1 ? $t('adventures.links') : $t('adventures.link')}
</p>
{/if} {/if}
{#if note.date && note.date !== ''} {#if note.date && note.date !== ''}
<div class="inline-flex items-center"> <div class="inline-flex items-center">
@ -54,7 +57,7 @@
><Launch class="w-6 h-6" />Open Details</button ><Launch class="w-6 h-6" />Open Details</button
> --> > -->
<button class="btn btn-neutral-200 mb-2" on:click={editNote}> <button class="btn btn-neutral-200 mb-2" on:click={editNote}>
<Launch class="w-6 h-6" />Open <Launch class="w-6 h-6" />{$t('notes.open')}
</button> </button>
{#if note.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))} {#if note.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<button <button

View file

@ -4,7 +4,7 @@
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import ShareModal from './ShareModal.svelte'; import { t } from 'svelte-i18n';
let modal: HTMLDialogElement; let modal: HTMLDialogElement;
export let note: Note | null = null; export let note: Note | null = null;
@ -98,8 +98,7 @@
} }
} else { } else {
let data = await res.json(); let data = await res.json();
console.error('Failed to save note', data); console.error($t('notes.failed_to_save'), data);
console.error('Failed to save note');
} }
} }
} }
@ -109,15 +108,15 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex --> <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0"> <div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">Note Editor</h3> <h3 class="font-bold text-lg">{$t('notes.note_editor')}</h3>
{#if initialName} {#if initialName}
<p class="font-semibold text-md mb-2">Editing note {initialName}</p> <p class="font-semibold text-md mb-2">{$t('notes.editing_note')} {initialName}</p>
{/if} {/if}
{#if (note && user?.pk == note?.user_id) || (collection && user && collection.shared_with.includes(user.uuid)) || !note} {#if (note && user?.pk == note?.user_id) || (collection && user && collection.shared_with.includes(user.uuid)) || !note}
<form on:submit|preventDefault> <form on:submit|preventDefault>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="name">Name</label> <label for="name">{$t('adventures.name')}</label>
<input <input
type="text" type="text"
id="name" id="name"
@ -126,7 +125,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Date</label> <label for="content">{$t('adventures.date')}</label>
<input <input
type="date" type="date"
id="date" id="date"
@ -138,7 +137,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Content</label> <label for="content">{$t('notes.content')}</label>
<textarea <textarea
id="content" id="content"
class="textarea textarea-bordered" class="textarea textarea-bordered"
@ -147,11 +146,11 @@
></textarea> ></textarea>
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Links</label> <label for="content">{$t('adventures.links')}</label>
<input <input
type="url" type="url"
class="input input-bordered w-full mb-1" class="input input-bordered w-full mb-1"
placeholder="Add a link (e.g. https://example.com)" placeholder="${$t('notes.add_a_link')} (e.g. https://example.com)"
bind:value={newLink} bind:value={newLink}
on:keydown={(e) => { on:keydown={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
@ -160,7 +159,9 @@
} }
}} }}
/> />
<button type="button" class="btn btn-sm btn-primary" on:click={addLink}>Add</button> <button type="button" class="btn btn-sm btn-primary" on:click={addLink}
>{$t('adventures.add')}</button
>
</div> </div>
{#if newNote.links.length > 0} {#if newNote.links.length > 0}
<ul class="list-none"> <ul class="list-none">
@ -174,7 +175,7 @@
newNote.links = newNote.links.filter((_, index) => index !== i); newNote.links = newNote.links.filter((_, index) => index !== i);
}} }}
> >
Remove {$t('adventures.remove')}
</button> </button>
</li> </li>
{/each} {/each}
@ -200,8 +201,8 @@
</div> </div>
{/if} {/if}
<button class="btn btn-primary mr-1" on:click={save}>Save</button> <button class="btn btn-primary mr-1" on:click={save}>{$t('notes.save')}</button>
<button class="btn btn-neutral" on:click={close}>Close</button> <button class="btn btn-neutral" on:click={close}>{$t('about.close')}</button>
{#if collection.is_public} {#if collection.is_public}
<div role="alert" class="alert mt-4"> <div role="alert" class="alert mt-4">
@ -218,14 +219,14 @@
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path> ></path>
</svg> </svg>
<span>This note is public because it is in a public collection.</span> <span>{$t('notes.note_public')}</span>
</div> </div>
{/if} {/if}
</form> </form>
{:else} {:else}
<form> <form>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="name">Name</label> <label for="name">{$t('adventures.public')}</label>
<input <input
type="text" type="text"
id="name" id="name"
@ -235,7 +236,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Date</label> <label for="content">{$t('adventures.date')}</label>
<input <input
type="date" type="date"
id="date" id="date"
@ -248,7 +249,7 @@
/> />
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Content</label> <label for="content">{$t('notes.content')}</label>
<textarea <textarea
id="content" id="content"
class="textarea textarea-bordered" class="textarea textarea-bordered"
@ -258,7 +259,7 @@
></textarea> ></textarea>
</div> </div>
<div class="form-control mb-2"> <div class="form-control mb-2">
<label for="content">Links</label> <label for="content">{$t('adventures.links')}</label>
</div> </div>
{#if newNote.links.length > 0} {#if newNote.links.length > 0}
<ul class="list-none"> <ul class="list-none">
@ -270,7 +271,7 @@
</ul> </ul>
{/if} {/if}
<button class="btn btn-neutral" on:click={close}>Close</button> <button class="btn btn-neutral" on:click={close}>{$t('about.close')}</button>
</form> </form>
{/if} {/if}
</div> </div>

View file

@ -4,6 +4,7 @@
import FileDocumentEdit from '~icons/mdi/file-document-edit'; import FileDocumentEdit from '~icons/mdi/file-document-edit';
import type { Collection, Transportation, User } from '$lib/types'; import type { Collection, Transportation, User } from '$lib/types';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
import { t } from 'svelte-i18n';
import ArrowDownThick from '~icons/mdi/arrow-down-thick'; import ArrowDownThick from '~icons/mdi/arrow-down-thick';
@ -25,10 +26,9 @@
} }
}); });
if (!res.ok) { if (!res.ok) {
console.log('Error deleting transportation'); console.log($t('transportation.transportation_delete_error'));
} else { } else {
console.log('Collection deleted'); addToast('info', $t('transportation.transportation_deleted'));
addToast('info', 'Transportation deleted successfully!');
dispatch('delete', transportation.id); dispatch('delete', transportation.id);
} }
} }
@ -39,7 +39,7 @@
> >
<div class="card-body"> <div class="card-body">
<h2 class="card-title overflow-ellipsis">{transportation.name}</h2> <h2 class="card-title overflow-ellipsis">{transportation.name}</h2>
<div class="badge badge-secondary">{transportation.type}</div> <div class="badge badge-secondary">{$t(`transportation.modes.${transportation.type}`)}</div>
<div> <div>
{#if transportation.from_location} {#if transportation.from_location}
<p class="break-words text-wrap">{transportation.from_location}</p> <p class="break-words text-wrap">{transportation.from_location}</p>

View file

@ -79,7 +79,6 @@
"count_txt": "results matching your search", "count_txt": "results matching your search",
"sort": "Sort", "sort": "Sort",
"order_direction": "Order Direction", "order_direction": "Order Direction",
"order_by": "Order By",
"ascending": "Ascending", "ascending": "Ascending",
"descending": "Descending", "descending": "Descending",
"updated": "Updated", "updated": "Updated",
@ -119,6 +118,7 @@
"public_adventure": "Public Adventure", "public_adventure": "Public Adventure",
"location_information": "Location Information", "location_information": "Location Information",
"link": "Link", "link": "Link",
"links": "Links",
"description": "Description", "description": "Description",
"sources": "Sources", "sources": "Sources",
"collection_adventures": "Include Collection Adventures", "collection_adventures": "Include Collection Adventures",
@ -162,6 +162,7 @@
"start_before_end_error": "Start date must be before end date", "start_before_end_error": "Start date must be before end date",
"activity": "Activity", "activity": "Activity",
"actions": "Actions", "actions": "Actions",
"no_end_date": "Please enter an end date",
"see_adventures": "See Adventures", "see_adventures": "See Adventures",
"image_fetch_failed": "Failed to fetch image", "image_fetch_failed": "Failed to fetch image",
"no_location": "Please enter a location", "no_location": "Please enter a location",
@ -183,6 +184,23 @@
"visited_region_check_desc": "By selecting this, the server will check all of your visited adventures and mark the regions they are located in as visited in world travel.", "visited_region_check_desc": "By selecting this, the server will check all of your visited adventures and mark the regions they are located in as visited in world travel.",
"update_visited_regions": "Update Visited Regions", "update_visited_regions": "Update Visited Regions",
"update_visited_regions_disclaimer": "This may take a while depending on the number of adventures you have visited.", "update_visited_regions_disclaimer": "This may take a while depending on the number of adventures you have visited.",
"link_new": "Link New...",
"add_new": "Add New...",
"transportation": "Transportation",
"note": "Note",
"checklist": "Checklist",
"collection_archived": "This collection has been archived.",
"visit_link": "Visit Link",
"collection_completed": "You've completed this collection!",
"collection_stats": "Collection Stats",
"keep_exploring": "Keep Exploring!",
"linked_adventures": "Linked Adventures",
"notes": "Notes",
"checklists": "Checklists",
"transportations": "Transportations",
"itineary_by_date": "Itinerary by Date",
"nothing_planned": "Nothing planned for this day. Enjoy the journey!<",
"days": "days",
"activities": { "activities": {
"general": "General 🌍", "general": "General 🌍",
"outdoor": "Outdoor 🏞️", "outdoor": "Outdoor 🏞️",
@ -261,5 +279,71 @@
"password_does_not_match": "Passwords do not match", "password_does_not_match": "Passwords do not match",
"password_is_required": "Password is required", "password_is_required": "Password is required",
"invalid_token": "Token is invalid or has expired" "invalid_token": "Token is invalid or has expired"
},
"collection": {
"collection_created": "Collection created successfully!",
"error_creating_collection": "Error creating collection",
"new_collection": "New Collection",
"create": "Create",
"collection_edit_success": "Collection edited successfully!",
"error_editing_collection": "Error editing collection",
"edit_collection": "Edit Collection"
},
"notes": {
"note_deleted": "Note deleted successfully!",
"note_delete_error": "Error deleting note",
"open": "Open",
"failed_to_save": "Failed to save note",
"note_editor": "Note Editor",
"editing_note": "Editing note",
"content": "Content",
"save": "Save",
"note_public": "This note is public because it is in a public collection.",
"add_a_link": "Add a link"
},
"checklist": {
"checklist_deleted": "Checklist deleted successfully!",
"checklist_delete_error": "Error deleting checklist",
"failed_to_save": "Failed to save checklist",
"checklist_editor": "Checklist Editor",
"editing_checklist": "Editing checklist",
"item": "Item",
"items": "Items",
"add_item": "Add Item",
"new_item": "New Item",
"save": "Save",
"checklist_public": "This checklist is public because it is in a public collection.",
"item_cannot_be_empty": "Item cannot be empty",
"item_already_exists": "Item already exists"
},
"transportation": {
"transportation_deleted": "Transportation deleted successfully!",
"transportation_delete_error": "Error deleting transportation",
"provide_start_date": "Please provide a start date",
"transport_type": "Transport Type",
"type": "Type",
"transportation_added": "Transportation added successfully!",
"error_editing_transportation": "Error editing transportation",
"new_transportation": "New Transportation",
"date_time": "Start Date & Time",
"end_date_time": "End Date & Time",
"flight_number": "Flight Number",
"from_location": "From Location",
"to_location": "To Location",
"edit": "Edit",
"modes": {
"car": "Car",
"plane": "Plane",
"train": "Train",
"bus": "Bus",
"boat": "Boat",
"bike": "Bike",
"walking": "Walking",
"other": "Other"
},
"transportation_edit_success": "Transportation edited successfully!",
"edit_transportation": "Edit Transportation",
"start": "Start",
"date_and_time": "Date & Time"
} }
} }

View file

@ -4,6 +4,7 @@
import type { PageData } from './$types'; import type { PageData } from './$types';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import Lost from '$lib/assets/undraw_lost.svg'; import Lost from '$lib/assets/undraw_lost.svg';
import { t } from 'svelte-i18n';
import Plus from '~icons/mdi/plus'; import Plus from '~icons/mdi/plus';
import AdventureCard from '$lib/components/AdventureCard.svelte'; import AdventureCard from '$lib/components/AdventureCard.svelte';
@ -106,19 +107,6 @@
} }
} }
function changeType(event: CustomEvent<string>) {
adventures = adventures.map((adventure) => {
if (adventure.id == event.detail) {
if (adventure.type == 'visited') {
adventure.type = 'planned';
} else {
adventure.type = 'visited';
}
}
return adventure;
});
}
let adventureToEdit: Adventure | null = null; let adventureToEdit: Adventure | null = null;
let transportationToEdit: Transportation; let transportationToEdit: Transportation;
let isAdventureModalOpen: boolean = false; let isAdventureModalOpen: boolean = false;
@ -255,14 +243,15 @@
<img src={Lost} alt="Lost" class="w-1/2" /> <img src={Lost} alt="Lost" class="w-1/2" />
</div> </div>
<h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"> <h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
Adventure not Found {$t('adventures.not_found')}
</h1> </h1>
<p class="mt-4 text-muted-foreground"> <p class="mt-4 text-muted-foreground">
The adventure you were looking for could not be found. Please try a different adventure or {$t('adventures.not_found_desc')}
check back later.
</p> </p>
<div class="mt-6"> <div class="mt-6">
<button class="btn btn-primary" on:click={() => goto('/')}>Homepage</button> <button class="btn btn-primary" on:click={() => goto('/')}
>{$t('adventures.homepage')}</button
>
</div> </div>
</div> </div>
</div> </div>
@ -287,17 +276,17 @@
class="dropdown-content z-[1] menu p-4 shadow bg-base-300 text-base-content rounded-box w-52 gap-4" class="dropdown-content z-[1] menu p-4 shadow bg-base-300 text-base-content rounded-box w-52 gap-4"
> >
{#if collection.user_id === data.user.pk} {#if collection.user_id === data.user.pk}
<p class="text-center font-bold text-lg">Link new...</p> <p class="text-center font-bold text-lg">{$t('adventures.link_new')}</p>
<button <button
class="btn btn-primary" class="btn btn-primary"
on:click={() => { on:click={() => {
isShowingLinkModal = true; isShowingLinkModal = true;
}} }}
> >
Adventure</button {$t('adventures.adventure')}</button
> >
{/if} {/if}
<p class="text-center font-bold text-lg">Add new...</p> <p class="text-center font-bold text-lg">{$t('adventures.add_new')}</p>
<button <button
class="btn btn-primary" class="btn btn-primary"
on:click={() => { on:click={() => {
@ -305,7 +294,7 @@
adventureToEdit = null; adventureToEdit = null;
}} }}
> >
Adventure</button {$t('adventures.adventure')}</button
> >
<button <button
@ -315,7 +304,7 @@
newType = ''; newType = '';
}} }}
> >
Transportation</button {$t('adventures.transportation')}</button
> >
<button <button
class="btn btn-primary" class="btn btn-primary"
@ -325,7 +314,7 @@
noteToEdit = null; noteToEdit = null;
}} }}
> >
Note</button {$t('adventures.note')}</button
> >
<button <button
class="btn btn-primary" class="btn btn-primary"
@ -335,7 +324,7 @@
checklistToEdit = null; checklistToEdit = null;
}} }}
> >
Checklist</button {$t('adventures.checklist')}</button
> >
<!-- <button <!-- <button
@ -363,7 +352,7 @@
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/> />
</svg> </svg>
<span>This collection has been archived.</span> <span>{$t('adventures.collection_archived')}</span>
</div> </div>
</div> </div>
{/if} {/if}
@ -373,7 +362,7 @@
{#if collection.link} {#if collection.link}
<div class="flex items-center justify-center mb-2"> <div class="flex items-center justify-center mb-2">
<a href={collection.link} target="_blank" rel="noopener noreferrer" class="btn btn-primary"> <a href={collection.link} target="_blank" rel="noopener noreferrer" class="btn btn-primary">
Visit Link {$t('adventures.visit_link')}
</a> </a>
</div> </div>
{/if} {/if}
@ -385,12 +374,12 @@
<div class="flex items-center justify-center mb-4"> <div class="flex items-center justify-center mb-4">
<div class="stats shadow bg-base-300"> <div class="stats shadow bg-base-300">
<div class="stat"> <div class="stat">
<div class="stat-title">Collection Stats</div> <div class="stat-title">{$t('adventures.collection_stats')}</div>
<div class="stat-value">{numVisited}/{numAdventures} Visited</div> <div class="stat-value">{numVisited}/{numAdventures} Visited</div>
{#if numAdventures === numVisited} {#if numAdventures === numVisited}
<div class="stat-desc">You've completed this collection! 🎉!</div> <div class="stat-desc">{$t('adventures.collection_completed')}</div>
{:else} {:else}
<div class="stat-desc">Keep exploring!</div> <div class="stat-desc">{$t('adventures.keep_exploring')}</div>
{/if} {/if}
</div> </div>
</div> </div>
@ -401,7 +390,7 @@
<NotFound error={undefined} /> <NotFound error={undefined} />
{/if} {/if}
{#if adventures.length > 0} {#if adventures.length > 0}
<h1 class="text-center font-bold text-4xl mt-4 mb-2">Linked Adventures</h1> <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"> <div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
{#each adventures as adventure} {#each adventures as adventure}
@ -411,7 +400,6 @@
on:delete={deleteAdventure} on:delete={deleteAdventure}
type={adventure.type} type={adventure.type}
{adventure} {adventure}
on:typeChange={changeType}
{collection} {collection}
/> />
{/each} {/each}
@ -419,7 +407,7 @@
{/if} {/if}
{#if transportations.length > 0} {#if transportations.length > 0}
<h1 class="text-center font-bold text-4xl mt-4 mb-4">Transportation</h1> <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"> <div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
{#each transportations as transportation} {#each transportations as transportation}
<TransportationCard <TransportationCard
@ -439,7 +427,7 @@
{/if} {/if}
{#if notes.length > 0} {#if notes.length > 0}
<h1 class="text-center font-bold text-4xl mt-4 mb-4">Notes</h1> <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"> <div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
{#each notes as note} {#each notes as note}
<NoteCard <NoteCard
@ -459,7 +447,7 @@
{/if} {/if}
{#if checklists.length > 0} {#if checklists.length > 0}
<h1 class="text-center font-bold text-4xl mt-4 mb-4">Checklists</h1> <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"> <div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
{#each checklists as checklist} {#each checklists as checklist}
<ChecklistCard <ChecklistCard
@ -480,9 +468,12 @@
{#if collection.start_date && collection.end_date} {#if collection.start_date && collection.end_date}
<div class="divider"></div> <div class="divider"></div>
<h1 class="text-center font-bold text-4xl mt-4">Itinerary by Date</h1> <h1 class="text-center font-bold text-4xl mt-4">{$t('adventures.itineary_by_date')}</h1>
{#if numberOfDays} {#if numberOfDays}
<p class="text-center text-lg pl-16 pr-16">Duration: {numberOfDays} days</p> <p class="text-center text-lg pl-16 pr-16">
{$t('adventures.duration')}: {numberOfDays}
{$t('adventures.days')}
</p>
{/if} {/if}
<p class="text-center text-lg pl-16 pr-16"> <p class="text-center text-lg pl-16 pr-16">
Dates: {new Date(collection.start_date).toLocaleDateString(undefined, { timeZone: 'UTC' })} - {new Date( Dates: {new Date(collection.start_date).toLocaleDateString(undefined, { timeZone: 'UTC' })} - {new Date(
@ -531,7 +522,6 @@
on:delete={deleteAdventure} on:delete={deleteAdventure}
type={adventure.type} type={adventure.type}
{adventure} {adventure}
on:typeChange={changeType}
/> />
{/each} {/each}
{/if} {/if}
@ -582,7 +572,7 @@
{/if} {/if}
{#if dayAdventures.length == 0 && dayTransportations.length == 0 && dayNotes.length == 0 && dayChecklists.length == 0} {#if dayAdventures.length == 0 && dayTransportations.length == 0 && dayNotes.length == 0 && dayChecklists.length == 0}
<p class="text-center text-lg mt-2">Nothing planned for this day. Enjoy the journey!</p> <p class="text-center text-lg mt-2">{$t('adventures.nothing_planned')}</p>
{/if} {/if}
</div> </div>
{/each} {/each}
@ -605,11 +595,6 @@
<p class="font-semibold text-black text-md"> <p class="font-semibold text-black text-md">
{adventure.type.charAt(0).toUpperCase() + adventure.type.slice(1)} {adventure.type.charAt(0).toUpperCase() + adventure.type.slice(1)}
</p> </p>
<!-- <p>
{adventure.
? new Date(adventure.date).toLocaleDateString(undefined, { timeZone: 'UTC' })
: ''}
</p> -->
</Popup> </Popup>
</DefaultMarker> </DefaultMarker>
{/if} {/if}
@ -622,7 +607,7 @@
<title <title
>{data.props.adventure && data.props.adventure.name >{data.props.adventure && data.props.adventure.name
? `${data.props.adventure.name}` ? `${data.props.adventure.name}`
: 'Collection'}</title : $t('adventures.collection')}</title
> >
<meta <meta
name="description" name="description"