├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── build └── index.html ├── package.json ├── src └── scripts │ ├── .app.jsx.swp │ ├── app.jsx │ ├── components │ ├── DropdownMenu.jsx │ ├── NavItem.jsx │ ├── Navbar.jsx │ ├── NavbarDropdown.jsx │ ├── NavbarHeader.jsx │ └── NavbarItems.jsx │ └── index.js ├── webpack.config.js └── webpack.development.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "settings": { 8 | "ecmascript": 6, 9 | "jsx": true 10 | }, 11 | "plugins": [ 12 | "react" 13 | ], 14 | "rules": { 15 | "strict": 0, 16 | "quotes": 0, 17 | "no-unused-vars": 0, 18 | "camelcase": 0, 19 | "no-underscore-dangle": 0, 20 | "comma-dangle": 2, // disallow or enforce trailing commas 21 | "no-cond-assign": 2, // disallow assignment in conditional expressions 22 | "no-console": 1, // disallow use of console (off by default in the node environment) 23 | "no-constant-condition": 2, // disallow use of constant expressions in conditions 24 | "no-control-regex": 2, // disallow control characters in regular expressions 25 | "no-debugger": 2, // disallow use of debugger 26 | "no-dupe-args": 2, // disallow duplicate arguments in functions 27 | "no-dupe-keys": 2, // disallow duplicate keys when creating object literals 28 | "no-duplicate-case": 2, // disallow a duplicate case label. 29 | "no-empty": 2, // disallow empty statements 30 | "no-empty-class": 2, // disallow the use of empty character classes in regular expressions 31 | "no-ex-assign": 2, // disallow assigning to the exception in a catch block 32 | "no-extra-boolean-cast": 2, // disallow double-negation boolean casts in a boolean context 33 | "no-extra-parens": 0, // disallow unnecessary parentheses (off by default) 34 | "no-extra-semi": 2, // disallow unnecessary semicolons 35 | "no-func-assign": 2, // disallow overwriting functions written as function declarations 36 | "no-inner-declarations": 2, // disallow function or variable declarations in nested blocks 37 | "no-invalid-regexp": 2, // disallow invalid regular expression strings in the RegExp constructor 38 | "no-irregular-whitespace": 2, // disallow irregular whitespace outside of strings and comments 39 | "no-negated-in-lhs": 2, // disallow negation of the left operand of an in expression 40 | "no-obj-calls": 2, // disallow the use of object properties of the global object (Math and JSON) as functions 41 | "no-regex-spaces": 2, // disallow multiple spaces in a regular expression literal 42 | "no-reserved-keys": 2, // disallow reserved words being used as object literal keys (off by default) 43 | "no-sparse-arrays": 2, // disallow sparse arrays 44 | "no-unreachable": 2, // disallow unreachable statements after a return, throw, continue, or break statement 45 | "use-isnan": 2, // disallow comparisons with the value NaN 46 | "valid-jsdoc": 2, // Ensure JSDoc comments are valid (off by default) 47 | "valid-typeof": 2, // Ensure that the results of typeof are compared against a valid string 48 | 49 | // 50 | // Best Practices 51 | // 52 | // These are rules designed to prevent you from making mistakes. 53 | // They either prescribe a better way of doing something or help you avoid footguns. 54 | // 55 | "block-scoped-var": 0, // treat var statements as if they were block scoped (off by default). 0: deep destructuring is not compatible https://github.com/eslint/eslint/issues/1863 56 | "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default) 57 | "consistent-return": 2, // require return statements to either always or never specify values 58 | "curly": 2, // specify curly brace conventions for all control statements 59 | "default-case": 2, // require default case in switch statements (off by default) 60 | "dot-notation": 2, // encourages use of dot notation whenever possible 61 | "eqeqeq": 2, // require the use of === and !== 62 | "guard-for-in": 0, // make sure for-in loops have an if statement (off by default) 63 | "no-alert": 2, // disallow the use of alert, confirm, and prompt 64 | "no-caller": 2, // disallow use of arguments.caller or arguments.callee 65 | "no-div-regex": 2, // disallow division operators explicitly at beginning of regular expression (off by default) 66 | "no-else-return": 2, // disallow else after a return in an if (off by default) 67 | "no-empty-label": 2, // disallow use of labels for anything other then loops and switches 68 | "no-eq-null": 2, // disallow comparisons to null without a type-checking operator (off by default) 69 | "no-eval": 2, // disallow use of eval() 70 | "no-extend-native": 2, // disallow adding to native types 71 | "no-extra-bind": 2, // disallow unnecessary function binding 72 | "no-fallthrough": 2, // disallow fallthrough of case statements 73 | "no-floating-decimal": 2, // disallow the use of leading or trailing decimal points in numeric literals (off by default) 74 | "no-implied-eval": 2, // disallow use of eval()-like methods 75 | "no-iterator": 2, // disallow usage of __iterator__ property 76 | "no-labels": 2, // disallow use of labeled statements 77 | "no-lone-blocks": 2, // disallow unnecessary nested blocks 78 | "no-loop-func": 2, // disallow creation of functions within loops 79 | "no-multi-spaces": 2, // disallow use of multiple spaces 80 | "no-multi-str": 2, // disallow use of multiline strings 81 | "no-native-reassign": 2, // disallow reassignments of native objects 82 | "no-new": 2, // disallow use of new operator when not part of the assignment or comparison 83 | "no-new-func": 2, // disallow use of new operator for Function object 84 | "no-new-wrappers": 2, // disallows creating new instances of String,Number, and Boolean 85 | "no-octal": 2, // disallow use of octal literals 86 | "no-octal-escape": 2, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; 87 | "no-param-reassign": 2, // disallow reassignment of function parameters (off by default) 88 | "no-process-env": 2, // disallow use of process.env (off by default) 89 | "no-proto": 2, // disallow usage of __proto__ property 90 | "no-redeclare": 2, // disallow declaring the same variable more then once 91 | "no-return-assign": 2, // disallow use of assignment in return statement 92 | "no-script-url": 2, // disallow use of javascript: urls. 93 | "no-self-compare": 2, // disallow comparisons where both sides are exactly the same (off by default) 94 | "no-sequences": 2, // disallow use of comma operator 95 | "no-throw-literal": 2, // restrict what can be thrown as an exception (off by default) 96 | "no-unused-expressions": 2, // disallow usage of expressions in statement position 97 | "no-void": 2, // disallow use of void operator (off by default) 98 | "no-warning-comments": [0, {"terms": ["todo", "fixme"], "location": "start"}], // disallow usage of configurable warning terms in comments": 2, // e.g. TODO or FIXME (off by default) 99 | "no-with": 2, // disallow use of the with statement 100 | "radix": 2, // require use of the second argument for parseInt() (off by default) 101 | "vars-on-top": 2, // requires to declare all vars on top of their containing scope (off by default) 102 | "wrap-iife": 2, // require immediate function invocation to be wrapped in parentheses (off by default) 103 | "yoda": 2, // require or disallow Yoda conditions 104 | 105 | 106 | // 107 | // Variables 108 | // 109 | // These rules have to do with variable declarations. 110 | // 111 | "no-catch-shadow": 2, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) 112 | "no-delete-var": 2, // disallow deletion of variables 113 | "no-label-var": 2, // disallow labels that share a name with a variable 114 | "no-shadow": 2, // disallow declaration of variables already declared in the outer scope 115 | "no-shadow-restricted-names": 2, // disallow shadowing of names such as arguments 116 | "no-undef": 2, // disallow use of undeclared variables unless mentioned in a /*global */ block 117 | "no-undef-init": 2, // disallow use of undefined when initializing variables 118 | "no-undefined": 2, // disallow use of undefined variable (off by default) 119 | "no-unused-vars": 2, // disallow declaration of variables that are not used in the code 120 | "no-use-before-define": 2, // disallow use of variables before they are defined 121 | 122 | // 123 | //Stylistic Issues 124 | // 125 | // These rules are purely matters of style and are quite subjective. 126 | // 127 | "indent": [1, 2], // this option sets a specific tab width for your code (off by default) 128 | "brace-style": 1, // enforce one true brace style (off by default) 129 | "camelcase": 1, // require camel case names 130 | "comma-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after comma 131 | "comma-style": [1, "last"], // enforce one true comma style (off by default) 132 | "consistent-this": [1, "_this"], // enforces consistent naming when capturing the current execution context (off by default) 133 | "eol-last": 1, // enforce newline at the end of file, with no multiple empty lines 134 | "func-names": 0, // require function expressions to have a name (off by default) 135 | "func-style": 0, // enforces use of function declarations or expressions (off by default) 136 | "key-spacing": [1, {"beforeColon": false, "afterColon": true}], // enforces spacing between keys and values in object literal properties 137 | "max-nested-callbacks": [1, 3], // specify the maximum depth callbacks can be nested (off by default) 138 | "new-cap": [1, {newIsCap: true, capIsNew: false}], // require a capital letter for constructors 139 | "new-parens": 1, // disallow the omission of parentheses when invoking a constructor with no arguments 140 | "newline-after-var": 0, // allow/disallow an empty newline after var statement (off by default) 141 | "no-array-constructor": 1, // disallow use of the Array constructor 142 | "no-inline-comments": 1, // disallow comments inline after code (off by default) 143 | "no-lonely-if": 1, // disallow if as the only statement in an else block (off by default) 144 | "no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation 145 | "no-multiple-empty-lines": [1, {"max": 2}], // disallow multiple empty lines (off by default) 146 | "no-nested-ternary": 1, // disallow nested ternary expressions (off by default) 147 | "no-new-object": 1, // disallow use of the Object constructor 148 | "no-spaced-func": 1, // disallow space between function identifier and application 149 | "no-ternary": 0, // disallow the use of ternary operators (off by default) 150 | "no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines 151 | "no-underscore-dangle": 1, // disallow dangling underscores in identifiers 152 | "no-wrap-func": 1, // disallow wrapping of non-IIFE statements in parens 153 | "one-var": [1, "never"], // allow just one var statement per function (off by default) 154 | "operator-assignment": [1, "never"], // require assignment operator shorthand where possible or prohibit it entirely (off by default) 155 | "padded-blocks": [1, "never"], // enforce padding within blocks (off by default) 156 | "quote-props": [1, "as-needed"], // require quotes around object literal property names (off by default) 157 | "quotes": [1, "single"], // specify whether double or single quotes should be used 158 | "semi": [1, "always"], // require or disallow use of semicolons instead of ASI 159 | "semi-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after semicolons 160 | "sort-vars": 0, // sort variables within the same declaration block (off by default) 161 | "space-unary-ops": [1, {"words": true, "nonwords": false}], // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default) 162 | "spaced-line-comment": [1, "always"], // require or disallow a space immediately following the // in a line comment (off by default) 163 | "wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default) 164 | "space-after-keywords": [1, "always"], // require a space after certain keywords (off by default) 165 | "space-before-blocks": [1, "always"], // require or disallow space before blocks (off by default) 166 | "space-before-function-paren": [1, {"anonymous": "always", "named": "never"}], // require or disallow space before function opening parenthesis (off by default) 167 | "space-in-brackets": [1, "never"], // require or disallow spaces inside brackets (off by default) 168 | "space-in-parens": [1, "never"], // require or disallow spaces inside parentheses (off by default) 169 | 170 | // 171 | // ECMAScript 6 172 | // 173 | // These rules are only relevant to ES6 environments and are off by default. 174 | // 175 | "no-var": 2, // require let or const instead of var (off by default) 176 | "generator-star-spacing": [2, "before"], // enforce the spacing around the * in generator functions (off by default) 177 | // 178 | // Legacy 179 | // 180 | // The following rules are included for compatibility with JSHint and JSLint. 181 | // While the names of the rules may not match up with the JSHint/JSLint counterpart, 182 | // the functionality is the same. 183 | // 184 | "max-depth": [2, 3], // specify the maximum depth that blocks can be nested (off by default) 185 | "max-len": [2, 100, 2], // specify the maximum length of a line in your program (off by default) 186 | "max-params": [2, 5], // limits the number of parameters that can be used in the function declaration. (off by default) 187 | "max-statements": 0, // specify the maximum number of statement allowed in a function (off by default) 188 | "no-bitwise": 0, // disallow use of bitwise operators (off by default) 189 | "no-plusplus": 2, // disallow use of unary operators, ++ and -- (off by default) 190 | 191 | // 192 | // eslint-plugin-react 193 | // 194 | // React specific linting rules for ESLint 195 | // 196 | "react/display-name": 1, // Prevent missing displayName in a React component definition 197 | "react/jsx-quotes": [2, "double", "avoid-escape"], // Enforce quote style for JSX attributes 198 | "react/jsx-no-undef": 2, // Disallow undeclared variables in JSX 199 | "react/jsx-sort-props": 0, // Enforce props alphabetical sorting 200 | "react/jsx-uses-react": 2, // Prevent React to be incorrectly marked as unused 201 | "react/jsx-uses-vars": 2, // Prevent variables used in JSX to be incorrectly marked as unused 202 | "react/no-did-mount-set-state": 2, // Prevent usage of setState in componentDidMount 203 | "react/no-did-update-set-state": 2, // Prevent usage of setState in componentDidUpdate 204 | "react/no-multi-comp": 0, // Prevent multiple component definition per file 205 | "react/no-unknown-property": 2, // Prevent usage of unknown DOM property 206 | "react/prop-types": 0, // Prevent missing props validation in a React component definition 207 | "react/react-in-jsx-scope": 2, // Prevent missing React when using JSX 208 | "react/self-closing-comp": 2, // Prevent extra closing tags for components without children 209 | "react/wrap-multilines": 2, // Prevent missing parentheses around multilines JSX 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Directories # 2 | ########### 3 | /node_modules/ 4 | /lib/ 5 | 6 | # Compiled source # 7 | ################### 8 | *.com 9 | *.class 10 | *.dll 11 | *.exe 12 | *.o 13 | *.so 14 | 15 | # Packages # 16 | ############ 17 | # it's better to unpack these files and commit the raw source 18 | # git has its own built in compression methods 19 | *.7z 20 | *.dmg 21 | *.gz 22 | *.iso 23 | *.jar 24 | *.rar 25 | *.tar 26 | *.zip 27 | 28 | # Logs and databases # 29 | ###################### 30 | *.log 31 | *.sql 32 | *.sqlite 33 | 34 | # OS generated files # 35 | ###################### 36 | .DS_Store 37 | .DS_Store? 38 | ._* 39 | .Spotlight-V100 40 | .Trashes 41 | ehthumbs.db 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /src/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Haridu Senadeera 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 | 2 | # Dynamic ReactJS Navigation Bar 3 | Bootstrap Navigation bar rebuilt with React components. Written in ECMAScript 6 (ES6). 4 | No external stylesheets! This navigation bar is built with [Radium](http://projects.formidablelabs.com/radium/) inline styling. 5 | 6 | ### Desktop View 7 | 8 | ![navbar-desktop](https://cloud.githubusercontent.com/assets/12897928/10146744/0c184176-65f0-11e5-91c0-f4ed7aa4e543.png) 9 | 10 | ### Mobile View 11 | 12 | navbar-responsive 13 | 14 | ## Tree Structure 15 | 16 | ![navbartree](https://cloud.githubusercontent.com/assets/12897928/10251633/b148ac44-68f7-11e5-9c8a-cc0c72b5ada2.png) 17 | 18 | ## Components 19 | ```js 20 | const dropdownItems = [ 21 | {href: '#', name: 'Overview'}, 22 | {href: '#', name: 'Setup'}, 23 | {href: '#', name: 'Usage'}, 24 | ]; 25 | 26 | const navbar = ( 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ); 39 | 40 | React.render(navbar, document.getElementById('navbar')); 41 | ``` 42 | # Install 43 | Clone the repository. Then install dependencies, 44 | 45 | ```js 46 | npm install 47 | ``` 48 | 49 | # Run the webpack dev server 50 | ```js 51 | npm start 52 | ``` 53 | Go to http://localhost:8080/ on your favorite browser to view the Navigation bar. 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React Nav Bar 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bootstrap-navbar", 3 | "version": "1.1.0", 4 | "description": "React bootstrap navigation bar", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "prepublish": "node_modules/babel/bin/babel.js src/scripts/ --out-dir lib", 8 | "lint": "eslint src", 9 | "build": "webpack", 10 | "start": "webpack-dev-server --config webpack.development.js --devtool source-map --progress --colors --hot --content-base build --host 0.0.0.0" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/haridusenadeera/react-navbar.git" 15 | }, 16 | "author": "Haridu Senadeera", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/haridusenadeera/react-navbar/issues" 20 | }, 21 | "homepage": "https://github.com/haridusenadeera/react-navbar", 22 | "devDependencies": { 23 | "babel": "^5.8.34", 24 | "babel-core": "^5.6.7", 25 | "babel-eslint": "^3.1.23", 26 | "babel-loader": "^5.2.0", 27 | "eslint": "^0.24.1", 28 | "eslint-plugin-react": "^2.7.0", 29 | "node-libs-browser": "^0.5.2", 30 | "webpack": "^1.9.12", 31 | "webpack-dev-server": "^1.9.0" 32 | }, 33 | "dependencies": { 34 | "path-is-absolute": "^1.0.0", 35 | "radium": "^0.13.4", 36 | "react": "^0.13.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/scripts/.app.jsx.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haridusenadeera/react-navbar/d5896d93fdff933dd0d423d75da6afbaa90dfbd9/src/scripts/.app.jsx.swp -------------------------------------------------------------------------------- /src/scripts/app.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Navbar from './components/Navbar'; 3 | import NavItem from './components/NavItem'; 4 | import NavbarHeader from './components/NavbarHeader'; 5 | import NavbarItems from './components/NavbarItems'; 6 | import NavbarDropdown from './components/NavbarDropdown'; 7 | import DropdownMenu from './components/DropdownMenu'; 8 | 9 | const navitems = [ 10 | {link: '#', title: 'Setup'}, 11 | {link: '#', title: 'Usage'}, 12 | {link: '#', title: 'Advanced'}, 13 | {link: '#', title: 'Try it out'}, 14 | {link: '#', title: 'FAQ'} 15 | ]; 16 | 17 | const dropdownItems = [ 18 | {href: '#', name: 'ES2015'}, 19 | {href: '#', name: 'Setup'}, 20 | {href: '#', name: 'Usage'}, 21 | {href: '#', name: 'Advanced'}, 22 | {href: '#', name: 'Try it'}, 23 | {href: '#', name: 'FAQ'} 24 | ]; 25 | 26 | const navbarInstance = ( 27 | 28 | 29 | 30 | {navitems.map(item => { 31 | return ; 32 | })} 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ); 42 | 43 | React.render(navbarInstance, document.getElementById('navigation_bar')); 44 | -------------------------------------------------------------------------------- /src/scripts/components/DropdownMenu.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class DropdownMenu extends React.Component { 6 | displayName = 'Dropdown menu items' 7 | 8 | static propTypes = { 9 | menuItems: React.PropTypes.array, 10 | style: React.PropTypes.object, 11 | menuItemStyle: React.PropTypes.object, 12 | open: React.PropTypes.bool 13 | } 14 | 15 | getStyles = () => { 16 | const {open, active} = this.props; 17 | let styles = { 18 | menu: { 19 | position: 'absolute', 20 | top: '100%', 21 | left: '0', 22 | zIndex: '1000', 23 | float: 'left', 24 | minWidth: '160px', 25 | margin: '0px', 26 | padding: '5px 0px', 27 | fontSize: '14px', 28 | textAlign: 'left', 29 | listStyle: 'none', 30 | backgroundColor: '#fff', 31 | backgroundClip: 'padding-box', 32 | border: '1px solid #ccc', 33 | borderBottomLeftRadius: '4px', 34 | borderBottomRightRadius: '4px', 35 | boxShadow: '0 6px 12px #C9C9C9', 36 | boxSizing: 'border-box', 37 | 38 | '@media (max-width: 767px)': { 39 | position: 'static', 40 | float: 'none', 41 | width: 'auto', 42 | marginTop: '0', 43 | backgroundColor: 'transparent', 44 | border: '0', 45 | boxShadow: 'none' 46 | } 47 | }, 48 | link: { 49 | display: 'block', 50 | padding: '3px 20px', 51 | clear: 'both', 52 | fontWeight: 'normal', 53 | lineHeight: '1.42857143', 54 | color: '#333', 55 | whiteSpace: 'nowrap', 56 | textDecoration: 'none', 57 | boxSizing: 'border-box', 58 | 59 | ':hover': { 60 | color: '#262626', 61 | backgroundColor: '#f5f5f5' 62 | }, 63 | 64 | ':focus': { 65 | color: '#262626', 66 | backgroundColor: '#f5f5f5' 67 | }, 68 | 69 | '@media (max-width: 767px)': { 70 | backgroundColor: 'transparent', 71 | color: '#777', 72 | 73 | ':hover': { 74 | color: '#333', 75 | backgroundColor: 'transparent' 76 | } 77 | } 78 | } 79 | }; 80 | if (active) { 81 | styles.menu.display = open ? 'block' : 'none'; 82 | } else { 83 | styles.menu.display = 'none'; 84 | } 85 | return styles; 86 | } 87 | 88 | render() { 89 | const defStyle = this.getStyles(); 90 | const {menuItems, style, menuItemStyle} = this.props; 91 | return ( 92 | 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/scripts/components/NavItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class NavItem extends React.Component { 6 | displayName = 'Navigation bar item' 7 | 8 | static propTypes = { 9 | link: React.PropTypes.string, 10 | title: React.PropTypes.string, 11 | style: React.PropTypes.object, 12 | itemStyle: React.PropTypes.object 13 | } 14 | 15 | getStyles = () => { 16 | return { 17 | base: { 18 | position: 'relative', 19 | display: 'block', 20 | boxSizing: 'border-box', 21 | 22 | '@media (min-width: 768px)': { 23 | float: 'left' 24 | } 25 | }, 26 | link: { 27 | paddingTop: '10px', 28 | paddingBottom: '10px', 29 | paddingLeft: '15px', 30 | paddingRight: '15px', 31 | lineHeight: '20px', 32 | position: 'relative', 33 | display: 'block', 34 | boxSizing: 'border-box', 35 | textDecoration: 'none', 36 | backgroundColor: 'transparent', 37 | color: '#777', 38 | 39 | ':hover': { 40 | color: '#333', 41 | backgroundColor: 'transparent' 42 | }, 43 | 44 | ':focus': { 45 | color: '#333', 46 | backgroundColor: 'transparent' 47 | }, 48 | 49 | '@media (min-width: 768px)': { 50 | paddingTop: '15px', 51 | paddingBottom: '15px' 52 | } 53 | } 54 | }; 55 | } 56 | 57 | render() { 58 | const defStyle = this.getStyles(); 59 | const {style, link, title, itemStyle} = this.props; 60 | return ( 61 |
  • 62 | {title} 63 |
  • 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/scripts/components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class Navbar extends React.Component { 6 | displayName = 'Navigation bar' 7 | 8 | static propTypes = { 9 | navStyle: React.PropTypes.object, 10 | contStyle: React.PropTypes.object, 11 | children: React.PropTypes.node 12 | } 13 | 14 | state = { 15 | collapseIn: false 16 | } 17 | 18 | getStyles = () => { 19 | return { 20 | navbar: { 21 | backgroundColor: '#f8f8f8', 22 | border: '1px solid #e7e7e7', 23 | borderRadius: '0px', 24 | position: 'relative', 25 | top: '0px', 26 | minHeight: '50px', 27 | marginBottom: '20px', 28 | display: 'block', 29 | boxSizing: 'border-box' 30 | }, 31 | container: { 32 | paddingRight: '15px', 33 | paddingLeft: '15px', 34 | marginRight: 'auto', 35 | marginLeft: 'auto', 36 | boxSizing: 'border-box', 37 | 38 | '@media (min-width: 768px)': { 39 | width: '750px' 40 | }, 41 | '@media (min-width: 992px)': { 42 | width: '970px' 43 | }, 44 | '@media (min-width: 1200px)': { 45 | width: '1170px' 46 | } 47 | }, 48 | pseudoBefore: { 49 | display: 'table', 50 | content: ' ', 51 | boxSizing: 'border-box' 52 | }, 53 | pseudoAfter: { 54 | clear: 'both', 55 | display: 'table', 56 | content: ' ', 57 | boxSizing: 'border-box' 58 | } 59 | }; 60 | } 61 | 62 | renderChildren = () => { 63 | const {children} = this.props; 64 | return React.Children.map(children, (child) => { 65 | return React.cloneElement(child, 66 | { 67 | navbarToggle: this.navbarToggle, 68 | collapseIn: this.state.collapseIn 69 | } 70 | ); 71 | }); 72 | } 73 | 74 | navbarToggle = () => { 75 | this.setState({collapseIn: !this.state.collapseIn}); 76 | } 77 | 78 | render() { 79 | const defStyle = this.getStyles(); 80 | const {navStyle, contStyle} = this.props; 81 | return ( 82 | 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/scripts/components/NavbarDropdown.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class NavbarDropdown extends React.Component { 6 | displayName = 'Navigation bar dropdown button' 7 | 8 | static propTypes = { 9 | name: React.PropTypes.string, 10 | style: React.PropTypes.object, 11 | itemStyle: React.PropTypes.object, 12 | index: React.PropTypes.number, 13 | activeIndex: React.PropTypes.number, 14 | parentCallBack: React.PropTypes.func 15 | } 16 | 17 | state = { 18 | open: false 19 | } 20 | 21 | getStyles = () => { 22 | let styles = { 23 | dropdown: { 24 | position: 'relative', 25 | display: 'block', 26 | boxSizing: 'border-box', 27 | 28 | '@media (min-width: 768px)': { 29 | float: 'left' 30 | } 31 | }, 32 | caret: { 33 | display: 'inline-block', 34 | width: '0', 35 | height: '0', 36 | marginLeft: '2px', 37 | verticalAlign: 'middle', 38 | borderTop: '4px dashed', 39 | borderRight: '4px solid transparent', 40 | borderLeft: '4px solid transparent' 41 | }, 42 | link: { 43 | paddingTop: '10px', 44 | paddingBottom: '10px', 45 | paddingLeft: '15px', 46 | paddingRight: '15px', 47 | lineHeight: '20px', 48 | position: 'relative', 49 | display: 'block', 50 | boxSizing: 'border-box', 51 | textDecoration: 'none', 52 | backgroundColor: 'transparent', 53 | color: '#777', 54 | 55 | ':hover': { 56 | color: '#333' 57 | }, 58 | 59 | ':focus': { 60 | color: '#333' 61 | }, 62 | 63 | '@media (min-width: 768px)': { 64 | paddingTop: '15px', 65 | paddingBottom: '15px' 66 | } 67 | } 68 | }; 69 | if (this.props.index === this.props.activeIndex) { 70 | styles.link.backgroundColor = this.state.open ? '#e7e7e7' : 'transparent'; 71 | } 72 | return styles; 73 | } 74 | 75 | renderChildren = () => { 76 | const {children, index, activeIndex} = this.props; 77 | let active = false; 78 | // this particular dropdown is clicked 79 | if (index === activeIndex) { 80 | active = true; 81 | } 82 | const newChildren = React.Children.map(children, (child) => { 83 | return React.cloneElement(child, 84 | { 85 | open: this.state.open, 86 | active: active 87 | }); 88 | }); 89 | return newChildren; 90 | } 91 | 92 | handleDocumentClick = () => { 93 | if (this.state.open) { 94 | this.setState({open: false}); 95 | // when all the dropdowns are closed, activeIndex is set to -1 96 | this.props.parentCallBack(-1); 97 | } 98 | } 99 | 100 | handleDropdownClick = (e) => { 101 | const {index, parentCallBack} = this.props; 102 | e.preventDefault(); 103 | e.nativeEvent.stopImmediatePropagation(); 104 | parentCallBack(index); 105 | } 106 | 107 | componentDidMount() { 108 | document.addEventListener('click', this.handleDocumentClick); 109 | } 110 | 111 | componentWillUnmount() { 112 | document.removeEventListener('click', this.handleDocumentClick); 113 | } 114 | 115 | componentWillReceiveProps(nextProps) { 116 | const {index, activeIndex} = nextProps; 117 | if (index === activeIndex) { 118 | if (this.state.open) { 119 | this.setState({open: false}); 120 | // when all the dropdowns are closed, activeIndex is set to -1 121 | this.props.parentCallBack(-1); 122 | }else { 123 | this.setState({open: true}); 124 | } 125 | } else { 126 | this.setState({open: false}); 127 | } 128 | } 129 | 130 | render() { 131 | const {style, name, itemStyle} = this.props; 132 | const defStyle = this.getStyles(); 133 | return ( 134 |
  • 135 | 137 | {name}{' '} 138 | 139 | 140 | {this.renderChildren()} 141 |
  • 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/scripts/components/NavbarHeader.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class NavbarHeader extends React.Component { 6 | displayName = 'Navigation bar header' 7 | 8 | static propTypes = { 9 | href: React.PropTypes.string, 10 | name: React.PropTypes.string, 11 | headerStyle: React.PropTypes.object, 12 | brandStyle: React.PropTypes.object 13 | } 14 | 15 | getStyles = () => { 16 | return { 17 | header: { 18 | marginRight: '-15px', 19 | marginLeft: '-15px', 20 | boxSizing: 'border-box', 21 | 22 | '@media (min-width: 768px)': { 23 | float: 'left', 24 | marginRight: '0', 25 | marginLeft: '0' 26 | } 27 | }, 28 | brand: { 29 | float: 'left', 30 | height: '50px', 31 | padding: '15px', 32 | lineHeight: '20px', 33 | textDecoration: 'none', 34 | backgroundColor: 'transparent', 35 | boxSizing: 'border-box', 36 | 37 | fontSize: '18px', 38 | color: '#777', 39 | fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif', 40 | 41 | ':hover': { 42 | color: '#5e5e5e' 43 | }, 44 | 45 | ':focus': { 46 | color: '#5e5e5e' 47 | }, 48 | 49 | '@media (min-width: 768px)': { 50 | marginLeft: '-15px' 51 | } 52 | }, 53 | navbarToggle: { 54 | position: 'relative', 55 | float: 'right', 56 | padding: '9px 10px', 57 | marginTop: '8px', 58 | marginRight: '15px', 59 | marginBottom: '8px', 60 | backgroundColor: 'transparent', 61 | backgroundImage: 'none', 62 | borderWidth: '1px', 63 | borderStyle: 'solid', 64 | borderRadius: '4px', 65 | borderColor: '#ddd', 66 | cursor: 'pointer', 67 | boxSizing: 'border-box', 68 | 69 | ':hover': { 70 | backgroundColor: '#ddd' 71 | }, 72 | 73 | ':focus': { 74 | outline: '0', 75 | backgroundColor: '#ddd' 76 | }, 77 | '@media (min-width: 768px)': { 78 | display: 'none' 79 | } 80 | }, 81 | srOnly: { 82 | position: 'absolute', 83 | width: '1px', 84 | height: '1px', 85 | padding: '0', 86 | margin: '-1px', 87 | overflow: 'hidden', 88 | clip: 'rect(0, 0, 0, 0)', 89 | borderWidth: '0', 90 | borderStyle: 'none', 91 | boxSizing: 'border-box' 92 | }, 93 | iconBar: { 94 | display: 'block', 95 | width: '22px', 96 | height: '2px', 97 | borderRadius: '1px', 98 | backgroundColor: '#888', 99 | boxSizing: 'border-box' 100 | }, 101 | burger: { 102 | marginTop: '4px' 103 | }, 104 | pseudoBefore: { 105 | display: 'table', 106 | content: ' ', 107 | boxSizing: 'border-box' 108 | }, 109 | pseudoAfter: { 110 | clear: 'both', 111 | display: 'table', 112 | content: ' ', 113 | boxSizing: 'border-box' 114 | } 115 | }; 116 | } 117 | 118 | renderToggleButton = () => { 119 | const defStyle = this.getStyles(); 120 | return ( 121 | 127 | ); 128 | } 129 | 130 | render() { 131 | const defStyle = this.getStyles(); 132 | const {href, name, headerStyle, brandStyle} = this.props; 133 | return ( 134 |
    135 | 136 | {this.renderToggleButton()} 137 | 138 | {name} 139 | 140 | 141 |
    142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/scripts/components/NavbarItems.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | @Radium 5 | export default class NavbarItems extends React.Component { 6 | displayName = 'Navigation list of items' 7 | 8 | static propTypes = { 9 | style: React.PropTypes.object, 10 | children: React.PropTypes.node 11 | } 12 | 13 | getStyles = () => { 14 | let styles = { 15 | base: { 16 | margin: '7.5px -15px', 17 | listStyle: 'outside none none', 18 | paddingLeft: '0', 19 | boxSizing: 'border-box', 20 | 21 | fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif', 22 | fontSize: '14px', 23 | 24 | '@media (min-width: 768px)': { 25 | float: 'left', 26 | margin: '0' 27 | } 28 | }, 29 | collapse: { 30 | paddingRight: '15px', 31 | paddingLeft: '15px', 32 | overflowX: 'visible', 33 | borderTopWidth: '1px', 34 | borderTopStyle: 'solid', 35 | borderColor: '#E7E7E7', 36 | boxShadow: '0px 1px 0px rgba(255, 255, 255, .1) inset', 37 | marginRight: '-15px', 38 | marginLeft: '-15px', 39 | maxHeight: '340px', 40 | boxSizing: 'border-box', 41 | display: 'none', 42 | 43 | '@media (min-width: 768px)': { 44 | marginRight: '0px', 45 | marginLeft: '0px', 46 | paddingRight: '0px', 47 | paddingLeft: '0px', 48 | height: 'auto', 49 | paddingBottom: '0px', 50 | display: 'block', 51 | overflow: 'visible', 52 | width: 'auto', 53 | borderTopWidth: '0px', 54 | borderTopStyle: 'none', 55 | boxShadow: 'none', 56 | overflowY: 'visible' 57 | } 58 | }, 59 | pseudoBefore: { 60 | display: 'table', 61 | content: ' ', 62 | boxSizing: 'border-box' 63 | }, 64 | pseudoAfter: { 65 | clear: 'both', 66 | display: 'table', 67 | content: ' ', 68 | boxSizing: 'border-box' 69 | } 70 | }; 71 | if (this.props.collapseIn) { 72 | styles.collapse.display = 'block'; 73 | styles.collapse.overflowY = 'auto'; 74 | } 75 | return styles; 76 | } 77 | 78 | onClickHandler = (activeIndex) => { 79 | this.setState({ 80 | activeIndex: activeIndex 81 | }); 82 | } 83 | 84 | renderChildren = () => { 85 | const {children} = this.props; 86 | const {activeIndex} = this.state; 87 | return React.Children.map(children, (child, index) => { 88 | return React.cloneElement(child, 89 | { 90 | index: index, 91 | activeIndex: activeIndex, 92 | parentCallBack: this.onClickHandler 93 | } 94 | ); 95 | }); 96 | } 97 | 98 | render() { 99 | const defStyle = this.getStyles(); 100 | const {style} = this.props; 101 | return ( 102 |
    103 | 104 | 109 | 110 |
    111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/scripts/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Navbar: require('./components/Navbar'), 3 | NavItem: require('./components/NavItem'), 4 | NavbarHeader: require('./components/NavbarHeader'), 5 | NavbarItems: require('./components/NavbarItems'), 6 | NavbarDropdown: require('./components/NavbarDropdown'), 7 | DropdownMenu: require('./components/DropdownMenu') 8 | }; 9 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | entry: path.resolve(__dirname, 'src/app.jsx'), 5 | output: { 6 | path: path.resolve(__dirname, 'build'), 7 | filename: 'bundle.js', 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /webpack.development.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | devtool: 'source-map', 5 | entry: [ 6 | 'webpack-dev-server/client?http://localhost:8080', 7 | 'webpack/hot/dev-server', 8 | path.join(__dirname, 'src/scripts/app.jsx') 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'build'), 12 | filename: 'bundle.js', 13 | publicPath: '/' 14 | }, 15 | resolve: { 16 | extensions: ['', '.js', '.jsx'] 17 | }, 18 | module: { 19 | loaders: [ 20 | { 21 | // test for both js and jsx 22 | test: /\.jsx?$/, 23 | 24 | // use babel loader with Stage 1 features 25 | loader: 'babel?stage=0', 26 | 27 | // operate only on our app directory 28 | include: path.join(__dirname, 'src') 29 | } 30 | ] 31 | } 32 | 33 | }; 34 | --------------------------------------------------------------------------------