From 13b5e68bf6480ebf6bc742baaf39f2227ddb3bd8 Mon Sep 17 00:00:00 2001 From: sadorowo Date: Sun, 10 Mar 2024 13:39:10 +0100 Subject: [PATCH] add: dcd files --- .DS_Store | Bin 0 -> 6148 bytes README.md | 73 ++++++++++++++++++++++++++++++++++++++++++ data/constants.js | 11 +++++++ data/custom-style.css | 1 + index.html | 23 +++++++++++++ scripts/script.js | 54 +++++++++++++++++++++++++++++++ scripts/sdk.js | 30 +++++++++++++++++ style.css | 72 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 264 insertions(+) create mode 100644 .DS_Store create mode 100644 README.md create mode 100644 data/constants.js create mode 100644 data/custom-style.css create mode 100644 index.html create mode 100644 scripts/script.js create mode 100644 scripts/sdk.js create mode 100644 style.css diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6ff898ebb44b0071915e70394b9f870cac55f2d4 GIT binary patch literal 6148 zcmeHKK`sPA6n!-&F-XMHM$#wfaDztALV|_405c*a#=E5>DU% zmbO;BUsa)NW>|{wfAZ^f*Z;5T_e-j(3xHWUZZ83I0BUr>>NJ}%CUNl*tN5N-qLDGO z&Qhb5cY7n5+Mx=l0>4oKS-Vxl=wKg%aQ&X$mSf#KO`BQXWM8d$eR=czc()wJ+uz1} zd!@a>ypYOy+t|SXJ8N0q@?*dGMHbd-7MNGAbrS1X!z$|7L<99O8=_b_dkS03Tt=zgbOF~n0PE4GD0(sN_14?uNcPB*&q45#AD&m z(P8}M!}ytvzo8gAJI9Y~I!xkFTU9_62o;!cuXA$#*SUtjxc`SFeNzQgfj^~ysiuu| zg`ecl){&2svo@k{)5RpOaA+xP{Bdj_qZv{40qRDpN! CY?EC8 literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 0000000..1b503c7 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +## Dynamic Content Delivery + +A static website that returns appropriate content to the website user based on the provided ID. + +## Which files am I allowed to edit? +- [template section of index.html](index.html) +- all files in `data` directory: + - [constants.js](data/constants.js) + - [custom-style.css](data/custom-style.css) + +## How to use +Firstly, create template for your webpage. Go to [index.html](index.html) and edit code **only between these lines**: +```html + + + +``` +This is the **template section** of the HTML file. + +Example: +```html + +

Hi!

+ +``` + +Then, prepare your API: +1. Clone [this](https://github.com/sadorowo/dynamic-content-delivery-api) repository. +2. Edit [data/data-source.json] file: + - provide your data in `DATA` constant like this: + ```javascript + const DATA = { + "id1": { + "#name": { + "textContent": "John", + "style": { + "color": "red" + } + } + }, + "id2": { + "#name": { + "textContent": "Anna", + "style": { + "color": "blue" + } + } + }, + ... + } + ``` + - edit your [data/config.json]: + 1. provide your API host in `API_HOST` constant. + 2. provide your API port in `PORT` constant. + + > Warning! + > Do not change the structure of the `DATA` object. It must be an object with keys being IDs and values, which are objects with CSS selectors as keys and objects with DOM properties as values. + > Make sure that your API is running on the same port as the one provided in `PORT` constant. + +3. Deploy your API: + 1. Install Node.js and npm. + 2. Run `npm install` in the root directory of the API. + 3. Run `npm start` in the root directory of the API. + +## Custom styles +This website supports custom CSS. Just edit [this](data/custom-style.css) file. +If provided style doesn't work, try adding `!important` to the end of CSS rule. + +## License +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Authors +- [**@sadorowo**](https://github.com/sadorowo) - original author \ No newline at end of file diff --git a/data/constants.js b/data/constants.js new file mode 100644 index 0000000..2e04ef6 --- /dev/null +++ b/data/constants.js @@ -0,0 +1,11 @@ +const API_HOST = 'http://localhost'; +const API_VERSION = 1; +const API_PORT = 3000; + +const prepareUrl = (...urls) => `${API_HOST}:${API_PORT}/api/v${API_VERSION}/${urls.join('/')}`; + +// Leave this unchanged, if you haven't modified anything in API route configuration. +const ROUTES = { + GET_RESOURCE: (id) => prepareUrl('resource', id), + STATUS: prepareUrl('status') +} \ No newline at end of file diff --git a/data/custom-style.css b/data/custom-style.css new file mode 100644 index 0000000..8021321 --- /dev/null +++ b/data/custom-style.css @@ -0,0 +1 @@ +/* If rule statements doesn't work, add !important to the end of it. */ \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..c32b52d --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + Content Delivery Network + + + + + + + +
+

Enter your access code:

+ + +
+
+ + + +
+ + \ No newline at end of file diff --git a/scripts/script.js b/scripts/script.js new file mode 100644 index 0000000..e1c8ed6 --- /dev/null +++ b/scripts/script.js @@ -0,0 +1,54 @@ +const startPage = document.getElementById('internal__start-page'); +const templatePage = document.getElementById('internal__template'); + +const wait = (time) => new Promise(resolve => setTimeout(resolve, time * 1000)); + +// Check if API is alive +fetchStatus() + .catch(() => alert('API is down or an error occurred.')); + +if (!startPage || !templatePage) { + alert("Base website template got corrupted! Can't find either start page or template page. Closing the window."); + window.close(); +} else { + async function proceed() { + const input = document.querySelector('#internal__start-page > input'); + const patches = await fetchResource(input.value); + + if (!patches) return alert('Bad access code!'); + applyPatches(patches); + await fadeBlock(); + } + + function applyPatches(patches) { + for (const [key, object] of Object.entries(patches)) { + const element = document.querySelector(key); + if (!element) { + alert(`Bad data source template! No HTML element found for selector '${key}'.`); + continue; + } + + parsePatch(element, object); + } + } + + function parsePatch(element, object) { + for (const [key, value] of Object.entries(object)) { + if (typeof value === 'object') + parsePatch(element[key], value); + else + element[key] = value; + } + } + + async function fadeBlock() { + startPage.style.opacity = 0; + await wait(0.2); + startPage.style.display = 'none'; + await wait(0.2); + templatePage.style.display = 'block'; + templatePage.style.opacity = 1; + } + + internal__submit.addEventListener('click', async () => await proceed()) +} diff --git a/scripts/sdk.js b/scripts/sdk.js new file mode 100644 index 0000000..e562754 --- /dev/null +++ b/scripts/sdk.js @@ -0,0 +1,30 @@ +async function fetchResource(id) { + const response = await fetch(ROUTES.GET_RESOURCE(id)); + if (!response.ok) { + const json = await response.json(); + + throw new Error(`${json.error}: ${json.message}`); + } + + return (await response.json()).resource; +} + +async function fetchStatus() { + const response = await fetch(ROUTES.STATUS); + + if (!response.ok) { + const json = await response.json(); + + throw new Error(`${json.error}: ${json.message}`); + } + + const json = await response.json(); + if (json.status !== 'ok') { + throw new Error('API status is not OK. Something went wrong.'); + } + + return json; +} + +// on error, provide alert to the user +window.addEventListener('unhandledrejection', event => alert(event.reason)); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..bb43c26 --- /dev/null +++ b/style.css @@ -0,0 +1,72 @@ +@import url('data/custom-style.css'); +@import url('https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap'); + +:root { + --text: #fff; + --background: #2f3136; + --button-color: #a8c0ff; + --button-color-hover: #c4d5ff; +} + +html, body { + width: 100%; + height: 100%; +} + +body { + font-family: 'Raleway', sans-serif; + padding: 0; + margin: 0; +} + +#internal__start-page, #internal__template { + transition: opacity 0.2s ease-in-out; +} + +#internal__template { + display: none; +} + +#internal__start-page { + width: 100%; + height: 100%; + + gap: 5px; + display: grid; + place-items: center; + align-content: center; + + background-color: var(--background) !important; +} + +#internal__start-page > *:is(h1, h2, h3, h4, h5, h6, p, span) { + color: var(--text); +} + +#internal__start-page > input { + border-radius: 10px; + text-align: center; + height: 50px; + border: none; +} + +#internal__start-page > input:focus { + border: none; + outline: none; +} + +#internal__start-page > button { + border: none; + outline: none; + cursor: pointer; + + height: 50px; + min-width: 100px; + border-radius: 10px; + background-color: var(--button-color); + transition: background-color 0.2s ease-in-out; +} + +#internal__start-page > button:hover { + background-color: var(--button-color-hover); +} \ No newline at end of file