Compare commits

...

7 commits

Author SHA1 Message Date
f2ff20ce73 feat: Add location change to intro 2026-03-08 20:50:25 +01:00
30fcd22a7b fix: Intro
- Move style inside .body_intro
- Fix overlap of ids
2026-03-08 18:54:44 +01:00
6ae411c83b feat: Update intro and placeholder
- Change intro from njk to liquid
- New svg content for brand shortcode
- New style for brand in ui
2026-03-08 18:18:54 +01:00
9b44963ba2 feat: Make game sub
- Move game and intro to own collection
- Add index
- Add brand placeholder to shortcodes
- Add variant of placeholder to menu
2026-03-08 17:00:04 +01:00
76791d93ba feat: Move hello world to examples 2026-03-08 16:51:39 +01:00
a5462dcc7e feat: Use paired styles
Change .list_link style to &.link.
2026-03-08 14:54:41 +01:00
3ae1cebdd6 feat: Responsiveness for lists
- New style for lists
- Change index list layout
2026-03-08 14:42:16 +01:00
18 changed files with 481 additions and 340 deletions

View file

@ -57,6 +57,56 @@ export default async function (eleventyConfig) {
return `<a id="${attrId}" class="${attrClass}" href="${target}">${text}</a>`;
});
eleventyConfig.addPairedShortcode("brand", function (content, attrClass = 'brand', direction = 'first') {
const logo = `
<svg
width="100%"
height="100%"
viewBox="0 0 512 512"
preserveAspectRatio="xMidYMid meet">
<defs
id="defs1" />
<g
id="layer1">
<g
id="g2"
transform="matrix(0.984375,0,0,0.984375,4,4)"
style="stroke-width:1.01587">
<rect
style="fill:none;stroke:#000000;stroke-width:8.12698;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1"
width="512"
height="512"
x="0"
y="0" />
<circle
style="fill:none;stroke:#000000;stroke-width:8.12698;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1"
cx="256"
cy="256"
r="256" />
<path
style="fill:none;stroke:#000000;stroke-width:8.12698;stroke-linecap:butt;stroke-linejoin:bevel;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2"
d="M 477.7025,128 256,512 34.297496,128 Z"
</g>
</g>
</svg>
`;
let output = '';
switch (direction) {
case 'first':
output = logo + `${content}`;
break;
case 'last':
output = `${content}` + logo;
break;
}
return `<div class="${attrClass}">` + output + `</div>`;
});
eleventyConfig.addPassthroughCopy({'source/art/images': 'art'});
eleventyConfig.addPassthroughCopy({'source/art/favicons/**/*.+(ico|png|svg)': '.'});

View file

@ -539,6 +539,11 @@ function mapRange(value, inMin, inMax, outMin, outMax, reverse = false, clamp =
return mapped;
}
// Source - https://stackoverflow.com/a/47480429
// Posted by Etienne Martin, modified by community. See post 'Timeline' for change history
// Retrieved 2026-03-08, License - CC BY-SA 4.0
const delay = ms => new Promise(res => setTimeout(res, ms));
// CONCEPTS
// NOTE: Benutzt private Zuweisungen

View file

@ -25,7 +25,7 @@ class UI {
msgNo: 'No agreement today.'
}
};
this.intro = document.getElementById('intro');
this.intro = document.getElementById('init');
this.agreement = this.steps.agreement.element;
this.hint = {
element: document.getElementById('hint'),
@ -61,7 +61,7 @@ class UI {
} else {
reject('No intro available.');
}
})
});
}
showHint() {
@ -100,7 +100,7 @@ class UI {
} else {
reject();
}
})
});
}
init() {
@ -119,7 +119,7 @@ function init() {
// Set all steps to not receive pointer events
document.querySelectorAll('.step').forEach(element => {
console.log(element);
element.style.pointerEvents = 'none';
});
@ -158,7 +158,7 @@ function showIntro() {
reject('No intro available.');
}
})
});
}
function showAgreement() {
@ -197,7 +197,7 @@ function showAgreement() {
resolve(steps.agreement.msgOut);
});
}
})
});
}
function showIdle() {
@ -212,16 +212,24 @@ function showIdle() {
el.classList.replace('op_hide', 'op_show');
el.style.pointerEvents = '';
el.addEventListener('click', idleStart, false);
resolve('Idle.');
el.addEventListener('contextmenu', (event) => {
event.preventDefault();
});
el.addEventListener('click', (event) => {
if (checkButtonAndTarget(event, event.target)) {
console.log('OK go', event.target);
resolve('Idle fin.');
} else {
event.preventDefault();
}
}, false);
} else {
document.removeEventListener('mouseleave', idleStart);
document.removeEventListener('mouseenter', idleStop);
reject();
}
})
});
}
function loadCore() {
@ -289,9 +297,9 @@ function idleStop() {
/**
* Blendet einen Schritt aus.
*
* @param {*} e
* @returns
*
* @param {*} e
* @returns
*/
function stepHandler(e) {
const el = e.target;
@ -303,8 +311,8 @@ function stepHandler(e) {
console.info(msg);
el.removeEventListener('transitionend', endListener);
resolve(msg);
});
})
});
}

View file

@ -151,8 +151,8 @@ tags:
<li>Mehr Abstand und</li>
<li>mit Unterstrichen.</li>
</ul>
<pre class="pre_code"><code>ul.list_link>(li>a)*2</code></pre>
<ul class="list_link">
<pre class="pre_code"><code>ul.link>(li>a)*2</code></pre>
<ul class="link">
<li>
<a href="">Mit</a>
</li>

View file

@ -1,25 +0,0 @@
---
title: Game - TFW
tags:
- demoExample
- gameExample
---
{% assign bodyClass = 'body_game' -%}
{% layout 'hippie/simple.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

@ -0,0 +1,24 @@
---
title: Game
tags:
- demoExample
- index
---
{% layout 'hippie/simple.liquid' %}
{% block title %}{{ title }}{% endblock %}
{% block body %}
<div class="sec_main_center">
<nav role="doc-toc">
<h1>{{ title }}</h1>
<ul class="link">
{%- for game in collections.game -%}
<li>
<a href="{{ game.page.url }}">{{ game.data.title }}</a>
</li>
{%- endfor -%}
</ul>
</nav>
</div>
{% endblock %}

View file

@ -0,0 +1,138 @@
---
title: Intro
tags:
- game
---
{% assign bodyClass = 'body_intro' -%}
{% layout 'hippie/app.liquid' %}
{% block body %}
<div id="loader" class="step op_show">
<div id="bar">
<div id="spinner">
<span>I</span>
</div>
<div id="wrap">
<div id="progress"></div>
</div>
<div id="status">0%</div>
</div>
</div>
<div id="init" class="step op_hide">
<div id="hint" class="toast di_none" role="alert" aria-live="assertive" aria-atomic="true">
<p>Hold
<kbd>space</kbd>
to skip.</p>
</div>
{% brand 'brand' %}
<h1>Marke</h1>
{% endbrand %}
<p>Powered by</p>
<ul class="tech-stack">
<li>Vendor</li>
<li>IDE</li>
<li>Engine</li>
</ul>
</div>
<div id="agreement" class="step op_hide">
<h1>Agreement</h1>
<p>This needs to be seen and acknowledged.<br>So an interaction must be made to continue.</p>
</div>
<div id="idle" class="step op_hide">
<div class="mouse-overlay"></div>
<div class="hello">Hello World!</div>
<p class="hello">Only left mouse click or any key</p>
</div>
{% endblock %}
{%- block script %}
{{ block.super -}}
<script src="/js/intro.js"></script>
<script>
//let intro = new Intro('Intro');
//intro.init();
//const ui = new UI();
//ui
// .init()
// .then(() => ui.showIntro())
// .then(() => ui.showHint())
// .then(() => ui.showIdle())
// .catch((error) => console.error(error));
let introDelay = 6;
let hintDelay = 1;
let cycleDelay = 2;
let isAgree = false;
const steps = {
agreement: {
element: document.getElementById('agreement'),
msgIn: 'Agreement shown.',
msgOut: 'Agreement accepted.',
msgNo: 'No agreement today.'
}
};
const intro = document.getElementById('init');
const agreement = steps.agreement.element;
const hint = {
element: document.getElementById('hint'),
delay: hintDelay * 1000,
show() {
if (typeof this.timeoutId === 'number') {
this.cancel();
}
this
.element
.classList
.remove('di_none');
this.timeoutId = setTimeout(() => {
this.dismiss();
}, this.delay);
},
dismiss() {
this
.element
.classList
.add('di_none');
this.timeoutId = undefined;
},
cancel() {
clearTimeout(this.timeoutId);
}
};
const loader = document.getElementById('loader');
const idle = {
element: document.getElementById('idle'),
delay: cycleDelay * 1000,
position: 0,
cycle() {
if (typeof this.intervalId === 'number') {
this.cancel();
}
this.intervalId = setInterval(() => {
this.position++;
if (this.position >= flagColors.length) {
this.position = 0;
}
this.element.style.backgroundColor = '#' + flagColors[this.position];
}, this.delay);
},
cancel() {
this.intervalId && clearInterval(this.intervalId);
}
}
init()
.then(loadCore)
.then(showIntro)
.catch(er => console.error(er))
.then(showAgreement)
.then(showIdle)
.catch(er => console.error(er))
.finally(() => {
console.debug('Init end.', isAgree);
// location = 'demo/examples/ui/new.html';
window.location.href = './menu.html';
});
</script>
{% endblock %}

View file

@ -0,0 +1,29 @@
---
title: Menu
tags:
- game
---
{% assign bodyClass = 'body_game' -%}
{% layout 'hippie/simple.liquid' %}
{% block body %}
<div class="sec_main_center">
<nav role="doc-toc">
<hgroup>
<h1>Game - TFW</h1>
<p>Additional name</p>
</hgroup>
<ul class="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>
<footer>
{% brand 'brand', 'last' %}
<p>Marke</p>
{% endbrand %}
</footer>
{% endblock %}

View file

@ -1,6 +1,8 @@
---
title: "Hello World"
layout: hippie/world.liquid
tags:
- demoExample
---
# {{ title }}

View file

@ -1,138 +0,0 @@
---
title: Intro
tags:
- demoExample
---
{% set pageId = "init" %}
{% set bodyClass = "body_intro" %}
{% extends "hippie/_app_frame.njk" %}
{% import "hippie/macros/_placeholder.njk" as ph %}
{% block body %}
<div id="loader" class="step op_show">
<div id="bar">
<div id="spinner">
<span>I</span>
</div>
<div id="wrap">
<div id="progress"></div>
</div>
<div id="status">0%</div>
</div>
</div>
<div id="intro" class="step op_hide">
<div id="hint" class="toast di_none" role="alert" aria-live="assertive" aria-atomic="true">
<p>Hold
<kbd>space</kbd>
to skip.</p>
</div>
{{ ph.brand('brand') }}
<p>Powered by</p>
<ul class="tech-stack">
<li>Vendor</li>
<li>IDE</li>
<li>Engine</li>
</ul>
</div>
<div id="agreement" class="step op_hide">
<h1>Agreement</h1>
<p>This needs to be seen and acknowledged.<br>So an interaction must be made to continue.</p>
</div>
<div id="idle" class="step op_hide">
<div class="mouse-overlay"></div>
<div class="hello">Hello World!</div>
<p class="hello">Only left mouse click or any key</p>
</div>
{% endblock %}
{%- block script %}
{{ super() }}
<script src="{{ pageBase }}js/intro.js"></script>
<script>
//let intro = new Intro('Intro');
//intro.init();
//const ui = new UI();
//ui
// .init()
// .then(() => ui.showIntro())
// .then(() => ui.showHint())
// .then(() => ui.showIdle())
// .catch((error) => console.error(error));
let introDelay = 6;
let hintDelay = 1;
let cycleDelay = 2;
let isAgree = false;
const steps = {
agreement: {
element: document.getElementById('agreement'),
msgIn: 'Agreement shown.',
msgOut: 'Agreement accepted.',
msgNo: 'No agreement today.'
}
};
const intro = document.getElementById('intro');
const agreement = steps.agreement.element;
const hint = {
element: document.getElementById('hint'),
delay: hintDelay * 1000,
show() {
if (typeof this.timeoutId === 'number') {
this.cancel();
}
this
.element
.classList
.remove('di_none');
this.timeoutId = setTimeout(() => {
this.dismiss();
}, this.delay);
},
dismiss() {
this
.element
.classList
.add('di_none');
this.timeoutId = undefined;
},
cancel() {
clearTimeout(this.timeoutId);
}
};
const loader = document.getElementById('loader');
const idle = {
element: document.getElementById('idle'),
delay: cycleDelay * 1000,
position: 0,
cycle() {
if (typeof this.intervalId === 'number') {
this.cancel();
}
this.intervalId = setInterval(() => {
this.position++;
if (this.position >= flagColors.length) {
this.position = 0;
}
this.element.style.backgroundColor = '#' + flagColors[this.position];
}, this.delay);
},
cancel() {
this.intervalId && clearInterval(this.intervalId);
}
}
init()
.then(loadCore)
.then(showIntro)
.catch(er => console.error(er))
.then(showAgreement)
.then(showIdle)
.catch(er => console.error(er))
.finally(() => {
console.debug('Init end.', isAgree);
// location = 'demo/examples/ui/new.html';
});
</script>
{% endblock %}

View file

@ -12,7 +12,7 @@ tags:
<div class="sec_main_center">
<nav role="doc-toc">
<h1>{{ title }}</h1>
<ul class="list_link">
<ul class="link">
{%- for ui in collections.ui -%}
<li>
<a href="{{ ui.page.url }}">{{ ui.data.title }}</a>

View file

@ -34,7 +34,7 @@ tags:
<h3>Overview</h3>
</div>
<nav>
<ul class="list_link">
<ul class="block link">
{% for link in collections.demoIndex %}
<li>
<a href="{{ link.page.url }}">{{ link.data.title }}</a>
@ -42,24 +42,30 @@ tags:
{% endfor %}
</ul>
</nav>
<h3>Page</h3>
<ul class="list_link">
{% assign pagesByTitle = collections.demoPage | sort: 'data.title' %}
<div class="responsive">
<section>
<h3>Page</h3>
<ul class="block link">
{% assign pagesByTitle = collections.demoPage | sort: 'data.title' %}
{% for link in pagesByTitle %}
<li>
<a href="{{ link.page.url }}">{{ link.data.title }}</a>
</li>
{% endfor %}
</ul>
<h3>Example</h3>
<ul class="list_link">
{% for link in collections.demoExample %}
<li>
<a href="{{ link.page.url }}">{{ link.data.title }}</a>
</li>
{% endfor %}
</ul>
{% for link in pagesByTitle %}
<li>
<a href="{{ link.page.url }}">{{ link.data.title }}</a>
</li>
{% endfor %}
</ul>
</section>
<section>
<h3>Example</h3>
<ul class="block link">
{% for link in collections.demoExample %}
<li>
<a href="{{ link.page.url }}">{{ link.data.title }}</a>
</li>
{% endfor %}
</ul>
</section>
</div>
</div>
</div>
{% endblock %}

View file

@ -231,9 +231,9 @@ tags:
<pre class="pre_code"><code>hr.dotted.space_even_fourth</code></pre>
<hr class="dotted space_even_fourth">
<h3>ul</h3>
<pre class="pre_code"><code>nav>ul.list_link>(li>a)+li>a>img+span</code></pre>
<pre class="pre_code"><code>nav>ul.link>(li>a)+li>a>img+span</code></pre>
<nav>
<ul class="list_link">
<ul class="link">
<li>{% link hippie.placeholders.mail, '📧 name@domain.tld' %}</li>
<li>
<a href=""><img src="/art/bullet.gif" alt="">{% text hippie.placeholders.name %}</a>

@ -1 +1 @@
Subproject commit ddedf3bbf2d6580dfeae297367fd673abaa11a96
Subproject commit b4c56320060548dacde62639876c6aee72b297ea

View file

@ -1,3 +1,27 @@
@use "../hippie-style/hippie";
.body_game {
@extend .h_full_view;
background-color: hotpink;
footer {
@extend .pos_abs;
@extend .pin_bottom;
@extend .width_full;
.brand {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-end;
gap: hippie.$space_half hippie.$space_basic;
margin: hippie.$space_basic hippie.$space_double;
& > svg {
height: 32px;
width: 32px;
}
}
}
}

View file

@ -281,10 +281,19 @@
.hello {
flex: 0 1 auto;
width: 80%;
}
ul {
padding: 1em 5em;
background-color: hippie.$color_darker;
.responsive {
@include hippie.forTabletPortraitUp {
display: flex;
flex-flow: row wrap;
align-items: stretch;
justify-content: space-between;
gap: hippie.$space_half hippie.$space_basic;
& > * {
flex: auto;
}
}
}
}

View file

@ -129,7 +129,7 @@ $portal_icon_size: 64px;
}
.portal__list {
@extend .list_link;
@extend .link;
display: none;
position: relative;

View file

@ -33,146 +33,162 @@ $space_gui_half: hippie.$space_half;
.body_intro {
background-color: black;
}
.step {
@extend %full_parent;
}
#loader {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: white;
}
#bar {
display: flex;
justify-content: space-between;
width: 50%;
}
#wrap {
flex: 1;
background-color: hippie.$color_back_basic;
}
#progress {
width: 0;
height: 100%;
background-color: black;
}
#status,
#spinner {
@extend %basic;
display: flex;
flex-grow: 0;
flex-shrink: 0;
justify-content: center;
align-items: center;
margin-inline: $space_gui_half;
padding-block: calc($space_gui_half - 1px) $space_gui_half;
line-height: hippie.$line_basic;
text-align: center;
}
#status {
width: 4em;
background-color: black;
color: white;
}
#spinner {
width: 2.5em;
background-color: hippie.$color_back_basic;
color: black;
span {
animation: rotate 1s linear infinite;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
.step {
@extend %full_parent;
}
to {
transform: rotate(360deg);
}
}
#intro {
z-index: map.get(hippie.$z-indexes, "content-top");
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: black;
h1,
p,
li {
color: white;
}
}
.brand {
text-align: center;
img {
display: inline-block;
width: 128px;
height: 128px;
#loader {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: white;
}
*+h1 {
margin-top: hippie.$space_small;
margin-bottom: hippie.$space_large;
#bar {
display: flex;
justify-content: space-between;
width: 50%;
}
}
.tech-stack {
display: flex;
padding-left: 0;
li {
list-style: none;
padding-inline: hippie.$space_double;
#wrap {
flex: 1;
background-color: hippie.$color_back_basic;
}
}
#agreement,
#idle {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
#agreement {
flex-direction: column;
background-color: map.get(hippie.$color_palette, bravo);
user-select: none;
h1 {
margin-top: 0;
color: hippie.$color_brightest;
#progress {
width: 0;
height: 100%;
background-color: black;
}
}
#idle {
background-color: hippie.$color_back_basic;
transition: background-color 4s;
#status,
#spinner {
@extend %basic;
&:hover>.mouse-overlay {
background-color: transparent !important;
transition: background-color hippie.$duration_basic hippie.$timing_basic 0s !important;
display: flex;
flex-grow: 0;
flex-shrink: 0;
justify-content: center;
align-items: center;
margin-inline: $space_gui_half;
padding-block: calc($space_gui_half - 1px) $space_gui_half;
line-height: hippie.$line_basic;
text-align: center;
}
#status {
width: 4em;
background-color: black;
color: white;
}
#spinner {
width: 2.5em;
background-color: hippie.$color_back_basic;
color: black;
span {
animation: rotate 1s linear infinite;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#init {
z-index: map.get(hippie.$z-indexes, "content-top");
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: black;
h1,
p,
li {
color: white;
}
}
.brand {
text-align: center;
svg {
height: 128px;
width: 128px;
rect, circle, path {
stroke: white !important;
}
}
img {
display: inline-block;
width: 128px;
height: 128px;
background-color: white;
}
* + h1 {
margin-top: hippie.$space_small;
margin-bottom: hippie.$space_large;
}
}
.tech-stack {
display: flex;
padding-left: 0;
li {
list-style: none;
padding-inline: hippie.$space_double;
}
}
#agreement,
#idle {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
#agreement {
flex-direction: column;
background-color: map.get(hippie.$color_palette, bravo);
user-select: none;
h1 {
margin-top: 0;
color: hippie.$color_brightest;
}
}
#idle {
background-color: hippie.$color_back_basic;
transition: background-color 4s;
&:hover > .mouse-overlay {
background-color: transparent !important;
transition: background-color hippie.$duration_basic hippie.$timing_basic 0s !important;
}
.hello {
flex: 0 1 auto;
padding: 1em 2em;
background-color: rgba(hippie.$color_bright, .5);
font-family: hippie.$family_text_mono;
}
}
}
@ -191,10 +207,3 @@ $space_gui_half: hippie.$space_half;
color: hippie.$color_back_io;
}
}
.hello {
flex: 0 1 auto;
padding: 1em 2em;
background-color: rgba(hippie.$color_bright, .5);
font-family: hippie.$family_text_mono;
}