Compare commits

..

12 commits

Author SHA1 Message Date
6098a1e62d feat: Style and content for windows 2025-10-27 23:24:49 +01:00
1ada62f6ec feat: Optimize DragAdv class
- Only use left mouse button
- Handle element and placeholder together
2025-10-27 23:24:37 +01:00
0996ace34f fix: Task bar drag behaviour
- Placeholder is centered to mouse cursor
- Placeholder is positioned on mouse down not only on move
2025-10-27 21:54:36 +01:00
e0cfcfac13 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
2025-10-27 21:33:38 +01:00
3c9c438b25 feat: Add game and gallery screens 2025-10-27 21:23:26 +01:00
e21b9d36b5 feat: Replace form screen with liquid version 2025-10-27 21:16:41 +01:00
ff5d4bd3eb feat: Add jquery dependency
- Add jquery version 3.7.1
- Remove external script resource from app template
- Add eleventy passthrough to build/vendor
2025-10-27 21:15:57 +01:00
c77bcd8bdc feat: Replace ui drag screen with liquid template
- Recreate io macros as liquid partials
- Add app template based on default
- Drag screen uses app.liquid layout instead of _app_frame.njk
2025-10-27 20:51:17 +01:00
6b644ca9f3 feat: Add macro for frame status bar 2025-10-27 20:41:38 +01:00
46988576a9 fix: Typo in css class 2025-10-27 20:40:18 +01:00
afc733f4d4 feat: Replace default screen using liquid instead of nunjucks 2025-10-26 15:29:12 +01:00
07656b404f feat: Introduce liquid templates 2025-10-26 15:19:14 +01:00
32 changed files with 860 additions and 145 deletions

View file

@ -1,6 +1,14 @@
module.exports = function (eleventyConfig) {
// eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
eleventyConfig.setLiquidOptions({
// greedy: false,
// trimOutputLeft: true,
// trimOutputRight: true,
// trimTagLeft: true,
// trimTagRight : true,
});
eleventyConfig.setNunjucksEnvironmentOptions({
// throwOnUndefined: true,
trimBlocks: true
@ -32,6 +40,10 @@ module.exports = function (eleventyConfig) {
eleventyConfig.addPassthroughCopy("vendor");
eleventyConfig.addPassthroughCopy({"node_modules/bootstrap-icons": "vendor/bootstrap-icons"});
eleventyConfig.addPassthroughCopy({
"node_modules/jquery/dist/jquery.min.js": "vendor",
"node_modules/jquery/dist/jquery.min.map": "vendor"
});
// eleventyConfig.addPassthroughCopy({"node_modules/normalize.css/normalize.css": "vendor/normalize.css"});
eleventyConfig.addWatchTarget("./source/style/");
@ -43,9 +55,7 @@ module.exports = function (eleventyConfig) {
includes: "../templates",
data: "../data"
},
markdownTemplateEngine: "njk",
htmlTemplateEngine: "njk",
templateFormats: ["html", "njk", "md"],
templateFormats: ["html", "liquid", "njk", "md"]
// pathPrefix: './demo/'
}
};
};

7
package-lock.json generated
View file

@ -11,6 +11,7 @@
"dependencies": {
"@11ty/eleventy": "^2.0.1",
"bootstrap-icons": "^1.13.1",
"jquery": "^3.7.1",
"sass": "^1.93.0"
},
"devDependencies": {
@ -1583,6 +1584,12 @@
"node": ">=10"
}
},
"node_modules/jquery": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
"license": "MIT"
},
"node_modules/js-stringify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",

View file

@ -36,6 +36,7 @@
"dependencies": {
"@11ty/eleventy": "^2.0.1",
"bootstrap-icons": "^1.13.1",
"jquery": "^3.7.1",
"sass": "^1.93.0"
}
}
}

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

@ -0,0 +1,280 @@
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);
/*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;
}*/
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', this.barSize);
}
onMouseDown(event) {
if (event.button === 0) {
this.isDragging = true;
this.showPlaceholder();
this.offsetX = this.placeholder.getBoundingClientRect().width / 2;
this.offsetY = this.placeholder.getBoundingClientRect().height / 2;
let x = event.clientX - this.offsetX;
let y = event.clientY - this.offsetY;
this.placeholder.style.left = `${x}px`;
this.placeholder.style.top = `${y}px`;
}
event.preventDefault();
}
onMouseMove(event) {
if (!this.isDragging) return;
let x = event.clientX - this.offsetX;
let y = event.clientY - this.offsetY;
this.placeholder.style.left = `${x}px`;
this.placeholder.style.top = `${y}px`;
}
onMouseUp() {
if (!this.isDragging) return;
this.isDragging = false;
this.snapToEdges();
this.hidePlaceholder();
}
showPlaceholder() {
this.element.style.display = 'none';
this.placeholder.style.display = 'block';
}
hidePlaceholder() {
this.placeholder.style.display = 'none';
this.element.style.display = '';
}
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);
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 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

@ -25,7 +25,7 @@ tags:
<div class="demo__queries">
<p class="query_phoneUp">Telefone und größer</p>
<p class="query_phoneOnly">Nur Telefone</p>
<p class="query_tabletPortaitOnly">Nur Schreibtafeln hochkant</p>
<p class="query_tabletPortraitOnly">Nur Schreibtafeln hochkant</p>
<p class="query_tabletPortraitUp">Schreibtafeln und größer</p>
<p class="query_tabletLandscapeOnly">Schreibtafeln im Querformat</p>
<p class="query_tabletLandscapeUp">Schreibtafeln quer und größer</p>

View file

@ -0,0 +1,25 @@
---
title: Game - TFW
tags:
- demoExample
- gameExample
---
{% assign bodyClass = "body_game" -%}
{% layout "hippie/app.liquid" %}
{% block body %}
<div class="sec_main_center">
<nav role="doc-toc">
<hgroup>
<h1>{{ title }}</h1>
<p>Additional name</p>
</hgroup>
<ul class="list_link">
<li><a href="#new">Neues Spiel</a></li>
<li><a href="#continue">Spiel fortsetzen</a></li>
<li><a href="#options">Einstellungen</a></li>
<li><a href="#quit">Spiel beenden</a></li>
</ul>
</nav>
</div>
{% endblock %}

View file

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

View file

@ -0,0 +1,48 @@
---
title: Drag
tags:
- ui
---
{% layout "hippie/app.liquid" %}
{% block body %}
<header class="io pos_fix pin_top pin_right pin_left">
<button data-action="add">Add</button>
</header>
<div id="space"></div>
<div>
<div id="test">
<div class="body_frame">
{% render 'hippie/partials/frame-header.liquid' %}
<main></main>
{% render 'hippie/partials/frame-mode.liquid' %}
</div>
</div>
</div>
{% endblock %}
{%- block script %}
<script src="{{ pageBase }}js/drag.js"></script>
<script>
// Get the space element
const space = document.getElementById('space');
const add = document.querySelector('[data-action=add]');
const test = document.getElementById('test');
// Add event listener to the add space button
add.addEventListener('click', () => {
const newDiv = new NewDiv(100, 100, 100, 100, getRandomColor());
newDiv.createDiv();
newDiv.appendToFrame(space);
});
// Create a new NewDiv instance
const newDiv = new NewDiv(100, 100, 200, 200, '#000');
newDiv.createDiv();
newDiv.appendToFrame(space);
const explorer = new NewDiv(256, 128, 800, 600, '#fff', test);
explorer.createDiv();
explorer.appendToFrame(space);
</script>
{% endblock %}

View file

@ -1,50 +0,0 @@
---
title: Drag
tags:
- ui
---
{% set pageId = page.fileSlug %}
{% extends "hippie/_app_frame.njk" %}
{% block body %}
<header class="io pos_fix pin_top pin_right pin_left">
<button data-action="add">Add</button>
</header>
<div id="space"></div>
<div>
<div id="test">
<div class="body_frame">
{{ io.frameHeader('title-bar') }}
<main></main>
{{ io.frameFooter('mode-bar') }}
</div>
</div>
</div>
{% endblock %}
{%- block script %}
<script src="{{ pageBase }}js/_ui.js"></script>
<script>
// Get the space element
const space = document.getElementById('space');
const add = document.querySelector('[data-action=add]');
const test = document.getElementById('test');
// Add event listener to the add space button
add.addEventListener('click', () => {
const newDiv = new NewDiv(100, 100, 100, 100, getRandomColor());
newDiv.createDiv();
newDiv.appendToFrame(space);
});
// Create a new NewDiv instance
const newDiv = new NewDiv(100, 100, 200, 200, '#000');
newDiv.createDiv();
newDiv.appendToFrame(space);
const explorer = new NewDiv(256, 128, 800, 600, '#fff', test);
explorer.createDiv();
explorer.appendToFrame(space);
</script>
{% endblock %}

View file

@ -12,7 +12,7 @@ tags:
<main class="io">
<aside class="io">
<nav>
<div>location-pane</div>
<span>location-pane</span>
<ul class="vertical">
<li>
<a class="a_button" href="">
@ -139,17 +139,7 @@ tags:
</tbody>
</table>
</div>
<footer class="io">
<nav>
<span>## items</span>
<span># selected (size)</span>
<span># type(s)</span>
<span># shared</span>
</nav>
<nav>
<span>status-bar</span>
</nav>
</footer>
{{ io.statusBar() }}
</section>
</main>
{{ io.frameFooter('mode-bar') }}

View file

@ -0,0 +1,56 @@
---
title: Form
tags:
- ui
---
{% assign bodyClass = "body_frame" -%}
{% layout "hippie/app.liquid" %}
{% block body %}
{% render 'hippie/partials/frame-header.liquid' %}
<header class="io">
<h1>Formulare</h1>
<button data-action="add">Hinzufügen</button>
<button data-action="change">Ändern</button>
<hr>
</header>
<form id="form" action="">
<div id="grid">
<div>a</div>
<div>b</div>
<div>c</div>
</div>
</form>
{% endblock %}
{%- block script %}
{{ block.super -}}
<script>
const add = document.querySelector('[data-action=add]');
const change = document.querySelector('[data-action=change]');
const grid = document.getElementById('grid');
add.addEventListener('click', (e) => {
const item = document.createElement('div');
item.style.backgroundColor = '#f0f';
item.textContent = 'c'
grid.appendChild(item);
});
change.addEventListener('click', (e) => {
changeLayout(grid);
});
function changeLayout(grid) {
const currentTemplate = grid.style.gridTemplateColumns;
if (currentTemplate === 'repeat(4, 1fr)') {
grid.style.gridTemplateColumns = 'repeat(2, 1fr)';
} else {
grid.style.gridTemplateColumns = 'repeat(4, 1fr)';
}
}
</script>
{% endblock %}

View file

@ -1,55 +0,0 @@
---
title: Form
tags:
- ui
---
{% extends "hippie/_app_frame.njk" %}
{% block body %}
{{ io.frameHeader('title-bar') }}
<header class="io">
<h1>Formulare</h1>
<button data-action="add">Hinzufügen</button>
<button data-action="change">Ändern</button>
<hr>
</header>
<form id="form" action="">
<div id="grid">
<div>a</div>
<div>b</div>
<div>c</div>
</div>
</form>
{% endblock %}
{%- block script %}
{{ super() }}
<script>
const add = document.querySelector('[data-action=add]');
const change = document.querySelector('[data-action=change]');
const grid = document.getElementById('grid');
add.addEventListener('click', (e) => {
const item = document.createElement('div');
item.style.backgroundColor = '#f0f';
item.textContent = 'c'
grid.appendChild(item);
});
change.addEventListener('click', (e) => {
changeLayout(grid);
});
function changeLayout(grid) {
const currentTemplate = grid.style.gridTemplateColumns;
if (currentTemplate === 'repeat(4, 1fr)') {
grid.style.gridTemplateColumns = 'repeat(2, 1fr)';
} else {
grid.style.gridTemplateColumns = 'repeat(4, 1fr)';
}
}
</script>
{% endblock %}

View file

@ -0,0 +1,77 @@
---
title: Gallery
tags:
- ui
---
{% assign bodyClass = "body_frame" -%}
{% layout "hippie/app.liquid" %}
{% block body %}
{% render 'hippie/partials/frame-header.liquid' %}
<main class="io">
<section>
<header class="io">
<nav>
<div class="group">
<input id="slider-size" value="5" min="1" max="10" step="1" type="range"/>
<label class="right" for="slider-size">Größe</label>
</div>
<button title="details">
<i class="bi bi-layout-sidebar-reverse"></i>&nbsp;Details
</button>
</nav>
<nav></nav>
</header>
<div class="gallery">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
{% render 'hippie/partials/frame-status.liquid' %}
</section>
</main>
{% render 'hippie/partials/frame-mode.liquid' %}
{% endblock %}
{%- block script %}
{{ block.super -}}
<script>
const sizeSlider = document.getElementById('slider-size');
const galleryItems = document.querySelectorAll('#flex > div');
// Set the default size
const defaultSize = 128; // In pixels
const minSize = 16; // Minimum width in pixels
const steps = 10;
// Define specific sizes for each step (from 1 to 10)
const sizes = [16, 32, 64, 96, 128, 256, 512, 1024, 2048]; // Sizes in pixels
// Calculate width based on slider value
function calculateWidth(value) {
// Map 1-10 to a pixel width
return Math.floor(minSize + (value - 1) * (defaultSize - minSize) / (steps - 1));
}
// Set initial size
galleryItems.forEach(item => {
item.style.width = `${defaultSize}px`;
item.style.width = `${sizes[5]}px`; // Initial width based on the default step (8 corresponds to index 7)
});
sizeSlider.addEventListener('input', function () {
// const newSize = calculateWidth(Number(sizeSlider.value));
// galleryItems.forEach(item => {
// item.style.width = `${newSize}px`;
// });
const selectedStep = Number(sizeSlider.value) - 1; // Adjust for zero-indexing
const newSize = sizes[selectedStep]; // Get size from the array using slider value
galleryItems.forEach(item => {
item.style.width = `${newSize}px`;
});
});
// Initialize slider to default
sizeSlider.value = 6; // Sets default to 128px width
</script>
{% endblock %}

View file

@ -0,0 +1,55 @@
---
title: Windows
tags:
- ui
---
{% assign bodyClass = "body_frame" -%}
{% layout "hippie/app.liquid" %}
{% block body %}
<div id="task-bar">
<nav>
<button data-action="start"><i class="bi bi-microsoft"></i></button>
</nav>
<nav>
<button><i class="bi bi-search"></i></button>
<button><i class="bi bi-layers-half"></i></button>
</nav>
<nav class="big">
<button><i class="bi bi-folder"></i></button>
<button><i class="bi bi-terminal"></i></button>
</nav>
<div>
<nav class="small">
<button><i class="bi bi-chevron-up"></i></button>
<button><i class="bi bi-steam"></i></button>
<button><i class="bi bi-router"></i></button>
<button><i class="bi bi-mic"></i></button>
<button><i class="bi bi-volume-down"></i></button>
</nav>
<nav class="clock">
<span>##:##<br>TT.MM.JJJJ</span>
</nav>
<nav>
<button data-action="notification"><i class="bi bi-bell-fill"></i></button>
</nav>
</div>
</div>
<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,18 @@
---
title: "Default"
---
{% assign pageBase = "../" -%}
{% assign pageId = page.fileSlug -%}
{% assign pageClass = "default" -%}
{% assign bodyClass = "default" -%}
{%- layout "hippie/default.liquid" %}
{% block title %}{{ title }}{% endblock %}
{% block script %}
{{ block.super -}}
<script>
// Page script
console.log("pageBase is: {{ pageBase }}");
</script>
{% endblock %}

View file

@ -1,21 +0,0 @@
---
title: Default
---
{% set pageBase = "../" %}
{% set pageId = page.fileSlug %}
{% extends "hippie/_default.njk" %}
{% block title %}{{ title }}{% endblock %}
{% block head %}
{{ super() }}
{% endblock %}
{% block body %}
<!-- {{ page.fileSlug }}.page -->
{% endblock %}
{% block script %}
{{ super() }}
{% endblock %}

View file

@ -0,0 +1,8 @@
---
title: "Hello World"
layout: hippie/world.liquid
---
# {{ title }}
This is a simple example for a *screen* written in Markdown, using Liquid *templates*.

View file

@ -0,0 +1,18 @@
@use "../../hippie-style/hippie";
.gallery {
display: flex;
flex-wrap: wrap;
justify-content: left;
align-items: start;
gap: 10px;
background-color: hippie.$color_back_io;
& > div {
background-color: hotpink;
aspect-ratio: 2 / 3;
width: 128px;
transition: width 0.3s ease;
}
}

View file

@ -0,0 +1,3 @@
.body_game {
background-color: hotpink;
}

View file

@ -0,0 +1,91 @@
@use "sass:map";
@use "../../hippie-style/hippie";
$padding_half: calc(#{hippie.$space_half} - 3px) hippie.$space_half;
%flex-bar {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: stretch;
align-content: center;
justify-content: flex-start;
gap: hippie.$space_half hippie.$space_basic;
}
#task-bar {
@extend %flex-bar;
z-index: map.get(hippie.$z-indexes, "content-top");
position: fixed;
//right: 0;
//bottom: 0;
//left: 0;
border: 1px solid transparent;
padding: hippie.$space_basic;
background-color: rgba(0, 0, 0, .1);
nav,
& > div {
@extend %flex-bar;
&:last-child {
margin-left: auto;
}
}
button {
@extend .button_io;
overflow: hidden;
}
nav.small {
//font-size: .8em;
button {
border: none;
padding: $padding_half;
&:hover {
background-color: transparent;
}
}
}
nav.big {
font-size: 1.5em;
button {
border: none;
padding: 0;
&:hover {
background-color: transparent;
}
}
}
.clock {
text-align: end;
&,
& > * {
line-height: 1;
}
}
}
#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/game_module";
@use "modules/ui/gallery_module";
@use "modules/ui/windows_module";
$color_gui_back: hippie.$color_dark;
$space_gui_half: hippie.$space_half;

View file

@ -0,0 +1,40 @@
{% assign pageBase = "../../../" -%}
{% assign pageId = page.fileSlug -%}
{% assign pageClass = "html_ui" -%}
{%- layout "hippie/default.liquid" %}
{% block title %}{{ title }}{% endblock %}
{% block links %}
{{ block.super -}}
<link href="/vendor/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet">
<link href="{{ pageBase }}css/ui.css" media="all" rel="stylesheet"/>
{% endblock %}
{% block script %}
{{ block.super -}}
<script src="/vendor/jquery.min.js"></script>
<script src="{{ pageBase }}js/variables.js"></script>
<script src="{{ pageBase }}js/app.js"></script>
<script>
const frameHeader = document.querySelector('body > header.io');
const closeActionElements = document.querySelectorAll('[data-action=close]');
if (frameHeader) {
console.log('frame header found', frameHeader);
frameHeader.addEventListener('click', (e) => {
if (e.target.dataset.action === 'close') {
console.debug('close', e.target);
history.back();
if (closeActionElements.length > 1) {
console.debug('other frames present', closeActionElements.length);
}
}
});
}
</script>
{% endblock %}

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
{% if pageId %}
{%- capture idAttr %} id="{{ pageId }}"{% endcapture -%}
{% endif -%}
{% if pageClass %}
{%- capture classAttr %} class="{{ pageClass }}"{% endcapture -%}
{% endif -%}
{% if bodyClass %}
{%- capture bodyClassAttr %} class="{{ bodyClass }}"{% endcapture -%}
{% endif -%}
<html{{ idAttr }}{{ classAttr }} lang="de">
<head>
<meta charset="utf-8">
{% block head %}
<title>
{{- hippie.titlePrefix -}}
{% block title %}{% endblock -%}
{{ hippie.titlePostfix -}}
</title>
{% block meta -%}
{% render "hippie/partials/meta.liquid" %}
{% endblock -%}
{% block links -%}
{% render "hippie/partials/links.liquid" %}
{% endblock -%}
{% endblock -%}
</head>
<body{{ bodyClassAttr }}>
{%- block body %}{% endblock -%}
{% block script -%}
<script>
// Default script
</script>
{% endblock -%}
</body>
</html>

View file

@ -32,4 +32,18 @@
<button>action</button>
</nav>
</footer>
{% endmacro %}
{% macro statusBar(title) %}
<footer class="io">
<nav>
<span>## items</span>
<span># selected (size)</span>
<span># type(s)</span>
<span># shared</span>
</nav>
<nav>
<span>{{ title | default('status-bar') }}</span>
</nav>
</footer>
{% endmacro %}

View file

@ -0,0 +1,20 @@
<header class="io">
<nav>
<button title="menu">
<i class="bi bi-three-dots"></i>
</button>
<span>{{ title | default: 'title-bar' }}</span>
</nav>
<nav>
<div class="spacer a"></div>
<button title="minimize">
<i class="bi bi-dash"></i>
</button>
<button title="maximize">
<i class="bi bi-fullscreen"></i>
</button>
<button title="close" data-action="close">
<i class="bi bi-x-square"></i>
</button>
</nav>
</header>

View file

@ -0,0 +1,10 @@
<footer class="io">
<nav>
<button>mode</button>
<span>{{ title | default: 'mode-bar' }}</span>
</nav>
<nav>
<div class="spacer a"></div>
<button>action</button>
</nav>
</footer>

View file

@ -0,0 +1,11 @@
<footer class="io">
<nav>
<span>## items</span>
<span># selected (size)</span>
<span># type(s)</span>
<span># shared</span>
</nav>
<nav>
<span>{{ title | default: 'status-bar' }}</span>
</nav>
</footer>

View file

@ -0,0 +1,3 @@
{% comment %}<link rel="icon" href="/favicon.ico" type="image/vnd.microsoft.icon">{% endcomment %}
<link rel="shortcut icon" type="image/x-icon" href="{{ pageBase }}favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAIBAQCbjUIABQQCAGdfKgDcxYUAiXpGABkWCgDXxnEApmxRAMGZawAIBwMArZ5PAKFydQBmIZIAoGJFAIx+QwBSSyIA1biBADlx0gBNn+0AgztQAMimcQAMCwQADAsFANS/dAB7P3EAeuH7ANb4/gBQPLwAp2pNAI6CQwCilEwAr3hdADyH5ADw/f8A////AHTU+AB6M2YA0LN4ABMRBwA/OhsAyKR2AGYvjQCf7PwA7fz/AENy2gCrclkAk4ZDAAYFAgDNtXEAjkhHAEul7QD8//8AlOn8AGk1hwDWvXsAGBYJAJaHSgCnbE4AVy6rAML0/gD7/v8AQ6vuAKx1YwCZjEQALCgTALyOZwB+NVoAZ8D0AL30/QBLULMA2sV+AB4bCwDFpm0Ak087AFArvgBv4PoAjOf7AIzm+wCN4/sAjuH7AI7h+gCP3fkAOI/sAKVvcwCfkUQAfnM6ANO2hAC3iGkAk150AI9OcACKRmkAhj9kAH84YQB9NWEAfTRgAH0zYAB6MWYAei9lAItFUADdy3wAKCQPAFtTJQB2bDIAhXk5AJKGPwCbjkQAq5xOALepWwDEtGcAzLlwAMyzcgDKrXIAx6NwALyNZgDWu4IApJZHAAcGAwANDAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3eGhpamtsbW5vcHFycwt0dXZYWVpbXF1eX2BhYmNkZWZnAktMTU5PUFFRUlNUVVZXAABDREVGJSUlJSUlR0hJSgAAADs8PT4lJSUlP0BBQgAAAAAyMzQ1NiUlJTc4OToAAAAAACorLC0lJS4vMDEAAAAAAAAAISIjJCUmJygpAAAAAAAAABkaGxwdHh8gAAAAAAAAAAAAEhMUFRYXGAAAAAAAAAAAAAANDg8QEQAAAAAAAAAAAAAACAkKCwwAAAAAAAAAAAAAAAAFBgcAAAAAAAAAAAAAAAAAAgMEAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=">

View file

@ -0,0 +1,7 @@
<meta name="robots" content="noindex">
<meta name="generator" content="{{ eleventy.generator }}">
<meta name="author" content="">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
</head>
<body>
{{ content }}
</body>
</html>