feat: improved sharing prompt

pull/1307/head
Ramires Viana 2021-02-16 15:39:11 +00:00
parent a809404ce1
commit 1819377897
5 changed files with 116 additions and 91 deletions

View File

@ -119,8 +119,8 @@ nav > div {
.dashboard p label { .dashboard p label {
color: var(--textPrimary); color: var(--textPrimary);
} }
.card#share ul li input, .card#share input,
.card#share ul li select, .card#share select,
.input { .input {
background: var(--surfaceSecondary); background: var(--surfaceSecondary);
color: var(--textPrimary); color: var(--textPrimary);

View File

@ -4,61 +4,82 @@
<h2>{{ $t('buttons.share') }}</h2> <h2>{{ $t('buttons.share') }}</h2>
</div> </div>
<div class="card-content"> <template v-if="listing">
<ul> <div class="card-content">
<table>
<tr>
<th>#</th>
<th>{{ $t('settings.shareDuration') }}</th>
<th></th>
<th></th>
</tr>
<li v-for="link in links" :key="link.hash"> <tr v-for="link in links" :key="link.hash">
<a :href="buildLink(link.hash)" target="_blank"> <td>{{ link.hash }}</td>
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template> <td>
<template v-else>{{ $t('permanent') }}</template> <template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
</a> <template v-else>{{ $t('permanent') }}</template>
</td>
<td class="small">
<button class="action copy-clipboard"
:data-clipboard-text="buildLink(link.hash)"
:aria-label="$t('buttons.copyToClipboard')"
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
</td>
<td class="small">
<button class="action"
@click="deleteLink($event, link)"
:aria-label="$t('buttons.delete')"
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
</td>
</tr>
</table>
</div>
<button class="action" <div class="card-action">
@click="deleteLink($event, link)" <button class="button button--flat button--grey"
:aria-label="$t('buttons.delete')" @click="$store.commit('closeHovers')"
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button> :aria-label="$t('buttons.close')"
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
<button class="button button--flat button--blue"
@click="() => switchListing()"
:aria-label="$t('buttons.new')"
:title="$t('buttons.new')">{{ $t('buttons.new') }}</button>
</div>
</template>
<button class="action copy-clipboard" <template v-else>
:data-clipboard-text="buildLink(link.hash)" <div class="card-content">
:aria-label="$t('buttons.copyToClipboard')" <p>{{ $t('settings.shareDuration') }}</p>
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button> <div class="input-group input">
</li> <input v-focus
type="number"
max="2147483647"
min="1"
@keyup.enter="submit"
v-model.trim="time">
<select class="right" v-model="unit" :aria-label="$t('time.unit')">
<option value="seconds">{{ $t('time.seconds') }}</option>
<option value="minutes">{{ $t('time.minutes') }}</option>
<option value="hours">{{ $t('time.hours') }}</option>
<option value="days">{{ $t('time.days') }}</option>
</select>
</div>
<p>{{ $t('prompts.optionalPassword') }}</p>
<input class="input input--block" type="password" v-model.trim="password">
</div>
<li v-if="!hasPermanent"> <div class="card-action">
<div> <button class="button button--flat button--grey"
<input type="password" :placeholder="$t('prompts.optionalPassword')" v-model="passwordPermalink"> @click="() => switchListing()"
<a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{ $t('buttons.permalink') }}</a> :aria-label="$t('buttons.cancel')"
</div> :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
</li> <button class="button button--flat button--blue"
@click="submit"
<li> :aria-label="$t('buttons.share')"
<input v-focus :title="$t('buttons.share')">{{ $t('buttons.share') }}</button>
type="number" </div>
max="2147483647" </template>
min="0"
@keyup.enter="submit"
v-model.trim="time">
<select v-model="unit" :aria-label="$t('time.unit')">
<option value="seconds">{{ $t('time.seconds') }}</option>
<option value="minutes">{{ $t('time.minutes') }}</option>
<option value="hours">{{ $t('time.hours') }}</option>
<option value="days">{{ $t('time.days') }}</option>
</select>
<input type="password" :placeholder="$t('prompts.optionalPassword')" v-model="password">
<button class="action"
@click="submit"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')"><i class="material-icons">add</i></button>
</li>
</ul>
</div>
<div class="card-action">
<button class="button button--flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.close')"
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
</div>
</div> </div>
</template> </template>
@ -75,11 +96,10 @@ export default {
return { return {
time: '', time: '',
unit: 'hours', unit: 'hours',
hasPermanent: false,
links: [], links: [],
clip: null, clip: null,
password: '', password: '',
passwordPermalink: '' listing: true
} }
}, },
computed: { computed: {
@ -104,11 +124,8 @@ export default {
this.links = links this.links = links
this.sort() this.sort()
for (let link of this.links) { if (this.links.length == 0) {
if (link.expire === 0) { this.listing = false
this.hasPermanent = true
break
}
} }
} catch (e) { } catch (e) {
this.$showError(e) this.$showError(e)
@ -125,22 +142,25 @@ export default {
}, },
methods: { methods: {
submit: async function () { submit: async function () {
if (!this.time) return let isPermanent = !this.time || this.time == 0
try { try {
const res = await api.create(this.url, this.password, this.time, this.unit) let res = null
if (isPermanent) {
res = await api.create(this.url, this.password)
} else {
res = await api.create(this.url, this.password, this.time, this.unit)
}
this.links.push(res) this.links.push(res)
this.sort() this.sort()
} catch (e) {
this.$showError(e) this.time = ''
} this.unit = 'hours'
}, this.password = ''
getPermalink: async function () {
try { this.listing = true
const res = await api.create(this.url, this.passwordPermalink)
this.links.push(res)
this.sort()
this.hasPermanent = true
} catch (e) { } catch (e) {
this.$showError(e) this.$showError(e)
} }
@ -149,8 +169,11 @@ export default {
event.preventDefault() event.preventDefault()
try { try {
await api.remove(link.hash) await api.remove(link.hash)
if (link.expire === 0) this.hasPermanent = false
this.links = this.links.filter(item => item.hash !== link.hash) this.links = this.links.filter(item => item.hash !== link.hash)
if (this.links.length == 0) {
this.listing = false
}
} catch (e) { } catch (e) {
this.$showError(e) this.$showError(e)
} }
@ -167,6 +190,13 @@ export default {
if (b.expire === 0) return 1 if (b.expire === 0) return 1
return new Date(a.expire) - new Date(b.expire) return new Date(a.expire) - new Date(b.expire)
}) })
},
switchListing () {
if (this.links.length == 0 && !this.listing) {
this.$store.commit('closeHovers')
}
this.listing = !this.listing
} }
} }
} }

View File

@ -71,8 +71,3 @@
text-align: center; text-align: center;
animation: .2s opac forwards; animation: .2s opac forwards;
} }
.share__promt__card {
max-width: max-content !important;
width: auto !important;
}

View File

@ -226,6 +226,18 @@ table tr>*:last-child {
opacity: 1; opacity: 1;
} }
.card#share .input-group {
display: flex;
}
.card#share .input-group * {
border: none;
}
.card#share .input-group input {
flex: 1;
}
.overlay { .overlay {
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
position: fixed; position: fixed;

View File

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"path"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -91,17 +90,6 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
defer r.Body.Close() defer r.Body.Close()
} }
if body.Expires == "" {
var err error
s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
if err == nil {
if _, err := w.Write([]byte(path.Join(d.server.BaseURL, "/share/", s.Hash))); err != nil {
return http.StatusInternalServerError, err
}
return 0, nil
}
}
bytes := make([]byte, 6) bytes := make([]byte, 6)
_, err := rand.Read(bytes) _, err := rand.Read(bytes)
if err != nil { if err != nil {