diff --git a/web/css/dropdown.css b/web/css/dropdown.css new file mode 100644 index 00000000..4db8db92 --- /dev/null +++ b/web/css/dropdown.css @@ -0,0 +1,107 @@ +*{ + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +.container { + width: 100%; + min-height: 100vh; + display: flex; + justify-content: center; + align-items: flex-start; + background-color: var(--bg); +} + +.dropdown { + position: relative; + box-shadow: var(--shadowPreset-3); + border-radius: 1rem; + background: var(--bg); + /* top: 50px; */ + /* left: 45%; */ + margin-top: 10px; + margin-left: 10px; + width: 17rem; + height: 4rem; +} + +.dropdown::before { + content: ""; + position: absolute; + top: 15px; + right: 20px; + z-index: 1000; + width: 8px; + height: 8px; + border: 2px solid #333; + border-top: 2px solid #fff; + border-right: 2px solid #fff; + transform: rotate(-45deg); + transition: 0.2s; + pointer-events: none; +} + +.dropdown.active::before { + top: 22px; + transform: rotate(-225deg); +} + +.dropdown input { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + cursor: pointer; + background: var(--bg); + + + font-size: 1.2em; + border: none; + outline: none; + box-shadow: 0.3rem 0.3rem 0.6rem var(--shadow-1), -0.2rem -0.2rem 0.5rem var(--shadow-2); + padding: 1.2rem 2rem; + border-radius: 1rem; +} + +.dropdown .options { + font-size: 1.2em; + position: relative; + top: 70px; + width: 100%; + background: var(--bg); + overflow: hidden; + display: none; +} + +.dropdown.active .options { + z-index: 9999; + display: block; + + position: relative; + font-family: Arial; + margin-top: 0.5rem; + width: 100%; + height: auto; + + padding: 0.4rem 0.8rem; + border: 0.1rem solid transparent; + cursor: pointer; + border-radius: 1rem; + box-shadow: 0.3rem 0.3rem 0.6rem var(--shadow-1), -0.2rem -0.2rem 0.5rem var(--shadow-2); +} + +.dropdown .options div { + padding: 0.4rem 0.6rem; + border: 0.1rem solid transparent; + cursor: pointer; + border-radius: 0.1rem; + color: var(--textColor-1); +} + +.dropdown .options div:hover { + background: var(--bg-bright); + color: var(--textColor-hover); +} diff --git a/web/css/guide.css b/web/css/guide.css index 5f64fb70..b25343ba 100644 --- a/web/css/guide.css +++ b/web/css/guide.css @@ -14,10 +14,7 @@ body { overflow: hidden; } -.ww, -.us, -.ca, -.uk { +li { margin-bottom: 1rem; justify-self: center; width: auto; diff --git a/web/css/style.css b/web/css/style.css index 909f5972..36299d30 100644 --- a/web/css/style.css +++ b/web/css/style.css @@ -35,10 +35,6 @@ html { height: unset !important; } -.gender-select, -.ethnicity-select, -.religion-select, -.civilstatus-select, .dropdown-select { position: relative; font-family: Arial; @@ -46,19 +42,19 @@ html { width: 17rem; } -.gender-select select, -.ethnicity-select select, -.religion-select select, -.civilstatus-select select, .dropdown-select select { display: none; /*hide original SELECT element:*/ } +.country-select { + margin-top: 0 !important; +} + .select-selected { margin-bottom: 1rem; justify-self: center; - width: 20rem; + width: 17rem; height: 3rem; border-radius: 1rem; box-shadow: var(--shadowPreset-3); @@ -72,7 +68,7 @@ html { position: absolute; content: ""; top: 14px; - right: -3.5rem; + right: 0.5rem; width: 0; height: 0; border: 6px solid transparent; diff --git a/web/dropdowntest.html b/web/dropdowntest.html new file mode 100644 index 00000000..b2165b7b --- /dev/null +++ b/web/dropdowntest.html @@ -0,0 +1,25 @@ + + + + + + Custom Dropdown + + + + + + + + + + + + + + + + + + diff --git a/web/guide.html b/web/guide.html index 2f650ac9..95bb6725 100644 --- a/web/guide.html +++ b/web/guide.html @@ -19,8 +19,9 @@ - - + + + + + +
-
- -
+ + + + + + + + + +
diff --git a/web/ts/dropdown.ts b/web/ts/dropdown.ts new file mode 100644 index 00000000..1e9c0155 --- /dev/null +++ b/web/ts/dropdown.ts @@ -0,0 +1,107 @@ +const dropdowns: Set = new Set([]); + + +class CustomDropdown extends HTMLElement { + constructor() { + super(); + const id = this.getAttribute("dropdown-id") || "" + if (id == "") { + console.error("error no dropdown name") + return + } else if (dropdowns.has(id)) { + console.error("ID" + id + "already exsists"); + return + } + dropdowns.add(id); + + const options = this.getAttribute("options") || ""; + if (options == "") { + console.error("error empty dropdown options") + dropdowns.delete(id) + return + } + + const placeholder = this.getAttribute("placeholder") || "Select Item"; + this.attachShadow({ mode: "open" }); + + this.shadowRoot!.innerHTML = ` + + + + + `; + + const dropdown = this.shadowRoot!.querySelector(".dropdown") as HTMLElement; + if (dropdown) { + dropdown.onclick = function() { + const allDropdowns = document.querySelectorAll("custom-dropdown"); + console.log(allDropdowns); + + allDropdowns.forEach((currentDropdown) => { + const shadowRoot = currentDropdown.shadowRoot; + if (shadowRoot) { + const dropdownElement = shadowRoot.querySelector(".dropdown"); + if (dropdownElement && dropdownElement != dropdown) { // don't remove on teh dropdown the user clicked on + dropdownElement.classList.remove("active"); + } + } + }); + dropdown.classList.toggle("active"); + }; + } + + const internalDivs = this.shadowRoot!.querySelectorAll(".dropdown-option"); + internalDivs.forEach((internalDiv) => { + internalDiv.addEventListener("click", () => { + const optionName = internalDiv.textContent || ""; + const textBox = this.shadowRoot!.querySelector(".text-box") as HTMLInputElement; + if (textBox) { + textBox.value = optionName; + } + this.setAttribute("value", optionName); + this.dispatchEvent(new Event("change")); + }); + }); + } +} + +customElements.define("custom-dropdown", CustomDropdown); + +function divTemplate(words: string): string { + const wordArray = words.split(",").map(word => word.trim()); + + let output = ""; + + wordArray.forEach(word => { + output += ``; + + }); + + return output; +} + +function getDropdown(id: string): Element | null { + if (!dropdowns.has(id)) { + console.error("Error: no dropdown with this name: " + id) + return null + } + return document.querySelector(`custom-dropdown[dropdown-id="${id}"]`); +} + +function getValue(id: string): string { + if (!dropdowns.has(id)) { + console.error("Error: no dropdown with this name: " + id) + return "" + } + const customOptionElement = getDropdown(id); + + return customOptionElement!.getAttribute("value") || "" +} + + +export { getValue, getDropdown }; diff --git a/web/ts/guide.ts b/web/ts/guide.ts index 7f592b33..5a6150e5 100644 --- a/web/ts/guide.ts +++ b/web/ts/guide.ts @@ -1,5 +1,8 @@ const channel = new BroadcastChannel("seekr-channel"); + +import { getValue,getDropdown } from "./dropdown.js"; + // Listen for messages on the broadcast channel channel.addEventListener('message', (event) => { if (event.data.type === "theme") { @@ -12,8 +15,7 @@ channel.addEventListener('message', (event) => { // The actual stuff -const countryDropdown = document.getElementById("country-select"); -const selectedSelect = document.querySelector(".country-select select"); +const countryDropdown = getDropdown("country") as HTMLInputElement; const checkboxName = document.getElementById("checkbox_01") as HTMLInputElement; const checkboxNameIcon = document.getElementById("checkbox_01_icon") as HTMLElement; @@ -73,7 +75,7 @@ function checkChecboxValue(checkboxType: string): boolean { function checkCountry(): "all" | "ww" | "us" | "ca" | "uk" | "se" | "de" | undefined { if (document) { - const selectedCountry = document.querySelector(".select-selected"); + const selectedCountry = getValue("country"); if (selectedCountry) { const countries: { [key: string]: "all" | "ww" | "us" | "ca" | "uk" | "se" | "de" } = {}; @@ -88,7 +90,7 @@ function checkCountry(): "all" | "ww" | "us" | "ca" | "uk" | "se" | "de" | undef countries["Sweden"] = "se"; countries["Germany"] = "de"; - return countries[selectedCountry.innerHTML]; // Error here + return countries[selectedCountry]; // Error here } } } @@ -205,30 +207,10 @@ function listHandler() { } } -// Function to handle changes in .select-selected innerHTML function preListHandler() { - const selectedCountry = document.querySelector(".select-selected"); - - if (selectedCountry && selectedCountry.innerHTML !== "") { listHandler(); - } -} - -// Create a MutationObserver instance -const observer = new MutationObserver(preListHandler); - -// Select the parent node containing the .select-selected element -const parentContainer = document.querySelector(".country-select"); - -// Define the configuration for the observer -const config = { childList: true, subtree: true }; - -// Start observing the parent node -if (parentContainer) { - observer.observe(parentContainer, config); } -// Rest of your code for checkbox event listeners checkboxName.addEventListener('change', preListHandler); checkboxAddress.addEventListener('change', preListHandler); checkboxPhone.addEventListener('change', preListHandler); @@ -237,6 +219,6 @@ checkboxBusiness.addEventListener('change', preListHandler); checkboxIP.addEventListener('change', preListHandler); checkboxUsername.addEventListener('change', preListHandler); checkboxDomain.addEventListener('change', preListHandler); +countryDropdown.addEventListener('change', preListHandler); - -export {}; \ No newline at end of file +export { listHandler }; diff --git a/web/ts/templates.ts b/web/ts/templates.ts index af72ca6c..2a3284ac 100644 --- a/web/ts/templates.ts +++ b/web/ts/templates.ts @@ -1,3 +1,5 @@ +import { listHandler } from "./guide.js"; + class CustomDropdown extends HTMLElement { constructor() { super(); @@ -21,7 +23,10 @@ class CustomDropdown extends HTMLElement { // Get dropdown title attribute and set initial values const dropdownTitleAttr = this.getAttribute("title")!; const dropdownTitle = dropdownTitleAttr.charAt(0).toUpperCase() + dropdownTitleAttr.slice(1) + ":"; - dropdownTitleElement.textContent = dropdownTitle; + + if (!this.hasAttribute("no-tag")) { + dropdownTitleElement.textContent = dropdownTitle; + } // Set initial option for select element const selElmntTag = selElmnt.children[0] as HTMLOptionElement; @@ -43,6 +48,10 @@ class CustomDropdown extends HTMLElement { const labelText = selElmnt.options[0].innerHTML; selectSelectedDiv.innerHTML = labelText; + if (this.getAttribute("title") == "country") { + node.classList.add("country-select"); + } + const b = document.createElement("div"); b.className = "select-items select-hide"; @@ -86,6 +95,14 @@ class CustomDropdown extends HTMLElement { s.classList.toggle("select-hide"); this.classList.toggle("select-arrow-active"); }); + + const selectSelected = this.shadowRoot!.querySelector("div > div > div > div.select-selected")!; + + selectSelected.addEventListener("DOMSubtreeModified", function () { + if (selectSelected && selectSelected.innerHTML != "") { + listHandler(); + } + }); } } @@ -112,4 +129,4 @@ function closeAllSelect(elmnt: HTMLElement) { selectItemsElements[selectItemsElementsIndex].classList.add("select-hide"); } } -} \ No newline at end of file +}