diff --git a/app/coffee/modules/projects/lightboxes.coffee b/app/coffee/modules/projects/lightboxes.coffee index 8039d3a4..f8b3d5b2 100644 --- a/app/coffee/modules/projects/lightboxes.coffee +++ b/app/coffee/modules/projects/lightboxes.coffee @@ -21,6 +21,7 @@ taiga = @.taiga bindOnce = @.taiga.bindOnce +timeout = @.taiga.timeout module = angular.module("taigaProject") @@ -28,6 +29,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project link = ($scope, $el, attrs) -> $scope.data = {} $scope.templates = [] + form = $el.find("form").checksley({"onlyOneErrorElement": true}) onSuccessSubmit = (response) -> @@ -37,8 +39,14 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project $rootscope.$broadcast("projects:reload") onErrorSubmit = (response) -> - $confirm.notify("light-error", "According to our Oompa Loompas, project name is - already in use.") #TODO: i18n + form.setErrors(response) + selectors = [] + for error_field in _.keys(response) + selectors.push("[name=#{error_field}]") + $el.find(".active").removeClass("active") + error_step = $el.find(selectors.join(",")).first().parents(".wizard-step") + error_step.addClass("active") + $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(error_step.data("step")) submit = -> if not form.validate() @@ -48,19 +56,64 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project promise.then(onSuccessSubmit, onErrorSubmit) $scope.$on "projects:create", -> - $scope.data = {} + $scope.$apply -> + $scope.data = { + total_story_points: 100 + total_milestones: 5 + } if !$scope.templates.length - $rs.projects.templates() - .then (result) => - $scope.templates = _.map(result, (item) -> {"id": item.id, "name": item.name}) + $rs.projects.templates().then (result) => + $scope.templates = result + $scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id + else + $scope.$apply -> + $scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id + + $el.find(".active").removeClass("active") + $el.find(".create-step1").addClass("active") lightboxService.open($el) + timeout 600, -> + $el.find(".progress-bar").addClass('step1') - $el.on "click", "a.button-green", (event) -> + $el.on "click", ".button-next", (event) -> + event.preventDefault() + + current = $el.find(".active") + + valid = true + for field in form.fields + if current.find("[name=#{field.element.attr('name')}]").length + valid = field.validate() != false and valid + + if not valid + return + + next = current.next() + current.toggleClass('active') + next.toggleClass('active') + step = next.data('step') + $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step) + + $el.on "click", ".button-prev", (event) -> + event.preventDefault() + current = $el.find(".active") + prev = current.prev() + current.toggleClass('active') + prev.toggleClass('active') + step = prev.data('step') + $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step) + + + $el.on "click", ".button-submit", (event) -> event.preventDefault() submit() + $el.on "click", ".close", (event) -> + event.preventDefault() + lightboxService.close($el) + return {link:link} module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", "$location", "$tgNavUrls", diff --git a/app/partials/views/modules/lightbox_create-project.jade b/app/partials/views/modules/lightbox_create-project.jade deleted file mode 100644 index 4209cb00..00000000 --- a/app/partials/views/modules/lightbox_create-project.jade +++ /dev/null @@ -1,27 +0,0 @@ -a.close(href="", title="close") - span.icon.icon-delete -form - h2.title Create Project - form - fieldset - input(type="text", name="name", ng-model="data.name", data-required="true", - placeholder="Name", maxlength="45") - fieldset - textarea(name="description", ng-model="data.description", data-required="true", - placeholder="Description") - fieldset - input(type="number", name="total_story_points", min="0", ng-model="data.total_story_points", - data-type="digits", data-required="true", placeholder="Total story points") - - fieldset - input(type="number", name="total_milestones", min="0", ng-model="data.total_milestones", - data-type="digits", placeholder="Total milestones") - - fieldset - select(name="creation_template", ng-model="data.creation_template", - ng-options="template.id as template.name for template in templates") - option(value="") Select one template to generate the defaults values for the new project - - fieldset - a.button.button-green(href="", title="Create") Create - input(type="submit", class="hidden") diff --git a/app/partials/views/modules/projects-nav.jade b/app/partials/views/modules/projects-nav.jade index 586e48cb..5013a176 100644 --- a/app/partials/views/modules/projects-nav.jade +++ b/app/partials/views/modules/projects-nav.jade @@ -3,7 +3,7 @@ include ../components/spinner p Loading project... -div.lightbox.lightbox_create-project.hidden(tg-lb-create-project) - include lightbox_create-project +div.wizard-create-project.hidden(tg-lb-create-project) + include wizard-create-project nav.projects-nav(ng-controller="ProjectsNavigationController", tg-projects-nav, tg-projects-pagination, projects="projects") diff --git a/app/partials/views/modules/wizard-create-project.jade b/app/partials/views/modules/wizard-create-project.jade new file mode 100644 index 00000000..2de41207 --- /dev/null +++ b/app/partials/views/modules/wizard-create-project.jade @@ -0,0 +1,54 @@ +form + section.wizard-step.create-step1.active(data-step="step1") + div.title + h1 Create Project + p Fresh and clean. So exciting! + fieldset + input(type="text", name="name", ng-model="data.name", data-required="true", placeholder="Name", maxlength="45") + fieldset + textarea(name="description", ng-model="data.description", data-required="true", placeholder="Description") + fieldset + a.button-next.button.button-green(href="", title="Next") Next + section.wizard-step.create-step2(data-step="step2") + div.title + h1 Choose a template + p Which template would fit better in your project? + div.template-wrapper + div.template-inner + fieldset(ng-repeat="template in templates") + input(type="radio", name="template", id="template-{{ template.id }}", + ng-value='template.id', ng-model="data.creation_template", + data-required="true") + label.backlog(for="template-{{ template.id }}") + span.icon.icon-backlog + h2 {{ template.name }} + p {{ template.description }} + + fieldset.wizard-action + div + a.button-prev.button.button-gray(href="", title="Prev") Prev + a.button-submit.button.button-green(href="", title="Create") Create + + // section.wizard-step.create-step3(data-step="step3") + // div.title + // h1 Final Touch + // p Give a final touch and make this project totally yours + // fieldset + // input(type="number", name="total_story_points", min="0", ng-model="data.total_story_points", data-type="digits", data-required="true", placeholder="Total story points") + // fieldset + // input(type="number", name="total_milestones", min="0", ng-model="data.total_milestones", data-type="digits", placeholder="Total milestones") + // fieldset.wizard-action + // div + // a.button-prev.button.button-gray(href="", title="Prev") Prev + // a.button-submit.button.button-green(href="", title="Create") Create + +div.progress-bar + div.progress-state + span Name and description + span Template selection + // span Final touches + div.progress-bar-wrapper + div.bar + +a.close(href="" title="close") + span.icon.icon-delete diff --git a/app/styles/dependencies/animation.scss b/app/styles/dependencies/animation.scss index f2befd29..3a787900 100644 --- a/app/styles/dependencies/animation.scss +++ b/app/styles/dependencies/animation.scss @@ -45,3 +45,18 @@ opacity: 1; } } + +@include keyframes(formSlide) { + 0% { + @include filter(blur(5px)); + @include transform(translateY(10rem)); + opacity: 0; + } + 50% { + @include filter(blur(0)); + } + 100% { + @include transform(translateY(0)); + opacity: 1; + } +} diff --git a/app/styles/main.scss b/app/styles/main.scss index f117b6f8..999f5739 100755 --- a/app/styles/main.scss +++ b/app/styles/main.scss @@ -62,6 +62,7 @@ $prefix-for-spec: true; @import 'modules/common/attachments'; @import 'modules/common/related-tasks'; @import 'modules/common/history'; +@import 'modules/common/wizard'; //Project modules @import 'modules/home-projects-list'; diff --git a/app/styles/modules/common/assigned-to.scss b/app/styles/modules/common/assigned-to.scss index 63f8e8f2..4b7be68b 100644 --- a/app/styles/modules/common/assigned-to.scss +++ b/app/styles/modules/common/assigned-to.scss @@ -1,6 +1,6 @@ .us-assigned-to { @include table-flex(); - margin-top: 2rem; + margin-top: 1rem; position: relative; .user-avatar { @include table-flex-child(1, 0); @@ -30,8 +30,8 @@ color: $gray-light; opacity: 1; position: absolute; - right: 1rem; - top: 1rem; + right: 0; + top: 0; &:hover { color: $red; } diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index a4c2f665..9a712975 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -1,4 +1,5 @@ -.lightbox { +.lightbox, +%lightbox { @include background-opacity($white, .95); @include table-flex(center, center, flex, row, wrap, center); @include transition (opacity .3s ease); @@ -27,7 +28,8 @@ textarea { resize: vertical; } - .button-green { + .button-green, + .button-gray { display: block; padding: 12px; text-align: center; @@ -496,12 +498,6 @@ } } -.lightbox_create-project { - form { - width: 600px; - } -} - .lb-create-edit-userstory { .points-per-role { margin-bottom: 1rem; diff --git a/app/styles/modules/common/wizard.scss b/app/styles/modules/common/wizard.scss new file mode 100644 index 00000000..e7cbc7ea --- /dev/null +++ b/app/styles/modules/common/wizard.scss @@ -0,0 +1,204 @@ +.wizard-create-project { + @extend %lightbox; + background: url('/images/invitation_bg.jpg') no-repeat center center; + background-size: cover; + color: $white; + text-align: center; + form { + width: 500px; + } + .title { + width: 100%; + } + h1, + p { + color: $white; + } + h1 { + line-height: 1.5rem; + } + p { + @extend %small; + opacity: .8; + } + input, + textarea, + select { + background: rgba($white, .7); + @include placeholder { + color: $grayer; + } + } + .close { + color: $white; + &:hover { + color: $red-light; + } + } + .wizard-step { + display: none; + @include animation(formSlide .4s ease-in-out); + @include animation-direction(alternate-reverse); + &.active { + @include animation(formSlide .4s ease-in-out); + &.create-step1, + &.create-step3 { + @include table-flex(); + } + &.create-step2 { + display: block; + } + } + } + .wizard-action { + div { + @include table-flex(); + } + a { + @include table-flex-child(1, 40%, 0); + color: $white; + display: inline-block; + &:first-child { + margin-right: .5rem; + } + } + } + .create-step2 { + .template-inner { + @include table-flex(); + fieldset { + @include table-flex-child(1, 0, 0); + &:first-child { + margin-right: .5rem; + } + } + } + input[type="radio"] { + display: none; + &:checked { + +label { + @include transition(background .3s ease-in); + background: rgba($fresh-taiga, .7); + } + } + +label { + @include transition(background .3s ease-in); + background: rgba($whitish, .7); + cursor: pointer; + display: block; + margin-bottom: 1rem; + padding: 1rem; + text-align: center; + &:hover { + @include transition(background .3s ease-in); + background: rgba($green-taiga, .7); + } + .icon { + @extend %xxlarge; + color: $white; + } + } + } + h2 { + color: $white; + margin: 0; + margin-top: .5rem; + text-transform: uppercase; + } + p { + text-align: center; + } + } + .progress-bar { + bottom: 0; + height: .5rem; + left: 0; + position: absolute; + width: 100%; + &.step1 { + .bar { + @include transition(width .6s ease-in-out); + width: 25%; + } + .progress-state { + span { + &:nth-child(1) { + @include transition(color .3s ease-in-out); + @include transition-delay(.6s); + color: rgba($white, 1); + } + } + } + } + &.step2 { + .bar { + @include transition(width .6s ease-in-out); + // width: 50%; + width: 75%; + } + .progress-state { + span { + &:nth-child(1), + &:nth-child(2) { + @include transition(color .3s ease-in-out); + @include transition-delay(.6s); + color: rgba($white, 1); + } + } + } + } + // &.step3 { + // .bar { + // @include transition(width .6s ease-in-out); + // width: 75%; + // } + // .progress-state { + // span { + // &:nth-child(1), + // &:nth-child(2), + // &:nth-child(3) { + // @include transition(color .3s ease-in-out); + // @include transition-delay(.6s); + // color: rgba($white, 1); + // } + // } + // } + // } + } + .progress-state { + position: absolute; + width: 100%; + span { + @include transition(all 1s ease-in); + color: rgba($white, .5); + display: inline-block; + margin-left: -100px; + position: absolute; + text-align: center; + top: -2rem; + width: 200px; + &:nth-child(1) { + left: 25%; + } + &:nth-child(2) { + // left: 50%; + left: 75%; + } + // &:nth-child(3) { + // left: 75%; + // } + } + } + .progress-bar-wrapper { + background: rgba($white, .3); + height: .5rem; + } + .bar { + background: rgba($fresh-taiga, .9); + height: .5rem; + left: 0; + position: absolute; + top: 0; + width: 0; + } +}