merge front end to server

This commit is contained in:
Nikola Petrov 2024-08-01 14:36:35 +02:00
parent d2e06bfaab
commit 76f638d818
16 changed files with 1160 additions and 5 deletions

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ public/assets/build/
.vscode/
package-lock.json
bun.lockb
bundle.js

26
build.ts Normal file
View File

@ -0,0 +1,26 @@
async function build() {
const minify = {
whitespace: true,
syntax: true,
identifiers: true,
}
const sa = await Bun.build({
entrypoints: ["./frontend/cash/cash", "./frontend/list/list"],
outdir: "./public/assets/build/",
minify,
})
console.log(sa);
const { stdout } = Bun.spawnSync({ cmd: ["bun", "build", "./app.ts", "--outfile=bundle.js", "--target=bun", "--minify"] });
console.log(stdout.toString());
}
build();
export default build;

5
dev.ts Normal file
View File

@ -0,0 +1,5 @@
const build_cash = Bun.spawn(["bun", "build", "./frontend/cash/cash.tsx", "--outfile=public/assets/build/cash/cash.js", "--watch"]);
const build_list = Bun.spawn(["bun", "build", "./frontend/list/list.tsx", "--outfile=public/assets/build/list/list.js", "--watch"]);
const build_app = Bun.spawn(["bun", "--watch", "./app.ts"]);

116
frontend/cash/cash.tsx Normal file
View File

@ -0,0 +1,116 @@
import Chart from 'chart.js/auto'
import * as elements from "../elementcreate";
interface Transaction {
day: number;
month: number;
year: number;
amount: number;
type: number;
company: string;
}
var types: Array<string> = [];
async function submitMedia(event: SubmitEvent) {
event.preventDefault();
const pass = document.getElementById("pass") as HTMLInputElement | null;
const date = document.getElementById("date") as HTMLInputElement | null;
if (!pass || !date) return;
if (pass.value == "") return;
try {
const result = await fetch('/api/cash/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ pass: pass.value, date: date.value }),
})
const data: { types: string[]; transactions: Array<Transaction>; } = await result.json();
types = data.types;
renderData(data.transactions);
renderChart(data.transactions);
} catch (e) {
console.log(e);
}
pass.value = "";
};
document.addEventListener('DOMContentLoaded', async () => {
document.getElementById("myform")?.addEventListener("submit", submitMedia);
});
function renderChart(transactions: Array<Transaction>) {
const cash = [];
for (let index = 0; index < 7; index++) {
cash.push(0);
}
for (let index = 0; index < transactions.length; index++) {
const element = transactions[index];
const type = element.type;
const amount = element.amount;
if (type == -1) continue;
cash[type] += amount;
}
var data = {
labels: types,
datasets: [{
label: '',
data: cash
}]
};
var ctx = document.getElementById('acquisitions') as HTMLCanvasElement | null;
if (ctx == null) return;
new Chart(
ctx,
{
type: 'pie',
data: data,
}
);
};
function getTypeName(type: number) {
if (type == -1) return "UNKNOWN";
return types[type];
}
function renderData(transactions: Array<Transaction>) {
var tbody = document.getElementById("tbody");
if (tbody == null) return;
tbody.innerHTML = "";
transactions
.sort((a, b) => a.day - b.day)
.sort((a, b) => a.month - b.month)
.sort((a, b) => a.year - b.year);
for (let index = 0; index < transactions.length; index++) {
const element = transactions[index];
var row =
<tr>
<th scope="row">{index}</th>
<td>{element.day}</td>
<td>{element.month}</td>
<td>{element.year}</td>
<td>{element.amount}</td>
<td>{getTypeName(element.type)}</td>
<td>{element.company}</td>
</tr>
tbody.appendChild(row);
}
};

View File

@ -0,0 +1,71 @@
/// <reference path="./utils/element-types.d.ts" />
/// <reference path="./utils/events.d.ts" />
/// <reference path="./utils/intrinsic-elements.d.ts" />
export interface Children {
children?: AttributeValue;
}
export interface CustomElementHandler {
(attributes: Attributes, contents: (string | HTMLElement)[]): HTMLElement;
}
export interface Attributes {
[key: string]: AttributeValue;
}
export function createElement(
tag: string | CustomElementHandler,
attrs: Attributes & Children | undefined = {},
...children: (string | HTMLElement)[]
): HTMLElement {
if (typeof tag === "function") {
if (attrs == null) {
attrs = { num: 0 };
}
if (children == null) {
children = [""];
}
return tag(attrs, children);
}
const retElement = document.createElement(tag);
for (let name in attrs) {
if (name && attrs.hasOwnProperty(name)) {
let value = attrs[name];
if (typeof value === "number") {
retElement.setAttribute(name, value.toString());
} else if (typeof value === "function") {
retElement.addEventListener(name.slice(2), value);
}
else {
retElement.setAttribute(name, value);
}
}
}
for (let i = 2; i < arguments.length; i++) {
let child = arguments[i];
// check if child is a HTMLElement
if (child.nodeType != undefined) {
retElement.appendChild(child);
continue;
}
if (child instanceof Array) {
for (let j = 0; j < child.length; j++) {
if (child[j].nodeType != undefined) retElement.appendChild(child[j]);
else retElement.appendChild(document.createTextNode(child[j].toString()));
}
continue;
}
// child is a string
retElement.appendChild(document.createTextNode(child.toString()));
}
return retElement;
}

View File

@ -0,0 +1,35 @@
import type { Attributes } from "../elementcreate";
import * as elements from "../elementcreate";
function MediaElement(attributes: Attributes, contents: string[]) {
const ret = <div class="col media-element" id={attributes['id']}>
<div class='card shadow-sm'>
<img class='card-img-top' src={attributes['webImg']} width='100%' onerror={attributes['imageError']}></img>
<div class='card-body'>
<h5 class='card-title'>{attributes['title']}</h5>
<p class='card-text'>{attributes['released']}</p>
<div class="d-none justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick={attributes['fun']}>delete</button>
</div>
</div>
</div>
</div>
</div>;
return ret;
}
function MyHeader(attributes: Attributes, contents: string[]) {
return <div class="row">
<div class='col'>
<h2 class='text-center'>{attributes['title']} {attributes['num'] ? ": " + attributes['num'] : ""}</h2>
</div>
</div>;
}
function MediaContainer(attributes: Attributes, contents: string[]) {
return <div id={attributes['id']} class="row row-cols-2 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-5 g-3">{contents[0]}</div>;
}
export { MediaElement, MyHeader, MediaContainer }

View File

@ -0,0 +1,25 @@
function splitByTitle(movies: Array<Movie>): { [s: string]: Movie[]; } {
const result = movies.reduce((r, a) => {
var letter = a.title[0].toUpperCase();
if (!isNaN(parseInt(letter))) letter = "#";
r[letter] = r[letter] || [];
r[letter].push(a);
return r;
}, Object.create(null));
return result;
}
function splitByYear(movies: Array<Movie>): { [s: string]: Movie[]; } {
const result = movies.reduce((r, a) => {
const year = new Date(a.released).getFullYear();
r[year] = r[year] || [];
r[year].push(a);
return r;
}, Object.create(null));
return result;
}
export { splitByTitle, splitByYear };

304
frontend/list/list.tsx Normal file
View File

@ -0,0 +1,304 @@
import { MediaElement, MyHeader, MediaContainer } from "./elements";
import { splitByTitle, splitByYear } from "./functions";
import * as elements from "../elementcreate";
var sortType = 0;
var listType = 0;
const sortTypeTitle = 0;
const sortTypeYear = 1;
const sortTypeId = 2;
const moviesType = 0;
const gamesType = 1;
const seriesType = 2;
var listButtons: Array<HTMLElement | null> = [];
var sortButtons: Array<HTMLElement | null> = [];
var root: HTMLElement | null;
var editButton: HTMLElement | null;
var movieElements: HTMLElement[] = [];
function getLink(): string {
switch (listType) {
case moviesType:
return "/api/media/movies";
case gamesType:
return "/api/media/games";
case seriesType:
return "/api/media/series";
}
return "/api/media/movies";
}
function submitMedia(event: SubmitEvent) {
event.preventDefault();
const pass = document.getElementById("pass") as HTMLInputElement | null;
if (!pass) return;
const input_id = document.getElementById("input_id") as HTMLInputElement | null;
if (!input_id) return;
if (pass.value == "" || input_id.value == "") return;
fetch(getLink(), {
body: JSON.stringify({ pass: pass.value, code: input_id.value }),
headers: { "Content-Type": "application/json" },
method: "POST"
})
.then(async (response) => {
if (response.status != 201) {
const json = await response.json();
console.log(json);
alert(json.message);
return;
}
const movie: Movie = await response.json();
var letter = movie.title[0].toUpperCase();
if (!isNaN(parseInt(letter))) letter = "#";
const mediaElement = <MediaElement webImg={movie.webImg} title={movie.title} released={movie.released} id={movie.code} fun={removeMedia} imageError={onImgError} />;
const container = document.getElementById(letter);
if (!container) {
root?.appendChild(<MyHeader title={letter} />);
root?.appendChild(<MediaContainer id={letter}>{mediaElement}</MediaContainer>);
return
};
container.appendChild(mediaElement);
movieElements.push(mediaElement);
})
.catch(err => {
console.log(err);
});
input_id.value = "";
}
function loadState() {
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has("listType")) {
switch (searchParams.get("listType")) {
case "movies":
listType = moviesType;
break;
case "series":
listType = seriesType;
break;
case "games":
listType = gamesType;
break;
default:
listType = moviesType;
break;
}
}
if (searchParams.has("sortType")) {
switch (searchParams.get("sortType")) {
case "title":
sortType = sortTypeTitle;
break;
case "year":
sortType = sortTypeYear;
break;
case "id":
sortType = sortTypeId;
break;
default:
sortType = sortTypeTitle;
break;
}
}
}
/**
* @param {number} type
*/
function changeType(type: number) {
listType = type;
loadPage();
const searchParams = new URLSearchParams(window.location.search);
switch (listType) {
case moviesType:
searchParams.set("listType", "movies");
break;
case gamesType:
searchParams.set("listType", "games");
break;
case seriesType:
searchParams.set("listType", "series");
break;
}
history.replaceState({}, '', window.location.pathname + '?' + searchParams.toString());
}
/**
* @param {number} type
*/
function changeSort(type: number) {
sortType = type;
loadPage();
const searchParams = new URLSearchParams(window.location.search);
switch (type) {
case sortTypeTitle:
searchParams.set("sortType", "title");
break;
case sortTypeYear:
searchParams.set("sortType", "year");
break;
case sortTypeId:
searchParams.set("sortType", "id");
break;
}
history.replaceState({}, '', window.location.pathname + '?' + searchParams.toString());
}
function splitBySort(movies: Array<Movie>): { [s: string]: Movie[]; } {
switch (sortType) {
case sortTypeYear:
const sorted = movies.sort((a, b) => {
const ay = Date.parse(a.released);
const by = Date.parse(b.released);
return ay - by;
});
return splitByYear(sorted);
case sortTypeId:
movies.sort((a, b) => a.id < b.id ? 1 : -1);
return { "added": movies };
default:
return splitByTitle(movies.sort((a, b) => a.title.localeCompare(b.title)));
}
}
function toggleEdit() {
movieElements.forEach(element => {
const div = element.querySelector(".d-none");
if (!div) return;
div.classList.remove("d-none");
div.classList.add("d-flex");
});
}
document.addEventListener('DOMContentLoaded', async () => {
document.getElementById("myform")?.addEventListener("submit", submitMedia);
listButtons.push(document.getElementById("movieButton"));
listButtons.push(document.getElementById("gameButton"));
listButtons.push(document.getElementById("seriesButton"));
listButtons.forEach((button, index) => button?.addEventListener("click", () => changeType(index)));
sortButtons.push(document.getElementById("titleButton"));
sortButtons.push(document.getElementById("yearButton"));
sortButtons.push(document.getElementById("idButton"));
sortButtons.forEach((button, index) => button?.addEventListener("click", () => changeSort(index)));
editButton = document.getElementById("editButton");
editButton?.addEventListener("click", () => toggleEdit());
loadState();
loadPage();
});
async function loadPage() {
listButtons.forEach(button => button?.classList.remove("active"));
listButtons[listType]?.classList.add("active");
try {
const response = await fetch(getLink());
const movies = await response.json();
renderMedias(movies);
} catch (err) {
console.log(err);
}
}
function removeMedia(evt: Event) {
const password = document.getElementById("pass") as HTMLInputElement | null;
if (!password) return;
if (password.value == "") return;
let elem = evt.target as HTMLElement | null;
while (elem && !elem.classList.contains('media-element')) {
elem = elem.parentElement;
}
if (!elem) return;
const id = elem.id;
fetch(getLink(), {
body: JSON.stringify({ pass: password.value, code: id }),
headers: { "Content-Type": "application/json" },
method: "DELETE"
})
.then(async (response) => {
if (response.status != 204) {
console.log("error");
console.log(response.body);
return;
}
document.getElementById(id)?.remove();
})
.catch(err => {
console.log(err);
});
password.value = "";
}
function onImgError(evt: Event) {
const imgT = evt.target as HTMLImageElement;
imgT.src = "/images/no_poster.jpg";
}
function renderMedias(unsorted_movies: Array<Movie>) {
root = document.getElementById('root');
if (!root) return;
root.innerHTML = "";
const splitMovies = splitBySort(unsorted_movies);
let years;
if (sortType == sortTypeTitle) {
years = Object.keys(splitMovies).sort((a, b) => -b.localeCompare(a));
} else {
years = Object.keys(splitMovies).sort((a, b) => b.localeCompare(a));
}
root.appendChild(<MyHeader title={unsorted_movies.length} />);
for (const letter of years) {
const movies = splitMovies[letter];
const header = <MyHeader title={letter} num={movies.length} />;
root.appendChild(header);
const row =
<MediaContainer id={letter}>
{movies.map(movie => {
const med = <MediaElement webImg={movie.webImg} title={movie.title} released={movie.released} id={movie.code} fun={removeMedia} imageError={onImgError}></MediaElement>;
movieElements.push(med);
return med;
})}
</MediaContainer>;
root.appendChild(row);
}
}

7
frontend/list/types.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
interface Movie {
title: string;
released: string;
code: string;
webImg: string;
id: string;
}

1
frontend/utils/attr.d.ts vendored Normal file
View File

@ -0,0 +1 @@
type AttributeValue = number | string | EventListener;

341
frontend/utils/element-types.d.ts vendored Normal file
View File

@ -0,0 +1,341 @@
declare namespace JSX {
interface HtmlTag {
accesskey?: string;
class?: string;
contenteditable?: string;
dir?: string;
hidden?: string | boolean;
id?: AttributeValue;
role?: string;
lang?: string;
draggable?: string | boolean;
spellcheck?: string | boolean;
style?: string;
tabindex?: string;
title?: string;
translate?: string | boolean;
}
interface HtmlAnchorTag extends HtmlTag {
href?: string;
target?: string;
download?: string;
ping?: string;
rel?: string;
media?: string;
hreflang?: string;
type?: string;
}
interface HtmlAreaTag extends HtmlTag {
alt?: string;
coords?: string;
shape?: string;
href?: string;
target?: string;
ping?: string;
rel?: string;
media?: string;
hreflang?: string;
type?: string;
}
interface HtmlAudioTag extends HtmlTag {
src?: string;
autobuffer?: string;
autoplay?: string;
loop?: string;
controls?: string;
}
interface BaseTag extends HtmlTag {
href?: string;
target?: string;
}
interface HtmlQuoteTag extends HtmlTag {
cite?: string;
}
interface HtmlBodyTag extends HtmlTag {
}
interface HtmlButtonTag extends HtmlTag {
action?: string;
autofocus?: string;
disabled?: string;
enctype?: string;
form?: string;
method?: string;
name?: string;
novalidate?: string | boolean;
target?: string;
type?: string;
value?: string;
onClick?: Function;
}
interface HtmlDataListTag extends HtmlTag {
}
interface HtmlCanvasTag extends HtmlTag {
width?: string;
height?: string;
}
interface HtmlTableColTag extends HtmlTag {
span?: string;
}
interface HtmlTableSectionTag extends HtmlTag {
}
interface HtmlTableRowTag extends HtmlTag {
}
interface DataTag extends HtmlTag {
value?: string;
}
interface HtmlEmbedTag extends HtmlTag {
src?: string;
type?: string;
width?: string;
height?: string;
}
interface HtmlFieldSetTag extends HtmlTag {
disabled?: string;
form?: string;
name?: string;
}
interface HtmlFormTag extends HtmlTag {
acceptCharset?: string;
action?: string;
autocomplete?: string;
enctype?: string;
method?: string;
name?: string;
novalidate?: string | boolean;
target?: string;
}
interface HtmlHtmlTag extends HtmlTag {
manifest?: string;
}
interface HtmlIFrameTag extends HtmlTag {
src?: string;
srcdoc?: string;
name?: string;
sandbox?: string;
seamless?: string;
width?: string;
height?: string;
}
interface HtmlImageTag extends HtmlTag {
alt?: string;
src?: AttributeValue;
crossorigin?: string;
usemap?: string;
ismap?: string;
width?: string;
height?: string;
}
interface HtmlInputTag extends HtmlTag {
accept?: string;
action?: string;
alt?: string;
autocomplete?: string;
autofocus?: string;
checked?: string | boolean;
disabled?: string | boolean;
enctype?: string;
form?: string;
height?: string;
list?: string;
max?: string;
maxlength?: string;
method?: string;
min?: string;
multiple?: string;
name?: string;
novalidate?: string | boolean;
pattern?: string;
placeholder?: string;
readonly?: string;
required?: string;
size?: string;
src?: string;
step?: string;
target?: string;
type?: string;
value?: string;
width?: string;
}
interface HtmlModTag extends HtmlTag {
cite?: string;
datetime?: string | Date;
}
interface KeygenTag extends HtmlTag {
autofocus?: string;
challenge?: string;
disabled?: string;
form?: string;
keytype?: string;
name?: string;
}
interface HtmlLabelTag extends HtmlTag {
form?: string;
for?: string;
}
interface HtmlLITag extends HtmlTag {
value?: string | number;
}
interface HtmlLinkTag extends HtmlTag {
href?: string;
crossorigin?: string;
rel?: string;
media?: string;
hreflang?: string;
type?: string;
sizes?: string;
integrity?: string;
}
interface HtmlMapTag extends HtmlTag {
name?: string;
}
interface HtmlMetaTag extends HtmlTag {
name?: string;
httpEquiv?: string;
content?: string;
charset?: string;
}
interface HtmlMeterTag extends HtmlTag {
value?: string | number;
min?: string | number;
max?: string | number;
low?: string | number;
high?: string | number;
optimum?: string | number;
}
interface HtmlObjectTag extends HtmlTag {
data?: string;
type?: string;
name?: string;
usemap?: string;
form?: string;
width?: string;
height?: string;
}
interface HtmlOListTag extends HtmlTag {
reversed?: string;
start?: string | number;
}
interface HtmlOptgroupTag extends HtmlTag {
disabled?: string;
label?: string;
}
interface HtmlOptionTag extends HtmlTag {
disabled?: string;
label?: string;
selected?: string;
value?: string;
}
interface HtmlOutputTag extends HtmlTag {
for?: string;
form?: string;
name?: string;
}
interface HtmlParamTag extends HtmlTag {
name?: string;
value?: string;
}
interface HtmlProgressTag extends HtmlTag {
value?: string | number;
max?: string | number;
}
interface HtmlCommandTag extends HtmlTag {
type?: string;
label?: string;
icon?: string;
disabled?: string;
checked?: string;
radiogroup?: string;
default?: string;
}
interface HtmlLegendTag extends HtmlTag {
}
interface HtmlBrowserButtonTag extends HtmlTag {
type?: string;
}
interface HtmlMenuTag extends HtmlTag {
type?: string;
label?: string;
}
interface HtmlScriptTag extends HtmlTag {
src?: string;
type?: string;
charset?: string;
async?: string;
defer?: string;
crossorigin?: string;
integrity?: string;
text?: string;
}
interface HtmlDetailsTag extends HtmlTag {
open?: string;
}
interface HtmlSelectTag extends HtmlTag {
autofocus?: string;
disabled?: string;
form?: string;
multiple?: string;
name?: string;
required?: string;
size?: string;
}
interface HtmlSourceTag extends HtmlTag {
src?: string;
type?: string;
media?: string;
}
interface HtmlStyleTag extends HtmlTag {
media?: string;
type?: string;
disabled?: string;
scoped?: string;
}
interface HtmlTableTag extends HtmlTag {
}
interface HtmlTableDataCellTag extends HtmlTag {
colspan?: string | number;
rowspan?: string | number;
headers?: string;
}
interface HtmlTextAreaTag extends HtmlTag {
autofocus?: string;
cols?: string;
dirname?: string;
disabled?: string;
form?: string;
maxlength?: string;
minlength?: string;
name?: string;
placeholder?: string;
readonly?: string;
required?: string;
rows?: string;
wrap?: string;
}
interface HtmlTableHeaderCellTag extends HtmlTag {
colspan?: string | number;
rowspan?: string | number;
headers?: string;
scope?: string;
}
interface HtmlTimeTag extends HtmlTag {
datetime?: string | Date;
}
interface HtmlTrackTag extends HtmlTag {
default?: string;
kind?: string;
label?: string;
src?: string;
srclang?: string;
}
interface HtmlVideoTag extends HtmlTag {
src?: string;
poster?: string;
autobuffer?: string;
autoplay?: string;
loop?: string;
controls?: string;
width?: string;
height?: string;
}
}
//# sourceMappingURL=element-types.d.ts.map

98
frontend/utils/events.d.ts vendored Normal file
View File

@ -0,0 +1,98 @@
declare namespace JSX {
interface HtmlBodyTag {
onafterprint?: string;
onbeforeprint?: string;
onbeforeonload?: string;
onblur?: string;
onerror?: string;
onfocus?: string;
onhaschange?: string;
onload?: string;
onmessage?: string;
onoffline?: string;
ononline?: string;
onpagehide?: string;
onpageshow?: string;
onpopstate?: string;
onredo?: string;
onresize?: string;
onstorage?: string;
onundo?: string;
onunload?: string;
}
interface HtmlTag {
oncontextmenu?: string;
onkeydown?: string;
onkeypress?: string;
onkeyup?: string;
onclick?: AttributeValue;
ondblclick?: string;
ondrag?: string;
ondragend?: string;
ondragenter?: string;
ondragleave?: string;
ondragover?: string;
ondragstart?: string;
ondrop?: string;
onmousedown?: string;
onmousemove?: string;
onmouseout?: string;
onmouseover?: string;
onmouseup?: string;
onmousewheel?: string;
onscroll?: string;
}
interface FormEvents {
onblur?: string;
onchange?: string;
onfocus?: string;
onformchange?: string;
onforminput?: string;
oninput?: string;
oninvalid?: string;
onselect?: string;
onsubmit?: string;
}
interface HtmlInputTag extends FormEvents {
}
interface HtmlFieldSetTag extends FormEvents {
}
interface HtmlFormTag extends FormEvents {
}
interface MediaEvents {
onabort?: string;
oncanplay?: string;
oncanplaythrough?: string;
ondurationchange?: string;
onemptied?: string;
onended?: string;
onerror?: AttributeValue;
onloadeddata?: string;
onloadedmetadata?: string;
onloadstart?: string;
onpause?: string;
onplay?: string;
onplaying?: string;
onprogress?: string;
onratechange?: string;
onreadystatechange?: string;
onseeked?: string;
onseeking?: string;
onstalled?: string;
onsuspend?: string;
ontimeupdate?: string;
onvolumechange?: string;
onwaiting?: string;
}
interface HtmlAudioTag extends MediaEvents {
}
interface HtmlEmbedTag extends MediaEvents {
}
interface HtmlImageTag extends MediaEvents {
}
interface HtmlObjectTag extends MediaEvents {
}
interface HtmlVideoTag extends MediaEvents {
}
}
//# sourceMappingURL=events.d.ts.map

118
frontend/utils/intrinsic-elements.d.ts vendored Normal file
View File

@ -0,0 +1,118 @@
declare namespace JSX {
type Element = HTMLElement;
interface IntrinsicElements {
a: HtmlAnchorTag;
abbr: HtmlTag;
address: HtmlTag;
area: HtmlAreaTag;
article: HtmlTag;
aside: HtmlTag;
audio: HtmlAudioTag;
b: HtmlTag;
bb: HtmlBrowserButtonTag;
base: BaseTag;
bdi: HtmlTag;
bdo: HtmlTag;
blockquote: HtmlQuoteTag;
body: HtmlBodyTag;
br: HtmlTag;
button: HtmlButtonTag;
canvas: HtmlCanvasTag;
caption: HtmlTag;
cite: HtmlTag;
code: HtmlTag;
col: HtmlTableColTag;
colgroup: HtmlTableColTag;
commands: HtmlCommandTag;
data: DataTag;
datalist: HtmlDataListTag;
dd: HtmlTag;
del: HtmlModTag;
details: HtmlDetailsTag;
dfn: HtmlTag;
div: HtmlTag;
dl: HtmlTag;
dt: HtmlTag;
em: HtmlTag;
embed: HtmlEmbedTag;
fieldset: HtmlFieldSetTag;
figcaption: HtmlTag;
figure: HtmlTag;
footer: HtmlTag;
form: HtmlFormTag;
h1: HtmlTag;
h2: HtmlTag;
h3: HtmlTag;
h4: HtmlTag;
h5: HtmlTag;
h6: HtmlTag;
head: HtmlTag;
header: HtmlTag;
hr: HtmlTag;
html: HtmlHtmlTag;
i: HtmlTag;
iframe: HtmlIFrameTag;
img: HtmlImageTag;
input: HtmlInputTag;
ins: HtmlModTag;
kbd: HtmlTag;
keygen: KeygenTag;
label: HtmlLabelTag;
legend: HtmlLegendTag;
li: HtmlLITag;
link: HtmlLinkTag;
main: HtmlTag;
map: HtmlMapTag;
mark: HtmlTag;
menu: HtmlMenuTag;
meta: HtmlMetaTag;
meter: HtmlMeterTag;
nav: HtmlTag;
noscript: HtmlTag;
object: HtmlObjectTag;
ol: HtmlOListTag;
optgroup: HtmlOptgroupTag;
option: HtmlOptionTag;
output: HtmlOutputTag;
p: HtmlTag;
param: HtmlParamTag;
pre: HtmlTag;
progress: HtmlProgressTag;
q: HtmlQuoteTag;
rb: HtmlTag;
rp: HtmlTag;
rt: HtmlTag;
rtc: HtmlTag;
ruby: HtmlTag;
s: HtmlTag;
samp: HtmlTag;
script: HtmlScriptTag;
section: HtmlTag;
select: HtmlSelectTag;
small: HtmlTag;
source: HtmlSourceTag;
span: HtmlTag;
strong: HtmlTag;
style: HtmlStyleTag;
sub: HtmlTag;
sup: HtmlTag;
table: HtmlTableTag;
tbody: HtmlTag;
td: HtmlTableDataCellTag;
template: HtmlTag;
textarea: HtmlTextAreaTag;
tfoot: HtmlTableSectionTag;
th: HtmlTableHeaderCellTag;
thead: HtmlTableSectionTag;
time: HtmlTimeTag;
title: HtmlTag;
tr: HtmlTableRowTag;
track: HtmlTrackTag;
u: HtmlTag;
ul: HtmlTag;
var: HtmlTag;
video: HtmlVideoTag;
wbr: HtmlTag;
}
}
//# sourceMappingURL=intrinsic-elements.d.ts.map

View File

@ -13,6 +13,9 @@
"express": "^4.18.2",
"hbs": "^4.2.0",
"morgan": "~1.9.1",
"mysql2": "^3.10.3"
"mysql2": "^3.10.3",
"chart.js": "^4.4.1",
"bun-types": "^1.0.23",
"typescript": "^5.3.3"
}
}

View File

@ -103,7 +103,7 @@
"des": "Graduate engineer of computer science and information technology"
},
{
"title": "(SŠTS Šiška) Secondary school of technical professions šiška",
"title": "(SSTS Siska) Secondary school of technical professions siska",
"time": "01/09/2016 - 07/07/2021",
"des": "Electrotechnician"
}

View File

@ -8,7 +8,8 @@
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"jsx": "react",
"jsxFactory": "elements.createElement",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
@ -24,6 +25,9 @@
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
"noPropertyAccessFromIndexSignature": false,
"types": [
"bun-types"
]
}
}