add initial project for frontend
Signed-off-by: Tobias Erbshäußer <tobias@tesoft.dev>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<template id="tesoft-button-template">
|
||||
<style>
|
||||
@import "src/styles/default.css";
|
||||
</style>
|
||||
|
||||
<button>
|
||||
<slot></slot>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script src="/src/components/button.ts" type="module"></script>
|
||||
@@ -0,0 +1,15 @@
|
||||
import {TesoftComponent} from "../scripts/main.ts";
|
||||
|
||||
export class TesoftButton extends TesoftComponent {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const template = document.getElementById("tesoft-button-template") as HTMLTemplateElement;
|
||||
const templateContent = template.content;
|
||||
|
||||
const shadowRoot = this.attachShadow({mode: "open"});
|
||||
shadowRoot.appendChild(templateContent.cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("tesoft-button", TesoftButton);
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ title }}</title>
|
||||
<link rel="stylesheet" href="/src/styles/main.css">
|
||||
{% block styles %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
{% block components %}
|
||||
{% endblock %}
|
||||
{% block sources %}
|
||||
{% endblock %}
|
||||
<script src="/src/scripts/main.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
{% extends 'layouts/main.njk' %}
|
||||
|
||||
{% set title='TESOFT - Home' %}
|
||||
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="/src/styles/index.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block sources %}
|
||||
<script src="/src/scripts/index.ts" type="module"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block components %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,85 @@
|
||||
export abstract class TesoftComponent extends HTMLElement {
|
||||
private ready: boolean;
|
||||
|
||||
protected constructor() {
|
||||
super();
|
||||
|
||||
this.ready = false;
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
async connectedCallback() {
|
||||
const promises = [];
|
||||
|
||||
for (const child of findComponents(this.shadowRoot)) {
|
||||
promises.push(new Promise(resolve =>
|
||||
window.customElements.whenDefined(child.tagName.toLowerCase()).then(() => {
|
||||
if (child.isConnected) {
|
||||
resolve(void {});
|
||||
} else {
|
||||
child.addEventListener("ready", (e: any) => {
|
||||
e.preventDefault();
|
||||
resolve(void {});
|
||||
}, {once: true});
|
||||
}
|
||||
})
|
||||
));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
await this.populate();
|
||||
|
||||
this.ready = true;
|
||||
this.dispatchEvent(new CustomEvent("ready", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}));
|
||||
}
|
||||
|
||||
async populate() {
|
||||
// Overwrite if necessary in components
|
||||
}
|
||||
|
||||
get isReady(): boolean {
|
||||
return this.ready;
|
||||
}
|
||||
}
|
||||
|
||||
function findComponents(root: any | null): TesoftComponent[] {
|
||||
const components = [];
|
||||
|
||||
for (const child of root?.querySelectorAll("*") ?? []) {
|
||||
if (child.tagName.toLowerCase().startsWith("snz-")) {
|
||||
components.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
export function onReady(callback: () => void, ...components: TesoftComponent[]) {
|
||||
async function domLoaded() {
|
||||
if (components.length === 0) {
|
||||
components = findComponents(document);
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
for (const component of components) {
|
||||
if (!component.isReady) {
|
||||
promises.push(new Promise(resolve => {
|
||||
component.addEventListener("ready", resolve, {once: true});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
callback();
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", domLoaded, {once: true});
|
||||
} else {
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
domLoaded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
:root {
|
||||
|
||||
}
|
||||
|
||||
html {
|
||||
/* Set font-size so that 1rem = 10 px */
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
line-height: 2.1rem;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
*::before {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
@import "default.css";
|
||||
Reference in New Issue
Block a user