fix: Fix Sideview (#8235)

* Fix #7890

* a-

* 3度目の正直

* fix

* ✌️

* update CHANGELOG

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
tamaina 2022-02-01 23:48:19 +09:00 committed by GitHub
parent 141c999acd
commit ae3abc2126
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 194 additions and 224 deletions

View file

@ -22,6 +22,7 @@
- 投稿フォームのハッシュタグ保持フィールドが動作しない問題を修正 - 投稿フォームのハッシュタグ保持フィールドが動作しない問題を修正
- Add `img-src` and `media-src` directives to `Content-Security-Policy` for - Add `img-src` and `media-src` directives to `Content-Security-Policy` for
files and media proxy files and media proxy
- サイドビューが動かないのを修正
- ensure that specified users does not get duplicates - ensure that specified users does not get duplicates
## 12.102.1 (2022/01/27) ## 12.102.1 (2022/01/27)

View file

@ -23,8 +23,9 @@ const props = withDefaults(defineProps<{
behavior: null, behavior: null,
}); });
const navHook = inject('navHook', null); type Navigate = (path: string, record?: boolean) => void;
const sideViewHook = inject('sideViewHook', null); const navHook = inject<null | Navigate>('navHook', null);
const sideViewHook = inject<null | Navigate>('sideViewHook', null);
const active = $computed(() => { const active = $computed(() => {
if (props.activeClass == null) return false; if (props.activeClass == null) return false;

View file

@ -4,7 +4,7 @@
<header class="header" @contextmenu.prevent.stop="onContextmenu"> <header class="header" @contextmenu.prevent.stop="onContextmenu">
<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-chevron-left"></i></button> <button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-chevron-left"></i></button>
<button v-else class="_button" style="pointer-events: none;"><!-- マージンのバランスを取るためのダミー --></button> <button v-else class="_button" style="pointer-events: none;"><!-- マージンのバランスを取るためのダミー --></button>
<span class="title">{{ pageInfo.title }}</span> <span class="title" v-text="pageInfo?.title" />
<button class="_button" @click="close()"><i class="fas fa-times"></i></button> <button class="_button" @click="close()"><i class="fas fa-times"></i></button>
</header> </header>
<MkHeader class="pageHeader" :info="pageInfo"/> <MkHeader class="pageHeader" :info="pageInfo"/>
@ -13,99 +13,89 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent } from 'vue'; import { provide } from 'vue';
import * as os from '@/os'; import * as os from '@/os';
import copyToClipboard from '@/scripts/copy-to-clipboard'; import copyToClipboard from '@/scripts/copy-to-clipboard';
import { resolve } from '@/router'; import { resolve, router } from '@/router';
import { url } from '@/config'; import { url as root } from '@/config';
import * as symbols from '@/symbols'; import * as symbols from '@/symbols';
import { i18n } from '@/i18n';
export default defineComponent({ provide('navHook', navigate);
provide() {
return {
navHook: (path) => {
this.navigate(path);
}
};
},
data() { let path: string | null = $ref(null);
return { let component: ReturnType<typeof resolve>['component'] | null = $ref(null);
path: null, let props: any | null = $ref(null);
component: null, let pageInfo: any | null = $ref(null);
props: {}, let history: string[] = $ref([]);
pageInfo: null,
history: [],
};
},
computed: { let url = $computed(() => `${root}${path}`);
url(): string {
return url + this.path;
}
},
methods: { function changePage(page) {
changePage(page) {
if (page == null) return; if (page == null) return;
if (page[symbols.PAGE_INFO]) { if (page[symbols.PAGE_INFO]) {
this.pageInfo = page[symbols.PAGE_INFO]; pageInfo = page[symbols.PAGE_INFO];
} }
}, }
navigate(path, record = true) { function navigate(_path: string, record = true) {
if (record && this.path) this.history.push(this.path); if (record && path) history.push($$(path).value);
this.path = path; path = _path;
const { component, props } = resolve(path); const resolved = resolve(path);
this.component = component; component = resolved.component;
this.props = props; props = resolved.props;
}, }
back() { function back() {
this.navigate(this.history.pop(), false); const prev = history.pop();
}, if (prev) navigate(prev, false);
}
close() { function close() {
this.path = null; path = null;
this.component = null; component = null;
this.props = {}; props = {};
}, }
onContextmenu(ev: MouseEvent) { function onContextmenu(ev: MouseEvent) {
os.contextMenu([{ os.contextMenu([{
type: 'label', type: 'label',
text: this.path, text: path || '',
}, { }, {
icon: 'fas fa-expand-alt', icon: 'fas fa-expand-alt',
text: this.$ts.showInPage, text: i18n.ts.showInPage,
action: () => { action: () => {
this.$router.push(this.path); if (path) router.push(path);
this.close(); close();
} }
}, { }, {
icon: 'fas fa-window-maximize', icon: 'fas fa-window-maximize',
text: this.$ts.openInWindow, text: i18n.ts.openInWindow,
action: () => { action: () => {
os.pageWindow(this.path); if (path) os.pageWindow(path);
this.close(); close();
} }
}, null, { }, null, {
icon: 'fas fa-external-link-alt', icon: 'fas fa-external-link-alt',
text: this.$ts.openInNewTab, text: i18n.ts.openInNewTab,
action: () => { action: () => {
window.open(this.url, '_blank'); window.open(url, '_blank');
this.close(); close();
} }
}, { }, {
icon: 'fas fa-link', icon: 'fas fa-link',
text: this.$ts.copyLink, text: i18n.ts.copyLink,
action: () => { action: () => {
copyToClipboard(this.url); copyToClipboard(url);
} }
}], ev); }], ev);
} }
}
defineExpose({
navigate,
back,
close,
}); });
</script> </script>

View file

@ -20,7 +20,7 @@
</main> </main>
</div> </div>
<XSideView v-if="isDesktop" ref="side" class="side"/> <XSideView v-if="isDesktop" ref="sideEl" class="side"/>
<div v-if="isDesktop" ref="widgetsEl" class="widgets"> <div v-if="isDesktop" ref="widgetsEl" class="widgets">
<XWidgets @mounted="attachSticky"/> <XWidgets @mounted="attachSticky"/>
@ -31,9 +31,9 @@
<div v-if="isMobile" class="buttons"> <div v-if="isMobile" class="buttons">
<button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button> <button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button> <button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button>
<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button> <button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i?.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button>
<button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button> <button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button>
<button class="button post _button" @click="post()"><i class="fas fa-pencil-alt"></i></button> <button class="button post _button" @click="os.post()"><i class="fas fa-pencil-alt"></i></button>
</div> </div>
<transition :name="$store.state.animation ? 'menuDrawer-back' : ''"> <transition :name="$store.state.animation ? 'menuDrawer-back' : ''">
@ -64,69 +64,60 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, defineAsyncComponent, provide, onMounted, computed, ref, watch } from 'vue'; import { defineAsyncComponent, provide, onMounted, computed, ref, watch } from 'vue';
import { instanceName } from '@/config'; import { instanceName } from '@/config';
import { StickySidebar } from '@/scripts/sticky-sidebar'; import { StickySidebar } from '@/scripts/sticky-sidebar';
import XSidebar from '@/ui/_common_/sidebar.vue';
import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import XSideView from './classic.side.vue'; import XSideView from './classic.side.vue';
import * as os from '@/os'; import * as os from '@/os';
import * as symbols from '@/symbols'; import * as symbols from '@/symbols';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import * as EventEmitter from 'eventemitter3';
import { menuDef } from '@/menu'; import { menuDef } from '@/menu';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { $i } from '@/account';
const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue'));
const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/sidebar.vue'));
const DESKTOP_THRESHOLD = 1100; const DESKTOP_THRESHOLD = 1100;
const MOBILE_THRESHOLD = 500; const MOBILE_THRESHOLD = 500;
export default defineComponent({ const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
components: { const isMobile = ref(window.innerWidth <= MOBILE_THRESHOLD);
XCommon, window.addEventListener('resize', () => {
XSidebar,
XDrawerMenu,
XWidgets: defineAsyncComponent(() => import('./universal.widgets.vue')),
XSideView, // NOTE: dynamic importAsyncComponentWrapperref
},
setup() {
const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
const isMobile = ref(window.innerWidth <= MOBILE_THRESHOLD);
window.addEventListener('resize', () => {
isMobile.value = window.innerWidth <= MOBILE_THRESHOLD; isMobile.value = window.innerWidth <= MOBILE_THRESHOLD;
}); });
const pageInfo = ref(); const pageInfo = ref();
const widgetsEl = ref<HTMLElement>(); const widgetsEl = $ref<HTMLElement>();
const widgetsShowing = ref(false); const widgetsShowing = ref(false);
const sideViewController = new EventEmitter(); let sideEl = $ref<InstanceType<typeof XSideView>>();
provide('sideViewHook', isDesktop.value ? (url) => { provide('sideViewHook', isDesktop.value ? (url) => {
sideViewController.emit('navigate', url); sideEl.navigate(url);
} : null); } : null);
const menuIndicated = computed(() => { const menuIndicated = computed(() => {
for (const def in menuDef) { for (const def in menuDef) {
if (def === 'notifications') continue; // if (def === 'notifications') continue; //
if (menuDef[def].indicated) return true; if (menuDef[def].indicated) return true;
} }
return false; return false;
}); });
const drawerMenuShowing = ref(false); const drawerMenuShowing = ref(false);
const route = useRoute(); const route = useRoute();
watch(route, () => { watch(route, () => {
drawerMenuShowing.value = false; drawerMenuShowing.value = false;
}); });
document.documentElement.style.overflowY = 'scroll'; document.documentElement.style.overflowY = 'scroll';
if (defaultStore.state.widgets.length === 0) { if (defaultStore.state.widgets.length === 0) {
defaultStore.set('widgets', [{ defaultStore.set('widgets', [{
name: 'calendar', name: 'calendar',
id: 'a', place: 'right', data: {} id: 'a', place: 'right', data: {}
@ -137,25 +128,25 @@ export default defineComponent({
name: 'trends', name: 'trends',
id: 'c', place: 'right', data: {} id: 'c', place: 'right', data: {}
}]); }]);
} }
onMounted(() => { onMounted(() => {
if (!isDesktop.value) { if (!isDesktop.value) {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true; if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true;
}, { passive: true }); }, { passive: true });
} }
}); });
const changePage = (page) => { const changePage = (page) => {
if (page == null) return; if (page == null) return;
if (page[symbols.PAGE_INFO]) { if (page[symbols.PAGE_INFO]) {
pageInfo.value = page[symbols.PAGE_INFO]; pageInfo.value = page[symbols.PAGE_INFO];
document.title = `${pageInfo.value.title} | ${instanceName}`; document.title = `${pageInfo.value.title} | ${instanceName}`;
} }
}; };
const onContextmenu = (ev) => { const onContextmenu = (ev) => {
const isLink = (el: HTMLElement) => { const isLink = (el: HTMLElement) => {
if (el.tagName === 'A') return true; if (el.tagName === 'A') return true;
if (el.parentElement) { if (el.parentElement) {
@ -164,7 +155,7 @@ export default defineComponent({
}; };
if (isLink(ev.target)) return; if (isLink(ev.target)) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return; if (window.getSelection()?.toString() !== '') return;
const path = route.path; const path = route.path;
os.contextMenu([{ os.contextMenu([{
type: 'label', type: 'label',
@ -173,7 +164,7 @@ export default defineComponent({
icon: 'fas fa-columns', icon: 'fas fa-columns',
text: i18n.ts.openInSideView, text: i18n.ts.openInSideView,
action: () => { action: () => {
this.$refs.side.navigate(path); sideEl.navigate(path);
} }
}, { }, {
icon: 'fas fa-window-maximize', icon: 'fas fa-window-maximize',
@ -182,37 +173,24 @@ export default defineComponent({
os.pageWindow(path); os.pageWindow(path);
} }
}], ev); }], ev);
}; };
const attachSticky = (el) => { const attachSticky = (el) => {
const sticky = new StickySidebar(widgetsEl.value); const sticky = new StickySidebar(widgetsEl);
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
sticky.calc(window.scrollY); sticky.calc(window.scrollY);
}, { passive: true }); }, { passive: true });
}; };
return { function top() {
pageInfo,
isDesktop,
isMobile,
widgetsEl,
widgetsShowing,
drawerMenuShowing,
menuIndicated,
wallpaper: localStorage.getItem('wallpaper') != null,
changePage,
top: () => {
window.scroll({ top: 0, behavior: 'smooth' }); window.scroll({ top: 0, behavior: 'smooth' });
}, }
onTransition: () => {
function onTransition() {
if (window._scroll) window._scroll(); if (window._scroll) window._scroll();
}, }
post: os.post,
onContextmenu, const wallpaper = localStorage.getItem('wallpaper') != null;
attachSticky,
};
},
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>