From 4803fb07c85914fd0c9756a1d399e9803f48b8c7 Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Mon, 8 Aug 2022 23:42:22 +0300 Subject: Allow opening profile when clicking an avatar inside of user popover --- src/components/settings_modal/tabs/general_tab.js | 5 +++++ src/components/settings_modal/tabs/general_tab.vue | 11 +++++++---- src/components/user_popover/user_popover.js | 4 ++-- src/components/user_popover/user_popover.vue | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src/components') diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index 1e11b9e0..d94a3be9 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -43,6 +43,11 @@ const GeneralTab = { value: mode, label: this.$t(`settings.third_column_mode_${mode}`) })), + userPopoverAvatarActionOptions: ['close', 'zoom', 'open'].map(mode => ({ + key: mode, + value: mode, + label: this.$t(`settings.user_popover_avatar_action_${mode}`) + })), loopSilentAvailable: // Firefox Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') || diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index a2609200..7ac61b2e 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -75,12 +75,15 @@
  • - - {{ $t('settings.user_popover_avatar_zoom') }} - + {{ $t('settings.user_popover_avatar_action') }} +
  • import('../popover/popover.vue')) }, computed: { - userPopoverZoom () { - return this.$store.getters.mergedConfig.userPopoverZoom + userPopoverAvatarAction () { + return this.$store.getters.mergedConfig.userPopoverAvatarAction }, userPopoverOverlay () { return this.$store.getters.mergedConfig.userPopoverOverlay diff --git a/src/components/user_popover/user_popover.vue b/src/components/user_popover/user_popover.vue index 4e999672..53d51fc4 100644 --- a/src/components/user_popover/user_popover.vue +++ b/src/components/user_popover/user_popover.vue @@ -14,7 +14,7 @@ class="user-popover" :user-id="userId" :hide-bio="true" - :avatar-action="userPopoverZoom ? 'zoom' : close" + :avatar-action="userPopoverAvatarAction == 'close' ? close : userPopoverAvatarAction" :on-close="close" /> -- cgit v1.2.3-70-g09d2 From a403f93b478eec67d779400b1fcfdc006bb787da Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Tue, 9 Aug 2022 10:44:20 +0300 Subject: Allow opening profile: multiChoiceProprties record, anonymous access --- src/components/settings_modal/tabs/general_tab.vue | 1 - src/modules/config.js | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/components') diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 7ac61b2e..c212a81a 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -76,7 +76,6 @@
  • Date: Tue, 9 Aug 2022 22:11:55 -0400 Subject: Use lookup endpoint to obtain users by nickname --- src/components/user_profile/user_profile.js | 15 ++++++++++----- src/modules/users.js | 7 +++++++ src/services/api/api.service.js | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) (limited to 'src/components') diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index f779b823..781fd601 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -45,7 +45,7 @@ const UserProfile = { }, created () { const routeParams = this.$route.params - this.load(routeParams.name || routeParams.id) + this.load({ name: routeParams.name, id: routeParams.id }) this.tab = get(this.$route, 'query.tab', defaultTabKey) }, unmounted () { @@ -106,12 +106,17 @@ const UserProfile = { this.userId = null this.error = false + const maybeId = userNameOrId.id + const maybeName = userNameOrId.name + // Check if user data is already loaded in store - const user = this.$store.getters.findUser(userNameOrId) + const user = this.$store.getters.findUser(maybeId || maybeName) if (user) { loadById(user.id) } else { - this.$store.dispatch('fetchUser', userNameOrId) + (maybeId + ? this.$store.dispatch('fetchUser', maybeId) + : this.$store.dispatch('fetchUserByName', maybeName)) .then(({ id }) => loadById(id)) .catch((reason) => { const errorMessage = get(reason, 'error.error') @@ -150,12 +155,12 @@ const UserProfile = { watch: { '$route.params.id': function (newVal) { if (newVal) { - this.switchUser(newVal) + this.switchUser({ id: newVal }) } }, '$route.params.name': function (newVal) { if (newVal) { - this.switchUser(newVal) + this.switchUser({ name: newVal }) } }, '$route.query': function (newVal) { diff --git a/src/modules/users.js b/src/modules/users.js index b6fb9746..47dc8493 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -285,6 +285,13 @@ const users = { return user }) }, + fetchUserByName (store, name) { + return store.rootState.api.backendInteractor.fetchUserByName({ name }) + .then((user) => { + store.commit('addNewUsers', [user]) + return user + }) + }, fetchUserRelationship (store, id) { if (store.state.currentUser) { store.rootState.api.backendInteractor.fetchUserRelationship({ id }) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 7b6f7d67..ce60d65a 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -50,6 +50,7 @@ const MASTODON_USER_HOME_TIMELINE_URL = '/api/v1/timelines/home' const MASTODON_STATUS_URL = id => `/api/v1/statuses/${id}` const MASTODON_STATUS_CONTEXT_URL = id => `/api/v1/statuses/${id}/context` const MASTODON_USER_URL = '/api/v1/accounts' +const MASTODON_USER_LOOKUP_URL = '/api/v1/accounts/lookup' const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships' const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses` const MASTODON_LIST_URL = id => `/api/v1/lists/${id}` @@ -318,6 +319,25 @@ const fetchUser = ({ id, credentials }) => { .then((data) => parseUser(data)) } +const fetchUserByName = ({ name, credentials }) => { + return promisedRequest({ + url: MASTODON_USER_LOOKUP_URL, + credentials, + params: { acct: name } + }) + .then(data => data.id) + .catch(error => { + if (error && error.statusCode === 404) { + // Either the backend does not support lookup endpoint, + // or there is no user with such name. Fallback and treat name as id. + return name + } else { + throw error + } + }) + .then(id => fetchUser({ id, credentials })) +} + const fetchUserRelationship = ({ id, credentials }) => { const url = `${MASTODON_USER_RELATIONSHIPS_URL}/?id=${id}` return fetch(url, { headers: authHeaders(credentials) }) @@ -1481,6 +1501,7 @@ const apiService = { blockUser, unblockUser, fetchUser, + fetchUserByName, fetchUserRelationship, favorite, unfavorite, -- cgit v1.2.3-70-g09d2 From ab4a75bdd92aba7973b6c32eb8ff11280552d6c6 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 10 Aug 2022 12:17:18 -0400 Subject: Do not allow to find by name in findUser() --- src/components/user_profile/user_profile.js | 2 +- src/modules/users.js | 20 +++++------ test/unit/specs/components/user_profile.spec.js | 5 ++- test/unit/specs/modules/users.spec.js | 44 ++++++++++++++++++++++--- 4 files changed, 54 insertions(+), 17 deletions(-) (limited to 'src/components') diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 781fd601..08adaeab 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -110,7 +110,7 @@ const UserProfile = { const maybeName = userNameOrId.name // Check if user data is already loaded in store - const user = this.$store.getters.findUser(maybeId || maybeName) + const user = maybeId ? this.$store.getters.findUser(maybeId) : this.$store.getters.findUserByName(maybeName) if (user) { loadById(user.id) } else { diff --git a/src/modules/users.js b/src/modules/users.js index 47dc8493..be0bc997 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -16,9 +16,6 @@ export const mergeOrAdd = (arr, obj, item) => { // This is a new item, prepare it arr.push(item) obj[item.id] = item - if (item.screen_name && !item.screen_name.includes('@')) { - obj[item.screen_name.toLowerCase()] = item - } return { item, new: true } } } @@ -162,7 +159,11 @@ export const mutations = { if (user.relationship) { state.relationships[user.relationship.id] = user.relationship } - mergeOrAdd(state.users, state.usersObject, user) + const res = mergeOrAdd(state.users, state.usersObject, user) + const item = res.item + if (res.new && item.screen_name && !item.screen_name.includes('@')) { + state.usersByNameObject[item.screen_name.toLowerCase()] = item + } }) }, updateUserRelationship (state, relationships) { @@ -239,12 +240,10 @@ export const mutations = { export const getters = { findUser: state => query => { - const result = state.usersObject[query] - // In case it's a screen_name, we can try searching case-insensitive - if (!result && typeof query === 'string') { - return state.usersObject[query.toLowerCase()] - } - return result + return state.usersObject[query] + }, + findUserByName: state => query => { + return state.usersByNameObject[query.toLowerCase()] }, findUserByUrl: state => query => { return state.users @@ -263,6 +262,7 @@ export const defaultState = { currentUser: false, users: [], usersObject: {}, + usersByNameObject: {}, signUpPending: false, signUpErrors: [], relationships: {} diff --git a/test/unit/specs/components/user_profile.spec.js b/test/unit/specs/components/user_profile.spec.js index 0fbab722..dc0b938a 100644 --- a/test/unit/specs/components/user_profile.spec.js +++ b/test/unit/specs/components/user_profile.spec.js @@ -15,6 +15,7 @@ const actions = { const testGetters = { findUser: state => getters.findUser(state.users), + findUserByName: state => getters.findUserByName(state.users), relationship: state => getters.relationship(state.users), mergedConfig: state => ({ colors: '', @@ -95,6 +96,7 @@ const externalProfileStore = createStore({ credentials: '' }, usersObject: { 100: extUser }, + usersByNameObject: {}, users: [extUser], relationships: {} } @@ -163,7 +165,8 @@ const localProfileStore = createStore({ currentUser: { credentials: '' }, - usersObject: { 100: localUser, testuser: localUser }, + usersObject: { 100: localUser }, + usersByNameObject: { testuser: localUser }, users: [localUser], relationships: {} } diff --git a/test/unit/specs/modules/users.spec.js b/test/unit/specs/modules/users.spec.js index dfa5684d..3073f507 100644 --- a/test/unit/specs/modules/users.spec.js +++ b/test/unit/specs/modules/users.spec.js @@ -57,24 +57,27 @@ describe('The users module', () => { }) describe('findUser', () => { - it('returns user with matching screen_name', () => { + it('does not return user with matching screen_name', () => { const user = { screen_name: 'Guy', id: '1' } const state = { usersObject: { - 1: user, + 1: user + }, + usersByNameObject: { guy: user } } const name = 'Guy' - const expected = { screen_name: 'Guy', id: '1' } - expect(getters.findUser(state)(name)).to.eql(expected) + expect(getters.findUser(state)(name)).to.eql(undefined) }) it('returns user with matching id', () => { const user = { screen_name: 'Guy', id: '1' } const state = { usersObject: { - 1: user, + 1: user + }, + usersByNameObject: { guy: user } } @@ -83,4 +86,35 @@ describe('The users module', () => { expect(getters.findUser(state)(id)).to.eql(expected) }) }) + + describe('findUserByName', () => { + it('returns user with matching screen_name', () => { + const user = { screen_name: 'Guy', id: '1' } + const state = { + usersObject: { + 1: user + }, + usersByNameObject: { + guy: user + } + } + const name = 'Guy' + const expected = { screen_name: 'Guy', id: '1' } + expect(getters.findUserByName(state)(name)).to.eql(expected) + }) + + it('does not return user with matching id', () => { + const user = { screen_name: 'Guy', id: '1' } + const state = { + usersObject: { + 1: user + }, + usersByNameObject: { + guy: user + } + } + const id = '1' + expect(getters.findUserByName(state)(id)).to.eql(undefined) + }) + }) }) -- cgit v1.2.3-70-g09d2 From 3e7e31d4a98f4cbdfdd3c92d952e58616c027beb Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Sun, 5 Jun 2022 17:10:44 +0300 Subject: Allow column width configuration Group column configuration in settings Column width configuration: do not act on defaults --- src/App.scss | 19 +++++- src/boot/after_store.js | 4 +- .../settings_modal/helpers/boolean_setting.js | 3 + .../settings_modal/helpers/boolean_setting.vue | 7 ++- .../settings_modal/helpers/choice_setting.js | 3 + .../settings_modal/helpers/choice_setting.vue | 5 +- .../settings_modal/helpers/integer_setting.js | 3 + .../settings_modal/helpers/integer_setting.vue | 5 +- .../settings_modal/helpers/size_setting.js | 67 ++++++++++++++++++++++ .../settings_modal/helpers/size_setting.vue | 54 +++++++++++++++++ src/components/settings_modal/tabs/general_tab.js | 16 ++++++ src/components/settings_modal/tabs/general_tab.vue | 38 +++++------- src/i18n/en.json | 5 ++ src/i18n/ru.json | 9 +++ src/modules/config.js | 9 ++- src/services/style_setter/style_setter.js | 31 ++++++++++ 16 files changed, 244 insertions(+), 34 deletions(-) create mode 100644 src/components/settings_modal/helpers/size_setting.js create mode 100644 src/components/settings_modal/helpers/size_setting.vue (limited to 'src/components') diff --git a/src/App.scss b/src/App.scss index ab025d63..0aa28933 100644 --- a/src/App.scss +++ b/src/App.scss @@ -186,9 +186,13 @@ nav { --columnGap: 1em; --status-margin: 0.75em; + --effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn))); + position: relative; display: grid; - grid-template-columns: var(--miniColumn) var(--maxiColumn); + grid-template-columns: + var(--sidebarColumnWidth, var(--miniColumn)) + var(--effectiveContentColumnWidth); grid-template-areas: "sidebar content"; grid-template-rows: 1fr; box-sizing: border-box; @@ -282,15 +286,24 @@ nav { } &.-reverse:not(.-wide):not(.-mobile) { - grid-template-columns: var(--maxiColumn) var(--miniColumn); + grid-template-columns: + var(--effectiveContentColumnWidth) + minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); grid-template-areas: "content sidebar"; } &.-wide { - grid-template-columns: var(--miniColumn) var(--maxiColumn) var(--miniColumn); + grid-template-columns: + minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))) + var(--effectiveContentColumnWidth) + minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))); grid-template-areas: "sidebar content notifs"; &.-reverse { + grid-template-columns: + minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))) + var(--effectiveContentColumnWidth) + minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); grid-template-areas: "notifs content sidebar"; } } diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 908d905a..38b5f38e 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -12,7 +12,7 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js' -import { applyTheme } from '../services/style_setter/style_setter.js' +import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js' import FaviconService from '../services/favicon_service/favicon_service.js' let staticInitialResults = null @@ -360,6 +360,8 @@ const afterStoreSetup = async ({ store, i18n }) => { console.error('Failed to load any theme!') } + applyConfig(store.state.config) + // Now we can try getting the server settings and logging in // Most of these are preloaded into the index.html so blocking is minimized await Promise.all([ diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js index 353e551c..dc832044 100644 --- a/src/components/settings_modal/helpers/boolean_setting.js +++ b/src/components/settings_modal/helpers/boolean_setting.js @@ -42,6 +42,9 @@ export default { methods: { update (e) { set(this.$parent, this.path, e) + }, + reset () { + set(this.$parent, this.path, this.defaultState) } } } diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue index 69584808..41142966 100644 --- a/src/components/settings_modal/helpers/boolean_setting.vue +++ b/src/components/settings_modal/helpers/boolean_setting.vue @@ -15,7 +15,12 @@ {{ ' ' }} - + + + diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index 4677d4c1..3da559fe 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -43,6 +43,9 @@ export default { methods: { update (e) { set(this.$parent, this.path, e) + }, + reset () { + set(this.$parent, this.path, this.defaultState) } } } diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue index 258c7422..d141a0d6 100644 --- a/src/components/settings_modal/helpers/choice_setting.vue +++ b/src/components/settings_modal/helpers/choice_setting.vue @@ -19,7 +19,10 @@ {{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }} - + diff --git a/src/components/settings_modal/helpers/integer_setting.js b/src/components/settings_modal/helpers/integer_setting.js index 17dc0e7b..e64d0cee 100644 --- a/src/components/settings_modal/helpers/integer_setting.js +++ b/src/components/settings_modal/helpers/integer_setting.js @@ -36,6 +36,9 @@ export default { methods: { update (e) { set(this.$parent, this.path, parseInt(e.target.value)) + }, + reset () { + set(this.$parent, this.path, this.defaultState) } } } diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue index e661a025..695e2673 100644 --- a/src/components/settings_modal/helpers/integer_setting.vue +++ b/src/components/settings_modal/helpers/integer_setting.vue @@ -17,7 +17,10 @@ @change="update" > {{ ' ' }} - + diff --git a/src/components/settings_modal/helpers/size_setting.js b/src/components/settings_modal/helpers/size_setting.js new file mode 100644 index 00000000..58697412 --- /dev/null +++ b/src/components/settings_modal/helpers/size_setting.js @@ -0,0 +1,67 @@ +import { get, set } from 'lodash' +import ModifiedIndicator from './modified_indicator.vue' +import Select from 'src/components/select/select.vue' + +export const allCssUnits = ['cm', 'mm', 'in', 'px', 'pt', 'pc', 'em', 'ex', 'ch', 'rem', 'vw', 'vh', 'vmin', 'vmax', '%'] +export const defaultHorizontalUnits = ['px', 'rem', 'vw'] +export const defaultVerticalUnits = ['px', 'rem', 'vh'] + +export default { + components: { + ModifiedIndicator, + Select + }, + props: { + path: String, + disabled: Boolean, + min: Number, + units: { + type: [String], + default: () => allCssUnits + }, + expert: [Number, String] + }, + computed: { + pathDefault () { + const [firstSegment, ...rest] = this.path.split('.') + return [firstSegment + 'DefaultValue', ...rest].join('.') + }, + stateUnit () { + return (this.state || '').replace(/\d+/, '') + }, + stateValue () { + return (this.state || '').replace(/\D+/, '') + }, + state () { + 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 this.state !== this.defaultState + }, + matchesExpertLevel () { + return (this.expert || 0) <= this.$parent.expertLevel + } + }, + methods: { + update (e) { + set(this.$parent, this.path, e) + }, + reset () { + set(this.$parent, this.path, this.defaultState) + }, + updateValue (e) { + set(this.$parent, this.path, parseInt(e.target.value) + this.stateUnit) + }, + updateUnit (e) { + set(this.$parent, this.path, this.stateValue + e.target.value) + } + } +} diff --git a/src/components/settings_modal/helpers/size_setting.vue b/src/components/settings_modal/helpers/size_setting.vue new file mode 100644 index 00000000..90c9f538 --- /dev/null +++ b/src/components/settings_modal/helpers/size_setting.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index 1e11b9e0..a22b9b03 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -2,6 +2,7 @@ import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' import ScopeSelector from 'src/components/scope_selector/scope_selector.vue' import IntegerSetting from '../helpers/integer_setting.vue' +import SizeSetting, { defaultHorizontalUnits } from '../helpers/size_setting.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' import SharedComputedObject from '../helpers/shared_computed_object.js' @@ -56,11 +57,15 @@ const GeneralTab = { BooleanSetting, ChoiceSetting, IntegerSetting, + SizeSetting, InterfaceLanguageSwitcher, ScopeSelector, ServerSideIndicator }, computed: { + horizontalUnits () { + return defaultHorizontalUnits + }, postFormats () { return this.$store.state.instance.postFormats || [] }, @@ -71,6 +76,17 @@ const GeneralTab = { label: this.$t(`post_status.content_type["${format}"]`) })) }, + columns () { + const mode = this.$store.getters.mergedConfig.thirdColumnMode + + const notif = mode === 'none' ? [] : ['notifs'] + + if (this.$store.getters.mergedConfig.sidebarRight || mode === 'postform') { + return [...notif, 'content', 'sidebar'] + } else { + return ['sidebar', 'content', ...notif] + } + }, instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel }, instanceWallpaperUsed () { return this.$store.state.instance.background && diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 91015955..db321363 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -15,11 +15,6 @@ {{ $t('settings.hide_isp') }}
  • -
  • - - {{ $t('settings.right_sidebar') }} - -
  • {{ $t('settings.hide_wallpaper') }} @@ -64,16 +59,6 @@ {{ $t('settings.virtual_scrolling') }}
  • -
  • - - {{ $t('settings.disable_sticky_headers') }} - -
  • -
  • - - {{ $t('settings.show_scrollbars') }} - -
  • -
  • - - {{ $t('settings.third_column_mode') }} - -
  • + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 2e845959..7e957ffd 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -533,6 +533,11 @@ "third_column_mode_none": "Don't show third column at all", "third_column_mode_notifications": "Notifications column", "third_column_mode_postform": "Main post form and navigation", + "columns": "Columns", + "column_sizes": "Column sizes", + "column_sizes_sidebar": "Sidebar", + "column_sizes_content": "Content", + "column_sizes_notifs": "Notifications", "tree_advanced": "Allow more flexible navigation in tree view", "tree_fade_ancestors": "Display ancestors of the current status in faint text", "conversation_display_linear": "Linear-style", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 7e6ff3f5..02815f3e 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -456,6 +456,15 @@ "subject_line_mastodon": "Как в Mastodon: скопировать как есть", "subject_line_email": "Как в электронной почте: \"re: тема\"", "subject_line_behavior": "Копировать тему в ответах", + "third_column_mode": "Когда недостаточно места, показывать третью колонку содержащую", + "third_column_mode_none": "Не показывать третью колонку совсем", + "third_column_mode_notifications": "Колонку уведомлений", + "third_column_mode_postform": "Форму отправки сообщения и навигацию", + "columns": "Колонки", + "column_sizes": "Размеры колонок", + "column_sizes_sidebar": "Боковой", + "column_sizes_content": "Содержимого", + "column_sizes_notifs": "Уведомлений", "no_mutes": "Нет игнорируемых", "no_blocks": "Нет блокировок", "notification_visibility_emoji_reactions": "Реакции", diff --git a/src/modules/config.js b/src/modules/config.js index c34b2c8c..2918f865 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -1,5 +1,5 @@ import Cookies from 'js-cookie' -import { setPreset, applyTheme } from '../services/style_setter/style_setter.js' +import { setPreset, applyTheme, applyConfig } from '../services/style_setter/style_setter.js' import messages from '../i18n/messages' import localeService from '../services/locale/locale.service.js' @@ -165,12 +165,17 @@ const config = { setHighlight ({ commit, dispatch }, { user, color, type }) { commit('setHighlight', { user, color, type }) }, - setOption ({ commit, dispatch }, { name, value }) { + setOption ({ commit, dispatch, state }, { name, value }) { commit('setOption', { name, value }) switch (name) { case 'theme': setPreset(value) break + case 'sidebarColumnWidth': + case 'contentColumnWidth': + case 'notifsColumnWidth': + applyConfig(state) + break case 'customTheme': case 'customThemeSource': applyTheme(value) diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 543aa874..d6e973a1 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -1,6 +1,7 @@ import { convert } from 'chromatism' import { rgb2hex, hex2rgb, rgba2css, getCssColor, relativeLuminance } from '../color_convert/color_convert.js' import { getColors, computeDynamicColor, getOpacitySlot } from '../theme_data/theme_data.service.js' +import { defaultState } from '../../modules/config.js' export const applyTheme = (input) => { const { rules } = generatePreset(input) @@ -20,6 +21,36 @@ export const applyTheme = (input) => { body.classList.remove('hidden') } +const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth }) => + ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth }) + +const defaultConfigColumns = configColumns(defaultState) + +export const applyConfig = (config) => { + const columns = configColumns(config) + + if (columns === defaultConfigColumns) { + return + } + + const head = document.head + const body = document.body + body.classList.add('hidden') + + const rules = Object + .entries(columns) + .filter(([k, v]) => v) + .map(([k, v]) => `--${k}: ${v}`).join(';') + + const styleEl = document.createElement('style') + head.appendChild(styleEl) + const styleSheet = styleEl.sheet + + styleSheet.toString() + styleSheet.insertRule(`:root { ${rules} }`, 'index-max') + body.classList.remove('hidden') +} + export const getCssShadow = (input, usesDropShadow) => { if (input.length === 0) { return 'none' -- cgit v1.2.3-70-g09d2 From a29835375a62549410a7df7922f8eb3f9b391487 Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Wed, 17 Aug 2022 02:33:39 +0300 Subject: Allow column width configuration: allow stretching navbar with columns --- src/App.js | 7 +++++++ src/App.scss | 15 ++++++++------- src/App.vue | 5 ++++- src/components/desktop_nav/desktop_nav.scss | 20 ++++++++++++++++++++ src/components/settings_modal/tabs/general_tab.vue | 5 +++++ src/i18n/en.json | 1 + src/modules/config.js | 1 + 7 files changed, 46 insertions(+), 8 deletions(-) (limited to 'src/components') diff --git a/src/App.js b/src/App.js index f5bd7e2e..d1ad16d5 100644 --- a/src/App.js +++ b/src/App.js @@ -60,6 +60,13 @@ export default { '-' + this.layoutType ] }, + navClasses () { + const { navbarColumnStretch } = this.$store.getters.mergedConfig + return [ + '-' + this.layoutType, + ...(navbarColumnStretch ? ['-column-stretch'] : []) + ] + }, currentUser () { return this.$store.state.users.currentUser }, userBackground () { return this.currentUser.background_image }, instanceBackground () { diff --git a/src/App.scss b/src/App.scss index 3c16007e..02f5e049 100644 --- a/src/App.scss +++ b/src/App.scss @@ -185,13 +185,14 @@ nav { --maxiColumn: 45rem; --columnGap: 1em; --status-margin: 0.75em; - + --effectiveSidebarColumnWidth: minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); + --effectiveNotifsColumnWidth: minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))); --effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn))); position: relative; display: grid; grid-template-columns: - minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))) + var(--effectiveSidebarColumnWidth) var(--effectiveContentColumnWidth); grid-template-areas: "sidebar content"; grid-template-rows: 1fr; @@ -288,22 +289,22 @@ nav { &.-reverse:not(.-wide):not(.-mobile) { grid-template-columns: var(--effectiveContentColumnWidth) - minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); + var(--effectiveSidebarColumnWidth); grid-template-areas: "content sidebar"; } &.-wide { grid-template-columns: - minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))) + var(--effectiveSidebarColumnWidth) var(--effectiveContentColumnWidth) - minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))); + var(--effectiveNotifsColumnWidth); grid-template-areas: "sidebar content notifs"; &.-reverse { grid-template-columns: - minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))) + var(--effectiveNotifsColumnWidth) var(--effectiveContentColumnWidth) - minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); + var(--effectiveSidebarColumnWidth); grid-template-areas: "notifs content sidebar"; } } diff --git a/src/App.vue b/src/App.vue index c741aa70..1f96efe8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -8,7 +8,10 @@ class="app-bg-wrapper" /> - +
  • +
  • + + {{ $t('settings.navbar_column_stretch') }} + +
  • Date: Sun, 16 Jan 2022 01:01:19 -0500 Subject: Add badges to status interacting buttons Now, the following badges will be added: 0: (+) sign to reply, favourite, repeat, react and extra buttons 1: (-) sign to unfavourite and unrepeat 2: (x) sign to close reply form, close react popover, and close extra buttons popover 3: Check mark to favourited and repeated statuses https://git.pleroma.social/pleroma/pleroma-fe/-/issues/1092 --- src/App.scss | 2 +- src/components/extra_buttons/extra_buttons.js | 19 +++++++++- src/components/extra_buttons/extra_buttons.vue | 34 +++++++++++++++-- src/components/favorite_button/favorite_button.js | 12 +++++- src/components/favorite_button/favorite_button.vue | 43 +++++++++++++++++++--- src/components/react_button/react_button.js | 17 ++++++++- src/components/react_button/react_button.vue | 35 +++++++++++++++--- src/components/reply_button/reply_button.js | 12 +++++- src/components/reply_button/reply_button.vue | 32 ++++++++++++++-- src/components/retweet_button/retweet_button.js | 14 ++++++- src/components/retweet_button/retweet_button.vue | 43 +++++++++++++++++++--- 11 files changed, 229 insertions(+), 34 deletions(-) (limited to 'src/components') diff --git a/src/App.scss b/src/App.scss index ab025d63..3e23ebfa 100644 --- a/src/App.scss +++ b/src/App.scss @@ -752,7 +752,7 @@ option { } .fa-old-padding { - &.svg-inline--fa { + &.svg-inline--fa, &-layer { padding: 0 0.3em; } } diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index 22ffb65a..68fa66ad 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -6,7 +6,9 @@ import { faEyeSlash, faThumbtack, faShareAlt, - faExternalLinkAlt + faExternalLinkAlt, + faPlus, + faTimes } from '@fortawesome/free-solid-svg-icons' import { faBookmark as faBookmarkReg, @@ -21,13 +23,26 @@ library.add( faThumbtack, faShareAlt, faExternalLinkAlt, - faFlag + faFlag, + faPlus, + faTimes ) const ExtraButtons = { props: ['status'], components: { Popover }, + data () { + return { + expanded: false + } + }, methods: { + onShow () { + this.expanded = true + }, + onClose () { + this.expanded = false + }, deleteStatus () { const confirmed = window.confirm(this.$t('status.delete_confirm')) if (confirmed) { diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index 2c893bf3..23d74fce 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -6,6 +6,8 @@ :offset="{ y: 5 }" :bound-to="{ x: 'container' }" remove-padding + @show="onShow" + @close="onClose" > @@ -151,6 +167,16 @@ color: $fallback--text; color: var(--text, $fallback--text); } + + .focus-marker { + visibility: hidden; + } + + &:hover, &:focus { + .focus-marker { + visibility: visible; + } + } } } diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js index 5cd05f73..c996cba2 100644 --- a/src/components/favorite_button/favorite_button.js +++ b/src/components/favorite_button/favorite_button.js @@ -1,13 +1,21 @@ import { mapGetters } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' -import { faStar } from '@fortawesome/free-solid-svg-icons' +import { + faStar, + faPlus, + faMinus, + faCheck +} from '@fortawesome/free-solid-svg-icons' import { faStar as faStarRegular } from '@fortawesome/free-regular-svg-icons' library.add( faStar, - faStarRegular + faStarRegular, + faPlus, + faMinus, + faCheck ) const FavoriteButton = { diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue index d5c4c61e..4015e1e6 100644 --- a/src/components/favorite_button/favorite_button.vue +++ b/src/components/favorite_button/favorite_button.vue @@ -7,11 +7,31 @@ :title="$t('tool_tip.favorite')" @click.prevent="favorite()" > - + + + + + + diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 37d6e7d0..5e052e1e 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -1,15 +1,21 @@ import Popover from '../popover/popover.vue' import { library } from '@fortawesome/fontawesome-svg-core' +import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons' import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' import { trim } from 'lodash' -library.add(faSmileBeam) +library.add( + faPlus, + faTimes, + faSmileBeam +) const ReactButton = { props: ['status'], data () { return { - filterWord: '' + filterWord: '', + expanded: false } }, components: { @@ -25,6 +31,13 @@ const ReactButton = { } close() }, + onShow () { + this.expanded = true + this.focusInput() + }, + onClose () { + this.expanded = false + }, focusInput () { this.$nextTick(() => { const input = this.$el.querySelector('input') diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue index 5a809847..e30f6b68 100644 --- a/src/components/react_button/react_button.vue +++ b/src/components/react_button/react_button.vue @@ -7,7 +7,8 @@ :bound-to="{ x: 'container' }" remove-padding popover-class="ReactButton popover-default" - @show="focusInput" + @show="onShow" + @close="onClose" > @@ -125,6 +140,16 @@ color: $fallback--text; color: var(--text, $fallback--text); } + + .focus-marker { + visibility: hidden; + } + + &:hover, &:focus { + .focus-marker { + visibility: visible; + } + } } } diff --git a/src/components/reply_button/reply_button.js b/src/components/reply_button/reply_button.js index c7bd2a2b..d6382982 100644 --- a/src/components/reply_button/reply_button.js +++ b/src/components/reply_button/reply_button.js @@ -1,7 +1,15 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faReply } from '@fortawesome/free-solid-svg-icons' +import { + faReply, + faPlus, + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faReply) +library.add( + faReply, + faPlus, + faTimes +) const ReplyButton = { name: 'ReplyButton', diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue index c17041da..56156c55 100644 --- a/src/components/reply_button/reply_button.vue +++ b/src/components/reply_button/reply_button.vue @@ -7,10 +7,24 @@ :title="$t('tool_tip.reply')" @click.prevent="$emit('toggle')" > - + + + + + - + + + + + + -- cgit v1.2.3-70-g09d2 From 378ed3682e56dc49ac74a9ab66b6ff9878d48882 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 19 Jan 2022 19:26:59 -0500 Subject: Optimize Reply badge position --- src/components/reply_button/reply_button.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/components') diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue index 56156c55..d75e6fd9 100644 --- a/src/components/reply_button/reply_button.vue +++ b/src/components/reply_button/reply_button.vue @@ -15,13 +15,13 @@ -- cgit v1.2.3-70-g09d2 From 97951fccfdce726c350ab633acc45213d675adb9 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 19 Jan 2022 19:45:38 -0500 Subject: Use :focus-visible instead of :focus for focus markers In this way, after the user clicked with a pointer and moved that pointer away, the focus marker will no longer show a focused style. As Safari remains the only major browser engine that does not support :focus-visible, a fallback to :focus is used if there is no browser support for :focus-visible. https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible --- src/components/extra_buttons/extra_buttons.vue | 5 +++-- src/components/favorite_button/favorite_button.vue | 9 +++++++-- src/components/react_button/react_button.vue | 5 +++-- src/components/reply_button/reply_button.vue | 5 +++-- src/components/retweet_button/retweet_button.vue | 9 +++++++-- 5 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src/components') diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index 23d74fce..d15e3102 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -168,11 +168,12 @@ color: var(--text, $fallback--text); } - .focus-marker { + .focus-marker, + &:focus:not(:focus-visible):not(:hover) .focus-marker { visibility: hidden; } - &:hover, &:focus { + &:hover, &:focus, &:focus-visible { .focus-marker { visibility: visible; } diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue index 4015e1e6..01db63be 100644 --- a/src/components/favorite_button/favorite_button.vue +++ b/src/components/favorite_button/favorite_button.vue @@ -78,11 +78,16 @@ color: var(--cOrange, $fallback--cOrange); } - .focus-marker { + .focus-marker, + &:focus:not(:focus-visible):not(:hover) .focus-marker { visibility: hidden; } - &:hover, &:focus { + &:focus:not(:focus-visible):not(:hover) .active-marker { + visibility: visible; + } + + &:hover, &:focus, &:focus-visible { .focus-marker { visibility: visible; } diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue index e30f6b68..885869f9 100644 --- a/src/components/react_button/react_button.vue +++ b/src/components/react_button/react_button.vue @@ -141,11 +141,12 @@ color: var(--text, $fallback--text); } - .focus-marker { + .focus-marker, + &:focus:not(:focus-visible):not(:hover) .focus-marker { visibility: hidden; } - &:hover, &:focus { + &:hover, &:focus, &:focus-visible { .focus-marker { visibility: visible; } diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue index d75e6fd9..0466ceb3 100644 --- a/src/components/reply_button/reply_button.vue +++ b/src/components/reply_button/reply_button.vue @@ -67,11 +67,12 @@ color: var(--cBlue, $fallback--cBlue); } - .focus-marker { + .focus-marker, + &:focus:not(:focus-visible):not(:hover) .focus-marker { visibility: hidden; } - &:hover, &:focus { + &:hover, &:focus, &:focus-visible { .focus-marker { visibility: visible; } diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index ed84066d..d88adacc 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -85,11 +85,16 @@ color: var(--cGreen, $fallback--cGreen); } - .focus-marker { + .focus-marker, + &:focus:not(:focus-visible):not(:hover) .focus-marker { visibility: hidden; } - &:hover, &:focus { + &:focus:not(:focus-visible):not(:hover) .active-marker { + visibility: visible; + } + + &:hover, &:focus, &:focus-visible { .focus-marker { visibility: visible; } -- cgit v1.2.3-70-g09d2 From 11672bc4907d41706ad164f1ca3c485f034061c1 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 19 Jan 2022 21:18:02 -0500 Subject: Fix styling on Safari --- src/_mixins.scss | 17 +++++++++++++++++ src/components/extra_buttons/extra_buttons.vue | 10 ++++++---- src/components/favorite_button/favorite_button.vue | 17 ++++++++++------- src/components/react_button/react_button.vue | 10 ++++++---- src/components/reply_button/reply_button.vue | 10 ++++++---- src/components/retweet_button/retweet_button.vue | 17 ++++++++++------- 6 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 src/_mixins.scss (limited to 'src/components') diff --git a/src/_mixins.scss b/src/_mixins.scss new file mode 100644 index 00000000..1fed16c3 --- /dev/null +++ b/src/_mixins.scss @@ -0,0 +1,17 @@ +@mixin unfocused-style { + @content; + + &:focus:not(:focus-visible):not(:hover) { + @content; + } +} + +@mixin focused-style { + &:hover, &:focus { + @content; + } + + &:focus-visible { + @content; + } +} diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index d15e3102..ae50c316 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -151,6 +151,7 @@