diff options
| author | crupest <crupest@outlook.com> | 2023-07-19 01:37:02 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2023-07-19 01:37:02 +0800 | 
| commit | bf3f4fcef32940991bf8f7a1d896d10653012339 (patch) | |
| tree | 4b48a597d23efd757623ae415d658a134ff75a45 /docker | |
| parent | 2197b07482b3500fdb87db579e7d538be17942c6 (diff) | |
| download | crupest-bf3f4fcef32940991bf8f7a1d896d10653012339.tar.gz crupest-bf3f4fcef32940991bf8f7a1d896d10653012339.tar.bz2 crupest-bf3f4fcef32940991bf8f7a1d896d10653012339.zip | |
A lot prettier.
Diffstat (limited to 'docker')
| -rw-r--r-- | docker/crupest-nginx/sites/www/index.html | 101 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/package.json | 8 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/pnpm-lock.yaml | 32 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/src/main.js | 89 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/src/main.ts | 96 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/src/mock-todos.ts | 126 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/src/style.css | 82 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/src/todos.ts | 29 | ||||
| -rw-r--r-- | docker/crupest-nginx/sites/www/tsconfig.json | 19 | 
9 files changed, 439 insertions, 143 deletions
| diff --git a/docker/crupest-nginx/sites/www/index.html b/docker/crupest-nginx/sites/www/index.html index 0a7a99b..339d3c2 100644 --- a/docker/crupest-nginx/sites/www/index.html +++ b/docker/crupest-nginx/sites/www/index.html @@ -20,50 +20,61 @@    </div>    <article id="main-article">      <h1 id="title">Hello! This is crupest.</h1> -    <p>Welcome to my home page! I'm very glad to meet you here.</p> -    <p>If you have something interesting to share with me, feel free to reach me via email at <a -        href="mailto:crupest@outlook.com">crupest@outlook.com</a> or, of course, <a -        href="mailto:I@crupest.life">I@crupest.life</a>. You can also fire an issue in -      any repo on GitHub. Here is the link to my GitHub profile, <a -        href="https://github.com/crupest">https://github.com/crupest</a>.</p> -    <p>Currently this page is hosted on my own server and my own apex domain (crupest.life). You can also share this -      website link, aka, <a href="https://crupest.life">https://crupest.life</a>.</p> -    <p>This is just the home page. I also run some other services on my server under this domain:</p> -    <p>Public:</p> -    <ul> -      <li> -        https://crupest.life/api: Some APIs written in <a -          href="https://learn.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core" target="_blank">ASP.NET -          Core</a>. -      </li> -      <li><a href="https://blog.crupest.life" target="_blank">https://blog.crupest.life</a>: My blogs built with <a -          href="https://gohugo.io" target="_blank">hugo</a>.</li> -      <li><a href="https://timeline.crupest.life" target="_blank">https://timeline.crupest.life</a>: My micro-blogs with -        my own web app <a href="https://github.com/crupest/Timeline">Timeline</a>.</li> -      <li><a href="https://github.crupest.life" target="_blank">https://github.crupest.life</a>: Redirect to my github -        profile, aka, <a href="https://github.com/crupest">https://github.com/crupest</a>.</li> -    </ul> -    <p>Private:</p> -    <ul> -      <li><a href="https://code.crupest.life" target="_blank">https://code.crupest.life</a>: Browser based vscode with -        <a href="https://github.com/coder/code-server" target="_blank">code-server</a>. -      </li> -    </ul> -    <p>If you wish to deploy similar services like me, you are in the right place. Take a look at <a -        href="https://github.com/crupest/crupest" target="_blank">https://github.com/crupest/crupest</a> and there is -      all you need to start with. Also, contact me if you run into some problem.</p> -    <h2 id="friends">Friends of me:</h2> -    <div id="friends-container"> -      <a class="friend-link" href="https://wsmcs.cn" target="_blank"> -        <img class="friend-img" -          src="https://wsmcs.cn/wp-content/uploads/2023/02/BifengxiaPanda_ZH-CN8879969527_UHD-scaled.jpg"> -        <span class="friend-name">wsm</span> -      </a> -    </div> -    <h2 id="todos">TODOs of me:</h2> -    <p id="todo-message">Fetching...</p> -    <ul id="todo-container"> -    </ul> +    <section> +      <p>Welcome to my home page! I'm very glad to meet you here.</p> +      <p>If you have something interesting to share with me, feel free to reach me via email at <a +          href="mailto:crupest@outlook.com">crupest@outlook.com</a> or, of course, <a +          href="mailto:I@crupest.life">I@crupest.life</a>. You can also fire an issue in +        any repo on GitHub. Here is the link to my GitHub profile, <a +          href="https://github.com/crupest">https://github.com/crupest</a>.</p> +      <p>Currently this page is hosted on my own server and my own apex domain (crupest.life). You can also share this +        website link, aka, <a href="https://crupest.life">https://crupest.life</a>.</p> +    </section> +    <section> +      <h2 id="todos">TODOs of me <span class="h-note">grabbed from <a +            href="https://github.com/users/crupest/projects/2">my Github +            project</a></span></h2> +      <p id="todo-message">Fetching...</p> +      <ul id="todo-container"> +      </ul> +    </section> +    <section> +      <h2 id="friends">Friends of me:</h2> +      <div id="friends-container"> +        <a class="friend-link" href="https://wsmcs.cn" target="_blank"> +          <img class="friend-img" +            src="https://wsmcs.cn/wp-content/uploads/2023/02/BifengxiaPanda_ZH-CN8879969527_UHD-scaled.jpg"> +          <span class="friend-name">wsm</span> +        </a> +      </div> +    </section> +    <section> +      <p>This is just the home page. I also run some other services on my server under this domain:</p> +      <p>Public:</p> +      <ul> +        <li> +          https://crupest.life/api: Some APIs written in <a +            href="https://learn.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core" target="_blank">ASP.NET +            Core</a>. +        </li> +        <li><a href="https://blog.crupest.life" target="_blank">https://blog.crupest.life</a>: My blogs built with <a +            href="https://gohugo.io" target="_blank">hugo</a>.</li> +        <li><a href="https://timeline.crupest.life" target="_blank">https://timeline.crupest.life</a>: My micro-blogs +          with +          my own web app <a href="https://github.com/crupest/Timeline">Timeline</a>.</li> +        <li><a href="https://github.crupest.life" target="_blank">https://github.crupest.life</a>: Redirect to my github +          profile, aka, <a href="https://github.com/crupest">https://github.com/crupest</a>.</li> +      </ul> +      <p>Private:</p> +      <ul> +        <li><a href="https://code.crupest.life" target="_blank">https://code.crupest.life</a>: Browser based vscode with +          <a href="https://github.com/coder/code-server" target="_blank">code-server</a>. +        </li> +      </ul> +      <p>If you wish to deploy similar services like me, you are in the right place. Take a look at <a +          href="https://github.com/crupest/crupest" target="_blank">https://github.com/crupest/crupest</a> and there is +        all you need to start with. Also, contact me if you run into some problem.</p> +    </section>      <footer>        <p>That's all of me!</p>        <p>© 2022 crupest</p> @@ -75,7 +86,7 @@        </p>      </footer>    </article> -  <script type="module" src="./src/main.js"></script> +  <script type="module" src="./src/main.ts"></script>  </body>  </html>
\ No newline at end of file diff --git a/docker/crupest-nginx/sites/www/package.json b/docker/crupest-nginx/sites/www/package.json index 29d2d78..6927dfa 100644 --- a/docker/crupest-nginx/sites/www/package.json +++ b/docker/crupest-nginx/sites/www/package.json @@ -5,9 +5,13 @@    "source": "index.html",    "scripts": {      "start": "parcel", -    "build": "parcel build" +    "build": "tsc && parcel build"    },    "devDependencies": { -    "parcel": "latest" +    "@tsconfig/recommended": "^1.0.2", +    "@types/parcel-env": "^0.0.1", +    "parcel": "latest", +    "prettier": "3.0.0", +    "typescript": "^5.1.6"    }  }
\ No newline at end of file diff --git a/docker/crupest-nginx/sites/www/pnpm-lock.yaml b/docker/crupest-nginx/sites/www/pnpm-lock.yaml index a868dab..6de8ce2 100644 --- a/docker/crupest-nginx/sites/www/pnpm-lock.yaml +++ b/docker/crupest-nginx/sites/www/pnpm-lock.yaml @@ -5,9 +5,21 @@ settings:    excludeLinksFromLockfile: false  devDependencies: +  '@tsconfig/recommended': +    specifier: ^1.0.2 +    version: 1.0.2 +  '@types/parcel-env': +    specifier: ^0.0.1 +    version: 0.0.1    parcel:      specifier: latest      version: 2.9.3 +  prettier: +    specifier: 3.0.0 +    version: 3.0.0 +  typescript: +    specifier: ^5.1.6 +    version: 5.1.6  packages: @@ -1057,6 +1069,14 @@ packages:      engines: {node: '>=10.13.0'}      dev: true +  /@tsconfig/recommended@1.0.2: +    resolution: {integrity: sha512-dbHBtbWBOjq0/otpopAE02NT2Cm05Qe2JsEKeCf/wjSYbI2hz8nCqnpnOJWHATgjDz4fd3dchs3Wy1gQGjfN6w==} +    dev: true + +  /@types/parcel-env@0.0.1: +    resolution: {integrity: sha512-8WmdiJ1uEBcW6AOWzQH7i0141ZXZr7B03YfTpguUDrTHXJHwYU9eEOckBRCZzYGrzb4pdoyBlaIMiTee04uqPQ==} +    dev: true +    /abortcontroller-polyfill@1.7.5:      resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==}      dev: true @@ -1699,6 +1719,12 @@ packages:        posthtml-render: 3.0.0      dev: true +  /prettier@3.0.0: +    resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==} +    engines: {node: '>=14'} +    hasBin: true +    dev: true +    /react-error-overlay@6.0.9:      resolution: {integrity: sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==}      dev: true @@ -1797,6 +1823,12 @@ packages:      engines: {node: '>=10'}      dev: true +  /typescript@5.1.6: +    resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} +    engines: {node: '>=14.17'} +    hasBin: true +    dev: true +    /update-browserslist-db@1.0.11(browserslist@4.21.9):      resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}      hasBin: true diff --git a/docker/crupest-nginx/sites/www/src/main.js b/docker/crupest-nginx/sites/www/src/main.js deleted file mode 100644 index 39d2ba8..0000000 --- a/docker/crupest-nginx/sites/www/src/main.js +++ /dev/null @@ -1,89 +0,0 @@ -import "./style.css"; - -const happy = "happy"; -const angry = "angry"; - -function emotionOpposite(emotion) { -  if (emotion === happy) { -    return angry; -  } else if (emotion === angry) { -    return happy; -  } -} - -function emotionElement(emotion) { -  return document.querySelector(`.slogan.${emotion}`); -} - -function emotionElementHeight(emotion) { -  return emotionElement(emotion).clientHeight; -} - -function setBodyPaddingForEmotion(emotion) { -  document.body.style.paddingTop = `${emotionElementHeight(emotion)}px`; -} - -const sloganEmotionKey = "sloganEmotion"; - -const savedEmotion = localStorage.getItem(sloganEmotionKey) ?? happy; -if (savedEmotion !== happy && savedEmotion !== angry) { -  console.error(`Invalid saved emotion: ${savedEmotion}`); -} - -setBodyPaddingForEmotion(savedEmotion); -setTimeout(() => { -  document.body.style.transition = "padding-top 1s"; -}) - -/** @type {HTMLDivElement} */ -const sloganContainer = document.querySelector(".slogan-container") - -setTimeout(() => { -  sloganContainer.dataset.sloganEmotion = savedEmotion; -  setBodyPaddingForEmotion(savedEmotion); -}, 500); - -for (const emotion of [happy, angry]) { -  emotionElement(emotion).addEventListener("click", () => { -    const opposite = emotionOpposite(emotion); -    localStorage.setItem(sloganEmotionKey, opposite); -    sloganContainer.dataset.sloganEmotion = opposite; -    setBodyPaddingForEmotion(opposite); -  }); -} - - -document.addEventListener("DOMContentLoaded", async () => { -  console.log("Try to fetch GitHub project(number: 2) of crupest."); - -  const todoMessage = document.getElementById("todo-message"); -  const todoContainer = document.getElementById("todo-container"); - -  const res = await fetch("/api/todos"); -  const body = await res.json(); - -  if (res.status !== 200) { -    todoMessage.style.color = "red"; -    todoMessage.textContent = -      "Failed to fetch TODOs. (Maybe due to rate limit. Please try later.)"; -    console.log( -      `Failed to get GitHub project info. Status: ${res.status}. Body: ${body}` -    ); -  } else { -    body.forEach((item) => { -      const { status, title, color } = item; -      const li = document.createElement("li"); -      const statusSpan = document.createElement("span"); -      const titleSpan = document.createElement("span"); -      statusSpan.textContent = status; -      statusSpan.style.color = color; -      titleSpan.textContent = title; -      li.appendChild(statusSpan); -      li.append(" : "); -      li.append(titleSpan); -      todoContainer.appendChild(li); -    }); - -    todoMessage.parentElement.removeChild(todoMessage); -  } -}); diff --git a/docker/crupest-nginx/sites/www/src/main.ts b/docker/crupest-nginx/sites/www/src/main.ts new file mode 100644 index 0000000..17d7e12 --- /dev/null +++ b/docker/crupest-nginx/sites/www/src/main.ts @@ -0,0 +1,96 @@ +import "./style.css"; + +import { fetchTodos } from "./todos"; + +const happy = "happy" as const; +const angry = "angry" as const; +type Emotion = typeof happy | typeof angry; + +function emotionOpposite(emotion: Emotion): Emotion { +  if (emotion === happy) { +    return angry; +  } else { +    return happy; +  } +} + +function emotionElement(emotion: Emotion): HTMLDivElement { +  return document.querySelector<HTMLDivElement>(`.slogan.${emotion}`)!; +} + +function emotionElementHeight(emotion: Emotion): number { +  return emotionElement(emotion).clientHeight; +} + +function updateBodyTopPadding(emotion: Emotion): void { +  document.body.style.paddingTop = `${emotionElementHeight(emotion)}px`; +} + +const sloganEmotionKey = "sloganEmotion"; + +const savedEmotion = +  (localStorage.getItem(sloganEmotionKey) as Emotion | null) ?? happy; +if (savedEmotion !== happy && savedEmotion !== angry) { +  console.error(`Invalid saved emotion: ${savedEmotion}`); +} + +updateBodyTopPadding(savedEmotion); +// Then we add transition animation. +setTimeout(() => { +  document.body.style.transition = "padding-top 1s"; +}); + +const sloganContainer = document.querySelector( +  ".slogan-container" +) as HTMLDivElement; + +setTimeout(() => { +  sloganContainer.dataset.sloganEmotion = savedEmotion; +}, 500); + +const sloganLoadedPromise = new Promise<void>((resolve) => { +  setTimeout(() => { +    resolve(); +  }, 1500); +}); + +for (const emotion of [happy, angry]) { +  emotionElement(emotion).addEventListener("click", () => { +    const opposite = emotionOpposite(emotion); +    localStorage.setItem(sloganEmotionKey, opposite); +    sloganContainer.dataset.sloganEmotion = opposite; +    updateBodyTopPadding(opposite); +  }); +} + +async function loadTodos(syncWith: Promise<unknown>): Promise<void> { +  const todoMessage = document.getElementById("todo-message")!; +  const todoContainer = document.getElementById("todo-container")!; + +  try { +    const todosPromise = fetchTodos(); +    await syncWith; // Let's wait this first. +    const todos = await todosPromise; +    todos.forEach((item) => { +      const { status, title, closed } = item; +      const li = document.createElement("li"); +      li.dataset.status = closed ? "closed" : "open"; +      // The color from api server is kind of ugly at present. +      // li.style.background = color; +      const statusSpan = document.createElement("span"); +      const titleSpan = document.createElement("span"); +      statusSpan.textContent = status; +      titleSpan.textContent = title; +      li.appendChild(statusSpan); +      li.append(" : "); +      li.append(titleSpan); +      todoContainer.appendChild(li); +    }); +    todoMessage.parentElement!.removeChild(todoMessage); +  } catch (e) { +    todoMessage.style.color = "red"; +    todoMessage.textContent = (e as Error).message; +  } +} + +loadTodos(sloganLoadedPromise); diff --git a/docker/crupest-nginx/sites/www/src/mock-todos.ts b/docker/crupest-nginx/sites/www/src/mock-todos.ts new file mode 100644 index 0000000..aacb40e --- /dev/null +++ b/docker/crupest-nginx/sites/www/src/mock-todos.ts @@ -0,0 +1,126 @@ +/** Grabbed at Tue, 18 Jul 2023 15:30:05 GMT, used as mock data. 🍻 */ + +const todos = [ +  { +    status: "Done", +    title: "All BLOCKed by graduate paper.", +    closed: true, +    color: "green", +  }, +  { +    status: "Done", +    title: "Slogan is not completely visible on phone.", +    closed: true, +    color: "green", +  }, +  { +    status: "Todo", +    title: "Users api.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "Secrets api.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "Refactor aio python scripts.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "Nginx path redirection.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "Make services optional.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Done", +    title: "Optimize code-server.", +    closed: true, +    color: "green", +  }, +  { +    status: "Todo", +    title: "No more alpine.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Done", +    title: "No netease music.", +    closed: true, +    color: "green", +  }, +  { +    status: "Done", +    title: "Draft issue status in www TODOs.", +    closed: true, +    color: "green", +  }, +  { +    status: "Done", +    title: "Re-bootstrap front end.", +    closed: true, +    color: "green", +  }, +  { +    status: "Todo", +    title: "Clean react imports for new jsx usage.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Done", +    title: "i18next backend bug.", +    closed: true, +    color: "green", +  }, +  { +    status: "Done", +    title: "Organize buttons.", +    closed: true, +    color: "green", +  }, +  { +    status: "Done", +    title: "Fix dialog typo.", +    closed: true, +    color: "green", +  }, +  { +    status: "Todo", +    title: "Organize OperationDialog.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "New palette api.", +    closed: false, +    color: "blue", +  }, +  { +    status: "Todo", +    title: "No Docker!!!", +    closed: false, +    color: "blue", +  }, +  { +    status: "Done", +    title: "Improve animation of slogan.", +    closed: true, +    color: "green", +  }, +]; + +export default todos; diff --git a/docker/crupest-nginx/sites/www/src/style.css b/docker/crupest-nginx/sites/www/src/style.css index f23bbc0..6937051 100644 --- a/docker/crupest-nginx/sites/www/src/style.css +++ b/docker/crupest-nginx/sites/www/src/style.css @@ -8,6 +8,11 @@ body {    box-sizing: border-box;  } +.h-note { +  font-size: 0.6em; +  color: gray; +} +  @keyframes article-enter {    from {      opacity: 0; @@ -20,17 +25,28 @@ body {    }  } -#main-article { -  padding: 0 1em; -  animation: article-enter 1s; +:root { +  --main-article-horizontal-padding: 1em; +  --main-article-horizontal-margin-shrink: -1em; + +  --im-happy: dodgerblue; +  --im-angry: orangered; +  --im-good: green; +  --im-active: blue;  }  @media (min-width: 576px) { -  #main-article { -    padding: 0 2em; +  :root { +    --main-article-horizontal-padding: 2em; +    --main-article-horizontal-margin-shrink: -2em;    }  } +#main-article { +  padding: 0 var(--main-article-horizontal-padding); +  animation: article-enter 1s; +} +  .slogan-container {    width: 100%;    position: fixed; @@ -48,11 +64,11 @@ body {  }  .slogan.happy { -  background-color: dodgerblue; +  background-color: var(--im-happy);  }  .slogan.angry { -  background-color: orangered; +  background-color: var(--im-angry);  }  .slogan-container[data-slogan-emotion="happy"] .slogan.happy { @@ -70,6 +86,58 @@ body {    font-size: 1.2em;  } +#todo-container { +  list-style: none; +  margin-block: 0; +  padding-inline: 0; +} + +#todo-container li { +  margin: 0 var(--main-article-horizontal-margin-shrink); +  padding: 0.6em 3em; +  color: white; +} + +@keyframes todo-enter-left { +  from { +    opacity: 0; +    transform: translateX(-100%); +  } + +  to { +    opacity: 1; +    transform: translateX(0); +  } +} + +@keyframes todo-enter-right { +  from { +    opacity: 0; +    transform: translateX(100%); +  } + +  to { +    opacity: 1; +    transform: translateX(0); +  } +} + +#todo-container li[data-status="closed"] { +  background-color: var(--im-good); +} + +#todo-container li[data-status="open"] { +  background-color: var(--im-active); +} + +#todo-container li:nth-child(odd) { +  animation: todo-enter-left 1s; +} + +#todo-container li:nth-child(even) { +  animation: todo-enter-right 1s; +} +  .friend-link {    display: inline-block;  } diff --git a/docker/crupest-nginx/sites/www/src/todos.ts b/docker/crupest-nginx/sites/www/src/todos.ts new file mode 100644 index 0000000..5e36875 --- /dev/null +++ b/docker/crupest-nginx/sites/www/src/todos.ts @@ -0,0 +1,29 @@ +export interface Todo { +  status: string; +  title: string; +  closed: boolean; +  color: string; +} + +export async function fetchTodos(): Promise<Todo[]> { +  console.log("Try to fetch TODOs from server."); + +  if (process.env.NODE_ENV !== "production") { +    console.log("YaY! We are developers. 🍻 Use mock TODOs. (After 2s)"); +    // await new Promise((resolve) => setTimeout(resolve, 2000)); +    return (await import("./mock-todos")).default; +  } else { +    const res = await fetch("/api/todos"); +    const body: Todo[] = await res.json(); + +    if (res.status !== 200) { +      console.error( +        `Failed to get TODOs. Status: ${res.status}. Body: ${body}` +      ); +      throw new Error( +        "Failed to fetch TODOs. (Maybe due to rate limit. Please try later.)" +      ); +    } +    return body; +  } +} diff --git a/docker/crupest-nginx/sites/www/tsconfig.json b/docker/crupest-nginx/sites/www/tsconfig.json new file mode 100644 index 0000000..9d1434c --- /dev/null +++ b/docker/crupest-nginx/sites/www/tsconfig.json @@ -0,0 +1,19 @@ +{ +    "extends": "@tsconfig/recommended/tsconfig.json", +    "compilerOptions": { +        "lib": [ +            "ESNext", +            "DOM", +            "DOM.Iterable" +        ], +        "types": [ +            "parcel-env" +        ], +        "target": "ESNext", +        "module": "ESNext", +        "moduleResolution": "bundler", +        "resolveJsonModule": true, +        "isolatedModules": true, +        "noEmit": true +    } +}
\ No newline at end of file | 
