Refactor options page to use Typescript

Also, I've added and ran eslint, and fixed several minor issues accross
the Typescript codebase.

Bug: translateselectedtext:15
Change-Id: I8cfd67697f9bfb22f6de93b64fd750de66bab863
diff --git a/src/options/options.ts b/src/options/options.ts
new file mode 100644
index 0000000..6cdcec9
--- /dev/null
+++ b/src/options/options.ts
@@ -0,0 +1,110 @@
+import './elements/credits-dialog/credits-dialog';
+import './elements/options-editor/options-editor';
+
+import {css, html, LitElement} from 'lit';
+import {customElement, property} from 'lit/decorators.js';
+
+import {msg} from '../common/i18n';
+import {default as Options, OptionsV0} from '../common/options';
+
+import {SHARED_STYLES} from './shared/shared-styles';
+
+const bodyStyles = document.createElement('style');
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore #!if browser_target == 'chromium'
+const widthProperty = 'width: 470px;';
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore #!else
+const widthProperty = '';
+// #!endif
+bodyStyles.textContent = `
+  body {
+    margin: 0;
+    padding: 0;
+    font-size: 90%;
+    ${widthProperty}
+  }
+`;
+
+document.head.append(bodyStyles);
+
+@customElement('options-page')
+export class OptionsPage extends LitElement {
+  @property({type: Object, state: true}) _storageData: OptionsV0;
+
+  constructor() {
+    super();
+    this._storageData = undefined;
+    this.updateStorageData();
+    chrome.storage.onChanged.addListener((_changes, areaName) => {
+      if (areaName == 'sync') this.updateStorageData();
+    });
+  }
+
+  static get styles() {
+    return [
+      SHARED_STYLES,
+      css`
+        :host {
+          display: block;
+          padding: 10px;
+          margin: 14px 17px;
+          font-family: "Roboto", "Arial", sans-serif!important;
+        }
+
+        #credits_container {
+          position: absolute;
+          top: 0px;
+          inset-inline-end: 50px;
+          background: #e3f2fd;
+          border: solid 1px rgb(139, 139, 139);
+          border-top: 0;
+          border-radius: 0px 0px 5px 5px;
+        }
+
+        #credits_container button#credits {
+          color: #1f649d!important;
+          margin: 0 5px;
+          padding: 1px 3px;
+          text-decoration: underline;
+          cursor: pointer;
+        }
+      `,
+    ];
+  }
+
+  render() {
+    return html`
+      <div id="credits_container">
+        <button
+            @click="${this.showCredits}" id="credits"
+            class="notbtn" tabindex="0" role="button">
+          ${msg('options_credits')}
+        </button>
+      </div>
+      <h1 id="welcome">${msg('options_welcome')}</h1>
+      <p id="introduction">${msg('options_introduction')}</p>
+      <options-editor .storageData=${this._storageData}></options-editor>
+      <credits-dialog></credits-dialog>
+    `;
+  }
+
+  updateStorageData() {
+    Options.getOptions(/* readOnly = */ true)
+        .then(options => {
+          this._storageData = {
+            translateinto: options.targetLangs,
+            uniquetab: options.uniqueTab,
+          };
+        })
+        .catch(err => {
+          console.error('Error retrieving user options.', err);
+        });
+  }
+
+  showCredits() {
+    const e =
+        new CustomEvent('show-credits-dialog', {bubbles: true, composed: true});
+    this.renderRoot.querySelector('credits-dialog').dispatchEvent(e);
+  }
+}