From e60b0f3e43776071536ddfddaa5fb45cc1108df4 Mon Sep 17 00:00:00 2001 From: Amanda Baker Date: Sun, 10 Sep 2023 20:45:31 -0700 Subject: [PATCH 01/19] Initial setup for Manifest Generator. --- manifest-generator/app.js | 12 ++++++++++++ .../components/placeholder-component.js | 1 + manifest-generator/icons/48x48.png | Bin 0 -> 180 bytes manifest-generator/icons/512x512.png | Bin 0 -> 1931 bytes manifest-generator/index.html | 16 ++++++++++++++++ manifest-generator/manifest.json | 17 +++++++++++++++++ manifest-generator/style.css | 0 manifest-generator/sw.js | 8 ++++++++ 8 files changed, 54 insertions(+) create mode 100644 manifest-generator/app.js create mode 100644 manifest-generator/components/placeholder-component.js create mode 100644 manifest-generator/icons/48x48.png create mode 100644 manifest-generator/icons/512x512.png create mode 100644 manifest-generator/index.html create mode 100644 manifest-generator/manifest.json create mode 100644 manifest-generator/style.css create mode 100644 manifest-generator/sw.js diff --git a/manifest-generator/app.js b/manifest-generator/app.js new file mode 100644 index 0000000..c16297b --- /dev/null +++ b/manifest-generator/app.js @@ -0,0 +1,12 @@ +const registerServiceWorker = async () => { + try { + await navigator.serviceWorker.register('sw.js'); + console.log('Service worker registered'); + } catch (e) { + console.log(`Registration failed: ${e}`); + } +} + +if (navigator.serviceWorker) { + registerServiceWorker(); +} diff --git a/manifest-generator/components/placeholder-component.js b/manifest-generator/components/placeholder-component.js new file mode 100644 index 0000000..40bd22c --- /dev/null +++ b/manifest-generator/components/placeholder-component.js @@ -0,0 +1 @@ +// This is just to show folder structure and will be deleted later. diff --git a/manifest-generator/icons/48x48.png b/manifest-generator/icons/48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..b549bc48ecabc34164ba6ea3f139dad2fd7dd00b GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HwsAD1)b~pUXO@geCw3Trp(; literal 0 HcmV?d00001 diff --git a/manifest-generator/icons/512x512.png b/manifest-generator/icons/512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..cb88de1b4a01c9986c330aab7ec5ce7efd097d21 GIT binary patch literal 1931 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&t&wwUqN(AjMc5RtvY3HEOcjI~J%dy}Ffgzyc)B=-RK&f#YRGs%LEylF<%d4DDyNhj zbbU9? + + + + Manifest Generator + + + + + + +

Manifest generator

+ + + + \ No newline at end of file diff --git a/manifest-generator/manifest.json b/manifest-generator/manifest.json new file mode 100644 index 0000000..f1e4e8d --- /dev/null +++ b/manifest-generator/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "Manifest Generator", + "start_url": "./index.html", + "display": "standalone", + "icons": [ + { + "src": "icons/48x48.png", + "type": "image/png", + "sizes": "48x48" + }, + { + "src": "icons/512x512.png", + "type": "image/png", + "sizes": "512x512" + } + ] +} \ No newline at end of file diff --git a/manifest-generator/style.css b/manifest-generator/style.css new file mode 100644 index 0000000..e69de29 diff --git a/manifest-generator/sw.js b/manifest-generator/sw.js new file mode 100644 index 0000000..e44d688 --- /dev/null +++ b/manifest-generator/sw.js @@ -0,0 +1,8 @@ +self.addEventListener('fetch', e => { + e.respondWith( + fetch(e.request).catch(() => { + // To-do: useful offline experience. + return new Response('Hello offline page'); + }) + ); +}); From 5a07c526d38ff00241b1b401d546b02b9c97f35d Mon Sep 17 00:00:00 2001 From: Amanda Baker Date: Mon, 11 Sep 2023 14:10:28 -0700 Subject: [PATCH 02/19] Adding Local Storage support (#1) --- manifest-generator/app.js | 8 +++++++- manifest-generator/index.html | 3 ++- manifest-generator/state.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 manifest-generator/state.js diff --git a/manifest-generator/app.js b/manifest-generator/app.js index c16297b..c7fb15b 100644 --- a/manifest-generator/app.js +++ b/manifest-generator/app.js @@ -1,6 +1,8 @@ +import { readManifestFromLocalStorage } from "./state.js"; + const registerServiceWorker = async () => { try { - await navigator.serviceWorker.register('sw.js'); + await navigator.serviceWorker.register("sw.js"); console.log('Service worker registered'); } catch (e) { console.log(`Registration failed: ${e}`); @@ -10,3 +12,7 @@ const registerServiceWorker = async () => { if (navigator.serviceWorker) { registerServiceWorker(); } + +// Grab previous state from Local Storage so that progress is not lost +// across sessions. +readManifestFromLocalStorage(); diff --git a/manifest-generator/index.html b/manifest-generator/index.html index 657d830..89480c8 100644 --- a/manifest-generator/index.html +++ b/manifest-generator/index.html @@ -11,6 +11,7 @@

Manifest generator

- + + \ No newline at end of file diff --git a/manifest-generator/state.js b/manifest-generator/state.js new file mode 100644 index 0000000..90c89b4 --- /dev/null +++ b/manifest-generator/state.js @@ -0,0 +1,28 @@ +let manifestState = {}; + +// Read (Get) entire object from LocalStorage. +// Other places can use this as: +// const state = getManifest(); +// state.name ... +export const getManifest = () => { + return structuredClone(manifestState); +}; + +// Write (Set) entire object LocalStorage. +// Other places can use this as: +// let state = getManifest(); +// state.name = "new value"; +// setManifest(state); +export const setManifest = (newState) => { + if (newState == manifestState) { + return; + } + + manifestState = newState; + localStorage.setItem("manifest", JSON.stringify(newState)); +}; + +export const readManifestFromLocalStorage = () => { + const manifestString = localStorage.getItem("manifest"); + manifestState = JSON.parse(manifestString); +} \ No newline at end of file From 6c5300d1846302575e044484d8048667f100c12c Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Mon, 11 Sep 2023 14:46:06 -0700 Subject: [PATCH 03/19] Adding a simple-text-input web component (#3) --- .../components/simple-text-input-example.html | 16 ++++++ .../components/simple-text-input.js | 49 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 manifest-generator/components/simple-text-input-example.html create mode 100644 manifest-generator/components/simple-text-input.js diff --git a/manifest-generator/components/simple-text-input-example.html b/manifest-generator/components/simple-text-input-example.html new file mode 100644 index 0000000..cd5bb6b --- /dev/null +++ b/manifest-generator/components/simple-text-input-example.html @@ -0,0 +1,16 @@ + + + + + + Simple word count web component + + + + + + + + + + \ No newline at end of file diff --git a/manifest-generator/components/simple-text-input.js b/manifest-generator/components/simple-text-input.js new file mode 100644 index 0000000..858bdbe --- /dev/null +++ b/manifest-generator/components/simple-text-input.js @@ -0,0 +1,49 @@ +// Component for a simple text input page -- a text label and a text input box. +/* + Usage: + +*/ +class SimpleTextInput extends HTMLElement { + constructor() { + super(); + + // Create a shadow root + const shadow = this.attachShadow({mode: 'open'}); + + const tableWrapper = document.createElement('div'); + tableWrapper.setAttribute("class", "table"); + + // Create the page label + const inputLabel = document.createElement('p'); + inputLabel.setAttribute("class", "tableitem"); + inputLabel.textContent = `${this.getAttribute("label")}`; + + // Create the input element + const inputElement = document.createElement('input'); + inputElement.setAttribute("class", "tableitem"); + inputElement.setAttribute("placeholder", `${this.getAttribute("placeholder-text")}`); + + // Style the elements + const style = document.createElement("style"); + style.textContent = `.tableitem { + align-self: center; + } + + .table { + display: flex; + flex-direction: column; + }`; + + // Append the text and input elements to the table + tableWrapper.append(inputLabel); + tableWrapper.append(inputElement); + + // Append the table and style to the shadow DOM + shadow.append(tableWrapper); + shadow.append(style); + } +} + +// Define the new element +customElements.define('simple-text-input', SimpleTextInput); + From 7511549616d5b16ca24c327390cdea2714e03964 Mon Sep 17 00:00:00 2001 From: Adolf Daniel <10156724+adolfdaniel@users.noreply.github.com> Date: Mon, 11 Sep 2023 14:54:23 -0700 Subject: [PATCH 04/19] Add initial manifest view (non-styled) (#2) * Add initial manifest view (non-styled) * rename to app-view --- manifest-generator/components/app-view.js | 55 ++++++++++ .../components/manifest-view/index.js | 64 +++++++++++ .../components/manifest-view/json.js | 64 +++++++++++ .../components/manifest-view/node.js | 102 ++++++++++++++++++ manifest-generator/index.html | 2 + 5 files changed, 287 insertions(+) create mode 100644 manifest-generator/components/app-view.js create mode 100644 manifest-generator/components/manifest-view/index.js create mode 100644 manifest-generator/components/manifest-view/json.js create mode 100644 manifest-generator/components/manifest-view/node.js diff --git a/manifest-generator/components/app-view.js b/manifest-generator/components/app-view.js new file mode 100644 index 0000000..3efc4f6 --- /dev/null +++ b/manifest-generator/components/app-view.js @@ -0,0 +1,55 @@ +// A split app-view to show the manifest viewer in the right pane and the editor in the left pane. + +import './manifest-view/index.js'; + +const template = document.createElement('template'); +template.innerHTML = ` + +
+ + +
+`; + +class AppView extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + connectedCallback() { + console.log('connected'); + } + + disconnectedCallback() { + console.log('disconnected'); + } + + render() { + console.log('render'); + } +} + +customElements.define('app-view', AppView); diff --git a/manifest-generator/components/manifest-view/index.js b/manifest-generator/components/manifest-view/index.js new file mode 100644 index 0000000..5123415 --- /dev/null +++ b/manifest-generator/components/manifest-view/index.js @@ -0,0 +1,64 @@ +import JSONView from './json.js'; + +const json = { + "name": "manifest-generator", + "short_name": "manifest-generator", + "start_url": "/", + "display": "standalone", + "background_color": "#fff", + "theme_color": "#fff", + "description": "A simple tool to generate a web app manifest", + "icons": [ + { + "src": "https://manifest-gen.now.sh/static/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "https://manifest-gen.now.sh/static/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +}; + +// create a web component +class ManifestView extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.innerHTML = ` + +
+

Manifest

+ +
+ `; + } + + connectedCallback() { + console.log('connected'); + } + + disconnectedCallback() { + console.log('disconnected'); + } + + render() { + console.log('render'); + } +} + + +// create a web component +customElements.define('manifest-view', ManifestView); + +// export to use in other files +export default ManifestView; \ No newline at end of file diff --git a/manifest-generator/components/manifest-view/json.js b/manifest-generator/components/manifest-view/json.js new file mode 100644 index 0000000..adb1b11 --- /dev/null +++ b/manifest-generator/components/manifest-view/json.js @@ -0,0 +1,64 @@ +import Node from "./node.js"; + +// Define a custom element for representing a JSON document +const template = document.createElement('template'); +template.innerHTML = ` + +
+`; + +class JSONView extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + + const jsonValue = this.getAttribute('json'); + this.json = JSON.parse(decodeURIComponent(jsonValue)); + } + + connectedCallback() { + console.log('connected'); + this.render(); + } + + disconnectedCallback() { + console.log('disconnected'); + } + + render() { + const json = this.json; + const jsonView = this.shadowRoot.querySelector('.json'); + + Object.keys(json).forEach(key => { + const node = document.createElement('json-node'); + var nodeType = typeof json[key]; + // find if object is an array + if (Array.isArray(json[key])) { + nodeType = 'array'; + } + node.setAttribute('type', nodeType); + // if the value is an object, add values recursively + if (nodeType === 'object' || nodeType === 'array') { + node.setAttribute('key', key); + node.setAttribute('value', encodeURIComponent(JSON.stringify(json[key]))); + jsonView.appendChild(node); + return; + } + node.setAttribute('key', key); + node.setAttribute('value', json[key]); + jsonView.appendChild(node); + }); + } +} + +customElements.define('json-view', JSONView); + +export default JSONView; diff --git a/manifest-generator/components/manifest-view/node.js b/manifest-generator/components/manifest-view/node.js new file mode 100644 index 0000000..f51532a --- /dev/null +++ b/manifest-generator/components/manifest-view/node.js @@ -0,0 +1,102 @@ + +// Define a custom element for representing a JSON node +const template = document.createElement('template'); +template.innerHTML = ` + +
+
+ + +
+ +
+`; +class Node extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + connectedCallback() { + console.log('connected'); + this.key = this.getAttribute('key'); + this.value = this.getAttribute('value'); + if (this.getAttribute('type') === 'array') { + this.shadowRoot.querySelector('.node').setAttribute('collapsed', ''); + } + this.render(); + } + + disconnectedCallback() { + console.log('disconnected'); + } + + observedAttributes() { + return ['key', 'value']; + } + + render() { + const node = this.shadowRoot.querySelector('.node'); + node.addEventListener('click', (e) => { + node.toggleAttribute('collapsed'); + e.stopPropagation(); + }); + + const type = this.getAttribute('type'); + const key = this.shadowRoot.querySelector('.key'); + const value = this.shadowRoot.querySelector('.value'); + key.textContent = this.key; + if (type === 'array') { + const jsonValue = JSON.parse(decodeURIComponent(this.value)); + for (let json of jsonValue) { + document.createElement('json-view'); + value.innerHTML += ``; + } + return; + } + if (type === 'object') { + document.createElement('json-view'); + value.innerHTML = ``; + return; + } + value.textContent = this.value; + } +} + +customElements.define('json-node', Node); + +export default Node; \ No newline at end of file diff --git a/manifest-generator/index.html b/manifest-generator/index.html index 89480c8..afd387f 100644 --- a/manifest-generator/index.html +++ b/manifest-generator/index.html @@ -13,5 +13,7 @@

Manifest generator

+ + \ No newline at end of file From 4c6b24e96234c0fa7677cde1ba757053fc957c59 Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Mon, 11 Sep 2023 15:52:43 -0700 Subject: [PATCH 05/19] updating label to be optional (#4) --- .../components/simple-text-input-example.html | 5 +++-- .../components/simple-text-input.js | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/manifest-generator/components/simple-text-input-example.html b/manifest-generator/components/simple-text-input-example.html index cd5bb6b..031f916 100644 --- a/manifest-generator/components/simple-text-input-example.html +++ b/manifest-generator/components/simple-text-input-example.html @@ -7,8 +7,9 @@ - - + + + diff --git a/manifest-generator/components/simple-text-input.js b/manifest-generator/components/simple-text-input.js index 858bdbe..dfdd543 100644 --- a/manifest-generator/components/simple-text-input.js +++ b/manifest-generator/components/simple-text-input.js @@ -1,7 +1,9 @@ -// Component for a simple text input page -- a text label and a text input box. +// Component for a simple text input field. Optional attributes for a label and placeholder text. /* Usage: - + + + */ class SimpleTextInput extends HTMLElement { constructor() { @@ -16,12 +18,18 @@ class SimpleTextInput extends HTMLElement { // Create the page label const inputLabel = document.createElement('p'); inputLabel.setAttribute("class", "tableitem"); - inputLabel.textContent = `${this.getAttribute("label")}`; + if (this.getAttribute("label")) { + inputLabel.textContent = `${this.getAttribute("label")}`; + } else { + inputLabel.setAttribute("hidden", true); + } // Create the input element const inputElement = document.createElement('input'); inputElement.setAttribute("class", "tableitem"); - inputElement.setAttribute("placeholder", `${this.getAttribute("placeholder-text")}`); + if (this.getAttribute("placeholder-text")) { + inputElement.setAttribute("placeholder", `${this.getAttribute("placeholder-text")}`); + } // Style the elements const style = document.createElement("style"); From 2754bddd0be06d7511e02145046c6264fe6659b1 Mon Sep 17 00:00:00 2001 From: Alexander Kyereboah <59938429+kyerebo@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:54:31 -0700 Subject: [PATCH 06/19] Adding color picker component (#5) --- manifest-generator/components/color-picker.js | 54 +++++++++++++++++++ .../components/simple-text-input-example.html | 1 + 2 files changed, 55 insertions(+) create mode 100644 manifest-generator/components/color-picker.js diff --git a/manifest-generator/components/color-picker.js b/manifest-generator/components/color-picker.js new file mode 100644 index 0000000..8baa59b --- /dev/null +++ b/manifest-generator/components/color-picker.js @@ -0,0 +1,54 @@ +// Component for a color picker -- a text label and a color input box. +/* + Usage: + +*/ +class ColorPicker extends HTMLElement { + inputElement; + constructor() { + super(); + this.inputElement = document.createElement('input'); + + // Create a shadow root + const shadow = this.attachShadow({mode: 'open'}); + + const tableWrapper = document.createElement('div'); + tableWrapper.setAttribute("class", "table"); + + // Create the page label + const inputLabel = document.createElement('p'); + inputLabel.setAttribute("class", "tableitem"); + inputLabel.textContent = `${this.getAttribute("label")}`; + + // Create the input element + this.inputElement.setAttribute("type", "color"); + this.inputElement.setAttribute("class", "tableitem"); + + // Style the elements + const style = document.createElement("style"); + style.textContent = `.tableitem { + align-self: center; + } + + .table { + display: flex; + flex-direction: column; + }`; + + // Append the text and input elements to the table + tableWrapper.append(inputLabel); + tableWrapper.append(this.inputElement); + + // Append the table and style to the shadow DOM + shadow.append(tableWrapper); + shadow.append(style); + } + + getUserInput(){ + return this.inputElement.value; + } + } + + // Define the new element + customElements.define('color-picker', ColorPicker); + \ No newline at end of file diff --git a/manifest-generator/components/simple-text-input-example.html b/manifest-generator/components/simple-text-input-example.html index 031f916..618f8da 100644 --- a/manifest-generator/components/simple-text-input-example.html +++ b/manifest-generator/components/simple-text-input-example.html @@ -13,5 +13,6 @@ + \ No newline at end of file From 0a22932fb88e5d5f8240db3ee92cc6cae3cf3762 Mon Sep 17 00:00:00 2001 From: Marcos Eizayaga <63314030+marcoseiza@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:05:41 -0400 Subject: [PATCH 07/19] Marcos/prettier (#7) * prettier config * format * update styling --- manifest-generator/.prettierrc.json | 11 +++ manifest-generator/app.js | 4 +- manifest-generator/components/app-view.js | 14 ++-- manifest-generator/components/color-picker.js | 79 +++++++++---------- .../components/manifest-view/index.js | 51 ++++++------ .../components/manifest-view/json.js | 35 ++++---- .../components/manifest-view/node.js | 51 ++++++------ .../components/simple-text-input-example.html | 31 ++++---- .../components/simple-text-input.js | 16 ++-- manifest-generator/index.html | 4 +- manifest-generator/manifest.json | 2 +- manifest-generator/state.js | 2 +- manifest-generator/sw.js | 4 +- 13 files changed, 162 insertions(+), 142 deletions(-) create mode 100644 manifest-generator/.prettierrc.json diff --git a/manifest-generator/.prettierrc.json b/manifest-generator/.prettierrc.json new file mode 100644 index 0000000..3626b62 --- /dev/null +++ b/manifest-generator/.prettierrc.json @@ -0,0 +1,11 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "printWidth": 80, + "singleQuote": false, + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "always", + "singleAttributePerLine": false +} diff --git a/manifest-generator/app.js b/manifest-generator/app.js index c7fb15b..f3b6ed4 100644 --- a/manifest-generator/app.js +++ b/manifest-generator/app.js @@ -3,11 +3,11 @@ import { readManifestFromLocalStorage } from "./state.js"; const registerServiceWorker = async () => { try { await navigator.serviceWorker.register("sw.js"); - console.log('Service worker registered'); + console.log("Service worker registered"); } catch (e) { console.log(`Registration failed: ${e}`); } -} +}; if (navigator.serviceWorker) { registerServiceWorker(); diff --git a/manifest-generator/components/app-view.js b/manifest-generator/components/app-view.js index 3efc4f6..5846a03 100644 --- a/manifest-generator/components/app-view.js +++ b/manifest-generator/components/app-view.js @@ -1,8 +1,8 @@ // A split app-view to show the manifest viewer in the right pane and the editor in the left pane. -import './manifest-view/index.js'; +import "./manifest-view/index.js"; -const template = document.createElement('template'); +const template = document.createElement("template"); template.innerHTML = `

Manifest

- +
`; } connectedCallback() { - console.log('connected'); + console.log("connected"); } disconnectedCallback() { - console.log('disconnected'); + console.log("disconnected"); } render() { - console.log('render'); + console.log("render"); } } - // create a web component -customElements.define('manifest-view', ManifestView); +customElements.define("manifest-view", ManifestView); // export to use in other files -export default ManifestView; \ No newline at end of file +export default ManifestView; diff --git a/manifest-generator/components/manifest-view/json.js b/manifest-generator/components/manifest-view/json.js index adb1b11..b19f7fb 100644 --- a/manifest-generator/components/manifest-view/json.js +++ b/manifest-generator/components/manifest-view/json.js @@ -1,7 +1,7 @@ import Node from "./node.js"; // Define a custom element for representing a JSON document -const template = document.createElement('template'); +const template = document.createElement("template"); template.innerHTML = ` +
+ Back home +
+
+

Title Lorem ipsum

+

H1 Lorem ipsum

+

H2 Lorem ipsum

+

H3 Lorem ipsum

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis + molestie, dictum est a, mattis tellus. Sed dignissim, metus nec + fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus + elit sed risus. Maecenas eget condimentum velit, sit amet feugiat + lectus. Class aptent taciti sociosqu ad litora torquent per conubia + nostra, per inceptos himenaeos. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis + molestie, dictum est a, mattis tellus. +

+
+ Link +
+

Error: Lorem ipsum dolor sit

+
+ +
+
+ +
+ +
+ + +
+
+ +
+
+ +
+
+ + diff --git a/manifest-generator/index.html b/manifest-generator/index.html index c046031..f3dd349 100644 --- a/manifest-generator/index.html +++ b/manifest-generator/index.html @@ -6,12 +6,18 @@ + + + -

Manifest generator

- + design reference + diff --git a/manifest-generator/style.css b/manifest-generator/style.css index e69de29..9ae8be9 100644 --- a/manifest-generator/style.css +++ b/manifest-generator/style.css @@ -0,0 +1,7 @@ +@import url("./styles/defaults.css"); +@import url("./styles/button.css"); +@import url("./styles/input.css"); + +body { + background: var(--c-bkg); +} diff --git a/manifest-generator/styles/button.css b/manifest-generator/styles/button.css new file mode 100644 index 0000000..48bfa31 --- /dev/null +++ b/manifest-generator/styles/button.css @@ -0,0 +1,77 @@ +button { + appearance: button; + -webkit-appearance: button; + + background-color: initial; + background-image: none; + + font-family: inherit; + font-size: 16px; + + text-transform: uppercase; + + color: var(--c-text); + + cursor: pointer; + margin: 0 0.2em; +} + +a.btn-primary, +a.btn-secondary, +a.btn-primary:focus-visible, +a.btn-secondary:focus-visible { + border: none; + color: var(--c-white); + text-transform: uppercase; + font-size: 16px; + line-height: 3em; + margin: 0 0.2em; +} + +button.btn-primary, +a.btn-primary { + background-color: var(--c-blue); + font-weight: 500; + padding: 0.8em 1.5em; + border-radius: var(--border-radius); + + transition: var(--transition-color); +} + +button.btn-primary:hover, +button.btn-primary:focus, +a.btn-primary:hover, +a.btn-primary:focus { + background-color: var(--c-blue-dark); +} + +button.btn-primary:focus-visible, +a.btn-primary:focus-visible { + outline: 2px solid var(--c-blue-dark); + outline-offset: 2px; + background-color: var(--c-blue-dark); +} + +button.btn-secondary, +a.btn-secondary { + background-color: var(--c-gray); + font-weight: 500; + padding: 0.8em 1.5em; + border-radius: var(--border-radius); + + transition: var(--transition-color); +} + +button.btn-secondary:hover, +button.btn-secondary:focus, +a.btn-secondary:hover, +a.btn-secondary:focus { + background-color: var(--c-gray-light); +} + +button.btn-secondary:focus-visible, +a.btn-secondary:focus-visible { + outline: 2px solid var(--c-gray-light); + outline-offset: 2px; + background-color: var(--c-gray-light); +} diff --git a/manifest-generator/styles/defaults.css b/manifest-generator/styles/defaults.css new file mode 100644 index 0000000..65b5517 --- /dev/null +++ b/manifest-generator/styles/defaults.css @@ -0,0 +1,140 @@ +:root { + --c-bkg: #252931; + --c-bkg-secondary: #353942; + --c-white: #ffffff; + --c-blue: #528bff; + --c-gray: #555b68; + --c-gray-light: #898b90; + --c-blue-gray: #898b90; + --c-blue-dark: #2870ff; + --c-red: #cb463a; + --c-bkg-card: var(--c-bkg-secondary); + --c-text: var(--c-white); + --c-error: var(--c-red); + + --border-radius: 10px; + + --transition-duration: 150ms; + --transition-color: color var(--transition-duration) ease-in-out, + background-color var(--transition-duration) ease-in-out; +} + +*, +:after, +:before { + box-sizing: border-box; + border: 0 solid #e5e7eb; +} + +html { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: "Montserrat", ui-sans-serif, system-ui, -apple-system, + BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, + sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, + Noto Color Emoji; +} + +body { + margin: 0; + line-height: inherit; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} +a { + color: inherit; + text-decoration: inherit; +} + +h1, +h2, +h3, +p, +span, +a { + color: var(--c-text); +} + +h1.text-title { + font-size: 72px; + line-height: 110%; + font-weight: 900; +} + +h1 { + font-size: 48px; + line-height: 110%; + letter-spacing: -1%; + font-weight: 700; +} + +h2 { + font-size: 32px; + line-height: 110%; + letter-spacing: 0%; + font-weight: 700; +} + +h3 { + font-size: 24px; + line-height: 150%; + letter-spacing: 0%; + font-weight: 500; +} + +p, +span, +a { + font-size: 16px; + line-height: 150%; + letter-spacing: 2%; + font-weight: 400; +} + +.text-sub { + font-size: 14px; + line-height: 150%; + letter-spacing: 2%; + font-weight: 400; +} + +.text-error { + color: var(--c-error); +} + +a { + font-size: 16px; + line-height: 150%; + font-weight: 500; + border-bottom: 2px solid currentColor; +} + +a:hover, +a:focus { + color: var(--c-blue); + transition: var(--transition-color); +} + +a:focus-within { + outline: none; +} + +p a { + font-size: inherit; + font-weight: inherit; + color: var(--c-blue); +} + +p a:hover, +p a:focus { + color: var(--c-blue-dark); +} diff --git a/manifest-generator/styles/input.css b/manifest-generator/styles/input.css new file mode 100644 index 0000000..43d1d65 --- /dev/null +++ b/manifest-generator/styles/input.css @@ -0,0 +1,45 @@ +input[type="text"] { + background-color: var(--c-gray); + padding: 0.8em 1em; + border-radius: var(--border-radius); + color: var(--c-text); + font-size: 16px; + font-weight: 400; + font-family: inherit; + margin: 0 0.2em; +} + +::placeholder { + color: var(--c-blue-gray); + opacity: 1; /* Firefox */ +} +:-ms-input-placeholder { + /* Internet Explorer 10-11 */ + color: var(--c-blue-gray); +} +::-ms-input-placeholder { + /* Microsoft Edge */ + color: var(--c-blue-gray); +} + +textarea { + background-color: var(--c-gray); + padding: 0.8em 1em; + border-radius: var(--border-radius); + color: var(--c-text); + font-size: 16px; + font-weight: 400; + font-family: inherit; + margin: 0 0.2em; + height: 10em; + min-width: 400px; + resize: vertical; +} + +input[error], +textarea[error] { + outline-style: solid; + outline-color: var(--c-red); + outline-width: 2px; + outline-offset: 2px; +} From 3903947a96ede186ad30fe275751a49dac8fc1e7 Mon Sep 17 00:00:00 2001 From: Hassan Talat Date: Tue, 12 Sep 2023 12:03:25 -0700 Subject: [PATCH 09/19] Make json collapsible (#8) * make json collapsible * formatting --------- Co-authored-by: Adolf Daniel <10156724+adolfdaniel@users.noreply.github.com> --- .../components/manifest-view/json-array.js | 56 ++++++++++++++++ .../components/manifest-view/json.js | 29 ++++++-- .../components/manifest-view/node.js | 67 +++++++------------ 3 files changed, 105 insertions(+), 47 deletions(-) create mode 100644 manifest-generator/components/manifest-view/json-array.js diff --git a/manifest-generator/components/manifest-view/json-array.js b/manifest-generator/components/manifest-view/json-array.js new file mode 100644 index 0000000..50d415d --- /dev/null +++ b/manifest-generator/components/manifest-view/json-array.js @@ -0,0 +1,56 @@ +const template = document.createElement("template"); +template.innerHTML = ` + +
+`; + +class JSONArray extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + connectedCallback() { + console.log("connected"); + const jsonValue = this.getAttribute("json"); + this.json = JSON.parse(decodeURIComponent(jsonValue)); + this.render(); + } + + disconnectedCallback() { + console.log("disconnected"); + } + + render() { + const jsonValue = this.json; + const arrayNode = this.shadowRoot.querySelector(".node"); + for (let json of jsonValue) { + const node = document.createElement("json-view"); + node.setAttribute("json", encodeURIComponent(JSON.stringify(json))); + arrayNode.appendChild(node); + } + } + + observedAttributes() { + return ["json"]; + } +} + +customElements.define("json-array", JSONArray); + +export default JSONArray; diff --git a/manifest-generator/components/manifest-view/json.js b/manifest-generator/components/manifest-view/json.js index 033ddf4..795f69c 100644 --- a/manifest-generator/components/manifest-view/json.js +++ b/manifest-generator/components/manifest-view/json.js @@ -1,4 +1,4 @@ -import Node from "./node.js"; +import "./node.js"; // Define a custom element for representing a JSON document const template = document.createElement("template"); @@ -11,6 +11,12 @@ template.innerHTML = ` max-width: 600px; margin: 0 auto; } + .json::before { + content: '{'; + } + .json::after { + content: '}'; + }
`; @@ -20,13 +26,12 @@ class JSONView extends HTMLElement { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild(template.content.cloneNode(true)); - - const jsonValue = this.getAttribute("json"); - this.json = JSON.parse(decodeURIComponent(jsonValue)); } connectedCallback() { console.log("connected"); + const jsonValue = this.getAttribute("json"); + this.json = JSON.parse(decodeURIComponent(jsonValue)); this.render(); } @@ -35,9 +40,23 @@ class JSONView extends HTMLElement { } render() { - const json = this.json; const jsonView = this.shadowRoot.querySelector(".json"); + jsonView.addEventListener("click", (e) => { + const isCollapsed = jsonView.getAttribute("collapsed") !== null; + jsonView.toggleAttribute("collapsed"); + if (isCollapsed) { + jsonView.innerHTML = ""; + this.renderNodes(jsonView, this.json); + } else { + jsonView.innerHTML = "..."; + } + e.stopPropagation(); + }); + + this.renderNodes(jsonView, this.json); + } + renderNodes(jsonView, json) { Object.keys(json).forEach((key) => { const node = document.createElement("json-node"); var nodeType = typeof json[key]; diff --git a/manifest-generator/components/manifest-view/node.js b/manifest-generator/components/manifest-view/node.js index e072c39..8807dcc 100644 --- a/manifest-generator/components/manifest-view/node.js +++ b/manifest-generator/components/manifest-view/node.js @@ -1,3 +1,5 @@ +import "./json-array.js"; + // Define a custom element for representing a JSON node const template = document.createElement("template"); template.innerHTML = ` @@ -5,42 +7,23 @@ template.innerHTML = `
-
- -
`; @@ -55,9 +38,6 @@ class Node extends HTMLElement { console.log("connected"); this.key = this.getAttribute("key"); this.value = this.getAttribute("value"); - if (this.getAttribute("type") === "array") { - this.shadowRoot.querySelector(".node").setAttribute("collapsed", ""); - } this.render(); } @@ -71,33 +51,36 @@ class Node extends HTMLElement { render() { const node = this.shadowRoot.querySelector(".node"); - node.addEventListener("click", (e) => { - node.toggleAttribute("collapsed"); - e.stopPropagation(); - }); const type = this.getAttribute("type"); const key = this.shadowRoot.querySelector(".key"); const value = this.shadowRoot.querySelector(".value"); - key.textContent = this.key; + key.textContent = `"${this.key}" : `; + if (type === "object" || type === "array") { + node.addEventListener("click", (e) => { + const isCollapsed = node.getAttribute("collapsed") !== null; + node.toggleAttribute("collapsed"); + if (!isCollapsed) { + value.innerHTML = "..."; + } else { + this.renderValue(value, type, this.value); + } + e.stopPropagation(); + }); + } + this.renderValue(value, type, this.value); + } + + renderValue(element, type, value) { if (type === "array") { - const jsonValue = JSON.parse(decodeURIComponent(this.value)); - for (let json of jsonValue) { - document.createElement("json-view"); - value.innerHTML += ``; - } + element.innerHTML = ``; return; } if (type === "object") { - document.createElement("json-view"); - value.innerHTML = ``; + element.innerHTML = ``; return; } - value.textContent = this.value; + element.textContent = value; } } From e2aae6aa834b60a6d8e9224c1d6a8f226e43884c Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Tue, 12 Sep 2023 14:28:14 -0700 Subject: [PATCH 10/19] Adding page web component (#9) * Adding page web component * formatting changes --- .../components/page-view-example.html | 28 ++++++++++++++ manifest-generator/components/page-view.js | 37 +++++++++++++++++++ .../components/simple-text-input-example.html | 2 +- .../components/simple-text-input.js | 6 +-- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 manifest-generator/components/page-view-example.html create mode 100644 manifest-generator/components/page-view.js diff --git a/manifest-generator/components/page-view-example.html b/manifest-generator/components/page-view-example.html new file mode 100644 index 0000000..3430fb3 --- /dev/null +++ b/manifest-generator/components/page-view-example.html @@ -0,0 +1,28 @@ + + + + + PageView example page + + + + + + + + + + + + + + diff --git a/manifest-generator/components/page-view.js b/manifest-generator/components/page-view.js new file mode 100644 index 0000000..fcd4bf7 --- /dev/null +++ b/manifest-generator/components/page-view.js @@ -0,0 +1,37 @@ +// Component for a page wrapper -- includes an h1 for page title and a slot for each custom component. +// See page-view-example.html for usage eaxmple. +// Has a public API `getId()` that returns this page's unique ID, set via page-id attribute. + +class PageView extends HTMLElement { + #id; + + constructor() { + super(); + + const pageViewTemplate = document.createElement("template"); + pageViewTemplate.innerHTML = ` + + +

${this.getAttribute("title")}

+ My Default Text`; + + // Create a shadow root + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(pageViewTemplate.content.cloneNode(true)); + + // Set the id field based on the id attribute + this.#id = this.getAttribute("page-id"); + console.log("this page's ID is = " + this.#id); + } + + getId() { + return this.#id; + } +} + +// Define the new element +customElements.define("page-view", PageView); diff --git a/manifest-generator/components/simple-text-input-example.html b/manifest-generator/components/simple-text-input-example.html index 4f73d76..4c6c87b 100644 --- a/manifest-generator/components/simple-text-input-example.html +++ b/manifest-generator/components/simple-text-input-example.html @@ -1,4 +1,4 @@ - + diff --git a/manifest-generator/components/simple-text-input.js b/manifest-generator/components/simple-text-input.js index 25e453f..d7d82ec 100644 --- a/manifest-generator/components/simple-text-input.js +++ b/manifest-generator/components/simple-text-input.js @@ -1,10 +1,6 @@ // Component for a simple text input field. Optional attributes for a label and placeholder text. -/* - Usage: - +// See simple-text-input-example.html for usage examples. - -*/ class SimpleTextInput extends HTMLElement { constructor() { super(); From b957ebda6b362b520069fefc3c9e1f5da2b44fa7 Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Tue, 12 Sep 2023 15:31:31 -0700 Subject: [PATCH 11/19] Add getting user input (#12) * adding get user input * Privatizing color picker input element * making simple-text-input inputElement private --- manifest-generator/components/color-picker.js | 12 ++++++------ .../components/simple-text-input.js | 17 +++++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/manifest-generator/components/color-picker.js b/manifest-generator/components/color-picker.js index 9b17b18..8d53287 100644 --- a/manifest-generator/components/color-picker.js +++ b/manifest-generator/components/color-picker.js @@ -4,10 +4,10 @@ */ class ColorPicker extends HTMLElement { - inputElement; + #inputElement; constructor() { super(); - this.inputElement = document.createElement("input"); + this.#inputElement = document.createElement("input"); // Create a shadow root const shadow = this.attachShadow({ mode: "open" }); @@ -21,8 +21,8 @@ class ColorPicker extends HTMLElement { inputLabel.textContent = `${this.getAttribute("label")}`; // Create the input element - this.inputElement.setAttribute("type", "color"); - this.inputElement.setAttribute("class", "tableitem"); + this.#inputElement.setAttribute("type", "color"); + this.#inputElement.setAttribute("class", "tableitem"); // Style the elements const style = document.createElement("style"); @@ -37,7 +37,7 @@ class ColorPicker extends HTMLElement { // Append the text and input elements to the table tableWrapper.append(inputLabel); - tableWrapper.append(this.inputElement); + tableWrapper.append(this.#inputElement); // Append the table and style to the shadow DOM shadow.append(tableWrapper); @@ -45,7 +45,7 @@ class ColorPicker extends HTMLElement { } getUserInput() { - return this.inputElement.value; + return this.#inputElement.value; } } diff --git a/manifest-generator/components/simple-text-input.js b/manifest-generator/components/simple-text-input.js index d7d82ec..6ff1710 100644 --- a/manifest-generator/components/simple-text-input.js +++ b/manifest-generator/components/simple-text-input.js @@ -2,6 +2,7 @@ // See simple-text-input-example.html for usage examples. class SimpleTextInput extends HTMLElement { + #inputElement; constructor() { super(); @@ -13,7 +14,7 @@ class SimpleTextInput extends HTMLElement { // Create the page label const inputLabel = document.createElement("p"); - inputLabel.setAttribute("class", "tableitem"); + inputLabel.setAttribute("class", "table-item"); if (this.getAttribute("label")) { inputLabel.textContent = `${this.getAttribute("label")}`; } else { @@ -21,10 +22,10 @@ class SimpleTextInput extends HTMLElement { } // Create the input element - const inputElement = document.createElement("input"); - inputElement.setAttribute("class", "tableitem"); + this.#inputElement = document.createElement("input"); + this.#inputElement.setAttribute("class", "table-item"); if (this.getAttribute("placeholder-text")) { - inputElement.setAttribute( + this.#inputElement.setAttribute( "placeholder", `${this.getAttribute("placeholder-text")}` ); @@ -32,7 +33,7 @@ class SimpleTextInput extends HTMLElement { // Style the elements const style = document.createElement("style"); - style.textContent = `.tableitem { + style.textContent = `.table-item { align-self: center; } @@ -43,12 +44,16 @@ class SimpleTextInput extends HTMLElement { // Append the text and input elements to the table tableWrapper.append(inputLabel); - tableWrapper.append(inputElement); + tableWrapper.append(this.#inputElement); // Append the table and style to the shadow DOM shadow.append(tableWrapper); shadow.append(style); } + + getUserInput() { + return this.#inputElement.value; + } } // Define the new element From 4c5b1fbb80383b4dac08cae2aefdf54c6eeb2922 Mon Sep 17 00:00:00 2001 From: Kristin <71902467+Kbhlee2121@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:35:05 -0700 Subject: [PATCH 12/19] add images as radio buttons (#10) * add images as radio buttons * update name to DisplayMode --- manifest-generator/components/display-mode.js | 110 ++++++++++++++++++ .../components/simple-text-input-example.html | 1 - 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 manifest-generator/components/display-mode.js diff --git a/manifest-generator/components/display-mode.js b/manifest-generator/components/display-mode.js new file mode 100644 index 0000000..9d16f38 --- /dev/null +++ b/manifest-generator/components/display-mode.js @@ -0,0 +1,110 @@ +// Component for a images as radio buttons. +/* + Usage: + + +*/ + +const template = document.createElement("template"); +template.innerHTML = ` + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+`; + +class DisplayMode extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + getUserInput() { + const inputElement = this.shadowRoot.querySelector( + "input[type='radio']:checked" + ); + if (inputElement) { + return inputElement.value; + } + return; + } +} + +// Define the new element +customElements.define("display-mode", DisplayMode); diff --git a/manifest-generator/components/simple-text-input-example.html b/manifest-generator/components/simple-text-input-example.html index 4c6c87b..d578adc 100644 --- a/manifest-generator/components/simple-text-input-example.html +++ b/manifest-generator/components/simple-text-input-example.html @@ -15,5 +15,4 @@ - From b949bc22d8d40b35b19cb0df85db6d0c6b8ba5af Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Tue, 12 Sep 2023 15:48:53 -0700 Subject: [PATCH 13/19] add long text input component (#13) * add long text input component * fixing formatting. --------- Co-authored-by: Lia Hiscock --- .../components/long-text-input-example.html | 18 ++++++ .../components/long-text-input.js | 60 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 manifest-generator/components/long-text-input-example.html create mode 100644 manifest-generator/components/long-text-input.js diff --git a/manifest-generator/components/long-text-input-example.html b/manifest-generator/components/long-text-input-example.html new file mode 100644 index 0000000..7a97d12 --- /dev/null +++ b/manifest-generator/components/long-text-input-example.html @@ -0,0 +1,18 @@ + + + + + Simple word count web component + + + + + + + + + + diff --git a/manifest-generator/components/long-text-input.js b/manifest-generator/components/long-text-input.js new file mode 100644 index 0000000..1141ae4 --- /dev/null +++ b/manifest-generator/components/long-text-input.js @@ -0,0 +1,60 @@ +// Component for a long text input box. Optional attributes for a label and placeholder text. +// See long-text-input-example.html for usage examples. + +class LongTextInput extends HTMLElement { + #inputElement; + constructor() { + super(); + + // Create a shadow root + const shadow = this.attachShadow({ mode: "open" }); + + const tableWrapper = document.createElement("div"); + tableWrapper.setAttribute("class", "table"); + + // Create the page label + const inputLabel = document.createElement("p"); + inputLabel.setAttribute("class", "table-item"); + if (this.getAttribute("label")) { + inputLabel.textContent = `${this.getAttribute("label")}`; + } else { + inputLabel.setAttribute("hidden", true); + } + + // Create the input element + this.#inputElement = document.createElement("textarea"); + this.#inputElement.setAttribute("class", "table-item"); + if (this.getAttribute("placeholder-text")) { + this.#inputElement.setAttribute( + "placeholder", + `${this.getAttribute("placeholder-text")}` + );∏ + } + + // Style the elements + const style = document.createElement("style"); + style.textContent = `.table-item { + align-self: center; + } + + .table { + display: flex; + flex-direction: column; + }`; + + // Append the text and input elements to the table + tableWrapper.append(inputLabel); + tableWrapper.append(this.#inputElement); + + // Append the table and style to the shadow DOM + shadow.append(tableWrapper); + shadow.append(style); + } + + getUserInput() { + return this.#inputElement.value; + } +} + +// Define the new element +customElements.define("long-text-input", LongTextInput); From 5898c7eca88418bf62ec74acda53308f31a43ea6 Mon Sep 17 00:00:00 2001 From: Marcos Eizayaga <63314030+marcoseiza@users.noreply.github.com> Date: Tue, 12 Sep 2023 19:27:12 -0400 Subject: [PATCH 14/19] Marcos/navigation (#11) * navigation component * add a couple of pages * fix lifecycle bug * remove lifecycle component --- manifest-generator/app.js | 1 - manifest-generator/components/app-view.js | 45 +++++- .../components/manifest-view/index.js | 12 -- .../components/manifest-view/json-array.js | 5 +- .../components/manifest-view/json.js | 6 +- .../components/manifest-view/node.js | 5 - .../components/navigation-view.js | 128 ++++++++++++++++++ manifest-generator/components/page-view.js | 6 +- manifest-generator/index.html | 6 +- 9 files changed, 173 insertions(+), 41 deletions(-) create mode 100644 manifest-generator/components/navigation-view.js diff --git a/manifest-generator/app.js b/manifest-generator/app.js index f3b6ed4..0363299 100644 --- a/manifest-generator/app.js +++ b/manifest-generator/app.js @@ -3,7 +3,6 @@ import { readManifestFromLocalStorage } from "./state.js"; const registerServiceWorker = async () => { try { await navigator.serviceWorker.register("sw.js"); - console.log("Service worker registered"); } catch (e) { console.log(`Registration failed: ${e}`); } diff --git a/manifest-generator/components/app-view.js b/manifest-generator/components/app-view.js index 5846a03..1c0d346 100644 --- a/manifest-generator/components/app-view.js +++ b/manifest-generator/components/app-view.js @@ -1,9 +1,12 @@ // A split app-view to show the manifest viewer in the right pane and the editor in the left pane. import "./manifest-view/index.js"; +import "./navigation-view.js"; +import "./page-view.js"; const template = document.createElement("template"); template.innerHTML = ` +
- + + +

Page 1

+
+ +

Page 2

+
+
`; @@ -35,20 +45,41 @@ template.innerHTML = ` class AppView extends HTMLElement { constructor() { super(); + this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild(template.content.cloneNode(true)); + this.navigationView = this.shadowRoot.querySelector("navigation-view"); + + this.pageIds = ["page-1", "page-2"]; + this.currentPageIdIndex = 0; + + this.navigationView.addEventListener("next", () => this.nextPage()); + this.navigationView.addEventListener("prev", () => this.prevPage()); + this.navigationView.addEventListener("skip", () => this.skipPage()); + } + + nextPage() { + this.jumpToPage( + Math.min(this.currentPageIdIndex + 1, this.pageIds.length - 1) + ); } - connectedCallback() { - console.log("connected"); + prevPage() { + this.jumpToPage(Math.max(this.currentPageIdIndex - 1, 0)); } - disconnectedCallback() { - console.log("disconnected"); + skipPage() { + this.jumpToPage( + Math.min(this.currentPageIdIndex + 1, this.pageIds.length - 1) + ); } - render() { - console.log("render"); + jumpToPage(pageIndex) { + this.currentPageIdIndex = pageIndex; + this.navigationView.setAttribute( + "current-id", + this.pageIds[this.currentPageIdIndex] + ); } } diff --git a/manifest-generator/components/manifest-view/index.js b/manifest-generator/components/manifest-view/index.js index cf74481..a05af49 100644 --- a/manifest-generator/components/manifest-view/index.js +++ b/manifest-generator/components/manifest-view/index.js @@ -45,18 +45,6 @@ class ManifestView extends HTMLElement { `; } - - connectedCallback() { - console.log("connected"); - } - - disconnectedCallback() { - console.log("disconnected"); - } - - render() { - console.log("render"); - } } // create a web component diff --git a/manifest-generator/components/manifest-view/json-array.js b/manifest-generator/components/manifest-view/json-array.js index 50d415d..921fe88 100644 --- a/manifest-generator/components/manifest-view/json-array.js +++ b/manifest-generator/components/manifest-view/json-array.js @@ -26,15 +26,12 @@ class JSONArray extends HTMLElement { } connectedCallback() { - console.log("connected"); const jsonValue = this.getAttribute("json"); this.json = JSON.parse(decodeURIComponent(jsonValue)); this.render(); } - disconnectedCallback() { - console.log("disconnected"); - } + disconnectedCallback() {} render() { const jsonValue = this.json; diff --git a/manifest-generator/components/manifest-view/json.js b/manifest-generator/components/manifest-view/json.js index 795f69c..e2e7fda 100644 --- a/manifest-generator/components/manifest-view/json.js +++ b/manifest-generator/components/manifest-view/json.js @@ -29,14 +29,10 @@ class JSONView extends HTMLElement { } connectedCallback() { - console.log("connected"); const jsonValue = this.getAttribute("json"); this.json = JSON.parse(decodeURIComponent(jsonValue)); - this.render(); - } - disconnectedCallback() { - console.log("disconnected"); + this.render(); } render() { diff --git a/manifest-generator/components/manifest-view/node.js b/manifest-generator/components/manifest-view/node.js index 8807dcc..ae4345b 100644 --- a/manifest-generator/components/manifest-view/node.js +++ b/manifest-generator/components/manifest-view/node.js @@ -35,16 +35,11 @@ class Node extends HTMLElement { } connectedCallback() { - console.log("connected"); this.key = this.getAttribute("key"); this.value = this.getAttribute("value"); this.render(); } - disconnectedCallback() { - console.log("disconnected"); - } - observedAttributes() { return ["key", "value"]; } diff --git a/manifest-generator/components/navigation-view.js b/manifest-generator/components/navigation-view.js new file mode 100644 index 0000000..022ebdb --- /dev/null +++ b/manifest-generator/components/navigation-view.js @@ -0,0 +1,128 @@ +const template = document.createElement("template"); +template.innerHTML = ` + + + +
+
+ +
+ +
+`; + +const attributes = { + currentId: { + name: "current-id", + required: true, + }, + pageSelector: { + name: "page-selector", + required: true, + }, +}; + +class NavigationView extends HTMLElement { + constructor() { + super(); + const shadow = this.attachShadow({ mode: "open" }); + shadow.append(template.content.cloneNode(true)); + this.prevButton = this.shadowRoot.querySelector("#prev"); + this.nextButton = this.shadowRoot.querySelector("#next"); + this.skipButton = this.shadowRoot.querySelector("#skip"); + + this.prevButton.addEventListener("click", () => { + this.shadowRoot.dispatchEvent( + new CustomEvent("prev", { + composed: true, + bubbles: true, + }) + ); + }); + + this.nextButton.addEventListener("click", () => { + this.shadowRoot.dispatchEvent( + new CustomEvent("next", { + composed: true, + bubbles: true, + }) + ); + }); + + this.skipButton.addEventListener("click", () => { + this.shadowRoot.dispatchEvent( + new CustomEvent("skip", { + composed: true, + bubbles: true, + }) + ); + }); + + this.shadowRoot.querySelector("slot").addEventListener("slotchange", () => { + this.togglePage(this.currentId); + }); + } + + static get observedAttributes() { + return Object.values(attributes).map((opt) => opt.name); + } + + // This method doesn't validate any form inputs, just html attributes. + validateAttributes(changedValue) { + Object.entries(attributes).forEach(([field, opts]) => { + if (changedValue !== undefined && opts.name !== changedValue) return; + const attribute = this.getAttribute(opts.name); + if (opts.required && !attribute) + throw new Error( + `Attribute ${opts.name} should be set in component ${this.tagName}` + ); + this[field] = attribute; + }); + } + + togglePage(id) { + const pages = this.querySelectorAll(this.pageSelector); + pages.forEach((page) => { + page.toggleAttribute("hidden", page.pageId !== id); + }); + } + + connectedCallback() { + this.validateAttributes(); + } + + attributeChangedCallback(attr, oldVal, newVal) { + this.validateAttributes(); + if (oldVal !== null && attr == attributes.currentId.name) { + this.togglePage(newVal); + } + } +} + +customElements.define("navigation-view", NavigationView); diff --git a/manifest-generator/components/page-view.js b/manifest-generator/components/page-view.js index fcd4bf7..db0dbd6 100644 --- a/manifest-generator/components/page-view.js +++ b/manifest-generator/components/page-view.js @@ -10,6 +10,7 @@ class PageView extends HTMLElement { const pageViewTemplate = document.createElement("template"); pageViewTemplate.innerHTML = ` +

${this.getAttribute("title")}

- My Default Text`; + My Default Text`; // Create a shadow root this.attachShadow({ mode: "open" }); @@ -25,10 +26,9 @@ class PageView extends HTMLElement { // Set the id field based on the id attribute this.#id = this.getAttribute("page-id"); - console.log("this page's ID is = " + this.#id); } - getId() { + get pageId() { return this.#id; } } diff --git a/manifest-generator/index.html b/manifest-generator/index.html index f3dd349..762d118 100644 --- a/manifest-generator/index.html +++ b/manifest-generator/index.html @@ -1,4 +1,4 @@ - + @@ -14,10 +14,8 @@ /> -

Manifest generator

- design reference + - From 86e2eca682af180361fbadee0e9945f0e5f5a9bd Mon Sep 17 00:00:00 2001 From: Stanley Hon Date: Tue, 12 Sep 2023 16:34:05 -0700 Subject: [PATCH 15/19] adding stylesheet imports (#14) Co-authored-by: Lia Hiscock Co-authored-by: Amanda Baker --- manifest-generator/components/color-picker.js | 5 +++++ manifest-generator/components/display-mode.js | 1 + manifest-generator/components/long-text-input.js | 12 +++++++++++- manifest-generator/components/page-view.js | 2 +- manifest-generator/components/simple-text-input.js | 11 +++++++++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/manifest-generator/components/color-picker.js b/manifest-generator/components/color-picker.js index 8d53287..0e5bc0c 100644 --- a/manifest-generator/components/color-picker.js +++ b/manifest-generator/components/color-picker.js @@ -35,6 +35,10 @@ class ColorPicker extends HTMLElement { flex-direction: column; }`; + const stylesheet = document.createElement("link"); + stylesheet.setAttribute("rel", "stylesheet"); + stylesheet.setAttribute("href", "styles/defaults.css"); + // Append the text and input elements to the table tableWrapper.append(inputLabel); tableWrapper.append(this.#inputElement); @@ -42,6 +46,7 @@ class ColorPicker extends HTMLElement { // Append the table and style to the shadow DOM shadow.append(tableWrapper); shadow.append(style); + shadow.append(stylesheet); } getUserInput() { diff --git a/manifest-generator/components/display-mode.js b/manifest-generator/components/display-mode.js index 9d16f38..e4c505e 100644 --- a/manifest-generator/components/display-mode.js +++ b/manifest-generator/components/display-mode.js @@ -7,6 +7,7 @@ const template = document.createElement("template"); template.innerHTML = ` +