diff options
Diffstat (limited to 'src/components')
25 files changed, 386 insertions, 109 deletions
diff --git a/src/components/follow_button/follow_button.js b/src/components/follow_button/follow_button.js index 95e7cb6b..3edbcb86 100644 --- a/src/components/follow_button/follow_button.js +++ b/src/components/follow_button/follow_button.js @@ -1,6 +1,6 @@ import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' export default { - props: ['relationship', 'labelFollowing', 'buttonClass'], + props: ['relationship', 'user', 'labelFollowing', 'buttonClass'], data () { return { inProgress: false @@ -14,7 +14,7 @@ export default { if (this.inProgress || this.relationship.following) { return this.$t('user_card.follow_unfollow') } else if (this.relationship.requested) { - return this.$t('user_card.follow_again') + return this.$t('user_card.follow_cancel') } else { return this.$t('user_card.follow') } @@ -29,11 +29,14 @@ export default { } else { return this.$t('user_card.follow') } + }, + disabled () { + return this.inProgress || this.user.deactivated } }, methods: { onClick () { - this.relationship.following ? this.unfollow() : this.follow() + this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow() }, follow () { this.inProgress = true diff --git a/src/components/follow_button/follow_button.vue b/src/components/follow_button/follow_button.vue index 7f85f1d7..965d5256 100644 --- a/src/components/follow_button/follow_button.vue +++ b/src/components/follow_button/follow_button.vue @@ -2,7 +2,7 @@ <button class="btn button-default follow-button" :class="{ toggled: isPressed }" - :disabled="inProgress" + :disabled="disabled" :title="title" @click="onClick" > diff --git a/src/components/hashtag_link/hashtag_link.js b/src/components/hashtag_link/hashtag_link.js new file mode 100644 index 00000000..a2433c2a --- /dev/null +++ b/src/components/hashtag_link/hashtag_link.js @@ -0,0 +1,36 @@ +import { extractTagFromUrl } from 'src/services/matcher/matcher.service.js' + +const HashtagLink = { + name: 'HashtagLink', + props: { + url: { + required: true, + type: String + }, + content: { + required: true, + type: String + }, + tag: { + required: false, + type: String, + default: '' + } + }, + methods: { + onClick () { + const tag = this.tag || extractTagFromUrl(this.url) + if (tag) { + const link = this.generateTagLink(tag) + this.$router.push(link) + } else { + window.open(this.url, '_blank') + } + }, + generateTagLink (tag) { + return `/tag/${tag}` + } + } +} + +export default HashtagLink diff --git a/src/components/hashtag_link/hashtag_link.scss b/src/components/hashtag_link/hashtag_link.scss new file mode 100644 index 00000000..78e8fb99 --- /dev/null +++ b/src/components/hashtag_link/hashtag_link.scss @@ -0,0 +1,6 @@ +.HashtagLink { + position: relative; + white-space: normal; + display: inline-block; + color: var(--link); +} diff --git a/src/components/hashtag_link/hashtag_link.vue b/src/components/hashtag_link/hashtag_link.vue new file mode 100644 index 00000000..918ed26b --- /dev/null +++ b/src/components/hashtag_link/hashtag_link.vue @@ -0,0 +1,19 @@ +<template> + <span + class="HashtagLink" + > + <!-- eslint-disable vue/no-v-html --> + <a + :href="url" + class="original" + target="_blank" + @click.prevent="onClick" + v-html="content" + /> + <!-- eslint-enable vue/no-v-html --> + </span> +</template> + +<script src="./hashtag_link.js"/> + +<style lang="scss" src="./hashtag_link.scss"/> diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue index 625eb727..a22b486c 100644 --- a/src/components/mention_link/mention_link.vue +++ b/src/components/mention_link/mention_link.vue @@ -17,8 +17,9 @@ :style="style" :class="classnames" > - <button + <a class="short button-unstyled" + :href="url" @click.prevent="onClick" > <!-- eslint-disable vue/no-v-html --> @@ -35,7 +36,7 @@ class="you" >{{ $t('status.you') }}</span> <!-- eslint-enable vue/no-v-html --> - </button> + </a> <span v-if="userName !== userNameFull" class="full popover-default" diff --git a/src/components/mentions_line/mentions_line.scss b/src/components/mentions_line/mentions_line.scss index 976a3fc7..b9d5c14a 100644 --- a/src/components/mentions_line/mentions_line.scss +++ b/src/components/mentions_line/mentions_line.scss @@ -2,10 +2,10 @@ .showMoreLess { white-space: normal; color: var(--link); - margin-right: 0.25em; } - .mention-link { + .fullExtraMentions, + .mention-link:not(:last-child) { margin-right: 0.25em; } } diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.js b/src/components/mobile_post_status_button/mobile_post_status_button.js index 366ea89c..d27fb3b8 100644 --- a/src/components/mobile_post_status_button/mobile_post_status_button.js +++ b/src/components/mobile_post_status_button/mobile_post_status_button.js @@ -44,6 +44,9 @@ const MobilePostStatusButton = { return this.autohideFloatingPostButton && (this.hidden || this.inputActive) }, + isPersistent () { + return !!this.$store.getters.mergedConfig.showNewPostButton + }, autohideFloatingPostButton () { return !!this.$store.getters.mergedConfig.autohideFloatingPostButton } diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.vue b/src/components/mobile_post_status_button/mobile_post_status_button.vue index 767f8244..37becf4c 100644 --- a/src/components/mobile_post_status_button/mobile_post_status_button.vue +++ b/src/components/mobile_post_status_button/mobile_post_status_button.vue @@ -2,7 +2,7 @@ <div v-if="isLoggedIn"> <button class="button-default new-status-button" - :class="{ 'hidden': isHidden }" + :class="{ 'hidden': isHidden, 'always-show': isPersistent }" @click="openPostForm" > <FAIcon icon="pen" /> @@ -47,7 +47,7 @@ } @media all and (min-width: 801px) { - .new-status-button { + .new-status-button:not(.always-show) { display: none; } } diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.js b/src/components/mrf_transparency_panel/mrf_transparency_panel.js index a0b600d2..3fde8106 100644 --- a/src/components/mrf_transparency_panel/mrf_transparency_panel.js +++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.js @@ -1,17 +1,56 @@ import { mapState } from 'vuex' import { get } from 'lodash' +/** + * This is for backwards compatibility. We originally didn't recieve + * extra info like a reason why an instance was rejected/quarantined/etc. + * Because we didn't want to break backwards compatibility it was decided + * to add an extra "info" key. + */ +const toInstanceReasonObject = (instances, info, key) => { + return instances.map(instance => { + if (info[key] && info[key][instance] && info[key][instance]['reason']) { + return { instance: instance, reason: info[key][instance]['reason'] } + } + return { instance: instance, reason: '' } + }) +} + const MRFTransparencyPanel = { computed: { ...mapState({ federationPolicy: state => get(state, 'instance.federationPolicy'), mrfPolicies: state => get(state, 'instance.federationPolicy.mrf_policies', []), - quarantineInstances: state => get(state, 'instance.federationPolicy.quarantined_instances', []), - acceptInstances: state => get(state, 'instance.federationPolicy.mrf_simple.accept', []), - rejectInstances: state => get(state, 'instance.federationPolicy.mrf_simple.reject', []), - ftlRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []), - mediaNsfwInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), - mediaRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), + quarantineInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.quarantined_instances', []), + get(state, 'instance.federationPolicy.quarantined_instances_info', []), + 'quarantined_instances' + ), + acceptInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.accept', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'accept' + ), + rejectInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.reject', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'reject' + ), + ftlRemovalInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'federated_timeline_removal' + ), + mediaNsfwInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'media_nsfw' + ), + mediaRemovalInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'media_removal' + ), keywordsFtlRemoval: state => get(state, 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', []), keywordsReject: state => get(state, 'instance.federationPolicy.mrf_keyword.reject', []), keywordsReplace: state => get(state, 'instance.federationPolicy.mrf_keyword.replace', []) diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.scss b/src/components/mrf_transparency_panel/mrf_transparency_panel.scss new file mode 100644 index 00000000..80ea01d4 --- /dev/null +++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.scss @@ -0,0 +1,21 @@ +.mrf-section { + margin: 1em; + + table { + width:100%; + text-align: left; + padding-left:10px; + padding-bottom:20px; + + th, td { + width: 180px; + max-width: 360px; + overflow: hidden; + vertical-align: text-top; + } + + th+th, td+td { + width: auto; + } + } +} diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue index acdf822e..1787fa07 100644 --- a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue +++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue @@ -31,13 +31,24 @@ <p>{{ $t("about.mrf.simple.accept_desc") }}</p> - <ul> - <li - v-for="instance in acceptInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in acceptInstances" + :key="entry.instance + '_accept'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <div v-if="rejectInstances.length"> @@ -45,13 +56,24 @@ <p>{{ $t("about.mrf.simple.reject_desc") }}</p> - <ul> - <li - v-for="instance in rejectInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in rejectInstances" + :key="entry.instance + '_reject'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <div v-if="quarantineInstances.length"> @@ -59,13 +81,24 @@ <p>{{ $t("about.mrf.simple.quarantine_desc") }}</p> - <ul> - <li - v-for="instance in quarantineInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in quarantineInstances" + :key="entry.instance + '_quarantine'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <div v-if="ftlRemovalInstances.length"> @@ -73,13 +106,24 @@ <p>{{ $t("about.mrf.simple.ftl_removal_desc") }}</p> - <ul> - <li - v-for="instance in ftlRemovalInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in ftlRemovalInstances" + :key="entry.instance + '_ftl_removal'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <div v-if="mediaNsfwInstances.length"> @@ -87,13 +131,24 @@ <p>{{ $t("about.mrf.simple.media_nsfw_desc") }}</p> - <ul> - <li - v-for="instance in mediaNsfwInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in mediaNsfwInstances" + :key="entry.instance + '_media_nsfw'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <div v-if="mediaRemovalInstances.length"> @@ -101,13 +156,24 @@ <p>{{ $t("about.mrf.simple.media_removal_desc") }}</p> - <ul> - <li - v-for="instance in mediaRemovalInstances" - :key="instance" - v-text="instance" - /> - </ul> + <table> + <tr> + <th>{{ $t("about.mrf.simple.instance") }}</th> + <th>{{ $t("about.mrf.simple.reason") }}</th> + </tr> + <tr + v-for="entry in mediaRemovalInstances" + :key="entry.instance + '_media_removal'" + > + <td>{{ entry.instance }}</td> + <td v-if="entry.reason === ''"> + {{ $t("about.mrf.simple.not_applicable") }} + </td> + <td v-else> + {{ entry.reason }} + </td> + </tr> + </table> </div> <h2 v-if="hasKeywordPolicies"> @@ -161,7 +227,6 @@ <script src="./mrf_transparency_panel.js"></script> <style lang="scss"> -.mrf-section { - margin: 1em; -} +@import '../../_variables.scss'; +@import './mrf_transparency_panel.scss'; </style> diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index 8ab007e3..c0d20c5e 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -5,6 +5,7 @@ import { convertHtmlToTree } from 'src/services/html_converter/html_tree_convert import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js' import StillImage from 'src/components/still-image/still-image.vue' import MentionsLine, { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.vue' +import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue' import './rich_content.scss' @@ -61,6 +62,8 @@ export default Vue.component('RichContent', { // Pre-process HTML const { newHtml: html } = preProcessPerLine(this.html, this.greentext) let currentMentions = null // Current chain of mentions, we group all mentions together + // This is used to recover spacing removed when parsing mentions + let lastSpacing = '' const lastTags = [] // Tags that appear at the end of post body const writtenMentions = [] // All mentions that appear in post body @@ -81,13 +84,10 @@ export default Vue.component('RichContent', { const renderHashtag = (attrs, children, encounteredTextReverse) => { const linkData = getLinkData(attrs, children, tagsIndex++) writtenTags.push(linkData) - attrs.target = '_blank' if (!encounteredTextReverse) { lastTags.push(linkData) } - return <a {...{ attrs }}> - { children.map(processItem) } - </a> + return <HashtagLink {...{ props: linkData }}/> } const renderMention = (attrs, children) => { @@ -119,14 +119,9 @@ export default Vue.component('RichContent', { if (emptyText) { // don't include spaces when processing mentions - we'll include them // in MentionsLine + lastSpacing = item return currentMentions !== null ? item.trim() : item } - // We add space with mentionsLine, otherwise non-text elements will - // stick to them. - if (currentMentions !== null) { - // single whitespace trim - item = item[0].match(/\s/) ? item.slice(1) : item - } currentMentions = null if (item.includes(':')) { @@ -151,21 +146,32 @@ export default Vue.component('RichContent', { const [opener, children, closer] = item const Tag = getTagName(opener) const attrs = getAttrs(opener) + const previouslyMentions = currentMentions !== null + /* During grouping of mentions we trim all the empty text elements + * This padding is added to recover last space removed in case + * we have a tag right next to mentions + */ + const mentionsLinePadding = + // Padding is only needed if we just finished parsing mentions + previouslyMentions && + // Don't add padding if content is string and has padding already + !(children && typeof children[0] === 'string' && children[0].match(/^\s/)) + ? lastSpacing + : '' switch (Tag) { case 'br': currentMentions = null break case 'img': // replace images with StillImage - return renderImage(opener) + return ['', [mentionsLinePadding, renderImage(opener)], ''] case 'a': // replace mentions with MentionLink if (!this.handleLinks) break if (attrs['class'] && attrs['class'].includes('mention')) { // Handling mentions here return renderMention(attrs, children) } else { - // Everything else will be handled in reverse pass currentMentions = null - return item // We'll handle it later + break } case 'span': if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) { @@ -174,9 +180,16 @@ export default Vue.component('RichContent', { } if (children !== undefined) { - return [opener, children.map(processItem), closer] + return [ + '', + [ + mentionsLinePadding, + [opener, children.map(processItem), closer] + ], + '' + ] } else { - return item + return ['', [mentionsLinePadding, item], ''] } } } @@ -199,7 +212,10 @@ export default Vue.component('RichContent', { if (!this.handleLinks) break const attrs = getAttrs(opener) // should only be this - if (attrs['class'] && attrs['class'].includes('hashtag')) { + if ( + (attrs['class'] && attrs['class'].includes('hashtag')) || // Pleroma style + (attrs['rel'] === 'tag') // Mastodon style + ) { return renderHashtag(attrs, children, encounteredTextReverse) } else { attrs.target = '_blank' @@ -215,7 +231,6 @@ export default Vue.component('RichContent', { // Render tag as is if (children !== undefined) { - html.includes('freenode') && console.log('PASS2', children) const newChildren = Array.isArray(children) ? [...children].reverse().map(processItemReverse).reverse() : children @@ -264,7 +279,7 @@ const getLinkData = (attrs, children, index) => { return { index, url: attrs.href, - hashtag: attrs['data-tag'], + tag: attrs['data-tag'], content: flattenDeep(children).join(''), textContent } @@ -283,8 +298,6 @@ export const preProcessPerLine = (html, greentext) => { const lines = convertHtmlToLines(html) const newHtml = lines.reverse().map((item, index, array) => { - // Going over each line in reverse to detect last mentions, - // keeping non-text stuff as-is if (!item.text) return item const string = item.text diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js index 1dda49f2..5c52f697 100644 --- a/src/components/settings_modal/helpers/boolean_setting.js +++ b/src/components/settings_modal/helpers/boolean_setting.js @@ -16,10 +16,18 @@ export default { return [firstSegment + 'DefaultValue', ...rest].join('.') }, state () { - return get(this.$parent, this.path) + const value = get(this.$parent, this.path) + if (value === undefined) { + return this.defaultState + } else { + return value + } + }, + defaultState () { + return get(this.$parent, this.pathDefault) }, isChanged () { - return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault) + return this.state !== this.defaultState } }, methods: { diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index 042e8106..a15f6bac 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -17,13 +17,18 @@ export default { return [firstSegment + 'DefaultValue', ...rest].join('.') }, state () { - return get(this.$parent, this.path) + const value = get(this.$parent, this.path) + if (value === undefined) { + return this.defaultState + } else { + return value + } }, defaultState () { return get(this.$parent, this.pathDefault) }, isChanged () { - return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault) + return this.state !== this.defaultState } }, methods: { diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index d3e71b31..f2ec7d64 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -123,6 +123,11 @@ </BooleanSetting> </li> <li> + <BooleanSetting path="alwaysShowNewPostButton"> + {{ $t('settings.always_show_post_button') }} + </BooleanSetting> + </li> + <li> <BooleanSetting path="autohideFloatingPostButton"> {{ $t('settings.autohide_floating_post_button') }} </BooleanSetting> diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js index 9709424c..64079fcd 100644 --- a/src/components/settings_modal/tabs/profile_tab.js +++ b/src/components/settings_modal/tabs/profile_tab.js @@ -24,7 +24,7 @@ library.add( const ProfileTab = { data () { return { - newName: this.$store.state.users.currentUser.name, + newName: this.$store.state.users.currentUser.name_unescaped, newBio: unescape(this.$store.state.users.currentUser.description), newLocked: this.$store.state.users.currentUser.locked, newNoRichText: this.$store.state.users.currentUser.no_rich_text, diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.js b/src/components/settings_modal/tabs/theme_tab/theme_tab.js index 85749045..0b6669fc 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.js +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.js @@ -73,7 +73,8 @@ export default { getExportedObject: () => this.exportedTheme }), availableStyles: [], - selected: this.$store.getters.mergedConfig.theme, + selected: '', + selectedTheme: this.$store.getters.mergedConfig.theme, themeWarning: undefined, tempImportFile: undefined, engineVersion: 0, @@ -207,7 +208,7 @@ export default { } }, selectedVersion () { - return Array.isArray(this.selected) ? 1 : 2 + return Array.isArray(this.selectedTheme) ? 1 : 2 }, currentColors () { return Object.keys(SLOT_INHERITANCE) @@ -745,6 +746,16 @@ export default { } }, selected () { + this.selectedTheme = Object.entries(this.availableStyles).find(([k, s]) => { + if (Array.isArray(s)) { + console.log(s[0] === this.selected, this.selected) + return s[0] === this.selected + } else { + return s.name === this.selected + } + })[1] + }, + selectedTheme () { this.dismissWarning() if (this.selectedVersion === 1) { if (!this.keepRoundness) { @@ -762,17 +773,17 @@ export default { if (!this.keepColor) { this.clearV1() - this.bgColorLocal = this.selected[1] - this.fgColorLocal = this.selected[2] - this.textColorLocal = this.selected[3] - this.linkColorLocal = this.selected[4] - this.cRedColorLocal = this.selected[5] - this.cGreenColorLocal = this.selected[6] - this.cBlueColorLocal = this.selected[7] - this.cOrangeColorLocal = this.selected[8] + this.bgColorLocal = this.selectedTheme[1] + this.fgColorLocal = this.selectedTheme[2] + this.textColorLocal = this.selectedTheme[3] + this.linkColorLocal = this.selectedTheme[4] + this.cRedColorLocal = this.selectedTheme[5] + this.cGreenColorLocal = this.selectedTheme[6] + this.cBlueColorLocal = this.selectedTheme[7] + this.cOrangeColorLocal = this.selectedTheme[8] } } else if (this.selectedVersion >= 2) { - this.normalizeLocalState(this.selected.theme, 2, this.selected.source) + this.normalizeLocalState(this.selectedTheme.theme, 2, this.selectedTheme.source) } } } diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss index 1b7d9f31..0db21537 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss @@ -270,6 +270,9 @@ .apply-container { justify-content: center; + position: absolute; + bottom: 8px; + right: 5px; } .radius-item, diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue index 548dc852..c02986ed 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue @@ -63,7 +63,7 @@ <option v-for="style in availableStyles" :key="style.name" - :value="style" + :value="style.name || style[0]" :style="{ backgroundColor: style[1] || (style.theme || style.source).colors.bg, color: style[3] || (style.theme || style.source).colors.text diff --git a/src/components/shout_panel/shout_panel.vue b/src/components/shout_panel/shout_panel.vue index f90baf80..c88797d1 100644 --- a/src/components/shout_panel/shout_panel.vue +++ b/src/components/shout_panel/shout_panel.vue @@ -79,12 +79,19 @@ .floating-shout { position: fixed; - right: 0px; bottom: 0px; z-index: 1000; max-width: 25em; } +.floating-shout.left { + left: 0px; +} + +.floating-shout:not(.left) { + right: 0px; +} + .shout-panel { .shout-heading { cursor: pointer; diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js index 0faf3b9e..89719df3 100644 --- a/src/components/side_drawer/side_drawer.js +++ b/src/components/side_drawer/side_drawer.js @@ -49,6 +49,7 @@ const SideDrawer = { currentUser () { return this.$store.state.users.currentUser }, + shout () { return this.$store.state.shout.channel.state === 'joined' }, unseenNotifications () { return unseenNotificationsFromStore(this.$store) }, diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index 223b1632..dd88de7d 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -106,10 +106,10 @@ </router-link> </li> <li - v-if="chat" + v-if="shout" @click="toggleDrawer" > - <router-link :to="{ name: 'chat-panel' }"> + <router-link :to="{ name: 'shout-panel' }"> <FAIcon fixed-width class="fa-scale-110 fa-old-padding" @@ -273,9 +273,7 @@ --icon: var(--popoverIcon, $fallback--icon); .badge { - position: absolute; - right: 0.7rem; - top: 1em; + margin-left: 10px; } } diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index a453ce79..4168c54a 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -13,14 +13,16 @@ import { faBell, faRss, faSearchPlus, - faExternalLinkAlt + faExternalLinkAlt, + faEdit } from '@fortawesome/free-solid-svg-icons' library.add( faRss, faBell, faSearchPlus, - faExternalLinkAlt + faExternalLinkAlt, + faEdit ) export default { @@ -155,6 +157,9 @@ export default { this.$store.state.instance.restrictedNicknames ) }, + openProfileTab () { + this.$store.dispatch('openSettingsModalTab', 'profile') + }, zoomAvatar () { const attachment = { url: this.user.profile_image_url_original, diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 794a2350..5f957003 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -45,6 +45,18 @@ :emoji="user.emoji" /> <button + v-if="!isOtherUser && user.is_local" + class="button-unstyled edit-profile-button" + @click.stop="openProfileTab" + > + <FAIcon + fixed-width + class="icon" + icon="edit" + :title="$t('user_card.edit_profile')" + /> + </button> + <a v-if="isOtherUser && !user.is_local" :href="user.statusnet_profile_url" target="_blank" @@ -54,7 +66,7 @@ class="icon" icon="external-link-alt" /> - </button> + </a> <AccountActions v-if="isOtherUser && loggedIn" :user="user" @@ -71,6 +83,12 @@ </router-link> <template v-if="!hideBio"> <span + v-if="user.deactivated" + class="alert user-role" + > + {{ $t('user_card.deactivated') }} + </span> + <span v-if="!!visibleRole" class="alert user-role" > @@ -148,7 +166,10 @@ class="user-interactions" > <div class="btn-group"> - <FollowButton :relationship="relationship" /> + <FollowButton + :relationship="relationship" + :user="user" + /> <template v-if="relationship.following"> <ProgressButton v-if="!relationship.subscribing" @@ -183,6 +204,7 @@ <button v-if="relationship.muting" class="btn button-default btn-block toggled" + :disabled="user.deactivated" @click="unmuteUser" > {{ $t('user_card.muted') }} @@ -190,6 +212,7 @@ <button v-else class="btn button-default btn-block" + :disabled="user.deactivated" @click="muteUser" > {{ $t('user_card.mute') }} @@ -198,6 +221,7 @@ <div> <button class="btn button-default btn-block" + :disabled="user.deactivated" @click="mentionUser" > {{ $t('user_card.mention') }} @@ -405,7 +429,7 @@ } } - .external-link-button { + .external-link-button, .edit-profile-button { cursor: pointer; width: 2.5em; text-align: center; @@ -545,6 +569,10 @@ } } +.sidebar .edit-profile-button { + display: none; +} + .user-counts { display: flex; line-height:16px; |
