Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
51fe933c
Commit
51fe933c
authored
Aug 03, 2017
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ee-sidebar-fly-out-sub-nav' into 'master'
EE port of sidebar-fly-out-sub-nav See merge request !2576
parents
e09a5a90
d8698f6e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
339 additions
and
33 deletions
+339
-33
app/assets/javascripts/fly_out_nav.js
app/assets/javascripts/fly_out_nav.js
+51
-0
app/assets/javascripts/layout_nav.js
app/assets/javascripts/layout_nav.js
+3
-0
app/assets/stylesheets/new_sidebar.scss
app/assets/stylesheets/new_sidebar.scss
+84
-12
app/views/layouts/nav/_new_project_sidebar.html.haml
app/views/layouts/nav/_new_project_sidebar.html.haml
+21
-21
spec/javascripts/fly_out_nav_spec.js
spec/javascripts/fly_out_nav_spec.js
+180
-0
No files found.
app/assets/javascripts/fly_out_nav.js
0 → 100644
View file @
51fe933c
/* global bp */
import
'
./breakpoints
'
;
export
const
canShowSubItems
=
()
=>
bp
.
getBreakpointSize
()
===
'
md
'
||
bp
.
getBreakpointSize
()
===
'
lg
'
;
export
const
calculateTop
=
(
boundingRect
,
outerHeight
)
=>
{
const
windowHeight
=
window
.
innerHeight
;
const
bottomOverflow
=
windowHeight
-
(
boundingRect
.
top
+
outerHeight
);
return
bottomOverflow
<
0
?
(
boundingRect
.
top
-
outerHeight
)
+
boundingRect
.
height
:
boundingRect
.
top
;
};
export
const
showSubLevelItems
=
(
el
)
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
if
(
!
subItems
||
!
canShowSubItems
())
return
;
subItems
.
style
.
display
=
'
block
'
;
el
.
classList
.
add
(
'
is-over
'
);
const
boundingRect
=
el
.
getBoundingClientRect
();
const
top
=
calculateTop
(
boundingRect
,
subItems
.
offsetHeight
);
const
isAbove
=
top
<
boundingRect
.
top
;
subItems
.
style
.
transform
=
`translate3d(0,
${
Math
.
floor
(
top
)}
px, 0)`
;
if
(
isAbove
)
{
subItems
.
classList
.
add
(
'
is-above
'
);
}
};
export
const
hideSubLevelItems
=
(
el
)
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
if
(
!
subItems
||
!
canShowSubItems
())
return
;
el
.
classList
.
remove
(
'
is-over
'
);
subItems
.
style
.
display
=
'
none
'
;
subItems
.
classList
.
remove
(
'
is-above
'
);
};
export
default
()
=>
{
const
items
=
[...
document
.
querySelectorAll
(
'
.sidebar-top-level-items > li:not(.active)
'
)]
.
filter
(
el
=>
el
.
querySelector
(
'
.sidebar-sub-level-items
'
));
items
.
forEach
((
el
)
=>
{
el
.
addEventListener
(
'
mouseenter
'
,
e
=>
showSubLevelItems
(
e
.
currentTarget
));
el
.
addEventListener
(
'
mouseleave
'
,
e
=>
hideSubLevelItems
(
e
.
currentTarget
));
});
};
app/assets/javascripts/layout_nav.js
View file @
51fe933c
...
...
@@ -2,6 +2,7 @@
import
_
from
'
underscore
'
;
import
Cookies
from
'
js-cookie
'
;
import
NewNavSidebar
from
'
./new_sidebar
'
;
import
initFlyOutNav
from
'
./fly_out_nav
'
;
(
function
()
{
var
hideEndFade
;
...
...
@@ -58,6 +59,8 @@ import NewNavSidebar from './new_sidebar';
if
(
Cookies
.
get
(
'
new_nav
'
)
===
'
true
'
)
{
const
newNavSidebar
=
new
NewNavSidebar
();
newNavSidebar
.
bindEvents
();
initFlyOutNav
();
}
$
(
window
).
on
(
'
scroll
'
,
_
.
throttle
(
applyScrollNavClass
,
100
));
...
...
app/assets/stylesheets/new_sidebar.scss
View file @
51fe933c
...
...
@@ -220,6 +220,82 @@ $new-sidebar-width: 220px;
.sidebar-top-level-items
{
>
li
{
>
a
{
@media
(
min-width
:
$screen-sm-min
)
{
margin-right
:
2px
;
}
&
:hover
{
color
:
$gl-text-color
;
}
}
&
:not
(
.active
)
{
>
a
{
margin-left
:
1px
;
margin-right
:
3px
;
}
.sidebar-sub-level-items
{
@media
(
min-width
:
$screen-sm-min
)
{
position
:
fixed
;
top
:
0
;
left
:
220px
;
width
:
150px
;
margin-top
:
-1px
;
padding
:
8px
1px
;
background-color
:
$white-light
;
box-shadow
:
2px
1px
3px
$dropdown-shadow-color
;
border
:
1px
solid
$gray-darker
;
border-left
:
0
;
border-radius
:
0
3px
3px
0
;
&
:
:
before
{
content
:
""
;
position
:
absolute
;
top
:
-30px
;
bottom
:
-30px
;
left
:
0
;
right
:
-30px
;
z-index
:
-1
;
}
&
:
:
after
{
content
:
""
;
position
:
absolute
;
top
:
44px
;
left
:
-30px
;
right
:
35px
;
bottom
:
0
;
height
:
100%
;
max-height
:
150px
;
z-index
:
-1
;
transform
:
skew
(
33deg
);
}
&
.is-above
{
margin-top
:
1px
;
&
:
:
after
{
top
:
auto
;
bottom
:
44px
;
transform
:
skew
(
-30deg
);
}
}
a
{
padding
:
8px
16px
;
color
:
$gl-text-color
;
&
:hover
,
&
:focus
{
background-color
:
$gray-darker
;
}
}
}
}
}
.badge
{
background-color
:
$inactive-badge-background
;
color
:
$inactive-color
;
...
...
@@ -228,6 +304,10 @@ $new-sidebar-width: 220px;
&
.active
{
background
:
$active-background
;
>
a
{
margin-left
:
4px
;
}
.badge
{
color
:
$active-color
;
font-weight
:
600
;
...
...
@@ -238,18 +318,10 @@ $new-sidebar-width: 220px;
}
}
>
a
:hover
{
background-color
:
$hover-background
;
color
:
$hover-color
;
svg
{
fill
:
$hover-color
;
}
.badge
{
background-color
:
$indigo-500
;
color
:
$hover-color
;
}
&
:not
(
.active
)
:hover
>
a
,
>
a
:hover
,
&
.is-over
>
a
{
background-color
:
$white-light
;
}
}
}
...
...
app/views/layouts/nav/_new_project_sidebar.html.haml
View file @
51fe933c
...
...
@@ -91,34 +91,34 @@
%span
.badge.count.issue_counter
=
number_with_delimiter
(
IssuesFinder
.
new
(
current_user
,
project_id:
@project
.
id
).
execute
.
opened
.
count
)
%ul
.sidebar-sub-level-items
-
if
project_nav_tab?
(
:issues
)
&&
!
current_controller?
(
:merge_requests
)
=
nav_link
(
controller: :issues
)
do
=
link_to
project_issues_path
(
@project
),
title:
'Issues'
do
%span
List
=
nav_link
(
controller: :issues
)
do
=
link_to
project_issues_path
(
@project
),
title:
'Issues'
do
%span
List
=
nav_link
(
controller: :boards
)
do
=
link_to
project_boards_path
(
@project
),
title:
'Boards'
do
%span
Boards
=
nav_link
(
controller: :issues
)
do
=
link_to
project_issues_path
(
@project
),
title:
'Issues'
do
%span
List
-
if
project_nav_tab?
(
:merge_requests
)
&&
current_controller?
(
:merge_requests
)
=
nav_link
(
controller: :merge_requests
)
do
=
link_to
project_merge_requests_path
(
@project
),
title:
'Merge Requests'
do
%span
Merge Requests
=
nav_link
(
controller: :boards
)
do
=
link_to
project_boards_path
(
@project
),
title:
'Board'
do
%span
Board
-
if
project_nav_tab?
:labels
=
nav_link
(
controller: :labels
)
do
=
link_to
project_labels_path
(
@project
),
title:
'Labels'
do
%span
Labels
=
nav_link
(
controller: :labels
)
do
=
link_to
project_labels_path
(
@project
),
title:
'Labels'
do
%span
Labels
-
if
project_nav_tab?
:milestones
=
nav_link
(
controller: :milestones
)
do
=
link_to
project_milestones_path
(
@project
),
title:
'Milestones'
do
%span
Milestones
=
nav_link
(
controller: :milestones
)
do
=
link_to
project_milestones_path
(
@project
),
title:
'Milestones'
do
%span
Milestones
-
if
project_nav_tab?
:merge_requests
=
nav_link
(
controller:
@project
.
issues_enabled?
?
:merge_requests
:
[
:merge_requests
,
:labels
,
:milestones
])
do
...
...
@@ -195,7 +195,7 @@
%ul
.sidebar-sub-level-items
-
can_edit
=
can?
(
current_user
,
:admin_project
,
@project
)
-
if
can_edit
=
nav_link
(
controller: :projects
)
do
=
nav_link
(
path:
%w[projects#edit]
)
do
=
link_to
edit_project_path
(
@project
),
title:
'General'
do
%span
General
...
...
spec/javascripts/fly_out_nav_spec.js
0 → 100644
View file @
51fe933c
/* global bp */
import
{
calculateTop
,
hideSubLevelItems
,
showSubLevelItems
,
canShowSubItems
,
}
from
'
~/fly_out_nav
'
;
describe
(
'
Fly out sidebar navigation
'
,
()
=>
{
let
el
;
let
breakpointSize
=
'
lg
'
;
beforeEach
(()
=>
{
el
=
document
.
createElement
(
'
div
'
);
el
.
style
.
position
=
'
relative
'
;
document
.
body
.
appendChild
(
el
);
spyOn
(
bp
,
'
getBreakpointSize
'
).
and
.
callFake
(()
=>
breakpointSize
);
});
afterEach
(()
=>
{
el
.
remove
();
breakpointSize
=
'
lg
'
;
});
describe
(
'
calculateTop
'
,
()
=>
{
it
(
'
returns boundingRect top
'
,
()
=>
{
const
boundingRect
=
{
top
:
100
,
height
:
100
,
};
expect
(
calculateTop
(
boundingRect
,
100
),
).
toBe
(
100
);
});
it
(
'
returns boundingRect - bottomOverflow
'
,
()
=>
{
const
boundingRect
=
{
top
:
window
.
innerHeight
-
50
,
height
:
100
,
};
expect
(
calculateTop
(
boundingRect
,
100
),
).
toBe
(
window
.
innerHeight
-
50
);
});
});
describe
(
'
hideSubLevelItems
'
,
()
=>
{
beforeEach
(()
=>
{
el
.
innerHTML
=
'
<div class="sidebar-sub-level-items"></div>
'
;
});
it
(
'
hides subitems
'
,
()
=>
{
hideSubLevelItems
(
el
);
expect
(
el
.
querySelector
(
'
.sidebar-sub-level-items
'
).
style
.
display
,
).
toBe
(
'
none
'
);
});
it
(
'
does not hude subitems on mobile
'
,
()
=>
{
breakpointSize
=
'
sm
'
;
hideSubLevelItems
(
el
);
expect
(
el
.
querySelector
(
'
.sidebar-sub-level-items
'
).
style
.
display
,
).
not
.
toBe
(
'
none
'
);
});
it
(
'
removes is-over class
'
,
()
=>
{
spyOn
(
el
.
classList
,
'
remove
'
);
hideSubLevelItems
(
el
);
expect
(
el
.
classList
.
remove
,
).
toHaveBeenCalledWith
(
'
is-over
'
);
});
it
(
'
removes is-above class from sub-items
'
,
()
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
spyOn
(
subItems
.
classList
,
'
remove
'
);
hideSubLevelItems
(
el
);
expect
(
subItems
.
classList
.
remove
,
).
toHaveBeenCalledWith
(
'
is-above
'
);
});
it
(
'
does nothing if el has no sub-items
'
,
()
=>
{
el
.
innerHTML
=
''
;
spyOn
(
el
.
classList
,
'
remove
'
);
hideSubLevelItems
(
el
);
expect
(
el
.
classList
.
remove
,
).
not
.
toHaveBeenCalledWith
();
});
});
describe
(
'
showSubLevelItems
'
,
()
=>
{
beforeEach
(()
=>
{
el
.
innerHTML
=
'
<div class="sidebar-sub-level-items" style="position: absolute;"></div>
'
;
});
it
(
'
adds is-over class to el
'
,
()
=>
{
spyOn
(
el
.
classList
,
'
add
'
);
showSubLevelItems
(
el
);
expect
(
el
.
classList
.
add
,
).
toHaveBeenCalledWith
(
'
is-over
'
);
});
it
(
'
does not show sub-items on mobile
'
,
()
=>
{
breakpointSize
=
'
sm
'
;
showSubLevelItems
(
el
);
expect
(
el
.
querySelector
(
'
.sidebar-sub-level-items
'
).
style
.
display
,
).
not
.
toBe
(
'
block
'
);
});
it
(
'
does not shows sub-items
'
,
()
=>
{
showSubLevelItems
(
el
);
expect
(
el
.
querySelector
(
'
.sidebar-sub-level-items
'
).
style
.
display
,
).
toBe
(
'
block
'
);
});
it
(
'
sets transform of sub-items
'
,
()
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
showSubLevelItems
(
el
);
expect
(
subItems
.
style
.
transform
,
).
toBe
(
`translate3d(0px,
${
Math
.
floor
(
el
.
getBoundingClientRect
().
top
)}
px, 0px)`
);
});
it
(
'
sets is-above when element is above
'
,
()
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
subItems
.
style
.
height
=
`
${
window
.
innerHeight
+
el
.
offsetHeight
}
px`
;
el
.
style
.
top
=
`
${
window
.
innerHeight
-
el
.
offsetHeight
}
px`
;
spyOn
(
subItems
.
classList
,
'
add
'
);
showSubLevelItems
(
el
);
expect
(
subItems
.
classList
.
add
,
).
toHaveBeenCalledWith
(
'
is-above
'
);
});
});
describe
(
'
canShowSubItems
'
,
()
=>
{
it
(
'
returns true if on desktop size
'
,
()
=>
{
expect
(
canShowSubItems
(),
).
toBeTruthy
();
});
it
(
'
returns false if on mobile size
'
,
()
=>
{
breakpointSize
=
'
sm
'
;
expect
(
canShowSubItems
(),
).
toBeFalsy
();
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment