<!-- "Likes" modal to see who liked a thing --> <!-- Reusable "Liked by Alice, Bob and 5 others" widget that invokes the Like Modal. Requirements: pass in a context providing the following variables: - LikeExample: slice of users - LikeRemainder: integer - LikeTableName: like 'photos' - LikeTableID: integer Call this like: {{template "like-example" .}} --> {{define "like-example"}} {{$Outer := .}} {{if .LikeExample}} <div class="mt-4 mb-2 has-text-centered"> Liked by <!-- User list --> {{range $i, $User := .LikeExample}} <!-- Avatar --> <figure class="image is-16x16 is-inline-block"> <a href="/u/{{$User.Username}}" class="has-text-dark"> {{if $User.ProfilePhoto.ID}} {{if and (eq $User.ProfilePhoto.Visibility "private") (not $User.UserRelationship.IsPrivateGranted)}} <img class="is-rounded" src="/static/img/shy-private.png"> {{else if and (eq $User.ProfilePhoto.Visibility "friends") (not $User.UserRelationship.IsFriend)}} <img class="is-rounded" src="/static/img/shy-friends.png"> {{else if and (eq $User.ProfilePhoto.Visibility "circle") (not $User.UserRelationship.IsInnerCirclePeer)}} <img class="is-rounded" src="/static/img/shy-secret.png"> {{else}} <img class="is-rounded" src="{{PhotoURL $User.ProfilePhoto.CroppedFilename}}"> {{end}} {{else}} <img class="is-rounded" src="/static/img/shy.png"> {{end}} </a> </figure> <!-- Username plus a comma if multiple --> <a href="/u/{{$User.Username}}"> {{- $User.Username -}} </a>{{if and (eq (len $Outer.LikeExample) 2) (not $Outer.LikeRemainder)}} {{if eq $i 0}} and {{end}} {{- else if gt (len $Outer.LikeExample) 1}},{{end}} {{end}} <!-- Others --> {{if .LikeRemainder}} and <a href="#" onclick="ShowLikeModal('{{.LikeTableName}}', {{.LikeTableID}}); return false" > {{.LikeRemainder}} other{{Pluralize64 .LikeRemainder}}</a>. {{end}} </div> {{end}} {{end}} {{define "like-modal"}} <div id="like-modal-app"> <div class="modal vue-managed" :class="{'is-active': visible}"> <div class="modal-background" @click="visible=false"></div> <div class="modal-content"> <div class="card"> <div class="card-header has-background-info"> <p class="card-header-title has-text-light"> <i class="fa fa-heart mr-2"></i> [[title]] </p> </div> <div class="card-content"> <div v-if="busy"> <i class="fa fa-spinner fa-spin"></i> Loading likes... </div> <div v-else> <p class="block"> Found [[ total ]] like[[ total === 1 ? '' : 's' ]] (page [[ page ]] of [[ pages ]]). </p> <div class="columns is-multiline"> <div class="column is-one-third" v-for="row in result"> <!-- Avatar --> <figure class="image is-16x16 is-inline-block mr-2"> <a :href="'/u/'+row.username" class="has-text-dark"> <img class="is-rounded" :src="row.avatar"> </a> </figure> <!-- Username link --> <a :href="'/u/'+row.username" target="_blank">[[ row.username ]]</a> </div> </div> <!-- Pager buttons --> <div class="columns is-mobile"> <div class="column is-narrow"> <button type="button" class="button" @click="prevPage()" :disabled="page <= 1"> Previous </button> </div> <div class="column is-narrow"> <button type="button" class="button" @click="nextPage()" :disabled="page >= pages"> Next page </button> </div> <div class="column has-text-right"> <button type="button" class="button is-primary" @click="visible=false"> Close </button> </div> </div> </div> </div> </div> </div> </div> </div> <script type="text/javascript"> // Implemented in Vue widget. var ShowLikeModal = function(tableName, tableID) {}; const likeModalApp = Vue.createApp({ delimiters: ['[[', ']]'], data() { return { visible: false, title: "Likes", busy: false, tableName: "photos", tableID: 0, page: 1, pages: 0, total: 0, result: [], } }, mounted() { ShowLikeModal = this.ShowLikeModal; }, methods: { ShowLikeModal(tableName, tableID) { this.tableName = tableName; this.tableID = tableID; this.visible = true; this.page = 1; this.get(); }, prevPage() { this.page--; if (this.page <= 1) { this.page = 1; } this.get(); }, nextPage() { this.page++; this.get(); }, get() { this.busy = true; return fetch("/v1/likes/users?" + new URLSearchParams({ table_name: this.tableName, table_id: this.tableID, page: this.page, }), { method: "GET", mode: "same-origin", cache: "no-cache", credentials: "same-origin", }) .then((response) => response.json()) .then((data) => { if (data.StatusCode !== 200) { window.alert(data.data.error); return; } let likes = data.data.likes; this.pages = data.data.pages; this.total = data.data.pager.Total; this.result = likes; }).catch(resp => { window.alert(resp); }).finally(() => { this.busy = false; }); }, }, }); likeModalApp.mount("#like-modal-app"); </script> {{end}}