From c4614644b4c2808b0a905a8b056344d6b770f967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Fri, 23 Oct 2015 17:00:01 +0200 Subject: [PATCH] Style for like, vote and watch functionalities and refactor of tiket detail pages --- app/coffee/app.coffee | 2 +- app/coffee/modules/admin/memberships.coffee | 10 +- app/coffee/modules/admin/third-parties.coffee | 6 +- app/coffee/modules/backlog/lightboxes.coffee | 6 +- app/coffee/modules/backlog/main.coffee | 6 +- app/coffee/modules/common/attachments.coffee | 6 +- app/coffee/modules/common/components.coffee | 18 +- app/coffee/modules/common/lightboxes.coffee | 8 +- app/coffee/modules/common/loading.coffee | 32 ++- app/coffee/modules/issues/list.coffee | 8 +- app/coffee/modules/related-tasks.coffee | 5 +- app/coffee/modules/wiki/main.coffee | 6 +- app/coffee/modules/wiki/nav.coffee | 8 +- app/fonts/taiga.eot | Bin 10012 -> 9256 bytes app/fonts/taiga.svg | 54 ++--- app/fonts/taiga.ttf | Bin 9856 -> 9100 bytes app/fonts/taiga.woff | Bin 7212 -> 6712 bytes app/modules/home/duties/duty.jade | 41 ++-- app/modules/home/duties/duty.scss | 44 +--- .../navigation-bar/navigation-bar.scss | 2 +- .../user-timeline/user-timeline.scss | 2 +- .../common/components/assigned-to.jade | 16 +- .../common/components/delete-button.jade | 2 +- .../common/components/status-display.jade | 2 +- app/partials/common/components/watchers.jade | 35 +-- .../us-estimation-points-per-role.jade | 4 +- .../lightbox/lightbox-assigned-to-users.jade | 35 ++- .../common/lightbox/lightbox-assigned-to.jade | 2 +- .../common/lightbox/lightbox-users.jade | 2 +- .../modules/lightbox-us-create-edit.jade | 2 +- app/styles/components/buttons.scss | 4 +- app/styles/components/created-by.scss | 17 +- app/styles/components/estimation.scss | 66 +++++ app/styles/components/list-items.scss | 104 ++++++++ app/styles/components/track-btn.scss | 176 ++++++++++++++ app/styles/components/user-list.scss | 84 +++++++ app/styles/components/watchers.scss | 66 ----- app/styles/core/typography.scss | 176 +++++++++----- app/styles/dependencies/mixins.scss | 31 +++ .../{us-detail.scss => ticket-detail.scss} | 228 +----------------- app/styles/modules/backlog/backlog-table.scss | 43 +++- app/styles/modules/common/assigned-to.scss | 18 +- app/styles/modules/common/lightbox.scss | 66 ++--- app/styles/modules/common/ticket-data.scss | 199 +++++++++++++++ app/styles/modules/home-project.scss | 22 +- app/styles/modules/issues/issues-table.scss | 16 ++ app/styles/shame/shame.scss | 4 +- app/svg/check.svg | 5 + app/svg/like.svg | 6 + app/svg/logo-nav.svg | 10 +- app/svg/unwatch.svg | 4 + app/svg/upvote.svg | 14 ++ app/svg/watch.svg | 4 + 53 files changed, 1125 insertions(+), 602 deletions(-) create mode 100644 app/styles/components/estimation.scss create mode 100644 app/styles/components/list-items.scss create mode 100644 app/styles/components/track-btn.scss create mode 100644 app/styles/components/user-list.scss delete mode 100644 app/styles/components/watchers.scss rename app/styles/layout/{us-detail.scss => ticket-detail.scss} (52%) create mode 100644 app/styles/modules/common/ticket-data.scss create mode 100644 app/svg/check.svg create mode 100644 app/svg/like.svg create mode 100644 app/svg/unwatch.svg create mode 100644 app/svg/upvote.svg create mode 100644 app/svg/watch.svg diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index a09e1a27..81b29ead 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -611,7 +611,7 @@ init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $na projectService.setSection(next.section) if next.params.pslug - projectService.setProject(next.params.pslug) + projectService.setProjectBySlug(next.params.pslug) else projectService.cleanProject() diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 505419fe..087fcf16 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -402,9 +402,9 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla defaultMsg = $translate.instant("ADMIN.MEMBERSHIP.DEFAULT_DELETE_MESSAGE", {email: member.email}) message = if member.user then member.full_name else defaultMsg - $confirm.askOnDelete(title, message).then (finish) -> - onSuccess = -> - finish() + $confirm.askOnDelete(title, message).then (askResponse) -> + onSuccess = => + askResponse.finish() if $scope.page > 1 && ($scope.count - 1) <= $scope.paginatedBy $ctrl.selectFilter("page", $scope.page - 1) @@ -414,8 +414,8 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla text = $translate.instant("ADMIN.MEMBERSHIP.SUCCESS_DELETE") $confirm.notify("success", null, text) - onError = -> - finish(false) + onError = => + askResponse.finish(false) text = $translate.instant("ADMIN.MEMBERSHIP.ERROR_DELETE", {message: message}) $confirm.notify("error", null, text) diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index 7d36fc4c..5a5506eb 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -177,13 +177,13 @@ WebhookDirective = ($rs, $repo, $confirm, $loading, $translate) -> title = $translate.instant("ADMIN.WEBHOOKS.DELETE") message = $translate.instant("ADMIN.WEBHOOKS.WEBHOOK_NAME", {name: webhook.name}) - $confirm.askOnDelete(title, message).then (finish) => + $confirm.askOnDelete(title, message).then (askResponse) => onSucces = -> - finish() + askResponse.finish() $scope.$emit("webhooks:reload") onError = -> - finish(false) + askResponse.finish(false) $confirm.notify("error") $repo.remove(webhook).then(onSucces, onError) diff --git a/app/coffee/modules/backlog/lightboxes.coffee b/app/coffee/modules/backlog/lightboxes.coffee index 7d7a9c7b..721f4b76 100644 --- a/app/coffee/modules/backlog/lightboxes.coffee +++ b/app/coffee/modules/backlog/lightboxes.coffee @@ -96,15 +96,15 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, title = $translate.instant("LIGHTBOX.DELETE_SPRINT.TITLE") message = $scope.sprint.name - $confirm.askOnDelete(title, message).then (finish) => + $confirm.askOnDelete(title, message).then (askResponse) => onSuccess = -> - finish() + askResponse.finish() $scope.milestonesCounter -= 1 lightboxService.close($el) $rootscope.$broadcast("sprintform:remove:success", $scope.sprint) onError = -> - finish(false) + askResponse.finish(false) $confirm.notify("error") $repo.remove($scope.sprint).then(onSuccess, onError) diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index ef6f2fce..7c24f62f 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -546,15 +546,15 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F message = us.subject - @confirm.askOnDelete(title, message).then (finish) => + @confirm.askOnDelete(title, message).then (askResponse) => # We modify the userstories in scope so the user doesn't see the removed US for a while @scope.userstories = _.without(@scope.userstories, us) promise = @.repo.remove(us) promise.then => - finish() + askResponse.finish() @.loadBacklog() promise.then null, => - finish(false) + askResponse.finish(false) @confirm.notify("error") addNewUs: (type) -> diff --git a/app/coffee/modules/common/attachments.coffee b/app/coffee/modules/common/attachments.coffee index fb966130..2993a531 100644 --- a/app/coffee/modules/common/attachments.coffee +++ b/app/coffee/modules/common/attachments.coffee @@ -136,16 +136,16 @@ class AttachmentsController extends taiga.Controller title = @translate.instant("ATTACHMENT.TITLE_LIGHTBOX_DELETE_ATTACHMENT") message = @translate.instant("ATTACHMENT.MSG_LIGHTBOX_DELETE_ATTACHMENT", {fileName: attachment.name}) - return @confirm.askOnDelete(title, message).then (finish) => + return @confirm.askOnDelete(title, message).then (askResponse) => onSuccess = => - finish() + askResponse.finish() index = @.attachments.indexOf(attachment) @.attachments.splice(index, 1) @.updateCounters() @rootscope.$broadcast("attachment:delete") onError = => - finish(false) + askResponse.finish(false) message = @translate.instant("ATTACHMENT.ERROR_DELETE_ATTACHMENT", {errorMessage: message}) @confirm.notify("error", null, message) return @q.reject() diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index 4fd9db57..bfc27854 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -223,11 +223,7 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, html = $compile(template(ctx))($scope) $el.html(html) - if isEditable() and watchers.length == 0 - $el.find(".title").text("Add watchers") - $el.find(".watchers-header").addClass("no-watchers") - - $el.on "click", ".icon-delete", (event) -> + $el.on "click", ".js-delete-watcher", (event) -> event.preventDefault() return if not isEditable() target = angular.element(event.currentTarget) @@ -236,15 +232,15 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, title = $translate.instant("COMMON.WATCHERS.TITLE_LIGHTBOX_DELETE_WARTCHER") message = $scope.usersById[watcherId].full_name_display - $confirm.askOnDelete(title, message).then (finish) => - finish() + $confirm.askOnDelete(title, message).then (askResponse) => + askResponse.finish() watcherIds = _.clone($model.$modelValue.watchers, false) watcherIds = _.pull(watcherIds, watcherId) deleteWatcher(watcherIds) - $el.on "click", ".add-watcher", (event) -> + $el.on "click", ".js-add-watcher", (event) -> event.preventDefault() return if not isEditable() $scope.$apply -> @@ -420,14 +416,14 @@ DeleteButtonDirective = ($log, $repo, $confirm, $location, $template) -> title = $attrs.onDeleteTitle subtitle = $model.$modelValue.subject - $confirm.askOnDelete(title, subtitle).then (finish) => + $confirm.askOnDelete(title, subtitle).then (askResponse) => promise = $repo.remove($model.$modelValue) promise.then => - finish() + askResponse.finish() url = $scope.$eval($attrs.onDeleteGoToUrl) $location.path(url) promise.then null, => - finish(false) + askResponse.finish(false) $confirm.notify("error") $scope.$on "$destroy", -> diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index fa1e5965..cd6f9925 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -478,7 +478,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic html = usersTemplate(ctx) html = $compile(html)($scope) - $el.find("div.watchers").html(html) + $el.find(".assigned-to-list").html(html) closeLightbox = () -> lightboxKeyboardNavigationService.stop() @@ -499,7 +499,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic render(selectedUser, searchingText) $el.find('input').focus() - $el.on "click", ".watcher-single", (event) -> + $el.on "click", ".assigned-to-single", (event) -> event.preventDefault() target = angular.element(event.currentTarget) @@ -573,7 +573,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS html = usersTemplate(ctx) html = $compile(html)($scope) - $el.find("div.watchers").html(html) + $el.find(".ticket-watchers").html(html) closeLightbox = () -> lightboxKeyboardNavigationService.stop() @@ -597,7 +597,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS render(users) $el.find("input").focus() - $el.on "click", ".watcher-single", debounce 2000, (event) -> + $el.on "click", ".user-list-single", debounce 2000, (event) -> closeLightbox() event.preventDefault() diff --git a/app/coffee/modules/common/loading.coffee b/app/coffee/modules/common/loading.coffee index 20e8d3ea..7bf8efbb 100644 --- a/app/coffee/modules/common/loading.coffee +++ b/app/coffee/modules/common/loading.coffee @@ -21,19 +21,29 @@ module = angular.module("taigaCommon") -TgLoadingService = -> +TgLoadingService = ($compile) -> spinner = "loading..." return () -> service = { settings: { target: null, + scope: null, classes: [] - timeout: 0 + timeout: 0, + template: null }, target: (target) -> service.settings.target = target + return service + scope: (scope) -> + service.settings.scope = scope + + return service + template: (template) -> + service.settings.template = template + return service removeClasses: (classess...) -> service.settings.classes = classess @@ -51,9 +61,11 @@ TgLoadingService = -> # The loader is shown after that quantity of milliseconds timeoutId = setTimeout (-> if not target.hasClass('loading') - service.settings.oldContent = target.html() + if !service.settings.template + service.settings.template = target.html() target.addClass('loading') + target.html(spinner) ), service.settings.timeout @@ -71,25 +83,35 @@ TgLoadingService = -> removeClasses = service.settings.classes removeClasses.map (className) -> service.settings.target.addClass(className) - target.html(service.settings.oldContent) + target.html(service.settings.template) target.removeClass('loading') + if service.settings.scope + $compile(target.contents())(service.settings.scope) + return service } return service +TgLoadingService.$inject = [ + "$compile" +] + module.factory("$tgLoading", TgLoadingService) LoadingDirective = ($loading) -> link = ($scope, $el, attr) -> currentLoading = null + template = $el.html() $scope.$watch attr.tgLoading, (showLoading) => - if showLoading currentLoading = $loading() .target($el) + .timeout(50) + .template(template) + .scope($scope) .start() else if currentLoading currentLoading.finish() diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 63640d44..6921b768 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -620,18 +620,18 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat title = $translate.instant("ISSUES.FILTERS.CONFIRM_DELETE.TITLE") message = $translate.instant("ISSUES.FILTERS.CONFIRM_DELETE.MESSAGE", {customFilterName: customFilterName}) - $confirm.askOnDelete(title, message).then (finish) -> + $confirm.askOnDelete(title, message).then (askResponse) -> promise = $ctrl.deleteMyFilter(customFilterName) promise.then -> promise = $ctrl.loadMyFilters() promise.then (filters) -> - finish() + askResponse.finish() $scope.filters.myFilters = filters renderFilters($scope.filters.myFilters) promise.then null, -> - finish() + askResponse.finish() promise.then null, -> - finish(false) + askResponse.finish(false) $confirm.notify("error") diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index b2a4595f..0035a646 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -85,14 +85,15 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem task = $model.$modelValue message = task.subject - $confirm.askOnDelete(title, message).then (finish) -> + $confirm.askOnDelete(title, message).then (askResponse) -> promise = $repo.remove(task) promise.then -> - finish() + askResponse.finish() $confirm.notify("success") $scope.$emit("related-tasks:delete") promise.then null, -> + askResponse.finish(false) $confirm.notify("error") $scope.$watch $attrs.ngModel, (val) -> diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index 902217e6..108149b0 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -126,15 +126,15 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) title = @translate.instant("WIKI.DELETE_LIGHTBOX_TITLE") message = @scope.wikiTitle - @confirm.askOnDelete(title, message).then (finish) => + @confirm.askOnDelete(title, message).then (askResponse) => onSuccess = => - finish() + askResponse.finish() ctx = {project: @scope.projectSlug} @location.path(@navUrls.resolve("project-wiki", ctx)) @confirm.notify("success") onError = => - finish(false) + askResponse.finish(false) @confirm.notify("error") @repo.remove(@scope.wiki).then onSuccess, onError diff --git a/app/coffee/modules/wiki/nav.coffee b/app/coffee/modules/wiki/nav.coffee index 15d46dd0..e63fb1a5 100644 --- a/app/coffee/modules/wiki/nav.coffee +++ b/app/coffee/modules/wiki/nav.coffee @@ -83,17 +83,17 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l title = $translate.instant("WIKI.DELETE_LIGHTBOX_TITLE") message = $scope.wikiLinks[linkId].title - $confirm.askOnDelete(title, message).then (finish) => + $confirm.askOnDelete(title, message).then (askResponse) => promise = $tgrepo.remove($scope.wikiLinks[linkId]) promise.then -> promise = $ctrl.loadWikiLinks() promise.then -> - finish() + askResponse.finish() render($scope.wikiLinks) promise.then null, -> - finish() + askResponse.finish() promise.then null, -> - finish(false) + askResponse.finish(false) $confirm.notify("error") $el.on "keyup", ".new input", (event) -> diff --git a/app/fonts/taiga.eot b/app/fonts/taiga.eot index f8cdfc90c9bfc24340534c3967586c34d1d6c547..17c2392104653cfa020f5381d6075f62d67faa82 100644 GIT binary patch delta 1187 zcmZWoU1%It6#nkqyEC)1f79&jkJ)7ZW_PpQWV4&i?o76A+O*Udi#0)QY)y=Aewrxx z+0vk~iV4!kl2C5JfC{B(DLxhVCHhc*@Ij$gNkkvif}oFrKT)cPk(u}q@E*=RA0OwO zd${ME*B`zyAZAm*CH=B!u+8zU=F5Gv%k>wJYyf&4K+6Ni@9)P1L_i+`5FdQBP#XMZ z^nHMw1~5D^SF2BWXL5j$0?5Vb+WGp<4k(}x0Fb9=UpV{O!lf;Mg@M-M%v5dCG4kDy z0KNra%*;&HSV3?AL<5kTnOj_5a-U#70puot#o2|4+9z**_z*yE0GOYvE!DAtR{_#v z6*OO)oBHkVg{wef03h@Ah4YKzEpY@$ZU9&X0W59a8sB`%cj$Mx1XyP?dS`L36=3r+ z1pYQ@5&(XSL>vaLK<0PJx4iZOCFja%e}X2^}b-8+ml1fFin3 z;VabOD%;oG8jZyhNj;U$v}O0_+Djef?tEvV*i`}lp0?8FNDC)yb?O}wCRc^5a6))a z*cAStVfqMtiC(97=sniYCfP;yk>jvqTO1cRBt?2mx*$Vdl7Db&&VJ{r^J7I;Qp%XJ zqFh(LbSbWkYtkKeKkI(Qz3w^fdCzm#^N%;d8x#+O2xs%`T5O zD9UcX*GDNc7^R}D`nF#mkrY}gC*0bl-n{%NepNqGiVy7 z5z=hWO4&5JOIBFui>KRj(U=xg6vY|RV$odtE)jAniW0Plj%P82oIeVvb-GPyTO8JNArc31yh* lK@|sZ5Zy3P!6E)tCe~H~0R#Tq3u{SnyZ74XmfgFW{{rH(*CGG_ delta 2001 zcma)-U1%KF8HV3)&dfRUKjYQTt}N}Yq?I%y?@HSB{>-cs*Ou)xj_bs6X&uXn<64bX z3o6;N6H+?=_q=?F7Xo12e~yQ;{o;XFo|{|lp8J4*AMj5BDD1!Mt9N4& z9PsY~Fna$tYK{BfJN`?6<^eqL$jZX%%dcMg2#}@#`t|9BM^}42Fu>mlKs~*D;X8Le z`T9$Md=eP>{nFyXDfYwlivT_b5H2k(F37Wz0#Fvf#L~)R-8IvfZvylhfVJhbk1YJ* z@JBxa*mVHsR~FV*@f2PFsFMVAW?^OV(|?|gfr$=4XI9TX`WXKme;$~;4B*EgAgQk$ zc+virv-2hl2}${|GxE;oeXj>dNY_PN^?LDD8df^^3AFec9i@64O5f`O$9g>w zIyizI$lyT`GROeQjni641%bE0(oq32E&f!gB!D{hU?Clgbe;qYa3oi2 zqJSbw7{Mso7(*H1H!+SWOrU~E_y{nK8Eiupv#6nt?P!2Oh5`-&6&iFHFk!)l0~cG6 z!2q)GkV77W*oqd0FdXkoY#y~jS4_sS>bb@{4thw@i`g1;`fI4m9)pQ-27 zYnrXiX+O}e>XKg4=k+J_OZxkUY>XNwj16;_dEI)`hCOJ{+BclT&Z=|SxxRTt{)bHM z_*JbTITZg`3vVTVsmFHeYZ{jP1um z@mm8^@h1ZhY}E@nu9^e3!oQituDV0szw&_$eilB@uRJ~y5G=&$nKbu-n z<-)P`f+p0Hx+=&ubca-pHtB2bq@i;W_y@a;4!FKYI{B@G`ObHJ zV_4(Dbwxpuq#?DW3Ux@&dWUS=s(LohX%&;170YrYyJ9-_kSffk;gDlA4OL72Hw}cl z>0k6(O1FvKIEZ)FmXDYHb}I~S15U^*316>| z-k<#Mjl{&hf4mRA*$8XY3jFS^Gy4+OUvN)6(8dz(uBB)C+Y;$^xe(On>3$0*#S*yrN*u1E6#kI7eCe)vriXbO(frLgE z6Y|~Ehsk?y+aP$~hD>S5>)Vjq+R^&LK~yQ_`s!l?8GYFHvd*v~$wS<=6Js?0xMiCa z&vvpEgBcaeG9@yrx@(O~To_H=ag3&>CAo;9gM;)gy@AbMp~B*GqkFpuIP0lTo)u4&_CZkNVKGZ;t{FZFtm(kH+M gFqp0-bA|{6IYp9`^pW`B#BV=KCSSZ`(#Sji2KKr=?*IS* diff --git a/app/fonts/taiga.svg b/app/fonts/taiga.svg index 435c7a92..afb37235 100644 --- a/app/fonts/taiga.svg +++ b/app/fonts/taiga.svg @@ -30,34 +30,32 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/app/fonts/taiga.ttf b/app/fonts/taiga.ttf index 67c906cc0890a72714a082892c4744a70d03e7f1..e31d761e90fa5a30ac2f2489aa2b608cb0b79245 100644 GIT binary patch delta 1249 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 diff --git a/app/fonts/taiga.woff b/app/fonts/taiga.woff index 5c346f3a23653fbe926725ed6cdcd7c5a9ea6200..e58fb93e293fd13addbb42ea5539b3621915c93c 100644 GIT binary patch delta 6694 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 literal 7212 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

{IhYzhl&l?*3UhioQ7wsP8Mh6h~rhtDX%CNS~ey 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 { align-items: center; + border-bottom: 0; display: flex; flex-direction: row; } } - .avatar { - flex-basis: 47px; - height: 47px; - margin-right: .5rem; - width: 47px; - } - .duty-data { - flex: 1; - margin-right: .5rem; - } - .duty-type, - .duty-status { - @extend %small; - color: $gray; - margin-right: .3rem; - } - .duty-title { - display: block; - margin-top: .25rem; - } - .duty-id { - color: $gray-light; - margin-right: .3rem; - } - .duty-project { - @extend %small; - align-self: flex-start; - color: $gray-light; - margin-left: auto; - text-align: right; - width: 120px; - } .see-more { display: block; margin: 2rem 30%; diff --git a/app/modules/navigation-bar/navigation-bar.scss b/app/modules/navigation-bar/navigation-bar.scss index 13702f76..920a1eea 100644 --- a/app/modules/navigation-bar/navigation-bar.scss +++ b/app/modules/navigation-bar/navigation-bar.scss @@ -106,7 +106,7 @@ $dropdown-width: 350px; min-width: $dropdown-width; position: absolute; top: 2.4rem; - z-index: 99; + z-index: 999; } } diff --git a/app/modules/user-timeline/user-timeline/user-timeline.scss b/app/modules/user-timeline/user-timeline/user-timeline.scss index 6446d82a..8086bcbd 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.scss +++ b/app/modules/user-timeline/user-timeline/user-timeline.scss @@ -1,7 +1,7 @@ .profile-timeline { .activity-item { border-bottom: 1px solid $whitish; - padding: 1rem .5rem; + padding: 1rem .5rem 1rem 0; position: relative; p { margin-bottom: 0; diff --git a/app/partials/common/components/assigned-to.jade b/app/partials/common/components/assigned-to.jade index ee144283..7ad68ab3 100644 --- a/app/partials/common/components/assigned-to.jade +++ b/app/partials/common/components/assigned-to.jade @@ -9,14 +9,14 @@ a(href="" title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}", class!="user-assigned <% if(isEditable){ %>editable<% }; %>") span.assigned-name - <% if (assignedTo) { %> - <%- assignedTo.full_name_display %> - <% } else { %> - | {{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }} - <% } %> - <% if(isEditable){ %> - span.icon.icon-arrow-bottom - <% }; %> + <% if (assignedTo) { %> + <%- assignedTo.full_name_display %> + <% } else { %> + | {{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }} + <% } %> + <% if(isEditable){ %> + span.icon.icon-arrow-bottom + <% }; %> <% if (assignedTo!==null && isEditable) { %> a.icon.icon-delete(href="" title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}") <% } %> diff --git a/app/partials/common/components/delete-button.jade b/app/partials/common/components/delete-button.jade index 205e4fb4..cc325950 100644 --- a/app/partials/common/components/delete-button.jade +++ b/app/partials/common/components/delete-button.jade @@ -1,2 +1,2 @@ -a(href="", class="button button-red") +a.button-red.button-delete(href="") span(translate="COMMON.DELETE") diff --git a/app/partials/common/components/status-display.jade b/app/partials/common/components/status-display.jade index 1062f3f4..d9c04b04 100644 --- a/app/partials/common/components/status-display.jade +++ b/app/partials/common/components/status-display.jade @@ -3,5 +3,5 @@ span(translate="COMMON.STATUS.CLOSED") <% } else { %> span(translate="COMMON.STATUS.OPEN") <% } %> -span(class="us-detail-status", style!="color:<%- status.color %>") +span(style!="color:<%- status.color %>") | <%- status.name %> diff --git a/app/partials/common/components/watchers.jade b/app/partials/common/components/watchers.jade index b11a4aeb..31e4ea94 100644 --- a/app/partials/common/components/watchers.jade +++ b/app/partials/common/components/watchers.jade @@ -1,22 +1,29 @@ -<% if(isEditable){ %> -.watchers-header - span.title(translate="COMMON.WATCHERS.TITLE") - a.icon.icon-plus.add-watcher(href="", title="{{'COMMON.WATCHERS.ADD' | translate}}") -<% } else if(watchers.length > 0){ %> -.watchers-header - span.title(translate="COMMON.WATCHERS.TITLE") -<% }; %> - <% _.each(watchers, function(watcher) { %> <% if(watcher) { %> -.watcher-single - .watcher-avatar - img(src!="<%- watcher.photo %>" alt!="<%- watcher.full_name_display %>") - .watcher-name +.user-list-single + .user-list-avatar + img( + src!="<%- watcher.photo %>" + alt!="<%- watcher.full_name_display %>" + ) + .user-list-name span <%- watcher.full_name_display %> <% if(isEditable){ %> - a.icon.icon-delete(data-watcher-id!="<%- watcher.id %>" href="" title="{{'COMMON.WATCHERS.DELETE' | translate}}") + a.icon.icon-delete.js-delete-watcher( + href="" + data-watcher-id!="<%- watcher.id %>" + title="{{'COMMON.WATCHERS.DELETE' | translate}}" + ) <% }; %> <% } %> <% }); %> + +<% if(isEditable){ %> +a.add-watcher.js-add-watcher( + href="" + title="{{'COMMON.WATCHERS.TITLE_ADD' | translate}}" +) + span.icon.icon-plus + span(translate="COMMON.WATCHERS.ADD") +<% }; %> diff --git a/app/partials/common/estimation/us-estimation-points-per-role.jade b/app/partials/common/estimation/us-estimation-points-per-role.jade index 8fd9ce85..904d6b4a 100644 --- a/app/partials/common/estimation/us-estimation-points-per-role.jade +++ b/app/partials/common/estimation/us-estimation-points-per-role.jade @@ -1,9 +1,9 @@ ul.points-per-role - li.total + li.ticket-role-points.total span.points <%- totalPoints %> span.role(translate="US.TOTAL_POINTS") <% _.each(roles, function(role) { %> - li(class!="total <% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") + li.ticket-role-points(class!="total <% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") span.points <%- role.points %> span.role <%- role.name %> <% }); %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to-users.jade b/app/partials/common/lightbox/lightbox-assigned-to-users.jade index 6dd8e65b..49c44b9a 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to-users.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to-users.jade @@ -1,23 +1,38 @@ <% if (selected) { %> -.watcher-single.active - .watcher-avatar - a(href="", title="{{'COMMON.ASSIGNED_TO' | translate}}", class="avatar") +.user-list-single.is-active + .user-list-avatar + a( + href="" + title="{{'COMMON.ASSIGNED_TO' | translate}}" + ) img(src!="<%- selected.photo %>") - a(href="", title!="<%- selected.full_name_display %>", class="watcher-name") + a.user-list-name( + href="" + title!="<%- selected.full_name_display %>" + ) | <%-selected.full_name_display %> - a(href="", title="{{'COMMON.ASSIGNED_TO.REMOVE_ASSIGNED' | translate}}", class="icon icon-delete remove-assigned-to") + a.icon-delete.remove-assigned-to( + href="" + title="{{'COMMON.ASSIGNED_TO.REMOVE_ASSIGNED' | translate}}" + ) <% } %> <% _.each(users, function(user) { %> -.watcher-single(data-user-id!="<%- user.id %>") - .watcher-avatar - a(href="#", title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}", class="avatar") +.user-list-single(data-user-id!="<%- user.id %>") + .user-list-avatar + a( + href="#" + title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" + ) img(src!="<%- user.photo %>") - a(href="", title!="<%- user.full_name_display %>", class="watcher-name") + a.user-list-name( + href="" + title!="<%- user.full_name_display %>" + ) | <%- user.full_name_display %> <% }) %> <% if (showMore) { %> -div(class="more-watchers") +.more-watchers span(translate="COMMON.ASSIGNED_TO.TOO_MANY") <% } %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to.jade b/app/partials/common/lightbox/lightbox-assigned-to.jade index 34e87b9a..7f00751d 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to.jade @@ -6,4 +6,4 @@ div.form input(type="text", data-maxlength="500", placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", ng-model="usersSearch") //-This block is rendered by the directive - div.watchers + .assigned-to-list diff --git a/app/partials/common/lightbox/lightbox-users.jade b/app/partials/common/lightbox/lightbox-users.jade index 180b8fb3..2c43e246 100644 --- a/app/partials/common/lightbox/lightbox-users.jade +++ b/app/partials/common/lightbox/lightbox-users.jade @@ -4,5 +4,5 @@ div.form h2.title(translate="COMMON.WATCHERS.ADD") fieldset input(type="text", data-maxlength="500", placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", ng-model="usersSearch") - div.watchers + div.ticket-watchers //- The content of this is rendered by directive diff --git a/app/partials/includes/modules/lightbox-us-create-edit.jade b/app/partials/includes/modules/lightbox-us-create-edit.jade index 067d5c27..98259aa3 100644 --- a/app/partials/includes/modules/lightbox-us-create-edit.jade +++ b/app/partials/includes/modules/lightbox-us-create-edit.jade @@ -6,7 +6,7 @@ form input(type="text", name="subject", ng-model="us.subject", placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}", data-required="true", data-maxlength="500") - fieldset.estimation + fieldset.ticket-estimation tg-lb-us-estimation(ng-model="us") fieldset diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index 51f877c7..743d669a 100755 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -1,7 +1,7 @@ .button, %button { - @extend %medium; - @extend %title; + @extend %light; + @extend %small; background: transparent; border: 0; color: $white; diff --git a/app/styles/components/created-by.scss b/app/styles/components/created-by.scss index f021993a..734bd5f9 100644 --- a/app/styles/components/created-by.scss +++ b/app/styles/components/created-by.scss @@ -1,30 +1,27 @@ -.us-created-by { +.ticket-created-by { display: flex; margin-bottom: 1rem; margin-top: .5rem; position: relative; .user-avatar { - flex-basis: 40px; + flex-basis: 3rem; flex-grow: 0; + margin-right: .5rem; img { - border-radius: 8%; width: 100%; } } .created-by { - flex-basis: 70px; - flex-grow: 3; - margin-left: .5rem; .created-title, .created-date { + @extend %light; @extend %small; - color: $gray-light; + color: $gray; display: block; + line-height: 1.5; } - .created-user { - @extend %large; + .created-title { color: $primary; - cursor: default; &.editable { cursor: pointer; } diff --git a/app/styles/components/estimation.scss b/app/styles/components/estimation.scss new file mode 100644 index 00000000..340e7b11 --- /dev/null +++ b/app/styles/components/estimation.scss @@ -0,0 +1,66 @@ +%estimation { + .points-per-role { + display: flex; + flex-wrap: wrap; + } + .ticket-role-points { + background: rgba($gray-light, .1); + border-radius: 2px; + color: rgba($grayer, .3); + flex-basis: 20%; + flex-grow: 1; + flex-shrink: 0; + margin: .1rem; + padding: .5rem 0 .1rem; + position: relative; + text-align: center; + transition: color .3s linear; + &.active { + background: rgba($primary-light, .9); + color: $whitish; + } + &:first-child { + background: rgba($grayer, .25); + border-radius: 0; + color: $whitish; + } + &:last-child { + border: 0; + } + .points { + @extend %larger; + @extend %text; + display: block; + text-align: center; + } + .role { + @extend %small; + @include ellipsis(90%); + display: inline-block; + text-align: center; + } + } + .popover { + @include popover(200px, $top: 105%, $left: 35%, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 10px, $arrow-height: 10px); + li { + display: inline-block; + width: 23%; + } + a { + display: block; + text-align: center; + &:hover, + &.active { + background: $primary-light; + color: $white; + } + } + &.fix { + @include popover(200px, $top: 105%, $left: -160px, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 90%, $arrow-height: 10px); + } + } +} + +.ticket-estimation { + @extend %estimation; +} diff --git a/app/styles/components/list-items.scss b/app/styles/components/list-items.scss new file mode 100644 index 00000000..92e35c8a --- /dev/null +++ b/app/styles/components/list-items.scss @@ -0,0 +1,104 @@ +// Like and Watch number component + +// Common styles for all list items +@mixin list-itemtype-common { + @include list-itemtype-track; + border-bottom: 1px solid $whitish; + display: flex; + padding: .5rem; + padding-right: 0; + h2 { + @extend %normal; + @extend %text; + line-height: 1.4; + margin-bottom: 0; + text-transform: none; + } + p { + @extend %light; + margin-bottom: 0; + } + .list-itemtype-avatar { + flex-basis: 3rem; + flex-shrink: 0; + margin-right: .75rem; + min-width: 3rem; + img { + width: 100%; + } + } +} + +.list-itemtype-project { + @include list-itemtype-common; + justify-content: space-between; + h2 { + @extend %large; + } + .list-itemtype-project-members { + align-self: flex-end; + display: flex; + flex-direction: row-reverse; + flex-grow: 0; + flex-wrap: wrap-reverse; + margin-top: 1rem; + img { + border-radius: .1rem; + margin-right: .3rem; + width: 2rem; + } + } + .list-itemtype-project-tags { + align-self: flex-end; + display: flex; + flex: 3; + flex-wrap: wrap; + margin-top: .5rem; + } + .tag { + align-self: flex-end; + margin-right: .5rem; + padding: .5rem; + } +} + +.list-itemtype-ticket { + @include list-itemtype-common; + h2 { + @extend %medium; + } + .ticket-type, + .ticket-project { + margin-right: .3rem; + } + .ticket-project { + color: $gray-light; + } + .list-itemtype-ticket-data { + flex: 1; + margin-right: 1rem; + } + .ticket-id { + color: $gray-light; + margin-right: .3rem; + } + +} + + +.list-itemtype-user { + @include list-itemtype-common; + h2 { + @extend %large; + } + .extra-info { + @extend %small; + @extend %light; + margin-top: .25rem; + } +} + +.list-itemtype-timeline { + @include list-itemtype-common; + +} diff --git a/app/styles/components/track-btn.scss b/app/styles/components/track-btn.scss new file mode 100644 index 00000000..a03e694b --- /dev/null +++ b/app/styles/components/track-btn.scss @@ -0,0 +1,176 @@ +////////////////////// +//Watch like buttons +////////////////////// + +.track-buttons-container { + @extend %small; + position: relative; +} + +.track-button { + align-items: stretch; + display: inline-flex; + position: relative; + .track-inner { + align-items: stretch; + background: $whitish; + border-radius: 4px 0 0 4px; + display: inline-flex; + flex: 1; + margin-right: .1rem; + width: 140px; + &:hover { + background: darken($whitish, 5%); + transition: background .3s; + } + span { + align-self: center; + } + } + &:hover { + color: $blackish; + } + &.active { + .track-inner { + background: rgba($primary-light, .2); + } + .track-icon { + path { + fill: $primary; + } + } + } + &.watch-container { + margin-right: 1rem; + position: relative; + } + .track-icon { + padding: .3rem .6rem .3rem .75rem; + svg { + height: 1.1rem; + position: relative; + top: 2px; + width: 1.1rem; + } + path { + fill: $grayer; + } + } + .track-button-counter { + align-items: center; + border: 1px solid $whitish; + display: flex; + justify-content: center; + min-width: 2rem; + } +} +.watch-button, +.like-button { + &.active { + &.is-hover { + .track-inner { + background: $red; + color: $whitish; + transition: background .3s; + } + path { + fill: $red-light; + } + } + } +} + +.watch-options { + animation: dropdownFade .2s cubic-bezier(.09, 0, .99, .01) alternate; + background: rgba($black, .9); + border-radius: 4px; + margin: 0; + margin-top: 2.5rem; + min-width: 300px; + padding: 1rem; + position: absolute; + right: 0; + top: 0; + z-index: 99; + &.hidden { + animation: dropdownFade .2s cubic-bezier(.09, 0, .99, .01) reverse; + } + li { + margin: 0; + &:last-child a { + border: 0; + } + } + a { + @extend %light; + border-bottom: 1px solid rgba($gray-light, .3); + color: $white; + display: flex; + justify-content: space-between; + padding: .5rem 0; + &.active { + color: $primary-light; + } + } + .watch-check { + height: 1.25rem; + width: 1.25rem; + path { + fill: $primary-light; + } + } +} + +.upvote-btn { + align-content: center; + align-items: stretch; + display: flex; + flex: 0; + flex-basis: 3rem; + justify-content: center; + margin-right: .3rem; + a { + background: $whitish; + color: $gray-light; + display: block; + padding: 1rem; + text-align: center; + &:hover { + background: darken($whitish, 5%); + color: $primary-dark; + transition: background .3s; + path { + fill: $primary-dark; + } + } + &.active { + background: rgba($primary-light, .2); + color: $primary; + transition: all .3s; + path { + fill: $primary; + } + } + &.is-hover { + background: $red; + color: $whitish; + svg { + transform: rotate(180deg); + transition: all .3s; + } + path { + fill: $red-light; + } + } + } + svg { + height: 1rem; + width: 1rem; + } + span { + display: block; + } + path { + fill: $gray-light; + } +} diff --git a/app/styles/components/user-list.scss b/app/styles/components/user-list.scss new file mode 100644 index 00000000..0000c4dc --- /dev/null +++ b/app/styles/components/user-list.scss @@ -0,0 +1,84 @@ +%user-list { + .user-list-single { + align-content: center; + align-items: center; + background: transparent; + border-bottom: 1px solid $whitish; + display: flex; + padding: .5rem .5rem .3rem; + vertical-align: middle; + + &:last-child { + border: 0; + } + } + .user-list-avatar { + flex-basis: 3rem; + margin-right: .25rem; + max-width: 3rem; + img { + width: 100%; + } + } + .user-list-name { + @extend %light; + color: $grayer; + margin-left: .5rem; + } +} + +.assigned-to-list { + @extend %user-list; + margin-top: 1rem; + .user-list-single { + &:hover { + background: lighten($primary, 58%); + cursor: pointer; + transition: background .3s linear; + transition-delay: .2s; + } + &.is-active { + background: lighten($primary, 55%); + cursor: pointer; + margin-bottom: 1rem; + position: relative; + transition: background .3s linear; + transition-delay: .1s; + .icon-delete { + opacity: 1; + position: absolute; + right: 1rem; + top: 1.3rem; + transition: opacity .2s ease-in; + } + } + } +} + +.ticket-watchers { + @extend %user-list; + margin-top: 1rem; + .user-list-single { + &:hover { + .icon-delete { + opacity: 1; + transition: opacity .2s ease-in; + } + } + } + .user-list-name { + flex: 1; + position: relative; + } + .icon-delete { + opacity: 0; + position: absolute; + right: .5rem; + top: 0; + transition: all .2s ease-in; + &:hover { + color: $red; + transition: color .3s ease-in; + } + } +} diff --git a/app/styles/components/watchers.scss b/app/styles/components/watchers.scss deleted file mode 100644 index 5c456568..00000000 --- a/app/styles/components/watchers.scss +++ /dev/null @@ -1,66 +0,0 @@ -.watchers { - margin-top: 1rem; - .watchers-header { - border-bottom: 2px solid $gray-light; - padding: .5rem; - position: relative; - .title { - @extend %large; - @extend %title; - text-transform: uppercase; - } - .icon { - @extend %large; - position: absolute; - right: 1rem; - } - &.no-watchers { - border-bottom: 0; - } - } - .watcher-single { - align-content: center; - align-items: center; - background: transparent; - border-bottom: 1px solid $gray-light; - display: flex; - justify-content: center; - padding: .5rem 0 .3rem; - vertical-align: middle; - &:last-child { - border: 0; - } - &:hover { - .icon-delete { - opacity: 1; - transition: opacity .2s ease-in; - } - } - } - .watcher-avatar { - flex-basis: 3rem; - max-width: 3rem; - padding-left: .3rem; - img { - width: 100%; - } - } - .watcher-name { - @extend %small; - color: $grayer; - flex-grow: 8; - margin-left: 1rem; - position: relative; - } - .icon-delete { - opacity: 0; - position: absolute; - right: .5rem; - top: 0; - transition: all .2s ease-in; - &:hover { - color: $red; - transition: color .3s ease-in; - } - } -} diff --git a/app/styles/core/typography.scss b/app/styles/core/typography.scss index 9e50fb32..4738077e 100755 --- a/app/styles/core/typography.scss +++ b/app/styles/core/typography.scss @@ -1,14 +1,14 @@ // Typography - // Font face -@each $font-face in OpenSans-CondLight, OpenSans-Light, opensans-regular, opensans-semibold, taiga { +@each $font-face in OpenSans-CondLight, +OpenSans-Light, +opensans-regular, +opensans-semibold, +taiga { @font-face { font-family: '#{$font-face}'; - src: url('../fonts/#{$font-face}.eot?#iefix') format('embedded-opentype'), - url('../fonts/#{$font-face}.woff') format('woff'), - url('../fonts/#{$font-face}.ttf') format('truetype'), - url('../fonts/#{$font-face}.svg#{$font-face}') format('svg'); + src: url("../fonts/#{$font-face}.eot?#iefix") format('embedded-opentype'), url("../fonts/#{$font-face}.woff") format('woff'), url("../fonts/#{$font-face}.ttf") format('truetype'), url("../fonts/#{$font-face}.svg#{$font-face}") format('svg'); } } @@ -21,6 +21,7 @@ h6 { color: $blackish; font-weight: normal; line-height: 1.5; + a { font-weight: inherit; } @@ -32,6 +33,7 @@ h1 { line-height: 1.5; margin-bottom: 1rem; text-transform: uppercase; + span { @extend %xxlarge; margin-right: .5rem; @@ -39,22 +41,27 @@ h1 { text-overflow: ellipsis; vertical-align: bottom; white-space: nowrap; + &.green, &:last-child { flex-shrink: 0; } } + .project-name { display: inline-block; - max-width: 60%; + margin-bottom: 0; } + .project-name-short { display: inline-block; max-width: 40%; } + .green { color: $primary; } + .date { @include ellipsis(500px); color: $gray-light; @@ -71,12 +78,16 @@ h2 { p { line-height: 1.5; margin: 0 0 20px; + img { margin: 0; } } -em { font-style: italic; } +em { + font-style: italic; +} + strong { font-weight: bold; } @@ -93,14 +104,15 @@ hr { a, a:visited { text-decoration: none; + &:hover { transition: color .3s linear; } } // Taiga Icons - [data-icon]:before { + // scss-lint:disable ImportantRule content: attr(data-icon); font-family: 'taiga' !important; @@ -116,6 +128,7 @@ a:visited { [class^='icon-']:before, [class*=' icon-']:before { + // scss-lint:disable ImportantRule font-family: 'taiga' !important; -moz-osx-font-smoothing: grayscale; @@ -131,160 +144,203 @@ a:visited { .icon-bug:before { content: 'a'; } + .icon-copy:before { content: 'b'; } + .icon-minimize:before { content: 'c'; } + .icon-maximize:before { content: 'd'; } + .icon-comment:before { content: 'e'; } + .icon-plus:before { content: 'f'; } + .icon-attachments:before { content: 'g'; } + .icon-edit:before { content: 'h'; } + .icon-documents:before { content: 'i'; } + .icon-delete:before { content: 'j'; } + .icon-arrow-bottom:before { content: 'k'; } + .icon-arrow-left:before { content: 'l'; } + .icon-arrow-right:before { content: 'm'; } + .icon-arrow-up:before { content: 'n'; } + .icon-briefcase:before { content: 'o'; } + .icon-caret-down:before { content: 'p'; } + .icon-caret-up:before { content: 'q'; } + .icon-check-square:before { content: 'r'; } + .icon-notification-error:before { content: 's'; } + .icon-settings:before { content: 't'; } + .icon-document:before { content: 'u'; } + .icon-warning:before { content: 'v'; } + .icon-move:before { content: 'w'; } + .icon-drag-v:before { + content: 'x'; +} + +.icon-filter:before { content: 'y'; } -.icon-filter:before { + +.icon-help:before { content: 'z'; } -.icon-help:before { + +.icon-reload:before { + content: 'A'; +} + +.icon-writer:before { content: 'B'; } -.icon-reload:before { + +.icon-stats:before { content: 'C'; } -.icon-writer:before { + +.icon-floppy:before { content: 'D'; } -.icon-stats:before { + +.icon-warning-alt:before { content: 'E'; } -.icon-floppy:before { + +.icon-video:before { content: 'F'; } -.icon-warning-alt:before { + +.icon-bulk:before { + content: 'G'; +} + +.icon-vunfold:before { content: 'H'; } -.icon-video:before { + +.icon-tasks:before { content: 'I'; } -.icon-bulk:before { + +.icon-kanban:before { + content: 'J'; +} + +.icon-search:before { content: 'K'; } -.icon-vunfold:before { - content: 'M'; -} -.icon-tasks:before { - content: 'O'; -} -.icon-kanban:before { - content: 'P'; -} -.icon-search:before { - content: 'Q'; -} + .icon-wiki:before { content: 'L'; } + .icon-team:before { - content: 'T'; + content: 'M'; } + .icon-vfold:before { content: 'N'; } + .icon-issues:before { + content: 'O'; +} + +.icon-iocaine:before { + content: 'Q'; +} + +.icon-archive:before { + content: 'T'; +} + +.icon-capslock:before { content: 'U'; } -.icon-backlog:before, -.icon-scrum:before, { - content: 'R'; -} -.icon-iocaine:before { - content: 'S'; -} -.icon-closed-eye:before { + +.icon-upload:before { content: 'V'; } -.icon-open-eye:before { + +.icon-github:before { content: 'W'; } -.icon-archive:before { + +.icon-timeline:before { content: 'X'; } -.icon-capslock:before { + +.icon-backlog:before { + content: 'P'; +} + +.icon-project:before { + content: 'S'; +} + +.icon-heart:before { + content: 'R'; +} + +.icon-eye:before { content: 'Y'; } -.icon-upload:before { - content: 'Z'; -} -.icon-github:before { - content: 'A'; -} -.icon-timeline:before { - content: 'x'; -} -.icon-project:before { - content: 'G'; -} -.icon-star-fill:before { - content: 'J'; -} -.icon-star:before { - content: '0'; -} diff --git a/app/styles/dependencies/mixins.scss b/app/styles/dependencies/mixins.scss index cdde2e53..15005727 100644 --- a/app/styles/dependencies/mixins.scss +++ b/app/styles/dependencies/mixins.scss @@ -102,3 +102,34 @@ margin-left: calc(-#{$border-size}px + #{$border-width}px); } } + +// Mixin for track buttons +@mixin list-itemtype-track { + .list-itemtype-track { + @extend %small; + color: $gray-light; + display: flex; + flex-basis: 150px; + flex-shrink: 0; + justify-content: flex-end; + } + .list-itemtype-track-likers, + .list-itemtype-track-watchers { + display: inline-block; + width: 2.5rem; + &.active { + color: $primary; + path { + fill: currentcolor; + } + } + } + .icon { + svg { + max-width: 1rem; + } + path { + fill: currentcolor; + } + } +} diff --git a/app/styles/layout/us-detail.scss b/app/styles/layout/ticket-detail.scss similarity index 52% rename from app/styles/layout/us-detail.scss rename to app/styles/layout/ticket-detail.scss index f3ea42fe..3fa22c44 100644 --- a/app/styles/layout/us-detail.scss +++ b/app/styles/layout/ticket-detail.scss @@ -1,10 +1,17 @@ .us-story-main-data { margin-bottom: 2rem; + header { + align-content: center; + align-items: stretch; + display: flex; + justify-content: center; + margin-bottom: .5rem; + } .us-title { @extend %large; @extend %text; background: $whitish; - margin-bottom: .5rem; + flex: 1; padding: 1rem; position: relative; transition: all .2s linear; @@ -234,222 +241,3 @@ .comment-list { padding: 1rem; } - -.us-detail-status { - @extend %large; - color: $primary; - vertical-align: middle; -} - -.us-detail-progress-bar { - background: $grayer; - height: 26px; - margin-bottom: 1rem; - position: relative; - .current-progress { - background: $primary-light; - height: 26px; - left: 0; - position: absolute; - top: 0; - width: 60%; - } - .tasks-completed { - @extend %small; - color: $white; - left: 10px; - position: absolute; - top: 2px; - } -} - -.points-per-role { - display: flex; - flex-wrap: wrap; - position: relative; - > li { - background: rgba($gray-light, .1); - border-radius: 2px; - color: rgba($grayer, .3); - flex-basis: 80px; - flex-grow: 1; - flex-shrink: 0; - margin: .1rem; - max-width: 50%; - padding: .5rem 0 .1rem; - position: relative; - text-align: center; - transition: color .3s linear; - &.active { - background: rgba($primary-light, .9); - color: $whitish; - } - &:first-child { - background: rgba($grayer, .5); - color: $whitish; - } - &:last-child { - border: 0; - } - } - .points { - @extend %xlarge; - @extend %title; - display: block; - margin-bottom: .3rem; - text-align: center; - } - .role { - @extend %small; - @include ellipsis(90%); - display: inline-block; - text-align: center; - } - .popover { - @include popover(200px, $top: 105%, $left: 35%, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 10px, $arrow-height: 10px); - li { - display: inline-block; - width: 23%; - } - a { - display: block; - text-align: center; - &:hover, - &.active { - background: $primary-light; - color: $white; - } - } - &.fix { - @include popover(200px, $top: 105%, $left: -160px, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 90%, $arrow-height: 10px); - } - } - -} - -.duty-data-container { - @extend %small; - margin-bottom: 1rem; - .duty-data { - margin-bottom: .5rem; - &:last-child { - margin: 0; - } - div { - background: darken($whitish, 5%); - padding: .5rem; - padding-right: 1rem; - transition: background .2s ease-in; - } - .clickable { - &:hover { - background: darken($whitish, 10%); - transition: background .2s ease-in; - } - } - } - .level { - display: inline-block; - margin-right: .5rem; - vertical-align: top; - } - .level-name { - color: darken($whitish, 20%); - float: right; - text-transform: lowercase; - } -} - -.us-detail-settings { - margin-top: 2rem; - .button { - color: $white; - display: block; - margin-bottom: .5rem; - text-align: center; - width: 100%; - } - .button-gray { - background: $gray-light; - &:hover { - background: $gray-light; - } - &.editable { - &:hover { - background: $grayer; - cursor: pointer; - } - } - &.active { - background: $primary; - } - } - .item-block { - &.editable { - &:hover { - background: $red; - cursor: pointer; - } - } - } - .button-red { - &:hover, - &.active { - background: $red; - } - } - label { - &.editable { - cursor: pointer; - } - +input { - display: none; - } - } - span { - &.button-gray, - &.button-gray:hover { - background: $gray-light; - &.active { - background: $gray; - } - } - &.button-red, - &.button-red:hover { - background: $red-light; - &.active { - background: $red; - } - } - } - .loading-spinner { - @extend %loading-spinner; - } -} - -.us-status { - .type-data { - position: relative; - .pop-type { - @include popover(150px, '', 30px, '', ''); - } - } - .severity-data { - position: relative; - .pop-severity { - @include popover(150px, '', 30px, '', ''); - } - } - .priority-data { - position: relative; - .pop-priority { - @include popover(150px, '', 30px, '', ''); - } - } - .status-data { - position: relative; - .pop-status { - @include popover(150px, '', 30px, '', ''); - } - } -} diff --git a/app/styles/modules/backlog/backlog-table.scss b/app/styles/modules/backlog/backlog-table.scss index c128124e..a667513e 100644 --- a/app/styles/modules/backlog/backlog-table.scss +++ b/app/styles/modules/backlog/backlog-table.scss @@ -10,6 +10,7 @@ } .row { @extend %small; + align-items: center; border-bottom: 1px solid $gray-light; display: flex; padding: .5rem 0 .5rem .5rem; @@ -22,6 +23,24 @@ &:hover { background: transparent; } + .input { + flex-basis: 25px; + flex-grow: 0; + flex-shrink: 0; + } + .votes { + color: $gray; + flex-basis: 50px; + flex-grow: 0; + flex-shrink: 0; + text-align: center; + &.inactive { + color: $gray-light; + } + &.is-voted { + color: $primary-light; + } + } .user-stories { overflow: hidden; width: 100%; @@ -99,8 +118,8 @@ .backlog-table-header { .backlog-table-title { + @extend %text; @extend %medium; - @extend %bold; border-bottom: 2px solid $gray-light; flex-wrap: nowrap; padding-right: 30px; @@ -124,6 +143,7 @@ &:hover { background: lighten($primary, 60%); transition: background .2s ease-in; + transition-delay: .2s; .us-settings, .icon-drag-v { opacity: 1; @@ -150,26 +170,25 @@ height: 40px; width: 100%; } - .row-selected { + .row-selected, + .is-checked { background: lighten($primary, 60%); transition: background .2s ease-in; } + input { + &:checked { + color: $primary-light; + transition: color .2s ease-in; + } + } .user-story-name { align-items: center; display: flex; flex-wrap: nowrap; - input { - flex-shrink: 0; - margin-right: 1rem; - vertical-align: super; - &:checked+a { - color: $primary-light; - transition: color .2s ease-in; - } - } a { + @extend %light; display: inline-block; - flex-grow: 20; + flex: 1; max-width: 90%; overflow: hidden; text-overflow: ellipsis; diff --git a/app/styles/modules/common/assigned-to.scss b/app/styles/modules/common/assigned-to.scss index cfb80a23..207ae322 100644 --- a/app/styles/modules/common/assigned-to.scss +++ b/app/styles/modules/common/assigned-to.scss @@ -1,6 +1,7 @@ -.duty-assigned-to { +.ticket-assigned-to { + align-items: center; display: flex; - margin-top: 1rem; + margin-bottom: 1rem; position: relative; &:hover { .assigned-to { @@ -17,18 +18,19 @@ max-width: 2rem; } .user-avatar { - flex-grow: 1; + flex-basis: 4rem; + flex-shrink: 0; img { - border-radius: 8%; width: 100%; } } .assigned-to { - flex-grow: 3; - margin-left: 1rem; + flex-grow: 1; + margin-left: .5rem; .assigned-title { @extend %small; - color: $gray-light; + @extend %light; + color: $gray; display: block; } .user-assigned { @@ -40,7 +42,7 @@ cursor: pointer; } .icon { - vertical-align: top; + vertical-align: middle; } } .assigned-name { diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index a3eef28d..88a3fcb9 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -1,5 +1,9 @@ .lightbox { @extend %lightbox; + h2 { + @extend %larger; + @extend %text; + } } .lightbox-generic-form { @@ -17,9 +21,12 @@ margin-bottom: 1rem; max-height: 9rem; min-height: 7rem; + resize: vertical; } label { + @extend %xsmall; + background: $whitish; border: 1px solid $gray-light; color: $grayer; cursor: pointer; @@ -38,43 +45,33 @@ } .settings { - align-content: flex-start; - align-items: stretch; display: flex; - justify-content: flex-start; + justify-content: center; margin-bottom: 1rem; - fieldset { - flex-basis: 30%; - flex-grow: 1; margin-right: .5rem; - text-align: center; + &:hover { + color: $white; + transition: all .2s ease-in; + } &:last-child { margin: 0; } } - .requirement, .iocaine { &:hover { background: $primary-light; border: 1px solid $primary; - color: $white; - transition: all .2s ease-in; } } .blocked { - padding: 8px 30px; &:hover { background: $red-light; border: 1px solid $red; - color: $white; - transition: all .2s ease-in; } } - - .client-requirement, .team-requirement, .iocaine-flag { @@ -87,13 +84,16 @@ } .blocking-flag { + label { + align-self: stretch; + display: block; + } input:checked+label { background: $red; border: 1px solid $red; color: $white; } } - input { display: none; } @@ -464,30 +464,12 @@ flex-grow: 0; width: 600px; } - .watchers { - margin-top: 1rem; - min-height: 440px; - - .watcher-name { - flex-grow: 12; - } - } - .watcher-single { - position: relative; - &:hover, - &.active { - background: lighten($primary, 55%); - cursor: pointer; - } + .user-list-single { &:hover { + background: lighten($primary, 58%); + cursor: pointer; transition: background .3s linear; - } - &.active { - .icon { - opacity: 1; - right: 1rem; - top: 1.3rem; - } + transition-delay: .2s; } } .more-watchers { @@ -499,10 +481,12 @@ } .lb-create-edit-userstory { + .ticket-role-points { + flex-basis: 10%; + flex-grow: 1; + flex-shrink: 1; + } .points-per-role { margin-bottom: 1rem; - li { - margin: .5rem .1rem; - } } } diff --git a/app/styles/modules/common/ticket-data.scss b/app/styles/modules/common/ticket-data.scss new file mode 100644 index 00000000..245ca8e1 --- /dev/null +++ b/app/styles/modules/common/ticket-data.scss @@ -0,0 +1,199 @@ +.ticket-data { + .ticket-title { + @extend %larger; + @extend %light; + margin: 1.5rem 0 2rem; + text-transform: uppercase; + span { + margin-right: .25rem; + &:last-child { + @extend %large; + } + } + } + .ticket-data-container { + @extend %small; + @extend %normal; + margin-bottom: 1rem; + .icon { + margin-left: .25rem; + } + } + .level { + display: inline-block; + margin-right: .5rem; + vertical-align: top; + } + .level-name { + color: darken($whitish, 20%); + float: right; + text-transform: lowercase; + } + + .ticket-estimation { + .ticket-role-points { + &:first-child { + flex-basis: 100%; + max-width: 100%; + } + } + } +} + +.ticket-status { + margin-bottom: .5rem; + &:last-child { + margin: 0; + } + div { + background: darken($whitish, 5%); + padding: .5rem; + padding-right: 1rem; + transition: background .2s ease-in; + } + .clickable { + &:hover { + background: darken($whitish, 10%); + transition: background .2s ease-in; + } + } + .type-data { + position: relative; + .pop-type { + @include popover(150px, '', 30px, '', ''); + } + } + .severity-data { + position: relative; + .pop-severity { + @include popover(150px, '', 30px, '', ''); + } + } + .priority-data { + position: relative; + .pop-priority { + @include popover(150px, '', 30px, '', ''); + } + } + .status-data { + position: relative; + .pop-status { + @include popover(150px, '', 30px, '', ''); + } + } +} + +.ticket-track-buttons { + .track-inner { + @extend %light; + @extend %small; + background: darken($whitish, 5%); + padding: .25rem; + text-transform: uppercase; + transition: background .25s; + &:hover { + background: darken($whitish, 10%); + } + } + .track-button { + width: 100%; + } + .active { + .track-button-counter { + background: rgba($grayer, .5); + } + &:hover { + .track-inner { + background: rgba($primary-light, .2); + } + } + &.is-hover { + .track-inner { + background: $red; + color: $whitish; + transition: background .3s; + } + path { + fill: $red-light; + } + } + } + .track-button-counter { + @extend %large; + background: rgba($grayer, .25); + color: $whitish; + padding: 0 .5rem; + } + .vote-button { + margin-bottom: .3rem; + } + .watch-button { + border-bottom: 0; + } + .ticket-watchers { + margin: .5rem 0; + } + .add-watcher { + display: block; + margin: .5rem; + .icon { + background: rgba($grayer, .25); + color: $whitish; + margin-right: .5rem; + padding: .25rem; + } + &:hover { + .icon { + background: $primary-light; + color: $whitish; + transition: background .3s linear; + } + } + } +} + +.ticket-detail-settings { + margin-top: 2rem; + label, + .button { + display: block; + margin-bottom: .5rem; + text-align: center; + &.editable { + cursor: pointer; + } + +input { + display: none; + } + } + .loading-spinner { + @extend %loading-spinner; + } + .button-gray { + background: $gray-light; + &:hover { + background: $gray-light; + } + &.editable { + &:hover { + background: $grayer; + cursor: pointer; + } + } + &.active { + background: $primary; + } + } + .item-block { + &.editable { + &:hover { + background: $red; + cursor: pointer; + } + } + } + .button-red { + display: block; + margin-top: 2rem; + } +} diff --git a/app/styles/modules/home-project.scss b/app/styles/modules/home-project.scss index 4956a40e..187d441c 100644 --- a/app/styles/modules/home-project.scss +++ b/app/styles/modules/home-project.scss @@ -2,15 +2,35 @@ .single-project-intro { margin-bottom: 2rem; } + .intro-options { + align-items: center; + display: flex; + justify-content: space-between; + } h1 { + color: $primary; + display: inline-block; line-height: 1.2; - margin: 0; + margin-bottom: 0; + margin-right: 3rem; vertical-align: middle; } .private { font-size: 1rem; vertical-align: super; } + .like-watch-container { + margin-left: auto; + } + .track-buttons-container { + display: flex; + } + .like-button { + margin-right: .75rem; + } + .track-container { + @include list-itemtype-track; + } .description { @extend %light; @extend %medium; diff --git a/app/styles/modules/issues/issues-table.scss b/app/styles/modules/issues/issues-table.scss index 9dc0ee51..3b4f8a26 100644 --- a/app/styles/modules/issues/issues-table.scss +++ b/app/styles/modules/issues/issues-table.scss @@ -34,6 +34,9 @@ div { cursor: pointer; } + .votes { + color: $gray; + } } .table-main { @extend %small; @@ -58,6 +61,19 @@ text-align: center; width: 75px; } + .votes { + color: $gray; + flex-basis: 75px; + flex-shrink: 0; + text-align: center; + width: 75px; + &.inactive { + color: $gray-light; + } + &.is-voted { + color: $primary-light; + } + } .subject { overflow: hidden; padding-right: 1rem; diff --git a/app/styles/shame/shame.scss b/app/styles/shame/shame.scss index 43772411..9342e459 100644 --- a/app/styles/shame/shame.scss +++ b/app/styles/shame/shame.scss @@ -1,8 +1,8 @@ -// Shame SCSS decalrations to be refactorized +// Shame SCSS declarations to be refactorized _:-ms-fullscreen, :root .taskboard-table-body { .task-row { min-height: auto; } -} \ No newline at end of file +} diff --git a/app/svg/check.svg b/app/svg/check.svg new file mode 100644 index 00000000..d97a17c3 --- /dev/null +++ b/app/svg/check.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/svg/like.svg b/app/svg/like.svg new file mode 100644 index 00000000..dd7c202d --- /dev/null +++ b/app/svg/like.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/svg/logo-nav.svg b/app/svg/logo-nav.svg index f18d9ef6..ff0d29ec 100644 --- a/app/svg/logo-nav.svg +++ b/app/svg/logo-nav.svg @@ -1,18 +1,18 @@ - + \ No newline at end of file + diff --git a/app/svg/unwatch.svg b/app/svg/unwatch.svg new file mode 100644 index 00000000..9a305958 --- /dev/null +++ b/app/svg/unwatch.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/svg/upvote.svg b/app/svg/upvote.svg new file mode 100644 index 00000000..187d6159 --- /dev/null +++ b/app/svg/upvote.svg @@ -0,0 +1,14 @@ + + + + diff --git a/app/svg/watch.svg b/app/svg/watch.svg new file mode 100644 index 00000000..cfce30c5 --- /dev/null +++ b/app/svg/watch.svg @@ -0,0 +1,4 @@ + + + +