summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2022-06-10 09:51:20 +0530
committerAndinus <andinus@nand.sh>2022-06-10 09:51:20 +0530
commitc868ff796fd8ebf9f0c5f4d69a4abbb0f9682df8 (patch)
tree4f0bd106c3f9ef8e80db285a941a00418737ec7f
parent1ac31ef10cc799f3cb7fc94d34178290a4e8dc00 (diff)
downloadcrater-c868ff796fd8ebf9f0c5f4d69a4abbb0f9682df8.tar.gz
Add bricks.js for masonry layout, fix password input
multi-column didn't do what I wanted. bricks.js does the masonry
layout, I think left-to-right would be even better but we'll go with
this.
-rw-r--r--lib/Crater/Routes.rakumod3
-rw-r--r--resources/css/style.css17
-rw-r--r--resources/js/bricks.js285
-rw-r--r--resources/js/gallery.js40
-rw-r--r--templates/gallery.crotmp2
-rw-r--r--templates/login.crotmp2
6 files changed, 339 insertions, 10 deletions
diff --git a/lib/Crater/Routes.rakumod b/lib/Crater/Routes.rakumod
index 6206e5c..cf4c5eb 100644
--- a/lib/Crater/Routes.rakumod
+++ b/lib/Crater/Routes.rakumod
@@ -20,5 +20,8 @@ sub routes(
         get -> 'resources', 'css', *@path {
             static 'resources', 'css', @path;
         }
+        get -> 'resources', 'js', *@path {
+            static 'resources', 'js', @path;
+        }
     }
 }
diff --git a/resources/css/style.css b/resources/css/style.css
index a49327e..87e6c9d 100644
--- a/resources/css/style.css
+++ b/resources/css/style.css
@@ -13,7 +13,7 @@ body {
     background-color: var(--bg-main);
     font-family: "Iosevka Aile", sans-serif;
 
-    margin: 2em auto;
+    margin: 4em auto;
     max-width: 90%;
     line-height: 1.5;
 }
@@ -59,9 +59,8 @@ input, .alert {
     min-width: 30%;
 }
 
-img, .text, .heading {
-    margin: 3.2em 1em;
-}
+img, .text { width: 384px; }
+.heading { width: 364px; }
 
 .heading {
     box-shadow: var(--blue-intense-bg) 0px 0px 0px 2px inset,
@@ -85,11 +84,11 @@ img, .text, .heading {
     padding: 1em;
 }
 
-.gallery {
-    column-count: auto;
-    column-width: 384px;
-    column-fill: balance;
-}
+/* .gallery { */
+/*     column-count: auto; */
+/*     column-width: 384px; */
+/*     column-fill: balance; */
+/* } */
 .gallery img {
     transform-origin: center;
     transform: perspective(800px) rotateY(2deg);
diff --git a/resources/js/bricks.js b/resources/js/bricks.js
new file mode 100644
index 0000000..7758b05
--- /dev/null
+++ b/resources/js/bricks.js
@@ -0,0 +1,285 @@
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+	typeof define === 'function' && define.amd ? define(factory) :
+	(global.Bricks = factory());
+}(this, (function () { 'use strict';
+
+var _extends = Object.assign || function (target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i];
+
+    for (var key in source) {
+      if (Object.prototype.hasOwnProperty.call(source, key)) {
+        target[key] = source[key];
+      }
+    }
+  }
+
+  return target;
+};
+
+var knot = function knot() {
+  var extended = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+  var events = Object.create(null);
+
+  function on(name, handler) {
+    events[name] = events[name] || [];
+    events[name].push(handler);
+    return this;
+  }
+
+  function once(name, handler) {
+    handler._once = true;
+    on(name, handler);
+    return this;
+  }
+
+  function off(name) {
+    var handler = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+    handler ? events[name].splice(events[name].indexOf(handler), 1) : delete events[name];
+
+    return this;
+  }
+
+  function emit(name) {
+    var _this = this;
+
+    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+      args[_key - 1] = arguments[_key];
+    }
+
+    // cache the events, to avoid consequences of mutation
+    var cache = events[name] && events[name].slice();
+
+    // only fire handlers if they exist
+    cache && cache.forEach(function (handler) {
+      // remove handlers added with 'once'
+      handler._once && off(name, handler);
+
+      // set 'this' context, pass args to handlers
+      handler.apply(_this, args);
+    });
+
+    return this;
+  }
+
+  return _extends({}, extended, {
+
+    on: on,
+    once: once,
+    off: off,
+    emit: emit
+  });
+};
+
+var bricks = function bricks() {
+  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+  // privates
+
+  var persist = void 0; // packing new elements, or all elements?
+  var ticking = void 0; // for debounced resize
+
+  var sizeIndex = void 0;
+  var sizeDetail = void 0;
+
+  var columnTarget = void 0;
+  var columnHeights = void 0;
+
+  var nodeTop = void 0;
+  var nodeLeft = void 0;
+  var nodeWidth = void 0;
+  var nodeHeight = void 0;
+
+  var nodes = void 0;
+  var nodesWidths = void 0;
+  var nodesHeights = void 0;
+
+  // resolve options
+
+  var packed = options.packed.indexOf('data-') === 0 ? options.packed : 'data-' + options.packed;
+  var sizes = options.sizes.slice().reverse();
+  var position = options.position !== false;
+
+  var container = options.container.nodeType ? options.container : document.querySelector(options.container);
+
+  var selectors = {
+    all: function all() {
+      return toArray(container.children);
+    },
+    new: function _new() {
+      return toArray(container.children).filter(function (node) {
+        return !node.hasAttribute('' + packed);
+      });
+    }
+  };
+
+  // series
+
+  var setup = [setSizeIndex, setSizeDetail, setColumns];
+
+  var run = [setNodes, setNodesDimensions, setNodesStyles, setContainerStyles];
+
+  // instance
+
+  var instance = knot({
+    pack: pack,
+    update: update,
+    resize: resize
+  });
+
+  return instance;
+
+  // general helpers
+
+  function runSeries(functions) {
+    functions.forEach(function (func) {
+      return func();
+    });
+  }
+
+  // array helpers
+
+  function toArray(input) {
+    var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
+
+    return Array.prototype.slice.call(input);
+  }
+
+  function fillArray(length) {
+    return Array.apply(null, Array(length)).map(function () {
+      return 0;
+    });
+  }
+
+  // size helpers
+
+  function getSizeIndex() {
+    // find index of widest matching media query
+    return sizes.map(function (size) {
+      return size.mq && window.matchMedia('(min-width: ' + size.mq + ')').matches;
+    }).indexOf(true);
+  }
+
+  function setSizeIndex() {
+    sizeIndex = getSizeIndex();
+  }
+
+  function setSizeDetail() {
+    // if no media queries matched, use the base case
+    sizeDetail = sizeIndex === -1 ? sizes[sizes.length - 1] : sizes[sizeIndex];
+  }
+
+  // column helpers
+
+  function setColumns() {
+    columnHeights = fillArray(sizeDetail.columns);
+  }
+
+  // node helpers
+
+  function setNodes() {
+    nodes = selectors[persist ? 'new' : 'all']();
+  }
+
+  function setNodesDimensions() {
+    // exit if empty container
+    if (nodes.length === 0) {
+      return;
+    }
+
+    nodesWidths = nodes.map(function (element) {
+      return element.clientWidth;
+    });
+    nodesHeights = nodes.map(function (element) {
+      return element.clientHeight;
+    });
+  }
+
+  function setNodesStyles() {
+    nodes.forEach(function (element, index) {
+      columnTarget = columnHeights.indexOf(Math.min.apply(Math, columnHeights));
+
+      element.style.position = 'absolute';
+
+      nodeTop = columnHeights[columnTarget] + 'px';
+      nodeLeft = columnTarget * nodesWidths[index] + columnTarget * sizeDetail.gutter + 'px';
+
+      // support positioned elements (default) or transformed elements
+      if (position) {
+        element.style.top = nodeTop;
+        element.style.left = nodeLeft;
+      } else {
+        element.style.transform = 'translate3d(' + nodeLeft + ', ' + nodeTop + ', 0)';
+      }
+
+      element.setAttribute(packed, '');
+
+      // ignore nodes with no width and/or height
+      nodeWidth = nodesWidths[index];
+      nodeHeight = nodesHeights[index];
+
+      if (nodeWidth && nodeHeight) {
+        columnHeights[columnTarget] += nodeHeight + sizeDetail.gutter;
+      }
+    });
+  }
+
+  // container helpers
+
+  function setContainerStyles() {
+    container.style.position = 'relative';
+    container.style.width = sizeDetail.columns * nodeWidth + (sizeDetail.columns - 1) * sizeDetail.gutter + 'px';
+    container.style.height = Math.max.apply(Math, columnHeights) - sizeDetail.gutter + 'px';
+  }
+
+  // resize helpers
+
+  function resizeFrame() {
+    if (!ticking) {
+      window.requestAnimationFrame(resizeHandler);
+      ticking = true;
+    }
+  }
+
+  function resizeHandler() {
+    if (sizeIndex !== getSizeIndex()) {
+      pack();
+      instance.emit('resize', sizeDetail);
+    }
+
+    ticking = false;
+  }
+
+  // API
+
+  function pack() {
+    persist = false;
+    runSeries(setup.concat(run));
+
+    return instance.emit('pack');
+  }
+
+  function update() {
+    persist = true;
+    runSeries(run);
+
+    return instance.emit('update');
+  }
+
+  function resize() {
+    var flag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
+
+    var action = flag ? 'addEventListener' : 'removeEventListener';
+
+    window[action]('resize', resizeFrame);
+
+    return instance;
+  }
+};
+
+return bricks;
+
+})));
diff --git a/resources/js/gallery.js b/resources/js/gallery.js
new file mode 100644
index 0000000..73e5458
--- /dev/null
+++ b/resources/js/gallery.js
@@ -0,0 +1,40 @@
+'use strict';
+/* import Bricks from '/bricks.js'; */
+
+// mq      - the minimum viewport width (String CSS unit: em, px, rem)
+// columns - the number of vertical columns
+// gutter  - the space (in px) between the columns and grid items
+
+// image width.
+const imgW = 384;
+
+const sizes = [
+    { columns: 1, gutter: 30 },
+    { mq: ((imgW * 2.5) + 40) + "px", columns: 2, gutter: 40 },
+    // { mq: '768px', columns: 2, gutter: 25 },
+    // { mq: '1280px', columns: 3, gutter: 50 }
+];
+
+const instance = Bricks({
+    container: '.gallery',
+    packed: 'data-packed',
+    sizes: sizes
+});
+
+instance
+    .on('pack',   () => console.log('ALL grid items packed.'))
+    .on('update', () => console.log('NEW grid items packed.'))
+    .on('resize', size => console.log('The grid has be re-packed to accommodate a new BREAKPOINT.', size));
+
+// start it up, when the DOM is ready. note that if images are in the
+// grid, you may need to wait for document.readyState === 'complete'.
+
+document.addEventListener('DOMContentLoaded', eve => {
+    document.addEventListener('readystatechange', event => {
+        if (event.target.readyState === 'complete') {
+            instance
+                .resize(true)     // bind resize handler
+                .pack()           // pack initial items
+        }
+    })
+})
diff --git a/templates/gallery.crotmp b/templates/gallery.crotmp
index 2afe7e9..021b366 100644
--- a/templates/gallery.crotmp
+++ b/templates/gallery.crotmp
@@ -19,4 +19,6 @@
 
     </@>
 </div>
+<script type="text/javascript" src="/resources/js/bricks.js"></script>
+<script type="text/javascript" src="/resources/js/gallery.js"></script>
 </|>
diff --git a/templates/login.crotmp b/templates/login.crotmp
index 3dbee24..2a5587c 100644
--- a/templates/login.crotmp
+++ b/templates/login.crotmp
@@ -7,7 +7,7 @@
     </div>
     </?>
 
-    <input type="pass" name="pass" id="pass" placeholder="Password" required>
+    <input type="password" name="pass" id="pass" placeholder="Password" required>
     <br>
     <input type="submit" value="Log In" />
 </form>