logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: 6df99133548fb209bf365b77665931be477f0a30
parent 732733f115a863408a339e164ff88f1022c46101
Author: Henry Jameson <me@hjkos.com>
Date:   Thu, 11 Aug 2022 14:30:58 +0300

ability to pin items in navigation menu, initial draft version

Diffstat:

Msrc/App.scss3+++
Msrc/components/nav_panel/nav_panel.js111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/components/nav_panel/nav_panel.vue140++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/components/settings_modal/tabs/general_tab.vue5-----
Msrc/components/timeline_menu/timeline_menu.vue2+-
Msrc/components/timeline_menu/timeline_menu_content.js27+++++++++++++++++++++++++--
Msrc/components/timeline_menu/timeline_menu_content.vue69+++++++++++++++++----------------------------------------------------
Msrc/modules/config.js1-
Msrc/modules/serverSideStorage.js9++++++---
9 files changed, 221 insertions(+), 146 deletions(-)

diff --git a/src/App.scss b/src/App.scss @@ -756,6 +756,9 @@ option { padding: 0 0.3em; } } +.veryfaint { + opacity: 0.25; +} .login-hint { text-align: center; diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js @@ -31,6 +31,66 @@ library.add( faList ) +export const TIMELINES = { + home: { + route: 'friends', + anonRoute: 'public-timeline', + icon: 'home', + label: 'nav.home_timeline', + criteria: ['!private'] + }, + public: { + route: 'public-timeline', + anon: true, + icon: 'users', + label: 'nav.public_tl', + criteria: ['!private'] + }, + twkn: { + route: 'public-external-timeline', + anon: true, + icon: 'globe', + label: 'nav.twkn', + criteria: ['!private', 'federating'] + }, + bookmarks: { + route: 'bookmarks', + icon: 'bookmark', + label: 'nav.bookmarks' + }, + dms: { + route: 'dms', + icon: 'envelope', + label: 'nav.dms' + } +} +export const ROOT_ITEMS = { + interactions: { + route: 'interactions', + icon: 'bell', + label: 'nav.interactions' + }, + chats: { + route: 'chats', + icon: 'comments', + label: 'nav.chats', + badgeGetter: 'unreadChatCount' + }, + friendRequests: { + route: 'friend-requests', + icon: 'user-plus', + label: 'nav.friend_requests', + criteria: ['lockedUser'], + badgeGetter: 'followRequestCount' + }, + about: { + route: 'about', + anon: true, + icon: 'info-circle', + label: 'nav.about' + } +} + const NavPanel = { created () { if (this.currentUser && this.currentUser.locked) { @@ -43,8 +103,11 @@ const NavPanel = { }, data () { return { + collapsed: false, showTimelines: false, - showLists: false + showLists: false, + timelinesList: Object.entries(TIMELINES).map(([k, v]) => ({ ...v, name: k })), + rootList: Object.entries(ROOT_ITEMS).map(([k, v]) => ({ ...v, name: k })) } }, methods: { @@ -53,19 +116,57 @@ const NavPanel = { }, toggleLists () { this.showLists = !this.showLists + }, + toggleCollapse () { + this.collapsed = !this.collapsed + }, + isPinned (item) { + return this.pinnedItems.has(item) + }, + togglePin (item) { + if (this.isPinned(item)) { + this.$store.commit('removeCollectionPreference', { path: 'collections.pinnedNavItems', value: item }) + } else { + this.$store.commit('addCollectionPreference', { path: 'collections.pinnedNavItems', value: item }) + } } }, computed: { - listsNavigation () { - return this.$store.getters.mergedConfig.listsNavigation - }, ...mapState({ currentUser: state => state.users.currentUser, followRequestCount: state => state.api.followRequests.length, privateMode: state => state.instance.private, federating: state => state.instance.federating, - pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable + pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable, + pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedNavItems) }), + rootItems () { + return Object + .entries({ ...ROOT_ITEMS }) + .map(([k, v]) => ({ ...v, name: k })) + .filter(({ criteria, anon, anonRoute }) => { + const set = new Set(criteria || []) + if (!this.federating && set.has('federating')) return false + if (this.private && set.has('!private')) return false + if (!this.currentUser && !(anon || anonRoute)) return false + if ((!this.currentUser || !this.currentUser.locked) && set.has('lockedUser')) return false + return true + }) + }, + pinnedList () { + return Object + .entries({ ...TIMELINES, ...ROOT_ITEMS }) + .filter(([k]) => this.pinnedItems.has(k)) + .map(([k, v]) => ({ ...v, name: k })) + .filter(({ criteria, anon, anonRoute }) => { + const set = new Set(criteria || []) + if (!this.federating && set.has('federating')) return false + if (this.private && set.has('!private')) return false + if (!this.currentUser && !(anon || anonRoute)) return false + if (this.currentUser && !this.currentUser.locked && set.has('locked')) return false + return true + }) + }, ...mapGetters(['unreadChatCount']) } } diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue @@ -1,7 +1,33 @@ <template> <div class="NavPanel"> <div class="panel panel-default"> - <ul> + <div class="panel-heading"> + <span> + <span v-for="item in pinnedList" :key="item.name" class="pinned-item"> + <router-link + :to="{ name: (currentUser || item.anon) ? item.route : item.anonRoute, params: { username: currentUser.screen_name } }" + > + <FAIcon + fixed-width + class="fa-scale-110 fa-old-padding " + :icon="item.icon" + /> + </router-link> + </span> + </span> + <div class="spacer"/> + <button + class="button-unstyled" + @click="toggleCollapse" + > + <FAIcon + class="timelines-chevron" + fixed-width + :icon="collapsed ? 'chevron-down' : 'chevron-up'" + /> + </button> + </div> + <ul class="panel-body" v-if="!collapsed"> <li v-if="currentUser || !privateMode"> <button class="button-unstyled menu-item" @@ -22,29 +48,34 @@ v-show="showTimelines" class="timelines-background" > - <TimelineMenuContent class="timelines" /> + <TimelineMenuContent class="timelines" :content="timelinesList" /> </div> </li> - <li v-if="currentUser && listsNavigation"> + <li v-if="currentUser"> <button class="button-unstyled menu-item" @click="toggleLists" > - <router-link - :to="{ name: 'lists' }" - @click.stop - > <FAIcon fixed-width class="fa-scale-110" icon="list" />{{ $t("nav.lists") }} - </router-link> <FAIcon class="timelines-chevron" fixed-width :icon="showLists ? 'chevron-up' : 'chevron-down'" /> + <router-link + :to="{ name: 'lists' }" + @click.stop + > + <FAIcon + class="timelines-chevron" + fixed-width + icon="wrench" + /> + </router-link> </button> <div v-show="showLists" @@ -53,83 +84,31 @@ <ListsMenuContent class="timelines" /> </div> </li> - <li v-if="currentUser && !listsNavigation"> + <li v-for="item in rootItems" :key="item.name"> <router-link - :to="{ name: 'lists' }" - @click.stop + class="menu-item" + :to="{ name: (currentUser || item.anon) ? item.route : item.anonRoute, params: { username: currentUser.screen_name } }" > + <FAIcon + fixed-width + class="fa-scale-110 fa-old-padding " + :icon="item.icon" + />{{ $t(item.label) }} <button - class="button-unstyled menu-item" - @click="toggleLists" - > + type="button" + class="button-unstyled" + @click.stop.prevent="togglePin(item.name)" + > <FAIcon fixed-width - class="fa-scale-110" - icon="list" - />{{ $t("nav.lists") }} + class="fa-scale-110 fa-old-padding " + :class="{ 'veryfaint': !isPinned(item.name) }" + :transform="!isPinned(item.name) ? 'rotate-45' : ''" + icon="thumbtack" + /> </button> </router-link> </li> - <li v-if="currentUser"> - <router-link - class="menu-item" - :to="{ name: 'interactions', params: { username: currentUser.screen_name } }" - > - <FAIcon - fixed-width - class="fa-scale-110" - icon="bell" - />{{ $t("nav.interactions") }} - </router-link> - </li> - <li v-if="currentUser && pleromaChatMessagesAvailable"> - <router-link - class="menu-item" - :to="{ name: 'chats', params: { username: currentUser.screen_name } }" - > - <div - v-if="unreadChatCount" - class="badge badge-notification" - > - {{ unreadChatCount }} - </div> - <FAIcon - fixed-width - class="fa-scale-110" - icon="comments" - />{{ $t("nav.chats") }} - </router-link> - </li> - <li v-if="currentUser && currentUser.locked"> - <router-link - class="menu-item" - :to="{ name: 'friend-requests' }" - > - <FAIcon - fixed-width - class="fa-scale-110" - icon="user-plus" - />{{ $t("nav.friend_requests") }} - <span - v-if="followRequestCount > 0" - class="badge badge-notification" - > - {{ followRequestCount }} - </span> - </router-link> - </li> - <li> - <router-link - class="menu-item" - :to="{ name: 'about' }" - > - <FAIcon - fixed-width - class="fa-scale-110" - icon="info-circle" - />{{ $t("nav.about") }} - </router-link> - </li> </ul> </div> </div> @@ -246,5 +225,12 @@ right: 0.6rem; top: 1.25em; } + + .pinned-item { + .router-link-exact-active .svg-inline--fa { + color: $fallback--text; + color: var(--selectedMenuText, $fallback--text); + } + } } </style> diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue @@ -125,11 +125,6 @@ </BooleanSetting> </li> <li> - <BooleanSetting path="listsNavigation"> - {{ $t('settings.lists_navigation') }} - </BooleanSetting> - </li> - <li> <h3>{{ $t('settings.columns') }}</h3> </li> <li> diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue @@ -10,7 +10,7 @@ @close="() => isOpen = false" > <template #content> - <TimelineMenuContent /> + <TimelineMenuContent :content="timelinesList" /> </template> <template #trigger> <span class="button-unstyled title timeline-menu-title"> diff --git a/src/components/timeline_menu/timeline_menu_content.js b/src/components/timeline_menu/timeline_menu_content.js @@ -17,12 +17,35 @@ library.add( ) const TimelineMenuContent = { + props: ['content'], + methods: { + isPinned (item) { + return this.pinnedItems.has(item) + }, + togglePin (item) { + if (this.isPinned(item)) { + this.$store.commit('removeCollectionPreference', { path: 'collections.pinnedNavItems', value: item }) + } else { + this.$store.commit('addCollectionPreference', { path: 'collections.pinnedNavItems', value: item }) + } + } + }, computed: { ...mapState({ currentUser: state => state.users.currentUser, privateMode: state => state.instance.private, - federating: state => state.instance.federating - }) + federating: state => state.instance.federating, + pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedNavItems) + }), + list () { + return (this.content || []).filter(({ criteria, anon, anonRoute }) => { + const set = new Set(criteria || []) + if (!this.federating && set.has('federating')) return false + if (this.private && set.has('!private')) return false + if (!this.currentUser && !(anon || anonRoute)) return false + return true + }) + } } } diff --git a/src/components/timeline_menu/timeline_menu_content.vue b/src/components/timeline_menu/timeline_menu_content.vue @@ -1,63 +1,28 @@ <template> <ul> - <li v-if="currentUser"> + <li v-for="item in list" :key="item.name"> <router-link class="menu-item" - :to="{ name: 'friends' }" + :to="{ name: (currentUser || item.anon) ? item.route : item.anonRoute, params: { username: currentUser.screen_name } }" > <FAIcon fixed-width class="fa-scale-110 fa-old-padding " - icon="home" - />{{ $t("nav.home_timeline") }} - </router-link> - </li> - <li v-if="currentUser || !privateMode"> - <router-link - class="menu-item" - :to="{ name: 'public-timeline' }" - > - <FAIcon - fixed-width - class="fa-scale-110 fa-old-padding " - icon="users" - />{{ $t("nav.public_tl") }} - </router-link> - </li> - <li v-if="federating && (currentUser || !privateMode)"> - <router-link - class="menu-item" - :to="{ name: 'public-external-timeline' }" - > - <FAIcon - fixed-width - class="fa-scale-110 fa-old-padding " - icon="globe" - />{{ $t("nav.twkn") }} - </router-link> - </li> - <li v-if="currentUser"> - <router-link - class="menu-item" - :to="{ name: 'bookmarks'}" - > - <FAIcon - fixed-width - class="fa-scale-110 fa-old-padding " - icon="bookmark" - />{{ $t("nav.bookmarks") }} - </router-link> - </li> - <li v-if="currentUser"> - <router-link - class="menu-item" - :to="{ name: 'dms', params: { username: currentUser.screen_name } }" - > - <FAIcon - fixed-width - class="fa-scale-110 fa-old-padding " - icon="envelope" - />{{ $t("nav.dms") }} + :icon="item.icon" + />{{ $t(item.label) }} + <button + type="button" + class="button-unstyled" + @click.stop.prevent="togglePin(item.name)" + > + <FAIcon + fixed-width + class="fa-scale-110 fa-old-padding " + :class="{ 'veryfaint': !isPinned(item.name) }" + :transform="!isPinned(item.name) ? 'rotate-45' : ''" + icon="thumbtack" + /> + </button> </router-link> </li> </ul> diff --git a/src/modules/config.js b/src/modules/config.js @@ -87,7 +87,6 @@ export const defaultState = { sidebarColumnWidth: '25rem', contentColumnWidth: '45rem', notifsColumnWidth: '25rem', - listsNavigation: false, greentext: undefined, // instance default useAtIcon: undefined, // instance default mentionLinkDisplay: undefined, // instance default diff --git a/src/modules/serverSideStorage.js b/src/modules/serverSideStorage.js @@ -23,6 +23,9 @@ export const defaultState = { _journal: [], simple: { dontShowUpdateNotifs: false + }, + collections: { + pinnedNavItems: ['home', 'dms', 'chats', 'about'] } }, // raw data @@ -274,8 +277,8 @@ export const mutations = { totalFlags = _resetFlags(totalFlags) - recent.flagStorage = totalFlags - recent.prefsStorage = totalPrefs + recent.flagStorage = { ...flagsTemplate, ...totalFlags } + recent.prefsStorage = { ...defaultState.prefsStorage, ...totalPrefs } state.dirty = dirty || needsUpload state.cache = recent @@ -320,7 +323,7 @@ export const mutations = { return } const collection = new Set(get(state.prefsStorage, path)) - collection.remove(value) + collection.delete(value) set(state.prefsStorage, path, collection) state.prefsStorage._journal = [ ...state.prefsStorage._journal,