fix: Fix Sideview (#8235)
* Fix #7890 * a- * 3度目の正直 * fix * ✌️ * update CHANGELOG Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
parent
141c999acd
commit
ae3abc2126
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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 importするとAsyncComponentWrapperが間に入るせいでref取得できなくて面倒になる
|
|
||||||
},
|
|
||||||
|
|
||||||
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>
|
||||||
|
|
Loading…
Reference in New Issue