diff --git a/app/components/travis-status.coffee b/app/components/travis-status.coffee new file mode 100644 index 00000000..3ae86598 --- /dev/null +++ b/app/components/travis-status.coffee @@ -0,0 +1,22 @@ +`import Ember from 'ember'` +`import Ajax from 'travis/utils/ajax'` +`import config from 'travis/config/environment'` + +TravisStatusComponent = Ember.Component.extend + status: null + + statusPageStatusUrl: (-> + config.statusPageStatusUrl + ).property() + + didInsertElement: -> + if url = @get('statusPageStatusUrl') + self = this + @getStatus(url).then (response) -> + if response.status and response.status.indicator + self.set('status', response.status.indicator) + + getStatus: (url) -> + $.ajax(url) + +`export default TravisStatusComponent` diff --git a/app/controllers/home.coffee b/app/controllers/home.coffee new file mode 100644 index 00000000..90babea0 --- /dev/null +++ b/app/controllers/home.coffee @@ -0,0 +1,5 @@ +`import Ember from 'ember'` + +Controller = Ember.Controller.extend() + +`export default Controller` diff --git a/app/controllers/repos.coffee b/app/controllers/repos.coffee index 390500f6..42a7e613 100644 --- a/app/controllers/repos.coffee +++ b/app/controllers/repos.coffee @@ -50,14 +50,10 @@ Controller = Ember.ArrayController.extend Visibility.every @config.intervals.updateTimes, @updateTimes.bind(this) recentRepos: (-> - Ember.ArrayProxy.extend( - isLoadedBinding: 'repos.isLoaded' - repos: Repo.withLastBuild(@store) - sorted: Ember.computed.sort('repos', 'sortedReposKeys') - content: limit('sorted', 'limit') - sortedReposKeys: ['sortOrder:asc'] - limit: 30 - ).create() + # I return an empty array here, because we're removing left sidebar, but + # I don't want to refactor too much code (it will be all changed anyway + # when we switch to new dashboard) + [] ).property() updateTimes: -> @@ -69,9 +65,6 @@ Controller = Ember.ArrayController.extend @set('tab', tab) this["view_#{tab}".camelize()](params) - viewRecent: -> - @set('content', @get('recentRepos')) - viewOwned: -> @set('content', @get('userRepos')) diff --git a/app/controllers/top.coffee b/app/controllers/top.coffee index 614d18ea..d70f1f6c 100644 --- a/app/controllers/top.coffee +++ b/app/controllers/top.coffee @@ -18,4 +18,8 @@ Controller = Ember.Controller.extend return false } + showCta: (-> + !@get('auth.signedIn') && !@get('config.pro') && !@get('landingPage') + ).property('auth.signedIn', 'landingPage') + `export default Controller` diff --git a/app/helpers/landing-page-last-build-time.coffee b/app/helpers/landing-page-last-build-time.coffee new file mode 100644 index 00000000..424bcde3 --- /dev/null +++ b/app/helpers/landing-page-last-build-time.coffee @@ -0,0 +1,7 @@ +`import { timeAgoInWords, safe } from 'travis/utils/helpers'` +`import Ember from "ember"` + +helper = Ember.Handlebars.makeBoundHelper (value, options) -> + safe timeAgoInWords(value) || 'currently running' + +`export default helper` diff --git a/app/models/repo.coffee b/app/models/repo.coffee index fdfe7ebf..b3083982 100644 --- a/app/models/repo.coffee +++ b/app/models/repo.coffee @@ -108,12 +108,12 @@ Repo = Model.extend ).property('_lastBuildDuration', 'lastBuildStartedAt', 'lastBuildFinishedAt') sortOrder: (-> - # cuz sortAscending seems buggy when set to false - if lastBuildFinishedAt = @get('lastBuildFinishedAt') - - new Date(lastBuildFinishedAt).getTime() + state = @get('lastBuildState') + if state != 'passed' && state != 'failed' + 0 else - - new Date('9999').getTime() - parseInt(@get('lastBuildId')) - ).property('lastBuildFinishedAt', 'lastBuildId') + parseInt(@get('lastBuildId')) + ).property('lastBuildId', 'lastBuildState') stats: (-> if @get('slug') diff --git a/app/router.coffee b/app/router.coffee index 22be0a06..708354c1 100644 --- a/app/router.coffee +++ b/app/router.coffee @@ -3,8 +3,26 @@ `import Location from 'travis/utils/location'` Router = Ember.Router.extend - # TODO: we should use TravisLocation here - location: if Ember.testing then 'none' else 'travis' + location: (-> + if Ember.testing + 'none' + else + # this is needed, because in the location + # we need to decide if repositories or home needs + # to be displayed, based on the current login status + # + # we should probably think about a more general way to + # do this, location should not know about auth status + Location.create(auth: @container.lookup('auth:main')) + ).property() + + # TODO: this is needed, because in the original version + # the router tries to run `this.location`, which fails + # with computed properties. It can be removed once this is + # changed in Ember.js + generate: -> + url = this.router.generate.apply(this.router, arguments) + return this.get('location').formatURL(url) handleURL: (url) -> url = url.replace(/#.*?$/, '') @@ -45,7 +63,8 @@ Router.map -> @route 'first_sync' @route 'insufficient_oauth_permissions' - @route 'auth', path: '/auth' + @route 'auth' + @route 'home' @resource 'profile', path: '/profile', -> @resource 'accounts', path: '/', -> diff --git a/app/routes/application.coffee b/app/routes/application.coffee index c46573fe..9838bfc5 100644 --- a/app/routes/application.coffee +++ b/app/routes/application.coffee @@ -51,6 +51,6 @@ Route = TravisRoute.extend BuildFaviconMixin, if @get('config').pro @transitionTo('auth') else - @transitionTo('main') + @transitionTo('home') `export default Route` diff --git a/app/routes/home.coffee b/app/routes/home.coffee new file mode 100644 index 00000000..c11760cc --- /dev/null +++ b/app/routes/home.coffee @@ -0,0 +1,68 @@ +`import BasicRoute from 'travis/routes/basic'` +`import config from 'travis/config/environment'` +`import limit from 'travis/utils/computed-limit'` + +Route = BasicRoute.extend + init: -> + store = @store + repos = Ember.ArrayProxy.extend( + isLoadedBinding: 'repos.isLoaded' + repos: @store.filter 'repo', (repo) -> + buildId = repo.get('lastBuildId') + if store.hasRecordForId('build', buildId) + state = repo.get('lastBuild.state') + state == 'passed' || state == 'failed' + external: [] + withExternal: Ember.computed.union('repos', 'external') + sorted: Ember.computed.sort('withExternal', 'sortedReposKeys') + content: limit('sorted', 'limit') + sortedReposKeys: ['sortOrder:desc'] + limit: 3 + ).create() + + @set('repos', repos) + + setInterval => + @set('letMoreReposThrough', true) + , 5000 + + setTimeout => + unless repos.get('length') + @store.find('repo').then (reposFromRequest) -> + repos.get('external').pushObjects reposFromRequest.toArray().slice(0, 3) + , 10000 + + @_super.apply this, arguments + + activate: -> + if !config.pro && @pusher + @pusher.subscribeAll(['common']) + + @store.addPusherEventHandlerGuard('landing-page', (event, data) => + @allowMoreRepos(event, data) + ) + + @_super.apply(this, arguments) + + @controllerFor('top').set('landingPage', true) + + allowMoreRepos: (event, data) -> + if @get('repos.length') < 3 + return true + + if event == 'build:finished' && + ['passed', 'failed'].indexOf(data.build.state) != -1 && + @get('letMoreReposThrough') + @set('letMoreReposThrough', false) + return true + + deactivate: -> + @_super.apply(this, arguments) + + @store.removePusherEventHandlerGuard('landing-page') + @controllerFor('top').set('landingPage', false) + + setupController: (controller, model) -> + controller.set('repos', @get('repos')) + +`export default Route` diff --git a/app/routes/main.coffee b/app/routes/main.coffee index 44376f91..f639e34d 100644 --- a/app/routes/main.coffee +++ b/app/routes/main.coffee @@ -14,8 +14,7 @@ Route = TravisRoute.extend setupController: (controller)-> # TODO: this is redundant with repositories and recent routes - toActivate = if @signedIn() then 'owned' else 'recent' - @container.lookup('controller:repos').activate(toActivate) + @container.lookup('controller:repos').activate('owned') activate: -> # subscribe to pusher only if we're at a main route diff --git a/app/routes/main/index.coffee b/app/routes/main/index.coffee index 4ebea1c0..6e01861f 100644 --- a/app/routes/main/index.coffee +++ b/app/routes/main/index.coffee @@ -2,7 +2,9 @@ Route = TravisRoute.extend redirect: -> - target = if @signedIn() then 'repositories' else 'recent' - @transitionTo("main.#{target}") + if @signedIn() + @transitionTo('main.repositories') + else + @transitionTo('home') `export default Route` diff --git a/app/routes/main/recent.coffee b/app/routes/main/recent.coffee index 4c00c403..caf6d5b9 100644 --- a/app/routes/main/recent.coffee +++ b/app/routes/main/recent.coffee @@ -1,15 +1,7 @@ -`import TravisRoute from 'travis/routes/basic'` -`import MainTabRoute from 'travis/routes/main-tab'` +`import Ember from 'ember'` -Route = MainTabRoute.extend - reposTabName: 'recent' - - activate: -> - @_super.apply(this, arguments) - @store.set('isRecentTabOpen', true) - - deactivate: -> - @_super.apply(this, arguments) - @store.set('isRecentTabOpen', false) +Route = Ember.Route.extend + redirect: -> + @transitionTo('main') `export default Route` diff --git a/app/routes/simple-layout.coffee b/app/routes/simple-layout.coffee index 95540a86..c6f045cc 100644 --- a/app/routes/simple-layout.coffee +++ b/app/routes/simple-layout.coffee @@ -3,8 +3,7 @@ Route = TravisRoute.extend setupController: -> $('body').attr('id', 'simple') - toActivate = if @signedIn() then 'owned' else 'recent' - @container.lookup('controller:repos').activate(toActivate) + @container.lookup('controller:repos').activate('owned') @_super.apply(this, arguments) renderTemplate: -> diff --git a/app/store.coffee b/app/store.coffee index a3eba84f..a76332c7 100644 --- a/app/store.coffee +++ b/app/store.coffee @@ -5,11 +5,20 @@ Store = DS.Store.extend defaultAdapter: 'application' adapter: 'application' - receivePusherEvent: (event, data) -> - [name, type] = event.split(':') + init: -> + @_super.apply(this, arguments) + @set('pusherEventHandlerGuards', {}) + addPusherEventHandlerGuard: (name, callback) -> + @get('pusherEventHandlerGuards')[name] = callback + + removePusherEventHandlerGuard: (name) -> + delete @get('pusherEventHandlerGuards')[name] + + canHandleEvent: (event, data) -> + [name, type] = event.split(':') auth = @container.lookup('auth:main') - if !@get('isRecentTabOpen') && event != 'job:log' && auth.get('signedIn') && + if event != 'job:log' && auth.get('signedIn') && !config.pro && !config.enterprise # if recent repos hasn't been opened yet, we can safely # drop any events that doesn't belong to repos owned by @@ -22,7 +31,18 @@ Store = DS.Store.extend else if name == 'build' id = data.repository.id - return if !@hasRecordForId('repo', id) && !permissions.contains(id) + return @hasRecordForId('repo', id) || permissions.contains(id) + + for name, callback of @get('pusherEventHandlerGuards') + unless callback(event, data) + return false + + return true + + receivePusherEvent: (event, data) -> + [name, type] = event.split(':') + + return unless @canHandleEvent(event, data) if name == 'job' && data.job?.commit @pushPayload(commits: [data.job.commit]) diff --git a/app/styles/app.scss b/app/styles/app.scss index 3403db9e..ef25d7a6 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -19,6 +19,7 @@ // @import "app/left"; @import "app/loading"; @import "app/main/annotations"; +@import "app/landing"; @import "app/main/list"; @import "app/main/log"; @import "app/main/sponsors"; diff --git a/app/styles/app/landing.sass b/app/styles/app/landing.sass new file mode 100644 index 00000000..695dd466 --- /dev/null +++ b/app/styles/app/landing.sass @@ -0,0 +1,554 @@ +.top.landing-page .topbar, +.wrapper.centered .topbar, +.wrapper.centered #top .cta p, +.top.landing-page .cta p + margin: 0 auto + max-width: 1024px + +.top.landing-page .topbar + background-color: #fff + + .button--signin + background-color: #ffffff + background-image: inline-image('landing-page/signingithub.svg') + background-size: 16px 16px + border: 2px solid #e4e7e7 + color: #a0a8a8 + + .button--signin:hover + background-color: #73c78d + background-image: inline-image('landing-page/signingithub-hover.svg') + border: 2px solid #73c78d + color: #fff + +.wrapper.centered .topbar + max-width: 1024px + +.wrapper.centered #top, +.wrapper.centered .topbar, +.wrapper.non-centered .topbar + background-color: #eff0ec + +#landing + margin: 0 auto 170px auto + font-weight: 300 + overflow: hidden + + h1 + font-size: 5em + line-height: 1em + font-weight: 300 + color: #8f9294 + margin-bottom: 0 + + h2 + font-size: 3.3em + line-height: 1.15em + font-weight: 300 + color: #39a85b + + p + font-color: #606162 + font-size: 1.7em + font-weight: 300 + + .hero, .oss-testing, .customers, .recent-builds, .free-for-oss, .private-repos, .features-list, .build-flows, .user-testimonials + padding: 70px 0 70px 0 + + h1, h2 + margin-top: 0 + + p + line-height: 1.5em + + .hero.z-1 + text-align: center + position: relative + z-index: 1 + + + .landing-centered-wrapper + max-width: 1024px + margin: 0 auto + + > .columns.medium-6:first-child + padding-right: 2em + > .columns.medium-6:last-child + padding-left: 2em + + #laptop + margin-bottom: -192px + + #laptop img + border: 2px solid #d8dadc + border-radius: 2px + + .hero + background-color: #faf9f6 + h1 + color: #339999 + line-height: 1.2em + margin-bottom: 0 + + p + margin: 0 + line-height: 1.5em + + br.mobile-break + display: none + + .button + background-color: #39a85b + color: #fff + font-size: 2em + font-weight: 300 + padding: 0.5em + margin: 1.3em 0 1.3em 0 + border-radius: 4px + border: 0 + + &:hover + background-color: #73c78d + + .sign-in-mascot + padding-right: 10px + + .oss-testing + background-color: #ffffff + text-align: center + position: relative + z-index: 1000 + + h2 + margin: 0 + + p + margin-top: 0.5em + margin-bottom: 2em + + br.mobile-break + display: none + + .customers + text-align: center + + .left + text-align: left + padding: 0 0 0 12% + + .recent-builds + background-color: #faf9f6 + text-align: center + min-height: 44rem + + h2 + color: #db4141 + text-align: right + margin: 0 + + a + color: #828282 + + p + text-align: right + margin-top: 0.5em + margin-bottom: 2em + + img + margin-bottom: 20px + + ul + padding-left: 0 + + li + background-color: #fff + border-radius: 4px + color: #828282 + font-weight: 400 + margin-bottom: 20px + list-style-type: none + position: relative + height: 120px + width: 100% + padding: 10px 0 0 60px + text-align: left + + .tile-status + position: absolute + top: 0 + left: 0 + bottom: 0 + + .owner, .name + display: block + + .owner + font-size: 14px + line-height: 1.8em + .name + font-size: 22px + + .state + display: inline-block + margin-left: 4px + + .commit, .number, .branch, .finished-at + position: absolute + display: block + background-repeat: no-repeat + background-position: left center + padding-left: 23px + + .number + left: 60px + top: 65px + background-image: inline-image('svg/build-number-icon.svg') + + .commit + left: 251px + top: 65px + background-image: inline-image('svg/commit-icon.svg') + + .branch + left: 250px + top: 90px + background-image: inline-image('dashboard/branch.svg') + background-size: 19px 19px + + .finished-at + left: 60px + top: 90px + background-image: inline-image('svg/finished-icon.svg') + background-size: 19px 19px + + &.started .tile-status, + &.created .tile-status, + &.received .tile-status, + &.queued .tile-status + background-color: $start-color + &.failed .tile-status + background-color: $fail-color + &.errored .tile-status + background-color: $error-color + &.canceled .tile-status + background-color: $cancel-color + &.passed .tile-status + background-color: $pass-color + &.inactive .tile-status + background-color: $cancel-color + + &.started .owner, + &.started .name, + &.created .owner, + &.created .name, + &.received .owner, + &.received .name, + &.queued .owner, + &.queued .name + color: $start-color + &.failed .owner, + &.failed .name + color: $fail-color + &.errored .owner, + &.errored .name + color: $error-color + &.canceled .owner, + &.canceled .name + color: $cancel-color + &.passed .owner, + &.passed .name + color: $pass-color + &.inactive .owner, + &.inactive .name + color: $cancel-color + + .free-for-oss + text-align: center + + h1 + margin-bottom: 0.3em + + p + margin: 0 + + span.bold-italic + font-weight: 600 + font-style: italic + + br.mobile-no-break + display: inline-block + + .private-repos + text-align: center + + h2 + color: #339999 + margin: 0 + text-align: right + + p + margin-top: 0.5em + margin-bottom: 2em + text-align: right + + a + text-decoration: underline + + .mobile-envelope + display: none + + .desktop-envelope + display: inline-block + + .features-list + background-color: #faf9f6 + + h2 + margin: 0 + + h3 + font-size: 1.4em + font-weight: 300 + color: #413c3c + text-align: center + margin-bottom: 35px + padding-top: 40px + + p + font-size: 1.15em + font-weight: 300 + color: #606162 + text-align: center + + br.mobile-break + display: none + + .features-callouts + text-align: center + @media #{$medium-only} + float: none + + #f-co-1, #f-co-2, #f-co-3, #f-co-4 + background-repeat: no-repeat; + background-position: 50% 0 + height: 32px + + #f-co-1, #f-co-2, #f-co-3, #f-co-4 + background-image: url('../images/landing-page/features-callouts-1.svg') + + #f-co-2 + background-image: url('../images/landing-page/features-callouts-2.svg') + + #f-co-3 + background-image: url('../images/landing-page/features-callouts-3.svg') + + #f-co-4 + background-image: url('../images/landing-page/features-callouts-4.svg') + + .features-checked + padding-left: 30px + @media #{$medium-only} + float: none + + h2 + @media #{$medium-only} + width: grid-calc(8, 12) + margin: 1em auto + ul + @media #{$medium-only} + width: grid-calc(5, 12) + margin: auto + + ul + @include resetul + margin-top: 1.6rem; + + li + font-color: #606162 + font-size: 1.7em + line-height: 1.7em + &:before + @extend %icon + content: "" + background-image: url('../images/landing-page/features-check.svg') + width: 0.7em + height: 0.7em + margin-right: .3em + + .build-flows + text-align: center + + h2 + color: #909295 + + h2#pr-bf-margin + margin-top: 90px + + .branch-bf + .bf + display: inline-block + width: 120px + + p + font-size: 1em + line-height: 1.5em + color: #5f6062 + + .divider-line-horizontal + width: 50px + height: 3px + background: #eaeaec + display: inline-block + margin-bottom: 75px + + .divider-line-vertical + display: none + + .user-testimonials + margin-bottom: 50px + + h2 + color: #418793 + text-align: right + + p + font-size: 1.2em + font-weight: 300 + color: #606162 + margin: 0 + display: inline-block + + img.avatar + max-width: 81px + float: right + + img.social + margin: -2px 3px 0 15px + display: inline-block + + .author + font-weight: 500 + margin: 6px 0 0 0 + + .title + margin: 0 0 20px 0 + + + a + font-size: 1.2em + + a:hover + text-decoration: underline + + @media (max-width: 900px) + .oss-testing br.mobile-break + display: inline-block + + .landing-centered-wrapper + width: 100% + + @media (max-width: 1024px) + .features-list .features-checked + margin-top: 40px + + .features-list .features-checked h2 + text-align: center + + @media (max-width: 886px) + #hero-copy + display: block + width: 100% + text-align: center + + .hero h1 + max-width: 100% + + .hero p + text-align: center + max-width: 100% + + .hero br.mobile-break + display: inline-block + + .features-list .features-callouts + padding: 0 60px 0 60px + + .features-list .features-checked + padding: 0 60px 0 60px + + @media (max-width: 846px) + .build-flows .branch-bf .bf + width: 100% + display: block + clear: all + + .build-flows .branch-bf .bf img + width: 120px + height: 120px + + .build-flows .branch-bf .bf p + font-size: 1.5em + + .build-flows .branch-bf .divider-line-horizontal + display: none + + .build-flows .branch-bf .divider-line-vertical + width: 3px + height: 40px + background: #eaeaec + display: inline-block + margin-bottom: 10px + + @media (max-width: 797px) + .customers .left + text-align: center + padding: 20px 0 0 0 + + .recent-builds h2 + text-align: center + + .recent-builds p + text-align: center + + .free-for-oss br.mobile-no-break + display: none + + .private-repos .desktop-envelope + display: none + + .private-repos .mobile-envelope + display: inline-block + margin-bottom: 40px + + .private-repos h2 + text-align: center + + .private-repos p + text-align: center + + .user-testimonials + margin-bottom: 50px + + .user-testimonials h2 + text-align: center + + .user-testimonails p + text-align: center + + @media (max-width: 640px) + .user-testimonials + margin-bottom: 140px + + @media (max-width: 608px) + br.mobile-break + display: inline-break + +.landing-vert-center-m + @media #{$medium-up} + position: relative + transform: translateY(65%) +.landing-vert-center-s + @media #{$medium-up} + position: relative + overflow: auto + transform: translateY(7%) diff --git a/app/styles/app/layout.sass b/app/styles/app/layout.sass index e75034fb..61fe2bd9 100644 --- a/app/styles/app/layout.sass +++ b/app/styles/app/layout.sass @@ -47,11 +47,13 @@ .wrapper overflow: hidden +.wrapper.non-centered #main, #left margin-bottom: -99999px padding-bottom: 100034px + @media #{$large-up} #left, #right, .wrapper-main @@ -63,30 +65,35 @@ margin-left: -100% max-width: 325px - .wrapper-main + .non-centered .wrapper-main width: grid-calc(18, 24) float: left margin-left: grid-calc(6, 24) overflow: visible + .centered .wrapper-main + max-width: 1024px + margin-left: auto + margin-right: auto + @media #{$xlarge-up} #left width: grid-calc(7, 36) - .wrapper-main + .non-centered .wrapper-main width: grid-calc(29, 36) margin-left: grid-calc(7, 36) @media #{$xxlarge-up} #left width: grid-calc(6, 36) - .wrapper-main + .non-centered .wrapper-main width: grid-calc(30, 36) margin-left: grid-calc(6, 36) @media screen and (min-width: 2200px) #left width: grid-calc(5, 36) - .wrapper-main + .non-centered .wrapper-main width: grid-calc(31, 36) margin-left: grid-calc(5, 36) diff --git a/app/styles/app/layouts/dashboard.sass b/app/styles/app/layouts/dashboard.sass index 68971f99..f3eac04c 100644 --- a/app/styles/app/layouts/dashboard.sass +++ b/app/styles/app/layouts/dashboard.sass @@ -214,3 +214,5 @@ $db-text-color: #ACAAAA h2, h3, p, button, .db-status opacity: .7 +.dashboard .topbar + background-color: transparent !important diff --git a/app/styles/app/layouts/footer.sass b/app/styles/app/layouts/footer.sass index 59d02b94..982ebbdb 100644 --- a/app/styles/app/layouts/footer.sass +++ b/app/styles/app/layouts/footer.sass @@ -2,11 +2,14 @@ * Footer on the dashboard */ +$footer-height: 204px + a color : $color-link text-decoration : none footer + position: relative padding : 20px 0 background-color : $footer-bg-color min-height : 334px @@ -24,12 +27,11 @@ footer height: auto @media (min-width: 640px) .wrapper - padding-bottom: 204px + padding-bottom: $footer-height + 50 footer - margin-top: -204px - min-height: 204px - + margin-top: - $footer-height + min-height: $footer-height footer h3 font-size : 15px @@ -43,6 +45,9 @@ footer .row p display : inline-block margin : 0 +footer .row + max-width: 1024px + footer .row ul, footer .row li display : block @@ -62,7 +67,6 @@ footer a:active text-decoration : underline .status-circle - background : $pass-color display : inline-block height : 11px width : 11px @@ -72,3 +76,16 @@ footer a:active -webkit-border-radius : 100px -moz-border-radius : 100px vertical-align: middle + +.status-circle.none + background: #2fcc66 + +.status-circle.degraded + background: #f1c40f + +.status-circle.minor + background: #e67e22 + +.status-circle.major + background: #e74c3c + diff --git a/app/styles/app/layouts/sidebar.sass b/app/styles/app/layouts/sidebar.sass index 12b5cd1e..88696923 100644 --- a/app/styles/app/layouts/sidebar.sass +++ b/app/styles/app/layouts/sidebar.sass @@ -75,7 +75,7 @@ $sb-font-size: 14px .icon--plus:after color: $teal1 &:after - bottom: 0 + bottom: -3px @media (min-width: #{lower-bound($large-range)}) ul diff --git a/app/styles/app/layouts/top.sass b/app/styles/app/layouts/top.sass index d4df65c5..a9fdb8c9 100644 --- a/app/styles/app/layouts/top.sass +++ b/app/styles/app/layouts/top.sass @@ -1,5 +1,35 @@ $top-height: 55px +#auth #top .cta + display: none + +#top .cta + border-bottom: 2px solid #E4E4E4 + border-top: 2px solid #E4E4E4 + line-height: 2.7em + font-size: 16px + color: #71AE76 + text-align: right + padding-right: 20px + background-color: #fff + + p + position: relative + margin-top: 0 + margin-bottom: 0 + padding-top: 0 + padding-bottom: 0 + + .arrow + display: block + position: absolute + top: -11px + right: 66px + background-image: inline-image('cta-arrow.svg') + background-repeat: no-repeat + width: 20px + height: 12px + .logo position: relative margin: 0 1.5rem 0 1.3rem @@ -39,7 +69,7 @@ $top-height: 55px .topbar font-size: $font-size-m - background-color: #eff0ec + background-color: #eff0ec color: $grey1 a @@ -84,7 +114,7 @@ $top-height: 55px height: $top-height > li display: inline-block - margin-right: 1rem + margin-right: 1rem a height: $top-height line-height: $top-height + 2px diff --git a/app/styles/app/modules/icons.sass b/app/styles/app/modules/icons.sass index c13230aa..8ad82bd9 100644 --- a/app/styles/app/modules/icons.sass +++ b/app/styles/app/modules/icons.sass @@ -1,11 +1,14 @@ -.icon - width: 1em - height: 1em +%icon display: inline-block background: size: 100% repeat: no-repeat +.icon + width: 1em + height: 1em + @extend %icon + .icon-cal, .icon--cal background-image: inline-image('svg/finished-icon.svg') diff --git a/app/templates/components/travis-status.hbs b/app/templates/components/travis-status.hbs new file mode 100644 index 00000000..a599939b --- /dev/null +++ b/app/templates/components/travis-status.hbs @@ -0,0 +1,8 @@ +{{#if statusPageStatusUrl}} +
Easily sync your github projects with Travis CI
and you’ll be testing your code in minutes!
Over 200k open source projects
and 126k users are testing on Travis CI.
Some pretty awesome companies
and projects are using us.
Here are just a few projects
currently running on Travis CI
Seriously. Always. We like to think of it as our way of giving
back to a community that gives us so much as well.
Travis CI for private repositories has
plans for every size project.
Login with GitHub, tell Travis CI to test a project, and then push to GitHub. Could it be any simpler!
+Make sure your code runs against all versions of your favorite language without breaking a sweat.
+Make sure every Pull Request to your project is tested before merging.
+Updating staging or production as soon as your tests pass has never been easier!
+You push your
code to github
github triggers
Travis CI to build
Hooray!
Your build passes!
Travis CI deploys
to Heroku
Travis CI tells the
team all is good
A pull request
is created
github tells Travis CI the build is mergeable
+Hooray!
Your build passes!
Travis CI updates the PR that it passed
+You merge in
the PR goodness
Travis CI makes it so much easier for us to coordinate the thousands of commits and contributors that flow through the Rails code base. The test suite for such a large project is vast, and we wouldn’t be catching issues as quickly or smoothly without the help of Travis.
+Creator of Ruby on Rails
+We love Travis CI at @TwitterOSS and use it for the majority of our open source projects on GitHub. Travis CI is simple to use, we love their API to build tooling and adore the new container infrastructure for speedier builds.
+Head of Open Source at Twitter
+Not only is Travis CI the best way to test your software, it is the right way. rm -rf jenkins && touch .travis.yml
+PyPy and Python Core Team Member
++ + Help make Open Source a better place and start building better software today! +
+