functioning resize
This commit is contained in:
parent
96046dab3d
commit
f1c3d50930
|
@ -9,51 +9,42 @@
|
||||||
import NavItem from "components/common/NavItem.svelte"
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
import RoleIndicator from "./RoleIndicator.svelte"
|
import RoleIndicator from "./RoleIndicator.svelte"
|
||||||
import DropdownMenu from "./DropdownMenu.svelte"
|
import DropdownMenu from "./DropdownMenu.svelte"
|
||||||
import { onMount, tick } from "svelte"
|
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
import { getVerticalResizeActions } from './resizable';
|
||||||
|
import { tick } from "svelte"
|
||||||
|
|
||||||
let search = false
|
const [resizable, resizableHandle] = getVerticalResizeActions();
|
||||||
|
|
||||||
|
let searching = false
|
||||||
let resizing = false
|
let resizing = false
|
||||||
let searchValue = ""
|
let searchValue = ""
|
||||||
let searchInput
|
let searchInput
|
||||||
let container
|
let container
|
||||||
let screensContainer
|
let screensContainer
|
||||||
let scrolling = false
|
let scrolling = false
|
||||||
let previousHeight = null
|
|
||||||
let dragOffset
|
|
||||||
|
|
||||||
$: filteredScreens = getFilteredScreens($sortedScreens, searchValue)
|
$: filteredScreens = getFilteredScreens($sortedScreens, searchValue)
|
||||||
|
|
||||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
|
|
||||||
const openSearch = async () => {
|
const openSearch = async () => {
|
||||||
search = true
|
searching = true
|
||||||
await tick()
|
await tick()
|
||||||
searchInput.focus()
|
searchInput.focus()
|
||||||
screensContainer.scroll({ top: 0, behavior: "smooth" })
|
screensContainer.scroll({ top: 0, behavior: "smooth" })
|
||||||
previousHeight = $screensHeight
|
|
||||||
$screensHeight = "calc(100% + 1px)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeSearch = async () => {
|
const closeSearch = async () => {
|
||||||
if (previousHeight) {
|
searching = false
|
||||||
// Restore previous height and wait for animation
|
|
||||||
$screensHeight = previousHeight
|
|
||||||
previousHeight = null
|
|
||||||
await sleep(300)
|
|
||||||
}
|
|
||||||
search = false
|
|
||||||
searchValue = ""
|
searchValue = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFilteredScreens = (screens, search) => {
|
const getFilteredScreens = (screens, searchValue) => {
|
||||||
return screens.filter(screen => {
|
return screens.filter(screen => {
|
||||||
return !search || screen.routing.route.includes(search)
|
return !searchValue || screen.routing.route.includes(searchValue)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddButton = () => {
|
const handleAddButton = () => {
|
||||||
if (search) {
|
if (searching) {
|
||||||
closeSearch()
|
closeSearch()
|
||||||
} else {
|
} else {
|
||||||
$goto("../new")
|
$goto("../new")
|
||||||
|
@ -70,67 +61,35 @@
|
||||||
scrolling = e.target.scrollTop !== 0
|
scrolling = e.target.scrollTop !== 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const startResizing = e => {
|
|
||||||
// Reset the height store to match the true height
|
|
||||||
$screensHeight = `${container.getBoundingClientRect().height}px`
|
|
||||||
|
|
||||||
// Store an offset to easily compute new height when moving the mouse
|
|
||||||
dragOffset = parseInt($screensHeight) - e.clientY
|
|
||||||
|
|
||||||
// Add event listeners
|
|
||||||
resizing = true
|
|
||||||
document.addEventListener("mousemove", resize)
|
|
||||||
document.addEventListener("mouseup", stopResizing)
|
|
||||||
}
|
|
||||||
|
|
||||||
const resize = e => {
|
|
||||||
// Prevent negative heights as this screws with layout
|
|
||||||
const newHeight = Math.max(0, e.clientY + dragOffset)
|
|
||||||
if (newHeight == null || isNaN(newHeight)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
$screensHeight = `${newHeight}px`
|
|
||||||
}
|
|
||||||
|
|
||||||
const stopResizing = () => {
|
|
||||||
resizing = false
|
|
||||||
document.removeEventListener("mousemove", resize)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
// Ensure we aren't stuck at 100% height from leaving while searching
|
|
||||||
if ($screensHeight == null || isNaN(parseInt($screensHeight))) {
|
|
||||||
$screensHeight = "210px"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown} />
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
<div
|
<div
|
||||||
class="screens"
|
class="screens"
|
||||||
class:search
|
class:searching
|
||||||
class:resizing
|
class:resizing
|
||||||
style={`height:${$screensHeight};`}
|
style={`height:${$screensHeight};`}
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
|
use:resizable
|
||||||
>
|
>
|
||||||
<div class="header" class:scrolling>
|
<div class="header" class:scrolling>
|
||||||
<input
|
<input
|
||||||
readonly={!search}
|
readonly={!searching}
|
||||||
bind:value={searchValue}
|
bind:value={searchValue}
|
||||||
bind:this={searchInput}
|
bind:this={searchInput}
|
||||||
class="input"
|
class="input"
|
||||||
placeholder="Search for screens"
|
placeholder="Search for screens"
|
||||||
/>
|
/>
|
||||||
<div class="title" class:hide={search}>
|
<div on:click={openSearch} class="title" class:hide={searching}>
|
||||||
<Body size="S">Screens</Body>
|
<Body size="S">Screens</Body>
|
||||||
</div>
|
</div>
|
||||||
<div on:click={openSearch} class="searchButton" class:hide={search}>
|
<div on:click={openSearch} class="searchButton" class:hide={searching}>
|
||||||
<Icon size="S" name="Search" />
|
<Icon size="S" name="Search" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
on:click={handleAddButton}
|
on:click={handleAddButton}
|
||||||
class="addButton"
|
class="addButton"
|
||||||
class:closeButton={search}
|
class:closeButton={searching}
|
||||||
>
|
>
|
||||||
<Icon name="Add" />
|
<Icon name="Add" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -164,8 +123,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
disabled={searching}
|
||||||
class="divider"
|
class="divider"
|
||||||
on:mousedown={startResizing}
|
class:disabled={searching}
|
||||||
|
use:resizableHandle
|
||||||
on:dblclick={() => screensHeight.set("210px")}
|
on:dblclick={() => screensHeight.set("210px")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -177,10 +138,11 @@
|
||||||
min-height: 147px;
|
min-height: 147px;
|
||||||
max-height: calc(100% - 147px);
|
max-height: calc(100% - 147px);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
.screens.search {
|
|
||||||
transition: height 300ms ease-out;
|
transition: height 300ms ease-out;
|
||||||
|
}
|
||||||
|
.screens.searching {
|
||||||
max-height: none;
|
max-height: none;
|
||||||
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
.screens.resizing {
|
.screens.resizing {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
@ -219,7 +181,7 @@
|
||||||
.input::placeholder {
|
.input::placeholder {
|
||||||
color: var(--spectrum-global-color-gray-600);
|
color: var(--spectrum-global-color-gray-600);
|
||||||
}
|
}
|
||||||
.screens.search input {
|
.screens.searching input {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,4 +267,10 @@
|
||||||
.divider:hover:after {
|
.divider:hover:after {
|
||||||
background: var(--spectrum-global-color-gray-300);
|
background: var(--spectrum-global-color-gray-300);
|
||||||
}
|
}
|
||||||
|
.divider.disabled {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
.divider.disabled:after {
|
||||||
|
background: var(--spectrum-global-color-gray-200);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
export const getHorizontalResizeActions = (initialValue, setValue = () => {}) => {
|
||||||
|
let element = null;
|
||||||
|
|
||||||
|
const elementAction = (node) => {
|
||||||
|
element = node;
|
||||||
|
|
||||||
|
if (initialValue != null) {
|
||||||
|
element.style.height = `${initialValue}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragHandleAction = (node) => {
|
||||||
|
let startWidth = null;
|
||||||
|
let startPosition = null;
|
||||||
|
|
||||||
|
const handleMouseMove = (e) => {
|
||||||
|
const change = e.pageX - startPosition;
|
||||||
|
element.style.width = `${startWidth + change}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
window.removeEventListener("mousemove", handleMouseMove);
|
||||||
|
window.removeEventListener("mouseup", handleMouseUp);
|
||||||
|
element.style.removeProperty('transition'); // remove temporary transition override
|
||||||
|
setValue(element.clientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseDown = (e) => {
|
||||||
|
if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.style.transition = "width 0ms"; // temporarily override any width transitions
|
||||||
|
startWidth = element.clientWidth;
|
||||||
|
startPosition = e.pageX;
|
||||||
|
|
||||||
|
window.addEventListener("mousemove", handleMouseMove);
|
||||||
|
window.addEventListener("mouseup", handleMouseUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
node.addEventListener("mousedown", handleMouseDown);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener("mousedown", handleMouseDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
elementAction,
|
||||||
|
dragHandleAction
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getVerticalResizeActions = (initialValue, setValue = () => {}) => {
|
||||||
|
let element = null;
|
||||||
|
|
||||||
|
const elementAction = (node) => {
|
||||||
|
element = node;
|
||||||
|
|
||||||
|
if (initialValue != null) {
|
||||||
|
element.style.height = `${initialValue}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragHandleAction = (node) => {
|
||||||
|
let startHeight = null;
|
||||||
|
let startPosition = null;
|
||||||
|
|
||||||
|
const handleMouseMove = (e) => {
|
||||||
|
const change = e.pageY - startPosition;
|
||||||
|
element.style.height = `${startHeight + change}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
window.removeEventListener("mousemove", handleMouseMove);
|
||||||
|
window.removeEventListener("mouseup", handleMouseUp);
|
||||||
|
element.style.removeProperty('transition'); // remove temporary transition override
|
||||||
|
setValue(element.clientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseDown = (e) => {
|
||||||
|
if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.style.transition = "height 0ms"; // temporarily override any height transitions
|
||||||
|
startHeight = element.clientHeight;
|
||||||
|
startPosition = e.pageY;
|
||||||
|
|
||||||
|
window.addEventListener("mousemove", handleMouseMove);
|
||||||
|
window.addEventListener("mouseup", handleMouseUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
node.addEventListener("mousedown", handleMouseDown);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener("mousedown", handleMouseDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
elementAction,
|
||||||
|
dragHandleAction
|
||||||
|
]
|
||||||
|
};
|
Loading…
Reference in New Issue