mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-22 22:39:36 +02:00
Shared with collaborative editing
This commit is contained in:
parent
f150423c1e
commit
ba89f90e53
10 changed files with 38 additions and 28 deletions
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
**Documentation can be found [here](https://docs.adventurelog.app).**
|
**Documentation can be found [here](https://docs.adventurelog.app).**
|
||||||
|
|
||||||
|
**Join the AdventureLog Community Discord Server [here](https://discord.gg/wRbQ9Egr8C).**
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import type { Adventure, User } from '$lib/types';
|
import type { Adventure, Collection, User } from '$lib/types';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
import Launch from '~icons/mdi/launch';
|
import Launch from '~icons/mdi/launch';
|
||||||
|
@ -21,8 +21,8 @@
|
||||||
import ImageDisplayModal from './ImageDisplayModal.svelte';
|
import ImageDisplayModal from './ImageDisplayModal.svelte';
|
||||||
|
|
||||||
export let type: string;
|
export let type: string;
|
||||||
|
|
||||||
export let user: User | null;
|
export let user: User | null;
|
||||||
|
export let collection: Collection | null = null;
|
||||||
|
|
||||||
let isCollectionModalOpen: boolean = false;
|
let isCollectionModalOpen: boolean = false;
|
||||||
let isWarningModalOpen: boolean = false;
|
let isWarningModalOpen: boolean = false;
|
||||||
|
@ -209,13 +209,11 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{#if adventure.type == 'visited' && user?.pk == adventure.user_id}
|
{#if adventure.type == 'visited'}
|
||||||
<div class="badge badge-primary">Visited</div>
|
<div class="badge badge-primary">Visited</div>
|
||||||
{:else if user?.pk == adventure.user_id && adventure.type == 'planned'}
|
{:else if adventure.type == 'planned'}
|
||||||
<div class="badge badge-secondary">Planned</div>
|
<div class="badge badge-secondary">Planned</div>
|
||||||
{:else if (user?.pk !== adventure.user_id && adventure.type == 'planned') || adventure.type == 'visited'}
|
{:else if adventure.type == 'lodging'}
|
||||||
<div class="badge badge-secondary">Adventure</div>
|
|
||||||
{:else if user?.pk == adventure.user_id && adventure.type == 'lodging'}
|
|
||||||
<div class="badge badge-success">Lodging</div>
|
<div class="badge badge-success">Lodging</div>
|
||||||
{:else if adventure.type == 'dining'}
|
{:else if adventure.type == 'dining'}
|
||||||
<div class="badge badge-accent">Dining</div>
|
<div class="badge badge-accent">Dining</div>
|
||||||
|
@ -254,7 +252,7 @@
|
||||||
<div class="card-actions justify-end mt-2">
|
<div class="card-actions justify-end mt-2">
|
||||||
<!-- action options dropdown -->
|
<!-- action options dropdown -->
|
||||||
{#if type != 'link'}
|
{#if type != 'link'}
|
||||||
{#if user?.pk == adventure.user_id}
|
{#if adventure.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end">
|
||||||
<div tabindex="0" role="button" class="btn btn-neutral-200">
|
<div tabindex="0" role="button" class="btn btn-neutral-200">
|
||||||
<DotsHorizontal class="w-6 h-6" />
|
<DotsHorizontal class="w-6 h-6" />
|
||||||
|
@ -272,18 +270,18 @@
|
||||||
<button class="btn btn-neutral mb-2" on:click={editAdventure}>
|
<button class="btn btn-neutral mb-2" on:click={editAdventure}>
|
||||||
<FileDocumentEdit class="w-6 h-6" />Edit {keyword}
|
<FileDocumentEdit class="w-6 h-6" />Edit {keyword}
|
||||||
</button>
|
</button>
|
||||||
{#if adventure.type == 'visited'}
|
{#if adventure.type == 'visited' && user?.pk == adventure.user_id}
|
||||||
<button class="btn btn-neutral mb-2" on:click={changeType('planned')}
|
<button class="btn btn-neutral mb-2" on:click={changeType('planned')}
|
||||||
><FormatListBulletedSquare class="w-6 h-6" />Change to Plan</button
|
><FormatListBulletedSquare class="w-6 h-6" />Change to Plan</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{#if adventure.type == 'planned'}
|
{#if adventure.type == 'planned' && user?.pk == adventure.user_id}
|
||||||
<button class="btn btn-neutral mb-2" on:click={changeType('visited')}
|
<button class="btn btn-neutral mb-2" on:click={changeType('visited')}
|
||||||
><CheckBold class="w-6 h-6" />Mark Visited</button
|
><CheckBold class="w-6 h-6" />Mark Visited</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- remove from adventure -->
|
<!-- remove from adventure -->
|
||||||
{#if adventure.collection && (adventure.type == 'visited' || adventure.type == 'planned')}
|
{#if adventure.collection && (adventure.type == 'visited' || adventure.type == 'planned') && user?.pk == adventure.user_id}
|
||||||
<button class="btn btn-neutral mb-2" on:click={removeFromCollection}
|
<button class="btn btn-neutral mb-2" on:click={removeFromCollection}
|
||||||
><LinkVariantRemove class="w-6 h-6" />Remove from Collection</button
|
><LinkVariantRemove class="w-6 h-6" />Remove from Collection</button
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
import type { Checklist, 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();
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
export let checklist: Checklist;
|
export let checklist: Checklist;
|
||||||
export let user: User | null = null;
|
export let user: User | null = null;
|
||||||
|
export let collection: Collection | null = null;
|
||||||
|
|
||||||
function editChecklist() {
|
function editChecklist() {
|
||||||
dispatch('edit', checklist);
|
dispatch('edit', checklist);
|
||||||
|
@ -51,10 +52,10 @@
|
||||||
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
|
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
|
||||||
><Launch class="w-6 h-6" />Open Details</button
|
><Launch class="w-6 h-6" />Open Details</button
|
||||||
> -->
|
> -->
|
||||||
<button class="btn btn-neutral 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" />Open
|
||||||
</button>
|
</button>
|
||||||
{#if checklist.user_id == user?.pk}
|
{#if checklist.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
|
||||||
<button
|
<button
|
||||||
id="delete_adventure"
|
id="delete_adventure"
|
||||||
data-umami-event="Delete Checklist"
|
data-umami-event="Delete Checklist"
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
{
|
{
|
||||||
name: newItem,
|
name: newItem,
|
||||||
is_checked: newStatus,
|
is_checked: newStatus,
|
||||||
id: 0,
|
id: '',
|
||||||
user_id: 0,
|
user_id: 0,
|
||||||
checklist: 0,
|
checklist: 0,
|
||||||
created_at: '',
|
created_at: '',
|
||||||
|
@ -135,7 +135,7 @@
|
||||||
<p class="font-semibold text-md mb-2">Editing checklist {initialName}</p>
|
<p class="font-semibold text-md mb-2">Editing checklist {initialName}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if (checklist && user?.pk == checklist?.user_id) || !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">Name</label>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
import type { Note, User } from '$lib/types';
|
import type { Collection, Note, User } from '$lib/types';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
export let note: Note;
|
export let note: Note;
|
||||||
export let user: User | null = null;
|
export let user: User | null = null;
|
||||||
|
export let collection: Collection | null = null;
|
||||||
|
|
||||||
function editNote() {
|
function editNote() {
|
||||||
dispatch('edit', note);
|
dispatch('edit', note);
|
||||||
|
@ -52,10 +53,10 @@
|
||||||
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
|
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
|
||||||
><Launch class="w-6 h-6" />Open Details</button
|
><Launch class="w-6 h-6" />Open Details</button
|
||||||
> -->
|
> -->
|
||||||
<button class="btn btn-neutral 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" />Open
|
||||||
</button>
|
</button>
|
||||||
{#if note.user_id == user?.pk}
|
{#if note.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
|
||||||
<button
|
<button
|
||||||
id="delete_adventure"
|
id="delete_adventure"
|
||||||
data-umami-event="Delete Adventure"
|
data-umami-event="Delete Adventure"
|
||||||
|
|
|
@ -4,6 +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';
|
||||||
let modal: HTMLDialogElement;
|
let modal: HTMLDialogElement;
|
||||||
|
|
||||||
export let note: Note | null = null;
|
export let note: Note | null = null;
|
||||||
|
@ -113,7 +114,7 @@
|
||||||
<p class="font-semibold text-md mb-2">Editing note {initialName}</p>
|
<p class="font-semibold text-md mb-2">Editing note {initialName}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if (note && user?.pk == note?.user_id) || !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">Name</label>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import TrashCanOutline from '~icons/mdi/trash-can-outline';
|
import TrashCanOutline from '~icons/mdi/trash-can-outline';
|
||||||
import FileDocumentEdit from '~icons/mdi/file-document-edit';
|
import FileDocumentEdit from '~icons/mdi/file-document-edit';
|
||||||
import type { Transportation, User } from '$lib/types';
|
import type { Collection, Transportation, User } from '$lib/types';
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
|
|
||||||
import ArrowDownThick from '~icons/mdi/arrow-down-thick';
|
import ArrowDownThick from '~icons/mdi/arrow-down-thick';
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
export let transportation: Transportation;
|
export let transportation: Transportation;
|
||||||
export let user: User | null = null;
|
export let user: User | null = null;
|
||||||
|
export let collection: Collection | null = null;
|
||||||
|
|
||||||
function editTransportation() {
|
function editTransportation() {
|
||||||
dispatch('edit', transportation);
|
dispatch('edit', transportation);
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if user?.pk === transportation.user_id}
|
{#if transportation.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
|
||||||
<div class="card-actions justify-end">
|
<div class="card-actions justify-end">
|
||||||
<button on:click={deleteTransportation} class="btn btn-secondary"
|
<button on:click={deleteTransportation} class="btn btn-secondary"
|
||||||
><TrashCanOutline class="w-5 h-5 mr-1" /></button
|
><TrashCanOutline class="w-5 h-5 mr-1" /></button
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import inspirationalQuotes from './json/quotes.json';
|
import inspirationalQuotes from './json/quotes.json';
|
||||||
import type { Adventure, Checklist, Collection, Note, Transportation } from './types';
|
import type { Adventure, Checklist, Collection, Note, Transportation, User } from './types';
|
||||||
|
|
||||||
export function getRandomQuote() {
|
export function getRandomQuote() {
|
||||||
const quotes = inspirationalQuotes.quotes;
|
const quotes = inspirationalQuotes.quotes;
|
||||||
|
|
|
@ -96,11 +96,13 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if adventure}
|
{#if adventure}
|
||||||
|
{#if data.user && data.user.pk == adventure.user_id}
|
||||||
<div class="fixed bottom-4 right-4 z-[999]">
|
<div class="fixed bottom-4 right-4 z-[999]">
|
||||||
<button class="btn m-1 size-16 btn-primary" on:click={() => (isEditModalOpen = true)}
|
<button class="btn m-1 size-16 btn-primary" on:click={() => (isEditModalOpen = true)}
|
||||||
><ClipboardList class="w-8 h-8" /></button
|
><ClipboardList class="w-8 h-8" /></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="flex flex-col min-h-dvh">
|
<div class="flex flex-col min-h-dvh">
|
||||||
<main class="flex-1">
|
<main class="flex-1">
|
||||||
<div class="max-w-5xl mx-auto p-4 md:p-6 lg:p-8">
|
<div class="max-w-5xl mx-auto p-4 md:p-6 lg:p-8">
|
||||||
|
|
|
@ -404,6 +404,7 @@
|
||||||
type={adventure.type}
|
type={adventure.type}
|
||||||
{adventure}
|
{adventure}
|
||||||
on:typeChange={changeType}
|
on:typeChange={changeType}
|
||||||
|
{collection}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -423,6 +424,7 @@
|
||||||
transportationToEdit = event.detail;
|
transportationToEdit = event.detail;
|
||||||
isTransportationEditModalOpen = true;
|
isTransportationEditModalOpen = true;
|
||||||
}}
|
}}
|
||||||
|
{collection}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -442,6 +444,7 @@
|
||||||
on:delete={(event) => {
|
on:delete={(event) => {
|
||||||
notes = notes.filter((n) => n.id != event.detail);
|
notes = notes.filter((n) => n.id != event.detail);
|
||||||
}}
|
}}
|
||||||
|
{collection}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -461,6 +464,7 @@
|
||||||
checklistToEdit = event.detail;
|
checklistToEdit = event.detail;
|
||||||
isShowingChecklistModal = true;
|
isShowingChecklistModal = true;
|
||||||
}}
|
}}
|
||||||
|
{collection}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue