mirror of https://github.com/wg-easy/wg-easy
committed by
Sergei Birukov
24 changed files with 401 additions and 301 deletions
@ -1,60 +1,62 @@ |
|||||
<!-- EditableAddress.vue --> |
<!-- EditableAddress.vue --> |
||||
<template> |
<template> |
||||
<span class="group block md:inline-block pb-1 md:pb-0"> |
<span class="group block md:inline-block pb-1 md:pb-0"> |
||||
<!-- Show --> |
<!-- Show --> |
||||
<input |
<input |
||||
v-show="editAddressId === client.id" |
v-show="editAddressId === client.id" |
||||
v-model="editAddress" |
v-model="editAddress" |
||||
@keyup.enter="updateAddress" |
@keyup.enter="updateAddress" |
||||
@keyup.escape="cancelEdit" |
@keyup.escape="cancelEdit" |
||||
:test="'client-' + client.id + '-address'" |
:test="'client-' + client.id + '-address'" |
||||
:ref="'client-' + client.id + '-address'" |
:ref="'client-' + client.id + '-address'" |
||||
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500" |
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500" |
||||
/> |
/> |
||||
<span v-show="editAddressId !== client.id" class="inline-block border-t-2 border-b-2 border-transparent">{{ |
<span |
||||
client.address |
v-show="editAddressId !== client.id" |
||||
}}</span> |
class="inline-block border-t-2 border-b-2 border-transparent" |
||||
|
>{{ client.address }}</span |
||||
|
> |
||||
|
|
||||
<!-- Edit --> |
<!-- Edit --> |
||||
<span |
<span |
||||
v-show="editAddressId !== client.id" |
v-show="editAddressId !== client.id" |
||||
@click="edit" |
@click="edit" |
||||
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" |
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" |
||||
> |
> |
||||
<IconEdit /> |
<IconEdit /> |
||||
</span> |
|
||||
</span> |
</span> |
||||
|
</span> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import IconEdit from './icons/IconEdit.vue'; |
import IconEdit from './icons/IconEdit.vue'; |
||||
|
|
||||
export default { |
export default { |
||||
props: ["client"], |
props: ['client'], |
||||
data() { |
data() { |
||||
return { |
return { |
||||
editAddress: null, |
editAddress: null, |
||||
editAddressId: null, |
editAddressId: null, |
||||
}; |
}; |
||||
|
}, |
||||
|
methods: { |
||||
|
updateAddress() { |
||||
|
this.$emit('update-address', this.client, this.editAddress); |
||||
|
this.editAddress = null; |
||||
|
this.editAddressId = null; |
||||
}, |
}, |
||||
methods: { |
cancelEdit() { |
||||
updateAddress() { |
this.editAddress = null; |
||||
this.$emit("update-address", this.client, this.editAddress); |
this.editAddressId = null; |
||||
this.editAddress = null; |
|
||||
this.editAddressId = null; |
|
||||
}, |
|
||||
cancelEdit() { |
|
||||
this.editAddress = null; |
|
||||
this.editAddressId = null; |
|
||||
}, |
|
||||
edit() { |
|
||||
this.editAddress = this.client.address; |
|
||||
this.editAddressId = this.client.id; |
|
||||
this.$nextTick(() => { |
|
||||
this.$refs["client-" + this.client.id + "-address"].select(); |
|
||||
}); |
|
||||
}, |
|
||||
}, |
}, |
||||
components: { IconEdit } |
edit() { |
||||
|
this.editAddress = this.client.address; |
||||
|
this.editAddressId = this.client.id; |
||||
|
this.$nextTick(() => { |
||||
|
this.$refs['client-' + this.client.id + '-address'].select(); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
components: { IconEdit }, |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|||||
@ -1,22 +1,33 @@ |
|||||
<script> |
<script> |
||||
import IconAvatarDefault from "./icons/IconAvatarDefault.vue"; |
import IconAvatarDefault from './icons/IconAvatarDefault.vue'; |
||||
|
|
||||
export default { |
export default { |
||||
props: ["client"], |
props: ['client'], |
||||
components: { IconAvatarDefault }, |
components: { IconAvatarDefault }, |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|
||||
<template> |
<template> |
||||
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative"> |
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative"> |
||||
<IconAvatarDefault class="w-6 m-2 text-gray-300" /> |
<IconAvatarDefault class="w-6 m-2 text-gray-300" /> |
||||
<img v-if="client.avatar" :src="client.avatar" class="w-10 rounded-full absolute top-0 left-0" /> |
<img |
||||
|
v-if="client.avatar" |
||||
|
:src="client.avatar" |
||||
|
class="w-10 rounded-full absolute top-0 left-0" |
||||
|
/> |
||||
|
|
||||
<div v-if="client.latestHandshakeAt && new Date() - new Date(client.latestHandshakeAt) < 1000 * 60 * 10"> |
<div |
||||
<div |
v-if=" |
||||
class="animate-ping w-4 h-4 p-1 bg-red-100 dark:bg-red-100 rounded-full absolute -bottom-1 -right-1" |
client.latestHandshakeAt && |
||||
></div> |
new Date() - new Date(client.latestHandshakeAt) < 1000 * 60 * 10 |
||||
<div class="w-2 h-2 bg-red-800 dark:bg-red-600 rounded-full absolute bottom-0 right-0"></div> |
" |
||||
</div> |
> |
||||
|
<div |
||||
|
class="animate-ping w-4 h-4 p-1 bg-red-100 dark:bg-red-100 rounded-full absolute -bottom-1 -right-1" |
||||
|
></div> |
||||
|
<div |
||||
|
class="w-2 h-2 bg-red-800 dark:bg-red-600 rounded-full absolute bottom-0 right-0" |
||||
|
></div> |
||||
</div> |
</div> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,30 +1,32 @@ |
|||||
<!-- ClientNewButton.vue --> |
<!-- ClientNewButton.vue --> |
||||
<template> |
<template> |
||||
<div class="flex flex-row flex-auto items-center p-3 px-5 border-b-2 border-gray-100 dark:border-neutral-600"> |
<div |
||||
<div class="flex-grow"> |
class="flex flex-row flex-auto items-center p-3 px-5 border-b-2 border-gray-100 dark:border-neutral-600" |
||||
<p class="text-2xl font-medium dark:text-neutral-200">Clients</p> |
> |
||||
</div> |
<div class="flex-grow"> |
||||
<div class="flex-shrink-0"> |
<p class="text-2xl font-medium dark:text-neutral-200">Clients</p> |
||||
<button |
|
||||
@click="createNewClient" |
|
||||
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition" |
|
||||
> |
|
||||
<IconNew class="w-4 mr-2" /> |
|
||||
<span class="text-sm">New</span> |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
|
<div class="flex-shrink-0"> |
||||
|
<button |
||||
|
@click="createNewClient" |
||||
|
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition" |
||||
|
> |
||||
|
<IconNew class="w-4 mr-2" /> |
||||
|
<span class="text-sm">New</span> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import IconNew from './icons/IconNew.vue'; |
import IconNew from './icons/IconNew.vue'; |
||||
|
|
||||
export default { |
export default { |
||||
methods: { |
methods: { |
||||
createNewClient() { |
createNewClient() { |
||||
this.$emit("create-new-client"); |
this.$emit('create-new-client'); |
||||
}, |
|
||||
}, |
}, |
||||
components: { IconNew } |
}, |
||||
|
components: { IconNew }, |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|||||
@ -1,13 +1,13 @@ |
|||||
<template> |
<template> |
||||
<span v-if="transferData" :title="title"> |
<span v-if="transferData" :title="title"> |
||||
· |
· |
||||
<slot></slot> |
<slot></slot> |
||||
{{ transferDataCurrent }}/s |
{{ transferDataCurrent }}/s |
||||
</span> |
</span> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
props: ["transferData", "transferDataCurrent", "title"], |
props: ['transferData', 'transferDataCurrent', 'title'], |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|||||
@ -1,11 +1,11 @@ |
|||||
<script> |
<script> |
||||
import IconSpinnerVue from "./icons/IconSpinner.vue"; |
import IconSpinnerVue from './icons/IconSpinner.vue'; |
||||
|
|
||||
export default { |
export default { |
||||
components: { IconSpinnerVue } |
components: { IconSpinnerVue }, |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|
||||
<template> |
<template> |
||||
<IconSpinnerVue class="w-5 animate-spin mx-auto" /> |
<IconSpinnerVue class="w-5 animate-spin mx-auto" /> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,5 +1,13 @@ |
|||||
<template> |
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> |
<svg |
||||
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" /> |
xmlns="http://www.w3.org/2000/svg" |
||||
</svg> |
viewBox="0 0 20 20" |
||||
|
fill="currentColor" |
||||
|
> |
||||
|
<path |
||||
|
fill-rule="evenodd" |
||||
|
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" |
||||
|
clip-rule="evenodd" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,5 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg class="w-8" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
<svg |
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> |
class="w-8" |
||||
</svg> |
xmlns="http://www.w3.org/2000/svg" |
||||
|
fill="none" |
||||
|
viewBox="0 0 24 24" |
||||
|
stroke="currentColor" |
||||
|
> |
||||
|
<path |
||||
|
stroke-linecap="round" |
||||
|
stroke-linejoin="round" |
||||
|
stroke-width="2" |
||||
|
d="M6 18L18 6M6 6l12 12" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,9 +1,14 @@ |
|||||
<template> |
<template> |
||||
<svg class="w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> |
<svg |
||||
<path |
class="w-5" |
||||
fill-rule="evenodd" |
xmlns="http://www.w3.org/2000/svg" |
||||
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" |
viewBox="0 0 20 20" |
||||
clip-rule="evenodd" |
fill="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
|
fill-rule="evenodd" |
||||
|
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" |
||||
|
clip-rule="evenodd" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,9 +1,14 @@ |
|||||
<template> |
<template> |
||||
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> |
<svg |
||||
<path |
class="align-middle h-3 inline" |
||||
fill-rule="evenodd" |
xmlns="http://www.w3.org/2000/svg" |
||||
d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z" |
viewBox="0 0 20 20" |
||||
clip-rule="evenodd" |
fill="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
|
fill-rule="evenodd" |
||||
|
d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z" |
||||
|
clip-rule="evenodd" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,10 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg class="w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
<svg |
||||
<path |
class="w-5" |
||||
stroke-linecap="round" |
xmlns="http://www.w3.org/2000/svg" |
||||
stroke-linejoin="round" |
fill="none" |
||||
stroke-width="2" |
viewBox="0 0 24 24" |
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" |
stroke="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
|
stroke-linecap="round" |
||||
|
stroke-linejoin="round" |
||||
|
stroke-width="2" |
||||
|
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,16 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg |
<svg |
||||
xmlns="http://www.w3.org/2000/svg" |
xmlns="http://www.w3.org/2000/svg" |
||||
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100" |
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100" |
||||
fill="none" |
fill="none" |
||||
viewBox="0 0 24 24" |
viewBox="0 0 24 24" |
||||
stroke="currentColor" |
stroke="currentColor" |
||||
> |
> |
||||
<path |
<path |
||||
stroke-linecap="round" |
stroke-linecap="round" |
||||
stroke-linejoin="round" |
stroke-linejoin="round" |
||||
stroke-width="2" |
stroke-width="2" |
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" |
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" |
||||
/> |
/> |
||||
</svg> |
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,10 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg class="h-3 inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
<svg |
||||
<path |
class="h-3 inline" |
||||
stroke-linecap="round" |
xmlns="http://www.w3.org/2000/svg" |
||||
stroke-linejoin="round" |
fill="none" |
||||
stroke-width="2" |
viewBox="0 0 24 24" |
||||
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" |
stroke="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
|
stroke-linecap="round" |
||||
|
stroke-linejoin="round" |
||||
|
stroke-width="2" |
||||
|
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,11 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg |
<svg |
||||
inline |
inline |
||||
xmlns="http://www.w3.org/2000/svg" |
xmlns="http://www.w3.org/2000/svg" |
||||
fill="none" |
fill="none" |
||||
viewBox="0 0 24 24" |
viewBox="0 0 24 24" |
||||
stroke="currentColor" |
stroke="currentColor" |
||||
> |
> |
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" /> |
<path |
||||
</svg> |
stroke-linecap="round" |
||||
</template> |
stroke-linejoin="round" |
||||
|
stroke-width="2" |
||||
|
d="M12 6v6m0 0v6m0-6h6m-6 0H6" |
||||
|
/> |
||||
|
</svg> |
||||
|
</template> |
||||
|
|||||
@ -1,10 +1,16 @@ |
|||||
<template> |
<template> |
||||
<svg class="w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
<svg |
||||
<path |
class="w-5" |
||||
stroke-linecap="round" |
xmlns="http://www.w3.org/2000/svg" |
||||
stroke-linejoin="round" |
fill="none" |
||||
stroke-width="2" |
viewBox="0 0 24 24" |
||||
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z" |
stroke="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
|
stroke-linecap="round" |
||||
|
stroke-linejoin="round" |
||||
|
stroke-width="2" |
||||
|
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z" |
||||
|
/> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,10 +1,21 @@ |
|||||
<template> |
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> |
<svg |
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> |
xmlns="http://www.w3.org/2000/svg" |
||||
<path |
viewBox="0 0 24 24" |
||||
class="opacity-75" |
fill="currentColor" |
||||
fill="currentColor" |
> |
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" |
<circle |
||||
></path> |
class="opacity-25" |
||||
</svg> |
cx="12" |
||||
|
cy="12" |
||||
|
r="10" |
||||
|
stroke="currentColor" |
||||
|
stroke-width="4" |
||||
|
></circle> |
||||
|
<path |
||||
|
class="opacity-75" |
||||
|
fill="currentColor" |
||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" |
||||
|
></path> |
||||
|
</svg> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,9 +1,14 @@ |
|||||
<template> |
<template> |
||||
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> |
<svg |
||||
<path |
class="align-middle h-3 inline" |
||||
fill-rule="evenodd" |
xmlns="http://www.w3.org/2000/svg" |
||||
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z" |
viewBox="0 0 20 20" |
||||
clip-rule="evenodd" |
fill="currentColor" |
||||
/> |
> |
||||
</svg> |
<path |
||||
</template> |
fill-rule="evenodd" |
||||
|
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z" |
||||
|
clip-rule="evenodd" |
||||
|
/> |
||||
|
</svg> |
||||
|
</template> |
||||
|
|||||
@ -1,17 +1,17 @@ |
|||||
<template> |
<template> |
||||
<svg |
<svg |
||||
class="h-6 w-6 text-red-600" |
class="h-6 w-6 text-red-600" |
||||
xmlns="http://www.w3.org/2000/svg" |
xmlns="http://www.w3.org/2000/svg" |
||||
fill="none" |
fill="none" |
||||
viewBox="0 0 24 24" |
viewBox="0 0 24 24" |
||||
stroke="currentColor" |
stroke="currentColor" |
||||
aria-hidden="true" |
aria-hidden="true" |
||||
> |
> |
||||
<path |
<path |
||||
stroke-linecap="round" |
stroke-linecap="round" |
||||
stroke-linejoin="round" |
stroke-linejoin="round" |
||||
stroke-width="2" |
stroke-width="2" |
||||
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> |
||||
</template> |
</template> |
||||
|
|||||
@ -1,13 +1,13 @@ |
|||||
export function useDateTime() { |
export function useDateTime() { |
||||
const dateTime = (value) => { |
const dateTime = (value) => { |
||||
return new Intl.DateTimeFormat(undefined, { |
return new Intl.DateTimeFormat(undefined, { |
||||
year: "numeric", |
year: 'numeric', |
||||
month: "short", |
month: 'short', |
||||
day: "numeric", |
day: 'numeric', |
||||
hour: "numeric", |
hour: 'numeric', |
||||
minute: "numeric", |
minute: 'numeric', |
||||
}).format(value); |
}).format(value); |
||||
}; |
}; |
||||
|
|
||||
return { dateTime }; |
return { dateTime }; |
||||
} |
} |
||||
|
|||||
@ -1,29 +1,29 @@ |
|||||
export function useTimeAgo() { |
export function useTimeAgo() { |
||||
const timeago = (date) => { |
const timeago = (date) => { |
||||
const now = new Date(); |
const now = new Date(); |
||||
const diff = now - date; |
const diff = now - date; |
||||
|
|
||||
if (diff < 1000) { |
if (diff < 1000) { |
||||
return "just now"; |
return 'just now'; |
||||
} else if (diff < 60000) { |
} else if (diff < 60000) { |
||||
const seconds = Math.floor(diff / 1000); |
const seconds = Math.floor(diff / 1000); |
||||
return `${seconds} ${plural("second", seconds)} ago`; |
return `${seconds} ${plural('second', seconds)} ago`; |
||||
} else if (diff < 3600000) { |
} else if (diff < 3600000) { |
||||
const minutes = Math.floor(diff / 60000); |
const minutes = Math.floor(diff / 60000); |
||||
return `${minutes} ${plural("minute", minutes)} ago`; |
return `${minutes} ${plural('minute', minutes)} ago`; |
||||
} else if (diff < 86400000) { |
} else if (diff < 86400000) { |
||||
const hours = Math.floor(diff / 3600000); |
const hours = Math.floor(diff / 3600000); |
||||
return `${hours} ${plural("hour", hours)} ago`; |
return `${hours} ${plural('hour', hours)} ago`; |
||||
} else { |
} else { |
||||
const days = Math.floor(diff / 86400000); |
const days = Math.floor(diff / 86400000); |
||||
return `${days} ${plural("day", days)} ago`; |
return `${days} ${plural('day', days)} ago`; |
||||
} |
} |
||||
}; |
}; |
||||
|
|
||||
// #278 -- this function might need to be rewritten to support l18n
|
// #278 -- this function might need to be rewritten to support l18n
|
||||
const plural = (word, count) => { |
const plural = (word, count) => { |
||||
return count !== 1 ? `${word}s` : word; |
return count !== 1 ? `${word}s` : word; |
||||
}; |
}; |
||||
|
|
||||
return { timeago }; |
return { timeago }; |
||||
} |
} |
||||
|
|||||
@ -1,6 +1,6 @@ |
|||||
import './assets/style.css' |
import './assets/style.css'; |
||||
|
|
||||
import { createApp } from 'vue' |
import App from './App.vue'; |
||||
import App from './App.vue' |
import { createApp } from 'vue'; |
||||
|
|
||||
createApp(App).mount('#app') |
createApp(App).mount('#app'); |
||||
|
|||||
Loading…
Reference in new issue