diff --git a/public/static/cookies.js b/public/static/cookies.js new file mode 100644 index 0000000..722cae2 --- /dev/null +++ b/public/static/cookies.js @@ -0,0 +1,14 @@ +// After the settings page finishes loading +document.addEventListener( + 'DOMContentLoaded', + () => { + let cookie = decodeURIComponent(document.cookie) + if (cookie !== '') { + document.querySelector('.cookies input').value = cookie + } else { + document.querySelector('.cookies input').value = + 'No cookies has been saved on your system' + } + }, + false +) diff --git a/public/static/settings.js b/public/static/settings.js index 87c4f58..ca25f6e 100644 --- a/public/static/settings.js +++ b/public/static/settings.js @@ -1,186 +1,73 @@ -/* - UI: Method for selecting all search engines - - This function is called when user click on - `select all` and `deselect all` toogle element. - - - If select all is pressed toggle all options and insert all value - joined with comma to input which is saved in cookie. - then changes text to `deselect all`. - eg value: 'ddg,searx,' - - - If deselect all is pressed uncheck all options and insert empty - value to input which is saved in cookie. -*/ -function selectAllHandler(elem) { - let span = elem.parentElement.querySelector("span"); - let mainInput = document.getElementsByName("searchEng")[0]; - let prevStateSelectAll = span.innerText == "Select all" ? true : false; - document.querySelectorAll(".searchEng-elem").forEach((engine) => { - if (prevStateSelectAll) { - engine.querySelector('input[type="checkbox"]').checked = true; - } else { - engine.querySelector('input[type="checkbox"]').checked = false; - } - }); - if (prevStateSelectAll) { - let getValues = () => { - let value = ""; - document - .querySelectorAll('[data-isCheckbox]:not([data-value="all"])') - .forEach((elem) => { - value += elem.getAttribute("data-value") + ","; - }); - return value; - }; - mainInput.value = getValues(); - } else { - mainInput.value = ""; - } - span.innerText = prevStateSelectAll ? "Deselect all" : "Select all"; +function toggleAllSelection() { + document + .querySelectorAll('.engine') + .forEach( + (engine_checkbox) => + (engine_checkbox.checked = + document.querySelector('.select_all').checked) + ) } -/* - UI: Filter settings as per category - - There are two elements one is `category` and `detail`. - Category contains `data-id` when a user click it - we need to show detail element having - `data-detailId` whose value is same as `data-id`. - - When a user clicks on a category on sidebar, view - settings containing `data-id` of sidebar element's `data-detailId` - and hide other settings - - - if `all` is clicked then show all settings. -*/ -document.querySelectorAll(".settings-sidebar .set-name").forEach((filter) => { - let target = filter.getAttribute("data-detailId"); - filter.addEventListener("click", () => { - try { - document.querySelector(".set-name.active").classList.remove("active"); - } catch (e) {} - filter.classList.add("active"); - if (target == "all") { - document.querySelectorAll(".set-item").forEach((elem) => { - elem.style.display = "block"; - }); - return; - } - document - .querySelectorAll('.set-item[data-id="' + target + '"]') - .forEach((elem) => { - elem.style.display = "block"; - }); - document - .querySelectorAll('.set-item:not([data-id="' + target + '"])') - .forEach((elem) => { - elem.style.display = "none"; - }); - }); -}); - - -/* - This function is called when a user click on submit button - it validates all user inputs and saves to a cookie. - - - if input having `required` attr and is empty it generates a - error text and insert above the setting element - - - else store setttings to a cookie. -*/ -function submitSettings() { - let form = document.settings; - let stopProceeding = false; - document.querySelectorAll(".errTxt").forEach((e) => e.remove()); - for (let i = 0; i < form.elements.length; i++) { - let input = form.elements[i]; - if (input.value == "" && input.hasAttribute("required")) { - stopProceeding = true; - let elem = input.parentElement.querySelector("[takeInput]"); - let errTxt = document.createElement("p"); - errTxt.classList.add("errTxt"); - errTxt.innerText = "This setting can't be empty!!"; - elem.classList.add("invalid"); - elem.parentElement.insertBefore(errTxt, elem); - let sidebarElement = input.closest(".set-item").getAttribute("data-id"); - document - .querySelector( - `.settings-sidebar .set-name[data-detailId="${sidebarElement}` - ) - .click(); - stopProceeding = true; - } - } - if (!stopProceeding) { - var expiration_date = new Date(); - expiration_date.setFullYear(expiration_date.getFullYear() + 1); - let formData = new FormData(document.querySelector("form")); - for (var [key, value] of formData.entries()) { - document.cookie = `${key}=${value}; expires=${expiration_date.toUTCString()}`; - } - } else { - return false; - } - // On settings saved successfully - alert("Settings saved succssfully!"); - window.location.reload(); +function setActiveTab(current_tab) { + document + .querySelectorAll('.tab') + .forEach((tab) => tab.classList.remove('active')) + document + .querySelectorAll('.btn') + .forEach((tab) => tab.classList.remove('active')) + current_tab.classList.add('active') + document + .querySelector(`.${current_tab.innerText.toLowerCase().replace(' ', '_')}`) + .classList.add('active') } - -/* - This function will be called on page ready. - it iterates over saved cookies and if cookie name is - in the list of valid cookies then load it. - - - if cookie is searchEng(type=toggle/checkbox) we deselect - all checkboxes and select those which are stored in cookie. - - - if cookie is of type `select` we deselect default selected - option and then select option which is stored in cookie. -*/ -function loadUserSettings() { - let inputs = ["searchEng", "theme", "color-sch"]; - var keyValuePairs = document.cookie.split(";"); - for (var i = 0; i < keyValuePairs.length; i++) { - var name = keyValuePairs[i].substring(0, keyValuePairs[i].indexOf("=")); - var value = keyValuePairs[i].substring(keyValuePairs[i].indexOf("=") + 1); - name = name.trim(); - if (!inputs.includes(name)) { - continue; +function setClientSettings() { + let cookie_dictionary = new Object() + document.querySelectorAll('select').forEach((select_tag) => { + if (select_tag.name === 'themes') { + cookie_dictionary['theme'] = select_tag.value + } else if (select_tag.name === 'colorschemes') { + cookie_dictionary['colorscheme'] = select_tag.value } - let input = document.getElementsByName(name)[0]; - input.value = value; - if (name == "searchEng") { - // Unload all checked engines - document - .querySelectorAll(".searchEng-elem input[type=checkbox]") - .forEach((e) => { - e.checked = false; - }); - value = value.replace(" ", ""); - value.split(",").forEach((val) => { - if (!val) { - return; + }) + let engines = [] + document.querySelectorAll('.engine').forEach((engine_checkbox) => { + if (engine_checkbox.checked === true) { + engines.push(engine_checkbox.parentNode.parentNode.innerText.trim()) + } + }) + cookie_dictionary['engines'] = engines + let expiration_date = new Date() + expiration_date.setFullYear(expiration_date.getFullYear() + 1) + document.cookie = `appCookie=${JSON.stringify( + cookie_dictionary + )}; expires=${expiration_date.toUTCString()}` + + document.querySelector('.message').innerText = + '✅ The settings have been saved sucessfully!!' + + setTimeout(() => { + document.querySelector('.message').innerText = '' + }, 10000) +} + +function getClientSettings() { + let cookie = decodeURIComponent(document.cookie) + + if (cookie !== '') { + let cookie_value = decodeURIComponent(document.cookie) + .split(';') + .map((item) => item.split('=')) + .reduce((acc, [_, v]) => (acc = JSON.parse(v)) && acc, {}) + + let links = Array.from(document.querySelectorAll('link')).forEach( + (item) => { + if (item.href.includes('static/themes')) { + item.href = `static/themes/${cookie_value['theme']}.css` + } else if (item.href.includes('static/colorschemes')) { + item.href = `static/colorschemes/${cookie_value['colorscheme']}.css` } - document - .querySelector(`[data-isCheckbox][data-value="${val}"]`) - .parentElement.querySelector("input").checked = true; - }); - } else { - // Unload all selected options - document - .querySelector( - `[data-input="${name}"] .options span[data-value="${value}"]` - ) - .removeAttribute("selected"); - singleSelectClickHandler( - document.querySelector(`.options span[data-value="${value}"]`) - ); - } + } + ) } } - -// Code where settings are loaded from cookie. -loadUserSettings(); diff --git a/public/static/themes/simple.css b/public/static/themes/simple.css index dfcda52..3d77878 100644 --- a/public/static/themes/simple.css +++ b/public/static/themes/simple.css @@ -263,38 +263,38 @@ footer { /* Styles for the about page */ -.about-container article{ +.about-container article { font-size: 1.5rem; - color:var(--fg); + color: var(--fg); padding-bottom: 10px; } -.about-container article h1{ +.about-container article h1 { color: var(--2); font-size: 2.8rem; } -.about-container article div{ +.about-container article div { padding-bottom: 15px; } -.about-container a{ - color:var(--3); +.about-container a { + color: var(--3); } -.about-container article h2{ +.about-container article h2 { color: var(--3); font-size: 1.8rem; padding-bottom: 10px; } -.about-container p{ - color:var(--fg); - font-size: 1.6rem; +.about-container p { + color: var(--fg); + font-size: 1.6rem; padding-bottom: 10px; } -.about-container h3{ +.about-container h3 { font-size: 1.5rem; } @@ -302,12 +302,10 @@ footer { width: 80%; } -/* css for settings page t */ -.settings { - margin: 2rem; - width: 80%; - height: 100%; - color: var(--fg); +.settings_container { + display: flex; + justify-content: space-around; + width: 80dvw; } .settings h1 { @@ -315,268 +313,187 @@ footer { font-size: 2.5rem; } - .settings hr { border-color: var(--3); - margin: .3rem 0 1rem 0; + margin: 0.3rem 0 1rem 0; } -.settings-view { - display: flex; - flex: 1 0 auto; - margin: 1.5rem 0; -} - -.settings-sidebar { - width: 25%; - height: 100%; -} - -.settings-sidebar .set-name { +.settings_container .sidebar { + width: 30%; cursor: pointer; font-size: 2rem; - display: block; - margin-right: .5rem; - margin-left: -.7rem; - padding: .7rem; + display: flex; + flex-direction: column; + margin-right: 0.5rem; + margin-left: -0.7rem; + padding: 0.7rem; border-radius: 5px; font-weight: bold; - margin-bottom: .5rem; + margin-bottom: 0.5rem; + color: var(--fg); + text-transform: capitalize; + gap: 1.5rem; } -.settings-sidebar .set-name:hover, .settings-sidebar .set-name.active { - background-color: rgba(255, 255, 255, 0.15); - +.settings_container .sidebar .btn { + padding: 0.5rem; + border-radius: 0.5rem; } -.settings-detail { +.settings_container .sidebar .btn.active { + background-color: var(--2); +} + +.settings_container .main_container { + width: 70%; border-left: 1.5px solid var(--3); padding-left: 3rem; } -.settings-detail .set-item { - margin: 2rem 0; - margin-top: 0; -} - -.settings-detail .set-name { - font-size: 2rem; - font-weight: bold; - color: var(--4) -} - -.settings-detail .set-desc { - font-size: 1.5rem; - margin-bottom: .5rem; -} - -/* css for custom select */ -.custom-select, .options { - font-size: 1.5rem; - background-color: var(--bg); - width: 250px; - padding: 1rem 1.7rem; - border-radius: 7px; -} - -.custom-select { - position: relative; - vertical-align: middle; - margin: .7rem 0; -} - -.custom-select.invalid { - border: 1px solid red; -} - -.custom-select svg { - float: right; -} - -.options { +.settings_container .tab { display: none; - position: absolute; - left: 0; - margin-top: 1.3rem; - width: 100%; - padding: .7rem 1rem; - cursor: pointer; - z-index: 3; - max-height: 15rem; - overflow-y: auto; } -.options span { - display: block; - padding: 1rem; - width: 100%; - border-radius: 5px; - vertical-align: middle; +.settings_container .tab.active { + display: flex; + flex-direction: column; + justify-content: space-around; } -.options span:hover { - background-color: var(--1); -} - -.selected-multiple-option { - padding: .8rem; - border-radius: 5px; - background-color: var(--bg); - margin: .5rem .3rem; -} - -.selected-multiple-option svg { - width: 1.3rem; - height: 1.3rem; - vertical-align: middle; - margin-bottom: .5rem; - cursor: pointer; -} - -.select-multiple-show { - margin: 1rem 0; - font-size: 1.5rem; -} - -.underlined-text { - font-size: 1.7rem; - cursor: pointer; - margin-bottom: .5rem; - display: block; -} - -.settings .submit-btn { +.settings_container button { + margin-top: 1rem; padding: 1rem 2rem; font-size: 1.5rem; background: var(--3); color: var(--bg); - border-radius: .5rem; + border-radius: 0.5rem; border: 2px solid transparent; font-weight: bold; - transition: all .1s ease-out; + transition: all 0.1s ease-out; cursor: pointer; box-shadow: 5px 5px; + outline: none; } -.settings .submit-btn:active { - outline: none; +.settings_container button:active { box-shadow: none; translate: 5px 5px; } -/* Css for error text */ - -.errTxt { - color: white; - background: red; - padding: .5rem; - border-radius: 5px; - font-size: 1.3rem; - width: max-content; -} - -/* Css for toggle element */ - -label, -label::before, -label::after { - transition: 200ms all ease-in-out 50ms; - box-sizing: border-box; - backface-visibility: hidden; -} - -input[type="checkbox"] { - display: none; -} - -/*Button is :CHECKED*/ - -input[type="checkbox"]:checked ~ div[data-isCheckbox] { - background: rgba(73,168,68,1); - box-shadow: 0 0 2px rgba(73,168,68,1); -} - -input[type="checkbox"]:checked ~ div[data-isCheckbox] label { - left: 25px; - transform: rotate(360deg); -} - - -/*shared*/ - -div[data-isCheckbox], -label { - border-radius: 50px; -} - - -/*'un':checked state*/ - -div[data-isCheckbox] { - height: 25px; - width: 50px; - background: rgba(43, 43, 43, 1); - position: relative; - box-shadow: 0 0 2px rgba(43,43,43,1); - -} - -label { - height: 20px; - width: 20px; - background: rgba(255, 255, 255, 1); - position: absolute; - top: 3px; - left: 3px; - cursor: pointer; -} - -label::before { - content: ''; - height: 15px; - width: 3px; - position: absolute; - top: calc(50% - 8px); - left: calc(50% - 1.5px); - transform: rotate(45deg); -} - -label::after { - content: ''; - height: 3px; - width: 15px; - position: absolute; - top: calc(50% - 2.5px); - left: calc(50% - 8px); - transform: rotate(45deg); -} - -label::before, -label::after{ - background: rgba(43,43,43,1); - border-radius: 5px; -} - -/* pesduo class on toggle */ - -input[type="checkbox"]:checked ~ div label::before{ - height: 15px; - top: calc(55% - 8px); - left: calc(60% - 2px); - background: rgba(73,168,68,1); -} - -input[type="checkbox"]:checked ~ div label::after{ - width: 7px; - top: calc(95% - 7px); - left: calc(22.5% - 2px); - background: rgba(73,168,68,1); -} - -.searchEng-elem { - display: flex; - gap: 3rem; - align-items: center; +.settings_container .main_container .message { font-size: 1.5rem; - margin: 1rem 0; + color: var(--fg); +} + +.settings_container .tab h3 { + font-size: 2rem; + font-weight: bold; + color: var(--4); + margin-top: 1.5rem; + text-transform: capitalize; +} + +.settings_container .tab .description { + font-size: 1.5rem; + margin-bottom: 0.5rem; + color: var(--fg); +} + +.settings_container .user_interface select { + margin: 0.7rem 0; + width: 20rem; + background-color: var(--bg); + color: var(--fg); + padding: 1rem 2rem; + border-radius: 0.5rem; + outline: none; + border: none; + text-transform: capitalize; +} + +.settings_container .user_interface option:hover { + background-color: var(--1); +} + +.settings_container .engines .engine_selection { + display: flex; + flex-direction: column; + justify-content: center; + gap: 1rem; + padding: 1rem 0; +} + +.settings_container .engines .toggle_btn { + color: var(--fg); + font-size: 1.5rem; + display: flex; + gap: 0.5rem; + align-items: center; +} + +.settings_container .engines hr { + margin: 0; +} + +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 6rem; + height: 3.4rem; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--bg); + -webkit-transition: 0.4s; + transition: 0.4s; +} + +.slider:before { + position: absolute; + content: ''; + height: 2.6rem; + width: 2.6rem; + left: 0.4rem; + bottom: 0.4rem; + background-color: var(--fg); + -webkit-transition: 0.4s; + transition: 0.4s; +} + +input:checked + .slider { + background-color: var(--3); +} + +input:focus + .slider { + box-shadow: 0 0 1px var(--3); +} + +input:checked + .slider:before { + -webkit-transform: translateX(2.6rem); + -ms-transform: translateX(2.6rem); + transform: translateX(2.6rem); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 3.4rem; +} + +.slider.round:before { + border-radius: 50%; } diff --git a/public/static/ui_plugins.js b/public/static/ui_plugins.js deleted file mode 100644 index 53dddb5..0000000 --- a/public/static/ui_plugins.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - Select plugin - Note: Only for single select option - Usage example: - ``` - -
- Svg Icon here -
- Simple -
-
- ``` -*/ - -let svg_tick = ` - - - - - `; - -function toggleSelectOptions(elem, state) { - elem.classList.remove("invalid"); - try { elem.parentElement.querySelector('.errTxt').remove();} catch (error) {} - let options = elem.querySelector('.options'); - const pos = elem.getBoundingClientRect(); - const windowWidth = document.getElementsByTagName("body")[0].clientHeight; - if(pos.y + 250 > windowWidth) { - options.style.bottom = '40px'; - } else { options.style.bottom = null } - options.style.display = state != 'close' ? getComputedStyle(options).display == 'none' ? 'block': 'none' : 'none'; -} - -let selectElements = document.querySelectorAll('.custom-select').forEach(element => { - let value = element.getAttribute('data-default') - element.childNodes[0].nodeValue = value; - element.querySelector(`.options span[data-value="${value.toLowerCase()}"]`). - innerHTML = `${value} ${svg_tick}`; - element.addEventListener('click', (e) => {if (e.target === element) toggleSelectOptions(element)}); - element.addEventListener('focusout', (e) => {if (e.target === element) toggleSelectOptions(element, 'close')}); -}); - -function singleSelectClickHandler(elem) { - let selectDiv = elem.closest('.custom-select'); - let selectedOption = selectDiv.querySelector('span[selected]'); - let input = document.querySelector(`[name="${selectDiv.getAttribute('data-input')}"]`); - if (!elem.hasAttribute('selected')) { - if (selectedOption != null) { - selectedOption.removeAttribute('selected'); - selectedOption.querySelector('svg').remove(); - } - elem.setAttribute('selected', ''); - elem.innerHTML = `${elem.innerText} ${svg_tick}` - // Code where value is inserted to input - input.value = elem.getAttribute('data-value') ? elem.getAttribute('data-value') : ''; - selectDiv.childNodes[0].nodeValue = elem.innerText; - } else { - elem.removeAttribute('selected'); - elem.querySelector('svg').remove(); - selectDiv.childNodes[0].nodeValue = selectDiv.getAttribute('data-defaultIfNone'); - - input.value = ""; - } - selectDiv.blur(); -} - -let singleSelectOptions = document.querySelectorAll('.custom-select:not([data-multiple="1"])>.options span'); -for (let i = 0; i < singleSelectOptions.length; i++) { - singleSelectOptions[i].addEventListener('click', () => {singleSelectClickHandler(singleSelectOptions[i])}); - singleSelectOptions[i].setAttribute('id', 'option-'+i.toString()); -} - - -/* - Toggle switch plugin - Usage example: - ``` - -
-
- -
- -
- Duck duck go -
-
- -
- -
- Searx -
-
- ``` -*/ - -document.querySelectorAll('[data-isCheckbox]:not([data-value="all"]) label').forEach(checkBoxLabel => { - checkBoxLabel.addEventListener('click', () => { - let checkBox = checkBoxLabel.parentElement; - let helperInput = checkBox.parentElement.querySelector('input[type="checkbox"]'); - let mainInput = document.getElementsByName(checkBox.getAttribute('data-input'))[0]; - if (helperInput.checked == true) { - mainInput.value = mainInput.value.replace(checkBox.getAttribute('data-value') + ',', ''); - } else { - mainInput.value += checkBox.getAttribute('data-value') + ','; - } - }); -}) diff --git a/public/templates/cookies_tab.html b/public/templates/cookies_tab.html new file mode 100644 index 0000000..b33ea4d --- /dev/null +++ b/public/templates/cookies_tab.html @@ -0,0 +1,5 @@ +
+

Cookies

+

+ +
diff --git a/public/templates/engines_tab.html b/public/templates/engines_tab.html new file mode 100644 index 0000000..9bb5e1c --- /dev/null +++ b/public/templates/engines_tab.html @@ -0,0 +1,31 @@ +
+

select search engines

+

+ Select the search engines from the list of engines that you want results + from +

+
+
+ + Select All +
+
+
+ + Duckduckgo +
+
+ + Searx +
+
+
diff --git a/public/templates/footer.html b/public/templates/footer.html index db43e6d..24d0d2c 100644 --- a/public/templates/footer.html +++ b/public/templates/footer.html @@ -10,6 +10,7 @@ + diff --git a/public/templates/general_tab.html b/public/templates/general_tab.html new file mode 100644 index 0000000..b83935a --- /dev/null +++ b/public/templates/general_tab.html @@ -0,0 +1,4 @@ +
+

General

+

Coming soon!!

+
diff --git a/public/templates/header.html b/public/templates/header.html index 7e9ac8c..ce12b51 100644 --- a/public/templates/header.html +++ b/public/templates/header.html @@ -1,29 +1,14 @@ - + + Websurfx - - - + + + - +
{{>navbar}}
- diff --git a/public/templates/navbar.html b/public/templates/navbar.html index 87d6550..c369739 100644 --- a/public/templates/navbar.html +++ b/public/templates/navbar.html @@ -1,7 +1,6 @@ diff --git a/public/templates/settings.html b/public/templates/settings.html index 679c036..3c97213 100644 --- a/public/templates/settings.html +++ b/public/templates/settings.html @@ -1,107 +1,22 @@ {{>header this}} -
-

Settings

-
-
-
- All - Search Engine - Theme -
-
-
- -
-

Select search engines

-

Select the search engines from the list of engines that you want results from

- - -
-
- -
- -
- Select all -
-
-
- -
- -
- Duck duck go -
-
- -
- -
- Searx -
-
- -
- - - -
-

Select theme

-

Select the theme from the available themes to be used in user interface

- - -
- - - - -
- simple -
-
- -
- - - -
-

Select Color Scheme

-

Select the color scheme for your theme to be used in user interface

- - -
- - - - -
- catppuccin-mocha - dracula - monokai - nord - oceanic-next - solarized-dark - solarized-light - tomorrow-night -
-
- -
- - - -
- -
- -
-
-
+
+

Settings

+
+
+ +
+ {{> general_tab}} {{> user_interface_tab}} {{> engines_tab}} {{> + cookies_tab}} +

+ +
+
- + {{>footer}} diff --git a/public/templates/user_interface_tab.html b/public/templates/user_interface_tab.html new file mode 100644 index 0000000..51b3237 --- /dev/null +++ b/public/templates/user_interface_tab.html @@ -0,0 +1,27 @@ +
+

select theme

+

+ Select the theme from the available themes to be used in user interface +

+ +

select color scheme

+

+ Select the color scheme for your theme to be used in user interface +

+ +