2020-10-17 11:12:00 +00:00
|
|
|
<template>
|
2023-01-14 02:39:35 +00:00
|
|
|
<Transition
|
2023-04-01 04:42:40 +00:00
|
|
|
:enter-active-class="defaultStore.state.animation ? $style.transition_window_enterActive : ''"
|
|
|
|
:leave-active-class="defaultStore.state.animation ? $style.transition_window_leaveActive : ''"
|
|
|
|
:enter-from-class="defaultStore.state.animation ? $style.transition_window_enterFrom : ''"
|
|
|
|
:leave-to-class="defaultStore.state.animation ? $style.transition_window_leaveTo : ''"
|
2023-01-14 02:39:35 +00:00
|
|
|
appear
|
|
|
|
@after-leave="$emit('closed')"
|
|
|
|
>
|
|
|
|
<div v-if="showing" ref="rootEl" :class="[$style.root, { [$style.maximized]: maximized }]">
|
|
|
|
<div :class="$style.body" class="_shadow" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
|
|
|
<div :class="[$style.header, { [$style.mini]: mini }]" @contextmenu.prevent.stop="onContextmenu">
|
2023-04-08 04:01:28 +00:00
|
|
|
<span :class="$style.headerLeft">
|
|
|
|
<template v-if="!minimized">
|
|
|
|
<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>
|
|
|
|
</template>
|
2021-10-08 13:03:06 +00:00
|
|
|
</span>
|
2023-01-14 02:39:35 +00:00
|
|
|
<span :class="$style.headerTitle" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
|
2020-10-17 11:12:00 +00:00
|
|
|
<slot name="header"></slot>
|
|
|
|
</span>
|
2023-01-14 02:39:35 +00:00
|
|
|
<span :class="$style.headerRight">
|
2023-04-08 03:57:05 +00:00
|
|
|
<template v-if="!minimized">
|
|
|
|
<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>
|
|
|
|
</template>
|
2023-04-08 03:55:05 +00:00
|
|
|
<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>
|
2023-01-14 02:39:35 +00:00
|
|
|
<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>
|
2023-04-08 03:55:05 +00:00
|
|
|
<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>
|
2023-01-14 02:39:35 +00:00
|
|
|
<button v-if="closeButton" v-tooltip="i18n.ts.close" class="_button" :class="$style.headerButton" @click="close()"><i class="ti ti-x"></i></button>
|
2021-10-08 13:03:06 +00:00
|
|
|
</span>
|
2020-10-17 11:12:00 +00:00
|
|
|
</div>
|
2023-03-02 23:48:52 +00:00
|
|
|
<div v-container :class="$style.content">
|
2020-10-17 11:12:00 +00:00
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-04-08 03:55:05 +00:00
|
|
|
<template v-if="canResize && !minimized">
|
2023-01-14 02:39:35 +00:00
|
|
|
<div :class="$style.handleTop" @mousedown.prevent="onTopHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleRight" @mousedown.prevent="onRightHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleBottom" @mousedown.prevent="onBottomHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleLeft" @mousedown.prevent="onLeftHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleTopLeft" @mousedown.prevent="onTopLeftHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleTopRight" @mousedown.prevent="onTopRightHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleBottomRight" @mousedown.prevent="onBottomRightHandleMousedown"></div>
|
|
|
|
<div :class="$style.handleBottomLeft" @mousedown.prevent="onBottomLeftHandleMousedown"></div>
|
2020-10-17 11:12:00 +00:00
|
|
|
</template>
|
|
|
|
</div>
|
2022-12-30 04:37:14 +00:00
|
|
|
</Transition>
|
2020-10-17 11:12:00 +00:00
|
|
|
</template>
|
|
|
|
|
2022-07-17 15:31:55 +00:00
|
|
|
<script lang="ts" setup>
|
|
|
|
import { onBeforeUnmount, onMounted, provide } from 'vue';
|
2021-11-11 17:02:25 +00:00
|
|
|
import contains from '@/scripts/contains';
|
|
|
|
import * as os from '@/os';
|
2022-07-17 15:31:55 +00:00
|
|
|
import { MenuItem } from '@/types/menu';
|
2022-12-20 06:11:20 +00:00
|
|
|
import { i18n } from '@/i18n';
|
2023-04-01 04:42:40 +00:00
|
|
|
import { defaultStore } from '@/store';
|
2020-10-17 11:12:00 +00:00
|
|
|
|
|
|
|
const minHeight = 50;
|
|
|
|
const minWidth = 250;
|
|
|
|
|
2022-07-17 15:31:55 +00:00
|
|
|
function dragListen(fn: (ev: MouseEvent) => void) {
|
2022-06-20 08:38:49 +00:00
|
|
|
window.addEventListener('mousemove', fn);
|
|
|
|
window.addEventListener('touchmove', fn);
|
2020-10-17 11:12:00 +00:00
|
|
|
window.addEventListener('mouseleave', dragClear.bind(null, fn));
|
2022-06-20 08:38:49 +00:00
|
|
|
window.addEventListener('mouseup', dragClear.bind(null, fn));
|
|
|
|
window.addEventListener('touchend', dragClear.bind(null, fn));
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function dragClear(fn) {
|
2022-06-20 08:38:49 +00:00
|
|
|
window.removeEventListener('mousemove', fn);
|
|
|
|
window.removeEventListener('touchmove', fn);
|
2020-10-17 11:12:00 +00:00
|
|
|
window.removeEventListener('mouseleave', dragClear);
|
2022-06-20 08:38:49 +00:00
|
|
|
window.removeEventListener('mouseup', dragClear);
|
|
|
|
window.removeEventListener('touchend', dragClear);
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
|
|
|
|
2022-07-17 15:31:55 +00:00
|
|
|
const props = withDefaults(defineProps<{
|
2023-01-07 05:44:50 +00:00
|
|
|
initialWidth: number;
|
|
|
|
initialHeight: number | null;
|
2022-07-17 15:31:55 +00:00
|
|
|
canResize?: boolean;
|
|
|
|
closeButton?: boolean;
|
|
|
|
mini?: boolean;
|
|
|
|
front?: boolean;
|
|
|
|
contextmenu?: MenuItem[] | null;
|
|
|
|
buttonsLeft?: any[];
|
|
|
|
buttonsRight?: any[];
|
|
|
|
}>(), {
|
|
|
|
initialWidth: 400,
|
|
|
|
initialHeight: null,
|
|
|
|
canResize: false,
|
|
|
|
closeButton: true,
|
|
|
|
mini: false,
|
2022-07-18 16:20:36 +00:00
|
|
|
front: false,
|
2022-07-17 15:31:55 +00:00
|
|
|
contextmenu: null,
|
|
|
|
buttonsLeft: () => [],
|
|
|
|
buttonsRight: () => [],
|
|
|
|
});
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
(ev: 'closed'): void;
|
|
|
|
}>();
|
|
|
|
|
|
|
|
provide('inWindow', true);
|
|
|
|
|
2023-01-03 01:12:37 +00:00
|
|
|
let rootEl = $shallowRef<HTMLElement | null>();
|
2022-07-17 15:31:55 +00:00
|
|
|
let showing = $ref(true);
|
|
|
|
let beforeClickedAt = 0;
|
|
|
|
let maximized = $ref(false);
|
2023-04-08 03:55:05 +00:00
|
|
|
let minimized = $ref(false);
|
|
|
|
let unResizedTop = '';
|
|
|
|
let unResizedLeft = '';
|
|
|
|
let unResizedWidth = '';
|
|
|
|
let unResizedHeight = '';
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
function close() {
|
|
|
|
showing = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onKeydown(evt) {
|
|
|
|
if (evt.which === 27) { // Esc
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onContextmenu(ev: MouseEvent) {
|
|
|
|
if (props.contextmenu) {
|
|
|
|
os.contextMenu(props.contextmenu, ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 最前面へ移動
|
|
|
|
function top() {
|
2022-07-17 20:03:39 +00:00
|
|
|
if (rootEl) {
|
|
|
|
rootEl.style.zIndex = os.claimZIndex(props.front ? 'middle' : 'low');
|
|
|
|
}
|
2022-07-17 15:31:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function maximize() {
|
|
|
|
maximized = true;
|
2023-04-08 03:55:05 +00:00
|
|
|
unResizedTop = rootEl.style.top;
|
|
|
|
unResizedLeft = rootEl.style.left;
|
|
|
|
unResizedWidth = rootEl.style.width;
|
|
|
|
unResizedHeight = rootEl.style.height;
|
2022-07-17 15:31:55 +00:00
|
|
|
rootEl.style.top = '0';
|
|
|
|
rootEl.style.left = '0';
|
|
|
|
rootEl.style.width = '100%';
|
|
|
|
rootEl.style.height = '100%';
|
|
|
|
}
|
|
|
|
|
|
|
|
function unMaximize() {
|
|
|
|
maximized = false;
|
2023-04-08 03:55:05 +00:00
|
|
|
rootEl.style.top = unResizedTop;
|
|
|
|
rootEl.style.left = unResizedLeft;
|
|
|
|
rootEl.style.width = unResizedWidth;
|
|
|
|
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';
|
2022-07-17 15:31:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function onBodyMousedown() {
|
|
|
|
top();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onDblClick() {
|
2023-04-08 03:56:21 +00:00
|
|
|
if (minimized) {
|
|
|
|
unMinimize();
|
|
|
|
} else {
|
|
|
|
maximize();
|
|
|
|
}
|
2022-07-17 15:31:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function onHeaderMousedown(evt: MouseEvent) {
|
|
|
|
// 右クリックはコンテキストメニューを開こうとした可能性が高いため無視
|
|
|
|
if (evt.button === 2) return;
|
|
|
|
|
|
|
|
let beforeMaximized = false;
|
|
|
|
|
|
|
|
if (maximized) {
|
|
|
|
beforeMaximized = true;
|
|
|
|
unMaximize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ダブルクリック判定
|
|
|
|
if (Date.now() - beforeClickedAt < 300) {
|
|
|
|
beforeClickedAt = Date.now();
|
|
|
|
onDblClick();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
beforeClickedAt = Date.now();
|
|
|
|
|
|
|
|
const main = rootEl;
|
2022-07-20 15:32:41 +00:00
|
|
|
if (main == null) return;
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
if (!contains(main, document.activeElement)) main.focus();
|
|
|
|
|
|
|
|
const position = main.getBoundingClientRect();
|
|
|
|
|
|
|
|
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;
|
2023-04-08 03:55:05 +00:00
|
|
|
const moveBaseX = beforeMaximized ? parseInt(unResizedWidth, 10) / 2 : clickX - position.left; // TODO: parseIntやめる
|
2022-07-17 15:31:55 +00:00
|
|
|
const moveBaseY = beforeMaximized ? 20 : clickY - position.top;
|
|
|
|
const browserWidth = window.innerWidth;
|
|
|
|
const browserHeight = window.innerHeight;
|
|
|
|
const windowWidth = main.offsetWidth;
|
|
|
|
const windowHeight = main.offsetHeight;
|
|
|
|
|
|
|
|
function move(x: number, y: number) {
|
|
|
|
let moveLeft = x - moveBaseX;
|
|
|
|
let moveTop = y - moveBaseY;
|
|
|
|
|
|
|
|
// 下はみ出し
|
|
|
|
if (moveTop + windowHeight > browserHeight) moveTop = browserHeight - windowHeight;
|
|
|
|
|
|
|
|
// 左はみ出し
|
|
|
|
if (moveLeft < 0) moveLeft = 0;
|
|
|
|
|
|
|
|
// 上はみ出し
|
|
|
|
if (moveTop < 0) moveTop = 0;
|
|
|
|
|
|
|
|
// 右はみ出し
|
|
|
|
if (moveLeft + windowWidth > browserWidth) moveLeft = browserWidth - windowWidth;
|
|
|
|
|
|
|
|
rootEl.style.left = moveLeft + 'px';
|
|
|
|
rootEl.style.top = moveTop + 'px';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (beforeMaximized) {
|
|
|
|
move(clickX, clickY);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 動かした時
|
|
|
|
dragListen(me => {
|
|
|
|
const x = me.touches && me.touches.length > 0 ? me.touches[0].clientX : me.clientX;
|
|
|
|
const y = me.touches && me.touches.length > 0 ? me.touches[0].clientY : me.clientY;
|
|
|
|
|
|
|
|
move(x, y);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 上ハンドル掴み時
|
|
|
|
function onTopHandleMousedown(evt) {
|
|
|
|
const main = rootEl;
|
2022-12-18 10:52:50 +00:00
|
|
|
// どういうわけかnullになることがある
|
|
|
|
if (main == null) return;
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
const base = evt.clientY;
|
|
|
|
const height = parseInt(getComputedStyle(main, '').height, 10);
|
|
|
|
const top = parseInt(getComputedStyle(main, '').top, 10);
|
|
|
|
|
|
|
|
// 動かした時
|
|
|
|
dragListen(me => {
|
|
|
|
const move = me.clientY - base;
|
|
|
|
if (top + move > 0) {
|
|
|
|
if (height + -move > minHeight) {
|
|
|
|
applyTransformHeight(height + -move);
|
|
|
|
applyTransformTop(top + move);
|
|
|
|
} else { // 最小の高さより小さくなろうとした時
|
|
|
|
applyTransformHeight(minHeight);
|
|
|
|
applyTransformTop(top + (height - minHeight));
|
|
|
|
}
|
|
|
|
} else { // 上のはみ出し時
|
|
|
|
applyTransformHeight(top + height);
|
|
|
|
applyTransformTop(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 右ハンドル掴み時
|
|
|
|
function onRightHandleMousedown(evt) {
|
|
|
|
const main = rootEl;
|
2022-12-18 10:52:50 +00:00
|
|
|
if (main == null) return;
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
const base = evt.clientX;
|
|
|
|
const width = parseInt(getComputedStyle(main, '').width, 10);
|
|
|
|
const left = parseInt(getComputedStyle(main, '').left, 10);
|
|
|
|
const browserWidth = window.innerWidth;
|
|
|
|
|
|
|
|
// 動かした時
|
|
|
|
dragListen(me => {
|
|
|
|
const move = me.clientX - base;
|
|
|
|
if (left + width + move < browserWidth) {
|
|
|
|
if (width + move > minWidth) {
|
|
|
|
applyTransformWidth(width + move);
|
|
|
|
} else { // 最小の幅より小さくなろうとした時
|
|
|
|
applyTransformWidth(minWidth);
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
2022-07-17 15:31:55 +00:00
|
|
|
} else { // 右のはみ出し時
|
|
|
|
applyTransformWidth(browserWidth - left);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 下ハンドル掴み時
|
|
|
|
function onBottomHandleMousedown(evt) {
|
|
|
|
const main = rootEl;
|
2022-12-18 10:52:50 +00:00
|
|
|
if (main == null) return;
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
const base = evt.clientY;
|
|
|
|
const height = parseInt(getComputedStyle(main, '').height, 10);
|
|
|
|
const top = parseInt(getComputedStyle(main, '').top, 10);
|
|
|
|
const browserHeight = window.innerHeight;
|
|
|
|
|
|
|
|
// 動かした時
|
|
|
|
dragListen(me => {
|
|
|
|
const move = me.clientY - base;
|
|
|
|
if (top + height + move < browserHeight) {
|
|
|
|
if (height + move > minHeight) {
|
|
|
|
applyTransformHeight(height + move);
|
|
|
|
} else { // 最小の高さより小さくなろうとした時
|
|
|
|
applyTransformHeight(minHeight);
|
|
|
|
}
|
|
|
|
} else { // 下のはみ出し時
|
|
|
|
applyTransformHeight(browserHeight - top);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2022-07-17 15:31:55 +00:00
|
|
|
// 左ハンドル掴み時
|
|
|
|
function onLeftHandleMousedown(evt) {
|
|
|
|
const main = rootEl;
|
2022-12-18 10:52:50 +00:00
|
|
|
if (main == null) return;
|
2022-07-17 15:31:55 +00:00
|
|
|
|
|
|
|
const base = evt.clientX;
|
|
|
|
const width = parseInt(getComputedStyle(main, '').width, 10);
|
|
|
|
const left = parseInt(getComputedStyle(main, '').left, 10);
|
|
|
|
|
|
|
|
// 動かした時
|
|
|
|
dragListen(me => {
|
|
|
|
const move = me.clientX - base;
|
|
|
|
if (left + move > 0) {
|
|
|
|
if (width + -move > minWidth) {
|
|
|
|
applyTransformWidth(width + -move);
|
|
|
|
applyTransformLeft(left + move);
|
|
|
|
} else { // 最小の幅より小さくなろうとした時
|
|
|
|
applyTransformWidth(minWidth);
|
|
|
|
applyTransformLeft(left + (width - minWidth));
|
2020-10-24 16:21:41 +00:00
|
|
|
}
|
2022-07-17 15:31:55 +00:00
|
|
|
} else { // 左のはみ出し時
|
|
|
|
applyTransformWidth(left + width);
|
|
|
|
applyTransformLeft(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 左上ハンドル掴み時
|
|
|
|
function onTopLeftHandleMousedown(evt) {
|
|
|
|
onTopHandleMousedown(evt);
|
|
|
|
onLeftHandleMousedown(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 右上ハンドル掴み時
|
|
|
|
function onTopRightHandleMousedown(evt) {
|
|
|
|
onTopHandleMousedown(evt);
|
|
|
|
onRightHandleMousedown(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 右下ハンドル掴み時
|
|
|
|
function onBottomRightHandleMousedown(evt) {
|
|
|
|
onBottomHandleMousedown(evt);
|
|
|
|
onRightHandleMousedown(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 左下ハンドル掴み時
|
|
|
|
function onBottomLeftHandleMousedown(evt) {
|
|
|
|
onBottomHandleMousedown(evt);
|
|
|
|
onLeftHandleMousedown(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 高さを適用
|
|
|
|
function applyTransformHeight(height) {
|
|
|
|
if (height > window.innerHeight) height = window.innerHeight;
|
|
|
|
rootEl.style.height = height + 'px';
|
|
|
|
}
|
|
|
|
|
|
|
|
// 幅を適用
|
|
|
|
function applyTransformWidth(width) {
|
|
|
|
if (width > window.innerWidth) width = window.innerWidth;
|
|
|
|
rootEl.style.width = width + 'px';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Y座標を適用
|
|
|
|
function applyTransformTop(top) {
|
|
|
|
rootEl.style.top = top + 'px';
|
|
|
|
}
|
|
|
|
|
|
|
|
// X座標を適用
|
|
|
|
function applyTransformLeft(left) {
|
|
|
|
rootEl.style.left = left + 'px';
|
|
|
|
}
|
|
|
|
|
|
|
|
function onBrowserResize() {
|
|
|
|
const main = rootEl;
|
2022-12-18 10:52:50 +00:00
|
|
|
if (main == null) return;
|
|
|
|
|
2022-07-17 15:31:55 +00:00
|
|
|
const position = main.getBoundingClientRect();
|
|
|
|
const browserWidth = window.innerWidth;
|
|
|
|
const browserHeight = window.innerHeight;
|
|
|
|
const windowWidth = main.offsetWidth;
|
|
|
|
const windowHeight = main.offsetHeight;
|
|
|
|
if (position.left < 0) main.style.left = '0'; // 左はみ出し
|
|
|
|
if (position.top + windowHeight > browserHeight) main.style.top = browserHeight - windowHeight + 'px'; // 下はみ出し
|
|
|
|
if (position.left + windowWidth > browserWidth) main.style.left = browserWidth - windowWidth + 'px'; // 右はみ出し
|
|
|
|
if (position.top < 0) main.style.top = '0'; // 上はみ出し
|
|
|
|
}
|
|
|
|
|
|
|
|
onMounted(() => {
|
2023-01-07 05:44:50 +00:00
|
|
|
applyTransformWidth(props.initialWidth);
|
2022-07-17 15:31:55 +00:00
|
|
|
if (props.initialHeight) applyTransformHeight(props.initialHeight);
|
|
|
|
|
|
|
|
applyTransformTop((window.innerHeight / 2) - (rootEl.offsetHeight / 2));
|
|
|
|
applyTransformLeft((window.innerWidth / 2) - (rootEl.offsetWidth / 2));
|
|
|
|
|
|
|
|
// 他のウィンドウ内のボタンなどを押してこのウィンドウが開かれた場合、親が最前面になろうとするのでそれに隠されないようにする
|
|
|
|
top();
|
|
|
|
|
|
|
|
window.addEventListener('resize', onBrowserResize);
|
|
|
|
});
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
window.removeEventListener('resize', onBrowserResize);
|
|
|
|
});
|
|
|
|
|
|
|
|
defineExpose({
|
|
|
|
close,
|
2020-10-17 11:12:00 +00:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
<style lang="scss" module>
|
|
|
|
.transition_window_enterActive,
|
|
|
|
.transition_window_leaveActive {
|
2021-10-16 10:30:31 +00:00
|
|
|
transition: opacity 0.2s, transform 0.2s !important;
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
2023-01-14 02:39:35 +00:00
|
|
|
.transition_window_enterFrom,
|
|
|
|
.transition_window_leaveTo {
|
2020-10-17 11:12:00 +00:00
|
|
|
pointer-events: none;
|
|
|
|
opacity: 0;
|
|
|
|
transform: scale(0.9);
|
|
|
|
}
|
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.root {
|
2020-10-17 11:12:00 +00:00
|
|
|
position: fixed;
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
2021-02-27 04:08:34 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
&.maximized {
|
|
|
|
> .body {
|
|
|
|
border-radius: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.body {
|
|
|
|
overflow: clip;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
contain: content;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
border-radius: var(--radius);
|
|
|
|
}
|
2021-02-27 04:08:34 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.header {
|
|
|
|
--height: 39px;
|
2021-02-27 04:08:34 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
&.mini {
|
|
|
|
--height: 32px;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
display: flex;
|
|
|
|
position: relative;
|
|
|
|
z-index: 1;
|
|
|
|
flex-shrink: 0;
|
|
|
|
user-select: none;
|
|
|
|
height: var(--height);
|
|
|
|
background: var(--windowHeader);
|
|
|
|
-webkit-backdrop-filter: var(--blur, blur(15px));
|
|
|
|
backdrop-filter: var(--blur, blur(15px));
|
|
|
|
//border-bottom: solid 1px var(--divider);
|
2023-03-01 08:30:23 +00:00
|
|
|
font-size: 90%;
|
2023-01-14 02:39:35 +00:00
|
|
|
font-weight: bold;
|
|
|
|
}
|
2022-06-20 08:38:49 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.headerButton {
|
|
|
|
height: var(--height);
|
|
|
|
width: var(--height);
|
2021-12-24 03:34:24 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
&:hover {
|
|
|
|
color: var(--fgHighlighted);
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
&.highlighted {
|
|
|
|
color: var(--accent);
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
2023-01-14 02:39:35 +00:00
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.headerLeft {
|
|
|
|
margin-right: 16px;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.headerRight {
|
|
|
|
min-width: 16px;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.headerTitle {
|
|
|
|
flex: 1;
|
|
|
|
position: relative;
|
|
|
|
line-height: var(--height);
|
|
|
|
white-space: nowrap;
|
|
|
|
overflow: hidden;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
cursor: move;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.content {
|
|
|
|
flex: 1;
|
|
|
|
overflow: auto;
|
|
|
|
background: var(--panel);
|
|
|
|
container-type: inline-size;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
$handleSize: 8px;
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handle {
|
|
|
|
position: absolute;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handleTop {
|
|
|
|
composes: handle;
|
|
|
|
top: -($handleSize);
|
|
|
|
left: 0;
|
|
|
|
width: 100%;
|
|
|
|
height: $handleSize;
|
|
|
|
cursor: ns-resize;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handleRight {
|
|
|
|
composes: handle;
|
|
|
|
top: 0;
|
|
|
|
right: -($handleSize);
|
|
|
|
width: $handleSize;
|
|
|
|
height: 100%;
|
|
|
|
cursor: ew-resize;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handleBottom {
|
|
|
|
composes: handle;
|
|
|
|
bottom: -($handleSize);
|
|
|
|
left: 0;
|
|
|
|
width: 100%;
|
|
|
|
height: $handleSize;
|
|
|
|
cursor: ns-resize;
|
|
|
|
}
|
2020-10-17 11:12:00 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handleLeft {
|
|
|
|
composes: handle;
|
|
|
|
top: 0;
|
|
|
|
left: -($handleSize);
|
|
|
|
width: $handleSize;
|
|
|
|
height: 100%;
|
|
|
|
cursor: ew-resize;
|
|
|
|
}
|
2022-07-17 20:03:39 +00:00
|
|
|
|
2023-01-14 02:39:35 +00:00
|
|
|
.handleTopLeft {
|
|
|
|
composes: handle;
|
|
|
|
top: -($handleSize);
|
|
|
|
left: -($handleSize);
|
|
|
|
width: $handleSize * 2;
|
|
|
|
height: $handleSize * 2;
|
|
|
|
cursor: nwse-resize;
|
|
|
|
}
|
|
|
|
|
|
|
|
.handleTopRight {
|
|
|
|
composes: handle;
|
|
|
|
top: -($handleSize);
|
|
|
|
right: -($handleSize);
|
|
|
|
width: $handleSize * 2;
|
|
|
|
height: $handleSize * 2;
|
|
|
|
cursor: nesw-resize;
|
|
|
|
}
|
|
|
|
|
|
|
|
.handleBottomRight {
|
|
|
|
composes: handle;
|
|
|
|
bottom: -($handleSize);
|
|
|
|
right: -($handleSize);
|
|
|
|
width: $handleSize * 2;
|
|
|
|
height: $handleSize * 2;
|
|
|
|
cursor: nwse-resize;
|
|
|
|
}
|
|
|
|
|
|
|
|
.handleBottomLeft {
|
|
|
|
composes: handle;
|
|
|
|
bottom: -($handleSize);
|
|
|
|
left: -($handleSize);
|
|
|
|
width: $handleSize * 2;
|
|
|
|
height: $handleSize * 2;
|
|
|
|
cursor: nesw-resize;
|
2020-10-17 11:12:00 +00:00
|
|
|
}
|
|
|
|
</style>
|