├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── chrome-tabs.sublime-project ├── gulpfile.js ├── package.json └── source ├── index.html ├── javascript └── app.js └── sass └── style.scss /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # Howto with your editor: 4 | # Sublime: https://github.com/sindresorhus/editorconfig-sublime 5 | 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | # Unix-style newlines with a newline ending every file 10 | [**] 11 | end_of_line = lf 12 | insert_final_newline = true 13 | 14 | # Standard at: https://github.com/felixge/node-style-guide 15 | [**.js, **.json] 16 | trim_trailing_whitespace = true 17 | indent_style = space 18 | indent_size = 2 19 | max_line_length = 80 20 | quote_type = single 21 | curly_bracket_next_line = false 22 | spaces_around_operators = true 23 | space_after_control_statements = true 24 | space_after_anonymous_functions = false 25 | spaces_in_brackets = false 26 | 27 | # https://github.com/jedmao/codepainter 28 | [node_modules/**.js] 29 | codepaint = false 30 | 31 | # No Standard. Please document a standard if different from .js 32 | [**.yml, **.html, **.css] 33 | trim_trailing_whitespace = true 34 | indent_style = space 35 | indent_size = 2 36 | 37 | # No standard. Please document a standard if different from .js 38 | [**.md] 39 | indent_style = space 40 | 41 | # Standard at: 42 | [**.py] 43 | indent_style = space 44 | indent_size = 4 45 | 46 | # Standard at: 47 | [Makefile] 48 | indent_style = tab 49 | indent_size = 8 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | node_modules 3 | 4 | dist 5 | 6 | *.sublime-workspace 7 | 8 | Thumbs.db 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dimitar Stojanov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chrome Tabs 2 | 3 | This is project to demonstrate Chrome-like tabs made with Bootstrap and AngularJS. 4 | 5 | ##Prerequisites 6 | 7 | In order to build this project you need to have Node.js and npm (Node Package Manager) installed on your system. You can download them from [here](https://nodejs.org/download/) and follow this [install instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager). 8 | 9 | To compile the Sass source to CSS, you’ll need Ruby, Sass and Compass. To install Ruby follow this [guide](https://www.ruby-lang.org/en/documentation/installation/), for Sass [this](http://sass-lang.com/install), and for Compass refer to [this guide](http://compass-style.org/install/). 10 | 11 | In some cases when installing node packages you'll need [Python 2.7](https://www.python.org/downloads/) and [C++ Libraries](https://support.microsoft.com/en-us/kb/2977003) (Windows) to build them. 12 | 13 | Note that these executables need to be accessed from command line, so make sure they're added in the environment path. On Linux and Mac they're automatically added to the path, and for Windows you may need to follow this [instructions](http://www.computerhope.com/issues/ch000549.htm), just be careful not to mess the existing path value. 14 | 15 | ## Setup 16 | 17 | First install gulp command line tool globally with: 18 | 19 | `npm install --global gulp` 20 | 21 | And from the project's root install the dependencies with: 22 | 23 | `npm install` 24 | 25 | ## Build 26 | 27 | To build the code just run `gulp` from the command line. This will produce functional version in the `dist` folder. 28 | 29 | ## License 30 | This source code is under [MIT license](https://github.com/imjustd/chrome-tabs/blob/master/LICENSE). 31 | -------------------------------------------------------------------------------- /chrome-tabs.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "follow_symlinks": true, 6 | "path": ".", 7 | "folder_exclude_patterns": ["node_modules", ".sass-cache", ".git"], 8 | "file_exclude_patterns": ["*.sublime-workspace"] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | gutil = require('gulp-util'), 3 | 4 | jshint = require('gulp-jshint'), 5 | compass = require('gulp-compass'), 6 | concat = require('gulp-concat'), 7 | uglify = require('gulp-uglify'), 8 | sourcemaps = require('gulp-sourcemaps'), 9 | 10 | input = { 11 | 'html': 'source/*.html', 12 | 'sass': 'source/sass/**/*.scss', 13 | 'javascript': 'source/javascript/**/*.js' 14 | }, 15 | 16 | output = { 17 | 'html': 'dist', 18 | 'stylesheets': 'dist/css', 19 | 'javascript': 'dist/js' 20 | }; 21 | 22 | /* run javascript through jshint */ 23 | gulp.task('jshint', function() { 24 | return gulp.src(input.javascript) 25 | .pipe(jshint()) 26 | .pipe(jshint.reporter('jshint-stylish')); 27 | }); 28 | 29 | /* concat javascript files, minify if --type production */ 30 | gulp.task('build-js', function() { 31 | return gulp.src(input.javascript) 32 | .pipe(sourcemaps.init()) 33 | .pipe(concat('app.js')) 34 | //only uglify if gulp is ran with '--type production' 35 | .pipe(gutil.env.type === 'production' ? uglify() : gutil.noop()) 36 | .pipe(sourcemaps.write()) 37 | .pipe(gulp.dest(output.javascript)); 38 | }); 39 | 40 | /* compile scss files */ 41 | gulp.task('build-css', function() { 42 | return gulp.src(input.sass) 43 | .pipe(sourcemaps.init()) 44 | .pipe(compass({ 45 | css: 'dist/css', 46 | sass: 'source/sass' 47 | })) 48 | .pipe(sourcemaps.write()) 49 | .pipe(gulp.dest(output.stylesheets)); 50 | }); 51 | 52 | /* copy any html files to dist */ 53 | gulp.task('copy-html', function() { 54 | return gulp.src(input.html) 55 | .pipe(gulp.dest(output.html)); 56 | }); 57 | 58 | /* Watch these files for changes and run the task on update */ 59 | gulp.task('watch', function() { 60 | gulp.watch(input.javascript, ['jshint', 'build-js']); 61 | gulp.watch(input.sass, ['build-css']); 62 | gulp.watch(input.html, ['copy-html']); 63 | }); 64 | 65 | /* run the watch task when gulp is called without arguments */ 66 | gulp.task('default', ['jshint', 'build-js', 'build-css', 'copy-html', 'watch']); 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chrome-tabs", 3 | "version": "1.0.0", 4 | "description": "Web chrome-like tabs made with Bootstrap and AngularJS", 5 | "homepage": "http://invoicebus.com", 6 | "repository": "imjustd/chrome-tabs", 7 | "keywords": [ 8 | "chrome", 9 | "tabs", 10 | "bootstrap", 11 | "angular" 12 | ], 13 | "author": "Dimitar Stojanov ", 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 0.10" 17 | }, 18 | "devDependencies": { 19 | "gulp": "^3.8.11", 20 | "gulp-compass": "^2.0.3", 21 | "gulp-concat": "^2.5.2", 22 | "gulp-jshint": "^1.9.2", 23 | "gulp-sourcemaps": "^1.3.0", 24 | "gulp-uglify": "^1.1.0", 25 | "gulp-util": "^3.0.4", 26 | "jshint-stylish": "^1.0.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chrome tabs with Bootstrap and AngularJS 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {{tab.title}} 20 | 21 |

{{tab.content}}

22 |
23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /source/javascript/app.js: -------------------------------------------------------------------------------- 1 | // Declare the chromeTabsApp module and its dependency 'ui.bootstrap' 2 | var app = angular.module('chromeTabsApp', ['ui.bootstrap']); 3 | // Declare the AppCtrl controller 4 | app 5 | .controller('AppCtrl', ['$scope', function ($scope) { 6 | // Tab counter 7 | var counter = 1; 8 | // Array to store the tabs 9 | $scope.tabs = []; 10 | 11 | // Add tab to the end of the array 12 | var addTab = function () { 13 | $scope.tabs.push({ title: 'Tab ' + counter, content: 'Tab ' + counter }); 14 | counter++; 15 | $scope.tabs[$scope.tabs.length - 1].active = true; 16 | }; 17 | 18 | // Remove tab by index 19 | var removeTab = function (event, index) { 20 | event.preventDefault(); 21 | event.stopPropagation(); 22 | $scope.tabs.splice(index, 1); 23 | }; 24 | 25 | // Initialize the scope functions 26 | $scope.addTab = addTab; 27 | $scope.removeTab = removeTab; 28 | 29 | // For demonstration add 10 tabs 30 | for (var i = 0; i < 10; i++) { 31 | addTab(); 32 | } 33 | }]) 34 | .directive('tabHighlight', [function () { 35 | return { 36 | restrict: 'A', 37 | link: function (scope, element) { 38 | // Here is the major jQuery usage where we add the event 39 | // listeners mousemove and mouseout on the tabs to initalize 40 | // the moving highlight for the inactive tabs 41 | var x, y, initial_background = '#c3d5e6'; 42 | 43 | element 44 | .removeAttr('style') 45 | .mousemove(function (e) { 46 | // Add highlight effect on inactive tabs 47 | if(!element.hasClass('active')) 48 | { 49 | x = e.pageX - this.offsetLeft; 50 | y = e.pageY - this.offsetTop; 51 | 52 | // Set the background when mouse moves over inactive tabs 53 | element 54 | .css({ background: '-moz-radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background }) 55 | .css({ background: '-webkit-radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background }) 56 | .css({ background: 'radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background }); 57 | } 58 | }) 59 | .mouseout(function () { 60 | // Return the inital background color of the tab 61 | element.removeAttr('style'); 62 | }); 63 | } 64 | }; 65 | }]); 66 | -------------------------------------------------------------------------------- /source/sass/style.scss: -------------------------------------------------------------------------------- 1 | @import "compass"; 2 | 3 | // The main tab container 4 | .tab-container { 5 | background: #8dc8fb; // Make the background blue 6 | margin: 0; 7 | padding: 0; 8 | max-height: 40px; 9 | 10 | ul { 11 | &.nav-tabs { 12 | margin: 0; 13 | list-style-type: none; 14 | line-height: 40px; 15 | max-height: 40px; 16 | overflow: hidden; 17 | display: inline-block; 18 | @include display-flex; // This is the magic that will dynamically expand/shrink the width tabs 19 | padding-right: 20px; 20 | border-bottom: 5px solid #f7f7f7; 21 | 22 | $color: #c3d5e6; // Color for the disabled files 23 | 24 | // Inactive tab styles 25 | > li { 26 | $raduis: 28px 145px; // Radius to make the tabs look like trapezoid 27 | 28 | // Apply the radius 29 | @include border-top-left-radius($raduis); 30 | @include border-top-right-radius($raduis); 31 | 32 | margin: 5px -14px 0; 33 | padding: 0 30px 0 25px; 34 | height: 170px; 35 | background: $color; 36 | position: relative; 37 | width: 200px; 38 | max-width: 200px; 39 | min-width: 20px; 40 | border:1px solid #aaa; 41 | 42 | @include box-shadow(0 4px 6px rgba(0,0,0,.5)); 43 | 44 | &:first-child { 45 | margin-left: 0; 46 | } 47 | 48 | &:last-of-type { 49 | margin-right: 0; 50 | } 51 | 52 | > a { 53 | display: block; 54 | max-width:100%; 55 | text-decoration: none; 56 | color: #222; 57 | padding: 3px 7px; 58 | 59 | span { 60 | overflow: hidden; 61 | white-space: nowrap; 62 | display: block; 63 | } 64 | 65 | &:focus, 66 | &:hover { 67 | background-color: transparent; 68 | border-color: transparent; 69 | } 70 | 71 | // The remove button styles 72 | .glyphicon-remove { 73 | color: #777; 74 | display: inline-block; 75 | padding:3px; 76 | font-size: 10px; 77 | position:absolute; 78 | z-index: 10; 79 | top:7px; 80 | right: -10px; 81 | @include border-radius(50%); 82 | 83 | &:hover { 84 | background: #d39ea3; 85 | color: white; 86 | @include box-shadow(inset 0 1px 1px rgba(0,0,0,.25)); 87 | @include text-shadow(0 1px 1px rgba(0,0,0,.25)); 88 | } 89 | } 90 | } 91 | 92 | // Active tab style 93 | &.active { 94 | z-index: 2; 95 | @include background-image(linear-gradient(white, #f7f7f7 30px)); 96 | 97 | > a { 98 | background-color: transparent; 99 | border-color: transparent; 100 | border-bottom-color: transparent; 101 | 102 | &:focus, 103 | &:hover { 104 | background-color: transparent; 105 | border-color: transparent; 106 | border-bottom-color: transparent; 107 | } 108 | } 109 | } 110 | } 111 | 112 | // The open new tab button 113 | .btn { 114 | float: left; 115 | height: 20px; 116 | width: 35px; 117 | min-width: 35px; 118 | max-width: 35px; 119 | margin: 10px 0 0 0; 120 | border-color: #71a0c9; 121 | outline: none; 122 | 123 | @include transform(skew(30deg)); 124 | 125 | &.btn-default { 126 | background: $color; 127 | 128 | &:hover { 129 | background: #d2deeb; 130 | } 131 | 132 | &:active { 133 | background: #9cb5cc; 134 | } 135 | } 136 | } 137 | } 138 | } 139 | 140 | // Styling the tab containter 141 | .tab-pane { 142 | padding: 60px 40px; 143 | text-align: center; 144 | 145 | &.active { 146 | border-top:1px solid #ddd; 147 | } 148 | } 149 | } 150 | --------------------------------------------------------------------------------