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 <mik-...@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"