diff options
author | lolcat <will@lolcat.ca> | 2025-08-11 01:55:15 +0000 |
---|---|---|
committer | lolcat <will@lolcat.ca> | 2025-08-11 01:55:15 +0000 |
commit | cdf958d29333d448f4521f4d2faa2592b58e9b27 (patch) | |
tree | 528f2a0ffa789a6f4279d9f54a4a2aaf391f390f /static | |
download | shittyweb-search-cdf958d29333d448f4521f4d2faa2592b58e9b27.tar.gz shittyweb-search-cdf958d29333d448f4521f4d2faa2592b58e9b27.tar.bz2 shittyweb-search-cdf958d29333d448f4521f4d2faa2592b58e9b27.zip |
fix wikipedia crashgrafted
Diffstat (limited to 'static')
41 files changed, 3501 insertions, 0 deletions
diff --git a/static/404.png b/static/404.png Binary files differnew file mode 100644 index 0000000..e8588cf --- /dev/null +++ b/static/404.png diff --git a/static/client.js b/static/client.js new file mode 100644 index 0000000..5935f92 --- /dev/null +++ b/static/client.js @@ -0,0 +1,985 @@ + +/* + Global functions +*/ +function htmlspecialchars(str){ + + var map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + } + + return str.replace(/[&<>"']/g, function(m){return map[m];}); +} + +function htmlspecialchars_decode(str){ + + var map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + } + + return str.replace(/&|<|>|"|'/g, function(m){return map[m];}); +} + +function is_click_within(elem, classname, is_id = false){ + + while(true){ + + if(elem === null){ + + return false; + } + + if( + ( + is_id === false && + elem.className == classname + ) || + ( + is_id === true && + elem.id == classname + ) + ){ + + return elem; + } + + elem = elem.parentElement; + } +} + + + +/* + Prevent GET parameter pollution +*/ +var form = document.getElementsByTagName("form"); + +if( + form.length !== 0 && + window.location.pathname != "/" && + window.location.pathname != "/settings.php" && + window.location.pathname != "/settings" +){ + form = form[0]; + + var scraper_dropdown = document.getElementsByName("scraper")[0]; + + scraper_dropdown.addEventListener("change", function(choice){ + + submit(form); + }); + + form.addEventListener("submit", function(e){ + + e.preventDefault(); + submit(e.srcElement); + }); +} + +function submit(e){ + + var GET = ""; + var first = true; + + if((s = document.getElementsByName("s")).length !== 0){ + + GET += "?s=" + encodeURIComponent(s[0].value).replaceAll("%20", "+"); + first = false; + } + + Array.from( + e.getElementsByTagName("select") + ).concat( + Array.from( + e.getElementsByTagName("input") + ) + ).forEach(function(el){ + + var firstelem = el.getElementsByTagName("option"); + + if( + ( + ( + firstelem.length === 0 || + firstelem[0].value != el.value + ) && + el.name != "" && + el.value != "" && + el.name != "s" + ) || + el.name == "scraper" || + el.name == "nsfw" + ){ + + if(first){ + + GET += "?"; + first = false; + }else{ + + GET += "&"; + } + + GET += encodeURIComponent(el.name).replaceAll("%20", "+") + "=" + encodeURIComponent(el.value).replaceAll("%20", "+"); + } + }); + + window.location.href = GET; +} + + + +/* + Hide show more button when it's not needed on answers +*/ +var answer_div = document.getElementsByClassName("answer"); + +if(answer_div.length !== 0){ + answer_div = Array.from(answer_div); + var spoiler_button_div = Array.from(document.getElementsByClassName("spoiler-button")); + + // execute on pageload + hide_show_more(); + + window.addEventListener("resize", hide_show_more); + + function hide_show_more(){ + + var height = window.innerWidth >= 1000 ? 600 : 200; + + for(i=0; i<answer_div.length; i++){ + + if(answer_div[i].scrollHeight < height){ + + spoiler_button_div[i].style.display = "none"; + + document.getElementById(spoiler_button_div[i].htmlFor).checked = true; + }else{ + + spoiler_button_div[i].style.display = "block"; + } + } + } +} + +switch(document.location.pathname){ + + case "/web": + case "/web.php": + var image_class = "image"; + break; + + case "/images": + case "/images.php": + var image_class = "thumb"; + break; + + default: + var image_class = null; +} + +if(image_class !== null){ + + /* + Add popup to document + */ + var popup_bg = document.createElement("div"); + popup_bg.id = "popup-bg"; + document.body.appendChild(popup_bg); + + // enable/disable pointer events + if(!document.cookie.includes("bg_noclick=yes")){ + + popup_bg.style.pointerEvents = "none"; + } + + var popup_status = document.createElement("div"); + popup_status.id = "popup-status"; + document.body.appendChild(popup_status); + + var popup_body = document.createElement("div"); + popup_body.id = "popup"; + document.body.appendChild(popup_body); + + // import popup + var popup_body = document.getElementById("popup"); + var popup_status = document.getElementById("popup-status"); + var popup_image = null; // is set later on popup click + + // image metadata + var collection = []; // will contain width, height, image URL + var collection_index = 0; + + // event handling helper variables + var is_popup_shown = false; + var mouse_down = false; + var mouse_move = false; + var move_x = 0; + var move_y = 0; + var target_is_popup = false; + var mirror_x = false; + var mirror_y = false; + var rotation = 0; + + /* + Image dragging (mousedown) + */ + document.addEventListener("mousedown", function(div){ + + if(div.buttons !== 1){ + + return; + } + + mouse_down = true; + mouse_move = false; + + if(is_click_within(div.target, "popup", true) === false){ + + target_is_popup = false; + }else{ + + target_is_popup = true; + + var pos = popup_body.getBoundingClientRect(); + move_x = div.x - pos.x; + move_y = div.y - pos.y; + } + }); + + /* + Image dragging (mousemove) + */ + document.addEventListener("mousemove", function(pos){ + + if( + target_is_popup && + mouse_down + ){ + + mouse_move = true; + movepopup(popup_body, pos.clientX - move_x, pos.clientY - move_y); + } + }); + + /* + Image dragging (mouseup) + */ + document.addEventListener("mouseup", function(){ + + mouse_down = false; + }); + + /* + Image popup open + */ + document.addEventListener("click", function(click){ + + // should our click trigger image open? + if( + elem = is_click_within(click.target, image_class) || + click.target.classList.contains("openimg") + ){ + + event.preventDefault(); + is_popup_shown = true; + + // reset position params + mirror_x = false; + mirror_y = false; + rotation = 0; + scale = 60; + collection_index = 0; + + // get popup data + if(elem === true){ + // we clicked a simple image preview + elem = click.target; + var image_url = elem.getAttribute("src"); + + if(image_url.startsWith("/proxy")){ + + var match = image_url.match(/i=([^&]+)/); + + if(match !== null){ + + image_url = decodeURIComponent(match[1]); + } + }else{ + + image_url = htmlspecialchars_decode(image_url); + } + + var w = Math.round(click.target.naturalWidth); + var h = Math.round(click.target.naturalHeight); + + if( + w === 0 || + h === 0 + ){ + + w = 100; + h = 100; + } + + collection = [ + { + "url": image_url, + "width": w, + "height": h + } + ]; + + var title = "No description provided"; + + if(click.target.title != ""){ + + title = click.target.title; + }else{ + + if(click.target.alt != ""){ + + title = click.target.alt; + } + } + }else{ + + if(image_class == "thumb"){ + // we're inside image.php + + elem = + elem + .parentElement + .parentElement; + + var image_url = elem.getElementsByTagName("a")[1].href; + }else{ + + // we're inside web.php + var image_url = elem.href; + } + + collection = + JSON.parse( + elem.getAttribute("data-json") + ); + + var imagesize = elem.getElementsByTagName("img")[0]; + + var imagesize_w = 0; + var imagesize_h = 0; + + if(imagesize.complete){ + + imagesize_w = imagesize.naturalWidth; + imagesize_h = imagesize.naturalHeight; + } + + if( + imagesize_w === 0 || + imagesize_h === 0 + ){ + + imagesize_w = 100; + imagesize_h = 100; + } + + for(var i=0; i<collection.length; i++){ + + if(collection[i].width === null){ + + collection[i].width = imagesize_w; + collection[i].height = imagesize_h; + } + } + + var title = elem.title; + } + + // prepare HTML + var html = + '<div id="popup-num">(' + collection.length + ')</div>' + + '<div id="popup-dropdown">' + + '<select name="viewer-res" onchange="changeimage(event)">'; + + for(i=0; i<collection.length; i++){ + + if(collection[i].url.startsWith("data:")){ + + var domain = "<Base64 Data>"; + }else{ + + var domain = new URL(collection[i].url).hostname; + } + + html += '<option value="' + i + '">' + '(' + collection[i].width + 'x' + collection[i].height + ') ' + domain + '</option>'; + } + + popup_status.innerHTML = + html + '</select></div>' + + '<a href="' + htmlspecialchars(image_url) + '" rel="noreferrer nofollow "id="popup-title">' + htmlspecialchars(title) + '</a>'; + + popup_body.innerHTML = + '<img src="' + getproxylink(collection[0].url) + '" draggable="false" id="popup-image">'; + + // make changes to DOM + popup_body.style.display = "block"; + popup_bg.style.display = "block"; + popup_status.style.display = "table"; + + // store for rotation functions & changeimage() + popup_image = document.getElementById("popup-image"); + + scalepopup(collection[collection_index], scale); + centerpopup(); + }else{ + + // click inside the image viewer + // resize image + if(is_click_within(click.target, "popup", true)){ + + if(mouse_move === false){ + scale = 80; + scalepopup(collection[collection_index], scale); + centerpopup(); + } + }else{ + + if(is_click_within(click.target, "popup-status", true) === false){ + + // click outside the popup while its open + // close it + if(is_popup_shown){ + + hidepopup(); + } + } + } + } + }); + + /* + Scale image viewer + */ + popup_body.addEventListener("wheel", function(scroll){ + + event.preventDefault(); + + if( + scroll.altKey || + scroll.ctrlKey || + scroll.shiftKey + ){ + + var increment = 7; + }else{ + + var increment = 14; + } + + if(scroll.wheelDelta > 0){ + + // scrolling up + scale = scale + increment; + }else{ + + // scrolling down + if(scale - increment > 7){ + scale = scale - increment; + } + } + + // calculate relative size before scroll + var pos = popup_body.getBoundingClientRect(); + var x = (scroll.x - pos.x) / pos.width; + var y = (scroll.y - pos.y) / pos.height; + + scalepopup(collection[collection_index], scale); + + // move popup to % we found + pos = popup_body.getBoundingClientRect(); + + movepopup( + popup_body, + scroll.clientX - (x * pos.width), + scroll.clientY - (y * pos.height) + ); + }); + + /* + Keyboard controls + */ + + document.addEventListener("keydown", function(key){ + + // close popup + if( + is_popup_shown && + key.keyCode === 27 + ){ + + hidepopup(); + return; + } + + if(is_popup_shown === false){ + + return; + } + + if( + key.altKey || + key.ctrlKey || + key.shiftKey + ){ + + // mirror image + switch(key.keyCode){ + + case 37: + // left + key.preventDefault(); + mirror_x = true; + break; + + case 38: + // up + key.preventDefault(); + mirror_y = false; + break; + + case 39: + // right + key.preventDefault(); + mirror_x = false; + break; + + case 40: + // down + key.preventDefault(); + mirror_y = true; + break; + } + }else{ + + // rotate image + switch(key.keyCode){ + + case 37: + // left + key.preventDefault(); + rotation = -90; + break; + + case 38: + // up + key.preventDefault(); + rotation = 0; + break; + + case 39: + // right + key.preventDefault(); + rotation = 90; + break; + + case 40: + // down + key.preventDefault(); + rotation = -180; + break; + } + } + + popup_image.style.transform = + "scale(" + + (mirror_x ? "-1" : "1") + + ", " + + (mirror_y ? "-1" : "1") + + ") " + + "rotate(" + + rotation + "deg" + + ")"; + }); +} + +function getproxylink(url){ + + if(url.startsWith("data:")){ + + return htmlspecialchars(url); + }else{ + + return '/proxy?i=' + encodeURIComponent(url); + } +} + +function hidepopup(){ + + is_popup_shown = false; + popup_status.style.display = "none"; + popup_body.style.display = "none"; + popup_bg.style.display = "none"; +} + +function scalepopup(size, scale){ + + var ratio = + Math.min( + (window.innerWidth * (scale / 100)) / collection[collection_index].width, (window.innerHeight * (scale / 100)) / collection[collection_index].height + ); + + popup_body.style.width = size.width * ratio + "px"; + popup_body.style.height = size.height * ratio + "px"; +} + +function centerpopup(){ + + var size = popup_body.getBoundingClientRect(); + var size = { + "width": parseInt(size.width), + "height": parseInt(size.height) + }; + + movepopup( + popup_body, + (window.innerWidth / 2) - (size.width / 2), + (window.innerHeight / 2) - (size.height / 2) + ); +} + +function movepopup(popup_body, x, y){ + + popup_body.style.left = x + "px"; + popup_body.style.top = y + "px"; +} + +function changeimage(event){ + + // reset rotation params + mirror_x = false; + mirror_y = false; + rotation = 0; + + scale = 60; + + collection_index = parseInt(event.target.value); + + // we set innerHTML otherwise old image lingers a little + popup_body.innerHTML = + '<img src="' + getproxylink(collection[collection_index].url) + '" draggable="false" id="popup-image">'; + + // store for rotation functions & changeimage() + popup_image = document.getElementById("popup-image"); + + scalepopup(collection[collection_index], scale); + centerpopup(); +} + +var searchbox_wrapper = document.getElementsByClassName("searchbox"); + +if(searchbox_wrapper.length !== 0){ + + searchbox_wrapper = searchbox_wrapper[0]; + var searchbox = searchbox_wrapper.getElementsByTagName("input")[1]; + + /* + Textarea shortcuts + */ + document.addEventListener("keydown", function(key){ + + switch(key.keyCode){ + + case 191: + // 191 = / + if(document.activeElement.tagName == "INPUT"){ + + // already focused, ignore + break; + } + + if( + typeof is_popup_shown != "undefined" && + is_popup_shown + ){ + + hidepopup(); + } + + window.scrollTo(0, 0); + searchbox.focus(); + key.preventDefault(); + break; + } + }); + + /* + Autocompleter + */ + if( // make sure the user wants it + document.cookie.includes("scraper_ac=") && + document.cookie.includes("scraper_ac=disabled") === false + ){ + + var autocomplete_cache = []; + var focuspos = -1; + var list = []; + var autocomplete_div = document.getElementsByClassName("autocomplete")[0]; + + if( + document.cookie.includes("scraper_ac=auto") && + typeof scraper_dropdown != "undefined" + ){ + + var ac_req_appendix = "&scraper=" + scraper_dropdown.value; + }else{ + + var ac_req_appendix = ""; + } + + function getsearchboxtext(){ + + var value = + searchbox.value + .trim() + .replace( + / +/g, + " " + ) + .toLowerCase(); + + return value; + } + + searchbox.addEventListener("input", async function(){ + + // ratelimit on input only + // dont ratelimit if we already have res + if(typeof autocomplete_cache[getsearchboxtext()] != "undefined"){ + + await getac(); + }else{ + + await getac_ratelimit(); + } + }); + + async function getac(){ + + var curvalue = getsearchboxtext(); + + if(curvalue == ""){ + + // hide autocompleter + autocomplete_div.style.display = "none"; + return; + } + + if(typeof autocomplete_cache[curvalue] == "undefined"){ + + /* + Fetch autocomplete + */ + // make sure we dont fetch same thing twice + autocomplete_cache[curvalue] = []; + + var res = await fetch("/api/v1/ac?s=" + (encodeURIComponent(curvalue).replaceAll("%20", "+")) + ac_req_appendix); + if(!res.ok){ + + return; + } + + var json = await res.json(); + + autocomplete_cache[curvalue] = json[1]; + + if(curvalue == getsearchboxtext()){ + + render_ac(curvalue, autocomplete_cache[curvalue]); + } + return; + } + + render_ac(curvalue, autocomplete_cache[curvalue]); + } + + var ac_func = null; + function getac_ratelimit(){ + + return new Promise(async function(resolve, reject){ + + if(ac_func !== null){ + + clearTimeout(ac_func); + }//else{ + + // no ratelimits + //getac(); + //} + + ac_func = + setTimeout(function(){ + + ac_func = null; + getac(); // get results after 100ms of no keystroke + resolve(); + }, 200); + }); + } + + function render_ac(query, list){ + + if(list.length === 0){ + + autocomplete_div.style.display = "none"; + return; + } + + html = ""; + + // prepare regex + var highlight = query.split(" "); + var regex = []; + + for(var k=0; k<highlight.length; k++){ + + // espace regex + regex.push( + highlight[k].replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ); + } + + regex = new RegExp(highlight.join("|"), "gi"); + + for(var i=0; i<list.length; i++){ + + html += + '<div tabindex="0" class="entry" onclick="handle_entry_click(this);">' + + htmlspecialchars( + list[i] + ).replace( + regex, + '<u>$&</u>' + ) + + '</div>'; + } + + autocomplete_div.innerHTML = html; + autocomplete_div.style.display = "block"; + } + + var should_focus = false; + document.addEventListener("keydown", function(event){ + + if(event.key == "Escape"){ + + document.activeElement.blur(); + focuspos = -1; + autocomplete_div.style.display = "none"; + return; + } + + if( + is_click_within(event.target, "searchbox") === false || + typeof autocomplete_cache[getsearchboxtext()] == "undefined" + ){ + + return; + } + + switch(event.key){ + + case "ArrowUp": + event.preventDefault(); + focuspos--; + if(focuspos === -2){ + + focuspos = autocomplete_cache[getsearchboxtext()].length - 1; + } + break; + + case "ArrowDown": + case "Tab": + event.preventDefault(); + + focuspos++; + if(focuspos >= autocomplete_cache[getsearchboxtext()].length){ + + focuspos = -1; + } + break; + + case "Enter": + should_focus = true; + + if(focuspos !== -1){ + + // replace input content + event.preventDefault(); + searchbox.value = + autocomplete_div.getElementsByClassName("entry")[focuspos].innerText; + break; + } + break; + + default: + focuspos = -1; + break; + } + + if(focuspos === -1){ + + searchbox.focus(); + return; + } + + autocomplete_div.getElementsByClassName("entry")[focuspos].focus(); + }); + + window.addEventListener("blur", function(){ + + autocomplete_div.style.display = "none"; + }); + + document.addEventListener("keyup", function(event){ + + // handle ENTER key on entry + if(should_focus){ + + should_focus = false; + searchbox.focus(); + } + }); + + document.addEventListener("mousedown", function(event){ + + // hide input if click is outside + if(is_click_within(event.target, "searchbox") === false){ + + autocomplete_div.style.display = "none"; + return; + } + }); + + function handle_entry_click(event){ + + searchbox.value = event.innerText; + focuspos = -1; + searchbox.focus(); + } + + searchbox.addEventListener("focus", function(){ + + focuspos = -1; + getac(); + }); + } +} diff --git a/static/icon/amazon.png b/static/icon/amazon.png Binary files differnew file mode 100644 index 0000000..043a7e2 --- /dev/null +++ b/static/icon/amazon.png diff --git a/static/icon/appstore.png b/static/icon/appstore.png Binary files differnew file mode 100644 index 0000000..85663bb --- /dev/null +++ b/static/icon/appstore.png diff --git a/static/icon/call.png b/static/icon/call.png Binary files differnew file mode 100644 index 0000000..c91bece --- /dev/null +++ b/static/icon/call.png diff --git a/static/icon/directions.png b/static/icon/directions.png Binary files differnew file mode 100644 index 0000000..699da40 --- /dev/null +++ b/static/icon/directions.png diff --git a/static/icon/facebook.png b/static/icon/facebook.png Binary files differnew file mode 100644 index 0000000..0ae3137 --- /dev/null +++ b/static/icon/facebook.png diff --git a/static/icon/gamespot.png b/static/icon/gamespot.png Binary files differnew file mode 100644 index 0000000..3453e07 --- /dev/null +++ b/static/icon/gamespot.png diff --git a/static/icon/github.png b/static/icon/github.png Binary files differnew file mode 100644 index 0000000..f78f0c0 --- /dev/null +++ b/static/icon/github.png diff --git a/static/icon/googleplay.png b/static/icon/googleplay.png Binary files differnew file mode 100644 index 0000000..05ffc19 --- /dev/null +++ b/static/icon/googleplay.png diff --git a/static/icon/imdb.png b/static/icon/imdb.png Binary files differnew file mode 100644 index 0000000..d8ccb2f --- /dev/null +++ b/static/icon/imdb.png diff --git a/static/icon/instagram.png b/static/icon/instagram.png Binary files differnew file mode 100644 index 0000000..41d9bf2 --- /dev/null +++ b/static/icon/instagram.png diff --git a/static/icon/itunes.png b/static/icon/itunes.png Binary files differnew file mode 100644 index 0000000..99a1dff --- /dev/null +++ b/static/icon/itunes.png diff --git a/static/icon/microsoft.png b/static/icon/microsoft.png Binary files differnew file mode 100644 index 0000000..46d048a --- /dev/null +++ b/static/icon/microsoft.png diff --git a/static/icon/quora.png b/static/icon/quora.png Binary files differnew file mode 100644 index 0000000..00746b3 --- /dev/null +++ b/static/icon/quora.png diff --git a/static/icon/reddit.png b/static/icon/reddit.png Binary files differnew file mode 100644 index 0000000..6522815 --- /dev/null +++ b/static/icon/reddit.png diff --git a/static/icon/rottentomatoes.png b/static/icon/rottentomatoes.png Binary files differnew file mode 100644 index 0000000..dd462e7 --- /dev/null +++ b/static/icon/rottentomatoes.png diff --git a/static/icon/sciencedirect.png b/static/icon/sciencedirect.png Binary files differnew file mode 100644 index 0000000..20cef17 --- /dev/null +++ b/static/icon/sciencedirect.png diff --git a/static/icon/soundcloud.png b/static/icon/soundcloud.png Binary files differnew file mode 100644 index 0000000..a12ba39 --- /dev/null +++ b/static/icon/soundcloud.png diff --git a/static/icon/spotify.png b/static/icon/spotify.png Binary files differnew file mode 100644 index 0000000..c7a35ca --- /dev/null +++ b/static/icon/spotify.png diff --git a/static/icon/steam.png b/static/icon/steam.png Binary files differnew file mode 100644 index 0000000..ab3e73d --- /dev/null +++ b/static/icon/steam.png diff --git a/static/icon/twitter.png b/static/icon/twitter.png Binary files differnew file mode 100644 index 0000000..bce2863 --- /dev/null +++ b/static/icon/twitter.png diff --git a/static/icon/w3html.png b/static/icon/w3html.png Binary files differnew file mode 100644 index 0000000..2f107db --- /dev/null +++ b/static/icon/w3html.png diff --git a/static/icon/website.png b/static/icon/website.png Binary files differnew file mode 100644 index 0000000..aa691f8 --- /dev/null +++ b/static/icon/website.png diff --git a/static/icon/wikipedia.png b/static/icon/wikipedia.png Binary files differnew file mode 100644 index 0000000..b3e778e --- /dev/null +++ b/static/icon/wikipedia.png diff --git a/static/icon/youtube.png b/static/icon/youtube.png Binary files differnew file mode 100644 index 0000000..542d7f0 --- /dev/null +++ b/static/icon/youtube.png diff --git a/static/misc/christmas-dark-bg.png b/static/misc/christmas-dark-bg.png Binary files differnew file mode 100644 index 0000000..83f7c0a --- /dev/null +++ b/static/misc/christmas-dark-bg.png diff --git a/static/misc/christmas-hat.png b/static/misc/christmas-hat.png Binary files differnew file mode 100644 index 0000000..91d96ad --- /dev/null +++ b/static/misc/christmas-hat.png diff --git a/static/misc/christmas-white-bg.png b/static/misc/christmas-white-bg.png Binary files differnew file mode 100644 index 0000000..a627775 --- /dev/null +++ b/static/misc/christmas-white-bg.png diff --git a/static/misc/snow.png b/static/misc/snow.png Binary files differnew file mode 100644 index 0000000..d157188 --- /dev/null +++ b/static/misc/snow.png diff --git a/static/serverping.js b/static/serverping.js new file mode 100644 index 0000000..6b680d5 --- /dev/null +++ b/static/serverping.js @@ -0,0 +1,473 @@ + +function htmlspecialchars(str){ + + if(str === null){ + + return "<i><Empty></i>"; + } + + var map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + } + + return str.replace(/[&<>"']/g, function(m){return map[m];}); +} + +// initialize garbage +var list = []; +var pinged_list = []; +var reqs = 0; +var errors = 0; +var sort = 6; // highest version first + +// check for instance redirect stuff +var redir = []; +var target = "/web?"; +new URL(window.location.href) + .searchParams + .forEach( + function(value, key){ + + if(key == "target"){ + + target = "/" + encodeURIComponent(value) + "?"; + return; + } + + if(key == "npt"){ return; } + redir.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)) + } + ); + +if(redir.length !== 0){ + + redir = target + redir.join("&"); +}else{ + + redir = ""; +} + +var quote = document.createElement("div"); +quote.className = "quote"; +quote.innerHTML = 'Pinged <b>0</b> servers (<b>0</b> failed requests)'; +var [div_servercount, div_failedreqs] = + quote.getElementsByTagName("b"); + +var noscript = document.getElementsByTagName("noscript")[0]; +document.body.insertBefore(quote, noscript.nextSibling); + +// create table +var table = document.createElement("table"); +table.innerHTML = + '<thead>' + + '<tr>' + + '<th class="extend">Server</th>' + + '<th>Address</th>' + + '<th>Bot protection</th>' + + '<th title="Amount of legit requests processed since the last APCU cache clear (usually happens at midnight)">Real reqs (?)</th>' + + '<th title="Amount of filtered requests processed since the last APCU cache clear (usually happens at midnight)">Bot reqs (?)</th>' + + '<th>API</th>' + + '<th><div class="arrow up"></div>Version</th>' + + '</tr>' + + '</thead>' + + '<tbody></tbody>'; + +document.body.insertBefore(table, quote.nextSibling); + +// handle sorting clicks +var tbody = table.getElementsByTagName("tbody")[0]; +var th = table.getElementsByTagName("th"); + +for(var i=0; i<th.length; i++){ + + th[i].addEventListener("click", function(event){ + + if(event.target.className.includes("arrow")){ + + var div = event.target.parentElement; + }else{ + + var div = event.target; + } + + var arrow = div.getElementsByClassName("arrow"); + var orientation = 0; // up + + if(arrow.length === 0){ + + // delete arrow and add new one + arrow = document.getElementsByClassName("arrow"); + arrow[0].remove(); + + arrow = document.createElement("div"); + arrow.className = "arrow up"; + div.insertBefore(arrow, event.target.firstChild); + }else{ + + // switch arrow position + if(arrow[0].className == "arrow down"){ + + arrow[0].className = "arrow up"; + }else{ + + arrow[0].className = "arrow down"; + orientation = 1; + } + } + + switch(div.textContent.toLowerCase()){ + + case "server": sort = 0 + orientation; break; + case "address": sort = 2 + orientation; break; + case "bot protection": sort = 4 + orientation; break; + case "real reqs (?)": sort = 6 + orientation; break; + case "bot reqs (?)": sort = 8 + orientation; break; + case "api": sort = 10 + orientation; break; + case "version": sort = 12 + orientation; break; + } + + render_list(); + }); +} + +function validate_url(url, allow_http = false){ + + try{ + + url = new URL(url); + if( + url.protocol == "https:" || + ( + ( + allow_http === true || + window.location.protocol == "http:" + ) && + url.protocol == "http:" + ) + ){ + + return true; + } + }catch(error){} // do nothing + + return false; +} + +function number_format(int){ + + return new Intl.NumberFormat().format(int); +} + +// parse initial server list +fetch_server(window.location.origin); + +async function fetch_server(server){ + + if(!validate_url(server)){ + console.warn("Invalid server URL: " + server); + return; + } + + // make sure baseURL is origin + server = new URL(server).origin; + // prevent multiple fetches + for(var i=0; i<list.length; i++){ + + if(list[i] == server){ + + // serber was already fetched + return; + } + } + + // prevent future fetches + list.push(server); + + var data = null; + + try{ + + var payload = await fetch(server + "/ami4get"); + + if(payload.status !== 200){ + + // endpoint is not available + errors++; + div_failedreqs.textContent = number_format(errors); + console.warn(server + ": Invalid HTTP code " + payload.status); + return; + } + + data = await payload.json(); + + }catch(error){ + + errors++; + div_failedreqs.textContent = number_format(errors); + console.warn(server + ": Could not fetch or decode JSON"); + return; + } + + // sanitize data + if( + typeof data.status != "string" || + data.status != "ok" || + typeof data.server != "object" || + !( + typeof data.server.name == "string" || + ( + typeof data.server.name == "object" && + data.server.name === null + ) + ) || + typeof data.service != "string" || + data.service != "4get" || + ( + typeof data.server.description != "string" && + data.server.description !== null + ) || + typeof data.server.bot_protection != "number" || + typeof data.server.real_requests != "number" || + typeof data.server.bot_requests != "number" || + typeof data.server.api_enabled != "boolean" || + typeof data.server.alt_addresses != "object" || + typeof data.server.version != "number" || + typeof data.instances != "object" + ){ + + errors++; + div_failedreqs.textContent = number_format(errors); + console.warn(server + ": Malformed JSON"); + return; + } + + data.server.ip = server; + + reqs++; + div_servercount.textContent = number_format(reqs); + + var total = pinged_list.push(data) - 1; + pinged_list[total].index = total; + + render_list(); + + // get more serbers + for(var i=0; i<data.instances.length; i++){ + + fetch_server(data.instances[i]); + } +} + +function sorta(object, element, order){ + + return object.slice().sort( + function(a, b){ + + if(order){ + + return a.server[element] - b.server[element]; + } + + return b.server[element] - a.server[element]; + } + ); +} + +function textsort(object, element, order){ + + var sort = object.slice().sort( + function(a, b){ + + return a.server[element].localeCompare(b.server[element]); + } + ); + + if(!order){ + return sort.reverse(); + } + + return sort; +} + +function render_list(){ + + var sorted_list = []; + + // sort + var filter = Boolean(sort % 2); + + switch(sort){ + + case 0: + case 1: + sorted_list = textsort(pinged_list, "name", filter === true ? false : true); + break; + + case 2: + case 3: + sorted_list = textsort(pinged_list, "ip", filter === true ? false : true); + break; + + case 4: + case 5: + sorted_list = sorta(pinged_list, "bot_protection", filter === true ? false : true); + break; + + case 6: + case 7: + sorted_list = sorta(pinged_list, "real_requests", filter); + break; + + case 8: + case 9: + sorted_list = sorta(pinged_list, "bot_requests", filter); + break; + + case 10: + case 11: + sorted_list = sorta(pinged_list, "api_enabled", filter); + break; + + case 12: + case 13: + sorted_list = sorta(pinged_list, "version", filter); + break; + } + + // render tabloid + var html = ""; + + for(var k=0; k<sorted_list.length; k++){ + + html += '<tr onclick="show_server(' + sorted_list[k].index + ');">'; + + for(var i=0; i<7; i++){ + + html += '<td'; + + switch(i){ + + // server name + case 0: html += ' class="extend">' + htmlspecialchars(sorted_list[k].server.name); break; + case 1: html += '>' + htmlspecialchars(new URL(sorted_list[k].server.ip).host); break; + case 2: // bot protection + switch(sorted_list[k].server.bot_protection){ + + case 0: + html += '><span style="color:var(--green);">Disabled</span>'; + break; + + case 1: + html += '><span style="color:var(--yellow);">Image captcha</span>'; + break; + + case 2: + html += '><span style="color:var(--red);">Invite only</span>'; + break; + + default: + html += '>Unknown'; + } + break; + + case 3: // real reqs + html += '>' + number_format(sorted_list[k].server.real_requests); + break; + + case 4: // bot reqs + html += '>' + number_format(sorted_list[k].server.bot_requests); + break; + + case 5: // api enabled + + if(sorted_list[k].server.api_enabled){ + + html += '><span style="color:var(--green);">Yes</span>'; + }else{ + + html += '><span style="color:var(--red);">No</span>'; + } + break; + + // version + case 6: html += ">v" + sorted_list[k].server.version; break; + } + + html += '</td>'; + } + + html += '</tr>'; + } + + console.log(html); + + tbody.innerHTML = html; +} + +var popup_bg = document.getElementById("popup-bg"); +var popup_wrapper = document.getElementsByClassName("popup-wrapper")[0]; +var popup = popup_wrapper.getElementsByClassName("popup")[0]; +var popup_shown = false; + +popup_bg.addEventListener("click", function(){ + + popup_wrapper.style.display = "none"; + popup_bg.style.display = "none"; +}); + +function show_server(serverid){ + + var html = + '<h2>' + htmlspecialchars(pinged_list[serverid].server.name) + '</h2>' + + 'Description' + + '<div class="code">' + htmlspecialchars(pinged_list[serverid].server.description) + '</div>'; + + var url_obj = new URL(pinged_list[serverid].server.ip); + var url = htmlspecialchars(url_obj.origin); + var domain = url_obj.hostname; + + html += + 'URL: <a rel="noreferer" target="_BLANK" href="' + url + redir + '">' + url + '</a> <a rel="noreferer" target="_BLANK" href="https://browserleaks.com/ip/' + encodeURIComponent(domain) + '">(IP lookup)</a>' + + '<br><br>Alt addresses:'; + + var len = pinged_list[serverid].server.alt_addresses.length; + + if(len === 0){ + + html += ' <i><Empty></i>'; + }else{ + + html += '<ul>'; + + for(var i=0; i<len; i++){ + + var url_obj = new URL(pinged_list[serverid].server.alt_addresses[i]); + var url = htmlspecialchars(url_obj.origin); + var domain = url_obj.hostname; + + if(validate_url(pinged_list[serverid].server.alt_addresses[i], true)){ + + html += '<li><a rel="noreferer" href="' + url + redir + '" target="_BLANK">' + url + '</a> <a rel="noreferer" target="_BLANK" href="https://browserleaks.com/ip/' + encodeURIComponent(domain) + '">(IP lookup)</a></li>'; + }else{ + + console.warn(pinged_list[serverid].server.ip + ": Invalid peer URL => " + pinged_list[serverid].server.alt_addresses[i]); + } + } + + html += '</ul>'; + } + popup.innerHTML = html; + + popup_wrapper.style.display = "block"; + popup_bg.style.display = "block"; +} + +function hide_server(){ + + popup_wrapper.style.display = "none"; + popup_bg.style.display = "none"; +} diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..6276417 --- /dev/null +++ b/static/style.css @@ -0,0 +1,1384 @@ +:root{ + /* background */ + --1d2021: #1d2021; + --282828: #282828; + --3c3836: #3c3836; + --504945: #504945; + + /* font */ + --928374: #928374; + --a89984: #a89984; + --bdae93: #bdae93; + --8ec07c: #8ec07c; + --ebdbb2: #ebdbb2; + + /* code highlighter */ + --comment: #9e8e73; + --default: #d4be98; + --keyword: #d8a657; + --string: #7daea7; + + /* color codes for instance list */ + --green: #b8bb26; + --yellow: #d8a657; + --red: #fb4934; +} + +audio{ + max-width:100%; + display:block; +} + +.left audio{ + margin-top:7px; +} + +.right-wrapper audio{ + margin-bottom:17px; +} + +body,html{ + padding:0; + margin:0; +} + +body{ + background:var(--1d2021); + color:var(--a89984); + font-size:16px; + box-sizing:border-box; + font-family:sans-serif; + margin:15px 7% 45px; + word-wrap:anywhere; + line-height:22px; + max-width:2000px; + position:relative; +} + +.navigation{ + position:absolute; + top:0; + right:0; + font-size:14px; + line-height:40px; +} + +.navigation a{ + color:var(--bdae93); + text-decoration:none; +} + +.navigation a:hover{ + text-decoration:underline; +} + +.navigation a:not(:last-child)::after{ + content:"|"; + padding:0 7px; + display:inline-block; + color:var(--504945); +} + +h1,h2,h3,h4,h5,h6{ + padding:0; + margin:0 0 7px 0; + line-height:initial; + color:var(--bdae93); +} + +h3,h4,h5,h6{ + margin-bottom:14px; +} + +/* + Web styles +*/ +#overflow{ + overflow:hidden; +} + +/* Searchbox */ +.searchbox{ + width:40%; + height:36px; + border:1px solid var(--504945); + background:var(--282828); + border-radius:2px; + margin-bottom:10px; + position:relative; +} + +.searchbox .wrapper{ + overflow:hidden; +} + +.searchbox input[type="text"]{ + width:100%; + padding-left:10px; +} + +.searchbox input[type="text"]::placeholder{ + color:var(--928374); +} + +.searchbox input[type="submit"]{ + float:right; + cursor:pointer; + padding:0 10px; +} + +.searchbox input[type="submit"]:hover{ + text-decoration:underline; +} + +.searchbox input{ + all:unset; + line-height:36px; + box-sizing:border-box; + height:36px; + color:var(--bdae93); +} + +.searchbox:focus-within{ + border:1px solid var(--928374); +} + +.autocomplete{ + display:none; + position:absolute; + top:35px; + left:-1px; + right:-1px; + background:var(--282828); + border:1px solid var(--928374); + border-top:none; + border-radius:0 0 2px 2px; + z-index:10; + overflow:hidden; +} + +.autocomplete .entry{ + overflow:hidden; + padding:4px 10px; + cursor:pointer; + outline:none; + user-select:none; +} + +.autocomplete .entry:hover{ + background:var(--3c3836); +} + +.autocomplete .entry:focus{ + background:var(--3c3836); +} + +/* Tabs */ +.tabs, .filters{ + overflow:hidden; + overflow-x:auto; + white-space:nowrap; +} + +.tabs{ + padding-bottom:10px; +} + +.tabs .tab{ + text-decoration:none; + color:var(--bdae93); + padding:4px 10px; + display:inline-block; +} + +.tabs .tab:hover{ + text-decoration:underline; +} + +.tabs .tab.selected{ + border-bottom:2px solid var(--bdae93); +} + +/* Filters */ +.filters{ + margin-bottom:7px; +} + +.filters .filter{ + display:inline-block; + margin-right:7px; + vertical-align:bottom; +} + +.filters .filter .title{ + font-size:13px; + margin:0 4px; +} + +.filters .filter input, +.filters .filter select{ + all:unset; + user-select:none; + display:block; + border:1px solid var(--504945); + border-radius:2px; + font-size:14px; + padding:0 4px; + width:127px; + height:24px; +} + +.timetaken{ + font-size:14px; + font-weight:bold; + margin-bottom:10px; +} + + +/* + HOME +*/ +.home{ + min-height:100vh; + margin:0 auto; + display:table; + text-align:center; +} + +.home .logo{ + max-width:400px; + height:100px; + margin:0 auto 17px auto; +} + +.home img{ + line-height:100px; + font-size:60px; + text-align:center; + font-family:Times; + width:100%; + height:100%; + background:var(--282828); + display:block; + object-fit:contain; +} + +.home #center{ + display:table-cell; + vertical-align:middle; + width:500px; +} + +.home .searchbox{ + width:100%; + text-align:left; + margin-bottom:20px; +} + +.home a{ + color:inherit; +} + +.home .subtext{ + margin-top:17px; + line-height:16px; + font-size:12px; +} + + +/* + WEB +*/ + +/* Captcha */ +.captcha-wrapper{ + position:relative; + max-width:400px; + margin:17px auto 0; + border:1px solid var(--928374); +} + +.captcha{ + padding-bottom:100%; + padding-top:6.2%; +} + +.captcha-wrapper img{ + position:absolute; + top:0; + left:0; + width:100%; + height:100%; +} + +.captcha-controls{ + position:absolute; + top:0; + left:0; + bottom:0; + right:0; + top:6.3%; +} + +.captcha-wrapper img{ + display:block; + background:#282828; +} + +.captcha-wrapper input{ + display:none; +} + +.captcha-wrapper label{ + float:left; + width:25%; + height:25%; + position:relative; + cursor:pointer; +} + +.captcha-wrapper label:hover{ + background:rgba(255,255,255,0.2); +} + +.captcha-wrapper input:checked + label{ + background:rgba(0,0,0,0.5); +} + +.captcha-wrapper input:checked + label:after{ + content:""; + position:absolute; + left:39%; + top:29%; + width:20%; + height:30%; + transform:rotate(45deg); + border-right:7px solid var(--ebdbb2); + border-bottom:7px solid var(--ebdbb2); + box-sizing:border-box; +} + +.captcha-submit{ + float:right; + margin:12px 0 4px; +} + +.web .left{ + width:40%; + float:left; +} + +/* infobox */ +.infobox{ + border:1px dashed var(--504945); + padding:10px; + margin-bottom:17px; + overflow:hidden; +} + +.infobox .code{ + white-space:initial; +} + +.infobox ul{ + padding-left:27px; + margin-bottom:0; +} + +.infobox a{ + color:var(--bdae93); +} + +.infobox a:hover{ + text-decoration:underline; +} + +/* text-result */ +.web .text-result{ + margin-bottom:30px; +} + +.web .description{ + white-space:pre-line; +} + +.web .type{ + border:1px solid var(--928374); + background:var(--282828); + padding:0 4px; + border-radius:2px; + font-size:14px; + line-height:16px; + float:left; + margin:2px 7px 0 0; +} + +.web .url{ + position:relative; +} + +.web .url .part{ + font-size:15px; + text-decoration:none; + color:var(--928374); +} + +.web .separator::before{ + content:"/"; + padding:0 4px; + color:var(--504945); + font-size:12px; +} + +.web .part:hover{ + text-decoration:underline; +} + +.web .hover{ + display:block; + text-decoration:none; + color:var(--a89984); + overflow:hidden; + clear:left; + padding-top:7px; +} + +.web .text-result .title{ + font-size:18px; + color:var(--bdae93); + margin-bottom:7px; +} + +.web .text-result a:visited .title{ + color:var(--928374) !important; +} + +.theme-white .web .text-result a:visited .title{ + color:#7c6f64 !important; +} + +.web .text-result .hover:hover .title{ + text-decoration:underline; +} + +.web .text-result .author{ + font-style:italic; +} + +.web .text-result .greentext{ + font-size:14px; + color:var(--8ec07c); +} + +.web .right-right .text-result:last-child, +.web .right-left .text-result:last-child{ + margin-bottom:0; +} + +/* favicon */ +.favicon{ + all:unset; + float:left; + cursor:pointer; +} + +.favicon-dropdown{ + display:none; + position:absolute; + top:25px; + background:var(--282828); + border:1px solid var(--504945); + border-radius:2px; + z-index:3; + word-wrap:normal; +} + +.favicon-dropdown::before{ + content:""; + position:absolute; + top:-10px; + left:2px; + border:5px solid transparent; + border-bottom:5px solid var(--504945); +} + +.favicon-dropdown a{ + text-decoration:none; + color:var(--bdae93); + display:block; + padding:2px 7px 2px 5px; + font-size:13px; +} + +.favicon-dropdown a:hover{ + text-decoration:underline; +} + +.favicon-dropdown:hover, +.favicon:focus + .favicon-dropdown, +.favicon-dropdown:focus-within{ + display:block; +} + +.web .favicon img, +.favicon-dropdown img{ + margin:3px 7px 0 0; + width:16px; + height:16px; + font-size:12px; + line-height:16px; + text-align:center; + display:block; + text-align:left; + white-space:nowrap; +} + +.favicon-dropdown img{ + float:left; + margin:2px 7px 0 0; +} + +/* thumbnails */ +.thumb-wrap{ + position:relative; + float:right; + width:160px; + height:90px; + background:var(--282828); + border:1px solid var(--504945); + margin-left:7px; +} + +.duration{ + position:absolute; + right:0; + bottom:0; + padding:1px 2px; + line-height:14px; + background:var(--3c3836); + font-size:12px; + border-left:1px solid var(--504945); + border-top:1px solid var(--504945); + font-family:monospace; +} + +.web .text-result:hover .thumb-wrap .duration{ + display:none; +} + +.thumb-wrap .thumb{ + display:block; + object-fit:contain; + width:100%; + height:100%; +} + +.thumb-wrap.portrait{ + width:50px; +} + +.thumb-wrap.square{ + width:90px; +} + +/* Next page */ +.nextpage{ + margin:0 0 30px; + text-align:center; + display:block; + padding:10px; + border:1px solid var(--504945); + border-radius:2px; + text-decoration:none; + color:var(--bdae93); +} + +.nextpage:hover{ + text-decoration:underline; +} + +/* Right wrapper */ +.web .right-wrapper{ + width:60%; + float:right; + overflow:hidden; + padding-left:15px; + box-sizing:border-box; +} + +.web .right-right, +.web .right-left{ + float:right; + width:50%; + padding:0 15px; + box-sizing:border-box; + overflow:hidden; + min-height:1px; +} + +.web .right-right{ + padding-right:0; +} + +/* + Tables +*/ +table{ + width:100%; + text-align:left; + border-collapse:collapse; +} + +table td{ + width:50%; + padding:0; + vertical-align:top; +} + +table tr td:first-child{ + padding-right:7px; +} + +table a{ + display:block; + text-decoration:none; + color:var(--a89984); + padding:0 10px 0 0; +} + +table tr a:last-child{ + padding-right:0; +} + +/* Related */ +.related{ + margin-bottom:20px; +} + +.related a{ + padding-bottom:10px; + color:var(--bdae93); +} + +.related a:hover{ + text-decoration:underline; +} + +/* + Answers +*/ +.web .answer{ + max-height:600px; + overflow:hidden; + padding-bottom:17px; + position:relative; +} + +.web .answer::after{ + content:""; + position:absolute; + bottom:0; + width:100%; + height:17px; + background:linear-gradient(transparent, var(--1d2021)); + pointer-events:none; +} + +.web .answer-title{ + text-decoration:none; + color:var(--a89984); +} + +.web .answer-title a:hover{ + text-decoration:underline; +} + +.web .spoiler:checked + .answer{ + overflow:initial; + max-height:initial; +} + +.web .spoiler{ + display:none; +} + +.web .spoiler-button{ + display:block; + border:1px solid var(--504945); + border-radius:2px; + line-height:30px; + padding:0 7px; + text-align:center; + cursor:pointer; +} + +.web .answer-wrapper{ + margin-bottom:27px; +} + +.web .spoiler-button:hover{ + text-decoration:underline; +} + +.web .spoiler-button::before{ + content:"Show more"; +} + +.web .spoiler:checked + .answer + .spoiler-button::before{ + content:"Show less"; +} + +/* Tables on left handside */ +.web .info-table{ + margin:10px 0; + font-size:15px; + color:var(--928374); + background:var(--282828); + border:1px dashed var(--504945); +} + +.web .info-table td{ + padding:4px 10px; +} + +.web .info-table tr td:first-child{ + width:1%; + white-space:nowrap; + padding-right:17px; + color:var(--a89984); +} + +.web .info-table tr:nth-child(even){ + background:var(--1d2021); +} + +.web .sublinks{ + padding:17px 10px 0; + font-size:15px; + color:var(--#928374); +} + +.web .sublinks table td{ + padding-bottom:17px; +} + +.web .sublinks table tr:last-child td:last-child{ + padding-bottom:0; +} + +.web .sublinks a:hover .title{ + text-decoration:underline; +} + +/* Wikipedia head */ +.web .wiki-head .photo{ + float:right; + margin:0 1px 10px 10px; +} +.web .wiki-head .photo img{ + display:block; + max-width:200px; + max-height:200px; + filter:drop-shadow(1px 0 0 var(--504945)) drop-shadow(-1px 0 0 var(--504945)) drop-shadow(0 -1px 0 var(--504945)) drop-shadow(0 1px 0 var(--504945)); +} + +.web .wiki-head .description{ + clear:left; + padding-top:7px; + overflow:hidden; +} + +.web .wiki-head table, .about table{ + margin-top:17px; + border:1px dashed var(--504945); + background:var(--1d2021); +} + +.web .wiki-head table td{ + white-space:pre-line; +} + +.web .wiki-head td, .about table td{ + padding:4px 7px; + vertical-align:middle; +} + +.web .wiki-head tr td:first-child, .about table tr td:first-child{ + width:30%; + min-width:150px; +} + +.web .wiki-head tr:nth-child(odd), .about table tr:nth-child(odd){ + background:var(--282828); +} + +.web .wiki-head .socials{ + overflow:hidden; + margin-top:17px; +} + +.web .wiki-head .socials a{ + width:74px; + height:80px; + padding-right:4px; + float:left; + color:var(--bdae93); + text-decoration:none; + display:table; +} + +.web .wiki-head .socials a:hover .title{ + text-decoration:underline; +} + +.web .wiki-head .socials .center{ + display:table-cell; + vertical-align:middle; +} + +.web .wiki-head .socials img{ + margin:0 auto; + display:block; + text-align:center; + width:36px; + height:36px; + line-height:36px; +} + +.web .wiki-head .socials .title{ + margin-top:7px; + text-align:center; + font-size:13px; + line-height:13px; +} + +.web .fullimg{ + display:block; + max-width:100%; + max-height:150px; + margin:7px 0 17px; + box-sizing:border-box; + border:1px solid var(--504945); +} + +/* + Code tags +*/ +.code{ + white-space:pre; + font-family:monospace; + background:var(--3c3836); + color:var(--bdae93); + padding:7px; + margin:4px 0 13px 0; + overflow-x:auto; + border-radius:2px; + border:1px solid var(--504945); +} + +.code-inline{ + display:inline; + font-family:monospace; + background:var(--282828); + color:var(--bdae93); + border:1px solid var(--928374); + padding:0 4px; + border-radius:2px; +} + +/* Wiki-head titles and quotes */ +.web .wiki-head h2{ + font-size:20px; + margin:20px 0 13px 0; +} + +.web .wiki-head h2:first-child{ + margin-top:10px; +} + +.web .wiki-head a{ + color:var(--bdae93); +} + +.quote{ + font-style:italic; + margin:10px 0 13px; + padding-left:10px; + border-left:1px solid #504945; +} + +/* + Web images +*/ +.web .images{ + overflow:hidden; + margin:0 -5px; + font-size:0; +} + +.web .images .duration{ + display:none; + border:1px solid var(--504945); + right:5px; + bottom:5px; +} + +.web .images .image:hover .duration{ + display:block; +} + +.web .images .image{ + width:90px; + height:90px; + padding:5px; + position:relative; + line-height:90px; + display:inline-block; + text-align:center; + color:inherit; +} + +.web .images .image img{ + max-width:100%; + max-height:100%; + vertical-align:middle; +} + + +/* + Images tab +*/ + +#images{ + overflow:hidden; + margin-bottom:10px; +} + +#images .infobox{ + width:40%; + box-sizing:border-box; +} + +#images .image-wrapper{ + line-height:15px; + width:20%; + float:left; +} + +#images .image{ + margin:0 auto; + width:250px; + max-width:100%; + padding:7px 7px 30px 7px; + box-sizing:border-box; + font-size:14px; +} + +#images a{ + color:inherit; + text-decoration:none; + display:block; +} + +#images a:hover .title{ + text-decoration:underline; +} + +#images .thumb{ + display:block; + height:180px; + margin-bottom:10px; + position:relative; +} + +#images .duration{ + display:block; + border:1px solid #504945; +} + +#images .image:hover .duration{ + display:none; +} + +#images img{ + width:100%; + height:100%; + object-fit:contain; +} + +#images .image .title{ + white-space:nowrap; + overflow:hidden; + margin-bottom:7px; + font-weight:bold; +} + +#images .image .description{ + overflow:hidden; + height:45px; +} + +.nextpage.img{ + width:50%; + margin:0 auto 50px; +} + +#popup{ + display:none; + position:fixed; + top:0; + left:0; + cursor:grab; + user-select:none; + pointer-events:none; + z-index:5; +} + +#popup:active{ + cursor:grabbing; +} + +#popup-image{ + border:1px solid var(--928374); + display:block; + margin:0 auto; + pointer-events:all; + width:100%; + height:100%; + object-fit:contain; + background:var(--282828); +} + +#popup-status{ + display:none; + position:fixed; + top:0; + left:0; + width:100%; + height:35px; + background:var(--1d2021); + border-bottom:1px solid var(--928374); + z-index:4; +} + +#popup-bg{ + background:var(--1d2021); + opacity:.5; + position:fixed; + top:0; + left:0; + width:100%; + height:100%; + display:none; + z-index:3; +} + +#popup-status select{ + display:block; + width:250px; +} + +#popup-num, +#popup-title{ + display:table-cell; + width:0; + word-wrap:normal; + padding:0 10px; + line-height:35px; + color:var(--ebdbb2); + text-decoration:none; +} + +#popup-title:hover{ + text-decoration:underline; +} + +#popup-title{ + width:initial; + overflow:hidden; + height:35px; + display:block; +} + +#popup-num{ + font-weight:bold; +} + +#popup-dropdown{ + display:table-cell; + vertical-align:middle; + width:0; +} + +/* + Settings page +*/ +.web .settings{ + margin-top:17px; + border:1px dashed var(--504945); + padding:7px 10px 0; +} + +.web .setting{ + margin-bottom:17px; +} + +.web .setting .title{ + font-size:14px; +} + +.web .settings-submit{ + margin:17px 10px; +} + +.web .settings-submit input{ + float:right; +} + +.web .settings-submit a{ + margin-right:17px; + color:var(--bdae93); +} + +/* + About page +*/ +.about a{ + color:var(--bdae93); +} + +.about h1, .about h2{ + margin-top:17px; +} + +.about table{ + margin-bottom:17px; +} + +.about table a{ + display:inline; +} + + +/* + Syntax highlight +*/ +.c-comment{ + color:var(--comment); +} +.c-default{ + color:var(--default); +} +.c-html{ + color:var(--html); +} +.c-keyword{ + color:var(--keyword); + font-weight:bold; +} +.c-string{ + color:var(--string); +} + +/* + Instances page +*/ +.instances table{ + white-space:nowrap; + margin-top:17px; +} + +.instances a{ + color:var(--bdae93); +} + +.instances tbody tr:nth-child(even){ + background:var(--282828); +} + +.instances thead{ + outline:1px solid var(--928374); + outline-offset:-1px; + background:var(--3c3836); + user-select:none; + z-index:2; + position:sticky; + top:0; +} + +.instances th{ + cursor:row-resize; +} + +.instances th:hover{ + background:var(--504945); +} + +.instances tbody{ + outline:1px solid var(--504945); + outline-offset:-1px; + position:relative; + top:-1px; +} + +.instances tbody tr:hover{ + background:var(--3c3836); + cursor:pointer; +} + +.instances .arrow{ + display:inline-block; + position:relative; + top:6px; + margin-right:7px; + width:0; + height:0; + border:6px solid transparent; + border-top:10px solid var(--bdae93); +} + +.instances .arrow.up{ + top:0; + border:6px solid transparent; + border-bottom:10px solid var(--bdae93); +} + +.instances th, .instances td{ + padding:4px 7px; + width:0; +} + +.instances .extend{ + width:unset; + overflow:hidden; + max-width:200px; +} + +.instances .popup-wrapper{ + display:none; + position:fixed; + left:50%; + top:50%; + transform:translate(-50%, -50%); + width:800px; + max-width:100%; + max-height:100%; + overflow-x:auto; + padding:17px; + box-sizing:border-box; + pointer-events:none; + z-index:3; +} + +.instances .popup{ + border:1px solid var(--928374); + background:var(--282828); + padding:7px 10px; + pointer-events:initial; +} + +.instances ul{ + padding-left:20px; +} + +.instances .go-back{ + margin-top:17px; + display:inline-block; +} + + +/* + Responsive image +*/ +@media only screen and (max-width: 1454px){ #images .image-wrapper{ width:25%; } } +@media only screen and (max-width: 1161px){ #images .image-wrapper{ width:33.3333%; } } +@media only screen and (max-width: 750px){ #images .image-wrapper{ width:50%; } } +@media only screen and (max-width: 450px){ #images .image-wrapper{ width:100%; } } + + +/* + Responsive design +*/ +@media only screen and (max-width: 1550px){ + + .web .right-right, + .web .right-left{ + float:none; + width:initial; + padding:0 0 0 15px; + } + + .web .left, + .searchbox, + #images .infobox{ + width:60%; + } + + .web .right-wrapper{ + width:40%; + } +} + +@media only screen and (max-width: 1000px){ + form{ + padding-top:27px; + } + + .navigation{ + left:0; + right:unset; + line-height:22px; + } + + .nextpage.img{ + width:initial; + } + + .web .right-right, + .web .right-left{ + border:none; + padding:0; + } + + .web .right-wrapper{ + float:none; + padding:0; + width:initial; + } + + .web .left, + .searchbox{ + width:100%; + } + + body:not(.instances) table td{ + display:block; + width:100%; + } + + table a{ + padding:0; + } + + .web.has-answer .left::before{ + display:block; + content:"Results"; + font-size:24px; + font-weight:bold; + margin-bottom:17px; + color:var(--bdae93); + } + + .web .answer{ + max-height:200px; + } + + .web .wiki-head tr td:first-child, + .web .info-table tr td:first-child{ + text-decoration:underline; + } + + #images .infobox{ + width:100%; + } +} diff --git a/static/themes/Catppuccin Latte.css b/static/themes/Catppuccin Latte.css new file mode 100644 index 0000000..7c70549 --- /dev/null +++ b/static/themes/Catppuccin Latte.css @@ -0,0 +1,20 @@ +:root{ + /* background */ + --1d2021: #eff1f5; + --282828: #eff1f5; + --3c3836: #dce0e8; + --504945: #5c5f77; + + /* font */ + --928374: #8c8fa1; + --a89984: #4c4f69; + --bdae93: #4c4f69; + --8ec07c: #df8e1d; + --ebdbb2: #4c4f69; + + /* code highlighter */ + --comment: #e64553; + --default: #eff1f5; + --keyword: #df8e1d; + --string: #209fb5; +} diff --git a/static/themes/Catppuccin Mocha.css b/static/themes/Catppuccin Mocha.css new file mode 100644 index 0000000..03a3fa8 --- /dev/null +++ b/static/themes/Catppuccin Mocha.css @@ -0,0 +1,20 @@ +:root{ + /* background */ + --1d2021: #1e1e2e; + --282828: #313244; + --3c3836: #45475a; + --504945: #585b70; + + /* font */ + --928374: #bac2de; + --a89984: #a6adc8; + --bdae93: #cdd6f4; + --8ec07c: #a6e3a1; + --ebdbb2: #f9e2af; + + /* code highlighter */ + --comment: #f5e0dc; + --default: #f2cdcd; + --keyword: #fab387; + --string: #74c7ec; +} diff --git a/static/themes/Cream.css b/static/themes/Cream.css new file mode 100644 index 0000000..3d6b615 --- /dev/null +++ b/static/themes/Cream.css @@ -0,0 +1,31 @@ +:root{ + /* background */ + --1d2021: #bdae93; + --282828: #a89984; + --3c3836: #a89984; + --504945: #504945; + + /* font */ + --928374: #1d2021; + --a89984: #282828; + --bdae93: #3c3836; + --8ec07c: #52520e; + --ebdbb2: #1d2021; + + /* code highlighter */ + --comment: #6a4400; + --default: #d4be98; + --keyword: #4a4706; + --string: #076678; + + /* color codes for instance list */ + --green: #636311; + --yellow: #8a6214; + --red: #711410; +} + +.autocomplete .entry:hover, +.instances th:hover +{ + background:#928374; +} diff --git a/static/themes/Dark Christmas.css b/static/themes/Dark Christmas.css new file mode 100644 index 0000000..0a097f1 --- /dev/null +++ b/static/themes/Dark Christmas.css @@ -0,0 +1,95 @@ +body{ + background-image:url("/static/misc/christmas-dark-bg.png"); +} + +.home::before{ + content:""; + position:fixed; + top:0; + left:0; + width:100%; + height:100%; + background-image:url("/static/misc/snow.png"); + pointer-events:none; + z-index:-1; + animation:snowfall 12s linear infinite; + opacity:.6; +} + +.home{ + background:#1d2021; +} + +@keyframes snowfall{ + from{ + background-position:0% 0px; + } + + to{ + background-position:0% 600px; + } +} + +.web .answer::after{ + display:none; +} + +:root{ + /* background */ + --1d2021: #1d2021; + --282828: #282828; + --3c3836: #3c3836; + --504945: #504945; + + /* font */ + --928374: #928374; + --a89984: #bdae93; + --bdae93: #d5c4a1; + --8ec07c: #8ec07c; + --ebdbb2: #ebdbb2; + + /* code highlighter */ + --comment: #9e8e73; + --default: #d4be98; + --keyword: #d8a657; + --string: #7daea7; + + /* color codes for instance list */ + --green: #b8bb26; + --yellow: #d8a657; + --red: #fb4934; +} + +.web .wiki-head table, .about table, .web .info-table, .instances table{ + background:#1d202170; + color:#bdae93; +} + +.web .wiki-head tr:nth-child(odd), .about table tr:nth-child(odd), .web .info-table tr:nth-child(even), .nextpage, .spoiler-button, .instances tbody tr:nth-child(even){ + background:#28282870; + color:#bdae93; +} + +.instances tbody tr:hover{ + background:#3c383690; +} + +.wiki-head .description{ + overflow:initial !important; +} + +.wiki-head .photo{ + position:relative; +} + +.wiki-head .photo::after{ + content:""; + position:absolute; + width:100px; + height:100px; + background-image:url("/static/misc/christmas-hat.png"); + background-size:contain; + top:-61px; + left:-31px; + transform:rotate(310deg); +} diff --git a/static/themes/Gore's shitty theme.css b/static/themes/Gore's shitty theme.css new file mode 100644 index 0000000..d32f44a --- /dev/null +++ b/static/themes/Gore's shitty theme.css @@ -0,0 +1,322 @@ +:root{ + --1d2021:#1d2021; + --282828:#282828; + --3c3836:#3c3836; + --504945:#504945; + + /* font */ + --928374:#928374; + --a89984:#c9c5bf; + --bdae93:#bdae93; + --8ec07c:#8ec07c; + --ebdbb2:#ebdbb2; +} + +body{ + padding:15px 4% 40px; + margin:unset; +} + +h1, h2, h3, h4, h5, h6{ + padding:0; + margin:0 0 7px 0; + line-height:initial; + color:var(--bdae93); +} + +h3, h4, h5, h6{ + margin-bottom:14px; +} + +/* + Web styles +*/ + +.searchbox input[type="submit"]{ + float:right; + cursor:pointer; + padding:0 10px; + border-left:1px solid var(--504945); + background:#723c0b; +} + +.searchbox input{ + all:unset; + line-height:36px; + box-sizing:border-box; + height:36px; +} + +.searchbox:focus-within{ + border:1px solid #ee8a9c; +} + +.autocomplete{ + display:none; + position:absolute; + top:35px; + left:-1px; + right:-1px; + background:var(--282828); + border:1px solid var(--504945); + border-top:none; + border-radius:0 0 2px 2px; + z-index:10; +} + +.autocomplete .entry{ + overflow:hidden; + padding:4px 10px; + cursor:pointer; +} + +.autocomplete .title{ + float:left; +} + +.autocomplete .subtext{ + float:right; + font-size:14px; + color:var(--928374); + margin-left:7px; +} + +/* Tabs */ + +.tabs{ + padding-bottom:0px; +} + +.tabs .tab{ + text-decoration:none; + color:#d3d0c1; + padding:0px 10px; + display:inline-block; +} + +.tabs .tab.selected{ + border-bottom:2px solid #fc92a5; +} + +/* Filters */ +.filters{ + padding-bottom:12px; + padding-top:7px; + margin-bottom:7px; + background-color:#232525; +} + +.filters .filter{ + display:inline-block; + margin-right:7px; +} + +.filters .filter .title{ + font-size:13px; +} + +.filters .filter input, +.filters .filter select{ + all:unset; + display:block; + border:1px solid var(--504945); + border-radius:2px; + font-size:14px; + padding:0 2px; + width:127px; + height:22px; +} + +/* infobox */ +.web .infobox{ + border:1px dashed var(--504945); + padding:10px; + margin-bottom:17px; +} + +.web .infobox .code{ + white-space:initial; +} + +.web .infobox ul{ + padding-left:27px; + margin-bottom:0; +} + +.web .infobox a{ + color:var(--bdae93); +} + +.web .infobox a:hover{ + text-decoration:underline; +} + +/* text-result */ + +.web .url .part{ + font-size:15px; + text-decoration:none; + color:#90c186; +} + +.web .separator::before{ + content:"/"; + padding:0 4px; + color:#5ab442; + font-size:12px; +} + +.web .hover{ + display:block; + text-decoration:none; + color:var(--a89984); + overflow:hidden; + clear:left; + padding-top:3px; +} + +.web .text-result .title{ + font-size:18px; + color:#81b5f4; + margin-bottom:5px; +} + +.web .text-result a:visited .title{ + color:#aa77c1 !important; +} + +.theme-white .web .text-result a:visited .title{ + color:#9760b1 !important; +} + +.web .text-result .greentext{ + font-size:14px; + color:var(--bdae93); +} + +/* favicon */ + +.favicon-dropdown a{ + text-decoration:none; + color:#d3d0c1; + display:block; + padding:2px 7px 2px 5px; + font-size:13px; +} + +.web .favicon img, .favicon-dropdown img{ + margin:3px 7px 0 0; + height:16px; + font-size:12px; + line-height:16px; + display:block; + text-align:left; +} + +.web .sublinks{ + padding:17px 10px; + font-size:15px; + color:var(--#928374); +} + +.web .text-result .sublinks:last-child{ + padding-bottom:0; +} + +/* Wikipedia head */ +.wiki-head{ + padding:5px; + background-color:#322f2b; +} + +/* + Images tab +*/ + +#images{ + line-height:15px; + overflow:hidden; + margin-bottom:10px; +} + +#images .image-wrapper{ + width:20%; + float:left; +} + +#images .image .title{ + white-space:nowrap; + overflow:hidden; + margin-bottom:7px; + font-weight:bold; + color:var(--bdae93); +} + +#popup-status{ + display:none; + position:fixed; + top:0; + left:0; + width:100%; + height:35px; + background:var(--1d2021); + border-bottom:1px solid var(--928374); +} + +/* + Settings page +*/ + +.web .settings-submit a{ + margin-right:17px; + color:#bdae93; +} + +/* + Responsive image +*/ +@media only screen and (max-width:1454px){ + #images .image-wrapper{ + width:25%; + } +} + +@media only screen and (max-width:1161px){ + #images .image-wrapper{ + width:25%; + } +} + +@media only screen and (max-width:750px){ + #images .image-wrapper{ + width:50%; + } +} + +@media only screen and (max-width:450px){ + #images .image-wrapper{ + width:100%; + } +} + +/* + Responsive design +*/ + +@media only screen and (max-width:1550px){ +.web .left, + .searchbox{ + width:60%; + } +} + +@media only screen and (max-width:1100px){ +.web .left, + .searchbox{ + width:100%; + } +} + +.type{ + color:var(--bdae93); +} diff --git a/static/themes/Kuuro.css b/static/themes/Kuuro.css new file mode 100644 index 0000000..fdb60e5 --- /dev/null +++ b/static/themes/Kuuro.css @@ -0,0 +1,17 @@ +:root{ + --1d2021: #101010; + --282828: #1a1a1a; + --3c3836: #1e1e1e; + --504945: #232323; + + --928374: #949494; + --a89984: #d2d2d2; + --bdae93: #d2d2d2; + --8ec07c: #99c794; + --ebdbb2: #d2d2d2; + + --comment: #5f6364; + --default: #cccece; + --keyword: #c594c5; + --string: #99c794; +}
\ No newline at end of file diff --git a/static/themes/White Christmas.css b/static/themes/White Christmas.css new file mode 100644 index 0000000..5368596 --- /dev/null +++ b/static/themes/White Christmas.css @@ -0,0 +1,94 @@ +body{ + background:#e7e7e7; + background-image:url("/static/misc/christmas-white-bg.png"); +} + +.home::before{ + content:""; + position:fixed; + top:0; + left:0; + width:100%; + height:100%; + background:#b9b5b380; + background-image:url("/static/misc/snow.png"); + pointer-events:none; + z-index:-1; + animation:snowfall 12s linear infinite; +} + +.web .answer::after{ + display:none; +} + +@keyframes snowfall{ + from{ + background-position:0% 0px; + } + + to{ + background-position:0% 600px; + } +} + +:root{ + /* background */ + --1d2021: #bdae93; + --282828: #e7e7e7; + --3c3836: #e7e7e7; + --504945: #504945; + + /* font */ + --928374: #1d2021; + --a89984: #282828; + --bdae93: #3c3836; + --8ec07c: #52520e; + --ebdbb2: #1d2021; + + /* code highlighter */ + --comment: #6a4400; + --default: #d4be98; + --keyword: #4a4706; + --string: #076678; + + /* color codes for instance list */ + --green: #636311; + --yellow: #8a6214; + --red: #711410; +} + +.autocomplete .entry:hover{ + background:#92837480; +} + +.web .wiki-head table, .about table, .web .info-table, .instances table{ + background:#a8998470; +} + +.web .wiki-head tr:nth-child(odd), .about table tr:nth-child(odd), .web .info-table tr:nth-child(even), .nextpage, .spoiler-button, .instances tbody tr:nth-child(even){ + background:#bdae9370; +} + +.instances tbody tr:hover{ + background:#92837480; +} + +.wiki-head .description{ + overflow:initial !important; +} + +.wiki-head .photo{ + position:relative; +} + +.wiki-head .photo::after{ + content:""; + position:absolute; + width:100px; + height:100px; + background-image:url("/static/misc/christmas-hat.png"); + background-size:contain; + top:-61px; + left:-31px; + transform:rotate(310deg); +} diff --git a/static/themes/Wine.css b/static/themes/Wine.css new file mode 100644 index 0000000..2d79f02 --- /dev/null +++ b/static/themes/Wine.css @@ -0,0 +1,40 @@ +:root +{ + --accent : #f79e98; + --1d2021 : #180d0c; + --282828 : #180d0c; + --3c3836 : #251615; + --504945 : #251615; + --928374 : var(--accent); + --a89984 : #d8c5c4; + --bdae93 : #d8c5c4; + --8ec07c : var(--accent); + --ebdbb2 : #d8c5c4; + --comment: #928374; + --default: #DCC9BC; + --keyword: #F07342; + --string : var(--accent); + --green : #959A6B; + --yellow : #E39C45; + --red : #CF223E; + --white : var(--a89984); + --black : var(--1d2021); + --hover : #b18884 +} + + a.link, a { color: var(--accent); text-decoration: none; } + .searchbox { width: 23%; } + .filters filter select { color: #E39C45; } + .web .separator::before { color: var(--white) } + .searchbox input[type="text"]::placeholder { color: var(--white); } + a.link:hover + { + color: var(--hover); + text-shadow: 0 0 .2rem var(--hover); + } + .code-inline + { border-color: var(--default); font-family: monospace;} + .home #center a + { color: var(--accent); } + .home .subtext + { color: var(--white); } diff --git a/static/themes/gentoo.css b/static/themes/gentoo.css new file mode 100644 index 0000000..b727108 --- /dev/null +++ b/static/themes/gentoo.css @@ -0,0 +1,20 @@ +:root{ + /* background */ + --1d2021: #21222d; + --282828: #393657; + --3c3836: #27273c; + --504945: #aa85e1; + + /* font */ + --928374: #906be3; + --a89984: #9794ac; + --bdae93: #cec0f2; + --8ec07c: #5db6e1; + --ebdbb2: #b194f5; + + /* code highlighter */ + --comment: #a0c0a4; + --default: #f00; + --keyword: #9376e4; + --string: #ecd78f; +} |