aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/navigation/filter.js2
-rw-r--r--src/components/navigation/navigation_pins.js10
-rw-r--r--src/components/notification/notification.js14
-rw-r--r--src/components/notification/notification.vue20
-rw-r--r--src/components/notifications/notifications.js3
-rw-r--r--src/components/notifications/notifications.scss10
-rw-r--r--src/components/registration/registration.vue4
-rw-r--r--src/components/settings_modal/helpers/boolean_setting.js6
-rw-r--r--src/components/settings_modal/tabs/filtering_tab.js9
-rw-r--r--src/components/settings_modal/tabs/theme_tab/theme_tab.js4
-rw-r--r--src/components/timeline_menu/timeline_menu.js21
-rw-r--r--src/components/user_card/user_card.js13
-rw-r--r--src/components/user_card/user_card.scss4
-rw-r--r--src/components/user_card/user_card.vue6
-rw-r--r--src/components/user_note/user_note.js45
-rw-r--r--src/components/user_note/user_note.vue88
-rw-r--r--src/components/user_profile/user_profile.vue1
17 files changed, 234 insertions, 26 deletions
diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js
index 5474a8ac..e8e77f8f 100644
--- a/src/components/navigation/filter.js
+++ b/src/components/navigation/filter.js
@@ -2,7 +2,7 @@ export const filterNavigation = (list = [], { hasChats, hasAnnouncements, isFede
return list.filter(({ criteria, anon, anonRoute }) => {
const set = new Set(criteria || [])
if (!isFederating && set.has('federating')) return false
- if (isPrivate && set.has('!private')) return false
+ if (!currentUser && isPrivate && set.has('!private')) return false
if (!currentUser && !(anon || anonRoute)) return false
if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) return false
if (!hasChats && set.has('chats')) return false
diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js
index 57b8d589..9dd795aa 100644
--- a/src/components/navigation/navigation_pins.js
+++ b/src/components/navigation/navigation_pins.js
@@ -56,11 +56,17 @@ const NavPanel = {
}),
pinnedList () {
if (!this.currentUser) {
- return [
+ return filterNavigation([
{ ...TIMELINES.public, name: 'public' },
{ ...TIMELINES.twkn, name: 'twkn' },
{ ...ROOT_ITEMS.about, name: 'about' }
- ]
+ ],
+ {
+ hasChats: this.pleromaChatMessagesAvailable,
+ isFederating: this.federating,
+ isPrivate: this.privateMode,
+ currentUser: this.currentUser
+ })
}
return filterNavigation(
[
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index ddba560e..265aaee0 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -20,7 +20,9 @@ import {
faUserPlus,
faEyeSlash,
faUser,
- faSuitcaseRolling
+ faSuitcaseRolling,
+ faExpandAlt,
+ faCompressAlt
} from '@fortawesome/free-solid-svg-icons'
library.add(
@@ -31,13 +33,15 @@ library.add(
faUserPlus,
faUser,
faEyeSlash,
- faSuitcaseRolling
+ faSuitcaseRolling,
+ faExpandAlt,
+ faCompressAlt
)
const Notification = {
data () {
return {
- userExpanded: false,
+ statusExpanded: false,
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
unmuted: false
}
@@ -55,8 +59,8 @@ const Notification = {
UserLink
},
methods: {
- toggleUserExpanded () {
- this.userExpanded = !this.userExpanded
+ toggleStatusExpanded () {
+ this.statusExpanded = !this.statusExpanded
},
generateUserProfileLink (user) {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 84f3f7de..f1aa5420 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -144,13 +144,25 @@
<router-link
v-if="notification.status"
:to="{ name: 'conversation', params: { id: notification.status.id } }"
- class="faint-link"
+ class="timeago-link faint-link"
>
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
</router-link>
+ <button
+ class="button-unstyled expand-icon"
+ @click.prevent="toggleStatusExpanded"
+ :title="$t('tool_tip.toggle_expand')"
+ :aria-expanded="statusExpanded"
+ >
+ <FAIcon
+ class="fa-scale-110"
+ fixed-width
+ :icon="statusExpanded ? 'compress-alt' : 'expand-alt'"
+ />
+ </button>
</div>
<div
v-else
@@ -166,6 +178,8 @@
<button
v-if="needMute"
class="button-unstyled"
+ :title="$t('tool_tip.toggle_mute')"
+ :aria-expanded="!unmuted"
@click.prevent="toggleMute"
>
<FAIcon
@@ -222,8 +236,8 @@
/>
<template v-else>
<StatusContent
- class="faint"
- :compact="true"
+ :class="{ faint: !statusExpanded }"
+ :compact="!statusExpanded"
:status="notification.action"
/>
</template>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index dde9c93e..d499d3d6 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -101,6 +101,9 @@ const Notifications = {
if (!this.scrollerRef) {
this.scrollerRef = this.$refs.root.closest('.mobile-notifications')
}
+ if (!this.scrollerRef) {
+ this.scrollerRef = this.$refs.root.closest('.column.main')
+ }
this.scrollerRef.addEventListener('scroll', this.updateScrollPosition)
},
unmounted () {
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index f71f9b76..9b241565 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -112,6 +112,16 @@
min-width: 3em;
text-align: right;
}
+
+ .timeago-link {
+ margin-right: 0.2em;
+ }
+
+ .expand-icon {
+ .svg-inline--fa {
+ margin-left: 0.25em;
+ }
+ }
}
.emoji-reaction-emoji {
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index d78d8da9..24d9b59b 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -158,10 +158,10 @@
class="form-error"
>
<ul>
- <li v-if="!v$.user.confirm.required">
+ <li v-if="v$.user.confirm.required.$invalid">
<span>{{ $t('registration.validations.password_confirmation_required') }}</span>
</li>
- <li v-if="!v$.user.confirm.sameAsPassword">
+ <li v-if="v$.user.confirm.sameAs.$invalid">
<span>{{ $t('registration.validations.password_confirmation_match') }}</span>
</li>
</ul>
diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js
index dc832044..2e6992cb 100644
--- a/src/components/settings_modal/helpers/boolean_setting.js
+++ b/src/components/settings_modal/helpers/boolean_setting.js
@@ -41,7 +41,13 @@ export default {
},
methods: {
update (e) {
+ const [firstSegment, ...rest] = this.path.split('.')
set(this.$parent, this.path, e)
+ // Updating nested properties does not trigger update on its parent.
+ // probably still not as reliable, but works for depth=1 at least
+ if (rest.length > 0) {
+ set(this.$parent, firstSegment, { ...get(this.$parent, firstSegment) })
+ }
},
reset () {
set(this.$parent, this.path, this.defaultState)
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 73413b48..5354e5db 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -38,15 +38,6 @@ const FilteringTab = {
},
// Updating nested properties
watch: {
- notificationVisibility: {
- handler (value) {
- this.$store.dispatch('setOption', {
- name: 'notificationVisibility',
- value: this.$store.getters.mergedConfig.notificationVisibility
- })
- },
- deep: true
- },
replyVisibility () {
this.$store.dispatch('queueFlushAll')
}
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 282cb384..4a739f73 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_tab.js
+++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.js
@@ -279,6 +279,9 @@ export default {
opacity
)
+ // Temporary patch for null-y value errors
+ if (layers.flat().some(v => v == null)) return acc
+
return {
...acc,
...textColors.reduce((acc, textColorKey) => {
@@ -300,6 +303,7 @@ export default {
return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
} catch (e) {
console.warn('Failure computing contrasts', e)
+ return {}
}
},
previewRules () {
diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js
index d74fbf4e..5a2a86c2 100644
--- a/src/components/timeline_menu/timeline_menu.js
+++ b/src/components/timeline_menu/timeline_menu.js
@@ -1,8 +1,10 @@
import Popover from '../popover/popover.vue'
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
+import { mapState } from 'vuex'
import { ListsMenuContent } from '../lists_menu/lists_menu_content.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { TIMELINES } from 'src/components/navigation/navigation.js'
+import { filterNavigation } from 'src/components/navigation/filter.js'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
@@ -29,8 +31,7 @@ const TimelineMenu = {
},
data () {
return {
- isOpen: false,
- timelinesList: Object.entries(TIMELINES).map(([k, v]) => ({ ...v, name: k }))
+ isOpen: false
}
},
created () {
@@ -42,6 +43,22 @@ const TimelineMenu = {
useListsMenu () {
const route = this.$route.name
return route === 'lists-timeline'
+ },
+ ...mapState({
+ currentUser: state => state.users.currentUser,
+ privateMode: state => state.instance.private,
+ federating: state => state.instance.federating
+ }),
+ timelinesList () {
+ return filterNavigation(
+ Object.entries(TIMELINES).map(([k, v]) => ({ ...v, name: k })),
+ {
+ hasChats: this.pleromaChatMessagesAvailable,
+ isFederating: this.federating,
+ isPrivate: this.privateMode,
+ currentUser: this.currentUser
+ }
+ )
}
},
methods: {
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index 8b64a07e..67879307 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -4,6 +4,7 @@ import ProgressButton from '../progress_button/progress_button.vue'
import FollowButton from '../follow_button/follow_button.vue'
import ModerationTools from '../moderation_tools/moderation_tools.vue'
import AccountActions from '../account_actions/account_actions.vue'
+import UserNote from '../user_note/user_note.vue'
import Select from '../select/select.vue'
import UserLink from '../user_link/user_link.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
@@ -39,7 +40,8 @@ export default {
'rounded',
'bordered',
'avatarAction', // default - open profile, 'zoom' - zoom, function - call function
- 'onClose'
+ 'onClose',
+ 'hasNoteEditor'
],
data () {
return {
@@ -129,6 +131,12 @@ export default {
const privileges = this.loggedIn.privileges
return this.loggedIn.role === 'admin' || privileges.includes('users_manage_activation_state') || privileges.includes('users_delete') || privileges.includes('users_manage_tags')
},
+ hasNote () {
+ return this.relationship.note
+ },
+ supportsNote () {
+ return 'note' in this.relationship
+ },
...mapGetters(['mergedConfig'])
},
components: {
@@ -140,7 +148,8 @@ export default {
FollowButton,
Select,
RichContent,
- UserLink
+ UserLink,
+ UserNote
},
methods: {
muteUser () {
diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss
index a0bbc6a6..cdb8cb57 100644
--- a/src/components/user_card/user_card.scss
+++ b/src/components/user_card/user_card.scss
@@ -315,6 +315,10 @@
margin: 0;
}
}
+
+ .user-note {
+ margin: 0 .75em .6em 0;
+ }
}
.sidebar .edit-profile-button {
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 897d89f9..349c7cb1 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -268,6 +268,12 @@
>
<RemoteFollow :user="user" />
</div>
+ <UserNote
+ v-if="loggedIn && isOtherUser && (hasNote || (hasNoteEditor && supportsNote))"
+ :user="user"
+ :relationship="relationship"
+ :editable="hasNoteEditor"
+ />
</div>
</div>
<div
diff --git a/src/components/user_note/user_note.js b/src/components/user_note/user_note.js
new file mode 100644
index 00000000..830b2e59
--- /dev/null
+++ b/src/components/user_note/user_note.js
@@ -0,0 +1,45 @@
+const UserNote = {
+ props: {
+ user: Object,
+ relationship: Object,
+ editable: Boolean
+ },
+ data () {
+ return {
+ localNote: '',
+ editing: false,
+ frozen: false
+ }
+ },
+ computed: {
+ shouldShow () {
+ return this.relationship.note || this.editing
+ }
+ },
+ methods: {
+ startEditing () {
+ this.localNote = this.relationship.note
+ this.editing = true
+ },
+ cancelEditing () {
+ this.editing = false
+ },
+ finalizeEditing () {
+ this.frozen = true
+
+ this.$store.dispatch('editUserNote', {
+ id: this.user.id,
+ comment: this.localNote
+ })
+ .then(() => {
+ this.frozen = false
+ this.editing = false
+ })
+ .catch(() => {
+ this.frozen = false
+ })
+ }
+ }
+}
+
+export default UserNote
diff --git a/src/components/user_note/user_note.vue b/src/components/user_note/user_note.vue
new file mode 100644
index 00000000..4286e017
--- /dev/null
+++ b/src/components/user_note/user_note.vue
@@ -0,0 +1,88 @@
+<template>
+ <div
+ class="user-note"
+ >
+ <div class="heading">
+ <span>{{ $t('user_card.note') }}</span>
+ <div class="buttons">
+ <button
+ v-show="!editing && editable"
+ class="button-default btn"
+ @click="startEditing"
+ >
+ {{ $t('user_card.edit_note') }}
+ </button>
+ <button
+ v-show="editing"
+ class="button-default btn"
+ :disabled="frozen"
+ @click="finalizeEditing"
+ >
+ {{ $t('user_card.edit_note_apply') }}
+ </button>
+ <button
+ v-show="editing"
+ class="button-default btn"
+ :disabled="frozen"
+ @click="cancelEditing"
+ >
+ {{ $t('user_card.edit_note_cancel') }}
+ </button>
+ </div>
+ </div>
+ <textarea
+ v-show="editing"
+ v-model="localNote"
+ class="note-text"
+ />
+ <span
+ v-show="!editing"
+ class="note-text"
+ :class="{ '-blank': !relationship.note }"
+ >
+ {{ relationship.note || $t('user_card.note_blank') }}
+ </span>
+ </div>
+</template>
+
+<script src="./user_note.js"></script>
+
+<style lang="scss">
+@import '../../variables';
+
+.user-note {
+ display: flex;
+ flex-direction: column;
+
+ .heading {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.75em;
+
+ .btn {
+ min-width: 95px;
+ }
+
+ .buttons {
+ display: flex;
+ flex-direction: row;
+ justify-content: right;
+
+ .btn {
+ margin-left: 0.5em;
+ }
+ }
+ }
+
+ .note-text {
+ align-self: stretch;
+ }
+
+ .note-text.-blank {
+ font-style: italic;
+ color: var(--faint, $fallback--faint);
+ }
+}
+</style>
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index d0da2b5b..d5e8d230 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -10,6 +10,7 @@
:selected="timeline.viewing"
avatar-action="zoom"
rounded="top"
+ :has-note-editor="true"
/>
<div
v-if="user.fields_html && user.fields_html.length > 0"