parent
							
								
									b77788b947
								
							
						
					
					
						commit
						4a08d5295e
					
				
					 7 changed files with 283 additions and 93 deletions
				
			
		|  | @ -498,6 +498,9 @@ removeAllFollowing: "フォローを全解除" | ||||||
| removeAllFollowingDescription: "{host}からのフォローをすべて解除します。そのインスタンスがもう存在しなくなった場合などに実行してください。" | removeAllFollowingDescription: "{host}からのフォローをすべて解除します。そのインスタンスがもう存在しなくなった場合などに実行してください。" | ||||||
| userSuspended: "このユーザーは凍結されています。" | userSuspended: "このユーザーは凍結されています。" | ||||||
| userSilenced: "このユーザーはサイレンスされています。" | userSilenced: "このユーザーはサイレンスされています。" | ||||||
|  | sidebar: "サイドバー" | ||||||
|  | divider: "分割線" | ||||||
|  | addItem: "項目を追加" | ||||||
| 
 | 
 | ||||||
| _theme: | _theme: | ||||||
|   explore: "テーマを探す" |   explore: "テーマを探す" | ||||||
|  |  | ||||||
							
								
								
									
										109
									
								
								src/client/app.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/client/app.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | ||||||
|  | import { faTerminal, faHashtag, faBroadcastTower, faFireAlt, faSearch, faStar, faAt, faListUl, faUserClock, faUsers, faCloud, faGamepad, faFileAlt, faSatellite } from '@fortawesome/free-solid-svg-icons'; | ||||||
|  | import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  | 
 | ||||||
|  | export function createMenuDef(actions) { | ||||||
|  | 	return { | ||||||
|  | 		notifications: { | ||||||
|  | 			title: 'notifications', | ||||||
|  | 			icon: faBell, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadNotification, | ||||||
|  | 			to: '/my/notifications', | ||||||
|  | 		}, | ||||||
|  | 		messaging: { | ||||||
|  | 			title: 'messaging', | ||||||
|  | 			icon: faComments, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadMessagingMessage, | ||||||
|  | 			to: '/my/messaging', | ||||||
|  | 		}, | ||||||
|  | 		drive: { | ||||||
|  | 			title: 'drive', | ||||||
|  | 			icon: faCloud, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/drive', | ||||||
|  | 		}, | ||||||
|  | 		followRequests: { | ||||||
|  | 			title: 'followRequests', | ||||||
|  | 			icon: faUserClock, | ||||||
|  | 			show: store => store.getters.isSignedIn && store.state.i.isLocked, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasPendingReceivedFollowRequest, | ||||||
|  | 			to: '/my/follow-requests', | ||||||
|  | 		}, | ||||||
|  | 		featured: { | ||||||
|  | 			title: 'featured', | ||||||
|  | 			icon: faFireAlt, | ||||||
|  | 			to: '/featured', | ||||||
|  | 		}, | ||||||
|  | 		explore: { | ||||||
|  | 			title: 'explore', | ||||||
|  | 			icon: faHashtag, | ||||||
|  | 			to: '/explore', | ||||||
|  | 		}, | ||||||
|  | 		announcements: { | ||||||
|  | 			title: 'announcements', | ||||||
|  | 			icon: faBroadcastTower, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadAnnouncement, | ||||||
|  | 			to: '/announcements', | ||||||
|  | 		}, | ||||||
|  | 		search: { | ||||||
|  | 			title: 'search', | ||||||
|  | 			icon: faSearch, | ||||||
|  | 			action: () => actions.search(), | ||||||
|  | 		}, | ||||||
|  | 		lists: { | ||||||
|  | 			title: 'lists', | ||||||
|  | 			icon: faListUl, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/lists', | ||||||
|  | 		}, | ||||||
|  | 		groups: { | ||||||
|  | 			title: 'groups', | ||||||
|  | 			icon: faUsers, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/groups', | ||||||
|  | 		}, | ||||||
|  | 		antennas: { | ||||||
|  | 			title: 'antennas', | ||||||
|  | 			icon: faSatellite, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/antennas', | ||||||
|  | 		}, | ||||||
|  | 		mentions: { | ||||||
|  | 			title: 'mentions', | ||||||
|  | 			icon: faAt, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadMentions, | ||||||
|  | 			to: '/my/mentions', | ||||||
|  | 		}, | ||||||
|  | 		messages: { | ||||||
|  | 			title: 'directNotes', | ||||||
|  | 			icon: faEnvelope, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadSpecifiedNotes, | ||||||
|  | 			to: '/my/messages', | ||||||
|  | 		}, | ||||||
|  | 		favorites: { | ||||||
|  | 			title: 'favorites', | ||||||
|  | 			icon: faStar, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/favorites', | ||||||
|  | 		}, | ||||||
|  | 		pages: { | ||||||
|  | 			title: 'pages', | ||||||
|  | 			icon: faFileAlt, | ||||||
|  | 			show: store => store.getters.isSignedIn, | ||||||
|  | 			to: '/my/pages', | ||||||
|  | 		}, | ||||||
|  | 		games: { | ||||||
|  | 			title: 'games', | ||||||
|  | 			icon: faGamepad, | ||||||
|  | 			to: '/games', | ||||||
|  | 		}, | ||||||
|  | 		scratchpad: { | ||||||
|  | 			title: 'scratchpad', | ||||||
|  | 			icon: faTerminal, | ||||||
|  | 			to: '/scratchpad', | ||||||
|  | 		}, | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  | @ -49,44 +49,20 @@ | ||||||
| 				<router-link class="item index" active-class="active" to="/" exact v-else> | 				<router-link class="item index" active-class="active" to="/" exact v-else> | ||||||
| 					<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> | 					<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> | ||||||
| 				</router-link> | 				</router-link> | ||||||
| 				<template v-if="$store.getters.isSignedIn"> | 				<template v-for="item in menu"> | ||||||
| 					<router-link class="item notifications" active-class="active" to="/my/notifications" ref="notificationButton"> | 					<div v-if="item === '-'" class="divider"></div> | ||||||
| 						<fa :icon="faBell" fixed-width/><span class="text">{{ $t('notifications') }}</span> | 					<component v-else-if="menuDef[item].display !== false" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to"> | ||||||
| 						<i v-if="$store.state.i.hasUnreadNotification"><fa :icon="faCircle"/></i> | 						<fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span> | ||||||
| 					</router-link> | 						<i v-if="menuDef[item].indicated"><fa :icon="faCircle"/></i> | ||||||
| 					<router-link class="item" active-class="active" to="/my/messaging"> | 					</component> | ||||||
| 						<fa :icon="faComments" fixed-width/><span class="text">{{ $t('messaging') }}</span> |  | ||||||
| 						<i v-if="$store.state.i.hasUnreadMessagingMessage"><fa :icon="faCircle"/></i> |  | ||||||
| 					</router-link> |  | ||||||
| 					<router-link class="item" active-class="active" to="/my/drive"> |  | ||||||
| 						<fa :icon="faCloud" fixed-width/><span class="text">{{ $t('drive') }}</span> |  | ||||||
| 					</router-link> |  | ||||||
| 					<router-link class="item" active-class="active" to="/my/follow-requests" v-if="$store.state.i.isLocked"> |  | ||||||
| 						<fa :icon="faUserClock" fixed-width/><span class="text">{{ $t('followRequests') }}</span> |  | ||||||
| 						<i v-if="$store.state.i.hasPendingReceivedFollowRequest"><fa :icon="faCircle"/></i> |  | ||||||
| 					</router-link> |  | ||||||
| 				</template> | 				</template> | ||||||
| 				<div class="divider"></div> | 				<div class="divider"></div> | ||||||
| 				<router-link class="item" active-class="active" to="/featured"> |  | ||||||
| 					<fa :icon="faFireAlt" fixed-width/><span class="text">{{ $t('featured') }}</span> |  | ||||||
| 				</router-link> |  | ||||||
| 				<router-link class="item" active-class="active" to="/explore"> |  | ||||||
| 					<fa :icon="faHashtag" fixed-width/><span class="text">{{ $t('explore') }}</span> |  | ||||||
| 				</router-link> |  | ||||||
| 				<router-link class="item" active-class="active" to="/announcements"> |  | ||||||
| 					<fa :icon="faBroadcastTower" fixed-width/><span class="text">{{ $t('announcements') }}</span> |  | ||||||
| 					<i v-if="$store.getters.isSignedIn && $store.state.i.hasUnreadAnnouncement"><fa :icon="faCircle"/></i> |  | ||||||
| 				</router-link> |  | ||||||
| 				<button class="item _button" @click="search()"> |  | ||||||
| 					<fa :icon="faSearch" fixed-width/><span class="text">{{ $t('search') }}</span> |  | ||||||
| 				</button> |  | ||||||
| 				<div class="divider"></div> |  | ||||||
| 				<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu"> | 				<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu"> | ||||||
| 					<fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span> | 					<fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span> | ||||||
| 				</button> | 				</button> | ||||||
| 				<button class="item _button" @click="more"> | 				<button class="item _button" @click="more"> | ||||||
| 					<fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span> | 					<fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span> | ||||||
| 					<i v-if="$store.getters.isSignedIn && ($store.state.i.hasUnreadMentions || $store.state.i.hasUnreadSpecifiedNotes)"><fa :icon="faCircle"/></i> | 					<i v-if="otherNavItemIndicated"><fa :icon="faCircle"/></i> | ||||||
| 				</button> | 				</button> | ||||||
| 				<router-link class="item" active-class="active" to="/preferences"> | 				<router-link class="item" active-class="active" to="/preferences"> | ||||||
| 					<fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span> | 					<fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span> | ||||||
|  | @ -141,10 +117,10 @@ | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
| 	<div class="buttons"> | 	<div class="buttons"> | ||||||
| 		<button class="button nav _button" @click="showNav = true" ref="navButton"><fa :icon="faBars"/><i v-if="$store.getters.isSignedIn && ($store.state.i.hasUnreadSpecifiedNotes || $store.state.i.hasPendingReceivedFollowRequest || $store.state.i.hasUnreadMessagingMessage || $store.state.i.hasUnreadAnnouncement)"><fa :icon="faCircle"/></i></button> | 		<button class="button nav _button" @click="showNav = true" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button> | ||||||
| 		<button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button> | 		<button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button> | ||||||
| 		<button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button> | 		<button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button> | ||||||
| 		<button v-if="$store.getters.isSignedIn" class="button notifications _button" @click="$router.push('/my/notifications')" ref="notificationButton2"><fa :icon="faBell"/><i v-if="$store.state.i.hasUnreadNotification"><fa :icon="faCircle"/></i></button> | 		<button v-if="$store.getters.isSignedIn" class="button notifications _button" @click="$router.push('/my/notifications')"><fa :icon="faBell"/><i v-if="$store.state.i.hasUnreadNotification"><fa :icon="faCircle"/></i></button> | ||||||
| 		<button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button> | 		<button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button> | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
|  | @ -156,13 +132,14 @@ | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import { faTerminal, faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faGamepad, faServer, faFileAlt, faSatellite, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; | import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; | ||||||
| import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons'; | import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons'; | ||||||
| import { ResizeObserver } from '@juggle/resize-observer'; | import { ResizeObserver } from '@juggle/resize-observer'; | ||||||
| import { v4 as uuid } from 'uuid'; | import { v4 as uuid } from 'uuid'; | ||||||
| import i18n from './i18n'; | import i18n from './i18n'; | ||||||
| import { host, instanceName } from './config'; | import { host, instanceName } from './config'; | ||||||
| import { search } from './scripts/search'; | import { search } from './scripts/search'; | ||||||
|  | import { createMenuDef } from './app'; | ||||||
| 
 | 
 | ||||||
| const DESKTOP_THRESHOLD = 1100; | const DESKTOP_THRESHOLD = 1100; | ||||||
| 
 | 
 | ||||||
|  | @ -187,6 +164,9 @@ export default Vue.extend({ | ||||||
| 			searchQuery: '', | 			searchQuery: '', | ||||||
| 			searchWait: false, | 			searchWait: false, | ||||||
| 			widgetsEditMode: false, | 			widgetsEditMode: false, | ||||||
|  | 			menuDef: createMenuDef({ | ||||||
|  | 				search: this.search | ||||||
|  | 			}), | ||||||
| 			isDesktop: window.innerWidth >= DESKTOP_THRESHOLD, | 			isDesktop: window.innerWidth >= DESKTOP_THRESHOLD, | ||||||
| 			canBack: false, | 			canBack: false, | ||||||
| 			wallpaper: localStorage.getItem('wallpaper') != null, | 			wallpaper: localStorage.getItem('wallpaper') != null, | ||||||
|  | @ -206,6 +186,29 @@ export default Vue.extend({ | ||||||
| 
 | 
 | ||||||
| 		widgets(): any[] { | 		widgets(): any[] { | ||||||
| 			return this.$store.state.deviceUser.widgets; | 			return this.$store.state.deviceUser.widgets; | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		menu(): string[] { | ||||||
|  | 			return this.$store.state.deviceUser.menu; | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		otherNavItemIndicated(): boolean { | ||||||
|  | 			if (!this.$store.getters.isSignedIn) return false; | ||||||
|  | 			for (const def in this.menuDef) { | ||||||
|  | 				if (this.menu.includes(def)) continue; | ||||||
|  | 				if (this.menuDef[def].indicated) return true; | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		navIndicated(): boolean { | ||||||
|  | 			if (!this.$store.getters.isSignedIn) return false; | ||||||
|  | 			for (const def in this.menuDef) { | ||||||
|  | 				if (def === 'timeline') continue; | ||||||
|  | 				if (def === 'notifications') continue; | ||||||
|  | 				if (this.menuDef[def].indicated) return true; | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | @ -238,6 +241,23 @@ export default Vue.extend({ | ||||||
| 					id: 'c', data: {} | 					id: 'c', data: {} | ||||||
| 				}]); | 				}]); | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			this.$store.watch(state => state.i, i => { | ||||||
|  | 				for (const def in this.menuDef) { | ||||||
|  | 					if (this.menuDef[def].indicate) { | ||||||
|  | 						Vue.set(this.menuDef[def], 'indicated', this.menuDef[def].indicate(this.$store)); | ||||||
|  | 					} | ||||||
|  | 					if (this.menuDef[def].show) { | ||||||
|  | 						Vue.set(this.menuDef[def], 'display', this.menuDef[def].show(this.$store)); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}, { immediate: true, deep: true }); | ||||||
|  | 		} else { | ||||||
|  | 			for (const def in this.menuDef) { | ||||||
|  | 				if (this.menuDef[def].show) { | ||||||
|  | 					Vue.set(this.menuDef[def], 'display', this.menuDef[def].show(this.$store)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | @ -425,55 +445,16 @@ export default Vue.extend({ | ||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| 		more(ev) { | 		more(ev) { | ||||||
|  | 			const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show ? def.show(this.$store) : true).map(def => ({ | ||||||
|  | 				type: def.to ? 'link' : 'button', | ||||||
|  | 				text: this.$t(def.title), | ||||||
|  | 				icon: def.icon, | ||||||
|  | 				to: def.to, | ||||||
|  | 				action: def.action, | ||||||
|  | 				indicate: def.indicate ? def.indicate(this.$store) : false, | ||||||
|  | 			})); | ||||||
| 			this.$root.menu({ | 			this.$root.menu({ | ||||||
| 				items: [...(this.$store.getters.isSignedIn ? [{ | 				items: [...items, null, { | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('lists'), |  | ||||||
| 					to: '/my/lists', |  | ||||||
| 					icon: faListUl, |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('groups'), |  | ||||||
| 					to: '/my/groups', |  | ||||||
| 					icon: faUsers, |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('antennas'), |  | ||||||
| 					to: '/my/antennas', |  | ||||||
| 					icon: faSatellite, |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('mentions'), |  | ||||||
| 					to: '/my/mentions', |  | ||||||
| 					icon: faAt, |  | ||||||
| 					indicate: this.$store.state.i.hasUnreadMentions |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('directNotes'), |  | ||||||
| 					to: '/my/messages', |  | ||||||
| 					icon: faEnvelope, |  | ||||||
| 					indicate: this.$store.state.i.hasUnreadSpecifiedNotes |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('favorites'), |  | ||||||
| 					to: '/my/favorites', |  | ||||||
| 					icon: faStar, |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('pages'), |  | ||||||
| 					to: '/my/pages', |  | ||||||
| 					icon: faFileAlt, |  | ||||||
| 				}, { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('games'), |  | ||||||
| 					to: '/games', |  | ||||||
| 					icon: faGamepad, |  | ||||||
| 				}, null] : []), { |  | ||||||
| 					type: 'link', |  | ||||||
| 					text: this.$t('scratchpad'), |  | ||||||
| 					to: '/scratchpad', |  | ||||||
| 					icon: faTerminal, |  | ||||||
| 				}, null, { |  | ||||||
| 					type: 'link', | 					type: 'link', | ||||||
| 					text: this.$t('help'), | 					text: this.$t('help'), | ||||||
| 					to: '/docs', | 					to: '/docs', | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ | ||||||
| 
 | 
 | ||||||
| 	<x-theme/> | 	<x-theme/> | ||||||
| 
 | 
 | ||||||
|  | 	<x-sidebar/> | ||||||
|  | 
 | ||||||
| 	<section class="_card"> | 	<section class="_card"> | ||||||
| 		<div class="_title"><fa :icon="faMusic"/> {{ $t('sounds') }}</div> | 		<div class="_title"><fa :icon="faMusic"/> {{ $t('sounds') }}</div> | ||||||
| 		<div class="_content"> | 		<div class="_content"> | ||||||
|  | @ -90,13 +92,13 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import { faImage, faCog, faMusic, faPlay, faVolumeUp, faVolumeMute } from '@fortawesome/free-solid-svg-icons'; | import { faImage, faCog, faMusic, faPlay, faVolumeUp, faVolumeMute } from '@fortawesome/free-solid-svg-icons'; | ||||||
| import MkInput from '../../components/ui/input.vue'; |  | ||||||
| import MkButton from '../../components/ui/button.vue'; | import MkButton from '../../components/ui/button.vue'; | ||||||
| import MkSwitch from '../../components/ui/switch.vue'; | import MkSwitch from '../../components/ui/switch.vue'; | ||||||
| import MkSelect from '../../components/ui/select.vue'; | import MkSelect from '../../components/ui/select.vue'; | ||||||
| import MkRadio from '../../components/ui/radio.vue'; | import MkRadio from '../../components/ui/radio.vue'; | ||||||
| import MkRange from '../../components/ui/range.vue'; | import MkRange from '../../components/ui/range.vue'; | ||||||
| import XTheme from './theme.vue'; | import XTheme from './theme.vue'; | ||||||
|  | import XSidebar from './sidebar.vue'; | ||||||
| import i18n from '../../i18n'; | import i18n from '../../i18n'; | ||||||
| import { langs } from '../../config'; | import { langs } from '../../config'; | ||||||
| 
 | 
 | ||||||
|  | @ -128,7 +130,7 @@ export default Vue.extend({ | ||||||
| 
 | 
 | ||||||
| 	components: { | 	components: { | ||||||
| 		XTheme, | 		XTheme, | ||||||
| 		MkInput, | 		XSidebar, | ||||||
| 		MkButton, | 		MkButton, | ||||||
| 		MkSwitch, | 		MkSwitch, | ||||||
| 		MkSelect, | 		MkSelect, | ||||||
|  |  | ||||||
							
								
								
									
										86
									
								
								src/client/pages/preferences/sidebar.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/client/pages/preferences/sidebar.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | ||||||
|  | <template> | ||||||
|  | <section class="_card"> | ||||||
|  | 	<div class="_title"><fa :icon="faListUl"/> {{ $t('sidebar') }}</div> | ||||||
|  | 	<div class="_content"> | ||||||
|  | 		<mk-textarea v-model="items" tall> | ||||||
|  | 			<span>{{ $t('sidebar') }}</span> | ||||||
|  | 			<template #desc><button class="_textButton" @click="addItem">{{ $t('addItem') }}</button></template> | ||||||
|  | 		</mk-textarea> | ||||||
|  | 	</div> | ||||||
|  | 	<div class="_footer"> | ||||||
|  | 		<mk-button inline @click="save()" primary><fa :icon="faSave"/> {{ $t('save') }}</mk-button> | ||||||
|  | 		<mk-button inline @click="reset()"><fa :icon="faRedo"/> {{ $t('default') }}</mk-button> | ||||||
|  | 	</div> | ||||||
|  | </section> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import { faListUl, faSave, faRedo } from '@fortawesome/free-solid-svg-icons'; | ||||||
|  | import MkButton from '../../components/ui/button.vue'; | ||||||
|  | import MkTextarea from '../../components/ui/textarea.vue'; | ||||||
|  | import i18n from '../../i18n'; | ||||||
|  | import { defaultDeviceUserSettings } from '../../store'; | ||||||
|  | import { createMenuDef } from '../../app'; | ||||||
|  | 
 | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	i18n, | ||||||
|  | 
 | ||||||
|  | 	components: { | ||||||
|  | 		MkButton, | ||||||
|  | 		MkTextarea, | ||||||
|  | 	}, | ||||||
|  | 	 | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			menuDef: createMenuDef({}), | ||||||
|  | 			items: '', | ||||||
|  | 			faListUl, faSave, faRedo | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	computed: { | ||||||
|  | 		splited(): string[] { | ||||||
|  | 			return this.items.trim().split('\n').filter(x => x.trim() !== ''); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	created() { | ||||||
|  | 		this.items = this.$store.state.deviceUser.menu.join('\n'); | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	methods: { | ||||||
|  | 		async addItem() { | ||||||
|  | 			const menu = Object.keys(this.menuDef).filter(k => !this.$store.state.deviceUser.menu.includes(k)); | ||||||
|  | 			const { canceled, result: item } = await this.$root.dialog({ | ||||||
|  | 				type: null, | ||||||
|  | 				title: this.$t('addItem'), | ||||||
|  | 				select: { | ||||||
|  | 					items: [...menu.map(k => ({ | ||||||
|  | 						value: k, text: this.$t(this.menuDef[k].title) | ||||||
|  | 					})), ...[{ | ||||||
|  | 						value: '-', text: this.$t('divider') | ||||||
|  | 					}]] | ||||||
|  | 				}, | ||||||
|  | 				showCancelButton: true | ||||||
|  | 			}); | ||||||
|  | 			if (canceled) return; | ||||||
|  | 			this.items = [...this.splited, item].join('\n'); | ||||||
|  | 			this.save(); | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		save() { | ||||||
|  | 			this.$store.commit('deviceUser/setMenu', this.splited); | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		reset() { | ||||||
|  | 			this.$store.commit('deviceUser/setMenu', defaultDeviceUserSettings.menu); | ||||||
|  | 			this.items = this.$store.state.deviceUser.menu.join('\n'); | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | 
 | ||||||
|  | </style> | ||||||
|  | @ -16,16 +16,27 @@ export const defaultSettings = { | ||||||
| 	reactions: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'], | 	reactions: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'], | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const defaultDeviceUserSettings = { | export const defaultDeviceUserSettings = { | ||||||
| 	visibility: 'public', | 	visibility: 'public', | ||||||
| 	localOnly: false, | 	localOnly: false, | ||||||
| 	widgets: [], | 	widgets: [], | ||||||
| 	tl: { | 	tl: { | ||||||
| 		src: 'home' | 		src: 'home' | ||||||
| 	}, | 	}, | ||||||
|  | 	menu: [ | ||||||
|  | 		'notifications', | ||||||
|  | 		'messaging', | ||||||
|  | 		'drive', | ||||||
|  | 		'-', | ||||||
|  | 		'followRequests', | ||||||
|  | 		'featured', | ||||||
|  | 		'explore', | ||||||
|  | 		'announcements', | ||||||
|  | 		'search', | ||||||
|  | 	], | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const defaultDeviceSettings = { | export const defaultDeviceSettings = { | ||||||
| 	lang: null, | 	lang: null, | ||||||
| 	loadRawImages: false, | 	loadRawImages: false, | ||||||
| 	alwaysShowNsfw: false, | 	alwaysShowNsfw: false, | ||||||
|  | @ -237,6 +248,10 @@ export default () => new Vuex.Store({ | ||||||
| 					}; | 					}; | ||||||
| 				}, | 				}, | ||||||
| 
 | 
 | ||||||
|  | 				setMenu(state, menu) { | ||||||
|  | 					state.menu = menu; | ||||||
|  | 				}, | ||||||
|  | 
 | ||||||
| 				setVisibility(state, visibility) { | 				setVisibility(state, visibility) { | ||||||
| 					state.visibility = visibility; | 					state.visibility = visibility; | ||||||
| 				}, | 				}, | ||||||
|  |  | ||||||
|  | @ -146,13 +146,7 @@ module.exports = { | ||||||
| 	resolveLoader: { | 	resolveLoader: { | ||||||
| 		modules: ['node_modules'] | 		modules: ['node_modules'] | ||||||
| 	}, | 	}, | ||||||
| 	cache: { | 	cache: false, | ||||||
| 		type: 'filesystem', |  | ||||||
| 		 |  | ||||||
| 		buildDependencies: { |  | ||||||
| 			config: [__filename] |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
| 	devtool: false, //'source-map',
 | 	devtool: false, //'source-map',
 | ||||||
| 	mode: isProduction ? 'production' : 'development' | 	mode: isProduction ? 'production' : 'development' | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue