├── .gitignore
├── README.md
├── dev
├── basic.coffee
└── materialize.config.styl
├── materialize.styl
├── package.json
└── src
└── side-nav.coffee
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.sublime-project
3 | *.sublime-workspace
4 | .vscode
5 | npm-debug.log
6 | static
7 | *.js
8 | shrinkwrap.yaml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ceri-side-nav
2 |
3 | a touch enabled, responsive side-nav.
4 |
5 | ### [Demo](https://ceri-comps.github.io/ceri-side-nav)
6 |
7 |
8 | # Install
9 |
10 | ```sh
11 | npm install --save-dev ceri-side-nav
12 | ```
13 |
14 | ## Usage
15 | - [general ceri component usage instructions](https://github.com/cerijs/ceri#i-want-to-use-a-component-built-with-ceri)
16 | - in your project
17 | ```coffee
18 | window.customElements.define("ceri-side-nav", require("ceri-side-nav"))
19 | ```
20 | ```html
21 |
22 | First Text
23 |
24 |
25 |
26 |
27 |
28 |
29 | ```
30 | For examples see [`dev/`](dev/).
31 |
32 |
33 |
34 | #### Props
35 | Name | type | default | description
36 | ---:| --- | ---| ---
37 | target | String | null | Will attach toggling on given element, resolved by `querySelector`.
38 | fixed-screen-size | Number | 992 | Used with `fixed`. Above this size, the menu will stay opened.
39 | fixed | Boolean | false | should always show on large screens
40 | open | Boolean | false | set to open / close
41 | right | Boolean | false | attach to the right side instead of the left
42 | opacity | Number | 0.5 | opacity of the overlay
43 | z-index | Number | 1000 | minimum zIndex of the overlay.
44 |
45 | To not close the nav on a click inside, call `e.preventDefault()` on click.
46 |
47 | #### Events
48 | Name | description
49 | ---:| ---
50 | fixed(isFixed:Boolean) | emitted when menu get fixed or unfixed on large screen.
51 | toggled(isOpened:Boolean) | emitted when menu gets opened or closed.
52 |
53 | #### Themes
54 | - [ceri-materialize](https://github.com/ceri-comps/ceri-materialize)
55 | ```html
56 |
57 |
58 | ```
59 |
60 | # Development
61 | Clone repository.
62 | ```sh
63 | npm install
64 | npm run dev
65 | ```
66 | Browse to `http://localhost:8080/`.
67 |
68 | ## Notable changes
69 | #### 0.2.0
70 | - use ceri-materialize@2
71 |
72 | ## License
73 | Copyright (c) 2016 Paul Pflugradt
74 | Licensed under the MIT license.
75 |
--------------------------------------------------------------------------------
/dev/basic.coffee:
--------------------------------------------------------------------------------
1 | require "./materialize.config.styl"
2 | window.customElements.define "ceri-side-nav", require "../src/side-nav.coffee"
3 | createView = require "ceri-dev-server/lib/createView"
4 | module.exports = createView
5 | mixins:[
6 | require "ce/#if"
7 | require "ce/watch"
8 | ]
9 | structure: template 1, """
10 |
11 | First Text
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
source
20 | """
21 | computed:
22 | text: ->
23 | if @fixed
24 | if @sideNav.isFixed
25 | "Side-nav is fixed for this window-size. Make the window smaller for it to collapse."
26 | else
27 | if @right
28 | s = "drag >>"
29 | else
30 | s = "<< drag"
31 | return s+"\r\nMake window larger for the nav to stay opened"
32 | else
33 | if @right
34 | "drag >>"
35 | else
36 | "<< drag"
37 | style: ->
38 | if @right
39 | "text-align:right"
40 | else
41 | null
42 | class: -> if @materialize then "materialize" else null
43 | btnCls: -> if @materialize then "btn" else null
44 | data: ->
45 | right: false
46 | fixed: false
47 | materialize: false
48 | fixedScreenSize: 992
49 | tests: sideNav: ->
50 | it "should work", =>
51 | should.exist @
--------------------------------------------------------------------------------
/dev/materialize.config.styl:
--------------------------------------------------------------------------------
1 | @require "~normalize.css"
2 | @require "../materialize"
3 | @require "~ceri-materialize/3_utils"
4 | @require "~ceri-materialize/3_typography"
5 | @require "~ceri-materialize/6_buttons"
6 |
7 | body {
8 | margin: 0;
9 | }
10 | ceri-side-nav:not(.materialize) {
11 | border:1px solid black;
12 | background-color: white;
13 | width:200px;
14 | padding: 20px;
15 | }
16 | .container {
17 | width: 100% !important
18 | }
--------------------------------------------------------------------------------
/materialize.styl:
--------------------------------------------------------------------------------
1 | @require "~ceri-materialize/2_variables"
2 | @require "~ceri-materialize/4_zLevels"
3 | ceri-side-nav.materialize
4 | width: 300px
5 | margin: 0
6 | padding-bottom: 60px
7 | background-color: $sidenav-bg-color
8 | overflow-y: auto
9 | backface-visibility: hidden
10 | list-style-type: none
11 | @extend .z-depth-1
12 | .collapsible
13 | margin: 0
14 | li
15 | float: none
16 | line-height: $sidenav-line-height
17 | &.active
18 | background-color: rgba(0, 0, 0, 0.05)
19 | li > a
20 | color: $sidenav-font-color
21 | display: block
22 | font-size: $sidenav-font-size
23 | font-weight: 500
24 | height: $sidenav-item-height
25 | line-height: $sidenav-line-height
26 | padding: 0 $sidenav-padding * 2
27 | &:hover
28 | background-color: rgba(0, 0, 0, 0.05)
29 | &.btn, &.btn-large, &.btn-flat, &.btn-floating
30 | margin: 10px 15px
31 | &.btn,
32 | &.btn-large,
33 | &.btn-floating
34 | color: $button-raised-color
35 | &.btn-flat
36 | color: $button-flat-color
37 | &.btn:hover,
38 | &.btn-large:hover
39 | background-color: lighten($button-raised-background, 5%)
40 | &.btn-floating:hover
41 | background-color: $button-raised-background
42 | & > i,
43 | & > [class^="mdi-"], li > a > [class*="mdi-"],
44 | & > i.material-icons
45 | float: left
46 | height: $sidenav-item-height
47 | line-height: $sidenav-line-height
48 | margin: 0 $sidenav-padding * 2 0 0
49 | width: ($sidenav-item-height / 2)
50 | color: rgba(0, 0, 0, 0.54)
51 | .divider
52 | margin: $sidenav-padding / 2 0 0 0
53 | .subheader
54 | &:hover
55 | background-color: transparent
56 | cursor: initial
57 | pointer-events: none
58 | color: rgba(0, 0, 0, 0.54)
59 | font-size: $sidenav-font-size
60 | font-weight: 500
61 | line-height: $sidenav-line-height
62 | .collapsible-body
63 | padding: 0
64 | & > ul:not(.collapsible) > li.active
65 | background-color: $primary-color
66 | a
67 | color: $sidenav-bg-color
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceri-side-nav",
3 | "description": "a touch enabled, responsive side-nav",
4 | "version": "0.2.0",
5 | "homepage": "https://github.com/ceri-comps",
6 | "author": {
7 | "name": "Paul Pflugradt",
8 | "email": "paul.pflugradt@gmail.com"
9 | },
10 | "license": "MIT",
11 | "main": "side-nav.js",
12 | "repository": {
13 | "type": "git",
14 | "url": "git://github.com/ceri-comps/ceri-side-nav"
15 | },
16 | "engines": {
17 | "node": "*"
18 | },
19 | "files": [
20 | "*.js",
21 | "*.styl"
22 | ],
23 | "dependencies": {
24 | "ceri": "^1.0.26"
25 | },
26 | "devDependencies": {
27 | "ceri-compiler": "^1.1.4",
28 | "ceri-dev-server": "^1.0.12",
29 | "ceri-materialize": "^2.0.0",
30 | "coffee-loader": "^0.7.3",
31 | "coffee-script": "^1.12.7",
32 | "css-loader": "^0.28.7",
33 | "gh-pages": "^1.0.0",
34 | "normalize.css": "^7.0.0",
35 | "script-runner": "^0.1.7",
36 | "stylus": "^0.54.5",
37 | "stylus-loader": "^3.0.1"
38 | },
39 | "keywords": [
40 | "side-nav",
41 | "ceri"
42 | ],
43 | "readmeFilename": "README.md",
44 | "scripts": {
45 | "build:coffee": "coffee -c -o . src/side-nav.coffee",
46 | "build:bundle": "ceri-compiler -b side-nav.js",
47 | "build": "run-npm build:*",
48 | "dev": "ceri-dev-server",
49 | "watch": "ceri-dev-server --test --watch",
50 | "test": "ceri-dev-server --test",
51 | "preversion": "npm test",
52 | "version": "npm run build && git add .",
53 | "postversion": "git push && git push --tags && npm publish",
54 | "ghpages": "ceri-dev-server --static static/ && gh-pages -d static"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/side-nav.coffee:
--------------------------------------------------------------------------------
1 | ceri = require "ceri/lib/wrapper"
2 | module.exports = ceri
3 |
4 | mixins: [
5 | require "ceri/lib/props"
6 | require "ceri/lib/style"
7 | require "ceri/lib/animate"
8 | require "ceri/lib/directives"
9 | require "ceri/lib/open"
10 | require "ceri/lib/overlay"
11 | require "ceri/lib/#if"
12 | require "ceri/lib/draghandle"
13 | ]
14 |
15 | props:
16 | opacity:
17 | type: Number
18 | default: 0.5
19 | right:
20 | type: Boolean
21 | cbs: ["setParentMargin",((val) ->
22 | if val
23 | @style.right = 0
24 | @style.left = null
25 | else
26 | @style.right = null
27 | @style.left = null
28 | )]
29 | target:
30 | type: String
31 | fixed:
32 | type: Boolean
33 | cbs: "processFixed"
34 | delay: true
35 | fixedScreenSize:
36 | type: Number
37 | default: 992
38 | cbs: "processFixed"
39 | zIndex:
40 | type:Number
41 | default: 1000
42 | cbs: (val,old) ->
43 | s = @style
44 | return if s.zIndex and s.zIndex != old
45 | s.zIndex = val
46 |
47 | data: -> isFixed: null, keepOpen: true, dhZIndex: null
48 |
49 | overlay:
50 | zIndex: "zIndex"
51 | active: "dismissable"
52 | animate: "toggleAnimate"
53 | delay: true
54 | onClose: -> @style.zIndex = @zIndex; @dhZIndex = @zIndex-1; @hide.call(@)
55 | onOpen: (zIndex) -> @style.zIndex = zIndex+2; @dhZIndex = zIndex+1
56 |
57 | draghandle:
58 | __parentElement:
59 | active: -> !@isFixed
60 | initStyle:
61 | position: "absolute"
62 | top: 0
63 | bottom: 0
64 | style: ->
65 | zIndex: @dhZIndex
66 | width: if @open then null else "20px"
67 | left: if !@right or @open then 0 else null
68 | right: if @right or @open then 0 else null
69 | onClick: -> @hide() if @open
70 | onFirstMove: (o) ->
71 | unless @open
72 | @style.transform = "translateX(#{@fac*100}%)"
73 | @_attach()
74 | o.wasOpened = @open
75 | w = @offsetWidth * @fac
76 | if @right
77 | o.shouldShow = (move) -> move < 0
78 | o.shouldHide = (move) -> move > w
79 | else
80 | o.shouldShow = (move) -> move > 0
81 | o.shouldHide = (move) -> move < w
82 | onMove: (delta, o) ->
83 | move = 2 * delta.x + @offsetWidth * @fac * !o.wasOpened
84 | if o.shouldShow(move)
85 | @_setOpen()
86 | @style.transform = null
87 | o.move = 0
88 | else if o.shouldHide(move)
89 | @_setClose()
90 | @style.transform = "translateX(#{@fac*100}%)"
91 | o.move = -@offsetWidth
92 | else
93 | @style.transform = "translateX(#{move}px)"
94 | o.move = move
95 | onEnd: (delta, o) ->
96 | if @open and o.move < 0
97 | @animation = @enter _percent: 1 - o.move/@offsetWidth * @fac
98 | else if not @open and o.move > -@offsetWidth
99 | @animation = @leave _percent: o.move/@offsetWidth * @fac, done: @_detach
100 |
101 | events:
102 | click:
103 | this:
104 | active: "dismissable"
105 | notPrevented: true
106 | prevent: true
107 | cbs: ["toggle"]
108 | _target:
109 | active: ->@_target? and not @isFixed
110 | notPrevented: true
111 | prevent: true
112 | cbs: ["toggle"]
113 | destroy: true
114 | resize:
115 | window:
116 | el: window
117 | active: "fixed"
118 | throttled: true
119 | destroy: true
120 | cbs: "processFixed"
121 | directives:
122 | _target:
123 | type: "#"
124 | name: "if"
125 | activate: "_target"
126 | value: "isFixed"
127 | not: true
128 | initStyle:
129 | position: "fixed"
130 | height: "100%"
131 | computedStyle:
132 | this: ->
133 | willChange: if @isFixed then null else "transform"
134 |
135 | computed:
136 | _target: ->
137 | return null unless @target
138 | return document.querySelector(@target)
139 | fac: -> @right*2-1
140 | dismissable: ->
141 | @openingOrOpen and not @isFixed
142 |
143 | methods:
144 | makeFixed: (fixed) ->
145 | if fixed != @isFixed
146 | @isFixed = fixed
147 | @$emit name:"fixed", detail:fixed
148 | setParentMargin: ->
149 | if @parentElement
150 | if @isFixed
151 | width = @offsetWidth + "px"
152 | else
153 | width = null
154 | for el in @parentElement.children
155 | if el != @
156 | @$style.set el,
157 | marginLeft: if @right then null else width
158 | marginRight: if @right then width else null
159 | processFixed: ->
160 | if @fixed
161 | old = @isFixed
162 | @makeFixed(window.innerWidth > @fixedScreenSize)
163 | if old != @isFixed
164 | @wasOpened = @open
165 | if @isFixed
166 | @show(false)
167 | @setParentMargin()
168 | else
169 | @setParentMargin()
170 | @hide(false)
171 | else
172 | @makeFixed(false)
173 | @setParentMargin()
174 | if not @openingOrOpen or not @wasOpened
175 | @hide(false)
176 | enter: (o) ->
177 | o.style = translateX: [@fac*100,0,"%"]
178 | return @$animate(o)
179 |
180 | leave: (o) ->
181 | o.style = translateX: [0,@fac*100,"%"]
182 | return @$animate(o)
183 |
184 | beforeToggle: -> not @isFixed
185 |
186 | onHide: -> @wasOpened = false
187 |
--------------------------------------------------------------------------------