2019-02-27 07:03:46 +00:00
< template >
2022-02-18 02:19:28 +00:00
< div class = "compose-modal-component" >
< input type = "file" id = "pf-dz" name = "media" class = "w-100 h-100 d-none file-input" multiple = "" v -bind :accept = "config.uploader.media_types" >
2020-11-28 02:52:40 +00:00
< canvas class = "d-none" id = "pr_canvas" > < / canvas >
< img class = "d-none" id = "pr_img" >
2019-07-09 05:23:59 +00:00
< div class = "timeline" >
2019-09-05 19:58:27 +00:00
< div v-if = "uploading" >
2019-10-16 03:44:48 +00:00
< div class = "card status-card card-md-rounded-0 w-100 h-100 bg-light py-3" style = "border-bottom: 1px solid #f1f1f1" >
2019-09-05 19:58:27 +00:00
< div class = "p-5 mt-2" >
< b-progress :value = "uploadProgress" :max = "100" striped :animated = "true" > < / b-progress >
< p class = "text-center mb-0 font-weight-bold" > Uploading ... ( { { uploadProgress } } % ) < / p >
2019-02-27 07:03:46 +00:00
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-09-05 19:58:27 +00:00
< / div >
2021-04-01 04:24:59 +00:00
2019-10-16 03:44:48 +00:00
< div v -else -if = " page = = ' cameraRoll ' " >
< div class = "card status-card card-md-rounded-0" style = "display:flex;" >
< div class = "card-header d-inline-flex align-items-center justify-content-between bg-white" >
< span class = "pr-3" >
< i class = "fas fa-cog fa-lg text-muted" > < / i >
< / span >
< span class = "font-weight-bold" >
Camera Roll
< / span >
< span class = "text-primary font-weight-bold" > Upload < / span >
< / div >
< div class = "h-100 card-body p-0 border-top" style = "width:100%; min-height: 400px;" >
< div v-if = "cameraRollMedia.length > 0" class="row p-0 m-0" >
< div v-for = "(m, index) in cameraRollMedia" :class="[index == 0 ? 'col-12 p-0' : 'col-3 p-0']" >
< div class = "card info-overlay p-0 rounded-0 shadow-none border" >
< div class = "square" >
2023-11-04 03:37:13 +00:00
< img class = "square-content" :src = "m.preview_url" / >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< / div >
< / div >
< div v -else class = "w-100 h-100 d-flex justify-content-center align-items-center" >
< span class = "w-100 h-100" >
< button type = "button" class = "btn btn-primary" > Upload < / button >
< button type = "button" class = "btn btn-primary" @click ="fetchCameraRollDrafts()" > Load Camera Roll < / button >
< / span >
< / div >
< / div >
< / div >
< / div >
2021-04-01 04:24:59 +00:00
2021-08-05 02:29:21 +00:00
< div v -else -if = " page = = ' poll ' " >
< div class = "card status-card card-md-rounded-0" style = "display:flex;" >
< div class = "card-header d-inline-flex align-items-center justify-content-between bg-white" >
< span class = "pr-3" >
< i class = "fas fa-info-circle fa-lg text-primary" > < / i >
< / span >
< span class = "font-weight-bold" >
New Poll
< / span >
< span v-if = "postingPoll" >
< div class = "spinner-border spinner-border-sm" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / span >
< button v -else -if = " ! postingPoll & & pollOptions.length > 1 && composeText . length " class=" btn btn - primary btn - sm font - weight - bold " @click=" postNewPoll " >
< span > Create Poll < / span >
< / button >
< span v -else class = "font-weight-bold text-lighter" >
Create Poll
< / span >
< / div >
< div class = "h-100 card-body p-0 border-top" style = "width:100%; min-height: 400px;" >
< div class = "border-bottom mt-2" >
< div class = "media px-3" >
2021-08-31 07:30:21 +00:00
< img :src = "profile.avatar" width = "42px" height = "42px" class = "rounded-circle" >
2021-08-05 02:29:21 +00:00
< div class = "media-body" >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small d-none" > Caption < / label >
< vue-tribute :options = "tributeSettings" >
< textarea class = "form-control border-0 rounded-0 no-focus" rows = "3" placeholder = "Write a poll question..." style = "" v-model = "composeText" v-on:keyup="composeTextLength = composeText.length" > < / textarea >
< / vue-tribute >
< p class = "help-text small text-right text-muted mb-0" > { { composeTextLength } } / { { config . uploader . max _caption _length } } < / p >
< / div >
< / div >
< / div >
< / div >
< div class = "p-3" >
< p class = "font-weight-bold text-muted small" >
Poll Options
< / p >
< div v-if = "pollOptions.length < 4" class="form-group mb-4" >
< input type = "text" class = "form-control rounded-pill" placeholder = "Add a poll option, press enter to save" v-model = "pollOptionModel" @keyup.enter="savePollOption" >
< / div >
< div v-for = "(option, index) in pollOptions" class="form-group mb-4 d-flex align-items-center" style="max-width:400px;position: relative;" >
< span class = "font-weight-bold mr-2" style = "position: absolute;left: 10px;" > { { index + 1 } } . < / span >
< input v-if = "pollOptions[index].length < 50" type="text" class="form-control rounded-pill" placeholder="Add a poll option, press enter to save" v-model="pollOptions[index]" style="padding-left: 30px;padding-right: 90px;" >
< textarea v -else class = "form-control" v-model = "pollOptions[index]" placeholder="Add a poll option, press enter to save" rows="3" style="padding-left: 30px;padding-right:90px;" > < / textarea >
< button class = "btn btn-danger btn-sm rounded-pill font-weight-bold" style = "position: absolute;right: 5px;" @click ="deletePollOption(index)" >
< i class = "fas fa-trash" > < / i > Delete
< / button >
< / div >
< hr >
< div class = "d-flex justify-content-between" >
< div >
< p class = "font-weight-bold text-muted small" >
Poll Expiry
< / p >
< div class = "form-group" >
< select class = "form-control rounded-pill" style = "width: 200px;" v-model = "pollExpiry" >
< option value = "60" > 1 hour < / option >
< option value = "360" > 6 hours < / option >
< option value = "1440" selected > 24 hours < / option >
< option value = "10080" > 7 days < / option >
< / select >
< / div >
< / div >
< div >
< p class = "font-weight-bold text-muted small" >
Poll Visibility
< / p >
< div class = "form-group" >
< select class = "form-control rounded-pill" style = "max-width: 200px;" v-model = "visibility" >
< option value = "public" > Public < / option >
< option value = "private" > Followers Only < / option >
< / select >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
2019-09-05 19:58:27 +00:00
< div v-else >
< div class = "card status-card card-md-rounded-0 w-100 h-100" style = "display:flex;" >
2019-09-13 04:36:12 +00:00
< div class = "card-header d-inline-flex align-items-center justify-content-between bg-white" >
2019-09-05 19:58:27 +00:00
< div >
< a v-if = "page == 1" href="#" @click.prevent="closeModal()" class="font-weight-bold text-decoration-none text-muted" >
< i class = "fas fa-times fa-lg" > < / i >
< span class = "font-weight-bold mb-0" > { { pageTitle } } < / span >
< / a >
2019-10-16 03:44:48 +00:00
< span v -else -if = " page = = 2 " >
2020-06-30 04:56:35 +00:00
< button v-if = "config.uploader.album_limit > media.length" class="btn btn-outline-primary btn-sm font-weight-bold" @click.prevent="addMedia" id="cm-add-media-btn"><i class="fas fa-plus" > < / i > < / button >
2019-10-16 03:44:48 +00:00
<!-- < button v-if = "config.uploader.album_limit > media.length" class="btn btn-outline-primary btn-sm font-weight-bold" @click.prevent="page = 'cameraRoll'" data-toggle="tooltip" data-placement="bottom" title="Upload another photo or video" ><i class="fas fa-chevron-left" > < / i > Camera Roll < / button > - - >
< button v -else class = "btn btn-outline-secondary btn-sm font-weight-bold" disabled > < i class = "fas fa-plus" > < / i > < / button >
2020-06-30 04:56:35 +00:00
< b-tooltip target = "cm-add-media-btn" triggers = "hover" >
Upload another photo or video
< / b-tooltip >
2019-10-16 03:44:48 +00:00
< / span >
< span v -else -if = " page = = 3 " >
2021-02-07 04:00:42 +00:00
< a class = "text-lighter text-decoration-none mr-3 d-flex align-items-center" href = "#" @click.prevent ="goBack()" >
< i class = "fas fa-long-arrow-alt-left fa-lg mr-2" > < / i >
< span class = "btn btn-outline-secondary btn-sm px-2 py-0 disabled" disabled = "" > { { media . length } } < / span >
< / a >
< span class = "font-weight-bold mb-0" > { { pageTitle } } < / span >
2019-09-05 19:58:27 +00:00
< / span >
2019-10-16 03:44:48 +00:00
< span v-else >
< a class = "text-lighter text-decoration-none mr-3" href = "#" @click.prevent ="goBack()" > < i class = "fas fa-long-arrow-alt-left fa-lg" > < / i > < / a >
< / span >
< span class = "font-weight-bold mb-0" > { { pageTitle } } < / span >
2019-02-27 07:03:46 +00:00
< / div >
2019-09-13 04:36:12 +00:00
< div v-if = "page == 2" >
2020-06-30 04:56:35 +00:00
< a v-if = "media.length == 1" href="#" class="text-center text-dark" @click.prevent="showCropPhotoCard" title="Crop & Resize" id="cm-crop-btn"><i class="fas fa-crop-alt fa-lg" > < / i > < / a >
< b-tooltip target = "cm-crop-btn" triggers = "hover" >
Crop & Resize
< / b-tooltip >
2019-09-13 04:36:12 +00:00
< / div >
< div >
2019-09-05 19:58:27 +00:00
<!-- < a v-if = "page > 1" class="font-weight-bold text-decoration-none" href="#" @click.prevent="page--" > Back < / a > - - >
< span v-if = "pageLoading" >
< div class = "spinner-border spinner-border-sm" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / span >
2019-09-13 04:36:12 +00:00
< span v-else >
< a v-if = "!pageLoading && (page > 1 && page <= 2) || (page == 1 && ids.length != 0) || page == 'cropPhoto'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="nextPage" > Next < / a >
2023-10-23 03:13:55 +00:00
< template v-if = "!pageLoading && page == 3" >
< b-spinner v-if = "isPosting" small / >
< a v -else class = "font-weight-bold text-decoration-none" href = "#" @click.prevent ="compose()" > Post < / a >
< / template >
2021-01-18 03:25:19 +00:00
< a v-if = "!pageLoading && page == 'addText'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="composeTextPost()" > Post < / a >
2023-10-23 03:13:55 +00:00
< a v-if = "!pageLoading && page == 'video-2'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()" > Post < / a >
< span v-if = "!pageLoading && page == 'filteringMedia'" class="font-weight-bold text-decoration-none text-muted" > Next < / span >
2019-09-13 04:36:12 +00:00
< / span >
2019-09-04 02:31:51 +00:00
< / div >
< / div >
2022-01-23 04:11:34 +00:00
2019-09-05 19:58:27 +00:00
< div class = "card-body p-0 border-top" >
2021-04-01 04:24:59 +00:00
< div v-if = "page == 'licensePicker'" class="w-100 h-100" style="min-height: 280px;" >
< div class = "list-group list-group-flush" >
< div
v - for = "(item, index) in availableLicenses"
2021-04-30 05:27:25 +00:00
class = "list-group-item cursor-pointer"
: class = " {
2021-07-23 15:47:14 +00:00
'text-primary' : licenseId === item . id ,
2023-07-02 04:36:22 +00:00
'font-weight-bold' : licenseId === item . id
2021-04-30 05:27:25 +00:00
} "
2021-07-23 15:47:14 +00:00
@ click = "toggleLicense(item)" >
2021-04-01 04:24:59 +00:00
{ { item . name } }
< / div >
< / div >
< / div >
2021-04-30 05:27:25 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' textOptions ' " class = "w-100 h-100" style = "min-height: 280px;" >
2021-01-18 03:25:19 +00:00
< / div >
2021-04-30 05:27:25 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' addText ' " class = "w-100 h-100" style = "min-height: 280px;" >
2021-01-18 03:25:19 +00:00
< div class = "mt-2" >
< div class = "media px-3" >
< div class = "media-body" >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small d-none" > Body < / label >
< textarea class = "form-control border-0 rounded-0 no-focus" rows = "7" placeholder = "What's happening?" style = "font-size:18px;resize:none" v-model = "composeText" v-on:keyup="composeTextLength = composeText.length" > < / textarea >
< div class = "border-bottom" > < / div >
< p class = "help-text small text-right text-muted mb-0 font-weight-bold" > { { composeTextLength } } / { { config . uploader . max _caption _length } } < / p >
< p class = "mb-0 mt-2" >
< a class = "btn btn-primary rounded-pill mr-2" href = "#" style = "height: 37px;" @click.prevent ="showTextOptions()" >
< i class = "fas fa-palette px-3 text-white" > < / i >
< / a >
<!-- < a class = "btn btn-outline-lighter rounded-pill ml-3" href = "#" @click.prevent ="showLocationCard()" >
< i class = "fas fa-map-marker-alt px-3" > < / i >
< / a >
< a class = "btn btn-outline-lighter rounded-pill mx-3" href = "#" @click.prevent ="showTagCard()" >
< i class = "fas fa-user-plus px-3" > < / i >
< / a > -- >
< a class = "btn rounded-pill mx-3 d-inline-flex align-items-center" href = "#" : class = "[nsfw ? 'btn-danger' : 'btn-outline-lighter']" style = "height: 37px;" @ click.prevent = " nsfw = ! nsfw " title = "Mark as sensitive/not safe for work" >
< i class = "far fa-flag px-3" > < / i > < span class = "text-muted small font-weight-bold" > < / span >
< / a >
< a class = "btn btn-outline-lighter rounded-pill d-inline-flex align-items-center" href = "#" style = "height: 37px;" @click.prevent ="showVisibilityCard()" >
< i class = "fas fa-eye mr-2" > < / i > < span class = "text-muted small font-weight-bold" > { { visibilityTag } } < / span >
< / a >
< / p >
< / div >
< / div >
< / div >
< / div >
< / div >
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = 1 " class = "w-100 h-100 d-flex justify-content-center align-items-center" style = "min-height: 400px;" >
2019-09-05 19:58:27 +00:00
< div class = "text-center" >
2022-01-23 04:11:34 +00:00
< div v-if = "media.length == 0" class="card my-md-3 shadow-none border compose-action text-decoration-none text-dark" >
2021-08-05 02:29:21 +00:00
< div @click.prevent ="addMedia" class = "card-body py-2" >
2019-10-16 03:44:48 +00:00
< div class = "media" >
< div class = "mr-3 align-items-center justify-content-center" style = "display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5" >
2021-08-31 07:30:21 +00:00
< i class = "fal fa-bolt text-white fa-lg" > < / i >
2021-04-30 05:27:25 +00:00
< / div >
2019-10-16 03:44:48 +00:00
< div class = "media-body text-left" >
2020-01-01 03:15:03 +00:00
< p class = "mb-0" >
2021-04-30 05:27:25 +00:00
< span class = "h5 mt-0 font-weight-bold text-primary" > New Post < / span >
2020-01-01 03:15:03 +00:00
< / p >
2020-01-07 06:22:17 +00:00
< p class = "mb-0 text-muted" > Share up to { { config . uploader . album _limit } } photos or videos < / p >
2022-01-23 04:11:34 +00:00
< p class = "mb-0 text-muted small" > < span class = "font-weight-bold" > { { config . uploader . media _types . split ( ',' ) . map ( v => v . split ( '/' ) [ 1 ] ) . join ( ', ' ) } } < / span > allowed up to < span class = "font-weight-bold" > { { filesize ( config . uploader . max _photo _size ) } } < / span > < / p >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< / div >
2020-01-01 03:15:03 +00:00
< / div >
2021-01-18 03:25:19 +00:00
2022-01-23 04:11:34 +00:00
< div v-if = "1==0 && config.ab.top == true && media.length == 0" class="card my-md-3 shadow-none border compose-action text-decoration-none text-dark" >
2021-08-05 02:29:21 +00:00
< div @click.prevent ="addText" class = "card-body py-2" >
2021-01-18 03:25:19 +00:00
< div class = "media" >
< div class = "mr-3 align-items-center justify-content-center" style = "display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5" >
< i class = "far fa-edit text-primary fa-lg" > < / i >
2021-04-30 05:27:25 +00:00
< / div >
2021-01-18 03:25:19 +00:00
< div class = "media-body text-left" >
< p class = "mb-0" >
< span class = "h5 mt-0 font-weight-bold text-primary" > New Text Post < / span >
< sup class = "float-right mt-2" >
< span class = "btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style = "font-size:10px;line-height: 0.6" > BETA < / span >
< / sup >
< / p >
< p class = "mb-0 text-muted" > Share a text only post < / p >
< / div >
< / div >
< / div >
< / div >
2022-01-23 04:11:34 +00:00
< a v-if = "config.features.stories == true" class="card my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/stories/new" >
2021-08-05 02:29:21 +00:00
< div class = "card-body py-2" >
2019-11-24 22:52:46 +00:00
< div class = "media" >
2021-08-31 07:30:21 +00:00
< div class = "mr-3 align-items-center justify-content-center" style = "display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 1px solid #008DF5" >
2020-01-07 06:22:17 +00:00
< i class = "fas fa-history text-primary fa-lg" > < / i >
2021-04-30 05:27:25 +00:00
< / div >
2019-11-24 22:52:46 +00:00
< div class = "media-body text-left" >
< p class = "mb-0" >
2021-04-30 05:27:25 +00:00
< span class = "h5 mt-0 font-weight-bold text-primary" > New Story < / span >
2020-01-07 06:22:17 +00:00
< sup class = "float-right mt-2" >
< span class = "btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style = "font-size:10px;line-height: 0.6" > BETA < / span >
2020-01-01 03:15:03 +00:00
< / sup >
2019-11-24 22:52:46 +00:00
< / p >
2021-08-31 07:30:21 +00:00
< p class = "mb-0 text-muted" > Add to your story < / p >
2019-11-24 22:52:46 +00:00
< / div >
< / div >
< / div >
< / a >
2022-01-23 04:11:34 +00:00
< a v-if = "1==0 && config.ab.polls == true" class="card my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="#" @click.prevent="newPoll" >
2021-08-05 02:29:21 +00:00
< div class = "card-body py-2" >
< div class = "media" >
< div class = "mr-3 align-items-center justify-content-center" style = "display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5" >
< i class = "fas fa-poll-h text-primary fa-lg" > < / i >
< / div >
< div class = "media-body text-left" >
< p class = "mb-0" >
< span class = "h5 mt-0 font-weight-bold text-primary" > New Poll < / span >
< sup class = "float-right mt-2" >
< span class = "btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style = "font-size:10px;line-height: 0.6" > BETA < / span >
< / sup >
< / p >
< p class = "mb-0 text-muted" > Create a poll < / p >
< / div >
< / div >
< / div >
< / a >
2022-01-23 04:11:34 +00:00
< a class = "card my-md-3 shadow-none border compose-action text-decoration-none text-dark" href = "/i/collections/create" >
2021-08-05 02:29:21 +00:00
< div class = "card-body py-2" >
2019-10-16 03:44:48 +00:00
< div class = "media" >
2021-08-31 07:30:21 +00:00
< div class = "mr-3 align-items-center justify-content-center" style = "display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 1px solid #008DF5" >
< i class = "fal fa-images text-primary fa-lg" > < / i >
2021-04-30 05:27:25 +00:00
< / div >
2019-10-16 03:44:48 +00:00
< div class = "media-body text-left" >
< p class = "mb-0" >
2021-04-30 05:27:25 +00:00
< span class = "h5 mt-0 font-weight-bold text-primary" > New Collection < / span >
2020-01-07 06:22:17 +00:00
< sup class = "float-right mt-2" >
< span class = "btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style = "font-size:10px;line-height: 0.6" > BETA < / span >
< / sup >
2019-10-16 03:44:48 +00:00
< / p >
2020-01-07 06:22:17 +00:00
< p class = "mb-0 text-muted" > New collection of posts < / p >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< / div >
< / a >
2020-01-07 06:22:17 +00:00
< p class = "py-3" >
2019-11-24 22:52:46 +00:00
< a class = "font-weight-bold" href = "/site/help" > Help < / a >
2019-09-05 19:58:27 +00:00
< / p >
< / div >
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' cropPhoto ' " class = "w-100 h-100" >
2019-09-05 19:58:27 +00:00
< div v-if = "ids.length > 0" >
< vue-cropper
ref = "cropper"
: relativeZoom = "cropper.zoom"
: aspectRatio = "cropper.aspectRatio"
: viewMode = "cropper.viewMode"
: zoomable = "cropper.zoomable"
: rotatable = "true"
2019-10-16 03:44:48 +00:00
: src = "media[carouselCursor].url"
2019-09-05 19:58:27 +00:00
>
< / vue-cropper >
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-09-05 19:58:27 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = 2 " class = "w-100 h-100" >
2019-10-16 03:44:48 +00:00
< div v-if = "media.length == 1" >
< div slot = "img" style = "display:flex;min-height: 420px;align-items: center;" >
< img : class = "'d-block img-fluid w-100 ' + [media[carouselCursor].filter_class?media[carouselCursor].filter_class:'']" :src = "media[carouselCursor].url" :alt = "media[carouselCursor].description" :title = "media[carouselCursor].description" >
< / div >
< hr >
2022-03-02 08:52:38 +00:00
< div v-if = "ids.length > 0 && media[carouselCursor].type == 'image'" class="align-items-center px-2 pt-2" >
2019-10-16 03:44:48 +00:00
< ul class = "nav media-drawer-filters text-center" >
< li class = "nav-item" >
< div class = "p-1 pt-3" >
< img :src = "media[carouselCursor].url" width = "100px" height = "60px" v -on : click.prevent = " toggleFilter ( $ event , null ) " class = "cursor-pointer" >
< / div >
< a : class = "[media[carouselCursor].filter_class == null ? 'nav-link text-primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , null ) " > No Filter < / a >
< / li >
< li class = "nav-item" v-for = "(filter, index) in filters" >
< div class = "p-1 pt-3" >
2023-10-23 03:13:55 +00:00
< div class = "rounded" :class = "filter[1]" >
< img :src = "media[carouselCursor].url" width = "100px" height = "60px" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " >
< / div >
2019-10-16 03:44:48 +00:00
< / div >
2022-12-31 04:43:23 +00:00
< a : class = "[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " > { { filter [ 0 ] } } < / a >
2019-10-16 03:44:48 +00:00
< / li >
< / ul >
< / div >
2019-09-05 19:58:27 +00:00
< / div >
2019-10-16 03:44:48 +00:00
< div v -else -if = " media.length > 1 " class=" d - flex - inline px - 2 pt - 2 " >
2023-10-23 03:13:55 +00:00
< ul class = "nav media-drawer-filters text-center pb-3" >
2019-10-16 03:44:48 +00:00
< li class = "nav-item mx-md-4" > & nbsp ; < / li >
2023-10-23 03:13:55 +00:00
< li v-for = "(m, i) in media" :key="m.id + ':' + carouselCursor" class="nav-item mx-md-4" >
2019-10-16 03:44:48 +00:00
< div class = "nav-link" style = "display:block;width:300px;height:300px;" @ click = "carouselCursor = i" >
<!-- < img : class = "'d-block img-fluid w-100 ' + [m.filter_class?m.filter_class:'']" :src = "m.url" :alt = "m.description" :title = "m.description" > -- >
2023-10-23 03:13:55 +00:00
< div :class = "[m.filter_class?m.filter_class:'']" style = "width:100%;height:100%;display:block;" >
< div : class = "'rounded ' + [i == carouselCursor ? ' border border-primary shadow':'']" : style = "'display:block;width:100%;height:100%;background-image: url(' + m.url + ');background-size:cover;'" > < / div >
< / div >
2019-10-16 03:44:48 +00:00
< / div >
< div v-if = "i == carouselCursor" class="text-center mb-0 small text-lighter font-weight-bold pt-2" >
2023-10-23 03:13:55 +00:00
< button class = "btn btn-link" @click ="mediaReorder('prev')" > < i class = "far fa-chevron-circle-left" > < / i > < / button >
2019-10-16 03:44:48 +00:00
< span class = "cursor-pointer" @click.prevent ="showCropPhotoCard" > Crop < / span >
< span class = "cursor-pointer px-3" @click.prevent ="showEditMediaCard()" > Edit < / span >
< span class = "cursor-pointer" @click ="deleteMedia()" > Delete < / span >
2023-10-23 03:13:55 +00:00
< button class = "btn btn-link" @click ="mediaReorder('next')" > < i class = "far fa-chevron-circle-right" > < / i > < / button >
2019-10-16 03:44:48 +00:00
< / div >
2019-09-05 19:58:27 +00:00
< / li >
2019-10-16 03:44:48 +00:00
< li class = "nav-item mx-md-4" > & nbsp ; < / li >
2019-09-05 19:58:27 +00:00
< / ul >
2019-10-16 03:44:48 +00:00
< hr >
2022-03-02 08:52:38 +00:00
< div v-if = "ids.length > 0 && media[carouselCursor].type == 'image'" class="align-items-center px-2 pt-2" >
2019-10-16 03:44:48 +00:00
< ul class = "nav media-drawer-filters text-center" >
< li class = "nav-item" >
< div class = "p-1 pt-3" >
< img :src = "media[carouselCursor].url" width = "100px" height = "60px" v -on : click.prevent = " toggleFilter ( $ event , null ) " class = "cursor-pointer" >
< / div >
< a : class = "[media[carouselCursor].filter_class == null ? 'nav-link text-primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , null ) " > No Filter < / a >
< / li >
< li class = "nav-item" v-for = "(filter, index) in filters" >
< div class = "p-1 pt-3" >
< img :src = "media[carouselCursor].url" width = "100px" height = "60px" :class = "filter[1]" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " >
< / div >
2022-12-31 04:43:23 +00:00
< a : class = "[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " > { { filter [ 0 ] } } < / a >
2019-10-16 03:44:48 +00:00
< / li >
< / ul >
< / div >
< / div >
< div v-else >
< p class = "mb-0 p-5 text-center font-weight-bold" > An error occured , please refresh the page . < / p >
2019-09-05 19:58:27 +00:00
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = 3 " class = "w-100 h-100" >
2019-09-05 19:58:27 +00:00
< div class = "border-bottom mt-2" >
< div class = "media px-3" >
< img :src = "media[0].url" width = "42px" height = "42px" : class = "[media[0].filter_class?'mr-2 ' + media[0].filter_class:'mr-2']" >
< div class = "media-body" >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small d-none" > Caption < / label >
2021-03-02 05:04:46 +00:00
< vue-tribute :options = "tributeSettings" >
< textarea class = "form-control border-0 rounded-0 no-focus" rows = "3" placeholder = "Write a caption..." style = "" v-model = "composeText" v-on:keyup="composeTextLength = composeText.length" > < / textarea >
< / vue-tribute >
2019-10-09 04:56:38 +00:00
< p class = "help-text small text-right text-muted mb-0" > { { composeTextLength } } / { { config . uploader . max _caption _length } } < / p >
2019-09-05 19:58:27 +00:00
< / div >
2019-09-04 02:31:51 +00:00
< / div >
< / div >
2019-07-22 02:24:03 +00:00
< / div >
2023-01-31 05:59:33 +00:00
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer d-flex justify-content-between" @click ="showMediaDescriptionsCard()" >
< span > Alt Text < / span >
< span >
< i v-if = "media && media.filter(m => m.alt).length == media.length" class="fas fa-check-circle fa-lg text-success" > < / i >
< i v -else class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
< / span >
< / p >
< / div >
2022-05-18 08:58:49 +00:00
< div class = "border-bottom px-4 mb-0 py-2" >
< div class = "d-flex justify-content-between" >
< div >
2023-01-31 05:59:33 +00:00
< div class = "text-dark " > Sensitive / NSFW Media < / div >
2022-05-18 08:58:49 +00:00
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asnsfw" v-model = "nsfw" >
< label class = "custom-control-label" for = "asnsfw" > < / label >
< / div >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
2022-05-18 08:58:49 +00:00
< div v-if = "nsfw" >
< textarea
class = "form-control mt-3"
placeholder = "Add an optional content warning or spoiler text"
maxlength = "140"
v - model = "spoilerText" >
< / textarea >
< p class = "help-text small text-right text-muted mb-0" > { { spoilerTextLength } } / 140 < / p >
< / div >
2019-09-05 19:58:27 +00:00
< / div >
2020-07-14 23:32:49 +00:00
< div class = "border-bottom" >
2021-04-01 04:24:59 +00:00
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showTagCard()" > Tag people < / p >
< / div >
2022-02-18 02:19:28 +00:00
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showCollectionCard()" >
< span > Add to Collection < span class = "ml-2 badge badge-primary" > NEW < / span > < / span >
< span class = "float-right" >
< span v-if = "collectionsSelected.length" href="#" class="btn btn-outline-secondary btn-sm small mr-3 mt-n1 disabled" style="font-size:10px;padding:3px 5px;text-transform: uppercase" disabled >
{ { collectionsSelected . length } }
< / span >
< span class = "text-decoration-none" > < i class = "fas fa-chevron-right fa-lg text-lighter" > < / i > < / span >
< / span >
< / p >
< / div >
2021-04-01 04:24:59 +00:00
< div class = "border-bottom" >
2021-07-23 15:47:14 +00:00
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showLicenseCard()" >
2022-02-18 02:19:28 +00:00
< span > Add license < / span >
2021-07-23 15:47:14 +00:00
< span class = "float-right" >
< a v-if = "licenseTitle" href="#" @click.prevent="showLicenseCard()" class="btn btn-outline-secondary btn-sm small mr-3 mt-n1 disabled" style="font-size:10px;padding:3px;text-transform: uppercase" disabled > { { licenseTitle } } < / a >
< a href = "#" @click.prevent ="showLicenseCard()" class = "text-decoration-none" > < i class = "fas fa-chevron-right fa-lg text-lighter" > < / i > < / a >
< / span >
< / p >
2020-07-14 23:32:49 +00:00
< / div >
2019-09-05 19:58:27 +00:00
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showLocationCard()" v-if = "!place" > Add location < / p >
< p v -else class = "px-4 mb-0 py-2" >
< span class = "text-lighter" > Location : < / span > { { place . name } } , { { place . country } }
< span class = "float-right" >
2019-10-16 03:44:48 +00:00
< a href = "#" @click.prevent ="showLocationCard()" class = "btn btn-outline-secondary btn-sm small mr-2" style = "font-size:10px;padding:3px;text-transform: uppercase" > Edit < / a >
< a href = "#" @ click.prevent = " place = false " class = "btn btn-outline-secondary btn-sm small" style = "font-size:10px;padding:3px;text-transform: uppercase" > Remove < / a >
2019-09-05 19:58:27 +00:00
< / span >
< / p >
< / div >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2" >
2020-07-14 23:32:49 +00:00
< span > Audience < / span >
2019-09-05 19:58:27 +00:00
< span class = "float-right" >
2020-11-18 21:19:02 +00:00
< a href = "#" @click.prevent ="showVisibilityCard()" class = "btn btn-outline-secondary btn-sm small mr-3 mt-n1 disabled" style = "font-size:10px;padding:3px;text-transform: uppercase" disabled > { { visibilityTag } } < / a >
2020-07-14 23:32:49 +00:00
< a href = "#" @click.prevent ="showVisibilityCard()" class = "text-decoration-none" > < i class = "fas fa-chevron-right fa-lg text-lighter" > < / i > < / a >
2019-09-05 19:58:27 +00:00
< / span >
< / p >
< / div >
2019-10-16 03:44:48 +00:00
<!-- < div class = "cursor-pointer border-bottom px-4 mb-0 py-2" @click.prevent ="showMediaDescriptionsCard()" >
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "text-dark" > Media Descriptions < / div >
< p class = "text-muted small mb-0" > Describe your photos for people with visual impairments . < / p >
< / div >
< div >
< i class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
< / div >
< / div >
< / div > -- >
2019-09-05 19:58:27 +00:00
< div style = "min-height: 200px;" >
< p class = "px-4 mb-0 py-2 small font-weight-bold text-muted cursor-pointer" @click ="showAdvancedSettingsCard()" > Advanced settings < / p >
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-02-27 07:03:46 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' tagPeople ' " class = "w-100 h-100 p-3" >
2021-04-30 05:27:25 +00:00
< autocomplete
2020-07-14 23:32:49 +00:00
v - show = "taggedUsernames.length < 10"
: search = "tagSearch"
placeholder = "@pixelfed"
aria - label = "Search usernames"
: get - result - value = "getTagResultValue"
@ submit = "onTagSubmitLocation"
ref = "autocomplete"
>
< / autocomplete >
< p v-show = "taggedUsernames.length < 10" class="font-weight-bold text-muted small" > You can tag {{ 10 - taggedUsernames.length }} more {{ taggedUsernames.length = = 9 ? ' person ' : ' people ' }} ! < / p >
< p class = "font-weight-bold text-center mt-3" > Tagged People < / p >
< div class = "list-group" >
< div v-for = "(tag, index) in taggedUsernames" class="list-group-item d-flex justify-content-between" >
< div class = "media" >
< img class = "mr-2 rounded-circle border" :src = "tag.avatar" width = "24px" height = "24px" >
< div class = "media-body" >
< span class = "font-weight-bold" > { { tag . name } } < / span >
< / div >
< / div >
< div class = "custom-control custom-switch" >
< input type = "checkbox" class = "custom-control-input disabled" :id = "'cci-tagged-privacy-switch'+index" v-model = "tag.privacy" disabled >
< label class = "custom-control-label font-weight-bold text-lighter" :for = "'cci-tagged-privacy-switch'+index" > { { tag . privacy ? 'Public' : 'Private' } } < / label >
< a href = "#" @click.prevent ="untagUsername(index)" class = "ml-3" > < i class = "fas fa-times text-muted" > < / i > < / a > < / div >
< / div >
< div v-if = "taggedUsernames.length == 0" class="list-group-item p-3" >
< p class = "text-center mb-0 font-weight-bold text-lighter" > Search usernames to tag . < / p >
< / div >
< / div >
< p class = "font-weight-bold text-center small text-muted pt-3 mb-0" > When you tag someone , they are sent a notification . < br > For more information on tagging , < a href = "#" class = "text-primary" @click.prevent ="showTagHelpCard()" > click here < / a > . < / p >
< / div >
2020-12-14 00:38:41 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' tagPeopleHelp ' " class = "w-100 h-100 p-3" >
2020-07-14 23:32:49 +00:00
< p class = "mb-0 text-center py-3 px-2 lead" > Tagging someone is like mentioning them , with the option to make it private between you . < / p >
< p class = "mb-3 py-3 px-2 font-weight-lighter" >
You can choose to tag someone in public or private mode . Public mode will allow others to see who you tagged in the post and private mode tagged users will not be shown to others .
< / p >
2019-09-05 19:58:27 +00:00
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' addLocation ' " class = "w-100 h-100 p-3" >
2019-09-05 19:58:27 +00:00
< p class = "mb-0" > Add Location < / p >
2021-04-30 05:27:25 +00:00
< autocomplete
2019-09-05 19:58:27 +00:00
: search = "locationSearch"
placeholder = "Search locations ..."
aria - label = "Search locations ..."
: get - result - value = "getResultValue"
@ submit = "onSubmitLocation"
>
< / autocomplete >
< / div >
2019-02-27 07:03:46 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' advancedSettings ' " class = "w-100 h-100" >
2019-09-05 19:58:27 +00:00
< div class = "list-group list-group-flush" >
2021-01-18 03:25:19 +00:00
<!-- < div class = "d-none list-group-item d-flex justify-content-between" >
< div >
< div class = "text-dark " > Optimize Media < / div >
< p v-if = "mediaCropped" class="text-muted small mb-0" > Media was cropped or filtered , it must be optimized. < / p >
< p v -else class = "text-muted small mb-0" > Compress media for smaller file size . < / p >
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asoptimizemedia" v-model ="optimizeMedia" :disabled ="mediaCropped" >
< label class = "custom-control-label" for = "asoptimizemedia" > < / label >
< / div >
< / div >
< / div > -- >
2019-09-05 19:58:27 +00:00
< div class = "list-group-item d-flex justify-content-between" >
< div >
< div class = "text-dark " > Turn off commenting < / div >
< p class = "text-muted small mb-0" > Disables comments for this post , you can change this later . < / p >
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asdisablecomments" v-model = "commentsDisabled" >
< label class = "custom-control-label" for = "asdisablecomments" > < / label >
< / div >
2019-09-04 02:31:51 +00:00
< / div >
< / div >
2019-10-16 03:44:48 +00:00
< a href = "#" class = "list-group-item" @click.prevent ="showMediaDescriptionsCard()" >
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "text-dark" > Media Descriptions < / div >
< p class = "text-muted small mb-0" > Describe your photos for people with visual impairments . < / p >
< / div >
< div >
< i class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
2019-09-05 19:58:27 +00:00
< / div >
2019-09-04 02:31:51 +00:00
< / div >
2019-09-05 19:58:27 +00:00
< / a >
2019-10-16 03:44:48 +00:00
<!-- < a href = "#" class = "list-group-item" @click.prevent ="showAddToCollectionsCard()" >
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "text-dark" > Add to Collection < / div >
< p class = "text-muted small mb-0" > Add this post to a collection . < / p >
< / div >
< div >
< i class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
< / div >
< / div >
2019-09-05 19:58:27 +00:00
< / a >
< a href = "#" class = "list-group-item" @ click.prevent = " page = 'schedulePost' " >
2019-10-16 03:44:48 +00:00
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "text-dark" > Schedule < / div >
< p class = "text-muted small mb-0" > Schedule post for a future date . < / p >
< / div >
< div >
< i class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
< / div >
< / div >
2019-09-05 19:58:27 +00:00
< / a >
< a href = "#" class = "list-group-item" @ click.prevent = " page = 'mediaMetadata' " >
2019-10-16 03:44:48 +00:00
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "text-dark" > Metadata < / div >
< p class = "text-muted small mb-0" > Manage media exif and metadata . < / p >
< / div >
< div >
< i class = "fas fa-chevron-right fa-lg text-lighter" > < / i >
< / div >
< / div >
< / a > -- >
2019-02-27 07:03:46 +00:00
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' visibility ' " class = "w-100 h-100" >
2019-09-05 19:58:27 +00:00
< div class = "list-group list-group-flush" >
2021-03-01 05:35:43 +00:00
< div
v - if = "!profile.locked"
2021-04-30 05:27:25 +00:00
class = "list-group-item lead cursor-pointer"
: class = "{ 'text-primary': visibility == 'public' }"
2021-03-01 05:35:43 +00:00
@ click = "toggleVisibility('public')" >
Public
< / div >
< div
v - if = "!profile.locked"
2021-04-30 05:27:25 +00:00
class = "list-group-item lead cursor-pointer"
: class = "{ 'text-primary': visibility == 'unlisted' }"
2021-03-01 05:35:43 +00:00
@ click = "toggleVisibility('unlisted')" >
Unlisted
< / div >
2021-04-30 05:27:25 +00:00
< div
class = "list-group-item lead cursor-pointer"
: class = "{ 'text-primary': visibility == 'private' }"
2021-03-01 05:35:43 +00:00
@ click = "toggleVisibility('private')" >
Followers Only
< / div >
2019-09-05 19:58:27 +00:00
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' altText ' " class = "w-100 h-100 p-3" >
2019-10-16 03:44:48 +00:00
< div v-for = "(m, index) in media" >
< div class = "media" >
< img :src = "m.preview_url" class = "mr-3" width = "50px" height = "50px" >
< div class = "media-body" >
2021-07-25 03:15:15 +00:00
< textarea class = "form-control" v-model = "m.alt" placeholder="Add a media description here..." :maxlength="maxAltTextLength" rows="4" > < / textarea >
< p class = "help-text small text-right text-muted mb-0" > { { m . alt ? m . alt . length : 0 } } / { { maxAltTextLength } } < / p >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< hr >
< / div >
< p class = "d-flex justify-content-between mb-0" >
< button type = "button" @click ="goBack()" class = "btn btn-link text-muted font-weight-bold text-decoration-none" > Cancel < / button >
< button type = "button" @click ="goBack()" class = "btn btn-primary font-weight-bold" > Save < / button >
< / p >
2019-09-05 19:58:27 +00:00
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' addToCollection ' " class = "w-100 h-100 p-3" >
2022-02-18 02:19:28 +00:00
< div v-if = "collectionsLoaded && collections.length" class="list-group mb-3 collections-list-group" >
< div
v - for = "(collection, index) in collections"
class = "list-group-item cursor-pointer compose-action border"
: class = "{ active: collectionsSelected.includes(index) }"
@ click = "toggleCollectionItem(index)" >
2019-10-16 03:44:48 +00:00
< div class = "media" >
2022-02-18 02:19:28 +00:00
< img :src = "collection.thumb" class = "mr-3" alt = "" width = "50px" height = "50px" >
2019-10-16 03:44:48 +00:00
< div class = "media-body" >
2022-02-18 02:19:28 +00:00
< h5 class = "mt-0" > { { collection . title } } < / h5 >
< p class = "mb-0 text-muted small" > { { collection . post _count } } Posts - Created { { timeAgo ( collection . published _at ) } } ago < / p >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< / div >
2022-02-18 02:19:28 +00:00
< button
v - if = "collectionsCanLoadMore"
class = "btn btn-light btn-block font-weight-bold mt-3"
@ click = "loadMoreCollections" >
Load more
< / button >
2019-10-16 03:44:48 +00:00
< / div >
< p class = "d-flex justify-content-between mb-0" >
2022-02-18 02:19:28 +00:00
< button type = "button" @click ="clearSelectedCollections()" class = "btn btn-link text-muted font-weight-bold text-decoration-none" > Clear < / button >
2019-10-16 03:44:48 +00:00
< button type = "button" @click ="goBack()" class = "btn btn-primary font-weight-bold" > Save < / button >
< / p >
2019-09-05 19:58:27 +00:00
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' schedulePost ' " class = "w-100 h-100 p-3" >
2019-09-05 19:58:27 +00:00
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' mediaMetadata ' " class = "w-100 h-100 p-3" >
2019-09-05 19:58:27 +00:00
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' addToStory ' " class = "w-100 h-100 p-3" >
2019-09-05 19:58:27 +00:00
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
2019-09-04 02:31:51 +00:00
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' editMedia ' " class = "w-100 h-100 p-3" >
2019-10-16 03:44:48 +00:00
< div class = "media" >
< img :src = "media[carouselCursor].preview_url" class = "mr-3" width = "50px" height = "50px" >
< div class = "media-body" >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small" > Media Description < / label >
2020-12-14 00:38:41 +00:00
< textarea class = "form-control" v-model = "media[carouselCursor].alt" placeholder="Add a media description here..." maxlength="140" > < / textarea >
2019-10-16 03:44:48 +00:00
< p class = "help-text small text-muted mb-0 d-flex justify-content-between" >
< span > Describe your photo for people with visual impairments . < / span >
< span > { { media [ carouselCursor ] . alt ? media [ carouselCursor ] . alt . length : 0 } } / 140 < / span >
< / p >
< / div >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small" > License < / label >
2021-04-01 04:24:59 +00:00
<!-- < input type = "text" class = "form-control" v-model = "media[carouselCursor].license" placeholder="All Rights Reserved (Default license)" > - - >
<!-- < p class = "help-text small text-muted mb-0 d-flex justify-content-between" >
2019-10-16 03:44:48 +00:00
< span > < / span >
< span > { { media [ carouselCursor ] . license ? media [ carouselCursor ] . license . length : 0 } } / 140 < / span >
2021-04-01 04:24:59 +00:00
< / p > -- >
2021-07-23 15:47:14 +00:00
< select class = "form-control" v-model = "licenseId" >
2021-04-30 05:27:25 +00:00
< option
2021-04-01 04:24:59 +00:00
v - for = "(item, index) in availableLicenses"
2021-07-23 15:47:14 +00:00
: value = "item.id"
: selected = "item.id == licenseId" >
2021-04-01 04:24:59 +00:00
{ { item . name } }
< / option >
< / select >
2019-10-16 03:44:48 +00:00
< / div >
< / div >
< / div >
< hr >
< p class = "d-flex justify-content-between mb-0" >
< button type = "button" @click ="goBack()" class = "btn btn-link text-muted font-weight-bold text-decoration-none" > Cancel < / button >
< button type = "button" @click ="goBack()" class = "btn btn-primary font-weight-bold" > Save < / button >
< / p >
< / div >
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' video -2 ' " class = "w-100 h-100" >
2021-04-30 05:27:25 +00:00
< div v-if = "video.title.length" class="border-bottom" >
< div class = "media p-3" >
< img :src = "media[0].url" width = "100px" height = "70px" : class = "[media[0].filter_class?'mr-2 ' + media[0].filter_class:'mr-2']" >
< div class = "media-body" >
< p class = "font-weight-bold mb-1" > { { video . title ? video . title . slice ( 0 , 70 ) : 'Untitled' } } < / p >
< p class = "mb-0 text-muted small" > { { video . description ? video . description . slice ( 0 , 90 ) : 'No description' } } < / p >
< / div >
< / div >
< / div >
< div class = "border-bottom d-flex justify-content-between px-4 mb-0 py-2 " >
< div >
< div class = "text-dark " > Contains NSFW Media < / div >
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asnsfw" v-model = "nsfw" >
< label class = "custom-control-label" for = "asnsfw" > < / label >
< / div >
< / div >
< / div >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showLicenseCard()" > Add license < / p >
< / div >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2" >
< span > Audience < / span >
< span class = "float-right" >
< a href = "#" @click.prevent ="showVisibilityCard()" class = "btn btn-outline-secondary btn-sm small mr-3 mt-n1 disabled" style = "font-size:10px;padding:3px;text-transform: uppercase" disabled > { { visibilityTag } } < / a >
< a href = "#" @click.prevent ="showVisibilityCard()" class = "text-decoration-none" > < i class = "fas fa-chevron-right fa-lg text-lighter" > < / i > < / a >
< / span >
< / p >
< / div >
< div class = "p-3" >
<!-- < div class = "card card-body shadow-none border d-flex justify-content-center align-items-center mb-3 p-5" >
< div class = "d-flex align-items-center" >
< p class = "mb-0 text-center" >
< div class = "spinner-border text-primary" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / p >
< p class = "ml-3 mb-0 text-center font-weight-bold" >
Processing video
< / p >
< / div >
< / div > -- >
< div class = "form-group" >
< p class = "small font-weight-bold text-muted mb-0" > Title < / p >
< input class = "form-control" v-model = "video.title" placeholder="Add a good title" >
< p class = "help-text mb-0 small text-muted" > { { video . title . length } } / 70 < / p >
< / div >
< div class = "form-group mb-0" >
< p class = "small font-weight-bold text-muted mb-0" > Description < / p >
< textarea class = "form-control" v-model = "video.description" placeholder="Add an optional description" maxlength="5000" rows="5" > < / textarea >
< p class = "help-text mb-0 small text-muted" > { { video . description . length } } / 5000 < / p >
< / div >
< / div >
< / div >
2023-10-23 03:13:55 +00:00
< div v -else -if = " page = = ' filteringMedia ' " class = "w-100 h-100 py-5" >
< div class = "d-flex flex-column align-items-center justify-content-center py-5" >
< b-spinner small / >
< p class = "font-weight-bold mt-3" > Applying filters ... < / p >
< / div >
< / div >
2019-09-04 02:31:51 +00:00
< / div >
2019-09-05 19:58:27 +00:00
<!-- card - footers -- >
2019-09-13 04:36:12 +00:00
< div v-if = "page == 'cropPhoto'" class="card-footer bg-white d-flex justify-content-between" >
2019-09-05 19:58:27 +00:00
< div >
2020-06-30 04:03:58 +00:00
< button type = "button" class = "btn btn-outline-secondary" @click ="rotate" > < i class = "fas fa-redo" > < / i > < / button >
2019-09-05 19:58:27 +00:00
< / div >
< div >
< div class = "d-inline-block button-group" >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 16/9 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(16/9)" > 16 : 9 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 4/3 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(4/3)" > 4 : 3 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 3/2 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(3/2)" > 3 : 2 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 1 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(1)" > 1 : 1 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 2/3 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(2/3)" > 2 : 3 < / button >
< / div >
2019-02-27 07:03:46 +00:00
< / div >
< / div >
< / div >
< / div >
< / div >
2019-07-09 05:23:59 +00:00
< / div >
2019-02-27 07:03:46 +00:00
< / template >
< script type = "text/javascript" >
2019-09-04 02:31:51 +00:00
import VueCropper from 'vue-cropperjs' ;
import 'cropperjs/dist/cropper.css' ;
import Autocomplete from '@trevoreyre/autocomplete-vue'
import '@trevoreyre/autocomplete-vue/dist/style.css'
2021-03-02 05:04:46 +00:00
import VueTribute from 'vue-tribute'
2019-09-04 02:31:51 +00:00
2019-02-27 07:03:46 +00:00
export default {
2021-03-02 05:04:46 +00:00
2021-04-30 05:27:25 +00:00
components : {
2019-09-04 02:31:51 +00:00
VueCropper ,
2021-03-02 05:04:46 +00:00
Autocomplete ,
VueTribute
2019-09-04 02:31:51 +00:00
} ,
2019-02-27 07:03:46 +00:00
data ( ) {
return {
2019-08-05 04:02:10 +00:00
config : window . App . config ,
2019-09-04 02:31:51 +00:00
pageLoading : false ,
2021-03-01 05:35:43 +00:00
profile : window . _sharedData . curUser ,
2019-03-26 04:22:43 +00:00
composeText : '' ,
2019-03-26 04:22:25 +00:00
composeTextLength : 0 ,
2019-02-27 07:03:46 +00:00
nsfw : false ,
filters : [ ] ,
2020-07-14 23:32:49 +00:00
currentFilter : false ,
2019-02-27 07:03:46 +00:00
ids : [ ] ,
media : [ ] ,
carouselCursor : 0 ,
2019-04-16 01:39:54 +00:00
uploading : false ,
2019-09-04 02:31:51 +00:00
uploadProgress : 100 ,
2021-04-30 05:27:25 +00:00
mode : 'photo' ,
modes : [
'photo' ,
'video' ,
'plain'
] ,
2019-09-04 02:31:51 +00:00
page : 1 ,
composeState : 'publish' ,
visibility : 'public' ,
visibilityTag : 'Public' ,
place : false ,
commentsDisabled : false ,
2021-01-18 03:25:19 +00:00
optimizeMedia : true ,
mediaCropped : false ,
2019-09-04 02:31:51 +00:00
pageTitle : '' ,
cropper : {
aspectRatio : 1 ,
viewMode : 1 ,
zoomable : true ,
zoom : 0
} ,
namedPages : [
2023-10-23 03:13:55 +00:00
'filteringMedia' ,
2019-09-13 04:36:12 +00:00
'cropPhoto' ,
2019-09-04 02:31:51 +00:00
'tagPeople' ,
'addLocation' ,
'advancedSettings' ,
'visibility' ,
'altText' ,
'addToCollection' ,
'schedulePost' ,
'mediaMetadata' ,
2019-10-16 03:44:48 +00:00
'addToStory' ,
'editMedia' ,
2020-07-14 23:32:49 +00:00
'cameraRoll' ,
2021-01-18 03:25:19 +00:00
'tagPeopleHelp' ,
2021-04-01 04:24:59 +00:00
'textOptions' ,
'licensePicker'
2019-10-16 03:44:48 +00:00
] ,
2020-07-14 23:32:49 +00:00
cameraRollMedia : [ ] ,
taggedUsernames : [ ] ,
2021-01-18 03:25:19 +00:00
taggedPeopleSearch : null ,
2021-03-02 05:04:46 +00:00
textMode : false ,
tributeSettings : {
2022-03-02 10:20:54 +00:00
noMatchTemplate : function ( ) { return null ; } ,
2021-03-02 05:04:46 +00:00
collection : [
{
trigger : '@' ,
menuShowMinLength : 2 ,
values : ( function ( text , cb ) {
let url = '/api/compose/v0/search/mention' ;
axios . get ( url , { params : { q : text } } )
. then ( res => {
cb ( res . data ) ;
} )
. catch ( err => {
} )
} )
} ,
{
trigger : '#' ,
menuShowMinLength : 2 ,
values : ( function ( text , cb ) {
let url = '/api/compose/v0/search/hashtag' ;
axios . get ( url , { params : { q : text } } )
. then ( res => {
cb ( res . data ) ;
} )
. catch ( err => {
} )
} )
}
]
2021-04-01 04:24:59 +00:00
} ,
availableLicenses : [
{
id : 1 ,
2021-07-23 15:47:14 +00:00
name : "All Rights Reserved" ,
title : ""
2021-04-01 04:24:59 +00:00
} ,
{
id : 5 ,
2021-07-23 15:47:14 +00:00
name : "Public Domain Work" ,
title : ""
2021-04-01 04:24:59 +00:00
} ,
{
id : 6 ,
2021-07-23 15:47:14 +00:00
name : "Public Domain Dedication (CC0)" ,
title : "CC0"
2021-04-01 04:24:59 +00:00
} ,
{
id : 11 ,
2021-07-23 15:47:14 +00:00
name : "Attribution" ,
title : "CC BY"
2021-04-01 04:24:59 +00:00
} ,
{
id : 12 ,
2021-07-23 15:47:14 +00:00
name : "Attribution-ShareAlike" ,
title : "CC BY-SA"
2021-04-01 04:24:59 +00:00
} ,
{
id : 13 ,
2021-07-23 15:47:14 +00:00
name : "Attribution-NonCommercial" ,
title : "CC BY-NC"
2021-04-01 04:24:59 +00:00
} ,
{
id : 14 ,
2021-07-23 15:47:14 +00:00
name : "Attribution-NonCommercial-ShareAlike" ,
title : "CC BY-NC-SA"
2021-04-01 04:24:59 +00:00
} ,
{
id : 15 ,
2021-07-23 15:47:14 +00:00
name : "Attribution-NoDerivs" ,
title : "CC BY-ND"
2021-04-01 04:24:59 +00:00
} ,
{
id : 16 ,
2021-07-23 15:47:14 +00:00
name : "Attribution-NonCommercial-NoDerivs" ,
title : "CC BY-NC-ND"
2021-04-01 04:24:59 +00:00
}
] ,
2021-04-30 05:27:25 +00:00
licenseIndex : 0 ,
video : {
title : '' ,
description : ''
2021-07-23 15:47:14 +00:00
} ,
composeSettings : {
default _license : null ,
media _descriptions : false
} ,
2021-07-25 03:15:15 +00:00
licenseId : 1 ,
licenseTitle : null ,
2021-08-05 02:29:21 +00:00
maxAltTextLength : 140 ,
pollOptionModel : null ,
pollOptions : [ ] ,
pollExpiry : 1440 ,
2022-02-18 02:19:28 +00:00
postingPoll : false ,
collections : [ ] ,
collectionsSelected : [ ] ,
collectionsLoaded : false ,
collectionsPage : 1 ,
collectionsCanLoadMore : false ,
2022-05-18 08:58:49 +00:00
spoilerText : undefined ,
2023-10-23 03:13:55 +00:00
isFilteringMedia : false ,
filteringMediaTimeout : undefined ,
filteringRemainingCount : 0 ,
isPosting : false ,
2022-05-18 08:58:49 +00:00
}
} ,
computed : {
spoilerTextLength : function ( ) {
return this . spoilerText ? this . spoilerText . length : 0 ;
2019-02-27 07:03:46 +00:00
}
} ,
beforeMount ( ) {
2022-12-31 04:43:23 +00:00
this . filters = window . App . util . filters . sort ( ) ;
2021-07-23 15:47:14 +00:00
axios . get ( '/api/compose/v0/settings' )
. then ( res => {
this . composeSettings = res . data ;
this . licenseId = this . composeSettings . default _license ;
2021-07-25 03:15:15 +00:00
this . maxAltTextLength = res . data . max _altext _length ;
2021-07-23 15:47:14 +00:00
if ( this . licenseId > 10 ) {
this . licenseTitle = this . availableLicenses . filter ( l => {
return l . id == this . licenseId ;
} ) . map ( l => {
return l . title ;
} ) [ 0 ] ;
}
2021-12-15 05:25:50 +00:00
this . fetchProfile ( ) ;
2021-07-23 15:47:14 +00:00
} ) ;
2019-02-27 07:03:46 +00:00
} ,
mounted ( ) {
this . mediaWatcher ( ) ;
2019-10-16 03:44:48 +00:00
} ,
2019-02-27 07:03:46 +00:00
methods : {
2022-02-18 02:19:28 +00:00
timeAgo ( ts ) {
return App . util . format . timeAgo ( ts ) ;
} ,
2023-10-04 19:02:55 +00:00
formatBytes ( bytes , decimals = 2 ) {
if ( ! + bytes ) {
return '0 Bytes'
}
const dec = decimals < 0 ? 0 : decimals
const units = [ 'Bytes' , 'KB' , 'MB' , 'GB' , 'TB' ] ;
const quotient = Math . floor ( Math . log ( bytes ) / Math . log ( 1024 ) )
return ` ${ parseFloat ( ( bytes / Math . pow ( 1024 , quotient ) ) . toFixed ( dec ) ) } ${ units [ quotient ] } `
} ,
2019-02-27 07:03:46 +00:00
fetchProfile ( ) {
2021-12-15 05:25:50 +00:00
let tags = {
public : 'Public' ,
private : 'Followers Only' ,
unlisted : 'Unlisted'
}
2021-03-01 05:35:43 +00:00
if ( window . _sharedData . curUser . id ) {
this . profile = window . _sharedData . curUser ;
2021-12-15 05:25:50 +00:00
if ( this . composeSettings && this . composeSettings . hasOwnProperty ( 'default_scope' ) && this . composeSettings . default _scope ) {
let ds = this . composeSettings . default _scope ;
this . visibility = ds ;
this . visibilityTag = tags [ ds ] ;
}
2021-03-01 05:35:43 +00:00
if ( this . profile . locked == true ) {
this . visibility = 'private' ;
this . visibilityTag = 'Followers Only' ;
2019-04-13 04:45:27 +00:00
}
2020-12-05 07:24:26 +00:00
} else {
axios . get ( '/api/pixelfed/v1/accounts/verify_credentials' ) . then ( res => {
2021-03-01 05:35:43 +00:00
window . _sharedData . currentUser = res . data ;
this . profile = res . data ;
2021-12-15 05:25:50 +00:00
if ( this . composeSettings && this . composeSettings . hasOwnProperty ( 'default_scope' ) && this . composeSettings . default _scope ) {
let ds = this . composeSettings . default _scope ;
this . visibility = ds ;
this . visibilityTag = tags [ ds ] ;
}
2021-03-01 05:35:43 +00:00
if ( this . profile . locked == true ) {
this . visibility = 'private' ;
this . visibilityTag = 'Followers Only' ;
2020-12-05 07:24:26 +00:00
}
} ) . catch ( err => {
} ) ;
}
2019-02-27 07:03:46 +00:00
} ,
2019-05-05 20:39:02 +00:00
addMedia ( event ) {
2019-02-27 07:03:46 +00:00
let el = $ ( event . target ) ;
el . attr ( 'disabled' , '' ) ;
let fi = $ ( '.file-input[name="media"]' ) ;
fi . trigger ( 'click' ) ;
el . blur ( ) ;
el . removeAttr ( 'disabled' ) ;
} ,
2021-01-18 03:25:19 +00:00
addText ( event ) {
this . pageTitle = 'New Text Post' ;
this . page = 'addText' ;
this . textMode = true ;
2021-04-30 05:27:25 +00:00
this . mode = 'text' ;
2021-01-18 03:25:19 +00:00
} ,
2019-02-27 07:03:46 +00:00
mediaWatcher ( ) {
let self = this ;
2019-09-04 02:31:51 +00:00
$ ( document ) . on ( 'change' , '#pf-dz' , function ( e ) {
self . mediaUpload ( ) ;
} ) ;
} ,
2019-02-27 07:03:46 +00:00
2019-09-04 02:31:51 +00:00
mediaUpload ( ) {
let self = this ;
self . uploading = true ;
let io = document . querySelector ( '#pf-dz' ) ;
2020-11-18 21:19:02 +00:00
if ( ! io . files . length ) {
self . uploading = false ;
}
2019-09-04 02:31:51 +00:00
Array . prototype . forEach . call ( io . files , function ( io , i ) {
if ( self . media && self . media . length + i >= self . config . uploader . album _limit ) {
swal ( 'Error' , 'You can only upload ' + self . config . uploader . album _limit + ' photos per album' , 'error' ) ;
2019-10-16 03:44:48 +00:00
self . uploading = false ;
self . page = 2 ;
2019-09-04 02:31:51 +00:00
return ;
}
let type = io . type ;
let acceptedMimes = self . config . uploader . media _types . split ( ',' ) ;
let validated = $ . inArray ( type , acceptedMimes ) ;
if ( validated == - 1 ) {
swal ( 'Invalid File Type' , 'The file you are trying to add is not a valid mime type. Please upload a ' + self . config . uploader . media _types + ' only.' , 'error' ) ;
2019-10-16 03:44:48 +00:00
self . uploading = false ;
self . page = 2 ;
2019-09-04 02:31:51 +00:00
return ;
}
2019-02-27 07:03:46 +00:00
2019-09-04 02:31:51 +00:00
let form = new FormData ( ) ;
form . append ( 'file' , io ) ;
2019-02-27 07:03:46 +00:00
2019-09-04 02:31:51 +00:00
let xhrConfig = {
onUploadProgress : function ( e ) {
let progress = Math . round ( ( e . loaded * 100 ) / e . total ) ;
self . uploadProgress = progress ;
}
} ;
2021-01-18 03:25:19 +00:00
axios . post ( '/api/compose/v0/media/upload' , form , xhrConfig )
2019-09-04 02:31:51 +00:00
. then ( function ( e ) {
self . uploadProgress = 100 ;
self . ids . push ( e . data . id ) ;
self . media . push ( e . data ) ;
2019-10-16 03:44:48 +00:00
self . uploading = false ;
2021-02-07 04:00:42 +00:00
setTimeout ( function ( ) {
2021-04-30 05:27:25 +00:00
// if(type === 'video/mp4') {
// self.pageTitle = 'Edit Video Details';
// self.mode = 'video';
// self.page = 'video-2';
// } else {
// self.page = 2;
// }
self . page = 3 ;
2021-02-07 04:00:42 +00:00
} , 300 ) ;
2019-09-04 02:31:51 +00:00
} ) . catch ( function ( e ) {
2020-07-26 02:55:40 +00:00
switch ( e . response . status ) {
2023-10-04 19:02:55 +00:00
case 413 :
self . uploading = false ;
io . value = null ;
swal ( 'File is too large' , 'The file you uploaded has the size of ' + self . formatBytes ( io . size ) + '. Unfortunately, only images up to ' + self . formatBytes ( self . config . uploader . max _photo _size * 1024 ) + ' are supported.\nPlease resize the file and try again.' , 'error' ) ;
self . page = 2 ;
break ;
2020-07-26 02:55:40 +00:00
case 451 :
self . uploading = false ;
io . value = null ;
swal ( 'Banned Content' , 'This content has been banned and cannot be uploaded.' , 'error' ) ;
self . page = 2 ;
break ;
2021-03-02 03:58:35 +00:00
case 429 :
self . uploading = false ;
io . value = null ;
swal ( 'Limit Reached' , 'You can upload up to 250 photos or videos per day and you\'ve reached that limit. Please try again later.' , 'error' ) ;
self . page = 2 ;
break ;
2023-02-02 05:58:06 +00:00
case 500 :
self . uploading = false ;
io . value = null ;
swal ( 'Error' , e . response . data . message , 'error' ) ;
self . page = 2 ;
break ;
2020-07-26 02:55:40 +00:00
default :
self . uploading = false ;
io . value = null ;
swal ( 'Oops, something went wrong!' , 'An unexpected error occurred.' , 'error' ) ;
self . page = 2 ;
break ;
}
2019-02-27 07:03:46 +00:00
} ) ;
2019-09-04 02:31:51 +00:00
io . value = null ;
self . uploadProgress = 0 ;
2019-02-27 07:03:46 +00:00
} ) ;
} ,
2019-03-26 04:22:25 +00:00
toggleFilter ( e , filter ) {
this . media [ this . carouselCursor ] . filter _class = filter ;
2020-07-14 23:32:49 +00:00
this . currentFilter = filter ;
2019-02-27 07:03:46 +00:00
} ,
deleteMedia ( ) {
2019-07-20 02:31:29 +00:00
if ( window . confirm ( 'Are you sure you want to delete this media?' ) == false ) {
2019-03-26 04:22:25 +00:00
return ;
}
2019-02-27 07:03:46 +00:00
let id = this . media [ this . carouselCursor ] . id ;
2021-04-30 05:27:25 +00:00
2021-01-18 03:25:19 +00:00
axios . delete ( '/api/compose/v0/media/delete' , {
2019-02-27 07:03:46 +00:00
params : {
id : id
}
} ) . then ( res => {
2019-10-16 03:44:48 +00:00
this . ids . splice ( this . carouselCursor , 1 ) ;
this . media . splice ( this . carouselCursor , 1 ) ;
if ( this . media . length == 0 ) {
2019-03-26 04:22:25 +00:00
this . ids = [ ] ;
this . media = [ ] ;
this . carouselCursor = 0 ;
2019-10-16 03:44:48 +00:00
} else {
this . carouselCursor = 0 ;
2019-02-27 07:03:46 +00:00
}
} ) . catch ( err => {
swal ( 'Whoops!' , 'An error occured when attempting to delete this, please try again' , 'error' ) ;
} ) ;
} ,
2023-10-23 03:13:55 +00:00
mediaReorder ( dir ) {
const m = this . media ;
const cur = this . carouselCursor ;
const pla = m [ cur ] ;
let res = [ ] ;
let cursor = 0 ;
if ( dir == 'prev' ) {
if ( cur == 0 ) {
for ( let i = cursor ; i < m . length - 1 ; i ++ ) {
res [ i ] = m [ i + 1 ] ;
}
res [ m . length - 1 ] = pla ;
cursor = 0 ;
} else {
res = this . handleSwap ( m , cur , cur - 1 ) ;
cursor = cur - 1 ;
}
} else {
if ( cur == m . length - 1 ) {
res = m ;
let lastItem = res . pop ( ) ;
res . unshift ( lastItem ) ;
cursor = m . length - 1 ;
} else {
res = this . handleSwap ( m , cur , cur + 1 ) ;
cursor = cur + 1 ;
}
}
this . $nextTick ( ( ) => {
this . media = res ;
this . carouselCursor = cursor ;
} )
} ,
handleSwap ( arr , index1 , index2 ) {
if ( index1 >= 0 && index1 < arr . length && index2 >= 0 && index2 < arr . length ) {
const temp = arr [ index1 ] ;
arr [ index1 ] = arr [ index2 ] ;
arr [ index2 ] = temp ;
return arr ;
}
} ,
2019-02-27 07:03:46 +00:00
compose ( ) {
2019-03-26 04:22:25 +00:00
let state = this . composeState ;
2019-06-11 18:50:35 +00:00
if ( this . uploadProgress != 100 || this . ids . length == 0 ) {
return ;
}
2019-06-19 08:54:21 +00:00
if ( this . composeText . length > this . config . uploader . max _caption _length ) {
swal ( 'Error' , 'Caption is too long' , 'error' ) ;
return ;
}
2023-10-23 03:13:55 +00:00
2019-03-26 04:22:25 +00:00
switch ( state ) {
2023-10-23 03:13:55 +00:00
case 'publish' :
this . isPosting = true ;
let count = this . media . filter ( m => m . filter _class && ! m . hasOwnProperty ( 'is_filtered' ) ) . length ;
if ( count ) {
this . applyFilterToMedia ( ) ;
return ;
}
2021-07-23 15:47:14 +00:00
if ( this . composeSettings . media _descriptions === true ) {
let count = this . media . filter ( m => {
return ! m . hasOwnProperty ( 'alt' ) || m . alt . length < 2 ;
} ) ;
if ( count . length ) {
swal ( 'Missing media descriptions' , 'You have enabled mandatory media descriptions. Please add media descriptions under Advanced settings to proceed. For more information, please see the media settings page.' , 'warning' ) ;
return ;
}
}
2019-03-26 04:22:25 +00:00
if ( this . media . length == 0 ) {
swal ( 'Whoops!' , 'You need to add media before you can save this!' , 'warning' ) ;
return ;
}
if ( this . composeText == 'Add optional caption...' ) {
this . composeText = '' ;
}
2022-02-18 02:19:28 +00:00
2019-03-26 04:22:25 +00:00
let data = {
media : this . media ,
caption : this . composeText ,
visibility : this . visibility ,
2019-09-04 02:31:51 +00:00
cw : this . nsfw ,
comments _disabled : this . commentsDisabled ,
2020-07-14 23:32:49 +00:00
place : this . place ,
2021-01-18 03:25:19 +00:00
tagged : this . taggedUsernames ,
2021-04-01 04:24:59 +00:00
optimize _media : this . optimizeMedia ,
2021-07-23 15:47:14 +00:00
license : this . licenseId ,
2022-05-18 08:58:49 +00:00
video : this . video ,
spoiler _text : this . spoilerText ,
2019-03-26 04:22:25 +00:00
} ;
2022-02-18 02:19:28 +00:00
if ( this . collectionsSelected . length ) {
data . collections = this . collectionsSelected
. map ( idx => {
return this . collections [ idx ] . id ;
} ) ;
}
2021-01-18 03:25:19 +00:00
axios . post ( '/api/compose/v0/publish' , data )
. then ( res => {
2022-02-18 02:19:28 +00:00
if ( location . pathname === '/i/web/compose' && res . data && res . data . length ) {
location . href = '/i/web/post/' + res . data . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
2021-12-22 07:47:33 +00:00
} else {
2022-02-19 23:31:46 +00:00
location . href = res . data ;
2021-12-22 07:47:33 +00:00
}
2021-01-18 03:25:19 +00:00
} ) . catch ( err => {
2022-02-18 02:19:28 +00:00
if ( err . response ) {
let msg = err . response . data . message ? err . response . data . message : 'An unexpected error occured.'
swal ( 'Oops, something went wrong!' , msg , 'error' ) ;
} else {
swal ( 'Oops, something went wrong!' , err . message , 'error' ) ;
}
2021-01-18 03:25:19 +00:00
} ) ;
return ;
break ;
case 'delete' :
this . ids = [ ] ;
this . media = [ ] ;
this . carouselCursor = 0 ;
this . composeText = '' ;
this . composeTextLength = 0 ;
$ ( '#composeModal' ) . modal ( 'hide' ) ;
return ;
break ;
}
} ,
composeTextPost ( ) {
let state = this . composeState ;
if ( this . composeText . length > this . config . uploader . max _caption _length ) {
swal ( 'Error' , 'Caption is too long' , 'error' ) ;
return ;
}
switch ( state ) {
case 'publish' :
let data = {
caption : this . composeText ,
visibility : this . visibility ,
cw : this . nsfw ,
comments _disabled : this . commentsDisabled ,
place : this . place ,
tagged : this . taggedUsernames ,
} ;
axios . post ( '/api/compose/v0/publish/text' , data )
2019-03-26 04:22:25 +00:00
. then ( res => {
let data = res . data ;
window . location . href = data ;
} ) . catch ( err => {
2019-12-15 04:29:00 +00:00
let msg = err . response . data . message ? err . response . data . message : 'An unexpected error occured.'
swal ( 'Oops, something went wrong!' , msg , 'error' ) ;
2019-03-26 04:22:25 +00:00
} ) ;
return ;
break ;
case 'delete' :
this . ids = [ ] ;
this . media = [ ] ;
this . carouselCursor = 0 ;
this . composeText = '' ;
this . composeTextLength = 0 ;
$ ( '#composeModal' ) . modal ( 'hide' ) ;
return ;
break ;
2019-02-27 07:03:46 +00:00
}
2019-03-26 04:22:25 +00:00
} ,
closeModal ( ) {
$ ( '#composeModal' ) . modal ( 'hide' ) ;
2022-02-19 23:31:46 +00:00
this . $emit ( 'close' ) ;
2019-06-04 03:04:39 +00:00
} ,
2019-10-16 03:44:48 +00:00
goBack ( ) {
this . pageTitle = '' ;
2021-01-18 03:25:19 +00:00
2021-04-30 05:27:25 +00:00
switch ( this . mode ) {
case 'photo' :
switch ( this . page ) {
2023-10-23 03:13:55 +00:00
case 'filteringMedia' :
this . page = 2 ;
break ;
2021-04-30 05:27:25 +00:00
case 'addText' :
this . page = 1 ;
break ;
2021-01-18 03:25:19 +00:00
2021-04-30 05:27:25 +00:00
case 'textOptions' :
this . page = 'addText' ;
break ;
2019-07-18 01:03:46 +00:00
2021-04-30 05:27:25 +00:00
case 'cropPhoto' :
case 'editMedia' :
this . page = 2 ;
break ;
case 'tagPeopleHelp' :
this . showTagCard ( ) ;
break ;
case 'licensePicker' :
this . page = 3 ;
break ;
case 'video-2' :
this . page = 1 ;
break ;
default :
this . namedPages . indexOf ( this . page ) != - 1 ?
this . page = 3 : this . page -- ;
break ;
}
2020-07-14 23:32:49 +00:00
break ;
2021-04-30 05:27:25 +00:00
case 'video' :
switch ( this . page ) {
2023-10-23 03:13:55 +00:00
case 'filteringMedia' :
this . page = 2 ;
break ;
2021-04-30 05:27:25 +00:00
case 'licensePicker' :
this . page = 'video-2' ;
break ;
case 'video-2' :
this . page = 'video-2' ;
break ;
default :
this . page = 'video-2' ;
break ;
}
2021-04-01 04:24:59 +00:00
break ;
2019-10-16 03:44:48 +00:00
default :
2021-04-30 05:27:25 +00:00
switch ( this . page ) {
case 'addText' :
this . page = 1 ;
break ;
2023-10-23 03:13:55 +00:00
case 'filteringMedia' :
this . page = 2 ;
break ;
2021-04-30 05:27:25 +00:00
case 'textOptions' :
this . page = 'addText' ;
break ;
case 'cropPhoto' :
case 'editMedia' :
this . page = 2 ;
break ;
case 'tagPeopleHelp' :
this . showTagCard ( ) ;
break ;
case 'licensePicker' :
this . page = 3 ;
break ;
case 'video-2' :
this . page = 1 ;
break ;
default :
this . namedPages . indexOf ( this . page ) != - 1 ?
this . page = ( this . mode == 'text' ? 'addText' : 3 ) :
( this . mode == 'text' ? 'addText' : this . page -- ) ;
break ;
}
2019-10-16 03:44:48 +00:00
break ;
}
2021-04-30 05:27:25 +00:00
2019-08-05 04:02:10 +00:00
} ,
2019-09-04 02:31:51 +00:00
nextPage ( ) {
2019-09-13 04:36:12 +00:00
this . pageTitle = '' ;
2019-09-04 02:31:51 +00:00
switch ( this . page ) {
case 1 :
2019-09-13 04:36:12 +00:00
this . page = 2 ;
2019-09-04 02:31:51 +00:00
break ;
2023-10-23 03:13:55 +00:00
case 'filteringMedia' :
break ;
2019-09-13 04:36:12 +00:00
case 'cropPhoto' :
2019-09-04 02:31:51 +00:00
this . pageLoading = true ;
let self = this ;
2021-04-30 05:27:25 +00:00
this . $refs . cropper . getCroppedCanvas ( {
2019-09-05 19:58:27 +00:00
maxWidth : 4096 ,
maxHeight : 4096 ,
fillColor : '#fff' ,
imageSmoothingEnabled : false ,
imageSmoothingQuality : 'high' ,
} ) . toBlob ( function ( blob ) {
2021-01-18 03:25:19 +00:00
self . mediaCropped = true ;
2019-09-04 02:31:51 +00:00
let data = new FormData ( ) ;
data . append ( 'file' , blob ) ;
2021-01-18 03:25:19 +00:00
data . append ( 'id' , self . ids [ self . carouselCursor ] ) ;
let url = '/api/compose/v0/media/update' ;
2019-09-04 02:31:51 +00:00
axios . post ( url , data ) . then ( res => {
self . media [ self . carouselCursor ] . url = res . data . url ;
self . pageLoading = false ;
2019-09-13 04:36:12 +00:00
self . page = 2 ;
2019-09-04 02:31:51 +00:00
} ) . catch ( err => {
} ) ;
} ) ;
break ;
2019-09-13 04:36:12 +00:00
case 2 :
2020-07-14 23:32:49 +00:00
this . page ++ ;
break ;
2019-09-04 02:31:51 +00:00
case 3 :
this . page ++ ;
break ;
}
} ,
rotate ( ) {
this . $refs . cropper . rotate ( 90 ) ;
} ,
changeAspect ( ratio ) {
this . cropper . aspectRatio = ratio ;
this . $refs . cropper . setAspectRatio ( ratio ) ;
} ,
showTagCard ( ) {
this . pageTitle = 'Tag People' ;
this . page = 'tagPeople' ;
} ,
2020-07-14 23:32:49 +00:00
showTagHelpCard ( ) {
this . pageTitle = 'About Tag People' ;
this . page = 'tagPeopleHelp' ;
} ,
2019-09-04 02:31:51 +00:00
showLocationCard ( ) {
this . pageTitle = 'Add Location' ;
this . page = 'addLocation' ;
} ,
showAdvancedSettingsCard ( ) {
this . pageTitle = 'Advanced Settings' ;
this . page = 'advancedSettings' ;
} ,
locationSearch ( input ) {
2022-05-14 09:42:07 +00:00
if ( input . length < 1 ) { return [ ] ; }
2019-09-04 02:31:51 +00:00
let results = [ ] ;
2021-01-18 03:25:19 +00:00
return axios . get ( '/api/compose/v0/search/location' , {
2019-09-04 02:31:51 +00:00
params : {
q : input
}
} ) . then ( res => {
return res . data ;
} ) ;
} ,
getResultValue ( result ) {
return result . name + ', ' + result . country
} ,
onSubmitLocation ( result ) {
this . place = result ;
2021-04-30 05:27:25 +00:00
switch ( this . mode ) {
case 'photo' :
this . pageTitle = '' ;
this . page = 3 ;
break ;
case 'video' :
this . pageTitle = 'Edit Video Details' ;
this . page = 'video-2' ;
break ;
case 'text' :
this . pageTitle = 'New Text Post' ;
this . page = 'addText' ;
break ;
}
2019-09-04 02:31:51 +00:00
return ;
} ,
showVisibilityCard ( ) {
this . pageTitle = 'Post Visibility' ;
this . page = 'visibility' ;
} ,
showAddToStoryCard ( ) {
this . pageTitle = 'Add to Story' ;
this . page = 'addToStory' ;
} ,
2019-09-13 04:36:12 +00:00
showCropPhotoCard ( ) {
this . pageTitle = 'Edit Photo' ;
this . page = 'cropPhoto' ;
} ,
2019-09-04 02:31:51 +00:00
toggleVisibility ( state ) {
let tags = {
public : 'Public' ,
private : 'Followers Only' ,
unlisted : 'Unlisted'
}
this . visibility = state ;
this . visibilityTag = tags [ state ] ;
2021-04-30 05:27:25 +00:00
switch ( this . mode ) {
case 'photo' :
this . pageTitle = '' ;
this . page = 3 ;
break ;
case 'video' :
this . pageTitle = 'Edit Video Details' ;
this . page = 'video-2' ;
break ;
case 'text' :
this . pageTitle = 'New Text Post' ;
this . page = 'addText' ;
break ;
}
2019-10-16 03:44:48 +00:00
} ,
showMediaDescriptionsCard ( ) {
this . pageTitle = 'Media Descriptions' ;
this . page = 'altText' ;
} ,
showAddToCollectionsCard ( ) {
this . pageTitle = 'Add to Collection' ;
this . page = 'addToCollection' ;
} ,
showSchedulePostCard ( ) {
this . pageTitle = 'Schedule Post' ;
this . page = 'schedulePost' ;
} ,
showEditMediaCard ( ) {
this . pageTitle = 'Edit Media' ;
this . page = 'editMedia' ;
} ,
fetchCameraRollDrafts ( ) {
axios . get ( '/api/pixelfed/local/drafts' )
. then ( res => {
this . cameraRollMedia = res . data ;
} ) ;
2019-11-24 22:52:46 +00:00
} ,
2020-11-28 02:52:40 +00:00
2020-07-14 23:32:49 +00:00
applyFilterToMedia ( ) {
// this is where the magic happens
2020-12-13 05:54:11 +00:00
var ua = navigator . userAgent . toLowerCase ( ) ;
if ( ua . indexOf ( 'firefox' ) == - 1 && ua . indexOf ( 'chrome' ) == - 1 ) {
2023-10-23 03:13:55 +00:00
this . isPosting = false ;
2021-02-07 07:09:28 +00:00
swal ( 'Oops!' , 'Your browser does not support the filter feature.' , 'error' ) ;
2023-10-23 03:13:55 +00:00
this . page = 3 ;
2020-12-13 05:54:11 +00:00
return ;
}
2019-11-24 22:52:46 +00:00
2023-10-23 03:13:55 +00:00
let count = this . media . filter ( m => m . filter _class ) . length ;
if ( count ) {
this . page = 'filteringMedia' ;
this . filteringRemainingCount = count ;
this . $nextTick ( ( ) => {
this . isFilteringMedia = true ;
this . media . forEach ( ( media , idx ) => this . applyFilterToMediaSave ( media , idx ) ) ;
} )
} else {
this . page = 3 ;
}
2020-07-14 23:32:49 +00:00
} ,
2023-10-23 03:13:55 +00:00
applyFilterToMediaSave ( media , idx ) {
if ( ! media . filter _class ) {
return ;
}
let self = this ;
let data = null ;
const canvas = document . createElement ( 'canvas' ) ;
const ctx = canvas . getContext ( '2d' ) ;
let image = document . createElement ( 'img' ) ;
image . src = media . url ;
image . addEventListener ( 'load' , e => {
canvas . width = image . width ;
canvas . height = image . height ;
ctx . filter = App . util . filterCss [ media . filter _class ] ;
ctx . drawImage ( image , 0 , 0 , image . width , image . height ) ;
ctx . save ( ) ;
canvas . toBlob ( function ( blob ) {
data = new FormData ( ) ;
data . append ( 'file' , blob ) ;
data . append ( 'id' , media . id ) ;
axios . post ( '/api/compose/v0/media/update' , data )
. then ( res => {
self . media [ idx ] . is _filtered = true ;
self . updateFilteringMedia ( ) ;
} ) . catch ( err => {
} ) ;
} ) ;
} , media . mime , 0.9 ) ;
ctx . clearRect ( 0 , 0 , image . width , image . height ) ;
} ,
updateFilteringMedia ( ) {
this . filteringRemainingCount -- ;
this . filteringMediaTimeout = setTimeout ( ( ) => this . filteringMediaTimeoutJob ( ) , 500 ) ;
} ,
filteringMediaTimeoutJob ( ) {
if ( this . filteringRemainingCount === 0 ) {
this . isFilteringMedia = false ;
clearTimeout ( this . filteringMediaTimeout ) ;
setTimeout ( ( ) => this . compose ( ) , 500 ) ;
} else {
clearTimeout ( this . filteringMediaTimeout ) ;
this . filteringMediaTimeout = setTimeout ( ( ) => this . filteringMediaTimeoutJob ( ) , 1000 ) ;
}
} ,
2020-07-14 23:32:49 +00:00
tagSearch ( input ) {
2022-05-14 09:42:07 +00:00
if ( input . length < 1 ) { return [ ] ; }
2020-07-14 23:32:49 +00:00
let self = this ;
let results = [ ] ;
2021-01-18 03:25:19 +00:00
return axios . get ( '/api/compose/v0/search/tag' , {
2020-07-14 23:32:49 +00:00
params : {
q : input
}
} ) . then ( res => {
2021-02-07 04:22:27 +00:00
if ( ! res . data . length ) {
return ;
}
2020-07-14 23:32:49 +00:00
return res . data . filter ( d => {
return self . taggedUsernames . filter ( r => {
return r . id == d . id ;
} ) . length == 0 ;
} ) ;
} ) ;
} ,
getTagResultValue ( result ) {
return '@' + result . name ;
} ,
onTagSubmitLocation ( result ) {
if ( this . taggedUsernames . filter ( r => {
return r . id == result . id ;
} ) . length ) {
return ;
}
this . taggedUsernames . push ( result ) ;
this . $refs . autocomplete . value = '' ;
return ;
} ,
untagUsername ( index ) {
this . taggedUsernames . splice ( index , 1 ) ;
2021-01-18 03:25:19 +00:00
} ,
showTextOptions ( ) {
this . page = 'textOptions' ;
this . pageTitle = 'Text Post Options' ;
2021-04-01 04:24:59 +00:00
} ,
showLicenseCard ( ) {
this . pageTitle = 'Select a License' ;
this . page = 'licensePicker' ;
} ,
2021-07-23 15:47:14 +00:00
toggleLicense ( license ) {
this . licenseId = license . id ;
if ( this . licenseId > 10 ) {
this . licenseTitle = this . availableLicenses . filter ( l => {
return l . id == this . licenseId ;
} ) . map ( l => {
return l . title ;
} ) [ 0 ] ;
} else {
this . licenseTitle = null ;
}
2021-04-30 05:27:25 +00:00
switch ( this . mode ) {
case 'photo' :
this . pageTitle = '' ;
this . page = 3 ;
break ;
case 'video' :
this . pageTitle = 'Edit Video Details' ;
this . page = 'video-2' ;
break ;
case 'text' :
this . pageTitle = 'New Text Post' ;
this . page = 'addText' ;
break ;
}
2021-04-01 04:24:59 +00:00
} ,
2021-08-05 02:29:21 +00:00
newPoll ( ) {
this . page = 'poll' ;
} ,
savePollOption ( ) {
if ( this . pollOptions . indexOf ( this . pollOptionModel ) != - 1 ) {
this . pollOptionModel = null ;
return ;
}
this . pollOptions . push ( this . pollOptionModel ) ;
this . pollOptionModel = null ;
} ,
deletePollOption ( index ) {
this . pollOptions . splice ( index , 1 ) ;
} ,
postNewPoll ( ) {
this . postingPoll = true ;
axios . post ( '/api/compose/v0/poll' , {
caption : this . composeText ,
cw : false ,
visibility : this . visibility ,
comments _disabled : false ,
expiry : this . pollExpiry ,
pollOptions : this . pollOptions
} ) . then ( res => {
if ( ! res . data . hasOwnProperty ( 'url' ) ) {
swal ( 'Oops!' , 'An error occured while attempting to create this poll. Please refresh the page and try again.' , 'error' ) ;
this . postingPoll = false ;
return ;
}
window . location . href = res . data . url ;
} ) . catch ( err => {
if ( err . response . data . hasOwnProperty ( 'error' ) ) {
if ( err . response . data . error == 'Duplicate detected.' ) {
this . postingPoll = false ;
swal ( 'Oops!' , 'The poll you are trying to create is similar to an existing poll you created. Please make the poll question (caption) unique.' , 'error' ) ;
return ;
}
}
this . postingPoll = false ;
swal ( 'Oops!' , 'An error occured while attempting to create this poll. Please refresh the page and try again.' , 'error' ) ;
} )
2022-01-23 04:11:34 +00:00
} ,
filesize ( val ) {
return filesize ( val * 1024 , { round : 0 } ) ;
2022-02-18 02:19:28 +00:00
} ,
showCollectionCard ( ) {
this . pageTitle = 'Add to Collection(s)' ;
this . page = 'addToCollection' ;
if ( ! this . collectionsLoaded ) {
this . fetchCollections ( ) ;
}
} ,
fetchCollections ( ) {
axios . get ( ` /api/local/profile/collections/ ${ this . profile . id } ` )
. then ( res => {
this . collections = res . data ;
this . collectionsLoaded = true ;
this . collectionsCanLoadMore = res . data . length == 9 ;
this . collectionsPage ++ ;
} ) ;
} ,
toggleCollectionItem ( index ) {
if ( ! this . collectionsSelected . includes ( index ) ) {
if ( this . collectionsSelected . length == 7 ) {
swal ( 'Oops!' , 'You can only share to 5 collections.' , 'info' ) ;
return ;
}
this . collectionsSelected . push ( index ) ;
} else {
this . collectionsSelected = this . collectionsSelected . filter ( c => c != index ) ;
}
} ,
clearSelectedCollections ( ) {
this . collectionsSelected = [ ] ;
this . pageTitle = 'Compose' ;
this . page = 3 ;
} ,
loadMoreCollections ( ) {
this . collectionsCanLoadMore = false ;
axios . get ( ` /api/local/profile/collections/ ${ this . profile . id } ` , {
params : {
page : this . collectionsPage
}
} )
. then ( res => {
let ids = this . collections . map ( c => c . id ) ;
let data = res . data . filter ( res => {
return ! ids . includes ( res . id ) ;
} ) ;
if ( ! data || ! data . length ) {
return ;
}
this . collections . push ( ... data ) ;
this . collectionsPage ++ ;
this . collectionsCanLoadMore = true ;
} ) ;
2021-08-05 02:29:21 +00:00
}
2019-02-27 07:03:46 +00:00
}
}
2021-04-30 05:27:25 +00:00
< / script >
2022-02-18 02:19:28 +00:00
< style lang = "scss" >
. compose - modal - component {
. media - drawer - filters {
2023-07-02 04:36:22 +00:00
overflow - x : auto ;
2022-02-18 02:19:28 +00:00
flex - wrap : unset ;
}
. media - drawer - filters . nav - link {
min - width : 100 px ;
padding - top : 1 rem ;
padding - bottom : 1 rem ;
}
. media - drawer - filters . active {
color : # fff ;
font - weight : bold ;
}
@ media ( hover : none ) and ( pointer : coarse ) {
. media - drawer - filters : : - webkit - scrollbar {
display : none ;
}
}
. no - focus {
border - color : none ;
outline : 0 ;
box - shadow : none ;
}
a . list - group - item {
text - decoration : none ;
}
a . list - group - item : hover {
text - decoration : none ;
2022-04-03 06:53:53 +00:00
background - color : # f8f9fa ;
2022-02-18 02:19:28 +00:00
}
. compose - action : hover {
cursor : pointer ;
2022-04-03 06:53:53 +00:00
background - color : # f8f9fa ;
2022-02-18 02:19:28 +00:00
}
. collections - list - group {
max - height : 500 px ;
overflow - y : auto ;
. list - group - item {
& . active {
color : # 212529 ;
border - color : # 60 a5fa ! important ;
background - color : # dbeafe ! important ;
}
}
}
}
< / style >