Browse Source

FEAT: Adding base code for the jpc-like-websites components.

master v1.0.0
chris 7 months ago
parent
commit
4423c3a917
  1. 1
      .gitignore
  2. 33
      README.md
  3. 18
      index.html
  4. 9
      join_js_files.sh
  5. 551
      jpc-like-websites.js
  6. 36
      package-lock.json
  7. 20
      package.json
  8. 67
      samplePage.js
  9. 60
      src/js/baseComponents.js
  10. 26
      src/js/builder.js
  11. 140
      src/js/component.js
  12. 164
      src/js/componentAttribute.js
  13. 32
      src/js/context.js
  14. 128
      src/js/modifier.js
  15. 15
      tsconfig.json

1
.gitignore

@ -0,0 +1 @@
node_modules/

33
README.md

@ -1,2 +1,35 @@
# jpc-like-websites # 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.

18
index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample Page</title>
<script src="jpc-like-websites.js"></script>
</head>
<body>
<main>
<div id="root"></div>
</main>
<footer>
<script src="samplePage.js"></script>
</footer>
</body>
</html>

9
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

551
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<Component>} 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<Component>} 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())
}
}

36
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
}
}
}

20
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"
}
}

67
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")
)
])
)

60
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<Component>} 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")
)
}
}

26
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())
}
}

140
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<Component>} 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)`)
}
}

164
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,
})

32
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();

128
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;
}
}

15
tsconfig.json

@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES2020",
"declaration": true,
"outDir": "./lib"
},
"include": [
"./src/ts/*"
],
"exclude": [
"node_modules",
"./lib/**/*"
]
}
Loading…
Cancel
Save