diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9ac337b52a..a79e01c21e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1524,6 +1524,7 @@ _deck: popRight: "右に出す" _columns: + main: "メイン" widgets: "ウィジェット" notifications: "通知" tl: "タイムライン" diff --git a/src/client/ui/deck.vue b/src/client/ui/deck.vue index 557df3a80d..453e169327 100644 --- a/src/client/ui/deck.vue +++ b/src/client/ui/deck.vue @@ -1,31 +1,25 @@ <template> -<div class="mk-deck" :class="`${deckStore.state.columnAlign}`" v-hotkey.global="keymap"> +<div class="mk-deck" :class="`${deckStore.state.columnAlign}`" v-hotkey.global="keymap" @contextmenu.self.prevent="onContextmenu"> <XSidebar ref="nav"/> - <!-- TODO: deckMainColumnPlace を見て位置変える --> - <DeckColumn class="column" v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'"> - <template #header> - <XHeader :info="pageInfo"/> - </template> - - <router-view v-slot="{ Component }"> - <transition> - <keep-alive :include="['timeline']"> - <component :is="Component" :ref="changePage"/> - </keep-alive> - </transition> - </router-view> - </DeckColumn> - <template v-for="ids in layout"> - <div v-if="ids.length > 1" class="folder column"> + <!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> + <section v-if="ids.length > 1" + class="folder column" + :style="{ width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }" + > <DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :is-stacked="true" @parent-focus="moveFocus(id, $event)"/> - </div> - <DeckColumnCore v-else class="column" :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id === ids[0])" @parent-focus="moveFocus(ids[0], $event)"/> + </section> + <DeckColumnCore v-else + class="column" + :ref="ids[0]" + :key="ids[0]" + :column="columns.find(c => c.id === ids[0])" + @parent-focus="moveFocus(ids[0], $event)" + :style="columns.find(c => c.id === ids[0]).flexible ? { flex: 1 } : { width: columns.find(c => c.id === ids[0]).width + 'px' }" + /> </template> - <button @click="addColumn" class="_button add"><Fa :icon="faPlus"/></button> - <button v-if="$i" class="nav _button" @click="showNav()"><Fa :icon="faBars"/><i v-if="navIndicated"><Fa :icon="faCircle"/></i></button> <button v-if="$i" class="post _buttonPrimary" @click="post()"><Fa :icon="faPencilAlt"/></button> @@ -41,9 +35,7 @@ import { v4 as uuid } from 'uuid'; import { host } from '@/config'; import { search } from '@/scripts/search'; import DeckColumnCore from '@/ui/deck/column-core.vue'; -import DeckColumn from '@/ui/deck/column.vue'; import XSidebar from '@/components/sidebar.vue'; -import XHeader from './_common_/header.vue'; import { getScrollContainer } from '@/scripts/scroll'; import * as os from '@/os'; import { sidebarDef } from '@/sidebar'; @@ -54,8 +46,6 @@ export default defineComponent({ components: { XCommon, XSidebar, - XHeader, - DeckColumn, DeckColumnCore, }, @@ -63,8 +53,6 @@ export default defineComponent({ return { deckStore, host: host, - pageInfo: null, - pageKey: 0, menuDef: sidebarDef, wallpaper: localStorage.getItem('wallpaper') != null, faPlus, faPencilAlt, faChevronLeft, faBars, faCircle @@ -95,12 +83,6 @@ export default defineComponent({ }, }, - watch: { - $route(to, from) { - this.pageKey++; - }, - }, - created() { document.documentElement.style.overflowY = 'hidden'; document.documentElement.style.scrollBehavior = 'auto'; @@ -111,13 +93,6 @@ export default defineComponent({ }, methods: { - changePage(page) { - if (page == null) return; - if (page.INFO) { - this.pageInfo = page.INFO; - } - }, - onWheel(e) { if (getScrollContainer(e.target) == null) { document.documentElement.scrollLeft += e.deltaY > 0 ? 96 : -96; @@ -138,6 +113,7 @@ export default defineComponent({ async addColumn(ev) { const columns = [ + 'main', 'widgets', 'notifications', 'tl', @@ -166,6 +142,14 @@ export default defineComponent({ width: 330, }); }, + + onContextmenu(e) { + os.contextMenu([{ + text: this.$ts._deck.addColumn, + icon: null, + action: this.addColumn + }], e); + }, } }); </script> @@ -175,7 +159,7 @@ export default defineComponent({ $nav-hide-threshold: 650px; // TODO: どこかに集約したい // TODO: この値を設定で変えられるようにする? - $columnMargin: 12px; + $columnMargin: 32px; $deckMargin: $columnMargin; @@ -186,14 +170,14 @@ export default defineComponent({ height: calc(var(--vh, 1vh) * 100); box-sizing: border-box; flex: 1; - padding: $deckMargin 0 $deckMargin $deckMargin; + padding: $deckMargin; &.center { > .column:first-of-type { margin-left: auto; } - > .add { + > .column:last-of-type { margin-right: auto; } } diff --git a/src/client/ui/deck/column-core.vue b/src/client/ui/deck/column-core.vue index 15cf763a52..c6a2104268 100644 --- a/src/client/ui/deck/column-core.vue +++ b/src/client/ui/deck/column-core.vue @@ -1,6 +1,7 @@ <template> <!-- TODO: リファクタの余地がありそう --> -<XWidgetsColumn v-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> +<XMainColumn v-if="column.type === 'main'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> +<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> <XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> <XTlColumn v-else-if="column.type === 'tl'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> <XListColumn v-else-if="column.type === 'list'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/> @@ -12,6 +13,7 @@ <script lang="ts"> import { defineComponent } from 'vue'; +import XMainColumn from './main-column.vue'; import XTlColumn from './tl-column.vue'; import XAntennaColumn from './antenna-column.vue'; import XListColumn from './list-column.vue'; @@ -22,6 +24,7 @@ import XDirectColumn from './direct-column.vue'; export default defineComponent({ components: { + XMainColumn, XTlColumn, XAntennaColumn, XListColumn, diff --git a/src/client/ui/deck/column.vue b/src/client/ui/deck/column.vue index 41dcc3e360..17aa922823 100644 --- a/src/client/ui/deck/column.vue +++ b/src/client/ui/deck/column.vue @@ -5,7 +5,6 @@ @dragleave="onDragleave" @drop.prevent.stop="onDrop" v-hotkey="keymap" - :style="{ width: `${width}px` }" > <header :class="{ indicated }" draggable="true" @@ -14,7 +13,7 @@ @dragend="onDragend" @contextmenu.prevent.stop="onContextmenu" > - <button class="toggleActive _button" @click="toggleActive" v-if="isStacked"> + <button class="toggleActive _button" @click="toggleActive" v-if="isStacked && !isMainColumn"> <template v-if="active"><Fa :icon="faAngleUp"/></template> <template v-else><Fa :icon="faAngleDown"/></template> </button> @@ -35,7 +34,7 @@ import { defineComponent } from 'vue'; import { faArrowUp, faArrowDown, faAngleUp, faAngleDown, faCaretDown, faArrowRight, faArrowLeft, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faWindowMaximize, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons'; import * as os from '@/os'; -import { renameColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store'; +import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store'; export default defineComponent({ props: { @@ -78,11 +77,7 @@ export default defineComponent({ computed: { isMainColumn(): boolean { - return this.column == null; - }, - - width(): number { - return this.isMainColumn ? 350 : this.column.width; + return this.column.type === 'main'; }, keymap(): any { @@ -106,17 +101,13 @@ export default defineComponent({ }, mounted() { - if (!this.isMainColumn) { - os.deckGlobalEvents.on('column.dragStart', this.onOtherDragStart); - os.deckGlobalEvents.on('column.dragEnd', this.onOtherDragEnd); - } + os.deckGlobalEvents.on('column.dragStart', this.onOtherDragStart); + os.deckGlobalEvents.on('column.dragEnd', this.onOtherDragEnd); }, beforeUnmount() { - if (!this.isMainColumn) { - os.deckGlobalEvents.off('column.dragStart', this.onOtherDragStart); - os.deckGlobalEvents.off('column.dragEnd', this.onOtherDragEnd); - } + os.deckGlobalEvents.off('column.dragStart', this.onOtherDragStart); + os.deckGlobalEvents.off('column.dragEnd', this.onOtherDragEnd); }, methods: { @@ -136,18 +127,27 @@ export default defineComponent({ getMenu() { const items = [{ icon: faPencilAlt, - text: this.$ts.rename, - action: () => { - os.dialog({ - title: this.$ts.rename, - input: { - default: this.column.name, - allowEmpty: false + text: this.$ts.edit, + action: async () => { + const { canceled, result } = await os.form(this.column.name, { + name: { + type: 'string', + label: this.$ts.name, + default: this.column.name + }, + width: { + type: 'number', + label: this.$ts.width, + default: this.column.width + }, + flexible: { + type: 'boolean', + label: this.$ts.flexible, + default: this.column.flexible } - }).then(({ canceled, result: name }) => { - if (canceled) return; - renameColumn(this.column.id, name); }); + if (canceled) return; + updateColumn(this.column.id, result); } }, null, { icon: faArrowLeft, @@ -203,8 +203,7 @@ export default defineComponent({ }, onContextmenu(e) { - if (this.isMainColumn) return; - this.showMenu(); + os.contextMenu(this.getMenu(), e); }, showMenu() { @@ -219,12 +218,6 @@ export default defineComponent({ }, onDragstart(e) { - // メインカラムはドラッグさせない - if (this.isMainColumn) { - e.preventDefault(); - return; - } - e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, this.column.id); this.dragging = true; @@ -235,12 +228,6 @@ export default defineComponent({ }, onDragover(e) { - // メインカラムにはドロップさせない - if (this.isMainColumn) { - e.dataTransfer.dropEffect = 'none'; - return; - } - // 自分自身がドラッグされている場合 if (this.dragging) { // 自分自身にはドロップさせない diff --git a/src/client/ui/deck/deck-store.ts b/src/client/ui/deck/deck-store.ts index 2d0012b566..7693401e15 100644 --- a/src/client/ui/deck/deck-store.ts +++ b/src/client/ui/deck/deck-store.ts @@ -36,10 +36,6 @@ export const deckStore = markRaw(new Storage('deck', { where: 'deviceAccount', default: true }, - mainColumnPlace: { - where: 'deviceAccount', - default: 'left' as 'left' | 'right' - }, navWindow: { where: 'deviceAccount', default: true @@ -200,16 +196,6 @@ export function updateColumnWidget(id: Column['id'], widgetId: string, data: any deckStore.set('columns', columns); } -export function renameColumn(id: Column['id'], name: Column['name']) { - const columns = copy(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const column = copy(deckStore.state.columns[columnIndex]); - if (column == null) return; - column.name = name; - columns[columnIndex] = column; - deckStore.set('columns', columns); -} - export function updateColumn(id: Column['id'], column: Partial<Column>) { const columns = copy(deckStore.state.columns); const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue new file mode 100644 index 0000000000..f652b01f6e --- /dev/null +++ b/src/client/ui/deck/main-column.vue @@ -0,0 +1,59 @@ +<template> +<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked"> + <template #header> + <XHeader :info="pageInfo"/> + </template> + + <router-view v-slot="{ Component }"> + <transition> + <keep-alive :include="['timeline']"> + <component :is="Component" :ref="changePage"/> + </keep-alive> + </transition> + </router-view> +</XColumn> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import XColumn from './column.vue'; +import XNotes from '@/components/notes.vue'; +import XHeader from '@/ui/_common_/header.vue'; +import { deckStore } from '@/ui/deck/deck-store'; + +export default defineComponent({ + components: { + XColumn, + XHeader, + XNotes + }, + + props: { + column: { + type: Object, + required: true + }, + isStacked: { + type: Boolean, + required: true + } + }, + + data() { + return { + deckStore, + pageInfo: null, + pageKey: 0, + } + }, + + methods: { + changePage(page) { + if (page == null) return; + if (page.INFO) { + this.pageInfo = page.INFO; + } + }, + } +}); +</script> diff --git a/src/server/web/boot.js b/src/server/web/boot.js index 8b1fd9a619..12731e5d3b 100644 --- a/src/server/web/boot.js +++ b/src/server/web/boot.js @@ -104,6 +104,11 @@ document.documentElement.classList.add('useSystemFont'); } + const wallpaper = localStorage.getItem('wallpaper'); + if (wallpaper) { + document.documentElement.style.backgroundImage = `url(${wallpaper})`; + } + // eslint-disable-next-line no-inner-declarations function refresh() { // Random