diff options
Diffstat (limited to 'src/client/ui/chat/side.vue')
| -rw-r--r-- | src/client/ui/chat/side.vue | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/client/ui/chat/side.vue b/src/client/ui/chat/side.vue new file mode 100644 index 0000000000..188123deb9 --- /dev/null +++ b/src/client/ui/chat/side.vue @@ -0,0 +1,165 @@ +<template> +<div class="qvzfzxam _narrow_" v-if="component"> + <div class="container"> + <header class="header" @contextmenu.prevent.stop="onContextmenu"> + <button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button> + <XHeader class="title" :info="pageInfo" :with-back="false" :center="false"/> + <button class="_button" @click="close()"><Fa :icon="faTimes"/></button> + </header> + <component :is="component" v-bind="props" :ref="changePage"/> + </div> +</div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { faTimes, faChevronLeft, faExpandAlt, faWindowMaximize, faExternalLinkAlt, faLink } from '@fortawesome/free-solid-svg-icons'; +import XHeader from '../_common_/header.vue'; +import * as os from '@/os'; +import copyToClipboard from '@/scripts/copy-to-clipboard'; +import { resolve } from '@/router'; +import { url } from '@/config'; + +export default defineComponent({ + components: { + XHeader + }, + + provide() { + return { + navHook: (path) => { + this.navigate(path); + } + }; + }, + + data() { + return { + path: null, + component: null, + props: {}, + pageInfo: null, + history: [], + faTimes, faChevronLeft, + }; + }, + + computed: { + url(): string { + return url + this.path; + } + }, + + methods: { + changePage(page) { + if (page == null) return; + if (page.INFO) { + this.pageInfo = 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(e) { + os.contextMenu([{ + type: 'label', + text: this.path, + }, { + icon: faExpandAlt, + text: this.$ts.showInPage, + action: () => { + this.$router.push(this.path); + this.close(); + } + }, { + icon: faWindowMaximize, + text: this.$ts.openInWindow, + action: () => { + os.pageWindow(this.path); + this.close(); + } + }, null, { + icon: faExternalLinkAlt, + text: this.$ts.openInNewTab, + action: () => { + window.open(this.url, '_blank'); + this.close(); + } + }, { + icon: faLink, + text: this.$ts.copyLink, + action: () => { + copyToClipboard(this.url); + } + }], e); + } + } +}); +</script> + +<style lang="scss" scoped> +.qvzfzxam { + $header-height: 54px; // TODO: どこかに集約したい + + --section-padding: 16px; + --margin: var(--marginHalf); + + width: 390px; + + > .container { + position: fixed; + width: 390px; + height: 100vh; + overflow: auto; + box-sizing: border-box; + + > .header { + display: flex; + position: sticky; + z-index: 1000; + top: 0; + height: $header-height; + width: 100%; + line-height: $header-height; + font-weight: bold; + //background-color: var(--panel); + -webkit-backdrop-filter: blur(32px); + backdrop-filter: blur(32px); + background-color: var(--header); + border-bottom: solid 1px var(--divider); + box-sizing: border-box; + + > ._button { + height: $header-height; + width: $header-height; + + &:hover { + color: var(--fgHighlighted); + } + } + + > .title { + flex: 1; + position: relative; + } + } + } +} +</style> + |