You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2019/10/30 04:04:05 UTC

[airflow-site] branch aip-11 updated: Add animations with flying cubes (#94)

This is an automated email from the ASF dual-hosted git repository.

kamilbregula pushed a commit to branch aip-11
in repository https://gitbox.apache.org/repos/asf/airflow-site.git


The following commit(s) were added to refs/heads/aip-11 by this push:
     new 16d71d0  Add animations with flying cubes (#94)
16d71d0 is described below

commit 16d71d0456570937f04458d9ff8b8b6ff910c20d
Author: Kamil BreguĊ‚a <mi...@users.noreply.github.com>
AuthorDate: Wed Oct 30 05:03:59 2019 +0100

    Add animations with flying cubes (#94)
---
 landing-pages/package.json                         |   3 +
 landing-pages/site/assets/scss/_header.scss        |  98 ++++++++
 landing-pages/site/assets/scss/_home-page.scss     |   5 +
 landing-pages/site/assets/scss/main-custom.scss    |   1 +
 landing-pages/site/layouts/_default/baseof.html    |  21 +-
 .../site/layouts/partials/hooks/head-end.html      |   8 +
 landing-pages/src/index.js                         |   6 +
 landing-pages/src/js/handleActiveVideo.js          |   2 +-
 landing-pages/src/js/headerAnimation.js            | 260 +++++++++++++++++++++
 .../scss/_home-page.scss => src/js/utils.js}       |  16 +-
 landing-pages/webpack.common.js                    |   5 +-
 landing-pages/webpack.dev.js                       |   2 +-
 landing-pages/webpack.prod.js                      |   2 +-
 landing-pages/yarn.lock                            |   5 +
 14 files changed, 414 insertions(+), 20 deletions(-)

diff --git a/landing-pages/package.json b/landing-pages/package.json
index 9285721..b1f2c72 100644
--- a/landing-pages/package.json
+++ b/landing-pages/package.json
@@ -23,6 +23,9 @@
     "start:hugo": "hugo -d ../dist -s site -vw",
     "start:webpack": "webpack-dev-server --config webpack.dev.js --hot"
   },
+  "dependencies": {
+    "p5": "^0.10.2"
+  },
   "devDependencies": {
     "@babel/core": "^7.5.4",
     "@babel/plugin-proposal-object-rest-spread": "^7.5.4",
diff --git a/landing-pages/site/assets/scss/_header.scss b/landing-pages/site/assets/scss/_header.scss
new file mode 100644
index 0000000..c89eac1
--- /dev/null
+++ b/landing-pages/site/assets/scss/_header.scss
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+@import "media";
+
+#header {
+  position: relative;
+  margin: 123px -20px 0;
+  min-height: calc(100vh - 123px);
+}
+
+#header-canvas {
+  padding: 0;
+  margin: 0;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+
+  .text-area {
+    max-width: 706px;
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+
+    &--header {
+      @extend .header__large--greyish-brown;
+      text-align: center;
+      margin-bottom: 20px;
+    }
+
+    &--subheader {
+      @extend .subtitle__large--brownish-grey;
+      text-align: center;
+      margin-bottom: 20px;
+    }
+  }
+
+  canvas {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: -1;
+  }
+}
+
+@media (max-width: $mobile) {
+  #header {
+    margin: 77px -20px 0;
+    min-height: calc(100vh - 77px);
+  }
+
+  #header-canvas {
+    .text-area {
+      max-width: 290px;
+
+      &--header {
+        font-size: 48px !important;
+        line-height: 1.25 !important;
+        margin-bottom: 14px;
+      }
+
+      &--subheader {
+        font-size: 16px !important;
+        font-weight: normal !important;
+        line-height: 1.63 !important;
+        text-align: center;
+        margin-bottom: 26px;
+      }
+    }
+  }
+}
diff --git a/landing-pages/site/assets/scss/_home-page.scss b/landing-pages/site/assets/scss/_home-page.scss
index 7bc6d31..feaea7c 100644
--- a/landing-pages/site/assets/scss/_home-page.scss
+++ b/landing-pages/site/assets/scss/_home-page.scss
@@ -18,6 +18,11 @@
  */
 @import "media";
 
+.home-page-layout {
+  &.container {
+    padding-top: 80px;
+  }
+}
 .principles-header {
   margin-top: 20px;
   margin-bottom: 4px;
diff --git a/landing-pages/site/assets/scss/main-custom.scss b/landing-pages/site/assets/scss/main-custom.scss
index 9470988..7425907 100644
--- a/landing-pages/site/assets/scss/main-custom.scss
+++ b/landing-pages/site/assets/scss/main-custom.scss
@@ -42,3 +42,4 @@
 @import "install-page";
 @import "footer";
 @import "navbar";
+@import "header";
diff --git a/landing-pages/site/layouts/_default/baseof.html b/landing-pages/site/layouts/_default/baseof.html
index 78ffb77..ba4792f 100644
--- a/landing-pages/site/layouts/_default/baseof.html
+++ b/landing-pages/site/layouts/_default/baseof.html
@@ -27,7 +27,21 @@
     {{ partial "navbar.html" . }}
 </header>
 <div class="container-fluid td-default">
-    <main role="main" class="td-main container base-layout">
+    <section id="header">
+        <div id="header-canvas">
+            <div class="text-area">
+                <h2 class="text-area--header" id="header-title">Apache Airflow</h2>
+                <h5 class="text-area--subheader" id="header-lead">
+                    Airflow is a platform created by community to programmatically author, schedule and monitor
+                    workflows.
+                </h5>
+                <a href="/install" id="header-button">
+                    {{ partial "buttons/button-filled" (dict "text" "Install") }}
+                </a>
+            </div>
+        </div>
+    </section>
+    <main role="main" class="home-page-layout td-main container base-layout">
         {{ block "main" . }}{{ end }}
         <div class="base-layout--button">
             <a href="https://github.com">
@@ -39,8 +53,7 @@
 {{ partialCached "footer.html" . }}
 {{ partialCached "scripts.html" . }}
 </body>
-{{ $script := .Site.Data.webpack.main }}
-{{ with $script.js }}
-    <script src="{{ relURL . }}"></script>
+{{ with .Site.Data.webpack }}
+    <script src="{{ relURL .main.js }}"></script>
 {{ end }}
 </html>
diff --git a/landing-pages/site/layouts/partials/hooks/head-end.html b/landing-pages/site/layouts/partials/hooks/head-end.html
index 8610cf5..da1307c 100644
--- a/landing-pages/site/layouts/partials/hooks/head-end.html
+++ b/landing-pages/site/layouts/partials/hooks/head-end.html
@@ -26,3 +26,11 @@
     <link rel="preload" href="{{ $css.RelPermalink }}" as="style">
     <link href="{{ $css.RelPermalink }}" rel="stylesheet" integrity="{{ $css.Data.integrity }}">
 {{ end }}
+
+{{ with .Site.Data.webpack }}
+<link rel="preload" href="{{ relURL .main.js }}" as="script">
+<link rel="preload" href="{{ relURL .header.js }}" as="script">
+{{ $vendorsHeader := index . "vendors~header" }}
+<link rel="preload" href="{{ relURL $vendorsHeader.js }}" as="script">
+
+{{ end }}
diff --git a/landing-pages/src/index.js b/landing-pages/src/index.js
index 4da5e47..4ce87db 100644
--- a/landing-pages/src/index.js
+++ b/landing-pages/src/index.js
@@ -26,3 +26,9 @@ showMore("#commiters-container", "#show-more-commiters");
 showMore("#pmc-container", "#show-more-pmcs");
 showMore("#case-studies-container", "#show-more-case-studies");
 handleActiveVideo();
+
+if (document.querySelector("#header")) {
+    import(/* webpackChunkName: "header" */ "./js/headerAnimation").then((module) => {
+      module.initHeaderAnimation();
+    });
+}
diff --git a/landing-pages/src/js/handleActiveVideo.js b/landing-pages/src/js/handleActiveVideo.js
index fd61e7a..c8f0d32 100644
--- a/landing-pages/src/js/handleActiveVideo.js
+++ b/landing-pages/src/js/handleActiveVideo.js
@@ -26,7 +26,7 @@ const addActiveClass = (videoItem) => {
 };
 
 export const handleActiveVideo = () => {
-  if (!videosList) return;
+  if (videosList.length === 0) return;
 
   urlHash ?
     videosList.forEach((videoLink) => videoLink.hash === urlHash && videoLink.classList.add("active"))
diff --git a/landing-pages/src/js/headerAnimation.js b/landing-pages/src/js/headerAnimation.js
new file mode 100644
index 0000000..60c6c0a
--- /dev/null
+++ b/landing-pages/src/js/headerAnimation.js
@@ -0,0 +1,260 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as p5 from "p5";
+import {documentReady} from "./utils.js";
+
+const BLOCK_COUNT_X = 7;
+const BLOCK_COUNT_Y = 7;
+const MAX_BLOCK_SIZE = 30;
+const ANIM_SPEED = 0.1;
+const ANIM_AMPLITUDE = 40;
+const DRAW_SAFE_AREA = false;
+
+const randomBetween = (from, to) => from + Math.random() * (to - from);
+const randomInt = (from, to) => randomBetween(from, to) | 0;
+
+class Polygon {
+  constructor(pos, vectors) {
+    this.pos = pos;
+    this.vectors = vectors;
+  }
+
+  draw(sketch) {
+    sketch.push();
+    sketch.noStroke();
+    sketch.fill(128, 128, 128);
+    sketch.translate(this.pos.x, this.pos.y);
+
+    sketch.beginShape();
+
+    for (let i = 0; i < this.vectors.length; i += 1) {
+      const v = this.vectors[i];
+      sketch.vertex(v.x, v.y);
+    }
+
+    sketch.endShape(p5.CLOSE);
+    sketch.pop();
+  }
+
+  isVectorInside(vector) {
+    const vs = this.vectors;
+    const x = vector.x - this.pos.x,
+      y = vector.y - this.pos.y;
+
+    let inside = false;
+    for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {
+      const intersect =
+                vs[i].y > y !== vs[j].y > y &&
+                x < (vs[j].x - vs[i].x) * (y - vs[i].y) / (vs[j].y - vs[i].y) + vs[i].x;
+      if (intersect) inside = !inside;
+    }
+    return inside;
+  }
+
+  calcArea() {
+    let total = 0;
+
+    for (let i = 0, l = this.vectors.length; i < l; i++) {
+      const addX = this.vectors[i].x;
+      const addY = this.vectors[i === this.vectors.length - 1 ? 0 : i + 1].y;
+      const subX = this.vectors[i === this.vectors.length - 1 ? 0 : i + 1].x;
+      const subY = this.vectors[i].y;
+
+      total += addX * addY * 0.5;
+      total -= subX * subY * 0.5;
+    }
+
+    return Math.abs(total);
+  }
+}
+
+class Box {
+  constructor(pos, size, color, scale, direction, rotate) {
+    this.pos = pos;
+    this.size = size;
+    this.color = color;
+    this.scale = scale;
+    this.rotate = rotate;
+    this.direction = direction;
+    this.shift = null;
+    this.animFrame = Math.random() * 100;
+  }
+
+  calc(sketch) {
+    if (!this.shift) {
+      this.shift = sketch.createVector(0, 0);
+    }
+
+    this.animFrame += ANIM_SPEED;
+    this.rotate = this.animFrame / 50 * sketch.PI;
+    this.shift.x =
+            Math.cos(this.animFrame / 10) *
+            Math.sin(this.animFrame / 10) *
+            ANIM_AMPLITUDE;
+    this.shift.y = Math.sin(this.animFrame / 10) * ANIM_AMPLITUDE;
+  }
+
+  draw(sketch) {
+    sketch.push();
+    sketch.noStroke();
+    sketch.fill(this.color);
+    sketch.translate(this.pos.x, this.pos.y);
+    sketch.scale(this.scale);
+    sketch.translate(this.shift.x, this.shift.y);
+    sketch.rotate(this.rotate * this.direction);
+    sketch.rect(-this.size / 2, -this.size / 2, this.size, this.size, 5);
+    sketch.pop();
+  }
+
+  calcArea() {
+    return this.size * this.size * this.scale;
+  }
+}
+
+
+function createBoxes(sketch, vw, vh, clearArea, colors) {
+  const boxes = [];
+  const gridWidth = vw / BLOCK_COUNT_Y;
+  const gridHeight = vh / BLOCK_COUNT_X;
+
+  for (let x = 0; x <= BLOCK_COUNT_X; x++) {
+    for (let y = 0; y <= BLOCK_COUNT_Y; y++) {
+      const pos = sketch.createVector(
+        randomBetween(gridWidth * x, gridWidth * (x + 1)),
+        randomBetween(gridHeight * y, gridHeight * (y + 1))
+      );
+
+      if (clearArea.isVectorInside(pos)) {
+        continue;
+      }
+      const box = new Box(
+        pos,
+        randomBetween(MAX_BLOCK_SIZE / 2, MAX_BLOCK_SIZE),
+        colors[randomInt(0, colors.length)],
+        randomBetween(0.5, 1),
+        randomBetween(0, 1) > 0.5 ? 1 : -1,
+        Math.random() * 2 * sketch.PI
+      );
+      boxes.push(box);
+    }
+  }
+  return boxes;
+}
+
+function createLogoArea(sketch, canvas, title, subtitle, button) {
+  const canvasRect = canvas.getBoundingClientRect();
+  const titleRect = title.getBoundingClientRect();
+  const subtitleRect = subtitle.getBoundingClientRect();
+  const buttonRect = button.getBoundingClientRect();
+
+  const vectors = [
+    sketch.createVector(titleRect.x, titleRect.y),
+    sketch.createVector(titleRect.x + titleRect.width, titleRect.y),
+    // sketch.createVector(titleRect.x + titleRect.width, titleRect.y + titleRect.height),
+    sketch.createVector(subtitleRect.x + subtitleRect.width, subtitleRect.y),
+    sketch.createVector(subtitleRect.x + subtitleRect.width, subtitleRect.y + subtitleRect.height),
+    sketch.createVector(buttonRect.x + buttonRect.width, buttonRect.y + buttonRect.height),
+    sketch.createVector(buttonRect.x, buttonRect.y + buttonRect.height),
+    sketch.createVector(subtitleRect.x, subtitleRect.y + subtitleRect.height),
+    sketch.createVector(subtitleRect.x, subtitleRect.y),
+  ];
+  for (const vector of vectors) {
+    // The canvas does not start from the beginning of the document.
+    vector.x = vector.x - canvasRect.x;
+    vector.y = vector.y  - canvasRect.y;
+  }
+
+  // Add a small margin for the entire stroke
+  const minX = Math.min(...vectors.map((d) => d.x));
+  const maxX = Math.max(...vectors.map((d) => d.x));
+  const minY = Math.min(...vectors.map((d) => d.y));
+  const maxY = Math.max(...vectors.map((d) => d.y));
+
+  const centerX = minX + (maxX - minX) / 2;
+  const centerY = minY + (maxY - minY) / 2;
+
+  for (const vector of vectors) {
+    vector.x -= centerX;
+    vector.x *= 1.2;
+    vector.x += centerX;
+    vector.y -= centerY;
+    vector.y *= 1.2;
+    vector.y += centerY;
+  }
+
+  return new Polygon(sketch.createVector(0, 0), vectors);
+}
+
+export function initHeaderAnimation() {
+  const canvas = document.querySelector("#header-canvas");
+  const title = document.querySelector("#header-title");
+  const subtitle = document.querySelector("#header-lead");
+  const button = document.querySelector("#header-button");
+
+  documentReady(function() {
+
+    new p5((sketch) => {
+
+      let colors = [];
+      let boxes = [];
+      let logoArea;
+      sketch.setup = () => {
+        const positionInfo = canvas.getBoundingClientRect();
+        const vw = positionInfo.width; // viewport width
+        const vh = positionInfo.height; // viewport height
+        colors = [
+          sketch.color("#017cee"),
+          sketch.color("#00ad46"),
+          sketch.color("#0cb6ff"),
+          sketch.color("#ff7557"),
+          sketch.color("#e43921"),
+          sketch.color("#11e1ee"),
+          sketch.color("#04d659"),
+          sketch.color("#00c7d4"),
+          sketch.color("#cbcbcb")
+        ];
+        logoArea = createLogoArea(sketch, canvas, title, subtitle, button);
+        boxes = createBoxes(sketch, vw, vh, logoArea, colors);
+        sketch.createCanvas(vw, vh);
+      };
+
+      sketch.draw = () => {
+        sketch.background(255, 255, 255);
+        if (DRAW_SAFE_AREA) {
+          logoArea.draw(sketch);
+        }
+        boxes.forEach((box) => {
+          box.calc(sketch);
+          box.draw(sketch);
+        });
+      };
+
+      sketch.windowResized = () => {
+        const positionInfo = canvas.getBoundingClientRect();
+        const vw = positionInfo.width; // viewport width
+        const vh = positionInfo.height; // viewport height
+        logoArea = createLogoArea(sketch, canvas, title, subtitle, button);
+        boxes = createBoxes(sketch, vw, vh, logoArea, colors);
+        sketch.resizeCanvas(vw, vh);
+      };
+    }, document.querySelector("#header-canvas"));
+  });
+
+}
diff --git a/landing-pages/site/assets/scss/_home-page.scss b/landing-pages/src/js/utils.js
similarity index 78%
copy from landing-pages/site/assets/scss/_home-page.scss
copy to landing-pages/src/js/utils.js
index 7bc6d31..64efb01 100644
--- a/landing-pages/site/assets/scss/_home-page.scss
+++ b/landing-pages/src/js/utils.js
@@ -16,17 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-@import "media";
 
-.principles-header {
-  margin-top: 20px;
-  margin-bottom: 4px;
-}
-
-.integrations-header {
-  margin-bottom: 60px; // to be changed when searchbox is added
-
-  @media (max-width: $mobile)  {
-    margin-bottom: 30px;
+export function documentReady(fn) {
+  if (document.readyState !== "loading") {
+    fn();
+  } else {
+    document.addEventListener("DOMContentLoaded", fn);
   }
 }
diff --git a/landing-pages/webpack.common.js b/landing-pages/webpack.common.js
index ad9f1a3..f004723 100644
--- a/landing-pages/webpack.common.js
+++ b/landing-pages/webpack.common.js
@@ -29,7 +29,8 @@ module.exports = {
   },
 
   output: {
-    path: path.join(__dirname, "dist")
+    path: path.join(__dirname, "dist"),
+    publicPath: '/'
   },
 
   module: {
@@ -58,7 +59,7 @@ module.exports = {
 
   plugins: [
     new webpack.ProvidePlugin({
-      fetch: "imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch"
+      fetch: 'exports-loader?self.fetch!whatwg-fetch/dist/fetch.umd',
     }),
 
     new AssetsPlugin({
diff --git a/landing-pages/webpack.dev.js b/landing-pages/webpack.dev.js
index c2099bc..cbab2c0 100644
--- a/landing-pages/webpack.dev.js
+++ b/landing-pages/webpack.dev.js
@@ -29,7 +29,7 @@ module.exports = merge(common, {
 
   output: {
     filename: "[name].js",
-    chunkFilename: "[id].css"
+    chunkFilename: "chunk-[id].js"
   },
 
   devServer: {
diff --git a/landing-pages/webpack.prod.js b/landing-pages/webpack.prod.js
index 2722bd4..52c4f1e 100644
--- a/landing-pages/webpack.prod.js
+++ b/landing-pages/webpack.prod.js
@@ -29,7 +29,7 @@ module.exports = merge(common, {
 
   output: {
     filename: "[name].[hash:5].js",
-    chunkFilename: "[id].[hash:5].css"
+    chunkFilename: "[id].[hash:5].js"
   },
 
   optimization: {
diff --git a/landing-pages/yarn.lock b/landing-pages/yarn.lock
index 36bf6fb..26ebd32 100644
--- a/landing-pages/yarn.lock
+++ b/landing-pages/yarn.lock
@@ -5592,6 +5592,11 @@ p-try@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
+p5@^0.10.2:
+  version "0.10.2"
+  resolved "https://registry.yarnpkg.com/p5/-/p5-0.10.2.tgz#9437b28e803b9c8a94383c6b5f4d05b13603e1cc"
+  integrity sha512-kZnC7JllCEnEUTB3sv2iETUg1ulNvB60h3MHb63u7W/nCJc3XIlMGXcKk28cuezdQ7TOlKScm0qmWCsol+302Q==
+
 pako@~1.0.5:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"