feat: Change file structure
- Move return object to named export for 11ty config - screens is now view - 11ty data files moved to view/_data - templates is now view/_includes - Both are the default directories - data is now used as intended, for user data - Update index to reflect filenames and structure
This commit is contained in:
parent
610e22b3c9
commit
b67a8a893a
78 changed files with 21 additions and 19 deletions
69
source/view/demo/examples/10print.liquid
Normal file
69
source/view/demo/examples/10print.liquid
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: 10print
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block style %}
|
||||
<style>
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<canvas id="pattern"></canvas>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
const canvas = document.getElementById('pattern');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const lineWidth = 20;
|
||||
const randomSeed = Math.random;
|
||||
|
||||
// Function to draw the 10PRINT pattern
|
||||
function draw10Print() {
|
||||
// Clear the canvas
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Set line style
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
// Loop through the canvas grid
|
||||
for (let x = 0; x < canvas.width; x += lineWidth) {
|
||||
for (let y = 0; y < canvas.height; y += lineWidth) {
|
||||
// Randomly choose between two diagonal lines
|
||||
if (randomSeed() > 0.5) {
|
||||
// Draw line from top-left to bottom-right
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + lineWidth, y + lineWidth);
|
||||
ctx.stroke();
|
||||
} else {
|
||||
// Draw line from top-right to bottom-left
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + lineWidth, y);
|
||||
ctx.lineTo(x, y + lineWidth);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
}
|
||||
|
||||
resizeCanvas();
|
||||
draw10Print();
|
||||
|
||||
// window.addEventListener('resize', resizeCanvas);
|
||||
canvas.addEventListener('click', draw10Print);
|
||||
</script>
|
||||
{% endblock %}
|
||||
32
source/view/demo/examples/blog.liquid
Normal file
32
source/view/demo/examples/blog.liquid
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title: Blog
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="sec_main_center">
|
||||
<header class="header_txt">
|
||||
<h1>Blog</h1>
|
||||
</header>
|
||||
<nav role="doc-toc">
|
||||
<h2>Inhaltsverzeichnis</h2>
|
||||
<ul>
|
||||
{%- for blog in collections.blog -%}
|
||||
<li>
|
||||
<a href="{{ blog.page.url }}">{{ blog.data.title }}</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</nav>
|
||||
<hr class="double dotted">
|
||||
{%- for post in collections.article -%}
|
||||
<article>
|
||||
{{ post.content }}
|
||||
</article>
|
||||
{%- endfor -%}
|
||||
<hr/>
|
||||
<address>{% text hippie.placeholders.name %}</address>
|
||||
</div>
|
||||
{% endblock %}
|
||||
11
source/view/demo/examples/blog/article.md
Normal file
11
source/view/demo/examples/blog/article.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
tags:
|
||||
- blog
|
||||
- article
|
||||
title: "Artikel"
|
||||
publishDate: JJJJ
|
||||
description: Text
|
||||
---
|
||||
# Titel
|
||||
|
||||
Inhalt
|
||||
69
source/view/demo/examples/card.liquid
Normal file
69
source/view/demo/examples/card.liquid
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Card
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% assign pageClass = "html_card" %}
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="card_bkg">
|
||||
<div id="dither"></div>
|
||||
{% render 'hippie/partials/placeholder-flag.liquid', type: '', id: 'flag' %}
|
||||
{% comment %}<img id="dither" src="art/flag_dither.png" width="1920" height="1200" alt="Background flag dithered"/>{% endcomment %}
|
||||
</div>
|
||||
<div class="card_box">
|
||||
<main>
|
||||
<p>Titel<br/>und Beschreibung</p>
|
||||
<h1>{% text hippie.placeholders.name %}</h1>
|
||||
<p>
|
||||
{% link hippie.placeholders.mail, '', '', 'card_address' %}<br/>
|
||||
{% link hippie.placeholders.domain, 'site.tld', '', 'decent' %}
|
||||
·
|
||||
{% text hippie.placeholders.address, '', 'decent' %}</p>
|
||||
</main>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
const flag = document.getElementById('flag');
|
||||
let colors = new Array();
|
||||
let iId = undefined;
|
||||
let position = 0;
|
||||
|
||||
for (let i = 1; i <= flag.childElementCount; i++) {
|
||||
colors.push(document.getElementById('triangle-' + i).getAttribute('fill'));
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector('main')
|
||||
.addEventListener('mouseenter', () => {
|
||||
iId = setInterval(() => {
|
||||
for (let i = 1; i <= colors.length; i++) {
|
||||
position++;
|
||||
|
||||
if (position >= colors.length) {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
document
|
||||
.getElementById('triangle-' + i)
|
||||
.setAttribute('fill', colors[position]);
|
||||
}
|
||||
|
||||
position++;
|
||||
|
||||
if (position >= colors.length) {
|
||||
position = 0;
|
||||
}
|
||||
}, 600);
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector('main')
|
||||
.addEventListener('mouseleave', () => {
|
||||
iId && clearInterval(iId);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
488
source/view/demo/examples/clock.liquid
Normal file
488
source/view/demo/examples/clock.liquid
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
---
|
||||
title: Clock
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% assign bodyClass = 'body_clock' -%}
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<header class="io pos_fix pin_top pin_right pin_left">
|
||||
<button id="tglOverlay" title="Toggle overlay">☰</button>
|
||||
<nav>
|
||||
<button id="tglFormat" title="Toggle hour display">12-Stunden</button>
|
||||
<button id="tglSections" title="Toggle sections">Abschnitte</button>
|
||||
</nav>
|
||||
</header>
|
||||
<main></main>
|
||||
{% endblock %}
|
||||
|
||||
{% block assets %}
|
||||
<script src="/vendor/hippie-script.js"></script>
|
||||
<script src="/js/globals.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
class HippieClock {
|
||||
constructor(element, date = new Date(), options = {}) {
|
||||
this.element = element;
|
||||
this.date = date;
|
||||
this.defaults = {
|
||||
debug: true,
|
||||
size: Math.floor(this.getSize().value * 0.9),
|
||||
h24: true,
|
||||
sections: true,
|
||||
overlay: false
|
||||
};
|
||||
this.options = {...this.defaults, ...options};
|
||||
this.values = this.getTime();
|
||||
this.parts = [];
|
||||
this.shapes = [];
|
||||
|
||||
this.#init();
|
||||
}
|
||||
|
||||
#init() {
|
||||
this.#createContext(['background', 'hands']);
|
||||
// this.createOverlay();
|
||||
|
||||
this.addRing('seconds', 1, 21, 60, `rgb(250, 216, 3)`);
|
||||
this.addRing('minutes', .9, 46, 60, `rgb(242, 175, 19)`);
|
||||
this.addRing('hours', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`);
|
||||
this.addRing('dotweek', .7, 2, 7, `rgb(142, 31, 104)`);
|
||||
this.addRing('dotmonth', .6, 12, this.values.daysMonth, `rgb(39, 63, 139)`);
|
||||
this.addRing('dotyear', .5, 256, this.values.daysYear, `rgb(60, 87, 154)`);
|
||||
this.addRing('week', .4, 10, this.values.weeksYear, `rgb(183, 224, 240)`);
|
||||
this.addRing('month', .3, 10, 12, `rgb(107, 199, 217)`);
|
||||
this.addRing('moon', .2, 4, 8, `rgb(82, 190, 209)`);
|
||||
|
||||
this.#resize();
|
||||
window.addEventListener('resize', () => this.#resize());
|
||||
|
||||
// console.debug(this);
|
||||
if (this.options.debug) {
|
||||
console.group('Clock');
|
||||
console.info('\nOptions:', this.options, '\n\n');
|
||||
console.info('Date:', this.date);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
#resize() {
|
||||
this.updateOptions({size: Math.floor(this.getSize().value * 0.9)});
|
||||
this.parts.forEach(part => {
|
||||
if (part.name === 'wrap') {
|
||||
part.element.style.height = this.options.size + 'px';
|
||||
part.element.style.width = this.options.size + 'px';
|
||||
}
|
||||
|
||||
// part.element.width = part.element.offsetWidth;
|
||||
// part.element.height = part.element.offsetHeight;
|
||||
part.element.width = this.options.size;
|
||||
part.element.height = this.options.size;
|
||||
|
||||
this.draw();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Zuweisung von shapes zu parts anpassen
|
||||
draw() {
|
||||
// TODO: Nur geänderte Teile löschen
|
||||
this.parts.forEach(part => {
|
||||
part.context?.clearRect(0, 0, part.element.width, part.element.height);
|
||||
});
|
||||
|
||||
let ctx = undefined;
|
||||
|
||||
this.shapes
|
||||
.filter(item => item.type === 'circle')
|
||||
.forEach((shape) => {
|
||||
const radius = this.#toPixelSize(shape.radius) / 2;
|
||||
ctx = this.parts[0].context;
|
||||
|
||||
ctx.fillStyle = shape.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
this.#toPixelX(shape.center),
|
||||
this.#toPixelY(shape.center),
|
||||
radius,
|
||||
0,
|
||||
Math.PI * 2
|
||||
);
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
this.shapes
|
||||
.filter(item => item.type === 'ring')
|
||||
.forEach((shape) => {
|
||||
if (this.options.sections) {
|
||||
const outerRadius = this.#toPixelSize(shape.radius) / 2;
|
||||
const innerRadius = this.#toPixelSize(shape.radius) / 2 - shape.stroke;
|
||||
ctx = this.parts[0].context;
|
||||
|
||||
for (let i = 0; i < shape.max; i++) {
|
||||
const angle = (i * (360 / shape.max) - 90) * (Math.PI / 180); // -90 to start at top
|
||||
const outerX = this.#toPixelX(shape.center) + outerRadius * Math.cos(angle);
|
||||
const outerY = this.#toPixelY(shape.center) + outerRadius * Math.sin(angle);
|
||||
const innerX = this.#toPixelX(shape.center) + innerRadius * Math.cos(angle);
|
||||
const innerY = this.#toPixelY(shape.center) + innerRadius * Math.sin(angle);
|
||||
|
||||
ctx.strokeStyle = `rgba(0, 0, 0, .25)`;
|
||||
ctx.lineWidth = mapRange(shape.max, 7, 72, .1, 5, true, true);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(outerX, outerY);
|
||||
ctx.lineTo(innerX, innerY);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
const radius = this.#toPixelSize(shape.radius) / 2 - shape.stroke / 2;
|
||||
const start = -0.5 * Math.PI; // Start at the top
|
||||
const angle = start + (2 * Math.PI * (shape.angle / shape.max));
|
||||
ctx = this.parts[1].context;
|
||||
|
||||
ctx.strokeStyle = shape.color;
|
||||
ctx.lineWidth = shape.stroke;
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
this.#toPixelX(shape.center),
|
||||
this.#toPixelY(shape.center),
|
||||
radius,
|
||||
start,
|
||||
angle
|
||||
);
|
||||
ctx.stroke();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Erfassung für geänderte Formen ergänzen
|
||||
update() {
|
||||
this.values = this.getTime();
|
||||
const second = this.values.second;
|
||||
const minute = this.values.minute;
|
||||
const hour = this.values.hour;
|
||||
|
||||
this.updateShape('seconds', (second === 0) ? 60 : second);
|
||||
this.updateShape('minutes', (minute === 0) ? 60 : minute);
|
||||
this.updateShape('hours', this.options.h24 ? hour : hour % 12, this.options.h24 ? 24 : 12);
|
||||
this.updateShape('dotweek', this.values.dayWeek);
|
||||
this.updateShape('dotmonth', this.values.dayMonth, this.values.daysMonth);
|
||||
this.updateShape('dotyear', this.values.dayYear);
|
||||
this.updateShape('week', this.values.week);
|
||||
this.updateShape('month', this.values.month);
|
||||
this.updateShape('moon', this.values.moon);
|
||||
this.draw();
|
||||
}
|
||||
|
||||
#toPixelX(number) {
|
||||
return number * this.parts[0].element.width;
|
||||
}
|
||||
|
||||
#toPixelY(number) {
|
||||
return number * this.parts[0].element.height;
|
||||
}
|
||||
|
||||
#toPixelSize(number) {
|
||||
return number * Math.min(this.parts[0].element.width, this.parts[0].element.height);
|
||||
}
|
||||
|
||||
// TODO: DateDisplay und TimeDisplay benutzen
|
||||
// TODO: Parameter für Wochenstart ergänzen
|
||||
getWeekday(date) {
|
||||
const weekday = date.getDay(); // 0 (Sunday) to 6 (Saturday)
|
||||
|
||||
return (weekday === 0) ? 7 : weekday;
|
||||
}
|
||||
|
||||
getYearDay(date) {
|
||||
const start = new Date(date.getFullYear(), 0, 0);
|
||||
|
||||
return Math.floor((date - start) / 86400000);
|
||||
}
|
||||
|
||||
isLeapYear(year) {
|
||||
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
|
||||
}
|
||||
|
||||
getDaysInYear(year) {
|
||||
return this.isLeapYear(year) ? 366 : 365;
|
||||
}
|
||||
|
||||
getYearInfo(date) {
|
||||
const current = this.getYearDay(date);
|
||||
const total = this.getDaysInYear(date.getFullYear());
|
||||
const remaining = total - current;
|
||||
|
||||
return {
|
||||
total: total,
|
||||
current: current,
|
||||
remaining: remaining
|
||||
}
|
||||
}
|
||||
|
||||
getDaysInMonth(month, year) {
|
||||
return new Date(year, month, 0).getDate();
|
||||
}
|
||||
|
||||
// ISO 8601
|
||||
getISOWeek(date) {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const start = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
|
||||
return Math.ceil((((d - start) / 86400000) + 1) / 7);
|
||||
}
|
||||
|
||||
getISOWeeksInYear(year) {
|
||||
// Check if Dec 28 is in week 53
|
||||
return this.getISOWeek(new Date(year, 11, 28)) === 53 ? 53 : 52;
|
||||
}
|
||||
|
||||
getISOWeekInfo(date) {
|
||||
const current = this.getISOWeek(date);
|
||||
const weeksYear = this.getISOWeeksInYear(date.getFullYear());
|
||||
|
||||
return {
|
||||
current,
|
||||
weeksYear
|
||||
};
|
||||
}
|
||||
|
||||
getMoonNameFrom(phase) {
|
||||
if (phase < 0.125) return 'New Moon';
|
||||
if (phase < 0.25) return 'Waxing Crescent';
|
||||
if (phase < 0.375) return 'First Quarter';
|
||||
if (phase < 0.5) return 'Waxing Gibbous';
|
||||
if (phase < 0.625) return 'Full Moon';
|
||||
if (phase < 0.75) return 'Waning Gibbous';
|
||||
if (phase < 0.875) return 'Last Quarter';
|
||||
return 'Waning Crescent';
|
||||
}
|
||||
|
||||
getMoonPhase(date) {
|
||||
// Known new moon date: January 6, 2000
|
||||
const newMoon = new Date(2000, 0, 6);
|
||||
const lunarCycle = 29.53058867; // days
|
||||
|
||||
const daysSinceNewMoon = (date - newMoon) / (1000 * 60 * 60 * 24);
|
||||
const phase = (daysSinceNewMoon % lunarCycle) / lunarCycle;
|
||||
|
||||
return {
|
||||
illumination: Math.abs(Math.cos(Math.PI * phase)),
|
||||
phase: mapRange(phase, 0, 1, 1, 8),
|
||||
phaseName: this.getMoonNameFrom(phase)
|
||||
};
|
||||
}
|
||||
|
||||
getSize() {
|
||||
const height = window.innerHeight;
|
||||
const width = window.innerWidth;
|
||||
|
||||
return {
|
||||
value: Math.min(height, width),
|
||||
smaller: height < width ? 'height' : 'width'
|
||||
};
|
||||
}
|
||||
|
||||
getTime(date) {
|
||||
this.date = date || new Date();
|
||||
|
||||
return {
|
||||
second: this.date.getSeconds(),
|
||||
minute: this.date.getMinutes(),
|
||||
hour: this.date.getHours(),
|
||||
dayWeek: this.getWeekday(this.date),
|
||||
dayMonth: this.date.getDate(),
|
||||
dayYear: this.getYearInfo(this.date).current,
|
||||
daysYear: this.getYearInfo(this.date).total,
|
||||
week: this.getISOWeekInfo(this.date).current,
|
||||
weeksYear: this.getISOWeekInfo(this.date).weeksYear,
|
||||
month: this.date.getMonth() + 1, // Get current month (0-11)
|
||||
daysMonth: this.getDaysInMonth(this.date.getMonth() + 1, this.date.getFullYear()),
|
||||
moon: this.getMoonPhase(this.date).phase
|
||||
};
|
||||
}
|
||||
|
||||
#createContext(names) {
|
||||
const wrap = document.createElement('div');
|
||||
|
||||
wrap.style.position = 'relative';
|
||||
wrap.style.height = this.options.size + 'px';
|
||||
wrap.style.width = this.options.size + 'px';
|
||||
|
||||
names.forEach(name => {
|
||||
const canvas = document.createElement('canvas');
|
||||
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.top = '0px';
|
||||
canvas.style.left = '0px';
|
||||
canvas.style.height = '100%';
|
||||
canvas.style.width = '100%';
|
||||
canvas.height = canvas.offsetHeight;
|
||||
canvas.width = canvas.offsetWidth;
|
||||
|
||||
wrap.appendChild(canvas);
|
||||
this.parts.push({name: name, element: canvas, context: canvas.getContext('2d')});
|
||||
});
|
||||
|
||||
this.element.appendChild(wrap);
|
||||
this.parts.push({name: 'wrap', element: wrap});
|
||||
}
|
||||
|
||||
createOverlay() {
|
||||
const overlay = document.createElement('div');
|
||||
const text = document.createElement('p');
|
||||
const timeElement = document.createElement('span');
|
||||
const dateElement = document.createElement('span');
|
||||
|
||||
new DateDisplay(dateElement);
|
||||
new TimeDisplay(timeElement);
|
||||
|
||||
Object.assign(overlay.style, {
|
||||
zIndex: 5,
|
||||
position: 'absolute',
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
display: this.options.overlay ? 'flex' : 'none',
|
||||
// display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: `rgba(0, 0, 0, .6)`,
|
||||
color: 'white'
|
||||
});
|
||||
overlay.dataset.part = 'overlay';
|
||||
|
||||
text.appendChild(timeElement);
|
||||
text.insertAdjacentText('beforeend', ' ');
|
||||
text.appendChild(dateElement);
|
||||
overlay.appendChild(text);
|
||||
this.element.appendChild(overlay);
|
||||
this.parts.push({name: 'overlay', element: overlay});
|
||||
}
|
||||
|
||||
removeOverlay() {
|
||||
const index = this.parts.findIndex(s => s.name === 'overlay');
|
||||
|
||||
if (index !== -1) {
|
||||
this.parts[index].element.remove();
|
||||
this.parts.splice(index, 1);
|
||||
this.draw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Proxy für Optionen benutzen
|
||||
updateOptions(changes) {
|
||||
this.options = {...this.options, ...changes};
|
||||
|
||||
// TODO: Änderungen durch setzen von Optionen vornehmen, oder nicht?
|
||||
const drawOptions = new Set(['sections', 'h24']);
|
||||
const hasKey = Object.keys(changes).some(key => drawOptions.has(key));
|
||||
|
||||
if (hasKey) {
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
|
||||
updateShape(id, angle, max) {
|
||||
const shape = this.shapes.find(s => s.id === id);
|
||||
|
||||
if (shape) {
|
||||
shape.angle = angle;
|
||||
if (max) shape.max = max;
|
||||
}
|
||||
}
|
||||
|
||||
removeShape(id) {
|
||||
const index = this.shapes.findIndex(s => s.id === id);
|
||||
|
||||
if (index !== -1) {
|
||||
this.shapes.splice(index, 1);
|
||||
this.draw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
clearShapes() {
|
||||
this.shapes = [];
|
||||
this.draw();
|
||||
}
|
||||
|
||||
findShape(id) {
|
||||
return this.shapes.some(s => s.id === id);
|
||||
}
|
||||
|
||||
getShape(id) {
|
||||
return this.shapes.find(s => s.id === id);
|
||||
}
|
||||
|
||||
addCircle(id, center, radius, color = `rgba(0, 0, 0, .1)`) {
|
||||
this.shapes.push({type: 'circle', id, center, radius, color});
|
||||
}
|
||||
|
||||
addRing(id, radius, angle, max, color = 'white', center = .5, stroke = 16) {
|
||||
this.shapes.push({type: 'ring', id, radius, angle, max, color, center, stroke});
|
||||
}
|
||||
|
||||
addSection(id, radius, color = 'black', center = .5, stroke = 1) {
|
||||
this.shapes.push({type: 'section', id, radius, color, center, stroke});
|
||||
}
|
||||
}
|
||||
|
||||
const container = document.querySelector('#clock main');
|
||||
const clock = new HippieClock(container);
|
||||
|
||||
clock.addCircle('base', .5, 1);
|
||||
clock.draw();
|
||||
|
||||
// TODO: Alternative mit requestAnimationFrame()
|
||||
// TODO: Möglichkeit für Start/Stop wie bei TimeDisplay
|
||||
setInterval(() => {
|
||||
clock.update();
|
||||
}, 1000);
|
||||
|
||||
// TODO: Aktionen gehören quasi zu HippieClock
|
||||
document.getElementById('tglFormat').addEventListener('click', () => {
|
||||
if (clock) {
|
||||
clock.updateOptions({h24: !clock.options.h24});
|
||||
document.getElementById('tglFormat').textContent = clock.options.h24 ? '12-Stunden' : '24-Stunden';
|
||||
} else {
|
||||
console.log('No clock available');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('tglSections').addEventListener('click', () => {
|
||||
if (clock) {
|
||||
clock.updateOptions({sections: !clock.options.sections});
|
||||
} else {
|
||||
console.log('No clock available');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('tglOverlay').addEventListener('click', () => {
|
||||
if (clock) {
|
||||
// TODO: Anzeigen und ausblenden, anstatt löschen und hinzufügen?
|
||||
clock.updateOptions({overlay: !clock.options.overlay});
|
||||
|
||||
if (clock.options.overlay) {
|
||||
clock.createOverlay();
|
||||
} else {
|
||||
clock.removeOverlay();
|
||||
}
|
||||
} else {
|
||||
console.log('No clock available');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
22
source/view/demo/examples/game/index.liquid
Normal file
22
source/view/demo/examples/game/index.liquid
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
title: Game
|
||||
tags:
|
||||
- demoExample
|
||||
- index
|
||||
---
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% 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 %}
|
||||
141
source/view/demo/examples/game/intro.liquid
Normal file
141
source/view/demo/examples/game/intro.liquid
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
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 assets %}
|
||||
{{ block.super -}}
|
||||
<script src="/js/intro.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ block.super -}}
|
||||
<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 %}
|
||||
16
source/view/demo/examples/game/menu.liquid
Normal file
16
source/view/demo/examples/game/menu.liquid
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: Menu
|
||||
tags:
|
||||
- game
|
||||
---
|
||||
{% assign bodyClass = 'body_menu' -%}
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
{% render 'hippie/partials/game-menu.liquid', links: menu %}
|
||||
<footer>
|
||||
{% brand 'brand', 'last' %}
|
||||
<p>Marke</p>
|
||||
{% endbrand %}
|
||||
</footer>
|
||||
{% endblock %}
|
||||
86
source/view/demo/examples/game/mwo.liquid
Normal file
86
source/view/demo/examples/game/mwo.liquid
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
title: MWO
|
||||
tags:
|
||||
- game
|
||||
---
|
||||
{% assign bodyClass = 'body_mwo' -%}
|
||||
{% layout 'hippie/game.liquid' %}
|
||||
|
||||
{% block links %}
|
||||
{{ block.super -}}
|
||||
<link href="/vendor/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<canvas id="view"></canvas>
|
||||
|
||||
<header class="io controls">
|
||||
<nav>
|
||||
<button onclick="toggleAnimation()">Toggle</button>
|
||||
</nav>
|
||||
<nav>
|
||||
<span>Color</span>
|
||||
<button onclick="changeColor('black')">Black</button>
|
||||
<button onclick="changeColor('white')">White</button>
|
||||
<button onclick="changeColor('crimson')">Red</button>
|
||||
<button onclick="changeColor('#00ffff')">Cyan</button>
|
||||
</nav>
|
||||
<nav>
|
||||
<span>Crosshair</span>
|
||||
<button onclick="changeCrosshairStyle('cross')"><i class="bi bi-plus-lg"></i></button>
|
||||
<button onclick="changeCrosshairStyle('circle')"><i class="bi bi-circle"></i></button>
|
||||
<button onclick="changeCrosshairStyle('dot')"><i class="bi bi-dot"></i></button>
|
||||
<button onclick="changeCrosshairStyle('level')"><i class="bi bi-dash-circle"></i></button>
|
||||
</nav>
|
||||
<nav>
|
||||
<span>Connector</span>
|
||||
<button onclick="toggleConnector()">Toggle</button>
|
||||
<hr class="vertical">
|
||||
<button onclick="changeConnectorStyle('arrow')"><i class="bi bi-caret-up-fill"></i></button>
|
||||
<button onclick="changeConnectorStyle('square')"><i class="bi bi-square-fill"></i></button>
|
||||
<button onclick="changeConnectorStyle('circle')"><i class="bi bi-circle-fill"></i></button>
|
||||
<button onclick="changeConnectorStyle('diamond')"><i class="bi bi-diamond-fill"></i></button>
|
||||
</nav>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block assets %}
|
||||
<script src="/js/game.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
const canvas = document.getElementById('view');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
const crosshair = new HippieCrosshair(canvas);
|
||||
|
||||
function changeCrosshairStyle(style) {
|
||||
crosshair.setCrosshairStyle(style);
|
||||
}
|
||||
|
||||
function changeConnectorStyle(style) {
|
||||
crosshair.setConnectorStyle(style);
|
||||
}
|
||||
|
||||
function changeColor(color) {
|
||||
crosshair.setCrosshairColor(color);
|
||||
crosshair.setConnectorColor(color);
|
||||
crosshair.lineColor = `rgba(${parseInt(color.slice(1, 3), 16)}, ${parseInt(color.slice(3, 5), 16)}, ${parseInt(color.slice(5, 7), 16)}, 0.3)`;
|
||||
}
|
||||
|
||||
function toggleConnector() {
|
||||
crosshair.setConnectorVisibility(!crosshair.connectorShow);
|
||||
}
|
||||
|
||||
function toggleAnimation() {
|
||||
crosshair.toggleAnimation();
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
236
source/view/demo/examples/game/tfw.liquid
Normal file
236
source/view/demo/examples/game/tfw.liquid
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
---
|
||||
title: TFW
|
||||
tags:
|
||||
- game
|
||||
---
|
||||
{% assign bodyClass = 'body_tfw' -%}
|
||||
{% layout 'hippie/game.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<header class="io">
|
||||
<button data-action="escape">☰</button>
|
||||
<button data-direction="previous"><</button>
|
||||
<button data-view="quest">Quests</button>
|
||||
<button data-view="region">Regions</button>
|
||||
<button data-view="vendor">Vendors</button>
|
||||
<button data-view="manufacture">Manufacture</button>
|
||||
<button data-view="character">Characters</button>
|
||||
<button data-view="stash">Stash</button>
|
||||
<button data-view="secret">Secret Storage</button>
|
||||
<button data-view="squad">Squads</button>
|
||||
<button data-view="ready">Ready Room</button>
|
||||
<button data-direction="next">></button>
|
||||
</header>
|
||||
<div id="viewQuest" class="view">
|
||||
<main>
|
||||
<nav>
|
||||
<div class="important">Filter</div>
|
||||
<input placeholder="Search" aria-label="search" type="text">
|
||||
<select name="type" aria-label="type">
|
||||
<option value="" selected>Type</option>
|
||||
<option value="all">All</option>
|
||||
<option value="assasin">Assasination</option>
|
||||
<option value="loot">Looting</option>
|
||||
<option value="extract">Extract</option>
|
||||
<option value="fetch">Fetch</option>
|
||||
<option value="kill">Kill</option>
|
||||
</select>
|
||||
</nav>
|
||||
<div>
|
||||
<div>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col class="l">
|
||||
<col class="q">
|
||||
<col class="t">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<th>Location</th>
|
||||
<th>Quest</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="background">
|
||||
<span>Scorched Earth</span>
|
||||
</td>
|
||||
<td>...</td>
|
||||
<td class="subtle">Available</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="background">
|
||||
<span>Location name</span>
|
||||
</td>
|
||||
<td>...</td>
|
||||
<td class="subtle">Available</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col class="l">
|
||||
<col class="q">
|
||||
<col class="s">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<th colspan="3">Active quests (Max.: 4)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="background"></td>
|
||||
<td>King Of Kings</td>
|
||||
<td class="subtle">Active</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="background"></td>
|
||||
<td>Garage Days Pt. 1</td>
|
||||
<td class="subtle success">Complete</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="quest">
|
||||
<div class="background">
|
||||
<h2>King Of Kings</h2>
|
||||
</div>
|
||||
<p>A hijacked medium mech dubbed the "Rat King" ...</p>
|
||||
<hr class="dotted">
|
||||
<p>Collect Rat King residue.</p>
|
||||
<hr>
|
||||
<p>Multiple rig container upgrades, 5000 CR, 5000 XP, 2 days of water, + Scav faction
|
||||
rating</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="io">
|
||||
<button data-action="back">Back</button>
|
||||
<button data-action="accept">Accept</button>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="viewRegion" class="view"></div>
|
||||
<div id="viewVendor" class="view"></div>
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ block.super -}}
|
||||
<script>
|
||||
const menu = document.querySelector('body > header');
|
||||
const placeholder = document.querySelectorAll('.background');
|
||||
const viewQuest = document.getElementById('viewQuest');
|
||||
|
||||
class Menu {
|
||||
constructor(element, options = {}) {
|
||||
this._element = element;
|
||||
this._siblings = element.querySelectorAll('button[data-view]');
|
||||
this.default = options.default || 'quest';
|
||||
|
||||
element.addEventListener('click', this.onClick.bind(this)); // Bind to get the clicked element and not the DOM element of the class
|
||||
|
||||
this.#init();
|
||||
}
|
||||
|
||||
escape() {
|
||||
console.log('escape');
|
||||
}
|
||||
|
||||
#init() {
|
||||
const currentBtn = Array.from(this._siblings).find(
|
||||
el => el.dataset.view === this.default
|
||||
);
|
||||
|
||||
currentBtn.classList.add('active');
|
||||
this.changeView(this.default);
|
||||
}
|
||||
|
||||
// TODO: Sollte auch die Menüauswahl anpassen
|
||||
changeView(type) {
|
||||
console.debug(type);
|
||||
const id = 'view' + capitalizeFirstLetter(type);
|
||||
const views = document.querySelectorAll('.view');
|
||||
|
||||
for (const view of views) {
|
||||
view.style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById(id).style.display = 'flex';
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
const siblings = this._siblings;
|
||||
const action = event.target.dataset.action;
|
||||
const view = event.target.dataset.view;
|
||||
const direction = event.target.dataset.direction;
|
||||
|
||||
if (event.button !== 0) return;
|
||||
|
||||
if (direction) {
|
||||
const currentBtn = this._element.querySelector('.active');
|
||||
let newButton, newView = undefined;
|
||||
|
||||
if (currentBtn === null) return;
|
||||
|
||||
if (direction === 'next') {
|
||||
newButton = currentBtn.nextElementSibling;
|
||||
newView = currentBtn.nextElementSibling.dataset.view;
|
||||
} else {
|
||||
newButton = currentBtn.previousElementSibling;
|
||||
newView = currentBtn.previousElementSibling.dataset.view;
|
||||
}
|
||||
|
||||
if (!newButton.dataset.view) {
|
||||
newButton = direction === 'next' ? siblings[0] : siblings[siblings.length - 1];
|
||||
}
|
||||
|
||||
currentBtn.classList.remove('active');
|
||||
newButton.classList.add('active');
|
||||
this.changeView(newView);
|
||||
}
|
||||
|
||||
if (view) {
|
||||
for (const sibling of siblings) {
|
||||
sibling.classList.remove('active');
|
||||
}
|
||||
|
||||
this.changeView(view);
|
||||
event.target.classList.add('active');
|
||||
}
|
||||
|
||||
if (action) this[action]();
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Allgemeinere Umsetzung anstreben
|
||||
viewQuest.addEventListener('click', (event) => {
|
||||
const rows = viewQuest.querySelectorAll('tr');
|
||||
const rowTarget = event.target.closest('tr');
|
||||
|
||||
if (event.button !== 0) return;
|
||||
|
||||
// TODO: Ziele unterscheiden
|
||||
if (rowTarget) {
|
||||
for (const row of rows) {
|
||||
row.classList.remove('active');
|
||||
}
|
||||
|
||||
rowTarget.classList.add('active');
|
||||
document.querySelector('.quest').style.opacity = 1;
|
||||
document.querySelector('footer button[data-action=accept]').style.display = 'inline-block';
|
||||
}
|
||||
});
|
||||
|
||||
placeholder.forEach(element => {
|
||||
const hue = randomIntFrom(0, 360);
|
||||
const grayscale = randomFloatFrom(0, 1);
|
||||
|
||||
new RandomPixelPlaceholder(element, {
|
||||
width: Math.floor(element.clientWidth),
|
||||
height: Math.floor(element.clientHeight),
|
||||
colors: ['#fad803', '#d30a51', '#273f8b', '#b7e0f0', '#52bed1', '#0c85ff'],
|
||||
filter: 'grayscale(' + grayscale + ') hue-rotate(' + hue + 'deg)',
|
||||
type: 'img'
|
||||
});
|
||||
});
|
||||
|
||||
new Menu(menu);
|
||||
</script>
|
||||
{% endblock %}
|
||||
10
source/view/demo/examples/hello.md
Normal file
10
source/view/demo/examples/hello.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Hello World"
|
||||
layout: hippie/world.liquid
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
|
||||
# {{ title }}
|
||||
|
||||
This is a simple example for a *screen* written in Markdown, using Liquid *templates*.
|
||||
167
source/view/demo/examples/matrix.liquid
Normal file
167
source/view/demo/examples/matrix.liquid
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
---
|
||||
title: Matrix
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block style %}
|
||||
<style>
|
||||
html, body {
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: grey;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<canvas id="canvas"></canvas>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const canvas = document.getElementById("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
// const observer = new ResizeObserver(() => {
|
||||
// canvas.width = canvas.clientWidth;
|
||||
// canvas.height = canvas.clientHeight;
|
||||
// console.log("resize");
|
||||
// });
|
||||
|
||||
canvas.width = canvas.clientWidth;
|
||||
canvas.height = canvas.clientHeight;
|
||||
|
||||
// observer.observe(canvas);
|
||||
|
||||
ctx.font = "24px 'Courier New', Courier, monospace";
|
||||
ctx.textBaseline = "top";
|
||||
|
||||
let char = characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
let charMeasure = ctx.measureText(char);
|
||||
let charW = Math.ceil(Math.max(charMeasure.actualBoundingBoxLeft + charMeasure.actualBoundingBoxRight, charMeasure.width));
|
||||
let charH = charMeasure.fontBoundingBoxDescent + charMeasure.fontBoundingBoxAscent;
|
||||
let glyph = {
|
||||
text: char,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: charH,
|
||||
h: charH
|
||||
}
|
||||
let lane = [];
|
||||
let max = Math.floor(canvas.clientHeight / glyph.h);
|
||||
|
||||
let newId = undefined;
|
||||
let holdId = undefined;
|
||||
let cleanId = undefined;
|
||||
let newInterval = 300;
|
||||
let holdInterval = 1000;
|
||||
let cleanInterval = 400;
|
||||
let newIndex = 0;
|
||||
let cleanIndex = randomIntFrom(1, max);
|
||||
|
||||
console.log("init", newInterval);
|
||||
console.log(glyph);
|
||||
|
||||
newId = setInterval(newTrail, newInterval);
|
||||
|
||||
function newTrail() {
|
||||
clearInterval(holdId);
|
||||
|
||||
glyph.text = characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
console.log(newIndex, glyph.text);
|
||||
|
||||
lane.push([newIndex, glyph.text, glyph.y]);
|
||||
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(glyph.x, glyph.y, glyph.w, glyph.h);
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillText(glyph.text, Math.floor((charH - charW) / 2), glyph.y);
|
||||
|
||||
if (newIndex > 0) {
|
||||
let prevY = glyph.y - glyph.h;
|
||||
let alpha = randomBetween(.2, 1);
|
||||
ctx.clearRect(glyph.x, prevY, glyph.w, glyph.h);
|
||||
ctx.fillStyle = "rgba(0, 0, 0, " + alpha + ")";
|
||||
ctx.fillRect(glyph.x, prevY, glyph.w, glyph.h);
|
||||
ctx.fillStyle = "rgba(255, 255, 255, " + alpha + ")";
|
||||
// TODO: can not use array lane if it is changed by cleanTrail()
|
||||
ctx.fillText(lane[newIndex - 1][1], Math.floor((charH - charW) / 2), prevY);
|
||||
}
|
||||
|
||||
if (newIndex === cleanIndex) {
|
||||
console.log("clean", cleanInterval, cleanIndex);
|
||||
|
||||
cleanId = setInterval(cleanTrail, cleanInterval);
|
||||
}
|
||||
|
||||
newIndex++;
|
||||
glyph.y += glyph.h;
|
||||
|
||||
if (newIndex > max) {
|
||||
// console.log("hold", holdInterval);
|
||||
console.log("end");
|
||||
|
||||
clearInterval(newId);
|
||||
|
||||
newIndex = 0;
|
||||
glyph.y = 0;
|
||||
newInterval = randomIntFrom(100, 1000, 2);
|
||||
|
||||
// holdId = setTimeout(() => {
|
||||
// console.log("clean", cleanInterval);
|
||||
|
||||
// holdInterval = randomIntFrom(1000, 10000, 3);
|
||||
// cleanId = setInterval(cleanTrail, cleanInterval);
|
||||
// }, holdInterval);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanTrail() {
|
||||
let pos = lane.shift();
|
||||
console.log(pos);
|
||||
|
||||
ctx.clearRect(0, pos[2], glyph.w, glyph.h);
|
||||
|
||||
if (!lane.length) {
|
||||
console.log("hold", holdInterval);
|
||||
|
||||
clearInterval(cleanId);
|
||||
|
||||
holdId = setTimeout(() => {
|
||||
console.clear();
|
||||
console.log("new", newInterval);
|
||||
|
||||
cleanIndex = randomIntFrom(1, max);
|
||||
cleanInterval = randomIntFrom(1000, 10000, 3);
|
||||
holdInterval = randomIntFrom(1000, 10000, 3);
|
||||
newId = setInterval(newTrail, newInterval);
|
||||
}, holdInterval);
|
||||
}
|
||||
}
|
||||
|
||||
function randomBetween(min, max) {
|
||||
return (Math.random() * (max - min) + min).toFixed(2);
|
||||
}
|
||||
|
||||
function randomIntFrom(min, max, pos = 0) {
|
||||
pos = Math.pow(10, pos);
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
|
||||
return Math.floor((Math.random() * (max - min + 1) + min) / pos) * pos;
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
29
source/view/demo/examples/portal.liquid
Normal file
29
source/view/demo/examples/portal.liquid
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Portal
|
||||
tags:
|
||||
- demoExample
|
||||
image:
|
||||
src: '/art/flag_websafe_128x80.gif'
|
||||
alt: 'Flag of Interaktionsweise'
|
||||
links:
|
||||
- name: '1'
|
||||
href: 'http://domain.tld'
|
||||
img: '/art/bullet.gif'
|
||||
- name: 'Zwei'
|
||||
href: 'http://domain.tld'
|
||||
img: '/art/bullet.gif'
|
||||
---
|
||||
{% assign bodyClass = "body_portal" %}
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="portal">
|
||||
{% render 'hippie/partials/gate-list',
|
||||
name: 'Tor mit Symbol und Liste',
|
||||
url: '../demo',
|
||||
image: image,
|
||||
links: links
|
||||
%}
|
||||
{% render 'hippie/partials/gate-simple', name: 'Tor', url: '../demo' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
39
source/view/demo/examples/songbook.liquid
Normal file
39
source/view/demo/examples/songbook.liquid
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
title: Songbook
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="sec_main_center">
|
||||
<header class="header_txt">
|
||||
<h1>Titel</h1>
|
||||
<p>Jahr</p>
|
||||
</header>
|
||||
<nav role="doc-toc">
|
||||
<h2>Inhaltsverzeichnis</h2>
|
||||
<ul>
|
||||
{%- for song in collections.song -%}
|
||||
<li>
|
||||
<a href="{{ song.page.url }}">{{ song.data.title }}</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</nav>
|
||||
<h2>Vorwort</h2>
|
||||
<p>Liederbuch für
|
||||
<em>Name</em>.</p>
|
||||
<p>Gibt es gebunden und hier
|
||||
{% link hippie.placeholders.domain %}.<br/>
|
||||
Bestellungen bitte an
|
||||
{% text hippie.placeholders.name %}
|
||||
richten.</p>
|
||||
<hr class="double dotted">
|
||||
{%- for piece in collections.song -%}
|
||||
{% render 'hippie/partials/song.liquid', index: forloop.index0, data: piece.data, content: piece.content %}
|
||||
{%- endfor -%}
|
||||
<hr/>
|
||||
<address>{% text hippie.placeholders.name %}</address>
|
||||
</div>
|
||||
{% endblock %}
|
||||
26
source/view/demo/examples/songbook/0_artist-title.md
Executable file
26
source/view/demo/examples/songbook/0_artist-title.md
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
tags:
|
||||
- songbook
|
||||
- song
|
||||
title: "Interpret - Titel"
|
||||
releaseDate: JJJJ
|
||||
description: Text
|
||||
---
|
||||
~~~
|
||||
[verse 1]
|
||||
strophe 1
|
||||
|
||||
[chorus]
|
||||
refrain
|
||||
|
||||
[verse 2]
|
||||
strophe 2
|
||||
|
||||
[chorus]
|
||||
[bridge]
|
||||
überleitung
|
||||
|
||||
[interlude]
|
||||
[chorus]
|
||||
[outro]
|
||||
~~~
|
||||
184
source/view/demo/examples/start.liquid
Normal file
184
source/view/demo/examples/start.liquid
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
title: Start
|
||||
tags:
|
||||
- demoExample
|
||||
---
|
||||
{% assign pageId = page.fileSlug -%}
|
||||
{% assign bodyClass = 'body_start' -%}
|
||||
{% layout 'hippie/simple.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
{% render 'hippie/partials/header-status', hippie: hippie, links: start %}
|
||||
<main>
|
||||
<header class="io">
|
||||
<form id="wwwForm" class="group_nav" action="https://duckduckgo.com/">
|
||||
<input id="qrySearch" class="input_io" name="q" placeholder="Suchbegriff" type="text" required/>
|
||||
<input class="button_io" value="Suchen" type="submit"/>
|
||||
</form>
|
||||
<nav>
|
||||
<hr class="vertical">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="" class="a_button">A</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="a_button">B</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="area">
|
||||
<div>1</div>
|
||||
<div>2</div>
|
||||
<div>3</div>
|
||||
<div>4</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block assets %}
|
||||
<script src="/vendor/hippie-script.js"></script>
|
||||
<script src="/js/globals.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
const timeElement = document.getElementById('time');
|
||||
const dateElement = document.getElementById('date');
|
||||
// NOTE: https://duckduckgo.com/duckduckgo-help-pages/settings/params
|
||||
const defaultOptions = {
|
||||
kl: 'de-de',
|
||||
kp: '-2',
|
||||
kz: '-1',
|
||||
// kae: 't',
|
||||
k1: '-1'
|
||||
};
|
||||
let options = Object.assign({}, defaultOptions);
|
||||
|
||||
function setOptions(jsonOptions) {
|
||||
if (!jsonOptions || typeof jsonOptions !== 'object') return;
|
||||
|
||||
options = Object.assign({}, options, jsonOptions);
|
||||
}
|
||||
|
||||
function buildSearchUrl(query) {
|
||||
const base = 'https://duckduckgo.com/';
|
||||
const params = new URLSearchParams({q: query});
|
||||
|
||||
for (const [k, v] of Object.entries(options)) {
|
||||
if (v === undefined || v === null || v === '') continue;
|
||||
|
||||
params.set(k, String(v));
|
||||
}
|
||||
|
||||
return base + '?' + params.toString();
|
||||
}
|
||||
|
||||
// Example of setting options programmatically:
|
||||
// setOptions({ kl: 'de-de', kp: '2', iar: 'images' });
|
||||
|
||||
new TimeDisplay(timeElement, {hour: '2-digit', minute: '2-digit'});
|
||||
new DateDisplay(dateElement, {
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
// ongoing();
|
||||
|
||||
document.addEventListener('mousemove', (event) => {
|
||||
document
|
||||
.getElementById('log')
|
||||
.textContent = "X: " + event.pageX + ", Y: " + event.pageY;
|
||||
});
|
||||
|
||||
document.getElementById('wwwForm').addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
const query = document.getElementById('qrySearch').value.trim();
|
||||
|
||||
if (!query) return;
|
||||
|
||||
const url = buildSearchUrl(query);
|
||||
|
||||
window.open(url, '_blank', 'noopener');
|
||||
});
|
||||
|
||||
function ongoing() {
|
||||
var now = new Date();
|
||||
var w = Math.floor(now.getDay());
|
||||
var D = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
|
||||
var DNumb = Math.floor(now.getDate());
|
||||
var MNumb = Math.floor(now.getMonth());
|
||||
var M = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];
|
||||
var y = Math.floor(now.getYear());
|
||||
if (y < 999) y += 1900;
|
||||
|
||||
var ms = Math.floor(now.getMilliseconds());
|
||||
var s = Math.floor(now.getSeconds());
|
||||
var m = Math.floor(now.getMinutes() + s / 60);
|
||||
var h = Math.floor(now.getHours() + m / 60);
|
||||
|
||||
var j2000 = new Date(); // Bezugspunkt ist der 1.1.2000 0:00 UT (entspricht JD 2451544,5)
|
||||
j2000.setUTCFullYear(2000, 0, 1);
|
||||
j2000.setUTCHours(0, 0, 0, 0);
|
||||
|
||||
var utc = new Date();
|
||||
utc.setUTCFullYear(y, MNumb, DNumb); // Monate müssen im Wertebereich 0...11 übergeben werden
|
||||
utc.setUTCHours(h, m, s, ms);
|
||||
|
||||
var utc0 = new Date();
|
||||
utc0.setUTCFullYear(y, MNumb, DNumb);
|
||||
utc0.setUTCHours(0, 0, 0, 0);
|
||||
|
||||
var jd = 2451544.5 + (utc - j2000) / 86400000; // Zählung erfolgt in Millisekunden, 1 Tag = 86.400.000 ms
|
||||
var jdUTC0 = 2451544.5 + (utc0 - j2000) / 86400000;
|
||||
|
||||
var N = jd - 2451545.0;
|
||||
var L = 280.460 + 0.9856474 * N; // mittlere ekliptikale Länge der Sonne
|
||||
var g = 357.528 + 0.9856003 * N; // mittlere Anomalie
|
||||
var el = L + 1.915 * Math.sin(g) + 0.020 * Math.sin(2 * g);
|
||||
var e = 23.439 - 0.0000004 * N;
|
||||
var rektaszension = Math.atan((Math.cos(e) * Math.sin(el)) / Math.cos(el));
|
||||
|
||||
var T = (jdUTC0 - 2451545.0) / 36525;
|
||||
var stGMT = (((6 * 3600) + (41 * 60) + 50.54841) + (8640184.812866 * T) + (0.093104 * Math.pow(T, 2)) - (0.0000062 * Math.pow(T, 3))) / 3600;
|
||||
|
||||
var stGMT2 = 6.697376 + 2400.05134 * T + 1.002738 * T;
|
||||
var hWGMT = stGMT2 * 15;
|
||||
var hW = hWGMT + 11.9566185772;
|
||||
|
||||
var st = (stGMT + (now.getUTCHours() * 1.00273790935)) + (11.9566185772 / 15); // Sommerzeit muss noch berücksichtigt werden
|
||||
var st24 = Math.abs(st - (Math.round(st / 24) * 24));
|
||||
var stH = Math.floor(st24);
|
||||
var stM = Math.floor((st24 % 1) * 60);
|
||||
var stS = zeroFill(Math.floor((((st24 % 1) * 60) % 1) * 60), 2);
|
||||
|
||||
const travelWidth = document.body.clientWidth;
|
||||
const travelHeight = document.body.clientHeight;
|
||||
var sunPosX = 0;
|
||||
var sunPosY = 0;
|
||||
var moonPosX = 0;
|
||||
var moonPosY = 0;
|
||||
|
||||
const sun = document.getElementById('sun');
|
||||
|
||||
if (sun) {
|
||||
sun.style.left = (s / 60) * travelWidth;
|
||||
sun.style.top = (m / 60) * travelHeight;
|
||||
}
|
||||
|
||||
/*document.getElementById('time').textContent = '' + zeroFill(h, 2) + ':' + zeroFill(m, 2) + ':' + zeroFill(s, 2);
|
||||
document.getElementById('day').textContent = D[w];
|
||||
document.getElementById('dayNumb').textContent = DNumb;
|
||||
document.getElementById('month').textContent = M[MNumb];
|
||||
document.getElementById('year').textContent = y;
|
||||
|
||||
document.getElementById('julian').textContent = jd.toFixed(6);
|
||||
document.getElementById('star').textContent = stH + ':' + stM + ':' + stS;
|
||||
document.getElementById('star').textContent = stH + ':' + stM;
|
||||
document.getElementById('star1').textContent = stGMT;
|
||||
document.getElementById('star2').textContent = stGMT2;*/
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
60
source/view/demo/examples/ui/cli.liquid
Normal file
60
source/view/demo/examples/ui/cli.liquid
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
title: CLI
|
||||
tags:
|
||||
- ui
|
||||
---
|
||||
{% assign bodyClass = 'body_cli' -%}
|
||||
{% layout 'hippie/app.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
<div id="cli">
|
||||
<div id="history">
|
||||
<pre>Previous prompt</pre>
|
||||
</div>
|
||||
<div id="line">
|
||||
<textarea name="prefix" id="prefix" rows="1" cols="1" readonly>></textarea>
|
||||
<textarea name="prompt" id="prompt" rows="1" autofocus></textarea>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ block.super -}}
|
||||
<script>
|
||||
function resizeTextArea(textarea) {
|
||||
const {style, value} = textarea;
|
||||
|
||||
style.height = style.minHeight = 'auto';
|
||||
style.minHeight = `${Math.min(textarea.scrollHeight + 4, parseInt(textarea.style.maxHeight))}px`;
|
||||
style.height = `${textarea.scrollHeight}px`;
|
||||
}
|
||||
|
||||
const textarea = document.getElementById('prompt');
|
||||
|
||||
document
|
||||
.body
|
||||
.addEventListener('click', () => {
|
||||
textarea.focus();
|
||||
});
|
||||
|
||||
textarea.addEventListener('input', () => {
|
||||
resizeTextArea(textarea);
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
|
||||
const p = document.createElement("pre");
|
||||
|
||||
p.textContent = event.target.value;
|
||||
document
|
||||
.getElementById("history")
|
||||
.appendChild(p);
|
||||
// window.scrollTo(0, document.body.scrollHeight);
|
||||
|
||||
event.target.value = '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
52
source/view/demo/examples/ui/drag.liquid
Executable file
52
source/view/demo/examples/ui/drag.liquid
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
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 assets %}
|
||||
{{ block.super -}}
|
||||
<script src="/js/drag.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{%- block 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 %}
|
||||
145
source/view/demo/examples/ui/explorer.liquid
Normal file
145
source/view/demo/examples/ui/explorer.liquid
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
title: Explorer
|
||||
tags:
|
||||
- ui
|
||||
---
|
||||
{% assign bodyClass = 'body_frame' -%}
|
||||
{% layout 'hippie/app.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
{% render 'hippie/partials/frame-header.liquid' %}
|
||||
<main class="io">
|
||||
<aside class="io">
|
||||
<nav>
|
||||
<span>location-pane</span>
|
||||
<ul class="vertical">
|
||||
<li>
|
||||
<a class="a_button" href="">
|
||||
<span>Start/Home</span>
|
||||
<i class="bi bi-pin-fill"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="a_button" href="">
|
||||
<span>System</span>
|
||||
<i class="bi bi-pin-fill"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<hr>
|
||||
<nav>
|
||||
<ul class="vertical">
|
||||
<li>
|
||||
<a class="a_button" href="">
|
||||
<span>💽 disc link</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="a_button" href="">
|
||||
<span>📁 folder link</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="a_button" href="">
|
||||
<span>🔗 location link</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
<section>
|
||||
<header class="io">
|
||||
<nav>
|
||||
<button title="back">
|
||||
<i class="bi bi-caret-left"></i>
|
||||
</button>
|
||||
<button title="up">
|
||||
<i class="bi bi-caret-up"></i>
|
||||
</button>
|
||||
<button title="forward">
|
||||
<i class="bi bi-caret-right"></i>
|
||||
</button>
|
||||
<button title="reload">
|
||||
<i class="bi bi-arrow-clockwise"></i>
|
||||
</button>
|
||||
<input placeholder="//" type="text">
|
||||
</nav>
|
||||
<nav>
|
||||
<span>location-bar</span>
|
||||
<hr class="vertical">
|
||||
<button title="search">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
<input placeholder="*" type="text">
|
||||
</nav>
|
||||
</header>
|
||||
<header class="io">
|
||||
<nav>
|
||||
<button title="add">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
<div class="spacer a"></div>
|
||||
<button title="cut">
|
||||
<i class="bi bi-scissors"></i>
|
||||
</button>
|
||||
<button title="copy">
|
||||
<i class="bi bi-copy"></i>
|
||||
</button>
|
||||
<button title="paste">
|
||||
<i class="bi bi-clipboard-check-fill"></i>
|
||||
</button>
|
||||
<div class="spacer b"></div>
|
||||
<button title="delete">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<hr class="vertical">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<button title="collapse">
|
||||
<i class="bi bi-arrows-collapse"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button title="expand">
|
||||
<i class="bi bi-arrows-expand-vertical"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<span>options-bar</span>
|
||||
</nav>
|
||||
<nav></nav>
|
||||
</header>
|
||||
<div id="content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>date</th>
|
||||
<th>type</th>
|
||||
<th>size</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>folder</td>
|
||||
<td>YYYY-MM-DD</td>
|
||||
<td>folder</td>
|
||||
<td>4KB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>file</td>
|
||||
<td>YYYY-MM-DD</td>
|
||||
<td>folder</td>
|
||||
<td>1B</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% render 'hippie/partials/frame-status.liquid' %}
|
||||
</section>
|
||||
</main>
|
||||
{% render 'hippie/partials/frame-mode.liquid' %}
|
||||
{% endblock %}
|
||||
56
source/view/demo/examples/ui/form.liquid
Normal file
56
source/view/demo/examples/ui/form.liquid
Normal 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 %}
|
||||
78
source/view/demo/examples/ui/gallery.liquid
Executable file
78
source/view/demo/examples/ui/gallery.liquid
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
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_nav">
|
||||
<input id="setSize" value="5" min="1" max="10" step="1" type="range"/>
|
||||
<label class="right" for="setSize">Größe</label>
|
||||
</div>
|
||||
<button title="details">
|
||||
<i class="bi bi-layout-sidebar-reverse"></i> 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('setSize');
|
||||
const galleryItems = document.querySelectorAll('.gallery > 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 () {
|
||||
console.debug('Change size');
|
||||
// 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 %}
|
||||
24
source/view/demo/examples/ui/index.liquid
Normal file
24
source/view/demo/examples/ui/index.liquid
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
title: UI
|
||||
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 ui in collections.ui -%}
|
||||
<li>
|
||||
<a href="{{ ui.page.url }}">{{ ui.data.title }}</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{% endblock %}
|
||||
462
source/view/demo/examples/ui/table.liquid
Executable file
462
source/view/demo/examples/ui/table.liquid
Executable file
|
|
@ -0,0 +1,462 @@
|
|||
---
|
||||
title: Table
|
||||
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_nav">
|
||||
<button id="addEntry" title="Add entry">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
<div class="wrap_input"><input id="setScroll" type="checkbox"></div>
|
||||
<label for="setScroll">Scroll to new entry</label>
|
||||
</div>
|
||||
</nav>
|
||||
<nav>
|
||||
<button id="tglIndex" title="Toggle index column">
|
||||
<i class="bi bi-hash"></i>
|
||||
</button>
|
||||
<div class="group_nav">
|
||||
<select id="sltNum" name="position-number" aria-label="numbering">
|
||||
<option value="" selected>None</option>
|
||||
<option value="numeric">123</option>
|
||||
<option value="latin">ABC</option>
|
||||
<option value="roman">IVX</option>
|
||||
</select>
|
||||
<button id="setPosNum" title="Set numbering" type="button"><i class="bi bi-list-ol"></i></button>
|
||||
</div>
|
||||
{% comment %}TODO: Auswahl für ziehbares Element hinzufügen{% endcomment %}
|
||||
</nav>
|
||||
</header>
|
||||
<table id="content" class="draggable content horizontal">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" title="Index">#</th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col" title="Position">#</th>
|
||||
<th scope="col">Number</th>
|
||||
<th scope="col">Name</th>
|
||||
<th class="max" scope="col">Description</th>
|
||||
<th scope="col">Amount</th>
|
||||
<th scope="col">Unit</th>
|
||||
<th scope="col">Price</th>
|
||||
<th scope="col">Sum</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="positions"></tbody>
|
||||
</table>
|
||||
{% render 'hippie/partials/frame-status.liquid' %}
|
||||
</section>
|
||||
</main>
|
||||
<template id="rowDefault">
|
||||
<tr draggable="true">
|
||||
<th scope="row"></th>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<input class="input_io" name="active" aria-label="active" type="checkbox">
|
||||
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
||||
</nav>
|
||||
</td>
|
||||
<td class="pos-num"></td>
|
||||
<td><input class="input_io" name="number" aria-label="number" type="text"></td>
|
||||
<td><input class="input_io" name="name" aria-label="name" type="text"></td>
|
||||
{% comment %}<td class="ellipsis"></td>{% endcomment %}
|
||||
<td>
|
||||
<textarea class="fit" name="description" cols="64" rows="2" aria-label="description"></textarea>
|
||||
</td>
|
||||
<td><input class="input_io" name="amount" aria-label="amount" type="number"></td>
|
||||
<td>
|
||||
<select class="io_select" name="unit" aria-label="unit">
|
||||
<option value="">None</option>
|
||||
<option value="piece">Piece(s)</option>
|
||||
<option value="hour">Hour(s)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="input_io" name="price" aria-label="price" type="text"></td>
|
||||
<td class="unit"></td>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
||||
<button title="Note"><i class="bi bi-journal"></i></button>
|
||||
<button title="Delete"><i class="bi bi-trash"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template id="rowArticle">
|
||||
<tr draggable="true">
|
||||
<th scope="row"></th>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<input class="input_io" name="active" aria-label="active" type="checkbox">
|
||||
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
||||
</nav>
|
||||
</td>
|
||||
<td class="pos-num"></td>
|
||||
<td class="rigid"></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<textarea class="fit" name="description" cols="64" rows="2" aria-label="description"></textarea>
|
||||
</td>
|
||||
<td><input name="amount" aria-label="number" type="number"></td>
|
||||
<td>
|
||||
<select name="unit" aria-label="unit">
|
||||
<option value="">None</option>
|
||||
<option value="piece">Piece(s)</option>
|
||||
<option value="hour">Hour(s)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="unit"></td>
|
||||
<td class="unit"></td>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
||||
<button title="Note"><i class="bi bi-journal"></i></button>
|
||||
<button title="Delete"><i class="bi bi-trash"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template id="rowText">
|
||||
<tr draggable="true">
|
||||
<th scope="row"></th>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<input class="input_io" name="active" aria-label="active" type="checkbox">
|
||||
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
||||
</nav>
|
||||
</td>
|
||||
<td class="pos-num"></td>
|
||||
<td colspan="7">
|
||||
<textarea class="fit" name="description" cols="64" rows="2" aria-label="description"></textarea>
|
||||
</td>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<button title="Delete"><i class="bi bi-trash"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template id="rowGroup">
|
||||
<tr draggable="true" class="header">
|
||||
<th scope="row"></th>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<input class="input_io" name="active" aria-label="active" type="checkbox">
|
||||
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
||||
<button name="group" title="Expand"><i class="bi bi-arrows-expand"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
<td class="pos-num"></td>
|
||||
<td colspan="7">Group</td>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<button title="Delete"><i class="bi bi-trash"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td></td>
|
||||
<td class="pos-num"></td>
|
||||
<td colspan="7">Content</td>
|
||||
<td class="io">
|
||||
<nav>
|
||||
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
||||
<button title="Note"><i class="bi bi-journal"></i></button>
|
||||
<button title="Delete"><i class="bi bi-trash"></i></button>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="footer">
|
||||
<th scope="row"></th>
|
||||
<td></td>
|
||||
<td class="pos-num"></td>
|
||||
<td colspan="8">End</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
{% render 'hippie/partials/frame-mode.liquid' %}
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ block.super -}}
|
||||
<script>
|
||||
const placeholderNames = [
|
||||
'Mac',
|
||||
'Sonic',
|
||||
'Furiosa',
|
||||
'Leia',
|
||||
'Frisbee',
|
||||
'Ripley',
|
||||
'Motoko',
|
||||
'Lupin',
|
||||
'Yoda',
|
||||
'Spike',
|
||||
'Obelix',
|
||||
'Samus',
|
||||
'Plisken'
|
||||
];
|
||||
const placeholderAttributes = [
|
||||
'blue',
|
||||
'tall',
|
||||
'clever',
|
||||
'true'
|
||||
];
|
||||
const placeholderContents = [
|
||||
'Description - At vero eos et accusam et justo duo dolores et ea rebum.',
|
||||
'',
|
||||
"Content with linebreaks - \nPhasellus finibus mollis diam non posuere. Vestibulum porttitor volutpat consectetur. Duis neque sapien, tincidunt ac odio vel, laoreet ultricies ligula. Suspendisse erat eros, volutpat vel fringilla at, placerat ac nisi. \nNulla arcu elit, facilisis egestas risus ac, aliquet varius sapien. Sed et nisi fringilla nibh ultrices sagittis ac in nisl. \nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam porta lectus ac pharetra feugiat. In ligula nunc, porttitor non arcu vel, feugiat tempor mi. Aenean pellentesque ipsum ac ligula pulvinar, vel auctor diam vehicula. Sed at arcu lacus.",
|
||||
'Very long content - Suspendisse lectus orci, convallis vitae sapien et, iaculis cursus magna. Pellentesque ultrices sodales eros eget vehicula. Aliquam tincidunt nulla non finibus ullamcorper. Ut accumsan nisi non aliquam fermentum. Vestibulum sit amet purus eu dolor vulputate pretium in eget libero. Donec vitae quam in leo eleifend semper. Cras mollis orci augue, vitae aliquam quam consequat quis. Donec sed nisi sed nulla ultricies ultricies quis ac erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris euismod mollis neque sit amet varius. In malesuada nibh faucibus orci tincidunt, in elementum sapien pretium. Cras vel urna felis. Proin cursus tempor egestas. Nulla facilisis justo enim. Mauris fermentum, tortor a malesuada facilisis, leo tortor aliquam elit, sed sodales ipsum tortor et tellus.',
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum facilisis condimentum quam, bibendum tristique odio.'
|
||||
];
|
||||
|
||||
const currencyEuro = new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'});
|
||||
|
||||
const content = document.querySelector('main.io section > table');
|
||||
const tbodyPosition = document.getElementById('positions');
|
||||
|
||||
tbodyPosition.addEventListener('click', (event) => {
|
||||
const rows = tbodyPosition.querySelectorAll('tr');
|
||||
const rowTarget = event.target.closest('tr');
|
||||
const groupTarget = event.target.closest('[name="group"]');
|
||||
|
||||
if (event.button !== 0) return;
|
||||
|
||||
if (rowTarget) {
|
||||
for (const row of rows) {
|
||||
row.classList.remove('active');
|
||||
}
|
||||
|
||||
rowTarget.classList.add('active');
|
||||
}
|
||||
|
||||
if (groupTarget) {
|
||||
console.log('group');
|
||||
let currentRow = groupTarget.closest('tr').nextElementSibling;
|
||||
|
||||
while (currentRow && !currentRow.classList.contains('footer')) {
|
||||
currentRow.classList.toggle('di_none');
|
||||
currentRow = currentRow.nextElementSibling;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const t = Math.random();
|
||||
let type = undefined;
|
||||
|
||||
if (t < .2) {
|
||||
type = 'default';
|
||||
} else if (t >= .2 && t < .4) {
|
||||
type = 'text';
|
||||
} else if (t >= .4 && t < .5) {
|
||||
type = 'group';
|
||||
} else {
|
||||
type = 'article';
|
||||
}
|
||||
|
||||
tbodyPosition.appendChild(cloneRow(i, type));
|
||||
}
|
||||
|
||||
const selectNum = document.getElementById('sltNum');
|
||||
const buttonPosNum = document.getElementById('setPosNum');
|
||||
|
||||
buttonPosNum.addEventListener('click', () => {
|
||||
const numType = selectNum.value;
|
||||
const cells = tbodyPosition.querySelectorAll('td.pos-num');
|
||||
let num = '';
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
switch (numType) {
|
||||
case 'numeric':
|
||||
num = (i + 1).toString();
|
||||
break;
|
||||
case 'roman':
|
||||
num = convertToRomanNumeral((i + 1)).toString();
|
||||
break;
|
||||
case '':
|
||||
default:
|
||||
}
|
||||
|
||||
cells[i].textContent = num;
|
||||
}
|
||||
});
|
||||
|
||||
const buttonIndex = document.getElementById('tglIndex');
|
||||
|
||||
buttonIndex.addEventListener('click', () => {
|
||||
const cells = content.querySelectorAll('th:first-child');
|
||||
const isHidden = cells[0].classList.contains('di_none');
|
||||
|
||||
for (const cell of cells) {
|
||||
if (isHidden) {
|
||||
cell.classList.remove('di_none');
|
||||
} else {
|
||||
cell.classList.add('di_none');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const buttonAdd = document.getElementById('addEntry');
|
||||
const checkScroll = document.getElementById('setScroll');
|
||||
|
||||
buttonAdd.addEventListener('click', () => {
|
||||
const clone = cloneRow();
|
||||
const viewportHeight = window.innerHeight;
|
||||
const elementActive = tbodyPosition.querySelector('tr.active');
|
||||
let elementNew;
|
||||
let elementBound = undefined;
|
||||
|
||||
if (elementActive) {
|
||||
elementActive.after(clone);
|
||||
elementNew = elementActive.nextElementSibling;
|
||||
} else {
|
||||
tbodyPosition.appendChild(clone);
|
||||
elementNew = tbodyPosition.lastElementChild;
|
||||
}
|
||||
|
||||
if (checkScroll.checked) {
|
||||
elementBound = elementNew.getBoundingClientRect();
|
||||
|
||||
if (elementBound.bottom > viewportHeight || elementBound.top < 0) {
|
||||
elementNew.scrollIntoView({behavior: 'smooth', block: 'nearest'});
|
||||
}
|
||||
}
|
||||
|
||||
reindexRows(tbodyPosition);
|
||||
});
|
||||
|
||||
let draggedRow = null;
|
||||
|
||||
tbodyPosition.addEventListener('dragstart', (event) => {
|
||||
const rowTarget = event.target.closest('tr[draggable="true"]');
|
||||
|
||||
if (rowTarget) {
|
||||
draggedRow = rowTarget;
|
||||
rowTarget.classList.add('dragging');
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
|
||||
console.debug('Drag', rowTarget);
|
||||
}
|
||||
});
|
||||
|
||||
tbodyPosition.addEventListener('dragend', () => {
|
||||
if (draggedRow) {
|
||||
draggedRow.classList.remove('dragging');
|
||||
draggedRow = null;
|
||||
}
|
||||
});
|
||||
|
||||
tbodyPosition.addEventListener('dragover', (event) => {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
|
||||
const rowTarget = event.target.closest('tr');
|
||||
|
||||
if (rowTarget && rowTarget !== draggedRow) {
|
||||
const rows = [...tbodyPosition.querySelectorAll('tr')];
|
||||
const draggedIndex = rows.indexOf(draggedRow);
|
||||
const targetIndex = rows.indexOf(rowTarget);
|
||||
|
||||
if (draggedIndex < targetIndex) {
|
||||
rowTarget.parentNode.insertBefore(draggedRow, rowTarget.nextSibling);
|
||||
} else {
|
||||
rowTarget.parentNode.insertBefore(draggedRow, rowTarget);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tbodyPosition.addEventListener('drop', (event) => {
|
||||
event.preventDefault();
|
||||
reindexRows(event.currentTarget);
|
||||
|
||||
console.debug('Drop');
|
||||
});
|
||||
|
||||
function cloneRow(index, type = 'article') {
|
||||
const id = 'row' + capitalizeFirstLetter(type);
|
||||
|
||||
const rowFragment = document.getElementById(id).content;
|
||||
const tr = rowFragment.querySelector('tr');
|
||||
const th = rowFragment.querySelector('th');
|
||||
const td = rowFragment.querySelectorAll('td');
|
||||
|
||||
const j = index % placeholderNames.length;
|
||||
const k = randomIntFrom(0, placeholderContents.length - 1);
|
||||
const l = Math.random() > .2;
|
||||
const amount = randomIntFrom(1, 100);
|
||||
const price = randomFloatFrom(1, 10000, 2);
|
||||
const sum = amount * price;
|
||||
|
||||
tr.setAttribute('data-id', index);
|
||||
th.textContent = index + 1;
|
||||
td[0].querySelector('[name="active"]').checked = l;
|
||||
// td[2].innerHTML = replaceLineBreaks(placeholderContents[k]);
|
||||
|
||||
switch (type) {
|
||||
case 'default':
|
||||
td[2].firstElementChild.style.width = '9ch';
|
||||
td[3].firstElementChild.style.width = '6ch';
|
||||
td[4].firstElementChild.textContent = placeholderContents[k];
|
||||
td[5].firstElementChild.value = amount;
|
||||
td[5].firstElementChild.style.width = '4em';
|
||||
td[7].firstElementChild.style.width = '8ch';
|
||||
td[8].textContent = currencyEuro.format(sum);
|
||||
break;
|
||||
case 'article':
|
||||
td[2].textContent = getRandomFormattedString();
|
||||
td[3].textContent = placeholderNames[j];
|
||||
td[4].firstElementChild.textContent = placeholderContents[k];
|
||||
td[5].firstElementChild.value = amount;
|
||||
td[5].firstElementChild.style.width = '4em';
|
||||
td[7].textContent = currencyEuro.format(price);
|
||||
td[8].textContent = currencyEuro.format(sum);
|
||||
break;
|
||||
case 'text':
|
||||
td[2].firstElementChild.textContent = placeholderContents[k];
|
||||
break;
|
||||
default:
|
||||
console.debug('No matching type found.');
|
||||
}
|
||||
|
||||
return document.importNode(rowFragment, true);
|
||||
}
|
||||
|
||||
function reindexRows(parent, selector = 'tr') {
|
||||
const rows = parent.querySelectorAll(selector);
|
||||
let th = undefined;
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
th = rows[i].querySelector('th');
|
||||
th.textContent = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleGroup(headerRow) {
|
||||
// Get the toggle icon
|
||||
const icon = headerRow.querySelector('.toggle-icon');
|
||||
|
||||
// Get all rows after this header
|
||||
let currentRow = headerRow.nextElementSibling;
|
||||
|
||||
// Toggle visibility of group rows until next header
|
||||
while (currentRow && !currentRow.classList.contains('group-header')) {
|
||||
currentRow.classList.toggle('hidden');
|
||||
currentRow = currentRow.nextElementSibling;
|
||||
}
|
||||
|
||||
// Toggle the icon rotation
|
||||
icon.classList.toggle('collapsed');
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
13
source/view/demo/examples/ui/tui.liquid
Normal file
13
source/view/demo/examples/ui/tui.liquid
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: TUI
|
||||
tags:
|
||||
- ui
|
||||
---
|
||||
{% assign bodyClass = 'body_frame' -%}
|
||||
{% layout 'hippie/app.liquid' %}
|
||||
|
||||
{% block body %}
|
||||
{% render 'hippie/partials/frame-header.liquid' %}
|
||||
<main class="io"></main>
|
||||
{% render 'hippie/partials/frame-mode.liquid' %}
|
||||
{% endblock %}
|
||||
82
source/view/demo/examples/ui/windows.liquid
Normal file
82
source/view/demo/examples/ui/windows.liquid
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
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>
|
||||
<button id="setPause"><i class="bi bi-pause"></i></button>
|
||||
<button id="setPlay"><i class="bi bi-play"></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>
|
||||
<div class="clock">
|
||||
<span id="time">##:##</span>
|
||||
<br>
|
||||
</div>
|
||||
<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 class="box"></div>
|
||||
<div class="box_brd"></div>
|
||||
<div>
|
||||
<span>task bar</span>
|
||||
<div class="box_brd"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block assets %}
|
||||
{{ block.super -}}
|
||||
<script src="/js/windows.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ block.super -}}
|
||||
<script>
|
||||
console.log(HIPPIE.brand);
|
||||
// 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');
|
||||
// TODO: TimeDisplay in HippieTaskbar aufnehmen
|
||||
const timeElement = document.getElementById('time');
|
||||
|
||||
const taskBar = new HippieTaskBar(draggableElement, placeholderElement);
|
||||
const timeFormat = {hour: '2-digit', minute: '2-digit'};
|
||||
const timeDisplay = new TimeDisplay(timeElement, timeFormat);
|
||||
|
||||
document.getElementById('setPause').addEventListener('click', () => {
|
||||
timeDisplay.pause();
|
||||
console.info('Pause time');
|
||||
});
|
||||
document.getElementById('setPlay').addEventListener('click', () => {
|
||||
timeDisplay.resume();
|
||||
console.info('Resume time');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue