diff --git a/Gemfile b/Gemfile index 60fc118c..8da55b10 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem "pygments.rb", "0.2.3" gem "thin" gem "git" gem "acts_as_list" +gem 'rdiscount' group :assets do gem 'sass-rails', " ~> 3.1.0" @@ -26,7 +27,8 @@ group :assets do gem 'uglifier' end -group :development do +group :development do + gem 'letter_opener' gem 'rails-footnotes', '>= 3.7.5.rc4' gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git' end diff --git a/Gemfile.lock b/Gemfile.lock index 83ccebd8..f66e832e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -119,6 +119,8 @@ GEM rails (>= 3.0.0) launchy (2.0.5) addressable (~> 2.2.6) + letter_opener (0.0.2) + launchy libv8 (3.3.10.2) linecache19 (0.5.12) ruby_core_source (>= 0.1.4) @@ -161,6 +163,7 @@ GEM rdoc (~> 3.4) thor (~> 0.14.6) rake (0.9.2) + rdiscount (1.6.8) rdoc (3.9.4) rspec (2.6.0) rspec-core (~> 2.6.0) @@ -261,9 +264,11 @@ DEPENDENCIES jquery-rails kaminari launchy + letter_opener pygments.rb (= 0.2.3) rails (= 3.1.0) rails-footnotes (>= 3.7.5.rc4) + rdiscount rspec-rails ruby-debug19 sass-rails (~> 3.1.0) diff --git a/app/assets/images/.directory b/app/assets/images/.directory index 93a51f7c..d6f1a908 100644 --- a/app/assets/images/.directory +++ b/app/assets/images/.directory @@ -1,4 +1,4 @@ [Dolphin] ShowPreview=true -Timestamp=2011,9,14,20,34,18 +Timestamp=2011,10,28,13,16,25 Version=2 diff --git a/app/assets/images/bg-header.png b/app/assets/images/bg-header.png new file mode 100644 index 00000000..8759ca58 Binary files /dev/null and b/app/assets/images/bg-header.png differ diff --git a/app/assets/images/icon-search.png b/app/assets/images/icon-search.png new file mode 100644 index 00000000..7632915c Binary files /dev/null and b/app/assets/images/icon-search.png differ diff --git a/app/assets/images/images.png b/app/assets/images/images.png new file mode 100644 index 00000000..973d3bdd Binary files /dev/null and b/app/assets/images/images.png differ diff --git a/app/assets/images/login-logo.png b/app/assets/images/login-logo.png new file mode 100644 index 00000000..8c064b12 Binary files /dev/null and b/app/assets/images/login-logo.png differ diff --git a/app/assets/javascripts/modernizr-2.0.6.min.js b/app/assets/javascripts/modernizr-2.0.6.min.js new file mode 100755 index 00000000..4f00b719 --- /dev/null +++ b/app/assets/javascripts/modernizr-2.0.6.min.js @@ -0,0 +1,4 @@ +/* Modernizr 2.0.6 | MIT & BSD + * Contains: All core tests, html5shiv, yepnope, respond.js. Get your own custom build at www.modernizr.com/download/ + */ +;window.Modernizr=function(a,b,c){function I(){e.input=function(a){for(var b=0,c=a.length;b",a,""].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},w=function(b){if(a.matchMedia)return matchMedia(b).matches;var c;v("@media "+b+" { #"+i+" { position: absolute; } }",function(b){c=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position=="absolute"});return c},x=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=D(e[d],"function"),D(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),y,z={}.hasOwnProperty,A;!D(z,c)&&!D(z.call,c)?A=function(a,b){return z.call(a,b)}:A=function(a,b){return b in a&&D(a.constructor.prototype[b],c)};var H=function(c,d){var f=c.join(""),g=d.length;v(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||j.touch.offsetTop===9,e.csstransforms3d=j.csstransforms3d.offsetLeft===9,e.generatedcontent=j.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("touch-enabled),("),i,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);r.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!D(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){return e.touch},r.geolocation=function(){return!!navigator.geolocation},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){var b=!!a.openDatabase;return b},r.indexedDB=function(){for(var b=-1,c=p.length;++b7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){for(var b=-1,c=p.length;++b";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var J in r)A(r,J)&&(y=J.toLowerCase(),e[y]=r[J](),u.push((e[y]?"":"no-")+y));e.input||I(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)A(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return;b=typeof b=="boolean"?b:!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},B(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b=u.minw)&&(!u.maxw||u.maxw&&l<=u.maxw))m[u.media]||(m[u.media]=[]),m[u.media].push(f[u.rules])}for(var t in g)g[t]&&g[t].parentNode===j&&j.removeChild(g[t]);for(var t in m){var v=c.createElement("style"),w=m[t].join("\n");v.type="text/css",v.media=t,v.styleSheet?v.styleSheet.cssText=w:v.appendChild(c.createTextNode(w)),n.appendChild(v),g.push(v)}j.insertBefore(n,o.nextSibling)}},s=function(a,b){var c=t();if(!!c){c.open("GET",a,!0),c.onreadystatechange=function(){c.readyState==4&&(c.status==200||c.status==304)&&b(c.responseText)};if(c.readyState==4)return;c.send()}},t=function(){var a=!1,b=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new XMLHttpRequest}],c=b.length;while(c--){try{a=b[c]()}catch(d){continue}break}return function(){return a}}();m(),respond.update=m,a.addEventListener?a.addEventListener("resize",u,!1):a.attachEvent&&a.attachEvent("onresize",u)}}(this,Modernizr.mq("only all")),function(a,b,c){function k(a){return!a||a=="loaded"||a=="complete"}function j(){var a=1,b=-1;while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;a&&g()}function i(a){var c=b.createElement("script"),d;c.src=a.s,c.onreadystatechange=c.onload=function(){!d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)},m(function(){d||(d=1,j())},H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)}function h(a){var c=b.createElement("link"),d;c.href=a.s,c.rel="stylesheet",c.type="text/css";if(!a.e&&(w||r)){var e=function(a){m(function(){if(!d)try{a.sheet.cssRules.length?(d=1,j()):e(a)}catch(b){b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){j()},0)):e(a)}},0)};e(c)}else c.onload=function(){d||(d=1,m(function(){j()},0))},a.e&&c.onload();m(function(){d||(d=1,j())},H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)}function g(){var a=p.shift();q=1,a?a.t?m(function(){a.t=="c"?h(a):i(a)},0):(a(),j()):q=0}function f(a,c,d,e,f,h){function i(){!o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){u.removeChild(l)},0))}var l=b.createElement(a),o=0,r={t:d,s:c,e:h};l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){r.e=r.r=1,g()}),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){o||(u.removeChild(l),r.r=r.e=o=1,j())},H.errorTimeout)}function e(a,b,c){var d=b=="c"?z:y;q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());return this}function d(){var a=H;a.loader={load:e,i:0};return a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){return o.call(a)=="[object Array]"},B=function(a){return Object(a)===a},C=function(a){return typeof a=="string"},D=function(a){return o.call(a)=="[object Function]"},E=[],F={},G,H;H=function(a){function f(a){var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={url:d,origUrl:d,prefixes:b},g,h;for(h=0;h .account-links, .account-box:hover > .arrow-up{display: block;} +header .account-links{background: white; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); } +header .account-links a{color: #666; padding: 6px 10px; display: block; text-shadow: none; border-bottom: 1px solid #eee} +header .account-links a:hover{background-color: #f1f1f1; text-shadow: none; color: #333} + +header .account-links a:first-child{ + -webkit-border-top-left-radius: 5px; + -webkit-border-top-right-radius: 5px; + -moz-border-radius-topleft: 5px; + -moz-border-radius-topright: 5px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +header .account-links a:last-child{ + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; + -moz-border-radius-bottomright: 5px; + -moz-border-radius-bottomleft: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + border-bottom: 0; +} + +header a.arrow-up{ + display: none; + width: 0; + height: 0; + float: right; + margin-right: 26px; + margin-bottom: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + + border-bottom: 5px solid white; +} +/* eo Account Box */ +input.search-input{float: left; text-shadow: none; width: 116px; background-image: url('icon-search.png') ; background-repeat: no-repeat; background-position: 10px; border-radius: 100px; border: 1px solid rgba(0,0,0,.7); box-shadow: 0 1px 0 rgba(255,255,255,.2), 0 2px 2px rgba(0,0,0,.4) inset ; background-color: #D2D5DA; background-color: rgba(255,255,255,.5); padding: 5px; padding-left: 26px; margin-top: 4px; margin-right: 10px } +input.search-input:focus{ background-color: white; width: 216px;} +input.search-input::-webkit-input-placeholder {color: #666} +/* eo Header */ + + +h2.icon{position: relative; padding-left: 40px; float: left; } +/*h2 a{font-weight: normal;}*/ +h2.icon span{background: #E3E5EA url('images.png'); height: 32px; width: 32px; left: 0; top: -5px; border-radius: 4px; display: inline-block; position: absolute} + + + +/* Dashboard Page */ +html, body { height: 100%; } + +body.dashboard-page h2.icon span{ background-position: 9px -69px; } +body.dashboard-page header{margin-bottom: 0} +body.dashboard-page .news-feed{padding-left: 1em; margin-right: 450px; margin-left: 1%} +body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; } +body.dashboard-page .news-feed h2{float: left;} +body.dashboard-page aside{ width: 420px; float: right; right: 0; height: 100%; bottom: 0; position: absolute; background-color: #f7f7f7; border-left: 1px solid #ccc } +body.dashboard-page aside h4{margin: 0; border-bottom: 1px solid #ccc; padding: 10px 10px; font-size: 11px; font-weight: bold; text-transform: uppercase;} +body.dashboard-page aside h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 4%; margin-top: -4px; display: block;} +body.dashboard-page aside .project-list {list-style: none; margin: 0; padding: 0;} +body.dashboard-page aside .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid #eee; padding: 14px 6% 14px 14px;} +body.dashboard-page aside .project-list li a:hover {background: #f1f1f1} +body.dashboard-page aside .project-list li a:hover span.arrow{background-color: #E3E5EA;} +body.dashboard-page aside .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px} +body.dashboard-page aside .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px} +body.dashboard-page aside .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999} +body.dashboard-page .news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;} +body.dashboard-page .news-feed .project-updates .data{ padding: 0} +body.dashboard-page .news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} +body.dashboard-page .news-feed .project-updates a.project-update:last-child{border-bottom: 0} +body.dashboard-page .news-feed .project-updates a.project-update img{float: left; margin-right: 10px;} +body.dashboard-page .news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;} +body.dashboard-page .news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px} +body.dashboard-page .news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;} +body.dashboard-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;} +/* eo Dashboard Page */ + + +.grey-button.right{margin-top: 20px} + +/* Project Page */ + +body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;} +body.project-page h2.icon .project-name i.arrow{float: right; + position: absolute; + right: 10px; + top: 13px; + display: block; + background: url('images.png') no-repeat -97px -29px; + width: 4px; + height: 5px; +} + + + +body.project-page h2.icon span{ background-position: -78px -68px; } +body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; } +body.project-page .page-title{margin-bottom: 0} +body.project-page .project-sidebar {width: 220px; left: 0; top: 0; height: 100%; bottom: 0; position: absolute; background-color: #f7f7f7; border-left: 1px solid #ccc; float: left; display: inline-block; background: #f7f7f7; padding: 20px 0 20px 2%; margin: 0; } +body.project-page .project-sidebar input.text.git-url{ font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 14px 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px;} +body.project-page .project-sidebar aside{width: 219px} +body.project-page .project-sidebar aside a{display: block; position: relative; background: white; padding: 15px 10px; border-bottom: 1px solid #eee} +body.project-page .project-sidebar aside a:first-child{ + -webkit-border-top-left-radius: 5px; + -moz-border-radius-topleft: 5px; + border-top-left-radius: 5px; +} +.project-page .project-sidebar aside a:last-child{ + -webkit-border-bottom-left-radius: 5px; + -moz-border-radius-bottomleft: 5px; + border-bottom-left-radius: 5px; +} +body.project-page .project-sidebar aside a:hover{background-color: #eee;} +body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px} +body.project-page .project-sidebar aside a.current{background-color: #79c3e0; color: white; text-shadow: none; border-color: transparent} +body.project-page .project-content{ padding: 20px; display: block; margin-left: 250px } +body.project-page .project-content h2{ margin-top: 6px} +body.project-page .project-content .button.right{margin-left: 20px} +body.project-page table .commit a{color: #{$blue_link}} +body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;} +body.project-page .fixed{position: fixed; } + +/* Commit Page */ +body.project-page.commits-page .commit-info{float: right;} +body.project-page.commits-page .commit-info data{ + padding: 4px 10px; + font-size: 11px; +} +body.project-page.commits-page .commit-info data.commit-button{ + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4)); + background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4); + background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4); + background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4); + box-shadow: 0 -1px 0 white inset; + display: block; + border: 1px solid #eee; + border-radius: 5px; + margin-bottom: 2px; + position: relative; + padding-right: 20px; +} + + +body.project-page.commits-page .commit-button i{ + background: url('images.png') no-repeat -138px -27px; + width: 6px; + height: 9px; + float: right; + position: absolute; + top: 6px; + right: 5px; +} +body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px} +body.project-page.commits-page .commits-date .data {padding: 0} +body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} +body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} +body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0} +body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;} +body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;} +body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px} +body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;} +body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;} + +/* eo Commit Page */ + +/* eo Project Page */ + + + + +/* Projects Page */ +body.projects-page h2.icon span{background-position: -31px -70px;} +body.projects-page .project-box.ui-box .data .repository {margin-bottom: 20px} +body.projects-page .project-box.ui-box .data .title span{ font-weight: bold;} +body.projects-page .project-box{width: 100%; margin-bottom: 3em} +body.projects-page .browse-code{margin-right: 10px} +/* eo Projects Page */ + + +/* ==|== non-semantic helper classes ======================================== */ +.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; } +.ir br { display: none; } +.hidden { display: none !important; visibility: hidden; } +.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } +.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } +.invisible { visibility: hidden; } +.clearfix:before, .clearfix:after { content: ""; display: table; } +.clearfix:after { clear: both; } +.clearfix { zoom: 1; } + + +/* ==|== media queries ====================================================== */ + +@media only screen and (min-width: 480px) { + + +} + +@media only screen and (min-width: 768px) { + +} + + + +/* ==|== print styles ======================================================= */ + +@media print { + * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + abbr[title]:after { content: " (" attr(title) ")"; } + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } + pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } + thead { display: table-header-group; } + tr, img { page-break-inside: avoid; } + img { max-width: 100% !important; } + @page { margin: 0.5cm; } + p, h2, h3 { orphans: 3; widows: 3; } + h2, h3 { page-break-after: avoid; } +} diff --git a/app/controllers/admin/mailer_controller.rb b/app/controllers/admin/mailer_controller.rb index d2fbbcd4..458ad277 100644 --- a/app/controllers/admin/mailer_controller.rb +++ b/app/controllers/admin/mailer_controller.rb @@ -1,4 +1,5 @@ class Admin::MailerController < ApplicationController + layout "admin" before_filter :authenticate_user! before_filter :authenticate_admin! diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index a7113639..21b25fc0 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -1,4 +1,5 @@ class Admin::ProjectsController < ApplicationController + layout "admin" before_filter :authenticate_user! before_filter :authenticate_admin! diff --git a/app/controllers/admin/team_members_controller.rb b/app/controllers/admin/team_members_controller.rb index 8ae32bc6..d04d32a6 100644 --- a/app/controllers/admin/team_members_controller.rb +++ b/app/controllers/admin/team_members_controller.rb @@ -1,4 +1,5 @@ class Admin::TeamMembersController < ApplicationController + layout "admin" before_filter :authenticate_user! before_filter :authenticate_admin! diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 65605765..1c008d90 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,4 +1,5 @@ class Admin::UsersController < ApplicationController + layout "admin" before_filter :authenticate_user! before_filter :authenticate_admin! diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 816c4c55..0bf38a57 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,8 +8,18 @@ class ApplicationController < ActionController::Base render :file => File.join(Rails.root, "public", "gitosis_error"), :layout => false end + layout :layout_by_resource + protected + def layout_by_resource + if devise_controller? + "devise" + else + "application" + end + end + def abilities @abilities ||= Six.new end diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 83071891..79b97ed7 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -2,6 +2,7 @@ require "base64" class CommitsController < ApplicationController before_filter :project + layout "project" # Authorize before_filter :add_project_abilities diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 2476b17e..1c50c66e 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,5 +1,6 @@ class DashboardController < ApplicationController def index @projects = current_user.projects.all + @active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse end end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index d0fad8ed..71c559a1 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -2,6 +2,7 @@ class IssuesController < ApplicationController before_filter :authenticate_user! before_filter :project before_filter :issue, :only => [:edit, :update, :destroy, :show] + layout "project" # Authorize before_filter :add_project_abilities @@ -41,7 +42,7 @@ class IssuesController < ApplicationController def create @issue = @project.issues.new(params[:issue]) @issue.author = current_user - if @issue.save + if @issue.save && @issue.assignee != current_user Notify.new_issue_email(@issue).deliver end diff --git a/app/controllers/keys_controller.rb b/app/controllers/keys_controller.rb index d3c93b5f..84f47675 100644 --- a/app/controllers/keys_controller.rb +++ b/app/controllers/keys_controller.rb @@ -1,4 +1,5 @@ class KeysController < ApplicationController + layout "profile" respond_to :js def index diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb index a0078f0e..2e58f3e1 100644 --- a/app/controllers/profile_controller.rb +++ b/app/controllers/profile_controller.rb @@ -1,4 +1,5 @@ class ProfileController < ApplicationController + layout "profile" def show @user = current_user end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 481e02fd..e046add3 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,5 +1,6 @@ class ProjectsController < ApplicationController before_filter :project, :except => [:index, :new, :create] + layout :determine_layout # Authorize before_filter :add_project_abilities @@ -152,4 +153,12 @@ class ProjectsController < ApplicationController def project @project ||= Project.find_by_code(params[:id]) end + + def determine_layout + if @project && !@project.new_record? + "project" + else + "application" + end + end end diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index d9a6ab2a..54ad6019 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -1,6 +1,7 @@ class SnippetsController < ApplicationController before_filter :authenticate_user! before_filter :project + layout "project" # Authorize before_filter :add_project_abilities diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 48e7e9b9..8a4e32e5 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -1,5 +1,6 @@ class TeamMembersController < ApplicationController before_filter :project + layout "project" # Authorize before_filter :add_project_abilities diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 599d1e5c..ef92953d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -28,6 +28,12 @@ module ApplicationHelper else "Never" end + rescue + "Never" + end + + def markdown(text) + RDiscount.new(text, :autolink, :no_pseudo_protocols, :safelink, :smart, :filter_html).to_html.html_safe end def search_autocomplete_source diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index a94ddfc2..0560af5d 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -1,2 +1,30 @@ module DashboardHelper + def dashboard_feed_path(project, object) + case object.class.name.to_s + when "Issue" then project_issues_path(project, project.issues.find(object.id)) + when "Grit::Commit" then project_commit_path(project, project.repo.commits(object.id).first) + when "Note" + then + note = object + case note.noteable_type + when "Issue" then project_issue_path(project, note.noteable_id) + when "Snippet" then project_snippet_path(project, note.noteable_id) + when "Commit" then project_commit_path(project, :id => note.noteable_id) + else wall_project_path(project) + end + else "#" + end + rescue + "#" + end + + def dashboard_feed_title(object) + title = case object.class.name.to_s + when "Note" then markdown(object.note) + when "Issue" then object.title + when "Grit::Commit" then object.safe_message + else "" + end + "[#{object.class.name}] #{truncate(sanitize(title, :tags => []), :length => 60)} " + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 9fb7ef30..f649cacb 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -10,6 +10,11 @@ class Issue < ActiveRecord::Base validates_presence_of :assignee_id validates_presence_of :author_id + delegate :name, + :email, + :to => :author, + :prefix => true + validates :title, :presence => true, :length => { :within => 0..255 } diff --git a/app/models/note.rb b/app/models/note.rb index 645bc7ce..3c59efef 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -7,6 +7,11 @@ class Note < ActiveRecord::Base belongs_to :author, :class_name => "User" + delegate :name, + :email, + :to => :author, + :prefix => true + attr_protected :author, :author_id validates_presence_of :project diff --git a/app/models/project.rb b/app/models/project.rb index ef7f4e46..befa1c6b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -119,6 +119,26 @@ class Project < ActiveRecord::Base repo rescue false end + def last_activity + updates(1).first + rescue + nil + end + + def last_activity_date + last_activity.try(:created_at) + end + + def updates(n = 3) + [ + fresh_commits(n), + issues.last(n), + notes.fresh.limit(n) + ].compact.flatten.sort do |x, y| + y.created_at <=> x.created_at + end[0...n] + end + def commit(commit_id = nil) if commit_id repo.commits(commit_id).first @@ -131,16 +151,16 @@ class Project < ActiveRecord::Base @heads ||= repo.heads end - def fresh_commits + def fresh_commits(n = 10) commits = heads.map do |h| - repo.commits(h.name, 10) + repo.commits(h.name, n) end.flatten.uniq { |c| c.id } commits.sort! do |x, y| y.committed_date <=> x.committed_date end - commits[0..10] + commits[0...n] end def commits_since(date) diff --git a/app/views/admin/_top_menu.html.haml b/app/views/admin/_top_menu.html.haml deleted file mode 100644 index d63caa7e..00000000 --- a/app/views/admin/_top_menu.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -%div.top_project_menu - %span= link_to "Users", admin_users_path, :style => "width:50px;", :class => controller.controller_name == "users" ? "current" : nil - %span= link_to "Projects", admin_projects_path, :style => "width:50px;", :class => controller.controller_name == "projects" ? "current" : nil - %span= link_to "Teams", admin_team_members_path, :style => "width:50px;", :class => controller.controller_name == "team_members" ? "current" : nil - %span= link_to "Emails", admin_emails_path, :style => "width:50px;", :class => controller.controller_name == "mailer" ? "current" : nil - diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 327561de..c529b82e 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,5 +1,5 @@ %table - %tr + %thead %th Name %th Code %th Path diff --git a/app/views/admin/team_members/index.html.haml b/app/views/admin/team_members/index.html.haml index 5aa4b597..33f58fa5 100644 --- a/app/views/admin/team_members/index.html.haml +++ b/app/views/admin/team_members/index.html.haml @@ -1,7 +1,7 @@ - @admin_team_members.group_by(&:project).sort.each do |project, members| %h3= link_to project.name, [:admin, project] %table - %tr + %thead %th Name %th Email %th Read diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 3b5aa399..cbec1060 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,5 +1,5 @@ %table - %tr + %thead %th Admin %th Name %th Email diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index 99823065..9761c65f 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -1,22 +1,25 @@ - @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| - .day-commits-table - .day-header + %div{ :class => "commits-date ui-box ui-box-small ui-box-big" } + .day-commits-table %h3= day.stamp("28 Aug, 2010") - %ul - - commits.each do |commit| - %li{ :class => "commit", :url => project_commit_path(@project, :id => commit.id) } - - if commit.author.email - = image_tag gravatar_icon(commit.author.email), :class => "left", :width => 40, :style => "padding-right:5px;" - - else - = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" - %p - %strong - = truncate(commit.safe_message, :length => 60) - = link_to "Browse Code", tree_project_path(@project, :commit_id => commit.id), :class => "lite_button", :style => "float:right" - = link_to truncate(commit.id.to_s, :length => 16), project_commit_path(@project, :id => commit.id), :class => "lite_button", :style => "width:120px;float:right" - %span - %span.author - = commit.author - = time_ago_in_words(commit.committed_date) - ago + .data + - commits.each do |commit| + %a{ :class => "commit", :href => project_commit_path(@project, :id => commit.id) } + %span.commit-info + %data.commit-button + = truncate(commit.id.to_s, :length => 16) + %i + %data.commit-browse{ :onclick => "location.href='#{tree_project_path(@project, :commit_id => commit.id)}';return false;"} + Browse Code + - if commit.author_email + = image_tag gravatar_icon(commit.author_email), :class => "left", :width => 40, :style => "padding-right:5px;" + - else + = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" + %span.commit-title + %strong + = truncate(commit.safe_message, :length => 60) + %span.commit-author + %strong= commit.author_name + = time_ago_in_words(commit.committed_date) + ago = more_commits_link if @commits.size > 99 diff --git a/app/views/commits/index.html.haml b/app/views/commits/index.html.haml index 452e13f8..f8928b6f 100644 --- a/app/views/commits/index.html.haml +++ b/app/views/commits/index.html.haml @@ -1,15 +1,33 @@ -%div - %h3 - .left - = form_tag project_commits_path(@project), :method => :get do - = select_tag "branch", options_for_select(@repo.heads.map(&:name), @branch), :onchange => "this.form.submit();", :class => "", :prompt => "Branches" -   - .left.prepend-1 - = form_tag project_commits_path(@project), :method => :get do - = select_tag "tag", options_for_select(@project.tags, @tag), :onchange => "this.form.submit();", :class => "", :prompt => "Tags" - = text_field_tag "ssh", @project.url_to_repo, :class => ["ssh_project_url", "one_click_select"] - .clear +- content_for(:body_class, "project-page commits-page") + +.left + = form_tag project_commits_path(@project), :method => :get do + = select_tag "branch", options_for_select(@repo.heads.map(&:name), @branch), :onchange => "this.form.submit();", :class => "", :prompt => "Branches" +.left + = form_tag project_commits_path(@project), :method => :get do + = select_tag "tag", options_for_select(@project.tags, @tag), :onchange => "this.form.submit();", :class => "", :prompt => "Tags" +.clear + +%br + + +-#%a.right.button{:href => "#"} Download +-#-if can? current_user, :admin_project, @project + %a.right.button.blue{:href => "#"} EDIT +%h2.icon + %span + %a.project-name{:href => "#"} + %i.arrow> + Project +   + %d + %a{:href => "#"} + = @ref - if params[:path] - %h3{:style => "color:#555"} /#{params[:path]} - %div{:id => dom_id(@project)} - = render "commits" +   + %d + %a{:href => "#"}= params[:path].split("/").join(" / ") + + +%div{:id => dom_id(@project)} + = render "commits" diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index 3beeada8..3bd9145e 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -7,7 +7,7 @@ %td= @commit.id %tr %td Author - %td= @commit.author + %td= @commit.author_name %tr %td Commiter %td= @commit.committer @@ -16,7 +16,9 @@ %td= @commit.committed_date %tr %td Message - %td= @commit.safe_message + %td + %pre.commit_message + = preserve @commit.safe_message %tr %td Tree %td= link_to 'Browse Code', tree_project_path(@project, :commit_id => @commit.id) diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index f4ce9a17..eb2122df 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -1 +1,40 @@ -timeline +- content_for(:body_class, "dashboard-page") + +#dashboard-content.dashboard-content.content + %aside + %h4 + - if current_user.can_create_project? + %a.button-small.button-green{:href => new_project_path} New Repository + Your Repositories + %ol.project-list + - @projects.each do |project| + %li + %a{:href => project_path(project)} + %span.arrow → + %span.project-name= project.name + %span.time + %strong Last activity: + = project.last_activity_date ? time_ago_in_words(project.last_activity_date) + " ago" : "Never" + #news-feed.news-feed + %h2.icon + %span> + Dashboard + - @active_projects.first(3).each do |project| + .project-box.project-updates.ui-box.ui-box-small.ui-box-big + %h3= project.name + .data + - project.updates.each do |update| + %a.project-update{:href => dashboard_feed_path(project, update)} + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 + %span.update-title + = dashboard_feed_title(update) + %span.update-author + %strong= update.author_name + authored + = time_ago_in_words(update.created_at) + ago + %br + / .project-update + / .project-updates + / #news-feed +/ #dashboard-content diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index bccf0181..01cb3375 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -1,15 +1,8 @@ -

Forgot your password?

- -
- <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> - <%= devise_error_messages! %> - -
<%= f.label :email %>
- <%= f.email_field :email %>
- -
<%= f.submit "Send me reset password instructions", :class => "lbutton vm" %>
- <% end %> -
-
- <%= render :partial => "devise/shared/links" %> -
+<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :class => "login-box", :method => :post }) do |f| %> + <%= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" %> + <%= devise_error_messages! %> + <%= f.email_field :email, :placeholder => "Email", :class => "text top" %> +
+ <%= f.submit "Reset password", :class => "grey-button" %> +
<%= render :partial => "devise/shared/links" %>
+<% end %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 21de54f0..c17ff3f9 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,20 +1,12 @@ -

Sign in

+<%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| %> + <%= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" %> + <%= f.text_field :email, :class => "text top", :placeholder => "Email" %> + <%= f.password_field :password, :class => "text bottom", :placeholder => "Password" %> -
- <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> -
<%= f.label :email %>
- <%= f.text_field :email %>
- -
<%= f.label :password %>
- <%= f.password_field :password %>
- - <% if devise_mapping.rememberable? -%> -
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
- <% end -%> -
-
<%= f.submit "Sign in", :class => "lbutton vm" %>
- <% end %> -
-
- <%= render :partial => "devise/shared/links" %> -
+ <% if devise_mapping.rememberable? -%> +
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
+ <% end -%> +
+ <%= f.submit "Sign in", :class => "grey-button" %> +
<%= render :partial => "devise/shared/links" %>
+<% end %> diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index 11e4c38e..a6a38e69 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -1,5 +1,5 @@ %table.round-borders#issues-table - %tr + %thead - if can?(current_user, :admin_issue, @project) && !params[:f] || params[:f] == "0" %th %th Assignee diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index c6105283..371a8033 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -1,9 +1,9 @@ %h2 = "Issue ##{@issue.id} - #{html_escape(@issue.title)}" -.span-15 +.left.width-65p -#= simple_format html_escape(@issue.content) .issue_notes= render "notes/notes" -.span-8.right +.right.width-30p .span-8 - if @issue.closed %center.success Closed diff --git a/app/views/layouts/_head_panel.html.erb b/app/views/layouts/_head_panel.html.erb index 07de8de4..a64aa3b5 100644 --- a/app/views/layouts/_head_panel.html.erb +++ b/app/views/layouts/_head_panel.html.erb @@ -1,22 +1,43 @@ -
+ +
+

+ GITLAB

+ + + + +
+ + +