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
This commit is contained in:
sthag 2025-10-27 21:33:38 +01:00
parent 3c9c438b25
commit e0cfcfac13
8 changed files with 351 additions and 2 deletions

282
source/code/windows.js Normal file
View file

@ -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);
}
}

View file

@ -49,7 +49,7 @@ tags:
{%- block script %} {%- block script %}
{{ super() }} {{ super() }}
<script src="{{ pageBase }}js/_intro.js"></script> <script src="{{ pageBase }}js/intro.js"></script>
<script> <script>
//let intro = new Intro('Intro'); //let intro = new Intro('Intro');
//intro.init(); //intro.init();

View file

@ -22,7 +22,7 @@ tags:
{% endblock %} {% endblock %}
{%- block script %} {%- block script %}
<script src="{{ pageBase }}js/_ui.js"></script> <script src="{{ pageBase }}js/drag.js"></script>
<script> <script>
// Get the space element // Get the space element
const space = document.getElementById('space'); const space = document.getElementById('space');

View file

@ -0,0 +1,30 @@
---
title: Windows
tags:
- ui
---
{% assign bodyClass = "body_frame" -%}
{% layout "hippie/app.liquid" %}
{% block body %}
<nav id="task-bar">
<button data-action="start">Start</button>
</nav>
<div id="screen-space"></div>
<div id="placeholder"></div>
{% endblock %}
{%- block script %}
<script src="{{ pageBase }}js/windows.js"></script>
<script>
// Get the space element
const space = document.getElementById('screen-space');
const start = document.querySelector('[data-action=start]');
const draggableElement = document.getElementById('task-bar');
const placeholderElement = document.getElementById('placeholder');
// const draggable = new Draggable(draggableElement);
const dragMore = new DragAdv(draggableElement, placeholderElement);
// const dragBest = new BestDrag(draggableElement, placeholderElement);
</script>
{% endblock %}

View file

@ -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;
}

View file

@ -9,6 +9,7 @@
@use "modules/ui/form_module"; @use "modules/ui/form_module";
@use "modules/ui/game_module"; @use "modules/ui/game_module";
@use "modules/ui/gallery_module"; @use "modules/ui/gallery_module";
@use "modules/ui/windows_module";
$color_gui_back: hippie.$color_dark; $color_gui_back: hippie.$color_dark;
$space_gui_half: hippie.$space_half; $space_gui_half: hippie.$space_half;