share with a png file

This commit is contained in:
Julien Calixte
2023-11-30 00:35:54 +01:00
parent 4b70cf9af2
commit 67a0b6bb7c
3 changed files with 101 additions and 67 deletions

View File

@@ -15,16 +15,10 @@ const { duration } = useTaskRecordMetadata(taskRecord)
<template> <template>
<div class="task-record-preview"> <div class="task-record-preview">
<router-link <div v-if="taskRecord !== null">
:to="{ Last record took {{ duration }} minutes.
name: 'record-view', </div>
params: { taskId } <div v-else>No record yet.</div>
}"
class="button is-primary is-light"
>start session</router-link
>
<div v-if="duration !== null">Last record took {{ duration }} minutes</div>
<div v-else>No record yet</div>
</div> </div>
</template> </template>

View File

@@ -1,44 +1,45 @@
import { useTaskRecordStore } from '@/modules/record/stores/useTaskRecordStore'
import type { Task } from '@/modules/task/models/task' import type { Task } from '@/modules/task/models/task'
import { formatDiffInMinutes, formatToShortDate } from '@/shared/format-date' import { computed, ref, type ComputedRef } from 'vue'
import { toValue } from '@vueuse/core' import { toBlob } from 'html-to-image'
import { ref, type ComputedRef } from 'vue'
export const useCopyRecord = (task: ComputedRef<Task | null>) => { export const useCopyRecord = (task: ComputedRef<Task | null>) => {
const recordStore = useTaskRecordStore() const canShareTask =
!!navigator && !!navigator.clipboard && !!navigator.clipboard.writeText
const canShareTask = !!navigator.clipboard
const taskCopied = ref(false) const taskCopied = ref(false)
const domId = computed(() => `task-${task.value?.id}`)
const shareTask = async () => { const shareTask = async () => {
const t = toValue(task) const node = document.getElementById(domId.value)
if (!t) { if (!node) {
return return
} }
const record = recordStore.getTaskRecord(t.id) const blob = await toBlob(node, {
style: {
let clipboardText = `${t.title};${formatToShortDate(t.date)}\n margin: 'inherit'
Step;Estimation;Duration\n` }
t.steps.forEach((step) => {
const recordStep = record?.stepRecords[step.id]
const duration =
recordStep && recordStep.end
? formatDiffInMinutes(recordStep.start, recordStep.end)
: '-'
const analyze = duration <= step.estimation ? '✅' : '⚠️'
clipboardText += `"${analyze} ${step.title}";${step.estimation};${duration}\n`
}) })
await navigator.clipboard.writeText(clipboardText) if (!blob) {
taskCopied.value = true return
}
setTimeout(() => { try {
taskCopied.value = false await navigator.clipboard.write([
}, 2000) new ClipboardItem({
[blob.type]: blob
})
])
taskCopied.value = true
} catch (error) {
console.warn(error)
} finally {
setTimeout(() => {
taskCopied.value = false
}, 2000)
}
} }
return { return {

View File

@@ -6,6 +6,7 @@ import { useCopyRecord } from '@/modules/record/hooks/useCopyRecord.hook'
import { useTaskStore } from '@/modules/task/stores/useTask.store' import { useTaskStore } from '@/modules/task/stores/useTask.store'
import { computed } from 'vue' import { computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import StepRecord from '@/modules/record/components/StepRecord.vue'
const props = defineProps<{ const props = defineProps<{
id: string id: string
@@ -31,47 +32,78 @@ const { canShareTask, taskCopied, shareTask } = useCopyRecord(task)
<template> <template>
<div class="task-view" v-if="task"> <div class="task-view" v-if="task">
<div class="buttons actions"> <div class="buttons actions">
<router-link :to="{ <router-link
name: 'edit-task', :to="{
params: { name: 'record-view',
id params: { taskId: id }
} }"
}" class="button"> class="button is-primary is-light"
>start session</router-link
>
<router-link
:to="{
name: 'edit-task',
params: {
id
}
}"
class="button"
>
<img src="/icons/edit.svg" alt="edit task" /> <img src="/icons/edit.svg" alt="edit task" />
</router-link> </router-link>
<button v-if="canShareTask" class="share-task button" @click="shareTask"> <button v-if="canShareTask" class="share-task button" @click="shareTask">
<img v-if="taskCopied" src="/icons/check.svg" alt="task copied!" /> <img v-if="taskCopied" src="/icons/check.svg" alt="task copied!" />
<img v-else src="/icons/share.svg" alt="share task" /> <img v-else src="/icons/share.svg" alt="share task" />
</button> </button>
<router-link :to="{ <router-link
name: 'duplicate-task', :to="{
params: { name: 'duplicate-task',
id params: {
} id
}" class="button"> }
}"
class="button"
>
<img src="/icons/copy.svg" alt="duplicate task" /> <img src="/icons/copy.svg" alt="duplicate task" />
</router-link> </router-link>
<button class="delete-task button is-light is-danger" @click="deleteTask"> <button class="delete-task button is-light is-danger" @click="deleteTask">
<img src="/icons/trash.svg" alt="delete task" /> <img src="/icons/trash.svg" alt="delete task" />
</button> </button>
</div> </div>
<h1 class="title">{{ task.title }}</h1> <a
<h2 class="subtitle"> v-if="task.link"
<estimation-time-arrival :estimation="task.totalEstimation" /> :href="task.link"
</h2> target="_blank"
<a v-if="task.link" :href="task.link" target="_blank" rel="noopener noreferrer" class="button is-link">user story rel="noopener noreferrer"
link</a> class="button is-link"
<task-record-preview :task-id="id" /> >user story link</a
<hr /> >
<div class="content"> <div class="content" :id="`task-${id}`">
<ol> <h1 class="title">{{ task.title }}</h1>
<li v-for="step in task.steps" :key="step.id"> <h2 class="subtitle">
<div class="step-item"> <estimation-time-arrival :estimation="task.totalEstimation" />
<span>{{ step.title }}</span> </h2>
<span class="tag">{{ step.estimation }} minutes</span> <task-record-preview :task-id="id" />
</div> <table class="table is-striped is-hoverable">
</li> <thead>
</ol> <tr>
<th>#</th>
<th>status</th>
<th>task</th>
<th>estimation</th>
<th>actual</th>
</tr>
</thead>
<tbody>
<step-record
v-for="(step, key) in task.steps"
:task-id="id"
:key="step.id"
:step-id="step.id"
:step-number="key + 1"
/>
</tbody>
</table>
</div> </div>
</div> </div>
<task-not-found v-else /> <task-not-found v-else />
@@ -89,4 +121,11 @@ const { canShareTask, taskCopied, shareTask } = useCopyRecord(task)
.actions { .actions {
float: right; float: right;
} }
.content {
background-color: white;
max-width: 800px;
margin: auto;
padding: 0 1rem;
}
</style> </style>