first commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
build/
|
||||||
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
build/MyCard.js: ./node_modules ./build
|
||||||
|
npx swc ./src/MyCard.ts -o ./build/MyCard.js
|
||||||
|
|
||||||
|
./build:
|
||||||
|
mkdir -p ./build
|
||||||
|
|
||||||
|
./node_modules:
|
||||||
|
npm install
|
||||||
|
|
||||||
|
serve: ./build/MyCard.js
|
||||||
|
npx serve
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf ./build ./node_modules
|
||||||
|
|
||||||
|
.PHONY: clean serve
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# MEDTRACE: Case - Frontend developer
|
||||||
|
|
||||||
|
## build and run
|
||||||
|
|
||||||
|
From the repo root, run `make` to build the project. From there you can use your own server to serve from the repo root, or run `make serve` to run a development server. `make clean` will remove the dependencies and build directory.
|
||||||
90
index.html
Normal file
90
index.html
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>MEDTRACE: Case - Frontend Developer</title>
|
||||||
|
<script type="module" src="./build/MyCard.js"></script>
|
||||||
|
<!-- "light" DOM styles -->
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
:root {
|
||||||
|
/* init the CSS var from the "light" DOM */
|
||||||
|
--my-card-header-color: red;
|
||||||
|
}
|
||||||
|
#cards {
|
||||||
|
padding: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, 200px);
|
||||||
|
grid-gap: 1rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- the template for the custom component -->
|
||||||
|
<template id="my-card-template">
|
||||||
|
<!-- shadow DOM styles -->
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
box-shadow: 0px 0px 5px #ccc;
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
/* using the CSS var assigned from the "light" DOM; default
|
||||||
|
green is never displayed because the var is initialized
|
||||||
|
above. */
|
||||||
|
color: var(--my-card-header-color, green);
|
||||||
|
}
|
||||||
|
#message {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header class="">
|
||||||
|
<h1>
|
||||||
|
<slot name="headline">
|
||||||
|
Default headline
|
||||||
|
</slot>
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<!-- this could have been a slot named "main" like
|
||||||
|
`<slot name="main"></slot>`
|
||||||
|
but that makes it harder to use in the HTML below. -->
|
||||||
|
<section id="main">
|
||||||
|
<slot></slot>
|
||||||
|
</section>
|
||||||
|
<div id="message"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- begin content -->
|
||||||
|
<section id="cards">
|
||||||
|
<my-card message="initial message parsed from HTML">
|
||||||
|
<span slot="headline">Custom headline</span>
|
||||||
|
<button id="my-button">click me</button>
|
||||||
|
</my-card>
|
||||||
|
<my-card>hello world</my-card>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const cards = document.getElementsByTagName("my-card");
|
||||||
|
const $myButton = document.getElementById("my-button");
|
||||||
|
$myButton.addEventListener("click", () => {
|
||||||
|
const msg = "button clicked";
|
||||||
|
|
||||||
|
for (const $card of cards) {
|
||||||
|
$card.setAttribute(
|
||||||
|
"message",
|
||||||
|
$card.getAttribute("message") === msg
|
||||||
|
? ""
|
||||||
|
: msg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2612
package-lock.json
generated
Normal file
2612
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
7
package.json
Normal file
7
package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"@swc/cli": "^0.3.12",
|
||||||
|
"@swc/core": "^1.4.15",
|
||||||
|
"serve": "^14.2.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/MyCard.ts
Normal file
49
src/MyCard.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* This could also be imported as a string or written here and attached to the
|
||||||
|
* `document.body` as a `template` element, like
|
||||||
|
*
|
||||||
|
* const template = document.createElement("template");
|
||||||
|
* template.innerHTML = `<style>...</style><div>...</div>`;
|
||||||
|
* document.body.appendChild(template);
|
||||||
|
*
|
||||||
|
* which would only be run here once, similar in performance to parsing it in
|
||||||
|
* index.html file.
|
||||||
|
*/
|
||||||
|
const template = document.getElementById("my-card-template") as
|
||||||
|
HTMLTemplateElement;
|
||||||
|
|
||||||
|
enum Attributes {
|
||||||
|
MESSAGE = "message",
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define("my-card", class extends HTMLElement {
|
||||||
|
static observedAttributes = [Attributes.MESSAGE];
|
||||||
|
|
||||||
|
private _content: DocumentFragment;
|
||||||
|
$message: HTMLElement;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.attachShadow({mode: "open"});
|
||||||
|
this._content = template.content.cloneNode(true) as DocumentFragment;
|
||||||
|
this.$message = this._content.getElementById("message")!;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
if (this.shadowRoot) {
|
||||||
|
this.shadowRoot.appendChild(this._content);
|
||||||
|
} else {
|
||||||
|
console.warn("No shadowRoot detected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name: string, _prev: string, curr: string) {
|
||||||
|
if (Attributes.MESSAGE === name) {
|
||||||
|
while (this.$message.firstChild) {
|
||||||
|
this.$message.removeChild(this.$message.lastChild!);
|
||||||
|
}
|
||||||
|
this.$message.appendChild(document.createTextNode(curr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user