diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/README.md b/README.md
index 90cf692..c2bc8c3 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,35 @@
# jpc-like-websites
+> Jetpack Compose like websites
+The building method of Jetpack Compose (for android),
+feels really straight forward
+and intuitive for me.
+Furthermore I personally found it more readable
+than my limited experiences with flutter
+(which were just two "get to know" bootstrap projects to be fair).
+Since I found myself frequently building small (local) websites for minor tasks (calculations, tasks etc.).
+I was looking for an option
+to build those websites more or less fast (easy)
+and reliable.
+While they do look the way I intend them to.
+
+After developing some minor apps with Jetpack Compose I liked a lot about the way
+the components are build/structured.
+The reusability and so on...
+
+Further I love to write code in a "method-chaning" kind of way:
+Every line is a chain-link concerning one particular task,
+the IDE offers an overview of possibilities.
+Method-chaining is more or less native in Kotlin.
+Logical support for git-line-wise change detection.
+
+After some (very little) searching,
+I choose to give it a couple of hours
+and develop a small "lib" to enable myself to do exactly that.
+> Develop jetpack compose like components in html/javascript.
+
+Javascript is by far not my strongest field,
+typescript even less.
+So it is recommended to not expect to much,
+you have been warned.
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9346fac
--- /dev/null
+++ b/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+ Sample Page
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/join_js_files.sh b/join_js_files.sh
new file mode 100644
index 0000000..d2eaf9e
--- /dev/null
+++ b/join_js_files.sh
@@ -0,0 +1,9 @@
+TARGET="jpc-like-websites.js"
+SRC="src/js"
+ORDERED_LIST="context.js componentAttribute.js modifier.js component.js baseComponents.js builder.js"
+
+echo "" > $TARGET
+
+for i in $ORDERED_LIST; do
+ cat $SRC/$i >> $TARGET
+done
\ No newline at end of file
diff --git a/jpc-like-websites.js b/jpc-like-websites.js
new file mode 100644
index 0000000..8dcbbfd
--- /dev/null
+++ b/jpc-like-websites.js
@@ -0,0 +1,551 @@
+
+/**
+ * The class provides overreaching options for building the website.
+ */
+class PageBuilder {
+ #cssClasses;
+ #functions;
+
+ constructor() {
+ this.#cssClasses = document.createElement("style");
+ this.#functions = document.createElement("script");
+ }
+
+ /**
+ * Registers a function to be added later in a script tag in the head of the document.
+ * @param {string} name
+ * @param {func} fun
+ */
+ registerFunction(name, fun) {
+ this.#functions.innerText += `const ${name} = ${fun}`;
+ }
+
+ /**
+ * Adds a script tag into the head of the document.
+ */
+ generate() {
+ document.querySelector("head")
+ .appendChild(this.#functions)
+ }
+
+}
+
+const Page = new PageBuilder();
+/**
+ * Enum to access common events
+ */
+const CommonEvents = Object.freeze({
+ ONCLICK: "onClick",
+})
+
+/**
+ * A simple Color class for rgb set color values.
+ */
+class Color {
+ #red;
+ #green;
+ #blue;
+
+ constructor(red, green, blue) {
+ this.#red = red
+ this.#green = green
+ this.#blue = blue
+ }
+
+ /**
+ *
+ * @returns {string} an rgb object string
+ */
+ cssRGBString() {
+ return `rgb(${this.#red}, ${this.#green}, ${this.#blue})`;
+ }
+}
+
+/**
+ * Simple Dimensions container for the height and width in pixels.
+ */
+class Dimensions {
+ #x;
+ #y;
+
+ /**
+ * Sets width (x) value of pixels
+ * @param {number} pixels
+ * @returns this Dimensions Modifier
+ */
+ width(pixels) {
+ this.x = pixels;
+ return this;
+ }
+
+ /**
+ * Sets height (y) value of pixels
+ * @param {number} pixels
+ * @returns this Dimensions Modifier
+ */
+ height(pixels) {
+ this.y = pixels;
+ return this;
+ }
+}
+
+/**
+ * The Class holds values from each side/direction of an element.
+ * Used for margin/padding.
+ */
+class Siding {
+ pxLeft = 0;
+ pxRight = 0;
+ pxTop = 0;
+ pxBottom = 0;
+
+ /**
+ * sets the pixels-value for all sides.
+ * @param {number} pixels siding from all sides
+ * @returns this Siding Object
+ */
+ all(pixels) {
+ this.pxLeft = pixels;
+ this.pxRight = pixels;
+ this.pxTop = pixels;
+ this.pxBottom = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the horizontal sides (left and right).
+ * @param {number} pixels siding for left and right.
+ * @returns this Siding Object
+ */
+ horizontal(pixels) {
+ this.pxLeft = pixels;
+ this.pxRight = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the vertical sides (left and right).
+ * @param {number} pixels siding for top and bottom.
+ * @returns this Siding Object
+ */
+ vertical(pixels) {
+ this.pxTop = pixels;
+ this.pxBottom = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the left side.
+ * @param {number} pixels siding for left
+ * @returns this Siding Object
+ */
+ left(pixels) {
+ this.pxLeft = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the right side.
+ * @param {number} pixels siding for right
+ * @returns this Siding Object
+ */
+ right(pixels) {
+ this.pxRight = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the top side.
+ * @param {number} pixels siding for top
+ * @returns this Siding Object
+ */
+ top(pixels) {
+ this.pxTop = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the bottom side.
+ * @param {number} pixels siding for bottom
+ * @returns this Siding Object
+ */
+ bottom(pixels) {
+ this.pxBottom = pixels;
+ return this;
+ }
+}
+
+/**
+ * Enum providing common alignment rules
+ */
+const Alignment = Object.freeze({
+ BEGIN_BORDER: 0,
+ CENTER: 1,
+ END_BORDER: 2,
+})
+
+/**
+ * Enum providing common alignment rules
+ */
+const Arrangement = Object.freeze({
+ START: 0,
+ END: 1,
+ CENTER: 2,
+ SPACE_BETWEEN: 3,
+ SPACE_EVENLY: 4,
+ SPACE_AROUND: 5,
+})
+/**
+ * A chained class that sets most of the stylings of an element.
+ */
+class Modifier {
+ modifications = {};
+
+ constructor() {
+ this.modifications = new Object();
+ }
+ /**
+ * Sets the modifications for widht and height to 100%.
+ * @returns this modifier object
+ */
+ fillMaxSize() {
+ this.modifications["width"] = "100%";
+ this.modifications["height"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets the modification for width to 100%.
+ * @returns this modifier object
+ */
+ fillMaxWidth() {
+ this.modifications["width"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets the modification for height to 100%.
+ * @returns this modifier object
+ */
+ fillMaxHeight() {
+ this.modifications["height"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets modifications according to the dimensions object.
+ * @param {Dimensions} dimensions
+ * @returns this modifier object
+ */
+ size(dimensions) {
+ this.modifications["height"] = dimensions.height + "px";
+ this.modifications["width"] = dimensions.width + "px";
+ return this;
+ }
+
+ /**
+ * Sets the padding on all sides according to the given siding object.
+ * Currently the padding will always be set
+ * to the most recent padding/siding.
+ * @param {Siding} siding
+ * @returns this modifier object
+ */
+ padding(siding) {
+ this.modifications["padding-right"] = siding.pxRight + "px";
+ this.modifications["padding-left"] = siding.pxLeft + "px";
+ this.modifications["padding-top"] = siding.pxTop + "px";
+ this.modifications["padding-bottom"] = siding.pxBottom + "px";
+ return this;
+ }
+
+ /**
+ * Sets the margin on all sides according to the given siding object.
+ * Currently the margin will always be set
+ * to the most recent margin/siding.
+ * @param {Siding} siding
+ * @returns this modifier object
+ */
+ margin(siding) {
+ this.modifications["margin-right"] = siding.pxRight + "px";
+ this.modifications["margin-left"] = siding.pxLeft + "px";
+ this.modifications["margin-top"] = siding.pxTop + "px";
+ this.modifications["margin-bottom"] = siding.pxBottom + "px";
+ return this;
+ }
+
+ /**
+ * Sets the background-color as a rgb color.
+ * @param {Color} color
+ * @returns this modifier object
+ */
+ background(color) {
+ this.modifications["background-color"] = color.cssRGBString();
+ return this;
+ }
+
+ /**
+ * Sets the color as a rgb color.
+ * @param {Color} color
+ * @returns this modifier object
+ */
+ color(color) {
+ this.modifications["color"] = color.cssRGBString();
+ return this;
+ }
+
+ /**
+ * Adds the modifications of the given Modifier to current Modifier.
+ * This is especailly used in the cases of extending existing/pre defined
+ * Components.
+ * CAUTION matching existing modifications will be ignored.
+ * @param modifier The "new" Modifier
+ * @returns The "old/current" Modifier,
+ * extended with the modifications of the given Modifier.
+ */
+ join(modifier, modifications = {}) {
+ var keys = Object.keys(modifier.modifications);
+ for (let i = 0; i < keys.length; i++) {
+ if (!this.modifications.hasOwnProperty(keys[i]))
+ this.modifications[keys[i]] = modifier.modifications[keys[i]];
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} key a css style rule
+ * @param {string} value the corresponding value to the css style rule
+ * @returns this modifier object
+ */
+ setStyleRule(key, value) {
+ this.modifications[key] = value;
+ return this;
+ }
+
+}
+/**
+ * A chainable HTMLElement builder.
+ */
+class Component {
+ _element;
+ _modifier
+ _alignment;
+ _arrangement;
+
+ constructor(element, attr = {}) {
+ this._modifier = new Modifier().margin(new Siding().all(0));
+ this._element = element;
+ Object.keys(attr)
+ .forEach(key => {
+ this._element.setAttribute(key, attr[key]);
+ })
+ }
+
+ /**
+ * Sets the alignment (modifications) for this element or more specific for its children.
+ * @param {Alignment} alignment
+ * @returns this component object
+ */
+ alignment(alignment) {
+ this._alignment = alignment;
+ return this;
+ }
+
+ /**
+ * Sets the arrangement (modifications) for this element or more specific for its children.
+ * @param {Arrangement} arrangement
+ * @returns this component object
+ */
+ arrangement(arrangement) {
+ this._arrangement = arrangement;
+ switch (arrangement) {
+ case Arrangement.START:
+ this._modifier.modifications["justify-content", "start"]
+ break;
+ case Arrangement.END:
+ this._modifier.modifications["justify-content", "end"]
+ break;
+ case Arrangement.CENTER:
+ this._modifier.modifications["justify-content", "center"]
+ break;
+ case Arrangement.SPACE_AROUND:
+ this._modifier.modifications["justify-content", "space-around"]
+ break;
+ case Arrangement.SPACE_BETWEEN:
+ this._modifier.modifications["justify-content", "space-between"]
+ break;
+ case Arrangement.SPACE_EVENLY:
+ this._modifier.modifications["justify-content", "space-evenly"]
+ break;
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {Modifier} modifier
+ * @returns this component object
+ */
+ modifier(modifier) {
+ this._modifier = this._modifier.join(modifier)
+ return this;
+ }
+
+ /**
+ * Sets the innerText of the element
+ * @param {string} text
+ * @returns this component object
+ */
+ text(text) {
+ this._element.innerText = text;
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} styleClass
+ * @returns this component object
+ */
+ addStyleClass(styleClass) {
+ this._element.classList.add(styleClass);
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} key
+ * @param {string} value
+ * @returns this component object
+ */
+ setAttribute(key, value) {
+ this._element.setAttribute(key, value);
+ return this;
+ }
+
+
+ /**
+ * Ends chain.
+ * Applies all modifications on the element.
+ * @returns {HTMLElemment} the html element
+ */
+ generate() {
+ var mkeys = Object.keys(this._modifier.modifications);
+ for (let i = 0; i < mkeys.length; i++) {
+ this._element.style[mkeys[i]] = this._modifier.modifications[mkeys[i]];
+ }
+ return this._element;
+ }
+
+ /**
+ *
+ * @param {Component|Array} innerComponent
+ * @returns this component object
+ */
+ childContext(innerComponent) {
+ if (innerComponent instanceof Array) {
+ for (let i = 0; i < innerComponent.length; i++) {
+ this._element.append(innerComponent[i].generate());
+ }
+ } else {
+ this._element.append(innerComponent.generate());
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {CommonEvent} commonEvent
+ * @param {string} functionName
+ * @returns this component object
+ */
+ setEvent(commonEvent, functionName) {
+ return this.setAttribute(commonEvent, `${functionName}(this)`)
+ }
+
+}
+/**
+ * Represents container Components.
+ * Some predefined modifications are applied on the child components.
+ */
+class FlexContainerComponent extends Component {
+ constructor(attr = {}) {
+ super(document.createElement("div"), attr)
+ .addStyleClass("flex-container-component")
+ }
+
+ /**
+ *
+ * @param {Component|Array} innerComponent
+ * @returns this component object
+ */
+ childContext(innerComponent) {
+ if (innerComponent instanceof Array) {
+ innerComponent.forEach(icomp => {
+ icomp.modifier(
+ new Modifier()
+ .setStyleRule("flex", "none")
+ )
+ })
+ } else {
+ innerComponent.modifier(
+ new Modifier()
+ .setStyleRule("flex", "none")
+ )
+ }
+ return super.childContext(innerComponent);
+ }
+}
+
+/**
+ * A FlexContainerComponent, which organizes the children in a column like manner.
+ */
+class Column extends FlexContainerComponent {
+ constructor(attr = {}) {
+ super(document.createElement("div"), attr)
+ .addStyleClass("column-component")
+ .modifier(
+ new Modifier()
+ .setStyleRule("flex-direction", "column")
+ );
+ }
+}
+
+/**
+ * A FlexContainerComponent, which organizes the children in a row like manner.
+ */
+class Row extends FlexContainerComponent {
+ constructor(attr = {}) {
+ super(attr)
+ .addStyleClass("row-component")
+ .modifier(
+ new Modifier()
+ .setStyleRule("flex-direction", "row")
+ )
+ }
+}
+const builder = {
+ genTag: function (tag, attr = {}) { return new Component(document.createElement(tag), attr); },
+
+ anchor: function (attr = {}) { return builder.genTag("a", attr); },
+ label: function (attr = {}) { return builder.genTag("label", attr); },
+ button: function (attr = {}) { return builder.genTag("button", attr); },
+ input: function (attr = {}) { return builder.genTag("input", attr); },
+ div: function (attr = {}) { return builder.genTag("div", attr); },
+ paragraph: function (attr = {}) { return builder.genTag("paragraph", attr); },
+ header: function (sizeGroup, attr = {}) { return builder.genTag(`h${sizeGroup}`, attr); },
+ checkbox: function (attr = {}) { return builder.genTag("checkbox", attr); },
+ selection: function (attr = {}) { return builder.genTag("selection", attr); },
+ option: function (attr = {}) { return builder.genTag("option", attr); },
+ section: function (attr = {}) { return builder.genTag("section", attr); },
+ radioBtn: function (attr = {}) { return builder.genTag("radioBtn", attr); },
+ icon: function (attr = {}) { return builder.genTag("icon", attr); },
+ img: function (attr = {}) { return builder.genTag("img", attr); },
+ textarea: function (attr = {}) { return builder.genTag("textarea", attr); },
+
+ row: function (attr = {}) { return new Row(attr) },
+ column: function (attr = {}) { return new Column(attr) },
+ page: function(innerComponents){
+ Page.generate();
+ document.querySelector('#root').appendChild(innerComponents.generate())
+ }
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..80ad93c
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,36 @@
+{
+ "name": "websites-like-jpc",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "version": "1.0.0",
+ "license": "ISC",
+ "devDependencies": {
+ "typescript": "^5.5.4"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ }
+ },
+ "dependencies": {
+ "typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fa58ec5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "websites-like-jpc",
+ "version": "1.0.0",
+ "description": "Framework to build websites in a Jetpack Compose like manner, as well as an extensive use of method-chaingin.",
+ "main": "lib/index.js",
+ "typings": "lib/index.d.ts",
+ "files": [
+ "/lib"
+ ],
+ "scripts": {
+ "prepare": "npm run build",
+ "build": "tsc",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "typescript": "^5.5.4"
+ }
+}
diff --git a/samplePage.js b/samplePage.js
new file mode 100644
index 0000000..811a365
--- /dev/null
+++ b/samplePage.js
@@ -0,0 +1,67 @@
+const fileSelection = function (labelText) {
+ return builder.row()
+ .arrangement(Arrangement.SPACE_BETWEEN)
+ .modifier(
+ new Modifier().fillMaxWidth()
+ .padding(
+ new Siding()
+ .horizontal(64)
+ .vertical(16)
+ )
+ )
+ .childContext([
+ builder.label().text(labelText),
+ builder.input().setAttribute("type", "file")
+ ])
+}
+
+const fileSelectionSection = function () {
+ return builder.column()
+ .arrangement(Arrangement.CENTER)
+ .modifier(
+ new Modifier()
+ .fillMaxWidth()
+ .padding(new Siding().vertical(16))
+ )
+ .childContext([
+ fileSelection("Script"),
+ builder.row()
+ .arrangement(Arrangement.CENTER)
+ .modifier(
+ new Modifier().fillMaxWidth()
+ )
+ .childContext([
+ builder.button()
+ .text('+')
+ .setEvent(CommonEvents.ONCLICK, "addFileSelection")
+ ])
+ ])
+}
+
+builder.page (
+ builder.column()
+ .modifier(
+ new Modifier()
+ .fillMaxSize()
+ )
+ .childContext([
+ builder.row()
+ .arrangement(Arrangement.SPACE_BETWEEN)
+ .modifier(
+ new Modifier().fillMaxWidth()
+ )
+ .childContext([
+ builder.header(1).text("Script Executer"),
+ builder.img().setAttribute("alt", "Logo")
+ ])
+ ,
+ fileSelectionSection()
+ ,
+ builder.row()
+ .arrangement(Arrangement.CENTER)
+ .childContext(
+ builder.button()
+ .text("Execute Script")
+ )
+ ])
+)
diff --git a/src/js/baseComponents.js b/src/js/baseComponents.js
new file mode 100644
index 0000000..ac93f36
--- /dev/null
+++ b/src/js/baseComponents.js
@@ -0,0 +1,60 @@
+/**
+ * Represents container Components.
+ * Some predefined modifications are applied on the child components.
+ */
+class FlexContainerComponent extends Component {
+ constructor(attr = {}) {
+ super(document.createElement("div"), attr)
+ .addStyleClass("flex-container-component")
+ }
+
+ /**
+ *
+ * @param {Component|Array} innerComponent
+ * @returns this component object
+ */
+ childContext(innerComponent) {
+ if (innerComponent instanceof Array) {
+ innerComponent.forEach(icomp => {
+ icomp.modifier(
+ new Modifier()
+ .setStyleRule("flex", "none")
+ )
+ })
+ } else {
+ innerComponent.modifier(
+ new Modifier()
+ .setStyleRule("flex", "none")
+ )
+ }
+ return super.childContext(innerComponent);
+ }
+}
+
+/**
+ * A FlexContainerComponent, which organizes the children in a column like manner.
+ */
+class Column extends FlexContainerComponent {
+ constructor(attr = {}) {
+ super(document.createElement("div"), attr)
+ .addStyleClass("column-component")
+ .modifier(
+ new Modifier()
+ .setStyleRule("flex-direction", "column")
+ );
+ }
+}
+
+/**
+ * A FlexContainerComponent, which organizes the children in a row like manner.
+ */
+class Row extends FlexContainerComponent {
+ constructor(attr = {}) {
+ super(attr)
+ .addStyleClass("row-component")
+ .modifier(
+ new Modifier()
+ .setStyleRule("flex-direction", "row")
+ )
+ }
+}
diff --git a/src/js/builder.js b/src/js/builder.js
new file mode 100644
index 0000000..2c52269
--- /dev/null
+++ b/src/js/builder.js
@@ -0,0 +1,26 @@
+const builder = {
+ genTag: function (tag, attr = {}) { return new Component(document.createElement(tag), attr); },
+
+ anchor: function (attr = {}) { return builder.genTag("a", attr); },
+ label: function (attr = {}) { return builder.genTag("label", attr); },
+ button: function (attr = {}) { return builder.genTag("button", attr); },
+ input: function (attr = {}) { return builder.genTag("input", attr); },
+ div: function (attr = {}) { return builder.genTag("div", attr); },
+ paragraph: function (attr = {}) { return builder.genTag("paragraph", attr); },
+ header: function (sizeGroup, attr = {}) { return builder.genTag(`h${sizeGroup}`, attr); },
+ checkbox: function (attr = {}) { return builder.genTag("checkbox", attr); },
+ selection: function (attr = {}) { return builder.genTag("selection", attr); },
+ option: function (attr = {}) { return builder.genTag("option", attr); },
+ section: function (attr = {}) { return builder.genTag("section", attr); },
+ radioBtn: function (attr = {}) { return builder.genTag("radioBtn", attr); },
+ icon: function (attr = {}) { return builder.genTag("icon", attr); },
+ img: function (attr = {}) { return builder.genTag("img", attr); },
+ textarea: function (attr = {}) { return builder.genTag("textarea", attr); },
+
+ row: function (attr = {}) { return new Row(attr) },
+ column: function (attr = {}) { return new Column(attr) },
+ page: function(innerComponents){
+ Page.generate();
+ document.querySelector('#root').appendChild(innerComponents.generate())
+ }
+}
diff --git a/src/js/component.js b/src/js/component.js
new file mode 100644
index 0000000..70091bb
--- /dev/null
+++ b/src/js/component.js
@@ -0,0 +1,140 @@
+/**
+ * A chainable HTMLElement builder.
+ */
+class Component {
+ _element;
+ _modifier
+ _alignment;
+ _arrangement;
+
+ constructor(element, attr = {}) {
+ this._modifier = new Modifier().margin(new Siding().all(0));
+ this._element = element;
+ Object.keys(attr)
+ .forEach(key => {
+ this._element.setAttribute(key, attr[key]);
+ })
+ }
+
+ /**
+ * Sets the alignment (modifications) for this element or more specific for its children.
+ * @param {Alignment} alignment
+ * @returns this component object
+ */
+ alignment(alignment) {
+ this._alignment = alignment;
+ return this;
+ }
+
+ /**
+ * Sets the arrangement (modifications) for this element or more specific for its children.
+ * @param {Arrangement} arrangement
+ * @returns this component object
+ */
+ arrangement(arrangement) {
+ this._arrangement = arrangement;
+ switch (arrangement) {
+ case Arrangement.START:
+ this._modifier.modifications["justify-content", "start"]
+ break;
+ case Arrangement.END:
+ this._modifier.modifications["justify-content", "end"]
+ break;
+ case Arrangement.CENTER:
+ this._modifier.modifications["justify-content", "center"]
+ break;
+ case Arrangement.SPACE_AROUND:
+ this._modifier.modifications["justify-content", "space-around"]
+ break;
+ case Arrangement.SPACE_BETWEEN:
+ this._modifier.modifications["justify-content", "space-between"]
+ break;
+ case Arrangement.SPACE_EVENLY:
+ this._modifier.modifications["justify-content", "space-evenly"]
+ break;
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {Modifier} modifier
+ * @returns this component object
+ */
+ modifier(modifier) {
+ this._modifier = this._modifier.join(modifier)
+ return this;
+ }
+
+ /**
+ * Sets the innerText of the element
+ * @param {string} text
+ * @returns this component object
+ */
+ text(text) {
+ this._element.innerText = text;
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} styleClass
+ * @returns this component object
+ */
+ addStyleClass(styleClass) {
+ this._element.classList.add(styleClass);
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} key
+ * @param {string} value
+ * @returns this component object
+ */
+ setAttribute(key, value) {
+ this._element.setAttribute(key, value);
+ return this;
+ }
+
+
+ /**
+ * Ends chain.
+ * Applies all modifications on the element.
+ * @returns {HTMLElemment} the html element
+ */
+ generate() {
+ var mkeys = Object.keys(this._modifier.modifications);
+ for (let i = 0; i < mkeys.length; i++) {
+ this._element.style[mkeys[i]] = this._modifier.modifications[mkeys[i]];
+ }
+ return this._element;
+ }
+
+ /**
+ *
+ * @param {Component|Array} innerComponent
+ * @returns this component object
+ */
+ childContext(innerComponent) {
+ if (innerComponent instanceof Array) {
+ for (let i = 0; i < innerComponent.length; i++) {
+ this._element.append(innerComponent[i].generate());
+ }
+ } else {
+ this._element.append(innerComponent.generate());
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {CommonEvent} commonEvent
+ * @param {string} functionName
+ * @returns this component object
+ */
+ setEvent(commonEvent, functionName) {
+ return this.setAttribute(commonEvent, `${functionName}(this)`)
+ }
+
+}
diff --git a/src/js/componentAttribute.js b/src/js/componentAttribute.js
new file mode 100644
index 0000000..4af42ec
--- /dev/null
+++ b/src/js/componentAttribute.js
@@ -0,0 +1,164 @@
+/**
+ * Enum to access common events
+ */
+const CommonEvents = Object.freeze({
+ ONCLICK: "onClick",
+})
+
+/**
+ * A simple Color class for rgb set color values.
+ */
+class Color {
+ #red;
+ #green;
+ #blue;
+
+ constructor(red, green, blue) {
+ this.#red = red
+ this.#green = green
+ this.#blue = blue
+ }
+
+ /**
+ *
+ * @returns {string} an rgb object string
+ */
+ cssRGBString() {
+ return `rgb(${this.#red}, ${this.#green}, ${this.#blue})`;
+ }
+}
+
+/**
+ * Simple Dimensions container for the height and width in pixels.
+ */
+class Dimensions {
+ #x;
+ #y;
+
+ /**
+ * Sets width (x) value of pixels
+ * @param {number} pixels
+ * @returns this Dimensions Modifier
+ */
+ width(pixels) {
+ this.x = pixels;
+ return this;
+ }
+
+ /**
+ * Sets height (y) value of pixels
+ * @param {number} pixels
+ * @returns this Dimensions Modifier
+ */
+ height(pixels) {
+ this.y = pixels;
+ return this;
+ }
+}
+
+/**
+ * The Class holds values from each side/direction of an element.
+ * Used for margin/padding.
+ */
+class Siding {
+ pxLeft = 0;
+ pxRight = 0;
+ pxTop = 0;
+ pxBottom = 0;
+
+ /**
+ * sets the pixels-value for all sides.
+ * @param {number} pixels siding from all sides
+ * @returns this Siding Object
+ */
+ all(pixels) {
+ this.pxLeft = pixels;
+ this.pxRight = pixels;
+ this.pxTop = pixels;
+ this.pxBottom = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the horizontal sides (left and right).
+ * @param {number} pixels siding for left and right.
+ * @returns this Siding Object
+ */
+ horizontal(pixels) {
+ this.pxLeft = pixels;
+ this.pxRight = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the vertical sides (left and right).
+ * @param {number} pixels siding for top and bottom.
+ * @returns this Siding Object
+ */
+ vertical(pixels) {
+ this.pxTop = pixels;
+ this.pxBottom = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the left side.
+ * @param {number} pixels siding for left
+ * @returns this Siding Object
+ */
+ left(pixels) {
+ this.pxLeft = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the right side.
+ * @param {number} pixels siding for right
+ * @returns this Siding Object
+ */
+ right(pixels) {
+ this.pxRight = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the top side.
+ * @param {number} pixels siding for top
+ * @returns this Siding Object
+ */
+ top(pixels) {
+ this.pxTop = pixels;
+ return this;
+ }
+
+ /**
+ * sets the pixels-value for the bottom side.
+ * @param {number} pixels siding for bottom
+ * @returns this Siding Object
+ */
+ bottom(pixels) {
+ this.pxBottom = pixels;
+ return this;
+ }
+}
+
+/**
+ * Enum providing common alignment rules
+ */
+const Alignment = Object.freeze({
+ BEGIN_BORDER: 0,
+ CENTER: 1,
+ END_BORDER: 2,
+})
+
+/**
+ * Enum providing common alignment rules
+ */
+const Arrangement = Object.freeze({
+ START: 0,
+ END: 1,
+ CENTER: 2,
+ SPACE_BETWEEN: 3,
+ SPACE_EVENLY: 4,
+ SPACE_AROUND: 5,
+})
diff --git a/src/js/context.js b/src/js/context.js
new file mode 100644
index 0000000..c30bc6f
--- /dev/null
+++ b/src/js/context.js
@@ -0,0 +1,32 @@
+/**
+ * The class provides overreaching options for building the website.
+ */
+class PageBuilder {
+ #cssClasses;
+ #functions;
+
+ constructor() {
+ this.#cssClasses = document.createElement("style");
+ this.#functions = document.createElement("script");
+ }
+
+ /**
+ * Registers a function to be added later in a script tag in the head of the document.
+ * @param {string} name
+ * @param {func} fun
+ */
+ registerFunction(name, fun) {
+ this.#functions.innerText += `const ${name} = ${fun}`;
+ }
+
+ /**
+ * Adds a script tag into the head of the document.
+ */
+ generate() {
+ document.querySelector("head")
+ .appendChild(this.#functions)
+ }
+
+}
+
+const Page = new PageBuilder();
diff --git a/src/js/modifier.js b/src/js/modifier.js
new file mode 100644
index 0000000..e09d449
--- /dev/null
+++ b/src/js/modifier.js
@@ -0,0 +1,128 @@
+/**
+ * A chained class that sets most of the stylings of an element.
+ */
+class Modifier {
+ modifications = {};
+
+ constructor() {
+ this.modifications = new Object();
+ }
+ /**
+ * Sets the modifications for widht and height to 100%.
+ * @returns this modifier object
+ */
+ fillMaxSize() {
+ this.modifications["width"] = "100%";
+ this.modifications["height"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets the modification for width to 100%.
+ * @returns this modifier object
+ */
+ fillMaxWidth() {
+ this.modifications["width"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets the modification for height to 100%.
+ * @returns this modifier object
+ */
+ fillMaxHeight() {
+ this.modifications["height"] = "100%";
+ return this;
+ }
+
+ /**
+ * Sets modifications according to the dimensions object.
+ * @param {Dimensions} dimensions
+ * @returns this modifier object
+ */
+ size(dimensions) {
+ this.modifications["height"] = dimensions.height + "px";
+ this.modifications["width"] = dimensions.width + "px";
+ return this;
+ }
+
+ /**
+ * Sets the padding on all sides according to the given siding object.
+ * Currently the padding will always be set
+ * to the most recent padding/siding.
+ * @param {Siding} siding
+ * @returns this modifier object
+ */
+ padding(siding) {
+ this.modifications["padding-right"] = siding.pxRight + "px";
+ this.modifications["padding-left"] = siding.pxLeft + "px";
+ this.modifications["padding-top"] = siding.pxTop + "px";
+ this.modifications["padding-bottom"] = siding.pxBottom + "px";
+ return this;
+ }
+
+ /**
+ * Sets the margin on all sides according to the given siding object.
+ * Currently the margin will always be set
+ * to the most recent margin/siding.
+ * @param {Siding} siding
+ * @returns this modifier object
+ */
+ margin(siding) {
+ this.modifications["margin-right"] = siding.pxRight + "px";
+ this.modifications["margin-left"] = siding.pxLeft + "px";
+ this.modifications["margin-top"] = siding.pxTop + "px";
+ this.modifications["margin-bottom"] = siding.pxBottom + "px";
+ return this;
+ }
+
+ /**
+ * Sets the background-color as a rgb color.
+ * @param {Color} color
+ * @returns this modifier object
+ */
+ background(color) {
+ this.modifications["background-color"] = color.cssRGBString();
+ return this;
+ }
+
+ /**
+ * Sets the color as a rgb color.
+ * @param {Color} color
+ * @returns this modifier object
+ */
+ color(color) {
+ this.modifications["color"] = color.cssRGBString();
+ return this;
+ }
+
+ /**
+ * Adds the modifications of the given Modifier to current Modifier.
+ * This is especailly used in the cases of extending existing/pre defined
+ * Components.
+ * CAUTION matching existing modifications will be ignored.
+ * @param modifier The "new" Modifier
+ * @returns The "old/current" Modifier,
+ * extended with the modifications of the given Modifier.
+ */
+ join(modifier, modifications = {}) {
+ var keys = Object.keys(modifier.modifications);
+ for (let i = 0; i < keys.length; i++) {
+ if (!this.modifications.hasOwnProperty(keys[i]))
+ this.modifications[keys[i]] = modifier.modifications[keys[i]];
+ }
+ return this;
+ }
+
+ /**
+ *
+ * @param {string} key a css style rule
+ * @param {string} value the corresponding value to the css style rule
+ * @returns this modifier object
+ */
+ setStyleRule(key, value) {
+ this.modifications[key] = value;
+ return this;
+ }
+
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..e3ed51a
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "module": "CommonJS",
+ "target": "ES2020",
+ "declaration": true,
+ "outDir": "./lib"
+ },
+ "include": [
+ "./src/ts/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "./lib/**/*"
+ ]
+}