1
0
forked from mirror/misskey

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]) { pageInfo = page[symbols.PAGE_INFO];
this.pageInfo = page[symbols.PAGE_INFO];
}
},
navigate(path, record = true) {
if (record && this.path) this.history.push(this.path);
this.path = path;
const { component, props } = resolve(path);
this.component = component;
this.props = props;
},
back() {
this.navigate(this.history.pop(), false);
},
close() {
this.path = null;
this.component = null;
this.props = {};
},
onContextmenu(ev: MouseEvent) {
os.contextMenu([{
type: 'label',
text: this.path,
}, {
icon: 'fas fa-expand-alt',
text: this.$ts.showInPage,
action: () => {
this.$router.push(this.path);
this.close();
}
}, {
icon: 'fas fa-window-maximize',
text: this.$ts.openInWindow,
action: () => {
os.pageWindow(this.path);
this.close();
}
}, null, {
icon: 'fas fa-external-link-alt',
text: this.$ts.openInNewTab,
action: () => {
window.open(this.url, '_blank');
this.close();
}
}, {
icon: 'fas fa-link',
text: this.$ts.copyLink,
action: () => {
copyToClipboard(this.url);
}
}], ev);
}
} }
}
function navigate(_path: string, record = true) {
if (record && path) history.push($$(path).value);
path = _path;
const resolved = resolve(path);
component = resolved.component;
props = resolved.props;
}
function back() {
const prev = history.pop();
if (prev) navigate(prev, false);
}
function close() {
path = null;
component = null;
props = {};
}
function onContextmenu(ev: MouseEvent) {
os.contextMenu([{
type: 'label',
text: path || '',
}, {
icon: 'fas fa-expand-alt',
text: i18n.ts.showInPage,
action: () => {
if (path) router.push(path);
close();
}
}, {
icon: 'fas fa-window-maximize',
text: i18n.ts.openInWindow,
action: () => {
if (path) os.pageWindow(path);
close();
}
}, null, {
icon: 'fas fa-external-link-alt',
text: i18n.ts.openInNewTab,
action: () => {
window.open(url, '_blank');
close();
}
}, {
icon: 'fas fa-link',
text: i18n.ts.copyLink,
action: () => {
copyToClipboard(url);
}
}], 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,155 +64,133 @@
</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, isMobile.value = window.innerWidth <= MOBILE_THRESHOLD;
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;
});
const pageInfo = ref();
const widgetsEl = ref<HTMLElement>();
const widgetsShowing = ref(false);
const sideViewController = new EventEmitter();
provide('sideViewHook', isDesktop.value ? (url) => {
sideViewController.emit('navigate', url);
} : null);
const menuIndicated = computed(() => {
for (const def in menuDef) {
if (def === 'notifications') continue; //
if (menuDef[def].indicated) return true;
}
return false;
});
const drawerMenuShowing = ref(false);
const route = useRoute();
watch(route, () => {
drawerMenuShowing.value = false;
});
document.documentElement.style.overflowY = 'scroll';
if (defaultStore.state.widgets.length === 0) {
defaultStore.set('widgets', [{
name: 'calendar',
id: 'a', place: 'right', data: {}
}, {
name: 'notifications',
id: 'b', place: 'right', data: {}
}, {
name: 'trends',
id: 'c', place: 'right', data: {}
}]);
}
onMounted(() => {
if (!isDesktop.value) {
window.addEventListener('resize', () => {
if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true;
}, { passive: true });
}
});
const changePage = (page) => {
if (page == null) return;
if (page[symbols.PAGE_INFO]) {
pageInfo.value = page[symbols.PAGE_INFO];
document.title = `${pageInfo.value.title} | ${instanceName}`;
}
};
const onContextmenu = (ev) => {
const isLink = (el: HTMLElement) => {
if (el.tagName === 'A') return true;
if (el.parentElement) {
return isLink(el.parentElement);
}
};
if (isLink(ev.target)) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return;
const path = route.path;
os.contextMenu([{
type: 'label',
text: path,
}, {
icon: 'fas fa-columns',
text: i18n.ts.openInSideView,
action: () => {
this.$refs.side.navigate(path);
}
}, {
icon: 'fas fa-window-maximize',
text: i18n.ts.openInWindow,
action: () => {
os.pageWindow(path);
}
}], ev);
};
const attachSticky = (el) => {
const sticky = new StickySidebar(widgetsEl.value);
window.addEventListener('scroll', () => {
sticky.calc(window.scrollY);
}, { passive: true });
};
return {
pageInfo,
isDesktop,
isMobile,
widgetsEl,
widgetsShowing,
drawerMenuShowing,
menuIndicated,
wallpaper: localStorage.getItem('wallpaper') != null,
changePage,
top: () => {
window.scroll({ top: 0, behavior: 'smooth' });
},
onTransition: () => {
if (window._scroll) window._scroll();
},
post: os.post,
onContextmenu,
attachSticky,
};
},
}); });
const pageInfo = ref();
const widgetsEl = $ref<HTMLElement>();
const widgetsShowing = ref(false);
let sideEl = $ref<InstanceType<typeof XSideView>>();
provide('sideViewHook', isDesktop.value ? (url) => {
sideEl.navigate(url);
} : null);
const menuIndicated = computed(() => {
for (const def in menuDef) {
if (def === 'notifications') continue; //
if (menuDef[def].indicated) return true;
}
return false;
});
const drawerMenuShowing = ref(false);
const route = useRoute();
watch(route, () => {
drawerMenuShowing.value = false;
});
document.documentElement.style.overflowY = 'scroll';
if (defaultStore.state.widgets.length === 0) {
defaultStore.set('widgets', [{
name: 'calendar',
id: 'a', place: 'right', data: {}
}, {
name: 'notifications',
id: 'b', place: 'right', data: {}
}, {
name: 'trends',
id: 'c', place: 'right', data: {}
}]);
}
onMounted(() => {
if (!isDesktop.value) {
window.addEventListener('resize', () => {
if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true;
}, { passive: true });
}
});
const changePage = (page) => {
if (page == null) return;
if (page[symbols.PAGE_INFO]) {
pageInfo.value = page[symbols.PAGE_INFO];
document.title = `${pageInfo.value.title} | ${instanceName}`;
}
};
const onContextmenu = (ev) => {
const isLink = (el: HTMLElement) => {
if (el.tagName === 'A') return true;
if (el.parentElement) {
return isLink(el.parentElement);
}
};
if (isLink(ev.target)) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return;
if (window.getSelection()?.toString() !== '') return;
const path = route.path;
os.contextMenu([{
type: 'label',
text: path,
}, {
icon: 'fas fa-columns',
text: i18n.ts.openInSideView,
action: () => {
sideEl.navigate(path);
}
}, {
icon: 'fas fa-window-maximize',
text: i18n.ts.openInWindow,
action: () => {
os.pageWindow(path);
}
}], ev);
};
const attachSticky = (el) => {
const sticky = new StickySidebar(widgetsEl);
window.addEventListener('scroll', () => {
sticky.calc(window.scrollY);
}, { passive: true });
};
function top() {
window.scroll({ top: 0, behavior: 'smooth' });
}
function onTransition() {
if (window._scroll) window._scroll();
}
const wallpaper = localStorage.getItem('wallpaper') != null;
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>