Compare commits

..

No commits in common. 'master' and 'toast' have entirely different histories.

  1. 1
      .gitignore
  2. 29
      index.html
  3. 1
      json/changelogs/1.4.4.json
  4. 1
      json/changelogs/1.5.0.json
  5. 1
      json/changelogs/1.5.1.json
  6. 1
      json/changelogs/1.6.0.json
  7. 1
      json/changelogs/1.6.1.json
  8. 1
      json/changelogs/1.6.2.json
  9. 1
      json/changelogs/1.6.3.json
  10. 1
      json/changelogs/1.6.4.json
  11. 1
      json/changelogs/1.7.0.json
  12. 1
      json/changelogs/1.7.1.json
  13. 10
      json/ctx.json
  14. 23
      json/qa.json
  15. 18
      package-lock.json
  16. 3
      package.json
  17. 5
      scripts/contextmenu/compress-selected.js
  18. 105
      scripts/contextmenu/compress.js
  19. 23
      scripts/contextmenu/createcontext.js
  20. 105
      scripts/contextmenu/decompress.js
  21. 79
      scripts/contextmenu/delete-folder.js
  22. 1
      scripts/contextmenu/hidecontext.js
  23. 5
      scripts/contextmenu/newfolder.js
  24. 36
      scripts/contextmenu/pin.js
  25. 94
      scripts/contextmenu/rename-folder.js
  26. 1
      scripts/fileview/load/load.js
  27. 20
      scripts/fileview/load/render.js
  28. 12
      scripts/fileview/selectfolder.js
  29. 33
      scripts/modal/common/error.js
  30. 4
      scripts/modal/post.js
  31. 8
      scripts/startup/changelog.js
  32. 1
      scripts/startup/initcontext.js
  33. 41
      scripts/startup/initsidebar.js
  34. 1
      scripts/startup/preload.js
  35. 3
      scripts/startup/setbuttons.js
  36. 6
      styles/context.css
  37. 2
      styles/files.css
  38. 18
      styles/modal.css
  39. 42
      styles/sidebar.css
  40. 50
      styles/styles.css

1
.gitignore vendored

@ -1,3 +1,2 @@
node_modules/ node_modules/
out/ out/
favorites.json

@ -3,7 +3,6 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="./styles/styles.css" rel="stylesheet"> <link href="./styles/styles.css" rel="stylesheet">
<link href='./styles/files.css' rel='stylesheet'> <link href='./styles/files.css' rel='stylesheet'>
@ -11,43 +10,16 @@
<link href='./styles/context.css' rel='stylesheet'> <link href='./styles/context.css' rel='stylesheet'>
<link href='./styles/modal.css' rel='stylesheet'> <link href='./styles/modal.css' rel='stylesheet'>
<link href="./styles/toast.css" rel="stylesheet"> <link href="./styles/toast.css" rel="stylesheet">
<link href="./styles/sidebar.css" rel="stylesheet">
<title>FileKade</title> <title>FileKade</title>
</head> </head>
<body> <body>
<div id="title-container"> <div id="title-container">
<div id="title-container-wrapper">
<div id="title-sub-container"> <div id="title-sub-container">
<p id="title" class="nosel">FileKade</p> <p id="title" class="nosel">FileKade</p>
</div> </div>
<div id="title-controls-container">
<div class="close-button-wrapper">
<div id="close-window" class="close-button"></div>
</div>
</div>
</div>
</div> </div>
<div id="master">
<div id="sidebar">
<div id="favorites">
<div id="favorites-wrapper">
<div>
<div>
<h2 class="favorites-header nosel">Quick Access</h2>
</div>
<div id="favorites-container"></div>
</div>
<div>
<div>
<h2 class="favorites-header nosel">Favorites</h2>
</div>
<div id="custom-favorites-container"></div>
</div>
</div>
</div>
</div>
<div id='container'> <div id='container'>
<div id='controls' class='controls'> <div id='controls' class='controls'>
<div id='header-buttons'></div> <div id='header-buttons'></div>
@ -63,7 +35,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div id="ctx"></div> <div id="ctx"></div>
<div id="toast-container"></div> <div id="toast-container"></div>

@ -1 +0,0 @@
{"log":{"Toasts":["Toasts now have moving timers","They'll soon pause on hover. (Soon:tm:)"]},"version":{"name":"Alpha","semver":"1.4.4"}}

@ -1 +0,0 @@
{"log":{"Sidebar":["There's now a sidebar! :D","The sidebar properly flows with other elements. Have to add this as a changelog cause it took some love","There are some default quick access buttons for Windows","The quick access buttons do in fact work"]},"version":{"name":"Alpha","semver":"1.5.0"}}

@ -1 +0,0 @@
{"log":{"Bugs":["Changelogs work in production","My brain is quite small yes yes","Hope this doesn't break anything else *shrug*"]},"version":{"name":"Alpha","semver":"1.5.1"}}

@ -1 +0,0 @@
{"log":{"Context Menu":["The right click menu now recognizes when you're on a folder","The 'rename' feature in context menu works!"],"Sidebar":["Added the custom favorites group","Doesn't work yet though"]},"version":{"name":"Alpha","semver":"1.6.0"}}

@ -1 +0,0 @@
{"log":{"Toasts":["Toasts now pause when you hover over them","This feature is somewhat experimental","Changed the internals of toasts. More butter. Mmmmmmbutter"]},"version":{"name":"Alpha","semver":"1.6.1"}}

@ -1 +0,0 @@
{"log":{"Sidebar":["The option to pin a folder to the sidebar now works","These pins save between restarts!"]},"version":{"name":"Alpha","semver":"1.6.2"}}

@ -1 +0,0 @@
{"log":{"Folder Deletion":["You can now delete folders by right clicking on them","Includes an obligatory confirmation to make sure you're sure you want to delete the folder :)"],"Bugs":["Error modals are actually closable now kekw","Right click will only show folder options on folders now"]},"version":{"name":"Alpha","semver":" 1.6.3"}}

@ -1 +0,0 @@
{"log":{"Misc":["Small update here","Cleaned up a few bugs too small to really talk about here","Fixed a really nasty bug where the app would try to delete a folder a whole bunch of times","Clicking on the same file again won't make it visibly un-click","A folder will select itself after it's created"]},"version":{"name":"Alpha","semver":"1.6.4"}}

@ -1 +0,0 @@
{"log":{"File opening":["Files now open!!","I know right, a file explorer that opens files. Revolutionary.","This feature is dependent on you being on a version of Windows where PowerShell exists. Whether or not it works every single time is a bit untested, so it could cause some twitchy stuff to happen. This has not been written for Linux or Mac yet."]},"version":{"name":"Alpha","semver":"1.7.0"}}

@ -1 +0,0 @@
{"log":{"Zipping":["You can now zip folders!","So far, this only applies to the directory you're currently viewing. It will not *yet* zip the directory you have selected"]},"version":{"name":"Alpha","semver":"1.7.1"}}

@ -1,9 +1,6 @@
[ [
[ [
{"name": "New Folder", "id": "ctx-new-folder", "onclick": "newfolder"}, {"name": "New Folder", "id": "ctx-new-folder", "onclick": "newfolder"}
{"name": "Compress", "id": "ctx-compress", "onclick": "compress"},
{"name": "Compress Selected", "id": "ctx-compress-selected", "onclick": "compress-selected"},
{"name": "Decompress", "id": "ctx-decompress", "onclick": "decompress"}
], ],
[ [
{"name": "Sort by: Name", "id": "ctx-sort-by", "onclick": "changesort"}, {"name": "Sort by: Name", "id": "ctx-sort-by", "onclick": "changesort"},
@ -13,10 +10,5 @@
{"name": "Reload", "id": "ctx-reload", "onclick": "reload"}, {"name": "Reload", "id": "ctx-reload", "onclick": "reload"},
{"name": "Refresh", "id": "ctx-refresh", "onclick": "refresh"}, {"name": "Refresh", "id": "ctx-refresh", "onclick": "refresh"},
{"name": "Options", "id": "ctx-options", "onclick": "options"} {"name": "Options", "id": "ctx-options", "onclick": "options"}
],
[
{"name": "Rename", "id": "ctx-rename-folder", "onclick": "rename-folder"},
{"name": "Pin to Favorites", "id": "ctx-pin", "onclick": "pin"},
{"name": "Delete", "id": "ctx-delete-folder", "onclick": "delete-folder"}
] ]
] ]

@ -1,23 +0,0 @@
{
"default": [
{
"name": "Desktop",
"win32": "{r}\\Desktop"
}, {
"name": "Documents",
"win32": "{r}\\Documents"
}, {
"name": "Pictures",
"win32": "{r}\\Pictures"
}, {
"name": "Videos",
"win32": "{r}\\Videos"
}, {
"name": "Music",
"win32": "{r}\\Music"
}, {
"name": "Downloads",
"win32": "{r}\\Downloads"
}
]
}

18
package-lock.json generated

@ -1,15 +1,14 @@
{ {
"name": "filekade", "name": "filekade",
"version": "1.7.1", "version": "1.4.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "filekade", "name": "filekade",
"version": "1.7.1", "version": "1.4.3",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"adm-zip": "^0.5.9",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"generator-code": "^1.6.5" "generator-code": "^1.6.5"
@ -1994,14 +1993,6 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true "dev": true
}, },
"node_modules/adm-zip": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==",
"engines": {
"node": ">=6.0"
}
},
"node_modules/agent-base": { "node_modules/agent-base": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -15227,11 +15218,6 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true "dev": true
}, },
"adm-zip": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg=="
},
"agent-base": { "agent-base": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",

@ -1,6 +1,6 @@
{ {
"name": "filekade", "name": "filekade",
"version": "1.7.1", "version": "1.4.3",
"description": "A file explorer (primarily a learning experience for me)", "description": "A file explorer (primarily a learning experience for me)",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
@ -14,7 +14,6 @@
"author": "WubzyGD", "author": "WubzyGD",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"adm-zip": "^0.5.9",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"generator-code": "^1.6.5" "generator-code": "^1.6.5"

@ -1,5 +0,0 @@
const path = require('path');
module.exports = () => {
return require('./compress')(undefined, path.join(window.kade.cpath, window.kade.currentFolder));
};

@ -1,105 +0,0 @@
const fs = require('fs');
const path = require('path');
const az = require('adm-zip');
const Mousetrap = require('../dep/mousetrap');
const lightRefresh = require('../fileview/lightrefresh');
const preModal = require('../modal/pre');
const postModal = require('../modal/post');
const showError = require('../modal/common/error');
const clearModals = require('../modal/clearmodals');
const newToast = require('../toast/createtoast');
const refresh = require('../fileview/refresh');
module.exports = (event, pathToCompress) => {
let zip = new az();
if (!pathToCompress) {pathToCompress = window.kade.cpath;}
if (window.kade.modal) {return;}
preModal('compress-folder-modal-container');
let modalOut = document.createElement('div');
modalOut.className = 'modal';
modalOut.id = 'compress-folder-modal-container';
document.body.appendChild(modalOut);
let modal = document.createElement('div');
modal.className = 'modal-wrapper';
modalOut.appendChild(modal);
let title = document.createElement('h2');
title.innerHTML = 'Compress Folder';
modal.appendChild(title);
let text = document.createElement('p');
text.innerHTML = "Please name the zip you'd like to compress to.";
modal.appendChild(text);
let cont = document.createElement('div');
cont.className = 'button-container';
modal.appendChild(cont);
let input = document.createElement('input');
input.placeholder = pathToCompress.split(/\\+|\/+/gm).reverse()[0];
input.value = input.placeholder;
input.id = 'compress-folder-input';
let lastIn = '';
input.oninput = () => {
if (!input.value.match(/^[a-zA-Z0-9-_() ]*$/gm)) {input.value = lastIn;}
else {lastIn = input.value;}
};
cont.appendChild(input);
let conf = document.createElement('button');
conf.innerHTML = 'Create';
conf.onclick = () => {
try {
input.value = input.value.trim();
if (input.value.endsWith('.zip')) {input.value = input.value.slice(0, input.value.length - 4);}
if (!input.value.length) {return;}
if (fs.existsSync(path.join(window.kade.cpath, `${input.value}.zip`))) {
if (!input.value.match(/^.+\(\d\)$/gm)) {input.value += ' (1)';}
else {
let tempstr = input.value.split('');
tempstr[input.value.length - 2] = `${Number(input.value.charAt(input.value.length - 2)) + 1}`;
input.value = tempstr.join('');
}
return;
}
input.style.display = 'none';
conf.style.display = 'none';
cont.style.display = 'none';
text.innerHTML = "Please wait a moment...";
closeWrap.style.display = 'none';
zip.addLocalFolderPromise(pathToCompress).then(() => {
title.innerHTML += " - In Progress..."
text.innerHTML = "Your folder is being compressed. Please wait a moment.<br><br>This may take some time...";
let bar = document.createElement('div');
bar.className = "loading-bar";
modal.appendChild(bar);
zip.writeZipPromise(`${window.kade.cpath}/${input.value}${input.value.endsWith('.zip') ? '' : '.zip'}`, {overwrite: true}).then(() => {
newToast("Folder compressed", [`The current folder was compressed into "${input.value}" successfully`, `<em>${window.kade.cpath}/${input.value}</em>`], undefined, false, 5);
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
});
} catch {
newToast("Folder not Compressed", "An error caused that folder to not be compressed.", "#b24355", false, 5, () => {showError("Folder Creation", "There was an unknown error while trying to compress that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");});
clearModals();
postModal(modalOut.id);
}
};
cont.appendChild(conf);
input.focus();
let msm = new Mousetrap(modal);
msm.bind('esc', () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
msm.bind('enter', () => {conf.click();});
let close = document.createElement('a');
close.className = 'close-button';
close.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
};
let closeWrap = document.createElement('div');
closeWrap.className = 'close-button-wrapper';
modal.appendChild(closeWrap);
closeWrap.appendChild(close);
};

@ -3,29 +3,6 @@ module.exports = (e, target, window) => {
window.kade.context = true; window.kade.context = true;
let ctx = document.getElementById('ctx'); let ctx = document.getElementById('ctx');
ctx.style.display = 'block'; ctx.style.display = 'block';
const ctxf = document.getElementById('ctx-folder');
const compress = document.getElementById('ctx-compress');
const compsel = document.getElementById('ctx-compress-selected');
if (target.classList.contains('folder') || (target.parentElement && target.parentElement.classList.contains('folder'))) {
ctxf.style.display = 'block';
ctxf.previousElementSibling.style.display = 'block';
if (target.classList.contains('folder')) {window.kade.currentFolder = target.children[1].innerHTML.trim();}
else {window.kade.currentFolder = target.parentElement.children[1].innerHTML.trim();}
compress.style.display = 'none';
compsel.style.display = 'block';
} else {
ctxf.style.display = 'none';
ctxf.previousElementSibling.style.display = 'none';
compress.style.display = 'block';
compsel.style.display = 'none';
}
if (target.classList.contains('zip') || (target.parentElement && target.parentElement.classList.contains('zip'))) {
if (target.classList.contains('zip')) {window.kade.currentFolder = target.children[1].innerHTML.trim();}
else {window.kade.currentFolder = target.parentElement.children[1].innerHTML.trim();}
document.getElementById('ctx-decompress').style.display = 'block';
} else {
document.getElementById('ctx-decompress').style.display = 'none';
}
ctx.style.left = `${Math.min(e.pageX, (window.innerWidth - (ctx.clientWidth + 2)))}px`; ctx.style.left = `${Math.min(e.pageX, (window.innerWidth - (ctx.clientWidth + 2)))}px`;
ctx.style.top = `${Math.min(e.pageY, ((window.innerHeight + window.scrollY) - (ctx.clientHeight + 2)))}px`; ctx.style.top = `${Math.min(e.pageY, ((window.innerHeight + window.scrollY) - (ctx.clientHeight + 2)))}px`;
}; };

@ -1,105 +0,0 @@
const fs = require('fs');
const path = require('path');
const az = require('adm-zip');
const Mousetrap = require('../dep/mousetrap');
const lightRefresh = require('../fileview/lightrefresh');
const preModal = require('../modal/pre');
const postModal = require('../modal/post');
const showError = require('../modal/common/error');
const clearModals = require('../modal/clearmodals');
const newToast = require('../toast/createtoast');
const refresh = require('../fileview/refresh');
module.exports = (event, pathToCompress) => {
if (!fs.existsSync(path.join(window.kade.cpath, window.kade.currentFolder))) {
return newToast("Decompression failed", "For some reason, that zip archive could not be found.");
}
let zip = new az(path.join(window.kade.cpath, window.kade.currentFolder));
if (!pathToCompress) {pathToCompress = window.kade.currentFolder;}
if (window.kade.modal) {return;}
preModal('decompress-folder-modal-container');
let modalOut = document.createElement('div');
modalOut.className = 'modal';
modalOut.id = 'decompress-folder-modal-container';
document.body.appendChild(modalOut);
let modal = document.createElement('div');
modal.className = 'modal-wrapper';
modalOut.appendChild(modal);
let title = document.createElement('h2');
title.innerHTML = 'Decompress Archive';
modal.appendChild(title);
let text = document.createElement('p');
text.innerHTML = "Please name the zip you'd like to decompress to.";
modal.appendChild(text);
let cont = document.createElement('div');
cont.className = 'button-container';
modal.appendChild(cont);
let input = document.createElement('input');
input.placeholder = pathToCompress.split(/\\+|\/+/gm).reverse()[0];
input.placeholder = input.placeholder.slice(0, input.placeholder.length - 4);
input.value = input.placeholder;
input.id = 'decompress-folder-input';
let lastIn = '';
input.oninput = () => {
if (!input.value.match(/^[a-zA-Z0-9-_() ]*$/gm)) {input.value = lastIn;}
else {lastIn = input.value;}
};
cont.appendChild(input);
let conf = document.createElement('button');
conf.innerHTML = 'Create';
conf.onclick = () => {
try {
input.value = input.value.trim();
if (!input.value.length) {return;}
if (fs.existsSync(path.join(window.kade.cpath, input.value))) {
if (!input.value.match(/^.+\(\d\)$/gm)) {input.value += ' (1)';}
else {
let tempstr = input.value.split('');
tempstr[input.value.length - 2] = `${Number(input.value.charAt(input.value.length - 2)) + 1}`;
input.value = tempstr.join('');
}
return;
}
input.style.display = 'none';
conf.style.display = 'none';
cont.style.display = 'none';
closeWrap.style.display = 'none';
title.innerHTML += " - In Progress..."
text.innerHTML = "Your arhive is being decompressed. Please wait a moment.<br><br>This may take some time...";
let bar = document.createElement('div');
bar.className = "loading-bar";
modal.appendChild(bar);
zip.extractAllToAsync(path.join(window.kade.cpath, input.value), undefined, undefined, () => {
newToast("Archive decompressed", [`The current folder was decompressed into "${input.value}" successfully`, `<em>${window.kade.cpath}/${input.value}</em>`], undefined, false, 5, () => refresh(`${window.kade.cpath}/${input.value}`));
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
} catch {
newToast("Archive not Decompressed", "An error caused that folder to not be decompressed.", "#b24355", false, 5, () => {showError("Folder Creation", "There was an unknown error while trying to decompress that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");});
clearModals();
postModal(modalOut.id);
}
};
cont.appendChild(conf);
input.focus();
let msm = new Mousetrap(modal);
msm.bind('esc', () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
msm.bind('enter', () => {conf.click();});
let close = document.createElement('a');
close.className = 'close-button';
close.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
};
let closeWrap = document.createElement('div');
closeWrap.className = 'close-button-wrapper';
modal.appendChild(closeWrap);
closeWrap.appendChild(close);
};

@ -1,79 +0,0 @@
const fs = require('fs');
const path = require('path');
const Mousetrap = require('../dep/mousetrap');
const lightRefresh = require('../fileview/lightrefresh');
const preModal = require('../modal/pre');
const postModal = require('../modal/post');
const showError = require('../modal/common/error');
const clearModals = require('../modal/clearmodals');
const newToast = require('../toast/createtoast');
module.exports = () => {
if (window.kade.modal) {return;}
preModal('delete-folder-modal-container');
let modalOut = document.createElement('div');
modalOut.className = 'modal';
modalOut.id = 'delete-folder-modal-container';
document.body.appendChild(modalOut);
let modal = document.createElement('div');
modal.className = 'modal-wrapper';
modalOut.appendChild(modal);
let title = document.createElement('h2');
title.innerHTML = 'Delete Folder';
modal.appendChild(title);
let text = document.createElement('p');
text.innerHTML = "Are you sure you'd like to delete this folder? Remember, this <b>cannot be undone</b>.";
modal.appendChild(text);
let cont = document.createElement('div');
cont.className = 'button-container';
modal.appendChild(cont);
let conf = document.createElement('button');
conf.innerHTML = 'Delete it!';
let cxl = document.createElement('button');
cxl.innerHTML = "Nevermind";
cxl.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
};
conf.onclick = () => {
try {
fs.rmdirSync(path.join(window.kade.cpath, window.kade.currentFolder));
postModal(modalOut.id);
modalOut.remove();
lightRefresh(window.kade.cpath);
newToast("Folder Deleted", "Your folder has been deleted successfully.");
} catch {
newToast("Folder not Deleted", "An error caused that folder to not be deleted.", "#b24355", false, 5, () => {showError("Folder Deletion", "There was an unknown error while trying to delete that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");});
clearModals();
try {modalOut.remove();} catch {}
postModal(modalOut.id);
}
};
cont.appendChild(conf);
cont.appendChild(cxl);
let iin = document.createElement('input');
iin.className = 'invis';
iin.classList.add('nosel');
cont.appendChild(iin);
iin.focus();
let msm = new Mousetrap(modal);
msm.bind('esc', () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
msm.bind('enter', () => {conf.click();});
let close = document.createElement('a');
close.className = 'close-button';
close.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
};
let closeWrap = document.createElement('div');
closeWrap.className = 'close-button-wrapper';
modal.appendChild(closeWrap);
closeWrap.appendChild(close);
};

@ -1,5 +1,4 @@
module.exports = (window) => { module.exports = (window) => {
document.getElementById('ctx').style.display = 'none'; document.getElementById('ctx').style.display = 'none';
if (!window) {return;}
window.kade.context = false; window.kade.context = false;
}; };

@ -9,7 +9,6 @@ const showError = require('../modal/common/error');
const clearModals = require('../modal/clearmodals'); const clearModals = require('../modal/clearmodals');
const newToast = require('../toast/createtoast'); const newToast = require('../toast/createtoast');
const refresh = require('../fileview/refresh'); const refresh = require('../fileview/refresh');
const selectFolder = require('../fileview/selectfolder');
module.exports = () => { module.exports = () => {
if (window.kade.modal) {return;} if (window.kade.modal) {return;}
@ -65,10 +64,6 @@ module.exports = () => {
newToast("Copied!", "<em>The folder's path has been copied to your clipboard.</em>", "#19df46"); newToast("Copied!", "<em>The folder's path has been copied to your clipboard.</em>", "#19df46");
} }
); );
setTimeout(() => {
selectFolder(input.value);
setTimeout(() => window.kade.cl.click(), 100);
}, 100);
} catch { } catch {
newToast("Folder not Created", "An error caused that folder to not be created.", "#b24355", false, 5, () => {showError("Folder Creation", "There was an unknown error while trying to create that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");}); newToast("Folder not Created", "An error caused that folder to not be created.", "#b24355", false, 5, () => {showError("Folder Creation", "There was an unknown error while trying to create that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");});
clearModals(); clearModals();

@ -1,36 +0,0 @@
const fs = require('fs');
const path = require('path');
const createToast = require('../toast/createtoast');
const refresh = require('../fileview/refresh');
const newToast = require("../toast/createtoast");
module.exports = () => {
if (!fs.existsSync(path.join(__dirname, '../../', '/json/config'))) {fs.mkdirSync(path.join(__dirname, '../../', '/json/config'));}
let pins;
if (fs.existsSync(path.join(__dirname, '../../', '/json/config/favorites.json'))) {
pins = require('../../json/config/favorites.json');
} else {pins = {};}
let fta = window.kade.currentFolder.trim();
if (Object.keys(pins).includes(`${window.kade.cpath.replace(/\\+/gm, '/')}/${fta}`)) {
return createToast("Already pinned", "That folder is already pinned!");
}
let tr = `${window.kade.cpath.replace(/\\+/gm, '/')}/${fta}`;
pins[tr] = fta;
let cfc = document.getElementById('custom-favorites-container');
let fav = document.createElement('div');
['favorites-button', 'folder-pin', 'nosel'].forEach(x => fav.classList.add(x));
fav.innerHTML = fta;
fav.onclick = () => {refresh(tr);};
cfc.appendChild(fav);
createToast(
"Folder Pinned", [`Folder "${fta}" was successfully pinned! You can now access it permanently in your sidebar!"`, `<em>${window.kade.cpath.replace(/\\+/gm, '/')}/${fta}</em>`], undefined, false, 5,
() => {
refresh(tr);
require('electron').clipboard.writeText(`${window.kade.cpath.replace(/\\+/gm, '/')}`);
newToast("Copied!", "<em>The folder's path has been copied to your clipboard.</em>", "#19df46");
}
);
try {fs.writeFileSync(path.join(__dirname, '../../', '/json/config/favorites.json'), JSON.stringify(pins));}
catch {createToast("Error", "Your pin was not saved for some reason. Please restart or reload (ctrl+shift+r) the app and try again.", "#ff557a");}
};

@ -1,94 +0,0 @@
const fs = require('fs');
const path = require('path');
const Mousetrap = require('../dep/mousetrap');
const lightRefresh = require('../fileview/lightrefresh');
const preModal = require('../modal/pre');
const postModal = require('../modal/post');
const showError = require('../modal/common/error');
const clearModals = require('../modal/clearmodals');
const newToast = require('../toast/createtoast');
const refresh = require('../fileview/refresh');
module.exports = () => {
if (window.kade.modal) {return;}
preModal('rename-folder-modal-container');
let modalOut = document.createElement('div');
modalOut.className = 'modal';
modalOut.id = 'rename-folder-modal-container';
document.body.appendChild(modalOut);
let modal = document.createElement('div');
modal.className = 'modal-wrapper';
modalOut.appendChild(modal);
let title = document.createElement('h2');
title.innerHTML = 'Rename Folder';
modal.appendChild(title);
let text = document.createElement('p');
text.innerHTML = "What would you like to rename this folder to?";
modal.appendChild(text);
let cont = document.createElement('div');
cont.className = 'button-container';
modal.appendChild(cont);
let input = document.createElement('input');
input.placeholder = window.kade.currentFolder;
input.id = 'rename-folder-input';
input.value = window.kade.currentFolder;
let lastIn = '';
input.oninput = () => {
if (!input.value.match(/^[a-zA-Z0-9-_() ]*$/gm)) {input.value = lastIn;}
else {lastIn = input.value;}
};
cont.appendChild(input);
let conf = document.createElement('button');
conf.innerHTML = 'Rename';
conf.onclick = () => {
try {
input.value = input.value.trim();
if (!input.value.length) {return;}
if (fs.existsSync(path.join(window.kade.cpath, input.value))) {
if (!input.value.match(/^.+\(\d\)$/gm)) {input.value += ' (1)';}
else {
let tempstr = input.value.split('');
tempstr[input.value.length - 2] = `${Number(input.value.charAt(input.value.length - 2)) + 1}`;
input.value = tempstr.join('');
}
return;
}
fs.renameSync(path.join(window.kade.cpath, window.kade.currentFolder), path.join(window.kade.cpath, input.value));
lightRefresh();
modalOut.remove();
newToast(
"Folder renamed", [`Folder "${window.kade.currentFolder}" was successfully renamed to "${input.value}"`, `<em>${window.kade.cpath}/${input.value}</em>`], undefined, false, 5,
() => {
refresh(`${window.kade.cpath}/${input.value}`);
require('electron').clipboard.writeText(`${window.kade.cpath}`);
newToast("Copied!", "<em>The folder's path has been copied to your clipboard.</em>", "#19df46");
}
);
} catch {
newToast("Folder not Renamed", "An error caused that folder to not be renamed.", "#b24355", false, 5, () => {showError("Folder Renaming", "There was an unknown error while trying to rename that folder. It may be a permissions issue, or the host folder doesn't exist anymore.");});
clearModals();
}
postModal(modalOut.id);
};
cont.appendChild(conf);
input.focus();
let msm = new Mousetrap(modal);
msm.bind('esc', () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
msm.bind('enter', () => {conf.click();});
let close = document.createElement('a');
close.className = 'close-button';
close.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
};
let closeWrap = document.createElement('div');
closeWrap.className = 'close-button-wrapper';
modal.appendChild(closeWrap);
closeWrap.appendChild(close);
}

@ -16,7 +16,6 @@ module.exports = (check=false) => {
for (const file of ldir) { for (const file of ldir) {
let ofile = {}; let ofile = {};
ofile.icon = fileIcon(`${dir}/${file}`, file); ofile.icon = fileIcon(`${dir}/${file}`, file);
ofile.trueName = file;
ofile.name = trimext.includes(path.extname(file)) ? file.slice(0, file.length - path.extname(file).length) : file; ofile.name = trimext.includes(path.extname(file)) ? file.slice(0, file.length - path.extname(file).length) : file;
try {ofile.type = fs.lstatSync(`${dir}/${file}`).isDirectory() ? "File Folder" : (extensions[(file.startsWith('.') ? file : path.extname(file)).slice(1)] || "File");} try {ofile.type = fs.lstatSync(`${dir}/${file}`).isDirectory() ? "File Folder" : (extensions[(file.startsWith('.') ? file : path.extname(file)).slice(1)] || "File");}
catch {ofile.type = `${path.extname(file)} File`.trim();} catch {ofile.type = `${path.extname(file)} File`.trim();}

@ -1,8 +1,4 @@
const cp = require('child_process');
const path = require('path');
const loadHierarchy = require("../hierarchy"); const loadHierarchy = require("../hierarchy");
const newToast = require('../../toast/createtoast');
const isOverflowing = require('../../dep/overflowing'); const isOverflowing = require('../../dep/overflowing');
@ -17,27 +13,17 @@ module.exports = (dir, options) => {
let cfc = document.createElement("div"); let cfc = document.createElement("div");
cfc.className = 'file'; cfc.className = 'file';
if (options.animate) {cfc.classList.add('rise');} if (options.animate) {cfc.classList.add('rise');}
if (file.dir) {cfc.classList.add('folder');}
if (!file.dir && path.extname(path.join(window.kade.cpath, file.trueName)) === '.zip') {cfc.classList.add('zip');}
cfc.onclick = function () { cfc.onclick = function () {
window.kade.elc = true; window.kade.elc = true;
if (cfc.classList.contains('file-active')) { if (cfc.classList.contains('file-active')) {if (file.dir) {refresh(`${window.kade.cpath}/${file.name}`);}}
if (file.dir) {refresh(`${window.kade.cpath}/${file.name}`);}
else {
try {cp.exec(`${window.kade.cpath}/${file.trueName}`, {shell: 'powershell.exe'}, (error) => {
if (error) {newToast("Error", "Unable to open file.", "#a4052b");}
});}
catch {newToast("Error", "Unable to open file.", "#a4052b");}
}
}
cfc.classList.add('file-active'); cfc.classList.add('file-active');
if (window.kade.cl && !cfc.isSameNode(window.kade.cl)) {window.kade.cl.classList.remove('file-active');} if (window.kade.cl) {window.kade.cl.classList.remove('file-active');}
window.kade.cl = cfc; window.kade.cl = cfc;
}; };
cfc.oncontextmenu = function () { cfc.oncontextmenu = function () {
window.kade.elc = true; window.kade.elc = true;
if (!cfc.classList.contains('file-active')) {cfc.classList.add('file-active');} if (!cfc.classList.contains('file-active')) {cfc.classList.add('file-active');}
if (window.kade.cl && !cfc.isSameNode(window.kade.cl)) {window.kade.cl.classList.remove('file-active');} if (window.kade.cl) {window.kade.cl.classList.remove('file-active');}
window.kade.cl = cfc; window.kade.cl = cfc;
window.kade.ctxel = cfc; window.kade.ctxel = cfc;
}; };

@ -1,12 +0,0 @@
module.exports = (name) => {
let folders = document.getElementById('files').getElementsByClassName('folder');
let folder = 1;
for (let i = 0; i < folders.length; i++) {
if (folders.item(i).children.item(1).innerHTML === name) {
folder = folders.item(i);
folder.click();
break;
}
}
return folder;
};

@ -1,21 +1,13 @@
const mousetrap = require('../../dep/mousetrap'); const preModal = require("../pre");
const lightRefresh = require('../../fileview/lightrefresh');
const preModal = require('../pre');
const postModal = require('../post'); const postModal = require('../post');
module.exports = (name, text, after = () => {}) => { module.exports = (name, text, after = () => {}) => {
if (window.kade.modal) {return;} preModal('error-modal');
preModal('error-modal-container');
let modalOut = document.createElement('div');
modalOut.className = 'modal';
modalOut.id = 'error-modal-container'
document.body.appendChild(modalOut);
let modal = document.createElement('div'); let modal = document.createElement('div');
modal.className = 'modal-wrapper'; modal.className = 'modal';
modalOut.appendChild(modal);
modal.classList.add('error-modal'); modal.classList.add('error-modal');
modal.id = 'error-modal'; modal.id = 'error-modal';
document.body.appendChild(modal);
let title = document.createElement('h2'); let title = document.createElement('h2');
title.innerHTML = `Error - ${name}`; title.innerHTML = `Error - ${name}`;
modal.appendChild(title); modal.appendChild(title);
@ -24,21 +16,4 @@ module.exports = (name, text, after = () => {}) => {
modal.appendChild(err); modal.appendChild(err);
after('error-modal'); after('error-modal');
postModal(); postModal();
let msm = new mousetrap(modal);
msm.bind('esc', () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
});
let close = document.createElement('a');
close.className = 'close-button';
close.onclick = () => {
lightRefresh();
modalOut.remove();
postModal(modalOut.id);
}; };
let closeWrap = document.createElement('div');
closeWrap.className = 'close-button-wrapper';
modal.appendChild(closeWrap);
closeWrap.appendChild(close);
}

@ -1,10 +1,8 @@
const transit = require("./transit"); const transit = require("./transit");
module.exports = (id) => { module.exports = (id) => {
try { document.getElementById('modal-block').remove();
try {document.getElementById('modal-block').remove();} catch {}
window.kade.modal = false; window.kade.modal = false;
document.body.style.overflowY = 'overlay'; document.body.style.overflowY = 'overlay';
transit(id, false); transit(id, false);
} catch {}
}; };

@ -1,11 +1,10 @@
const fs = require('fs'); const fs = require('fs');
const Mousetrap = require('../dep/mousetrap'); const Mousetrap = require('../dep/mousetrap');
const path = require('path');
const preModal = require('../modal/pre'); const preModal = require('../modal/pre');
const postModal = require('../modal/post'); const postModal = require('../modal/post');
const changelogs = fs.readdirSync(path.join(__dirname, '../../', '/json/changelogs')).filter(file => file.endsWith('.json')); const changelogs = fs.readdirSync('./json/changelogs').filter(file => file.endsWith('.json'));
module.exports = () => { module.exports = () => {
if (window.kade.modal) {return;} if (window.kade.modal) {return;}
@ -59,7 +58,10 @@ module.exports = () => {
}); });
}); });
clww.style = `height: ${modalOut.clientHeight - 6};`; clww.style = `height: ${modalOut.clientHeight - 6};`; // TODO cry enough tears that they magically make this line work
console.log(clww.style.height);
console.log(modalOut.clientHeight - 6);
console.log(typeof clww.style);
let msm = new Mousetrap(modal); let msm = new Mousetrap(modal);
msm.bind('esc', () => { msm.bind('esc', () => {

@ -23,6 +23,5 @@ module.exports = () => {
} }
if (i + 1 < ctxl.length) {ctx.appendChild(document.createElement('hr'));} if (i + 1 < ctxl.length) {ctx.appendChild(document.createElement('hr'));}
} }
document.getElementById('ctx-pin').parentElement.id = 'ctx-folder';
} catch (e) {console.error(e);} } catch (e) {console.error(e);}
}; };

@ -1,41 +0,0 @@
const refresh = require('../fileview/refresh');
const qa = require('../../json/qa.json');
const os = require("os");
const fs = require('fs');
const path = require('path');
module.exports = () => {
let root
switch (window.kade.platform) {
case 'win32':
root = `${os.homedir()}`;
break;
case 'linux':
root = `~/home`;
break;
}
let quickAccess = document.getElementById('favorites-container');
qa.default.forEach(i => {
let quick = document.createElement('div');
quick.innerHTML = i.name;
quick.onclick = () => {refresh(i[window.kade.platform].replace('{r}', root));};
quick.className = 'favorites-button';
quick.classList.add('nosel');
quickAccess.appendChild(quick);
});
if (fs.existsSync(path.join(__dirname, '../../', '/json/config/favorites.json'))) {
const pins = require('../../json/config/favorites.json');
let cfc = document.getElementById('custom-favorites-container');
Object.keys(pins).forEach(pin => {
let fav = document.createElement('div');
['favorites-button', 'folder-pin', 'nosel'].forEach(x => fav.classList.add(x));
fav.innerHTML = pins[pin];
fav.onclick = () => {refresh(pin);};
cfc.appendChild(fav);
});
}
};

@ -44,7 +44,6 @@ window.addEventListener('DOMContentLoaded', () => {
} }
require('./initcontext')(); require('./initcontext')();
require('./initsidebar')();
require('../fileview/refresh')(startDir); require('../fileview/refresh')(startDir);
setButtons(); setButtons();

@ -11,7 +11,6 @@ module.exports = () => {
backb.innerHTML = 'Go Back'; backb.innerHTML = 'Go Back';
backb.setAttribute('id', 'back-button'); backb.setAttribute('id', 'back-button');
backb.className = 'header-button'; backb.className = 'header-button';
backb.classList.add('nosel');
backb.onclick = () => { backb.onclick = () => {
if (window.kade.cpath !== 'C:\\' && window.kade.cpath !== '\\') {refresh(path.join(window.kade.cpath, '..'));} if (window.kade.cpath !== 'C:\\' && window.kade.cpath !== '\\') {refresh(path.join(window.kade.cpath, '..'));}
}; };
@ -20,7 +19,6 @@ module.exports = () => {
let sb = document.createElement('p'); let sb = document.createElement('p');
sb.innerHTML = 'Sort by: Name'; sb.innerHTML = 'Sort by: Name';
sb.className = 'header-button'; sb.className = 'header-button';
sb.classList.add("nosel");
sb.onclick = () => {changesort();}; sb.onclick = () => {changesort();};
sb.setAttribute('id', 'sort-button'); sb.setAttribute('id', 'sort-button');
hb.appendChild(sb); hb.appendChild(sb);
@ -28,7 +26,6 @@ module.exports = () => {
let ob = document.createElement('p'); let ob = document.createElement('p');
ob.innerHTML = 'Ascending'; ob.innerHTML = 'Ascending';
ob.className = 'header-button'; ob.className = 'header-button';
ob.classList.add("nosel");
ob.onclick = () => {changeascend();}; ob.onclick = () => {changeascend();};
ob.setAttribute('id', 'order-button'); ob.setAttribute('id', 'order-button');
hb.appendChild(ob); hb.appendChild(ob);

@ -7,7 +7,6 @@
position: absolute; position: absolute;
background-color: #101010df; background-color: #101010df;
padding: 7px 5px; padding: 7px 5px;
z-index: 2;
} }
#ctx hr { #ctx hr {
@ -34,8 +33,3 @@
align-content: stretch; align-content: stretch;
row-gap: 2px; row-gap: 2px;
} }
#ctx-folder {
padding: 0 0;
margin: 0 0;
}

@ -10,7 +10,7 @@
} }
.files { .files {
margin: 0 15px 12px 7px; margin: 0 15px 12px 15px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;

@ -9,7 +9,7 @@
border: 1px solid #af2188a4; border: 1px solid #af2188a4;
background-color: #171717da; background-color: #171717da;
padding: 6px 8px; padding: 6px 8px;
z-index: 4; z-index: 3;
max-width: 50%; max-width: 50%;
} }
@ -65,9 +65,11 @@
top: 0; top: 0;
left: 0; left: 0;
background-color: #1717176d; background-color: #1717176d;
z-index: 3; z-index: 2;
} }
.error-modal {max-width: 45%;}
.modal-wrapper { .modal-wrapper {
margin: 0 0; margin: 0 0;
padding: 0 0; padding: 0 0;
@ -93,7 +95,6 @@
display: block; display: block;
z-index: 200; z-index: 200;
position: relative; position: relative;
cursor: pointer;
} }
.close-button:before, .close-button:after { .close-button:before, .close-button:after {
content: ''; content: '';
@ -135,14 +136,3 @@
} }
#changelog-modal {max-height: 70vh;} #changelog-modal {max-height: 70vh;}
.loading-bar {
width: 90%;
margin: 12px auto 10px auto;
border-radius: 3px;
padding: 0 0;
height: 5px;
animation: 12s linear infinite, moving-stripes 10s linear infinite;
background-image: repeating-linear-gradient(-45deg, #a172a6 10px, #5d60ca98, #a172a6 30px);
background-size: 200%;
}

@ -1,42 +0,0 @@
#sidebar {
width: 180px;
border-right: 1px solid #5d60caaf;
margin: 26px 0 0 0;
padding: 0 14px 12px 14px;
position: fixed;
z-index: 1;
overflow-x: hidden;
top: 0;
left: 0;
background-color: #0000006d;
height: 100%;
}
#container {margin-left: 200px;}
#favorites-container, #favorites-wrapper, #custom-favorites-container {
display: flex;
flex-direction: column;
align-items: stretch;
align-content: flex-start;
justify-content: flex-start;
row-gap: 6px;
}
.favorites-button {
padding: 4px 6px;
color: #afafaf;
border-radius: 3px 3px;
cursor: pointer;
transition: padding-left .05s linear;
}
.favorites-button:hover {
background-color: #a172a65f;
padding-left: 10px;
color: white;
}
.favorites-header {
margin-bottom: 7px;
}

@ -11,6 +11,7 @@ body {
color: #d3d3d3; color: #d3d3d3;
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
overflow-y: overlay; overflow-y: overlay;
width: calc(100vw) - 10px;
} }
.rise { .rise {
@ -28,16 +29,10 @@ body {
to {transform: translateY(0);} to {transform: translateY(0);}
} }
@keyframes fade {
0% {background-color: #5d60ca;}
50% {background-color: #af2188;}
100% {background-color: #5d60ca;}
}
#title { #title {
font-family: 'Nunito', sans-serif; font-family: 'Nunito', sans-serif;
margin: 0 0; margin: 0 0;
z-index: 2; z-index: 1;
animation: shine 5s linear infinite; animation: shine 5s linear infinite;
background: linear-gradient(to right, #5d60ca 20%, #171717 35%, #171717 35%, #5d60ca 50%, #5d60ca 50%, #af2188 75%, #5d60ca 90%); background: linear-gradient(to right, #5d60ca 20%, #171717 35%, #171717 35%, #5d60ca 50%, #5d60ca 50%, #af2188 75%, #5d60ca 90%);
background-size: 200% auto; background-size: 200% auto;
@ -47,13 +42,11 @@ body {
-webkit-user-select: none; -webkit-user-select: none;
} }
#title-sub-container, #title-controls-container, #title-container-wrapper { #title-sub-container {
padding: 0 0; padding: 0 0;
margin: 0 0; margin: 0 0;
} }
#title-container-wrapper {position: relative;}
#title-container { #title-container {
position: fixed; position: fixed;
top: -5px; top: -5px;
@ -62,35 +55,10 @@ body {
width: 100vw; width: 100vw;
overflow: hidden; overflow: hidden;
background-color: #0000006d; background-color: #0000006d;
z-index: 2; z-index: 1;
-webkit-app-region: drag; -webkit-app-region: drag;
} }
#title-controls-container {
font-family: 'Nunito', sans-serif;
right: 10px;
position: absolute;
top: -2px;
font-size: 20px;
}
#title-controls-container > * {
display: inline-block;
padding: 0 0;
margin: 0 5px;
}
#close-window {
top: -1px;
cursor: pointer!important;
z-index: 2;
}
#close-window:before, #close-window:after {
background-color: #5d60ca;
animation: fade 10s linear infinite;
}
.nosel {-webkit-user-select: none;} .nosel {-webkit-user-select: none;}
@ -110,13 +78,3 @@ body {
} }
::-webkit-scrollbar-thumb:hover {background-image: linear-gradient(to bottom, #af2188ff 0%, #af2188ff 10%, #fa59cfff 75%, #fa59cfff 100%);} ::-webkit-scrollbar-thumb:hover {background-image: linear-gradient(to bottom, #af2188ff 0%, #af2188ff 10%, #fa59cfff 75%, #fa59cfff 100%);}
.invis {
position: relative;
left: -1000px;
width: 0;
height: 0;
padding: 0 0;
margin: 0 0;
opacity: 0;
}
Loading…
Cancel
Save