logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: 091532d577ae9a23f7a43f681bfd344f040c7738
parent bfdad56b0d4b4f8ed89295661ff8abba22dca7f0
Author: Ekaterina Vaartis <vaartis@kotobank.ch>
Date:   Sun,  7 Jan 2024 02:45:49 +0300

Editing emojis in popover, pack creation/deletion

Also fixed some API calls since they weren't working apparently

Diffstat:

Msrc/components/settings_modal/admin_tabs/emoji_tab.js117++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/components/settings_modal/admin_tabs/emoji_tab.scss22++++++++++++++++++++++
Msrc/components/settings_modal/admin_tabs/emoji_tab.vue206+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/components/settings_modal/settings_modal_admin_content.vue2+-
Msrc/services/api/api.service.js14+++++++-------
5 files changed, 272 insertions(+), 89 deletions(-)

diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.js b/src/components/settings_modal/admin_tabs/emoji_tab.js @@ -1,20 +1,46 @@ +import { clone } from 'lodash' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import StringSetting from '../helpers/string_setting.vue' import Checkbox from 'components/checkbox/checkbox.vue' import StillImage from 'components/still-image/still-image.vue' +import Select from 'components/select/select.vue' +import Popover from 'components/popover/popover.vue' +import ConfirmModal from 'components/confirm_modal/confirm_modal.vue' +import ModifiedIndicator from '../helpers/modified_indicator.vue' const EmojiTab = { components: { TabSwitcher, StringSetting, Checkbox, - StillImage + StillImage, + Select, + Popover, + ConfirmModal, + ModifiedIndicator }, data () { return { knownPacks: { }, - editedParts: { } + editedParts: { }, + editedMetadata: { }, + packName: '', + newPackName: '', + deleteModalVisible: false + } + }, + + computed: { + pack () { + return this.packName !== '' ? this.knownPacks[this.packName] : undefined + }, + packMeta () { + if (this.editedMetadata[this.packName] === undefined) { + this.editedMetadata[this.packName] = clone(this.knownPacks[this.packName].pack) + } + + return this.editedMetadata[this.packName] } }, @@ -25,37 +51,90 @@ const EmojiTab = { importFromFS () { this.$store.state.api.backendInteractor.importEmojiFromFS() }, - emojiAddr (packName, name) { - return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(packName)}/${name}` + emojiAddr (name) { + return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(this.packName)}/${name}` }, - editEmoji (packName, shortcode) { - if (this.editedParts[packName] === undefined) { this.editedParts[packName] = {} } - this.editedParts[packName][shortcode] = { - shortcode, file: this.knownPacks[packName].files[shortcode] + createEmojiPack () { + this.$store.state.api.backendInteractor.createEmojiPack( + { name: this.newPackName } + ).then(resp => resp.json()).then(resp => { + if (resp === 'ok') { + return this.refreshPackList() + } else { + return Promise.reject(resp) + } + }).then(done => { + this.$refs.createPackPopover.hidePopover() + + this.packName = this.newPackName + this.newPackName = '' + }) + }, + deleteEmojiPack () { + this.$store.state.api.backendInteractor.deleteEmojiPack( + { name: this.packName } + ).then(resp => resp.json()).then(resp => { + if (resp === 'ok') { + return this.refreshPackList() + } else { + return Promise.reject(resp) + } + }).then(done => { + delete this.editedMetadata[this.packName] + delete this.editedParts[this.packName] + + this.deleteModalVisible = false + this.packName = '' + }) + }, + + metaEdited (prop) { + return this.pack && this.packMeta[prop] !== this.pack.pack[prop] + }, + savePackMetadata () { + this.$store.state.api.backendInteractor.saveEmojiPackMetadata({ name: this.packName, newData: this.packMeta }).then( + resp => resp.json() + ).then(resp => { + // Update actual pack data + this.pack.pack = resp + // Delete edited pack data, should auto-update itself + delete this.editedMetadata[this.packName] + }) + }, + + editEmoji (shortcode) { + if (this.editedParts[this.packName] === undefined) { this.editedParts[this.packName] = {} } + + if (this.editedParts[this.packName][shortcode] === undefined) { + this.editedParts[this.packName][shortcode] = { + shortcode, file: this.knownPacks[this.packName].files[shortcode] + } } }, - saveEditedEmoji (packName, shortcode) { - const edited = this.editedParts[packName][shortcode] + saveEditedEmoji (shortcode) { + const edited = this.editedParts[this.packName][shortcode] this.$store.state.api.backendInteractor.updateEmojiFile( - { packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false } + { packName: this.packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false } ).then(resp => resp.ok ? resp.json() : resp.text().then(respText => Promise.reject(respText)) ).then(resp => { - this.knownPacks[packName].files = resp - delete this.editedParts[packName][shortcode] + this.knownPacks[this.packName].files = resp + delete this.editedParts[this.packName][shortcode] }) + }, + refreshPackList () { + return this.$store.state.api.backendInteractor.listEmojiPacks() + .then(data => data.json()) + .then(packData => { + this.knownPacks = packData.packs + }) } }, mounted () { - this.$store.state.api.backendInteractor.listEmojiPacks() - .then(data => data.json()) - .then(packData => { - this.knownPacks = packData.packs - console.log(this.knownPacks) - }) + this.refreshPackList() } } diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.scss b/src/components/settings_modal/admin_tabs/emoji_tab.scss @@ -1,3 +1,5 @@ +@import "src/variables"; + .emoji-tab { .btn-group .btn { margin-left: 0.5em; @@ -21,4 +23,24 @@ width: 32px; height: 32px; } + + .emoji-unsaved { + box-shadow: 2px 3px 5px var(--cBlue, $fallback--cBlue); + } + + .emoji-list { + display: flex; + flex-wrap: wrap; + gap: 1em 1em; + } +} + +.emoji-tab-edit-popover { + padding-left: 0.5em; + padding-right: 0.5em; + padding-bottom: 0.5em; +} + +.emoji-tab-popover-button { + margin-left: 0.5em; } diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.vue b/src/components/settings_modal/admin_tabs/emoji_tab.vue @@ -6,84 +6,166 @@ <div class="setting-item"> <h2>{{ $t('admin_dash.tabs.emoji') }}</h2> - <span class="btn-group"> - <button - class="button button-default btn" - type="button" - @click="reloadEmoji"> - {{ $t('admin_dash.emoji.reload') }} - </button> - <button - class="button button-default btn" - type="button" - @click="importFromFS"> - {{ $t('admin_dash.emoji.importFS') }} - </button> - </span> + <ul class="setting-list"> + <li class="btn-group setting-item"> + <button + class="button button-default btn" + type="button" + @click="reloadEmoji"> + {{ $t('admin_dash.emoji.reload') }} + </button> + <button + class="button button-default btn" + type="button" + @click="importFromFS"> + {{ $t('admin_dash.emoji.importFS') }} + </button> + </li> - <tab-switcher :scrollable-tabs="true" v-if="Object.keys(knownPacks).length > 0"> - <div v-for="(pack, packName) in knownPacks" :label="packName" :key="packName"> - <div class="pack-info-wrapper"> - <ul class="setting-list"> - <li> - <div>Description</div> - <textarea - v-model="pack.pack.description" - class="bio resize-height" /> - </li> - <li> - <div>Homepage</div> - <input class="emoji-info-input" v-model="pack.pack.homepage"> - </li> - <li> - <div>Fallback source</div> - <input class="emoji-info-input" v-model="pack.pack['fallback-src']"> - </li> - <li> - <Checkbox v-model="pack.pack['can-download']">Downloadable</Checkbox> - </li> - </ul> - </div> + <li class="setting-item btn-group"> + <button + class="button button-default btn" + type="button" + @click="$refs.createPackPopover.showPopover"> + Create pack + </button> + <Popover + ref="createPackPopover" + trigger="click" + placement="bottom" + bound-to-selector=".emoji-tab" + :bound-to="{ x: 'container' }" + :offset="{ y: 5 }" + > + <template #content> + <input v-model="newPackName" placeholder="New pack name"> + <button + class="button button-default btn emoji-tab-popover-button" + type="button" + @click="createEmojiPack"> + Create + </button> + </template> + </Popover> - <h2>Files</h2> + <button + class="button button-default btn" + :disabled="packName == ''" + type="button" + @click="deleteModalVisible = true"> + Delete pack + </button> + <ConfirmModal + v-if="deleteModalVisible" + title="Delete?" + :cancel-text="$t('status.delete_confirm_cancel_button')" + :confirm-text="$t('status.delete_confirm_accept_button')" + @cancelled="deleteModalVisible = false" + @accepted="deleteEmojiPack" > + Are you sure you want to delete {{ packName }}? + </ConfirmModal> + </li> + <li> + <Select class="form-control" v-model="packName"> + <option value="" disabled hidden>Emoji pack</option> + <option v-for="(pack, listPackName) in knownPacks" :label="listPackName" :key="listPackName"> + {{ listPackName }} + </option> + </Select> + </li> + </ul> + + <div v-if="packName !== ''"> + <div class="pack-info-wrapper"> <ul class="setting-list"> - <li v-for="(file, shortcode) in pack.files" :key="shortcode"> - <StillImage - class="emoji img" - :src="emojiAddr(packName, file)" - :title="`:${shortcode}:`" - :alt="`:${shortcode}:`" - /> + <li> + <div> + Description + <ModifiedIndicator :changed="metaEdited('description')" /> + </div> + <textarea + v-model="packMeta.description" + class="bio resize-height" /> + </li> + <li> + <div> + Homepage + <ModifiedIndicator :changed="metaEdited('homepage')" /> + </div> + <input class="emoji-info-input" v-model="packMeta.homepage"> + </li> + <li> + <div> + Fallback source + <ModifiedIndicator :changed="metaEdited('fallback-src')" /> + </div> + <input class="emoji-info-input" v-model="packMeta['fallback-src']"> + </li> + <li> + <div>Fallback SHA256</div> + <input :disabled="true" class="emoji-info-input" v-model="packMeta['fallback-src-sha256']"> + </li> + <li> + <Checkbox v-model="packMeta['share-files']">Share</Checkbox> + + <ModifiedIndicator :changed="metaEdited('share-files')" /> + </li> + <li> + <button + class="button button-default btn" + type="button" + @click="savePackMetadata"> + Save + </button> + </li> + </ul> + </div> + + <h2>Files</h2> - <template v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined"> + <div class="emoji-list" v-if="pack"> + <Popover + v-for="(file, shortcode) in pack.files" :key="shortcode" + trigger="click" + placement="top" + :class="{'emoji-unsaved': editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined}" + popover-class="emoji-tab-edit-popover popover-default" + bound-to-selector=".emoji-list" + :bound-to="{ x: 'container' }" + :offset="{ y: 5 }" + @show="editEmoji(shortcode)" + > + <template #content> + <h3> + Editing <i>{{ shortcode }}</i> + </h3> + <div v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined"> <input class="emoji-data-input" v-model="editedParts[packName][shortcode].shortcode"> <input class="emoji-data-input" v-model="editedParts[packName][shortcode].file"> <button - class="button button-default btn" + class="button button-default btn emoji-tab-popover-button" type="button" - @click="saveEditedEmoji(packName, shortcode)"> + @click="saveEditedEmoji(shortcode)"> Save </button> - </template> - <template v-else> - <input disabled class="emoji-data-input" :value="shortcode"> - <input disabled class="emoji-data-input" :value="file"> - <button - class="button button-default btn" - type="button" - @click="editEmoji(packName, shortcode)"> - Edit - </button> - </template> - </li> - </ul> + </div> + </template> + <template #trigger> + <StillImage + class="emoji" + :src="emojiAddr(file)" + :title="`:${shortcode}:`" + :alt="`:${shortcode}:`" + /> + </template> + </Popover> </div> - </tab-switcher> + </div> </div> </div> </template> diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue @@ -63,7 +63,7 @@ <div :label="$t('admin_dash.tabs.emoji')" - icon="laptop-code" + icon="face-smile-beam" data-tab-name="emoji" > <EmojiTab /> diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js @@ -116,12 +116,12 @@ const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL = '/api/pleroma/admin/frontends/instal const PLEROMA_EMOJI_RELOAD_URL = '/api/pleroma/admin/reload_emoji' const PLEROMA_EMOJI_IMPORT_FS_URL = '/api/pleroma/emoji/packs/import' -const PLEROMA_EMOJI_PACKS_URL = (page, pageSize) => `/api/pleroma/emoji/packs?page=${page}&page_size=${pageSize}` -const PLEROMA_EMOJI_PACK_URL = (name) => `/api/pleroma/emoji/pack?name=${name}` -const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/pleroma/emoji/packs/download' +const PLEROMA_EMOJI_PACKS_URL = (page, pageSize) => `/api/v1/pleroma/emoji/packs?page=${page}&page_size=${pageSize}` +const PLEROMA_EMOJI_PACK_URL = (name) => `/api/v1/pleroma/emoji/pack?name=${name}` +const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/v1/pleroma/emoji/packs/download' const PLEROMA_EMOJI_PACKS_LS_REMOTE_URL = - (url, page, pageSize) => `/api/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}` -const PLEROMA_EMOJI_UPDATE_FILE_URL = (name) => `/api/pleroma/emoji/packs/files?name=${name}` + (url, page, pageSize) => `/api/v1/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}` +const PLEROMA_EMOJI_UPDATE_FILE_URL = (name) => `/api/v1/pleroma/emoji/packs/files?name=${name}` const oldfetch = window.fetch @@ -1809,7 +1809,7 @@ const importEmojiFromFS = () => { } const createEmojiPack = ({ name }) => { - return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'PUT' }) + return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'POST' }) } const listEmojiPacks = () => { @@ -1850,7 +1850,7 @@ const saveEmojiPackMetadata = ({ name, newData }) => { { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name, new_data: newData }) + body: JSON.stringify({ metadata: newData }) } ) }