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"