You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2017/04/28 09:53:57 UTC

zeppelin git commit: [ZEPPELIN-2427] Hide navbar and noteAction bar when scrolling down

Repository: zeppelin
Updated Branches:
  refs/heads/master 925d09cef -> bba0a7b47


[ZEPPELIN-2427] Hide navbar and noteAction bar when scrolling down

### What is this PR for?

Hide navbar and noteAction bar when scrolling down to

- **widen view area**

Here are few famous services which hiding their navbar too.

- https://www.kaggle.com/c/titanic
- http://github.com/tj (profile page)

### Implementation Details

Since [headroom](wicky.nillia.ms/headroom.js/) functionality makes integration tests fail,
we can't use `headroom` for CI build. to resolve this issue,

- created new maven profiles: `web-ci` and `web-dist` (default)
- maven will execute `yarn run build:ci` with the `web-ci` profile which doesn't include headroom in `app.js`

### What type of PR is it?
[Improvement]

### Todos
* [x] - Add headroom.js
* [x] - Filter out useless dependencies
* [x] - Apply headroom.js

### What is the Jira issue?

[ZEPPELIN-2427](https://issues.apache.org/jira/browse/ZEPPELIN-2427)

### How should this be tested?

1. Open Zeppelin
2. Scroll down, up to see whether navbar and note action bar are hided or not.

### Screenshots (if appropriate)

![2427](https://cloud.githubusercontent.com/assets/4968473/25214004/afae7a1c-25cf-11e7-9ee1-f41e767d2039.gif)

### Questions:
* Does the licenses files need update?
* Is there breaking changes for older versions?
* Does this needs documentation?

Author: 1ambda <1a...@gmail.com>

Closes #2265 from 1ambda/ZEPPELIN-2427/hide-navbar-and-noteActionBar-scrolling-down and squashes the following commits:

32933d8 [1ambda] fix: Download headroom using npm
8930d70 [1ambda] fix: DON'T apply headroom for CI build
5a0219e [1ambda] fix: Remove invalid Gruntfile conf
16a12e6 [1ambda] chore: Add license description
efdd42e [1ambda] fix: Inject headroom to karma
14905be [1ambda] feat: Apply headroom.js
8934d04 [1ambda] fix: Filter out useless deps
e58e357 [1ambda] feat: Add headroom dep


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/bba0a7b4
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/bba0a7b4
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/bba0a7b4

Branch: refs/heads/master
Commit: bba0a7b47f95f35efd692d78cd4a5c3bd0c6b071
Parents: 925d09c
Author: 1ambda <1a...@gmail.com>
Authored: Sun Apr 23 14:57:25 2017 +0900
Committer: Lee moon soo <mo...@apache.org>
Committed: Fri Apr 28 02:53:53 2017 -0700

----------------------------------------------------------------------
 .travis.yml                                     | 12 ++---
 zeppelin-distribution/src/bin_license/LICENSE   |  3 +-
 zeppelin-web/Gruntfile.js                       | 55 +++++++++-----------
 zeppelin-web/package.json                       |  7 ++-
 zeppelin-web/pom.xml                            | 20 ++++++-
 zeppelin-web/src/app/app.js                     | 15 ++++--
 .../src/app/notebook/notebook-actionBar.html    |  5 +-
 zeppelin-web/src/app/notebook/notebook.css      | 11 ++++
 .../src/assets/styles/looknfeel/default.css     |  1 -
 zeppelin-web/src/components/navbar/navbar.css   | 17 ++++--
 zeppelin-web/src/components/navbar/navbar.html  |  6 ++-
 zeppelin-web/webpack.config.js                  | 11 +++-
 12 files changed, 109 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 72104db..6130509 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -47,11 +47,11 @@ matrix:
 
     # Test core modules
     - jdk: "oraclejdk7"
-      env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtest='!ZeppelinSparkClusterTest,!org.apache.zeppelin.spark.*' -DfailIfNoTests=false"
+      env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtest='!ZeppelinSparkClusterTest,!org.apache.zeppelin.spark.*' -DfailIfNoTests=false"
 
     # Test selenium with spark module for 1.6.3
     - jdk: "oraclejdk7"
-      env: TEST_SELENIUM="true" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop-2.6 -Phelium-dev -Pexamples" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
+      env: TEST_SELENIUM="true" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop-2.6 -Phelium-dev -Pexamples" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
 
     # Test interpreter modules
     - jdk: "oraclejdk7"
@@ -59,19 +59,19 @@ matrix:
 
     # Test spark module for 2.1.0 with scala 2.11, livy
     - jdk: "oraclejdk7"
-      env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.1 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,livy" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
+      env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.1 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,livy" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
 
     # Test spark module for 2.0.2 with scala 2.11
     - jdk: "oraclejdk7"
-      env: SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pspark-2.0 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.0 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
     # Test spark module for 1.6.3 with scala 2.10
     - jdk: "oraclejdk7"
-      env: SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop-2.6 -Pscala-2.10" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop-2.6 -Pscala-2.10" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
     # Test spark module for 1.6.3 with scala 2.11
     - jdk: "oraclejdk7"
-      env: SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
     # Test python/pyspark with python 2, livy 0.2
     - sudo: required

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-distribution/src/bin_license/LICENSE
----------------------------------------------------------------------
diff --git a/zeppelin-distribution/src/bin_license/LICENSE b/zeppelin-distribution/src/bin_license/LICENSE
index ce5b3bb..d941093 100644
--- a/zeppelin-distribution/src/bin_license/LICENSE
+++ b/zeppelin-distribution/src/bin_license/LICENSE
@@ -269,7 +269,8 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
     (The MIT License) Java LSH 0.10 (info.debatty:java-lsh:0.10 - https://github.com/tdebatty/java-LSH)
     (The MIT License) JSoup 1.6.1 (org.jsoup:jsoup:1.6.1 - https://github.com/jhy/jsoup/)
     (The MIT License) Unirest 1.4.9 (com.mashape.unirest:unirest-java:1.4.9 - https://github.com/Mashape/unirest-java)
-    (The MIT License) ngclipboard v1.1.1 (https://github.com/sachinchoolur/ngclipboard) - https://github.com/sachinchoolur/ngclipboard/blob/1.1.1/LICENSE)
+    (The MIT License) ngclipboard v1.1.1 (https://github.com/sachinchoolur/ngclipboard) - https://github.com/sachinchoolur/ngclipboard/blob/1.1.1/LICENSE
+    (The MIT License) headroom.js 0.9.3 (https://github.com/WickyNilliams/headroom.js) - https://github.com/WickyNilliams/headroom.js/blob/master/LICENSE
 
 ========================================================================
 BSD-style licenses

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/Gruntfile.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/Gruntfile.js b/zeppelin-web/Gruntfile.js
index 764bbc2..c25b560 100644
--- a/zeppelin-web/Gruntfile.js
+++ b/zeppelin-web/Gruntfile.js
@@ -15,14 +15,6 @@
  * limitations under the License.
  */
 
-// Generated on 2014-08-29 using generator-angular 0.9.5
-
-// # Globbing
-// for performance reasons we're only matching one level down:
-// 'test/spec/{,*/}*.js'
-// use this if you want to recursively match all subfolders:
-// 'test/spec/**/*.js'
-
 module.exports = function(grunt) {
 
   // Load grunt tasks automatically
@@ -47,22 +39,6 @@ module.exports = function(grunt) {
     // Project settings
     yeoman: appConfig,
 
-    babel: {
-      options: {
-        sourceMap: true,
-        presets: ['es2015'],
-        plugins: ['transform-object-rest-spread']
-      },
-      dist: {
-        files: [{
-          expand: true,
-          cwd: '.tmp/concat/scripts',
-          src: ['scripts.js'],
-          dest: '.tmp/concat/scripts',
-        }]
-      }
-    },
-
     // use ngAnnotate instead og ngMin
     ngAnnotate: {
       dist: {
@@ -102,7 +78,7 @@ module.exports = function(grunt) {
     watch: {
       bower: {
         files: ['bower.json'],
-        tasks: ['wiredep']
+        tasks: ['wiredep:dist', 'wiredep:test']
       },
       html: {
         files: [
@@ -160,15 +136,24 @@ module.exports = function(grunt) {
 
     // Automatically inject Bower components into the app
     wiredep: {
-      options: {},
-      app: {
+      ci: {
         src: ['<%= yeoman.app %>/index.html'],
-        ignorePath: /\.\.\//
+        ignorePath: /\.\.\//,
+        exclude: [
+        ]
+      },
+      dist: {
+        src: ['<%= yeoman.app %>/index.html'],
+        ignorePath: /\.\.\//,
+        exclude: [
+        ],
       },
       test: {
         devDependencies: true,
         src: '<%= karma.unit.configFile %>',
         ignorePath: /\.\.\//,
+        exclude: [
+        ],
         fileTypes: {
           js: {
             block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
@@ -387,7 +372,7 @@ module.exports = function(grunt) {
     // Test settings
     karma: {
       unit: {
-        configFile: 'test/karma.conf.js',
+        configFile: 'karma.conf.js',
         singleRun: true
       }
     }
@@ -395,7 +380,8 @@ module.exports = function(grunt) {
 
   grunt.registerTask('pre-webpack-dev', 'Compile then start a connect web server', function(target) {
     grunt.task.run([
-      'wiredep',
+      'wiredep:test',
+      'wiredep:dist',
     ]);
   });
 
@@ -405,7 +391,14 @@ module.exports = function(grunt) {
 
   grunt.registerTask('pre-webpack-dist', [
     'htmlhint',
-    'wiredep',
+    'wiredep:test',
+    'wiredep:dist',
+  ]);
+
+  grunt.registerTask('pre-webpack-ci', [
+    'htmlhint',
+    'wiredep:test',
+    'wiredep:ci',
   ]);
 
   grunt.registerTask('post-webpack-dist', [

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/package.json
----------------------------------------------------------------------
diff --git a/zeppelin-web/package.json b/zeppelin-web/package.json
index 106d28f..e25254e 100644
--- a/zeppelin-web/package.json
+++ b/zeppelin-web/package.json
@@ -9,7 +9,8 @@
     "clean": "rimraf dist && rimraf .tmp",
     "postinstall": "bower install --silent",
     "prebuild": "npm-run-all clean lint:once",
-    "build": "grunt pre-webpack-dist && webpack && grunt post-webpack-dist",
+    "build:dist": "grunt pre-webpack-dist && webpack && grunt post-webpack-dist",
+    "build:ci": "grunt pre-webpack-ci && webpack && grunt post-webpack-dist",
     "lint:watch": "esw --watch src",
     "lint:once": "eslint src",
     "predev": "grunt pre-webpack-dev",
@@ -22,7 +23,8 @@
   },
   "dependencies": {
     "grunt-angular-templates": "^0.5.7",
-    "grunt-dom-munger": "^3.4.0"
+    "grunt-dom-munger": "^3.4.0",
+    "headroom.js": "^0.9.3"
   },
   "devDependencies": {
     "autoprefixer": "^6.5.4",
@@ -64,6 +66,7 @@
     "grunt-usemin": "^2.1.1",
     "grunt-wiredep": "~2.0.0",
     "html-webpack-plugin": "^2.24.1",
+    "imports-loader": "^0.7.1",
     "jasmine-core": "^2.5.2",
     "karma": "~1.3.0",
     "karma-coverage": "^1.1.1",

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-web/pom.xml b/zeppelin-web/pom.xml
index 8c114dd1..d529930 100644
--- a/zeppelin-web/pom.xml
+++ b/zeppelin-web/pom.xml
@@ -93,7 +93,7 @@
               <goal>yarn</goal>
             </goals>
             <configuration>
-              <arguments>run build</arguments>
+              <arguments>${web.build.command}</arguments>
             </configuration>
           </execution>
 
@@ -154,5 +154,23 @@
     </plugins>
   </build>
 
+  <profiles>
+    <profile>
+      <id>web-dist</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <web.build.command>run build:dist</web.build.command>
+      </properties>
+    </profile>
+    <profile>
+      <id>web-ci</id>
+      <properties>
+        <web.build.command>run build:ci</web.build.command>
+      </properties>
+    </profile>
+  </profiles>
+
 
 </project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/app/app.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/app.js b/zeppelin-web/src/app/app.js
index 0775d38..fc5ffbd 100644
--- a/zeppelin-web/src/app/app.js
+++ b/zeppelin-web/src/app/app.js
@@ -15,7 +15,10 @@
  * limitations under the License.
  */
 
-let zeppelinWebApp = angular.module('zeppelinWebApp', [
+import 'headroom.js'
+import 'headroom.js/dist/angular.headroom'
+
+const requiredModules = [
   'ngCookies',
   'ngAnimate',
   'ngRoute',
@@ -33,8 +36,14 @@ let zeppelinWebApp = angular.module('zeppelinWebApp', [
   'ngToast',
   'focus-if',
   'ngResource',
-  'ngclipboard'
-])
+  'ngclipboard',
+]
+
+// headroom should not be used for CI, since we have to execute some integration tests.
+// otherwise, they will fail.
+if (!process.env.BUILD_CI) { requiredModules.push('headroom') }
+
+let zeppelinWebApp = angular.module('zeppelinWebApp', requiredModules)
   .filter('breakFilter', function () {
     return function (text) {
       // eslint-disable-next-line no-extra-boolean-cast

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/app/notebook/notebook-actionBar.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html b/zeppelin-web/src/app/notebook/notebook-actionBar.html
index c90c120..00434c9 100644
--- a/zeppelin-web/src/app/notebook/notebook-actionBar.html
+++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html
@@ -11,7 +11,8 @@ 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.
 -->
-<div class="noteAction" ng-show="note.id && !paragraphUrl">
+<headroom class="noteAction"
+          ng-show="note.id && !paragraphUrl">
   <h3>
     <div style="float: left; width: auto; max-width: 40%"
       ng-controller="ElasticInputCtrl as input">
@@ -274,4 +275,4 @@ limitations under the License.
       </span>
     </div>
   </h3>
-</div>
+</headroom>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/app/notebook/notebook.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.css b/zeppelin-web/src/app/notebook/notebook.css
index 8c48528..86a2dd2 100644
--- a/zeppelin-web/src/app/notebook/notebook.css
+++ b/zeppelin-web/src/app/notebook/notebook.css
@@ -320,3 +320,14 @@
   pointer-events: none;
 }
 
+/** required to pin, unpin `noteAction` */
+.noteAction.headroom {
+  position: fixed;
+  top: 50px;
+  left: 0;
+  right: 0;
+  transition: all .2s ease-in-out;
+}
+.noteAction.headroom--unpinned { top: -100px; }
+.noteAction.headroom--pinned { top: 50px; /** `noteAction` top */ }
+

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/assets/styles/looknfeel/default.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/assets/styles/looknfeel/default.css b/zeppelin-web/src/assets/styles/looknfeel/default.css
index 9803bc2..dd24013 100644
--- a/zeppelin-web/src/assets/styles/looknfeel/default.css
+++ b/zeppelin-web/src/assets/styles/looknfeel/default.css
@@ -36,4 +36,3 @@ body {
 .ng-toast.ng-toast--top {
   top: 100px;
 }
-

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/components/navbar/navbar.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.css b/zeppelin-web/src/components/navbar/navbar.css
index e5d299a..5592e7d 100644
--- a/zeppelin-web/src/components/navbar/navbar.css
+++ b/zeppelin-web/src/components/navbar/navbar.css
@@ -12,21 +12,32 @@
  * limitations under the License.
  */
 
-#searchTermId {  
+#searchTermId {
   min-width: 200px;
 }
 
 
 @media (min-width: 795px) and (max-width: 830px) {
-  input#searchTermId {  
+  input#searchTermId {
     width: 170px;
     min-width: 170px;
   }
 }
 
 @media (min-width: 768px) and (max-width: 794px) {
-  input#searchTermId {  
+  input#searchTermId {
     width: 140px;
     min-width: 140px;
   }
 }
+
+/** required to pin, unpin `navbar-fixed-top` */
+.navbar-fixed-top.headroom {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  transition: all .2s ease-in-out;
+}
+.navbar-fixed-top.headroom--unpinned { top: -100px; }
+.navbar-fixed-top.headroom--pinned { top: 0; /** `navbar` top */ }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/src/components/navbar/navbar.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html
index 799206b..dec48a6 100644
--- a/zeppelin-web/src/components/navbar/navbar.html
+++ b/zeppelin-web/src/components/navbar/navbar.html
@@ -10,7 +10,9 @@ See the License for the specific language governing permissions and
 limitations under the License.
 -->
 
-<div class="navbar navbar-inverse navbar-fixed-top" style="display: none;" role="navigation" ng-class="{'displayNavBar': !asIframe}">
+<headroom class="navbar navbar-inverse navbar-fixed-top"
+          style="display: none;" role="navigation"
+          ng-class="{'displayNavBar': !asIframe}">
   <div class="container">
     <div class="navbar-header">
       <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
@@ -109,7 +111,7 @@ limitations under the License.
       </ul>
     </div>
   </div>
-</div>
+</headroom>
 <div id="aboutModal" class="modal fade" role="dialog"
      tabindex="-1">
   <div class="modal-dialog">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/bba0a7b4/zeppelin-web/webpack.config.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/webpack.config.js b/zeppelin-web/webpack.config.js
index f3ed276..2011440 100644
--- a/zeppelin-web/webpack.config.js
+++ b/zeppelin-web/webpack.config.js
@@ -68,7 +68,8 @@ InsertLiveReloadPlugin.prototype.apply = function apply(compiler) {
  */
 var ENV = process.env.npm_lifecycle_event;
 var isTest = ENV === 'test';
-var isProd = ENV === 'build';
+var isProd = ENV.startsWith('build')
+var isCI = ENV === 'build:ci'
 
 module.exports = function makeWebpackConfig () {
   /**
@@ -139,6 +140,11 @@ module.exports = function makeWebpackConfig () {
   config.module = {
     preLoaders: [],
     loaders: [{
+      // headroom 0.9.3 doesn't work with webpack
+      // https://github.com/WickyNilliams/headroom.js/issues/213#issuecomment-281106943
+      test: require.resolve('headroom.js'),
+      loader: 'imports-loader?this=>window,define=>false,exports=>false'
+    }, {
       // JS LOADER
       // Reference: https://github.com/babel/babel-loader
       // Transpile .js files using babel-loader
@@ -231,7 +237,8 @@ module.exports = function makeWebpackConfig () {
         'process.env': {
           HELIUM_BUNDLE_DEV: process.env.HELIUM_BUNDLE_DEV,
           SERVER_PORT: serverPort,
-          WEB_PORT: webPort
+          WEB_PORT: webPort,
+          BUILD_CI: (isCI) ? JSON.stringify(true) : JSON.stringify(false)
         }
       })
     )