]> MadKous Network Git Server - photo-site.git/commitdiff
Refactor and Update Filter Logic
authorMatthew Kousoulas <shaman.kous@gmail.com>
Wed, 23 Jun 2021 19:34:29 +0000 (15:34 -0400)
committerMatthew Kousoulas <shaman.kous@gmail.com>
Wed, 23 Jun 2021 19:34:29 +0000 (15:34 -0400)
12 files changed:
data/CSVtoJSON.awk [moved from CSVtoJSON.awk with 100% similarity]
data/CSVtoJSON.sh [moved from CSVtoJSON.sh with 100% similarity]
data/pictures.csv [moved from pictures.csv with 100% similarity]
data/pictures.json [moved from pictures.json with 100% similarity]
driver.js [deleted file]
index.html
scripts/click.js [new file with mode: 0644]
scripts/dom.js [new file with mode: 0644]
scripts/main.js [new file with mode: 0644]
scripts/photo.js [new file with mode: 0644]
scripts/util.js [new file with mode: 0644]
styles/main.css [moved from style.css with 66% similarity]

similarity index 100%
rename from CSVtoJSON.awk
rename to data/CSVtoJSON.awk
similarity index 100%
rename from CSVtoJSON.sh
rename to data/CSVtoJSON.sh
similarity index 100%
rename from pictures.csv
rename to data/pictures.csv
similarity index 100%
rename from pictures.json
rename to data/pictures.json
diff --git a/driver.js b/driver.js
deleted file mode 100644 (file)
index d8cefe1..0000000
--- a/driver.js
+++ /dev/null
@@ -1,156 +0,0 @@
-// (() => {
-"use strict";
-const methods = [ "loc", "date", "sub" ];
-let up_dom, photo_dom;
-// pointers to <ul>
-let meth_dom, cat_dom, thumb_dom;
-// pointers to [<li>]
-let meth_list = new Object();
-// pointers to photos
-let photos;
-let state = [];
-
-function loadJson(text) {
-       let json = JSON.parse(text);
-       photos = json.photos;
-       photos.forEach(p => {
-               let t = document.createElement("img");
-               t.alt = p.desc;
-               t.src = `/pictures/${p.name}_thm.jpg`;
-
-               p.thm = document.createElement("div");
-               p.thm.classList.add("thumb-tile");
-               p.thm.appendChild(t);
-               p.thm.addEventListener("click", () => {
-                       event.stopPropagation();
-                       loadPhoto(p);
-               });
-
-               p.img = document.createElement("img");
-               p.img.alt = p.desc;
-               p.img.classList.add("responsive");
-               p.img.src = `/pictures/${p.name}_sm.jpg`;
-       });
-
-       methods.forEach(m => {
-               let a = [];
-               json[m].forEach(
-                       s => {
-                               let e = document.createElement("li");
-                               e.innerText = s;
-                               e.id = s;
-                               e.addEventListener("click", () => {
-                                       event.stopPropagation();
-                                       loadCategory(m, e);
-                               });
-                               a.push(e);
-                       });
-               meth_list[m] = a;
-       });
-}
-
-function keyDown(e) {
-       if (e.keyCode === 27 || e.keyCode === 32) {
-               console.log("close picture");
-               photo_dom.classList.add("hidden");
-       }
-}
-
-function loadPhoto(p) {
-       removeAll(photo_dom);
-       console.log("load picture " + p.name);
-       photo_dom.appendChild(p.img);
-       photo_dom.classList.remove("hidden");
-}
-
-function loadCategory(m, node) {
-       let s = node.innerText;
-       console.log(`load category ${s}:${m}`);
-       let a = siblings(node);
-
-       removeAll(thumb_dom);
-       if (peek(state) === s) {
-               ascend(node);
-       } else {
-               state.push(s);
-               photos.filter(p => p[m] === s)
-                       .forEach(p => thumb_dom.appendChild(p.thm));
-
-               a.forEach(e => {
-                       e.classList.add("deselected")
-                       e.classList.remove("selected");
-               });
-               node.classList.remove("deselected");
-               node.classList.add("selected");
-       }
-}
-
-function loadMethod(node) {
-       let m = node.id;
-       console.log(`load method ${m}`);
-       let a = siblings(node);
-
-       removeAll(cat_dom);
-       if (peek(state) === m) {
-               ascend(node);
-       } else {
-               state.push(m);
-               meth_list[m].forEach(e => cat_dom.appendChild(e));
-
-               node.appendChild(cat_dom);
-               a.forEach(e => {
-                       e.classList.add("deselected")
-                       e.classList.remove("selected");
-               });
-               node.classList.remove("deselected");
-               node.classList.add("selected");
-       }
-}
-
-function ascend(node) {
-       state.pop();
-       removeLast(node);
-       siblings(node).forEach(e => {
-               e.classList.remove("deselected")
-               e.classList.remove("selected");
-       });
-}
-
-function removeAll(e) {
-       while(e.lastChild) {
-               e.removeChild(e.lastChild);
-       }
-}
-function siblings(n) { return Array.from(n.parentNode.children); }
-function removeLast(e) { e.removeChild(e.lastChild); }
-function peek(a) { return a[a.length-1]; }
-
-document.addEventListener("DOMContentLoaded",
-       (event) => {
-               let xhttp = new XMLHttpRequest();
-               xhttp.onload = (() => loadJson(xhttp.responseText));
-               xhttp.open("GET", "pictures.json");
-               xhttp.send();
-
-               cat_dom = document.createElement("ul");
-
-               thumb_dom = document.getElementById("thumbs");
-               meth_dom = document.getElementById("methods");
-               up_dom = document.getElementById("up");
-               photo_dom = document.getElementById("photo");
-
-               photo_dom.addEventListener("click", () => {
-                       photo_dom.classList.add("hidden");
-               });
-
-               Array.from(meth_dom.children)
-                       .forEach(e => {
-                               e.addEventListener("click", () => {
-                                       event.stopPropagation();
-                                       loadMethod(e);
-                               });
-                       });
-
-               document.addEventListener("keydown", keyDown);
-       });
-// })();
index feadf2bf385545128fb28c369b192b887bb05633..bdb5d9b40a8be7965a649073de49e84588deb7d3 100644 (file)
@@ -3,15 +3,21 @@
        <head>
                <meta charset="UTF-8">
                <title>MadKous Photography</title>
-               <link rel="stylesheet" type="text/css" href="style.css"></script>
-               <script type="text/javascript" src="driver.js"></script>
+               <link rel="stylesheet" type="text/css" href="styles/main.css"></script>
+               <!-- util must be first; driver must be last -->
+               <script type="text/javascript" src="scripts/util.js"></script>
+               <script type="text/javascript" src="scripts/photo.js"></script>
+               <script type="text/javascript" src="scripts/click.js"></script>
+               <script type="text/javascript" src="scripts/dom.js"></script>
+               <script type="text/javascript" src="scripts/main.js"></script>
        </head>
        <body class="parent">
+               <div id="logo">
+                       <img src="logo_sm.png" alt="MadKous">
+               </div>
                <div class="grid parent">
                        <div class="menu">
-                               <ul id="methods">
-                                       Filter
-                                       <li id="loc">by Location</li>
+                               <ul id="methods">Filter<li id="loc">by Location</li>
                                        <li id="sub">by Subject</li>
                                        <li id="date">by Date</li>
                                </ul>
diff --git a/scripts/click.js b/scripts/click.js
new file mode 100644 (file)
index 0000000..d0d407b
--- /dev/null
@@ -0,0 +1,61 @@
+var CLICK = (click => {
+       click.category = (m, node) => {
+               let s = node.innerText;
+
+               if (UTIL.is_selected(node)) {
+                       if(PHOTO.removeFilter(m, s)) {
+                               UTIL.siblings(node).forEach(e => {
+                                       UTIL.un_deselected(e);
+                                       UTIL.normal(e);
+                               });
+                       }
+                       UTIL.un_selected(node);
+               } else if (UTIL.is_normal(node)) {
+                       PHOTO.addFilter(m, s, p => p[m] === s);
+                       UTIL.siblings(node).forEach(e => {
+                               UTIL.deselected(e);
+                               UTIL.un_normal(e);
+                       });
+                       UTIL.un_deselected(node);
+                       UTIL.selected(node);
+               } else { // assumed to be 'deselected'
+                       PHOTO.addFilter(m, s, p => p[m] === s);
+                       UTIL.un_deselected(node);
+                       UTIL.selected(node);
+               }
+       }
+
+       click.method = (node) => {
+               let m = node.id;
+               console.log(`click method ${m}`);
+
+               if (node.classList.contains("selected")) {
+                       Array.from(node.children).forEach(UTIL.hidden);
+                       click.close(node);
+               } else {
+                       Array.from(node.children).forEach(UTIL.un_hidden);
+                       click.open(node);
+               }
+       }
+
+       click.open = (node) => {
+               UTIL.siblings(node).forEach(e => {
+                       UTIL.deselected(e);
+                       UTIL.un_selected(e);
+                       UTIL.un_normal(e);
+               });
+               UTIL.un_deselected(node);
+               UTIL.un_normal(node);
+               UTIL.selected(node);
+       }
+
+       click.close = (node) => {
+               UTIL.siblings(node).forEach(e => {
+                       UTIL.un_deselected(e);
+                       UTIL.un_selected(e);
+                       UTIL.normal(e);
+               });
+       }
+
+       return click;
+})(CLICK || {});
diff --git a/scripts/dom.js b/scripts/dom.js
new file mode 100644 (file)
index 0000000..6761a09
--- /dev/null
@@ -0,0 +1,79 @@
+var DOM = (dom => {
+       // main photo container
+       dom.photo_dom;
+       // pointers to <ul>
+       dom.meth_dom;
+       // thumbnail container
+       dom.thumb_dom;
+       // lists of <li> by method
+       dom.meth_list = new Object();
+
+       //// dom creation ////
+       dom.makeThumbnail = (p) => {
+               let t = document.createElement("img");
+               let e = document.createElement("div");
+
+               t.alt = p.desc;
+               t.src = `pictures/${p.name}_thm.jpg`;
+
+               e.appendChild(t);
+               e.addEventListener("click", () => {
+                       event.stopPropagation();
+                       dom.loadPhoto(p);
+               });
+               return e;
+       }
+
+       dom.makePicture = (p) => {
+               let e = document.createElement("img");
+               e.alt = p.desc;
+               e.src = `pictures/${p.name}_sm.jpg`;
+               return e;
+       }
+
+       dom.makeCategory = (s, m) => {
+               let e = document.createElement("li");
+               e.innerText = s;
+               e.id = s;
+               e.addEventListener("click", () => {
+                       event.stopPropagation();
+                       CLICK.category(m, e);
+               });
+               UTIL.normal(e);
+               return e;
+       }
+
+       dom.makeList = (l) => {
+               let c = document.createElement("ul");
+               l.forEach(e => c.appendChild(e));
+               UTIL.hidden(c);
+               return c;
+       }
+
+       dom.makeMethod = (node, l) => {
+               let m = node.id;
+               console.log(`load method ${m}`);
+               node.appendChild(dom.makeList(l[m]));
+       }
+
+       dom.loadPhoto = (p) => {
+               UTIL.removeAll(dom.photo_dom);
+               console.log("load picture " + p.name);
+               dom.photo_dom.appendChild(p.img);
+               UTIL.un_hidden(dom.photo_dom);
+       }
+
+       dom.init = () => {
+               // methods
+               Array.from(dom.meth_dom.children)
+                       .forEach(e => {
+                               dom.makeMethod(e, dom.meth_list);
+                               e.addEventListener("click", () => {
+                                       event.stopPropagation();
+                                       CLICK.method(e);
+                               });
+                       });
+       }
+
+       return dom;
+})(DOM || {});
diff --git a/scripts/main.js b/scripts/main.js
new file mode 100644 (file)
index 0000000..2bd4832
--- /dev/null
@@ -0,0 +1,49 @@
+(() => {
+"use strict";
+       //// json handling ////
+       function loadJson(text) {
+               let json = JSON.parse(text);
+               PHOTO.all = json.photos;
+               PHOTO.all.forEach(p => {
+                       p.thm = DOM.makeThumbnail(p);
+                       p.img = DOM.makePicture(p);
+               });
+
+               PHOTO.methods.forEach(m => {
+                       let a = [];
+                       json[m].forEach(s => a.push(DOM.makeCategory(s, m)));
+                       DOM.meth_list[m] = a;
+               });
+       }
+
+       ///// input handling /////
+       function keyDown(e) {
+               if (e.keyCode === 27 || e.keyCode === 32) {
+                       DOM.photo_dom.classList.add("hidden");
+               } else {
+                       console.log(`${e.code} -> ${e.keyCode}`);
+               }
+       }
+
+       document.addEventListener("DOMContentLoaded",
+               (event) => {
+                       let xhttp = new XMLHttpRequest();
+                       xhttp.onload = (() => {
+                               loadJson(xhttp.responseText);
+                               PHOTO.updateThumbs();
+                               DOM.init();
+                       });
+                       xhttp.open("GET", "data/pictures.json");
+                       xhttp.send();
+
+                       DOM.thumb_dom = document.getElementById("thumbs");
+                       DOM.meth_dom = document.getElementById("methods");
+                       DOM.photo_dom = document.getElementById("photo");
+
+                       DOM.photo_dom.addEventListener("click", () => {
+                               DOM.photo_dom.classList.add("hidden");
+                       });
+
+                       document.addEventListener("keydown", keyDown);
+               });
+})();
diff --git a/scripts/photo.js b/scripts/photo.js
new file mode 100644 (file)
index 0000000..e683655
--- /dev/null
@@ -0,0 +1,38 @@
+var PHOTO = (photo => {
+       photo.methods = [ "loc", "date", "sub" ];
+       photo.all;
+       photo.shown;
+       photo.filter_groups
+               = new Map(photo.methods.map(s => [s, new Map([["T", UTIL.top]])]));
+
+       photo.updateThumbs = () => {
+               UTIL.removeAll(DOM.thumb_dom);
+               let pred = p => Array.from(photo.filter_groups.values()).every(
+                       m => Array.from(m.values()).some(f => f(p)));
+               photo.shown = photo.all.filter(pred);
+               photo.shown.forEach(p => DOM.thumb_dom.appendChild(p.thm));
+       }
+
+       photo.addFilter = (m, s, f) => {
+               let g = photo.filter_groups.get(m);
+               g.delete("T");
+               g.set(s, f);
+               photo.updateThumbs();
+       }
+
+       // returns true iff last filter removed
+       photo.removeFilter = (m, s) => {
+               let g = photo.filter_groups.get(m);
+               let r = false;
+               if (g.delete(s)) {
+                       if (g.size === 0) {
+                               g.set("T", UTIL.top);
+                               r = true;
+                       }
+                       photo.updateThumbs();
+               }
+               return r;
+       }
+
+       return photo;
+})(PHOTO || {});
diff --git a/scripts/util.js b/scripts/util.js
new file mode 100644 (file)
index 0000000..ec3c858
--- /dev/null
@@ -0,0 +1,21 @@
+var UTIL = (util => {
+       util.top = _ => true;
+       util.siblings = (n) => Array.from(n.parentNode.children);
+       util.peek = (a) => a[a.length-1];
+
+       util.removeLast = (e) => e.removeChild(e.lastChild);
+       util.removeAll = (e) => {
+               while(e.lastChild) {
+                       e.removeChild(e.lastChild);
+               }
+       }
+
+       let classes = ["hidden", "selected", "deselected", "normal"];
+       classes.forEach(c => {
+               util[c] = (e) => e.classList.add(c);
+               util[`un_${c}`] = (e) => e.classList.remove(c);
+               util[`is_${c}`] = (e) => e.classList.contains(c);
+       });
+
+       return util;
+})(UTIL || {});
similarity index 66%
rename from style.css
rename to styles/main.css
index ec0de6a4e38ffad59dddb61e835551203fdc53eb..517afea88b6673111ff7d81b12a33909e6de8387 100644 (file)
--- a/style.css
@@ -1,13 +1,14 @@
 .parent { height: 95%; }
 .deselected { color: #797777; }
 .selected { color: #e3e2e2; }
+.normal { color: #c3c2c2; }
 .hidden { display: none; }
 
 body {
        background-color: #161516;
        color: #c3c2c2;
        margin: 5%;
-       font-size: larger;
+       font-size: 2vw;
        font-family: sans-serif;
 }
 
@@ -18,7 +19,7 @@ ul {
 }
 
 li {
-       line-height: 1.8;
+       padding: 1vw;
 }
 
 img {
@@ -28,8 +29,8 @@ img {
 
 .grid {
        display: grid;
-       grid-template-columns: 15vw 70vw;
-       grid-column-gap: 5vw;
+       grid-template-columns: 15vw 0.8fr;
+       grid-column-gap: 3vw;
 }
 
 .menu {
@@ -37,25 +38,29 @@ img {
 }
 
 .thumb-grid {
-       max-width: 1200px;
-       margin: 0 auto;
        display: grid;
-       grid-gap: 1rem;
-       grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+       grid-gap: 1vw;
+       grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
 }
 
-.thumb-tile {
-       display: inline grid;
+.thumb-grid > div {
+       display: flex;
+       height: 160px;
+       width: 160px;
+       justify-content: center;
+       align-items: center;
 }
 
-.thumb-tile > img {
+.thumb-grid > div > img {
+       display: block;
        max-height: 160px;
        max-width: 160px;
        border-radius: 10px;
        box-shadow: 5px 5px 5px #050404;
+       /* margin: auto; */
 }
 
-.thumb-tile > img:hover {
+.thumb-grid > div > img:hover {
        animation-name: bounce;
        animation-timing-function: ease-in-out;
        animation-duration: 300ms;
@@ -63,7 +68,7 @@ img {
        transform: translate(0px, -2.5px);
 }
 
-.thumb-tile > img:active {
+.thumb-grid > div > img:active {
        animation-name: press;
        animation-timing-function: ease-in-out;
        animation-duration: 100ms;
@@ -77,8 +82,8 @@ img {
                transform: translate(0px, -2.5px);
        }
        100% {
-       box-shadow: 2px 2px 5px #050404;
-       transform: translate(0px, 1px);
+               box-shadow: 2px 2px 5px #050404;
+               transform: translate(0px, 1px);
        }
 }
 
@@ -87,22 +92,6 @@ img {
                box-shadow: 5px 5px 5px #050404;
                transform: translate(0px, 0px);
        }
-       20% {
-               box-shadow: 8px 8px 5px #050404;
-               transform: translate(0px, -1.0px);
-       }
-       40% {
-               box-shadow: 10px 10px 5px #050404;
-               transform: translate(0px, -2.5px);
-       }
-       60% {
-               box-shadow: 12px 12px 5px #050404;
-               transform: translate(0px, -4.0px);
-       }
-       80% {
-               box-shadow: 8px 8px 5px #050404;
-               transform: translate(0px, -1.0px);
-       }
        100% {
                box-shadow: 10px 10px 5px #050404;
                transform: translate(0px, -2.5px);