Feature #31353 » 0001-wip.patch
app/views/layouts/base.html.erb | ||
---|---|---|
60 | 60 | |
61 | 61 |
<div id="wrapper2"> |
62 | 62 |
<div id="wrapper3"> |
63 |
<div id="top-menu"> |
|
64 |
<div id="account"> |
|
65 |
<%= render_menu :account_menu -%> |
|
66 |
</div> |
|
67 |
<%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> |
|
63 |
<nav id="top-menu"> |
|
64 |
<nav class="general-menu"> |
|
68 | 65 |
<%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> |
69 |
</div> |
|
66 |
</nav> |
|
67 |
<nav class="profile-menu"> |
|
68 |
<ul class="nav-list"> |
|
69 |
<% if User.current.logged? || !Setting.login_required? %> |
|
70 |
<li class="nav-item"> |
|
71 |
<div id="quick-search"> |
|
72 |
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %> |
|
73 |
<%= hidden_field_tag 'scope', default_search_project_scope, :id => nil %> |
|
74 |
<%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %> |
|
75 |
<label for='q'> |
|
76 |
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project, :scope => default_search_project_scope}, :accesskey => accesskey(:search) %>: |
|
77 |
</label> |
|
78 |
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search), |
|
79 |
:data => { |
|
80 |
:auto_complete => true, |
|
81 |
:issues_url => auto_complete_issues_path(:q => '') |
|
82 |
} %> |
|
83 |
<% end %> |
|
84 |
</div> |
|
85 |
</li> |
|
86 |
<li class="nav-item"> |
|
87 |
<%= render_project_jump_box %> |
|
88 |
</li> |
|
89 |
<% end %> |
|
90 |
<% if User.current.logged? %> |
|
91 |
<li class="nav-item avatar-menu drdn"> |
|
92 |
<a href="#" class="drdn-trigger" onclick="toggleNewObjectDropdown(); return false;"> |
|
93 |
<%= Setting.gravatar_enabled? ? avatar(User.current, :size => '22') : User.current.login.to_s %> |
|
94 |
<span class="icon-only icon-expended" ></span> |
|
95 |
</a> |
|
96 |
<div class="drdn-content"> |
|
97 |
<div class="drdn-items"> |
|
98 |
<ul id="loggedas"><li> |
|
99 |
<span class="name"><%= User.current.name %></span> |
|
100 |
<%= link_to("@" + User.current.login, user_url(User.current)) %> |
|
101 |
</li></ul> |
|
102 |
<span class="divider"></span> |
|
103 |
<%= render_menu(:account_menu, nil, :class => 'account-menu') -%> |
|
104 |
</div> |
|
105 |
</div> |
|
106 |
</li> |
|
107 |
<% else %> |
|
108 |
<li class="nav-item"> |
|
109 |
<div id="account"> |
|
110 |
<%= render_menu :account_menu -%> |
|
111 |
</div> |
|
112 |
</li |
|
113 |
<% end %> |
|
114 |
</ul> |
|
115 |
</nav> |
|
116 |
</nav> |
|
70 | 117 | |
71 | 118 |
<div id="header"> |
72 | 119 | |
73 | 120 |
<a href="#" class="mobile-toggle-button js-flyout-menu-toggle-button"></a> |
74 | 121 | |
75 |
<% if User.current.logged? || !Setting.login_required? %> |
|
76 |
<div id="quick-search"> |
|
77 |
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %> |
|
78 |
<%= hidden_field_tag 'scope', default_search_project_scope, :id => nil %> |
|
79 |
<%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %> |
|
80 |
<label for='q'> |
|
81 |
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project, :scope => default_search_project_scope}, :accesskey => accesskey(:search) %>: |
|
82 |
</label> |
|
83 |
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search), |
|
84 |
:data => { |
|
85 |
:auto_complete => true, |
|
86 |
:issues_url => auto_complete_issues_path(:q => '') |
|
87 |
} %> |
|
88 |
<% end %> |
|
89 |
<%= render_project_jump_box %> |
|
90 |
</div> |
|
91 |
<% end %> |
|
92 | ||
93 | 122 |
<h1><%= page_header_title %></h1> |
94 | 123 | |
95 | 124 |
<% if display_main_menu?(@project) %> |
96 |
<div id="main-menu" class="tabs">
|
|
125 |
<nav id="main-menu" class="tabs">
|
|
97 | 126 |
<%= render_main_menu(@project) %> |
98 | 127 |
<div class="tabs-buttons" style="display:none;"> |
99 | 128 |
<button class="tab-left" onclick="moveTabLeft(this); return false;"></button> |
100 | 129 |
<button class="tab-right" onclick="moveTabRight(this); return false;"></button> |
101 | 130 |
</div> |
102 |
</div>
|
|
131 |
</nav>
|
|
103 | 132 |
<% end %> |
104 | 133 |
</div> |
105 | 134 |
lib/redmine/menu_manager.rb | ||
---|---|---|
110 | 110 |
menu_name.present? && Redmine::MenuManager.items(menu_name).children.present? |
111 | 111 |
end |
112 | 112 | |
113 |
def render_menu(menu, project=nil) |
|
113 |
def render_menu(menu, project=nil, options={})
|
|
114 | 114 |
links = [] |
115 | 115 |
menu_items_for(menu, project) do |node| |
116 | 116 |
links << render_menu_node(node, project) |
117 | 117 |
end |
118 |
links.empty? ? nil : content_tag('ul', links.join.html_safe) |
|
118 |
default_options = {:class => 'nav-list'} |
|
119 |
options = default_options.merge(options) |
|
120 |
links.empty? ? nil : content_tag('ul', links.join.html_safe, options) |
|
119 | 121 |
end |
120 | 122 | |
121 | 123 |
def render_menu_node(node, project=nil) |
... | ... | |
124 | 126 |
else |
125 | 127 |
caption, url, selected = extract_node_details(node, project) |
126 | 128 |
return content_tag('li', |
127 |
render_single_menu_node(node, caption, url, selected)) |
|
129 |
render_single_menu_node(node, caption, url, selected), :class => 'nav-item')
|
|
128 | 130 |
end |
129 | 131 |
end |
130 | 132 | |
... | ... | |
132 | 134 |
caption, url, selected = extract_node_details(node, project) |
133 | 135 | |
134 | 136 |
html = [].tap do |html| |
135 |
html << '<li>' |
|
137 |
html << '<li class="nav-item">'
|
|
136 | 138 |
# Parent |
137 | 139 |
html << render_single_menu_node(node, caption, url, selected) |
138 | 140 |
public/javascripts/application.js | ||
---|---|---|
892 | 892 |
$('input[data-disables], input[data-enables], input[data-shows]').each(toggleDisabledOnChange); |
893 | 893 |
} |
894 | 894 | |
895 |
function toggleNewObjectDropdown() { |
|
896 |
var dropdown = $('#new-object + ul.menu-children');
|
|
895 |
function toggleNewObjectDropdown(element) {
|
|
896 |
var dropdown = $(element).next('.menu-children');
|
|
897 | 897 |
if(dropdown.hasClass('visible')){ |
898 | 898 |
dropdown.removeClass('visible'); |
899 | 899 |
}else{ |
public/stylesheets/application.css | ||
---|---|---|
15 | 15 |
#wrapper {background: white;overflow: hidden;} |
16 | 16 |
#wrapper3 { display: flex; flex-direction: column; } |
17 | 17 | |
18 |
#top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;} |
|
19 |
#top-menu ul {margin: 0; padding: 0;} |
|
20 |
#top-menu li { |
|
21 |
float:left; |
|
22 |
list-style-type:none; |
|
23 |
margin: 0px 0px 0px 0px; |
|
24 |
padding: 0px 0px 0px 0px; |
|
25 |
white-space:nowrap; |
|
18 |
#top-menu *, *::before, *::after { |
|
19 |
box-sizing: border-box; |
|
26 | 20 |
} |
27 |
#top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} |
|
28 |
#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } |
|
29 | ||
30 |
#account {float:right;} |
|
31 | ||
32 |
#header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;} |
|
21 |
#top-menu {background: #3E5B76; padding: 2px 6px 0px 6px; display: flex;} |
|
22 |
#top-menu > nav { |
|
23 |
line-height: 24px; |
|
24 |
padding: 6px 0 6px 0; |
|
25 |
} |
|
26 |
#top-menu .general-menu { |
|
27 |
align-items: stretch; |
|
28 |
flex: 1 1 auto; |
|
29 |
} |
|
30 |
#top-menu .profile-menu { |
|
31 |
flex: 0 0 auto; |
|
32 |
border-top: 0; |
|
33 |
} |
|
34 |
#top-menu ul.nav-list > li.nav-item { |
|
35 |
margin-right: 8px; |
|
36 |
} |
|
37 |
#top-menu ul.nav-list > li.nav-item:last-child { |
|
38 |
margin-right: 0; |
|
39 |
} |
|
40 |
#top-menu ul.nav-list li.nav-item > a { |
|
41 |
font-size: 0.9em; |
|
42 |
color: #fff; |
|
43 |
} |
|
44 |
#top-menu .profile-menu li.avatar-menu .drdn-content { |
|
45 |
padding-top: 5px; |
|
46 |
padding-bottom: 5px; |
|
47 |
} |
|
48 |
#top-menu .profile-menu li.avatar-menu li { |
|
49 |
flex-direction: column; |
|
50 |
} |
|
51 |
#top-menu .profile-menu li.avatar-menu li a { |
|
52 |
width: 100%; |
|
53 |
display: block; |
|
54 |
padding: 4px; |
|
55 |
} |
|
56 |
#top-menu .profile-menu li.avatar-menu:hover > a { |
|
57 |
text-decoration: none; |
|
58 |
} |
|
59 |
#top-menu .profile-menu li.avatar-menu img.gravatar { |
|
60 |
border: 1px solid #dfdfdf; |
|
61 |
margin-right: 4px; |
|
62 |
} |
|
63 |
#top-menu .profile-menu li.avatar-menu:hover img.gravatar { |
|
64 |
border: 1px solid #fff; |
|
65 |
} |
|
66 |
#top-menu .profile-menu li.avatar-menu ul { |
|
67 |
padding: 0; |
|
68 |
min-width: 200px; |
|
69 |
} |
|
70 |
#loggedas span.name { |
|
71 |
font-weight: 600; |
|
72 |
padding: 4px; |
|
73 |
} |
|
74 |
#loggedas span.login { |
|
75 |
display: block; |
|
76 |
} |
|
77 |
#header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 0 6px;} |
|
33 | 78 |
#header a {color:#f8f8f8;} |
34 | 79 |
#header h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;} |
35 | 80 |
#header h1 .breadcrumbs { display:block; font-size: .5em; font-weight: normal; } |
36 | 81 | |
37 |
#quick-search {float:right;}
|
|
38 |
#quick-search #q {width:130px; height:24px; box-sizing:border-box; vertical-align:middle; border:1px solid #ccc; border-radius:3px;}
|
|
82 |
#quick-search label, #quick-search label a {color: #fff;}
|
|
83 |
#quick-search #q {width:130px; height:24px;} |
|
39 | 84 | |
40 |
#main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px; width: 100%;} |
|
41 |
#main-menu ul {margin: 0; padding: 0; width: 100%; white-space: nowrap;} |
|
42 |
#main-menu li { |
|
43 |
float:none; |
|
44 |
list-style-type:none; |
|
45 |
margin: 0px 2px 0px 0px; |
|
46 |
padding: 0px 0px 0px 0px; |
|
47 |
white-space:nowrap; |
|
48 |
display:inline-block; |
|
49 |
} |
|
50 |
#main-menu li a { |
|
51 |
display: block; |
|
85 |
#main-menu {margin-right: -500px; width: 100%;} |
|
86 |
#main-menu li.nav-item a { |
|
52 | 87 |
color: #fff; |
53 | 88 |
text-decoration: none; |
54 | 89 |
font-weight: bold; |
55 |
margin: 0;
|
|
90 |
display: block;
|
|
56 | 91 |
padding: 4px 10px 4px 10px; |
57 | 92 |
border-top-left-radius: 3px; |
58 | 93 |
border-top-right-radius: 3px; |
... | ... | |
149 | 184 | |
150 | 185 |
a#toggle-completed-versions {color:#999;} |
151 | 186 | |
187 |
/***** Navigation *****/ |
|
188 |
nav ul.nav-list { |
|
189 |
margin: 0; |
|
190 |
padding: 0; |
|
191 |
width: 100%; |
|
192 |
white-space: nowrap; |
|
193 |
display: flex; |
|
194 |
flex-direction: row; |
|
195 |
} |
|
196 |
nav ul.nav-list li.nav-item { |
|
197 |
list-style-type: none; |
|
198 |
margin: 0; |
|
199 |
padding: 0; |
|
200 |
white-space: nowrap; |
|
201 |
} |
|
202 |
nav ul.nav-list li.nav-item > a { |
|
203 |
padding: 4px; |
|
204 |
} |
|
152 | 205 |
/***** Dropdown *****/ |
153 | 206 |
.drdn {position:relative;} |
154 | 207 |
.drdn-trigger { |
... | ... | |
165 | 218 |
display:none; |
166 | 219 |
position:absolute; |
167 | 220 |
right:0px; |
168 |
top:25px;
|
|
221 |
top:28px;
|
|
169 | 222 |
min-width:100px; |
170 | 223 |
background-color:#fff; |
171 | 224 |
border:1px solid #ccc; |
... | ... | |
173 | 226 |
color:#555; |
174 | 227 |
z-index:99; |
175 | 228 |
} |
229 |
.drdn-content .divider { |
|
230 |
height: 1px; |
|
231 |
background-color: #ccc; |
|
232 |
padding: 0; |
|
233 |
margin: 0; |
|
234 |
border: 0; |
|
235 |
} |
|
176 | 236 |
.drdn.expanded .drdn-content {display:block;} |
177 | 237 | |
178 | 238 |
.drdn-content .quick-search {margin:8px;} |
... | ... | |
207 | 267 |
border: none; |
208 | 268 |
} |
209 | 269 |
.drdn-items>span {color:#999;} |
210 | ||
211 | 270 |
.contextual .drdn-content {top:18px;} |
212 | 271 |
.contextual .drdn-items {padding:2px;} |
213 | 272 |
.contextual .drdn-items>a:hover {color:#2A5685; border:1px solid #628db6; background-color:#eef5fd; border-radius:3px;} |
... | ... | |
216 | 275 |
#project-jump .drdn-trigger { |
217 | 276 |
width:100%; |
218 | 277 |
height:24px; |
278 |
line-height: 16px; |
|
219 | 279 |
display:inline-block; |
220 | 280 |
padding:3px 18px 3px 6px; |
221 | 281 |
border-radius:3px; |
222 | 282 |
border:1px solid #ccc; |
223 |
margin:0 !important; |
|
224 | 283 |
vertical-align:middle; |
225 | 284 |
color:#555; |
226 | 285 |
background:#fff url(../images/arrow_down.png) no-repeat 97% 50%; |
227 | 286 |
} |
228 | 287 |
#project-jump .drdn.expanded .drdn-trigger {background-image:url(../images/arrow_up.png);} |
229 | 288 |
#project-jump .drdn-content {width:280px;} |
230 |
#project-jump .drdn-items>* {color:#555 !important;} |
|
231 |
#project-jump .drdn-items>a:hover {background-color:#759FCF; color:#fff !important;}
|
|
289 |
#project-jump .drdn-items>*, .avatar-menu .drdn-items * {color:#555 !important;}
|
|
290 |
#project-jump .drdn-items>a:hover, .avatar-menu .drdn-items a:hover {background-color:#759FCF; color:#fff !important; text-decoration: none;}
|
|
232 | 291 | |
233 | 292 |
/***** Tables *****/ |
234 | 293 |
table.list, .table-list { border: 1px solid #e4e4e4; width: 100%; margin-bottom: 4px; border-radius: 3px; border-spacing: 0; overflow: hidden;} |