From e0cfcfac13552d2372d2f99233460e2f5b598a6e Mon Sep 17 00:00:00 2001 From: sthag Date: Mon, 27 Oct 2025 21:33:38 +0100 Subject: [PATCH] feat: Add and rename screens - Add windows screen - Add windows.js - Different variants of classes for drag and edge snap behaviour - Rename js files to better distinguish usage --- source/code/{_ui.js => drag.js} | 0 source/code/{_intro.js => intro.js} | 0 source/code/windows.js | 282 ++++++++++++++++++ source/screens/demo/examples/intro.njk | 2 +- source/screens/demo/examples/ui/drag.liquid | 2 +- .../screens/demo/examples/ui/windows.liquid | 30 ++ source/style/modules/ui/_windows_module.scss | 36 +++ source/style/ui.scss | 1 + 8 files changed, 351 insertions(+), 2 deletions(-) rename source/code/{_ui.js => drag.js} (100%) rename source/code/{_intro.js => intro.js} (100%) create mode 100644 source/code/windows.js create mode 100644 source/screens/demo/examples/ui/windows.liquid create mode 100644 source/style/modules/ui/_windows_module.scss diff --git a/source/code/_ui.js b/source/code/drag.js similarity index 100% rename from source/code/_ui.js rename to source/code/drag.js diff --git a/source/code/_intro.js b/source/code/intro.js similarity index 100% rename from source/code/_intro.js rename to source/code/intro.js diff --git a/source/code/windows.js b/source/code/windows.js new file mode 100644 index 0000000..6c68eec --- /dev/null +++ b/source/code/windows.js @@ -0,0 +1,282 @@ +class Draggable { + constructor(element) { + this.element = element; + this.offsetX = 0; + this.offsetY = 0; + this.isDragging = false; + this.barSize = ''; + + this.init(); + } + + init() { + this.element.addEventListener('mousedown', this.onMouseDown.bind(this)); + document.addEventListener('mousemove', this.onMouseMove.bind(this)); + document.addEventListener('mouseup', this.onMouseUp.bind(this)); + this.setPosition('bottom'); + } + + onMouseDown(event) { + this.isDragging = true; + this.offsetX = event.clientX - this.element.getBoundingClientRect().left; + this.offsetY = event.clientY - this.element.getBoundingClientRect().top; + + event.preventDefault(); + } + + onMouseMove(event) { + if (!this.isDragging) { + return; + } + + let x = event.clientX - this.offsetX; + let y = event.clientY - this.offsetY; + + // Update the position of the element + this.element.style.left = `${x}px`; + this.element.style.top = `${y}px`; + } + + onMouseUp() { + if (!this.isDragging) { + return; + } + this.isDragging = false; + + this.snapToEdges(); + } + + snapToEdges() { + const rect = this.element.getBoundingClientRect(); + const windowWidth = window.innerWidth; + const windowHeight = window.innerHeight; + + // Determine the closest edge + const distances = { + left: rect.left, + right: windowWidth - rect.right, + top: rect.top, + bottom: windowHeight - rect.bottom + }; + + const closestEdge = Object.keys(distances).reduce((a, b) => distances[a] < distances[b] ? a : b); + + this.setPosition(closestEdge, this.barSize); + } + + setPosition(side, barSize) { + switch (side) { + case 'left': + // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position + this.element.style.top = '0px'; + this.element.style.right = ''; + this.element.style.bottom = '0px'; + this.element.style.left = '0px'; + this.element.style.width = barSize; + this.element.style.height = ''; + break; + case 'right': + // this.element.style.left = `${windowWidth - rect.width}px`; + // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position + this.element.style.top = '0px'; + this.element.style.right = '0px'; + this.element.style.bottom = '0px'; + this.element.style.left = ''; + this.element.style.width = barSize; + this.element.style.height = ''; + break; + case 'top': + // this.element.style.top = '0px'; + // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position + this.element.style.top = '0px'; + this.element.style.right = '0px'; + this.element.style.bottom = ''; + this.element.style.left = '0px'; + this.element.style.width = ''; + this.element.style.height = barSize; + break; + case 'bottom': + // this.element.style.top = `${windowHeight - rect.height}px`; + // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position + this.element.style.top = ''; + this.element.style.right = '0px'; + this.element.style.bottom = '0px'; + this.element.style.left = '0px'; + this.element.style.width = ''; + this.element.style.height = barSize; + break; + } + } +} + +class DragAdv { + constructor(element, placeholder) { + this.element = element; + this.placeholder = placeholder; + this.offsetX = 0; + this.offsetY = 0; + this.isDragging = false; + this.barSize = ''; + + this.init(); + } + + init() { + this.element.addEventListener('mousedown', this.onMouseDown.bind(this)); + document.addEventListener('mousemove', this.onMouseMove.bind(this)); + document.addEventListener('mouseup', this.onMouseUp.bind(this)); + this.setPosition('bottom'); + } + + onMouseDown(event) { + this.isDragging = true; + // this.offsetX = event.clientX - this.element.getBoundingClientRect().left; + // this.offsetY = event.clientY - this.element.getBoundingClientRect().top; + this.offsetX = 0; + this.offsetY = 0; + this.element.style.display = 'none'; + + this.showPlaceholder(); + event.preventDefault(); + } + + onMouseMove(event) { + if (!this.isDragging) return; + + let x = event.clientX - this.offsetX; + let y = event.clientY - this.offsetY; + + // Update the position of the element + // this.element.style.left = `${x}px`; + // this.element.style.top = `${y}px`; + // this.element.style.display = 'none'; + + // Update placeholder position + this.placeholder.style.left = `${x}px`; + this.placeholder.style.top = `${y}px`; + // this.placeholder.style.display = 'block'; + } + + onMouseUp() { + if (!this.isDragging) return; + this.isDragging = false; + + this.element.style.display = 'block'; + + this.snapToEdges(); + this.hidePlaceholder(); + } + + showPlaceholder() { + this.placeholder.style.display = 'block'; + } + + hidePlaceholder() { + this.placeholder.style.display = 'none'; + } + + snapToEdges() { + const rect = this.placeholder.getBoundingClientRect(); + const windowWidth = window.innerWidth; + const windowHeight = window.innerHeight; + + const distances = { + left: rect.left, + right: windowWidth - rect.right, + top: rect.top, + bottom: windowHeight - rect.bottom + }; + + const closestEdge = Object.keys(distances).reduce((a, b) => distances[a] < distances[b] ? a : b); + + console.log(rect); + console.log(closestEdge); + this.setPosition(closestEdge, this.barSize); + /*switch (closestEdge) { + case 'left': + this.element.style.left = '0px'; + this.element.style.top = `${rect.top}px`; + break; + case 'right': + this.element.style.left = `${windowWidth - rect.width}px`; + this.element.style.top = `${rect.top}px`; + break; + case 'top': + this.element.style.top = '0px'; + this.element.style.left = `${rect.left}px`; + break; + case 'bottom': + this.element.style.top = `${windowHeight - rect.height}px`; + this.element.style.left = `${rect.left}px`; + break; + }*/ + } + + setPosition(side, barSize) { + switch (side) { + case 'left': + // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position + this.element.style.top = '0px'; + this.element.style.right = ''; + this.element.style.bottom = '0px'; + this.element.style.left = '0px'; + this.element.style.width = barSize; + this.element.style.height = ''; + break; + case 'right': + // this.element.style.left = `${windowWidth - rect.width}px`; + // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position + this.element.style.top = '0px'; + this.element.style.right = '0px'; + this.element.style.bottom = '0px'; + this.element.style.left = ''; + this.element.style.width = barSize; + this.element.style.height = ''; + break; + case 'top': + // this.element.style.top = '0px'; + // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position + this.element.style.top = '0px'; + this.element.style.right = '0px'; + this.element.style.bottom = ''; + this.element.style.left = '0px'; + this.element.style.width = ''; + this.element.style.height = barSize; + break; + case 'bottom': + // this.element.style.top = `${windowHeight - rect.height}px`; + // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position + this.element.style.top = ''; + this.element.style.right = '0px'; + this.element.style.bottom = '0px'; + this.element.style.left = '0px'; + this.element.style.width = ''; + this.element.style.height = barSize; + break; + } + } +} + +class BestDrag { + #element; + + constructor(element) { + this.#setElement(element); + } + + #setElement(value) { + if (!value) { + throw new Error('No element found'); + } + this.#element = value; + this.#element.style.background = "hotpink"; + } + + get element() { + return this.#element; + } + + set element(value) { + this.#setElement(value); + } +} \ No newline at end of file diff --git a/source/screens/demo/examples/intro.njk b/source/screens/demo/examples/intro.njk index 1358739..548cc3f 100644 --- a/source/screens/demo/examples/intro.njk +++ b/source/screens/demo/examples/intro.njk @@ -49,7 +49,7 @@ tags: {%- block script %} {{ super() }} - + + + +{% endblock %} \ No newline at end of file diff --git a/source/style/modules/ui/_windows_module.scss b/source/style/modules/ui/_windows_module.scss new file mode 100644 index 0000000..0f46b78 --- /dev/null +++ b/source/style/modules/ui/_windows_module.scss @@ -0,0 +1,36 @@ +@use "sass:map"; + +@use "../../hippie-style/hippie"; + +#task-bar { + @extend %flex-inline; + z-index: map.get(hippie.$z-indexes, "content-top"); + align-items: stretch; + position: fixed; + //right: 0; + //bottom: 0; + //left: 0; + border: 1px solid transparent; + padding: hippie.$space_basic; + background-color: rgba(0, 0, 0, .1); + + button { + @extend .button_io; + overflow: hidden; + } +} + +#screen-space { + position: relative; + height: 100%; +} + +#placeholder { + display: none; + z-index: map.get(hippie.$z-indexes, "content-top"); + position: fixed; + width: 100px; + height: 100px; + border: 2px dashed deeppink; + background-color: hotpink; +} \ No newline at end of file diff --git a/source/style/ui.scss b/source/style/ui.scss index 4a1e6c8..da6ecf7 100644 --- a/source/style/ui.scss +++ b/source/style/ui.scss @@ -9,6 +9,7 @@ @use "modules/ui/form_module"; @use "modules/ui/game_module"; @use "modules/ui/gallery_module"; +@use "modules/ui/windows_module"; $color_gui_back: hippie.$color_dark; $space_gui_half: hippie.$space_half;