feat: share list
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
- [x] handle errors
|
- [x] handle errors
|
||||||
- [x] list per URL
|
- [x] list per URL
|
||||||
- [x] home screen
|
- [x] home screen
|
||||||
- [ ] share link
|
- [x] share link
|
||||||
- [ ] fill new list with "fill todo" item
|
- [ ] fill new list with "fill todo" item
|
||||||
- [x] lang in cookies
|
- [x] lang in cookies
|
||||||
- [ ] simple view
|
- [ ] simple view
|
||||||
|
|||||||
@@ -68,10 +68,13 @@
|
|||||||
"task_create_error": "Could not create task",
|
"task_create_error": "Could not create task",
|
||||||
"task_cloned": "Task cloned",
|
"task_cloned": "Task cloned",
|
||||||
"task_deleted": "Task deleted",
|
"task_deleted": "Task deleted",
|
||||||
"task_delete_error": "Could not delete task"
|
"task_delete_error": "Could not delete task",
|
||||||
|
"share_clipboard": "Link copied to clipboard",
|
||||||
|
"share_error": "Could not share link"
|
||||||
},
|
},
|
||||||
"not_found": "Looks like there's nothing here...",
|
"not_found": "Looks like there's nothing here...",
|
||||||
"not_found_button": "Go back to familiar territory",
|
"not_found_button": "Go back to familiar territory",
|
||||||
"home": "A shareable task list with auto resetting items.<br/>Create your list below.",
|
"home": "A shareable task list with auto resetting items.<br/>Create your list below.",
|
||||||
"home_button": "Let's go !"
|
"home_button": "Let's go !",
|
||||||
|
"share_button": "Share my list"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,10 +68,13 @@
|
|||||||
"task_create_error": "Impossible de créer la tâche",
|
"task_create_error": "Impossible de créer la tâche",
|
||||||
"task_cloned": "Tâche clonée",
|
"task_cloned": "Tâche clonée",
|
||||||
"task_deleted": "Tâche supprimée",
|
"task_deleted": "Tâche supprimée",
|
||||||
"task_delete_error": "Impossible de supprimer la tâche"
|
"task_delete_error": "Impossible de supprimer la tâche",
|
||||||
|
"share_clipboard": "Lien copié dans le presse-papier",
|
||||||
|
"share_error": "Impossible de partager le lien"
|
||||||
},
|
},
|
||||||
"not_found": "On dirait qu'il n'y a rien ici...",
|
"not_found": "On dirait qu'il n'y a rien ici...",
|
||||||
"not_found_button": "Retour en terrain connu",
|
"not_found_button": "Retour en terrain connu",
|
||||||
"home": "Une liste de tâches avec réinitialisation automatique des éléments.<br/>Créez ta liste ci-dessous.",
|
"home": "Une liste de tâches avec réinitialisation automatique des éléments.<br/>Créez ta liste ci-dessous.",
|
||||||
"home_button": "C'est parti !"
|
"home_button": "C'est parti !",
|
||||||
|
"share_button": "Partager ma liste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
export async function shareLink(
|
||||||
|
title: string,
|
||||||
|
text: string,
|
||||||
|
url: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
if (navigator.canShare()) {
|
||||||
|
await navigator.share({ title, text, url });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -44,9 +44,9 @@ onBeforeRouteUpdate(updateTitle);
|
|||||||
<dices-icon />
|
<dices-icon />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full px-4">
|
<div class="w-full">
|
||||||
<router-link
|
<router-link
|
||||||
class="btn btn-lg"
|
class="btn btn-lg px-4"
|
||||||
:class="listNameInput.trim().length === 0 ? 'btn-disabled' : ''"
|
:class="listNameInput.trim().length === 0 ? 'btn-disabled' : ''"
|
||||||
:to="`/${listNameInput.trim()}`"
|
:to="`/${listNameInput.trim()}`"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
CircleCheckBigIcon,
|
CircleCheckBigIcon,
|
||||||
CheckCheckIcon,
|
CheckCheckIcon,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
|
Share2Icon
|
||||||
} from "@lucide/vue";
|
} from "@lucide/vue";
|
||||||
const TaskItem = defineAsyncComponent(
|
const TaskItem = defineAsyncComponent(
|
||||||
() => import("@/components/TaskItem.vue"),
|
() => import("@/components/TaskItem.vue"),
|
||||||
@@ -19,6 +20,7 @@ import { booleanCookieRef, enumCookieRef } from "@/lib/cookies";
|
|||||||
import { useAlertStore } from "@/stores/alerts";
|
import { useAlertStore } from "@/stores/alerts";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||||
|
import { shareLink } from "@/lib/share";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
@@ -125,6 +127,18 @@ function onChangeSortReverse() {
|
|||||||
reSortTasks();
|
reSortTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onShare() {
|
||||||
|
shareLink(`Tout Doux - ${list.value ?? ''}`, '', `${document.location.href.split('?')[0] ?? ''}?lang=${i18n.locale.value}`)
|
||||||
|
.then((viaShare) => {
|
||||||
|
if (!viaShare) {
|
||||||
|
alertSuccess(i18n.t("alerts.share_clipboard"));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
alertError(i18n.t("alerts.share_error"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function updateTitle() {
|
function updateTitle() {
|
||||||
if (list.value !== null) {
|
if (list.value !== null) {
|
||||||
document.title = `Tout Doux - ${list.value} (${completedCount.value.toFixed(0)}/${taskCount.value.toFixed(0)})`
|
document.title = `Tout Doux - ${list.value} (${completedCount.value.toFixed(0)}/${taskCount.value.toFixed(0)})`
|
||||||
@@ -227,6 +241,11 @@ onBeforeRouteUpdate((to) => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm px-4" @click="onShare">
|
||||||
|
<share-2-icon class="inline" :size="16" /> {{ $t('share_button') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="collapse collapse-arrow font-light text-sm">
|
<div class="collapse collapse-arrow font-light text-sm">
|
||||||
<input id="options-dropdown" type="checkbox" />
|
<input id="options-dropdown" type="checkbox" />
|
||||||
<div class="collapse-title">
|
<div class="collapse-title">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ onBeforeRouteUpdate(updateTitle);
|
|||||||
<div class="italic text-xl font-extralight mb-4">
|
<div class="italic text-xl font-extralight mb-4">
|
||||||
<circle-question-mark-icon class="inline" /> {{ $t('not_found') }}
|
<circle-question-mark-icon class="inline" /> {{ $t('not_found') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full px-4">
|
<div class="w-full">
|
||||||
<router-link to="/" class="btn mb-4">{{ $t('not_found_button') }}</router-link>
|
<router-link to="/" class="btn mb-4 px-4">{{ $t('not_found_button') }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user