feat: add minimize/Fold button for windows (#10508)
* add window minimizing! * Fix window being able to go offscreen * Revert en-US.yml changes --------- Co-authored-by: mothmoon <remilia@remilia.se>
This commit is contained in:
parent
79f198e4f1
commit
44a4faebc0
|
@ -34,6 +34,7 @@
|
||||||
- 左耳は上からおよそ 10%, 左からおよそ 20% の位置で決定します
|
- 左耳は上からおよそ 10%, 左からおよそ 20% の位置で決定します
|
||||||
- 右耳は上からおよそ 10%, 左からおよそ 80% の位置で決定します
|
- 右耳は上からおよそ 10%, 左からおよそ 80% の位置で決定します
|
||||||
- 「UIのアニメーションを減らす」 (`reduceAnimation`) で猫耳を撫でられなくなります
|
- 「UIのアニメーションを減らす」 (`reduceAnimation`) で猫耳を撫でられなくなります
|
||||||
|
- Add Minimizing ("folding") of windows
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- イベント用Redisを別サーバーに分離できるように
|
- イベント用Redisを別サーバーに分離できるように
|
||||||
|
|
|
@ -920,6 +920,7 @@ pushNotificationNotSupported: "ブラウザかサーバーがプッシュ通知
|
||||||
sendPushNotificationReadMessage: "通知やメッセージが既読になったらプッシュ通知を削除する"
|
sendPushNotificationReadMessage: "通知やメッセージが既読になったらプッシュ通知を削除する"
|
||||||
sendPushNotificationReadMessageCaption: "「{emptyPushNotificationMessage}」という通知が一瞬表示されるようになります。端末の電池消費量が増加する可能性があります。"
|
sendPushNotificationReadMessageCaption: "「{emptyPushNotificationMessage}」という通知が一瞬表示されるようになります。端末の電池消費量が増加する可能性があります。"
|
||||||
windowMaximize: "最大化"
|
windowMaximize: "最大化"
|
||||||
|
windowMinimize: "最小化"
|
||||||
windowRestore: "元に戻す"
|
windowRestore: "元に戻す"
|
||||||
caption: "キャプション"
|
caption: "キャプション"
|
||||||
loggedInAsBot: "Botアカウントでログイン中"
|
loggedInAsBot: "Botアカウントでログイン中"
|
||||||
|
|
|
@ -11,15 +11,17 @@
|
||||||
<div :class="$style.body" class="_shadow" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
<div :class="$style.body" class="_shadow" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
||||||
<div :class="[$style.header, { [$style.mini]: mini }]" @contextmenu.prevent.stop="onContextmenu">
|
<div :class="[$style.header, { [$style.mini]: mini }]" @contextmenu.prevent.stop="onContextmenu">
|
||||||
<span :class="$style.headerLeft">
|
<span :class="$style.headerLeft">
|
||||||
<button v-for="button in buttonsLeft" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button>
|
<button v-for="button in buttonsLeft" v-if="!minimized" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button>
|
||||||
</span>
|
</span>
|
||||||
<span :class="$style.headerTitle" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
|
<span :class="$style.headerTitle" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</span>
|
</span>
|
||||||
<span :class="$style.headerRight">
|
<span :class="$style.headerRight">
|
||||||
<button v-for="button in buttonsRight" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button>
|
<button v-for="button in buttonsRight" v-if="!minimized" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button>
|
||||||
|
<button v-if="canResize && minimized" v-tooltip="i18n.ts.windowRestore" class="_button" :class="$style.headerButton" @click="unMinimize()"><i class="ti ti-maximize"></i></button>
|
||||||
|
<button v-else-if="canResize && !maximized" v-tooltip="i18n.ts.windowMinimize" class="_button" :class="$style.headerButton" @click="minimize()"><i class="ti ti-minimize"></i></button>
|
||||||
<button v-if="canResize && maximized" v-tooltip="i18n.ts.windowRestore" class="_button" :class="$style.headerButton" @click="unMaximize()"><i class="ti ti-picture-in-picture"></i></button>
|
<button v-if="canResize && maximized" v-tooltip="i18n.ts.windowRestore" class="_button" :class="$style.headerButton" @click="unMaximize()"><i class="ti ti-picture-in-picture"></i></button>
|
||||||
<button v-else-if="canResize && !maximized" v-tooltip="i18n.ts.windowMaximize" class="_button" :class="$style.headerButton" @click="maximize()"><i class="ti ti-rectangle"></i></button>
|
<button v-else-if="canResize && !maximized && !minimized" v-tooltip="i18n.ts.windowMaximize" class="_button" :class="$style.headerButton" @click="maximize()"><i class="ti ti-rectangle"></i></button>
|
||||||
<button v-if="closeButton" v-tooltip="i18n.ts.close" class="_button" :class="$style.headerButton" @click="close()"><i class="ti ti-x"></i></button>
|
<button v-if="closeButton" v-tooltip="i18n.ts.close" class="_button" :class="$style.headerButton" @click="close()"><i class="ti ti-x"></i></button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +29,7 @@
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="canResize">
|
<template v-if="canResize && !minimized">
|
||||||
<div :class="$style.handleTop" @mousedown.prevent="onTopHandleMousedown"></div>
|
<div :class="$style.handleTop" @mousedown.prevent="onTopHandleMousedown"></div>
|
||||||
<div :class="$style.handleRight" @mousedown.prevent="onRightHandleMousedown"></div>
|
<div :class="$style.handleRight" @mousedown.prevent="onRightHandleMousedown"></div>
|
||||||
<div :class="$style.handleBottom" @mousedown.prevent="onBottomHandleMousedown"></div>
|
<div :class="$style.handleBottom" @mousedown.prevent="onBottomHandleMousedown"></div>
|
||||||
|
@ -100,10 +102,11 @@ let rootEl = $shallowRef<HTMLElement | null>();
|
||||||
let showing = $ref(true);
|
let showing = $ref(true);
|
||||||
let beforeClickedAt = 0;
|
let beforeClickedAt = 0;
|
||||||
let maximized = $ref(false);
|
let maximized = $ref(false);
|
||||||
let unMaximizedTop = '';
|
let minimized = $ref(false);
|
||||||
let unMaximizedLeft = '';
|
let unResizedTop = '';
|
||||||
let unMaximizedWidth = '';
|
let unResizedLeft = '';
|
||||||
let unMaximizedHeight = '';
|
let unResizedWidth = '';
|
||||||
|
let unResizedHeight = '';
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
showing = false;
|
showing = false;
|
||||||
|
@ -132,10 +135,10 @@ function top() {
|
||||||
|
|
||||||
function maximize() {
|
function maximize() {
|
||||||
maximized = true;
|
maximized = true;
|
||||||
unMaximizedTop = rootEl.style.top;
|
unResizedTop = rootEl.style.top;
|
||||||
unMaximizedLeft = rootEl.style.left;
|
unResizedLeft = rootEl.style.left;
|
||||||
unMaximizedWidth = rootEl.style.width;
|
unResizedWidth = rootEl.style.width;
|
||||||
unMaximizedHeight = rootEl.style.height;
|
unResizedHeight = rootEl.style.height;
|
||||||
rootEl.style.top = '0';
|
rootEl.style.top = '0';
|
||||||
rootEl.style.left = '0';
|
rootEl.style.left = '0';
|
||||||
rootEl.style.width = '100%';
|
rootEl.style.width = '100%';
|
||||||
|
@ -144,10 +147,35 @@ function maximize() {
|
||||||
|
|
||||||
function unMaximize() {
|
function unMaximize() {
|
||||||
maximized = false;
|
maximized = false;
|
||||||
rootEl.style.top = unMaximizedTop;
|
rootEl.style.top = unResizedTop;
|
||||||
rootEl.style.left = unMaximizedLeft;
|
rootEl.style.left = unResizedLeft;
|
||||||
rootEl.style.width = unMaximizedWidth;
|
rootEl.style.width = unResizedWidth;
|
||||||
rootEl.style.height = unMaximizedHeight;
|
rootEl.style.height = unResizedHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function minimize() {
|
||||||
|
minimized = true;
|
||||||
|
unResizedWidth = rootEl.style.width;
|
||||||
|
unResizedHeight = rootEl.style.height;
|
||||||
|
rootEl.style.width = minWidth + 'px';
|
||||||
|
rootEl.style.height = props.mini ? '32px' : '39px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function unMinimize() {
|
||||||
|
const main = rootEl;
|
||||||
|
if (main == null) return;
|
||||||
|
|
||||||
|
minimized = false;
|
||||||
|
rootEl.style.width = unResizedWidth;
|
||||||
|
rootEl.style.height = unResizedHeight;
|
||||||
|
const browserWidth = window.innerWidth;
|
||||||
|
const browserHeight = window.innerHeight;
|
||||||
|
const windowWidth = main.offsetWidth;
|
||||||
|
const windowHeight = main.offsetHeight;
|
||||||
|
|
||||||
|
const position = main.getBoundingClientRect();
|
||||||
|
if (position.top + windowHeight > browserHeight) main.style.top = browserHeight - windowHeight + 'px';
|
||||||
|
if (position.left + windowWidth > browserWidth) main.style.left = browserWidth - windowWidth + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBodyMousedown() {
|
function onBodyMousedown() {
|
||||||
|
@ -155,7 +183,7 @@ function onBodyMousedown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDblClick() {
|
function onDblClick() {
|
||||||
maximize();
|
if (minimized) {unMinimize();} else {maximize();}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHeaderMousedown(evt: MouseEvent) {
|
function onHeaderMousedown(evt: MouseEvent) {
|
||||||
|
@ -187,7 +215,7 @@ function onHeaderMousedown(evt: MouseEvent) {
|
||||||
|
|
||||||
const clickX = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientX : evt.clientX;
|
const clickX = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientX : evt.clientX;
|
||||||
const clickY = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientY : evt.clientY;
|
const clickY = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientY : evt.clientY;
|
||||||
const moveBaseX = beforeMaximized ? parseInt(unMaximizedWidth, 10) / 2 : clickX - position.left; // TODO: parseIntやめる
|
const moveBaseX = beforeMaximized ? parseInt(unResizedWidth, 10) / 2 : clickX - position.left; // TODO: parseIntやめる
|
||||||
const moveBaseY = beforeMaximized ? 20 : clickY - position.top;
|
const moveBaseY = beforeMaximized ? 20 : clickY - position.top;
|
||||||
const browserWidth = window.innerWidth;
|
const browserWidth = window.innerWidth;
|
||||||
const browserHeight = window.innerHeight;
|
const browserHeight = window.innerHeight;
|
||||||
|
|
Loading…
Reference in New Issue