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