summaryrefslogtreecommitdiff
path: root/src/client/ui/default.side.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/ui/default.side.vue')
-rw-r--r--src/client/ui/default.side.vue157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/client/ui/default.side.vue b/src/client/ui/default.side.vue
new file mode 100644
index 0000000000..cff35f6ed3
--- /dev/null
+++ b/src/client/ui/default.side.vue
@@ -0,0 +1,157 @@
+<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>
+ <button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
+ <XHeader class="title" :info="pageInfo" :with-back="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';
+
+export default defineComponent({
+ components: {
+ XHeader
+ },
+
+ provide() {
+ return {
+ navHook: (url) => {
+ this.navigate(url);
+ }
+ };
+ },
+
+ data() {
+ return {
+ url: null,
+ component: null,
+ props: {},
+ pageInfo: null,
+ history: [],
+ faTimes, faChevronLeft,
+ };
+ },
+
+ methods: {
+ changePage(page) {
+ if (page == null) return;
+ if (page.INFO) {
+ this.pageInfo = page.INFO;
+ }
+ },
+
+ navigate(url, record = true) {
+ if (record && this.url) this.history.push(this.url);
+ this.url = url;
+ const { component, props } = resolve(url);
+ this.component = component;
+ this.props = props;
+ },
+
+ back() {
+ this.navigate(this.history.pop(), false);
+ },
+
+ close() {
+ this.url = null;
+ this.component = null;
+ this.props = {};
+ },
+
+ onContextmenu(e) {
+ os.contextMenu([{
+ type: 'label',
+ text: this.url,
+ }, {
+ icon: faExpandAlt,
+ text: this.$t('showInPage'),
+ action: () => {
+ this.$router.push(this.url);
+ this.close();
+ }
+ }, {
+ icon: faWindowMaximize,
+ text: this.$t('openInWindow'),
+ action: () => {
+ os.pageWindow(this.url);
+ this.close();
+ }
+ }, null, {
+ icon: faExternalLinkAlt,
+ text: this.$t('openInNewTab'),
+ action: () => {
+ window.open(this.url, '_blank');
+ this.close();
+ }
+ }, {
+ icon: faLink,
+ text: this.$t('copyLink'),
+ action: () => {
+ copyToClipboard(this.url);
+ }
+ }], e);
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.qvzfzxam {
+ $header-height: 58px; // TODO: どこかに集約したい
+
+ --section-padding: 16px;
+ --margin: var(--marginHalf);
+
+ > .container {
+ position: fixed;
+ width: 370px;
+ 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;
+ text-align: center;
+ 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);
+
+ > ._button {
+ height: $header-height;
+ width: $header-height;
+
+ &:hover {
+ color: var(--fgHighlighted);
+ }
+ }
+
+ > .title {
+ flex: 1;
+ position: relative;
+ }
+ }
+ }
+}
+</style>
+