diff --git a/src/boot/routes.js b/src/boot/routes.js index 7400a682..d98a3b50 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -7,10 +7,8 @@ import Interactions from 'components/interactions/interactions.vue' import DMs from 'components/dm_timeline/dm_timeline.vue' import UserProfile from 'components/user_profile/user_profile.vue' import Search from 'components/search/search.vue' -import Settings from 'components/settings/settings.vue' import Registration from 'components/registration/registration.vue' import PasswordReset from 'components/password_reset/password_reset.vue' -import UserSettings from 'components/user_settings/user_settings.vue' import FollowRequests from 'components/follow_requests/follow_requests.vue' import OAuthCallback from 'components/oauth_callback/oauth_callback.vue' import Notifications from 'components/notifications/notifications.vue' @@ -56,12 +54,10 @@ export default (store) => { { name: 'external-user-profile', path: '/users/:id', component: UserProfile }, { name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute }, { name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute }, - { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, { name: 'password-reset', path: '/password-reset', component: PasswordReset, props: true }, { name: 'registration-token', path: '/registration/:token', component: Registration }, { name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute }, - { name: 'user-settings', path: '/user-settings', component: UserSettings, beforeEnter: validateAuthenticatedRoute }, { name: 'notifications', path: '/:username/notifications', component: Notifications, beforeEnter: validateAuthenticatedRoute }, { name: 'login', path: '/login', component: AuthForm }, { name: 'chat', path: '/chat', component: ChatPanel, props: () => ({ floating: false }) }, diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue index e5ecc0c0..2b58913f 100644 --- a/src/components/modal/modal.vue +++ b/src/components/modal/modal.vue @@ -1,9 +1,9 @@ <template> <div v-show="isOpen" - v-body-scroll-lock="isOpen" + v-body-scroll-lock="isOpen && !noBackground" class="modal-view" - :class="{ 'modal-background': !noBackground }" + :class="classes" @click.self="$emit('backdropClicked')" > <slot /> @@ -21,6 +21,14 @@ export default { type: Boolean, default: false } + }, + computed: { + classes () { + return { + 'modal-background': !this.noBackground, + 'open': this.isOpen + } + } } } </script> @@ -40,6 +48,7 @@ export default { pointer-events: none; animation-duration: 0.2s; animation-name: modal-background-fadein; + opacity: 0; > * { pointer-events: initial; @@ -50,8 +59,8 @@ export default { background-color: rgba(0, 0, 0, 0.5); } - body:not(.scroll-locked) & { - opacity: 0; + &.open { + opacity: 1; } } diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss index 3efbe205..b82590a7 100644 --- a/src/components/settings_modal/settings_modal.scss +++ b/src/components/settings_modal/settings_modal.scss @@ -1,12 +1,21 @@ @import 'src/_variables.scss'; .settings-modal { + overflow: hidden; .settings_tab-switcher { height: 100%; } &.peek { .settings-modal-panel { - transform: translateY(calc(100% - 50px)); + /* Explanation: + * Modal is positioned vertically centered. + * 100vh - 100% = Distance between modal's top+bottom boundaries and screen + * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen + * + 100% - we move modal completely off-screen, it's top boundary touches + * bottom of the screen + * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible + */ + transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px)); } } @@ -25,17 +34,22 @@ .panel-body { height: 100%; overflow-y: hidden; - } - .setting-item { - border-bottom: 2px solid var(--fg, $fallback--fg); - margin: 1em 1em 1.4em; - padding-bottom: 1.4em; .btn { min-height: 28px; min-width: 10em; padding: 0 2em; } + } + + .full-height { + height: 100%; + } + + .setting-item { + border-bottom: 2px solid var(--fg, $fallback--fg); + margin: 1em 1em 1.4em; + padding-bottom: 1.4em; > div { margin-bottom: .5em; diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue index 53481bdd..741c15c4 100644 --- a/src/components/settings_modal/settings_modal.vue +++ b/src/components/settings_modal/settings_modal.vue @@ -1,6 +1,5 @@ <template> <Modal - v-if="isLoggedIn && !resettingForm" :is-open="modalActivated" class="settings-modal" :class="{ peek: modalPeeked }" @@ -25,15 +24,57 @@ :scrollableTabs="true" ref="tabSwitcher" > - <div :label="$t('settings.general')"><GeneralTab /></div> - <div :label="$t('settings.profile_tab')"><ProfileTab /></div> - <div :label="$t('settings.security_tab')"><SecurityTab /></div> - <div :label="$t('settings.filtering')"><FilteringTab /></div> - <div :label="$t('settings.theme')"><ThemeTab /></div> - <div :label="$t('settings.notifications')"><NotificationsTab /></div> - <div :label="$t('settings.data_import_export_tab')"><DataImportExportTab /></div> - <div :label="$t('settings.mutes_and_blocks')"><MutesAndBlocksTab /></div> - <div :label="$t('settings.version.title')"><VersionTab /></div> + <div + :label="$t('settings.general')" + > + <GeneralTab /> + </div> + <div v-if="isLoggedIn" + :label="$t('settings.profile_tab')" + > + <ProfileTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.security_tab')" + > + <SecurityTab /> + </div> + <div + :label="$t('settings.filtering')" + > + <FilteringTab /> + </div> + <div + :label="$t('settings.theme')" + > + <ThemeTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.notifications')" + > + <NotificationsTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.data_import_export_tab')" + > + <DataImportExportTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.mutes_and_blocks')" + :fullHeight="true" + class="full-height" + > + <MutesAndBlocksTab /> + </div> + <div + :label="$t('settings.version.title')" + > + <VersionTab /> + </div> </tab-switcher> </div> </div> diff --git a/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue b/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue index 7fce7b78..04f9c6dd 100644 --- a/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue +++ b/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue @@ -1,173 +1,176 @@ <template> - <tab-switcher> - <div :label="$t('settings.blocks_tab')"> - <div class="profile-edit-usersearch-wrapper"> - <Autosuggest - :filter="filterUnblockedUsers" - :query="queryUserIds" - :placeholder="$t('settings.search_user_to_block')" - > - <BlockCard - slot-scope="row" - :user-id="row.item" - /> - </Autosuggest> - </div> - <BlockList - :refresh="true" - :get-key="i => i" +<tab-switcher + :scrollableTabs="true" + class="mutes-and-blocks-tab" + > + <div :label="$t('settings.blocks_tab')"> + <div class="usersearch-wrapper"> + <Autosuggest + :filter="filterUnblockedUsers" + :query="queryUserIds" + :placeholder="$t('settings.search_user_to_block')" > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => blockUsers(selected)" - > - {{ $t('user_card.block') }} - <template slot="progress"> - {{ $t('user_card.block_progress') }} - </template> - </ProgressButton> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => unblockUsers(selected)" - > - {{ $t('user_card.unblock') }} - <template slot="progress"> - {{ $t('user_card.unblock_progress') }} - </template> - </ProgressButton> - </div> - </template> - <template - slot="item" - slot-scope="{item}" - > - <BlockCard :user-id="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_blocks') }} - </template> - </BlockList> + <BlockCard + slot-scope="row" + :user-id="row.item" + /> + </Autosuggest> </div> - - <div :label="$t('settings.mutes_tab')"> - <tab-switcher> - <div label="Users"> - <div class="profile-edit-usersearch-wrapper"> - <Autosuggest - :filter="filterUnMutedUsers" - :query="queryUserIds" - :placeholder="$t('settings.search_user_to_mute')" - > - <MuteCard - slot-scope="row" - :user-id="row.item" - /> - </Autosuggest> - </div> - <MuteList - :refresh="true" - :get-key="i => i" + <BlockList + :refresh="true" + :get-key="i => i" + > + <template + slot="header" + slot-scope="{selected}" + > + <div class="bulk-actions"> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default bulk-action-button" + :click="() => blockUsers(selected)" > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => muteUsers(selected)" - > - {{ $t('user_card.mute') }} - <template slot="progress"> - {{ $t('user_card.mute_progress') }} - </template> - </ProgressButton> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => unmuteUsers(selected)" - > - {{ $t('user_card.unmute') }} - <template slot="progress"> - {{ $t('user_card.unmute_progress') }} - </template> - </ProgressButton> - </div> + {{ $t('user_card.block') }} + <template slot="progress"> + {{ $t('user_card.block_progress') }} </template> - <template - slot="item" - slot-scope="{item}" - > - <MuteCard :user-id="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_mutes') }} - </template> - </MuteList> - </div> - - <div :label="$t('settings.domain_mutes')"> - <div class="profile-edit-domain-mute-form"> - <input - v-model="newDomainToMute" - :placeholder="$t('settings.type_domains_to_mute')" - type="text" - @keyup.enter="muteDomain" - > - <ProgressButton - class="btn btn-default" - :click="muteDomain" - > - {{ $t('domain_mute_card.mute') }} - <template slot="progress"> - {{ $t('domain_mute_card.mute_progress') }} - </template> - </ProgressButton> - </div> - <DomainMuteList - :refresh="true" - :get-key="i => i" + </ProgressButton> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => unblockUsers(selected)" > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => unmuteDomains(selected)" - > - {{ $t('domain_mute_card.unmute') }} - <template slot="progress"> - {{ $t('domain_mute_card.unmute_progress') }} - </template> - </ProgressButton> - </div> + {{ $t('user_card.unblock') }} + <template slot="progress"> + {{ $t('user_card.unblock_progress') }} </template> - <template - slot="item" - slot-scope="{item}" - > - <DomainMuteCard :domain="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_mutes') }} - </template> - </DomainMuteList> + </ProgressButton> </div> - </tab-switcher> - </div> - </tab-switcher> + </template> + <template + slot="item" + slot-scope="{item}" + > + <BlockCard :user-id="item" /> + </template> + <template slot="empty"> + {{ $t('settings.no_blocks') }} + </template> + </BlockList> + </div> + + <div :label="$t('settings.mutes_tab')"> + <tab-switcher> + <div label="Users"> + <div class="usersearch-wrapper"> + <Autosuggest + :filter="filterUnMutedUsers" + :query="queryUserIds" + :placeholder="$t('settings.search_user_to_mute')" + > + <MuteCard + slot-scope="row" + :user-id="row.item" + /> + </Autosuggest> + </div> + <MuteList + :refresh="true" + :get-key="i => i" + > + <template + slot="header" + slot-scope="{selected}" + > + <div class="bulk-actions"> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => muteUsers(selected)" + > + {{ $t('user_card.mute') }} + <template slot="progress"> + {{ $t('user_card.mute_progress') }} + </template> + </ProgressButton> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => unmuteUsers(selected)" + > + {{ $t('user_card.unmute') }} + <template slot="progress"> + {{ $t('user_card.unmute_progress') }} + </template> + </ProgressButton> + </div> + </template> + <template + slot="item" + slot-scope="{item}" + > + <MuteCard :user-id="item" /> + </template> + <template slot="empty"> + {{ $t('settings.no_mutes') }} + </template> + </MuteList> + </div> + + <div :label="$t('settings.domain_mutes')"> + <div class="domain-mute-form"> + <input + v-model="newDomainToMute" + :placeholder="$t('settings.type_domains_to_mute')" + type="text" + @keyup.enter="muteDomain" + > + <ProgressButton + class="btn btn-default domain-mute-button" + :click="muteDomain" + > + {{ $t('domain_mute_card.mute') }} + <template slot="progress"> + {{ $t('domain_mute_card.mute_progress') }} + </template> + </ProgressButton> + </div> + <DomainMuteList + :refresh="true" + :get-key="i => i" + > + <template + slot="header" + slot-scope="{selected}" + > + <div class="bulk-actions"> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => unmuteDomains(selected)" + > + {{ $t('domain_mute_card.unmute') }} + <template slot="progress"> + {{ $t('domain_mute_card.unmute_progress') }} + </template> + </ProgressButton> + </div> + </template> + <template + slot="item" + slot-scope="{item}" + > + <DomainMuteCard :domain="item" /> + </template> + <template slot="empty"> + {{ $t('settings.no_mutes') }} + </template> + </DomainMuteList> + </div> + </tab-switcher> + </div> +</tab-switcher> </template> <script src="./mutes_and_blocks_tab.js"></script> -<!-- <style lang="scss" src="./profile.scss"></style> --> +<style lang="scss" src="./mutes_and_blocks_tab.scss"></style> 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 75b3017d..e0b1a2df 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss @@ -1,5 +1,6 @@ @import 'src/_variables.scss'; .theme-tab { + padding-bottom: 2em; .theme-warning { display: flex; align-items: baseline; diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js index 97791de3..a54b474f 100644 --- a/src/components/tab_switcher/tab_switcher.js +++ b/src/components/tab_switcher/tab_switcher.js @@ -69,7 +69,6 @@ export default Vue.component('tab-switcher', { if (!slot.tag) return const classesTab = ['tab'] const classesWrapper = ['tab-wrapper'] - if (this.activeIndex === index) { classesTab.push('active') classesWrapper.push('active') @@ -101,12 +100,17 @@ export default Vue.component('tab-switcher', { const contents = this.$slots.default.map((slot, index) => { if (!slot.tag) return const active = this.activeIndex === index + const classes = [ active ? 'active' : 'hidden' ] + if (slot.data.attrs.fullHeight) { + classes.push('full-height') + } + if (this.renderOnlyFocused) { return active - ? <div class="active">{slot}</div> - : <div class="hidden"></div> + ? <div class={classes.join(' ')}>{slot}</div> + : <div class={classes.join(' ')}></div> } - return <div class={active ? 'active' : 'hidden' }>{slot}</div> + return <div class={classes.join(' ')}>{slot}</div> }) return ( diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss index a7b790a3..c9050781 100644 --- a/src/components/tab_switcher/tab_switcher.scss +++ b/src/components/tab_switcher/tab_switcher.scss @@ -59,7 +59,6 @@ flex: 1 0 auto; overflow-y: auto; overflow-x: hidden; - padding-top: 5px; flex-direction: column; &::after { content: ''; @@ -78,6 +77,9 @@ border-right-color: $fallback--border; border-right-color: var(--border, $fallback--border); } + &:last-child .tab { + margin-bottom: 0; + } } .tab { box-sizing: content-box; @@ -87,8 +89,8 @@ min-width: 1px; border-top-right-radius: 0; border-bottom-right-radius: 0; - // padding-right: 200px; - // margin-right: 6px - 200px; + padding-right: calc(1em + 200px); + margin-right: 6px - 200px; margin-left: 6px; }