diff --git a/test/api/unit/models/group_tasks.test.js b/test/api/unit/models/group_tasks.test.js index 848b4b0792..1c60fa947b 100644 --- a/test/api/unit/models/group_tasks.test.js +++ b/test/api/unit/models/group_tasks.test.js @@ -235,15 +235,16 @@ describe('Group Task Methods', () => { }); }); - it('removes an assigned task and unlinks assignees', async () => { + it('removes assigned tasks when master task is deleted', async () => { await guild.syncTask(task, leader); await guild.removeTask(task); const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); + const updatedLeadersTasks = await Tasks.Task.find({ userId: leader._id, type: taskType }); const syncedTask = find(updatedLeadersTasks, findLinkedTask); - expect(syncedTask.group.broken).to.equal('TASK_DELETED'); + expect(updatedLeader.tasksOrder[`${taskType}s`]).to.not.include(task._id); + expect(syncedTask).to.not.exist; }); it('unlinks and deletes group tasks for a user when remove-all is specified', async () => { diff --git a/test/api/v3/integration/groups/POST-group_remove_manager.test.js b/test/api/v3/integration/groups/POST-group_remove_manager.test.js index e8cae4ab29..6c5d4cee9f 100644 --- a/test/api/v3/integration/groups/POST-group_remove_manager.test.js +++ b/test/api/v3/integration/groups/POST-group_remove_manager.test.js @@ -75,12 +75,7 @@ describe('POST /group/:groupId/remove-manager', () => { await nonLeader.post(`/tasks/${task._id}/assign/${nonManager._id}`); const memberTasks = await nonManager.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(nonManager.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await nonManager.post(`/tasks/${syncedTask._id}/score/up`); const updatedGroup = await leader.post(`/groups/${groupToUpdate._id}/remove-manager`, { managerId: nonLeader._id, diff --git a/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js b/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js index 59dba9f5ed..73828accdc 100644 --- a/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js +++ b/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js @@ -73,12 +73,7 @@ describe('Groups DELETE /tasks/:id', () => { }); const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.sync(); await member2.sync(); @@ -96,16 +91,16 @@ describe('Groups DELETE /tasks/:id', () => { expect(member2.notifications.length).to.equal(1); }); - it('unlinks assigned user', async () => { + it('deletes task from assigned user', async () => { await user.del(`/tasks/${task._id}`); const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - expect(syncedTask.group.broken).to.equal('TASK_DELETED'); + expect(syncedTask).to.not.exist; }); - it('unlinks all assigned users', async () => { + it('deletes task from all assigned users', async () => { await user.del(`/tasks/${task._id}`); const memberTasks = await member.get('/tasks/user'); @@ -114,8 +109,8 @@ describe('Groups DELETE /tasks/:id', () => { const member2Tasks = await member2.get('/tasks/user'); const member2SyncedTask = find(member2Tasks, findAssignedTask); - expect(syncedTask.group.broken).to.equal('TASK_DELETED'); - expect(member2SyncedTask.group.broken).to.equal('TASK_DELETED'); + expect(syncedTask).to.not.exist; + expect(member2SyncedTask).to.not.exist; }); it('prevents a user from deleting a task they are assigned to', async () => { @@ -130,22 +125,6 @@ describe('Groups DELETE /tasks/:id', () => { }); }); - it('allows a user to delete a broken task', async () => { - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await user.del(`/tasks/${task._id}`); - - await member.del(`/tasks/${syncedTask._id}`); - - await expect(member.get(`/tasks/${syncedTask._id}`)) - .to.eventually.be.rejected.and.eql({ - code: 404, - error: 'NotFound', - message: 'Task not found.', - }); - }); - it('allows a user to delete a task after leaving a group', async () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js index 599086e463..1d23e5f85c 100644 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js +++ b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js @@ -58,22 +58,14 @@ describe('POST /tasks/:id/approve/:userId', () => { let memberTasks = await member.get('/tasks/user'); let syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${task._id}/approve/${member._id}`); await member.sync(); - expect(member.notifications.length).to.equal(3); + expect(member.notifications.length).to.equal(2); expect(member.notifications[1].type).to.equal('GROUP_TASK_APPROVED'); expect(member.notifications[1].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); - expect(member.notifications[2].type).to.equal('SCORED_TASK'); - expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); memberTasks = await member.get('/tasks/user'); syncedTask = find(memberTasks, findAssignedTask); @@ -93,21 +85,13 @@ describe('POST /tasks/:id/approve/:userId', () => { let memberTasks = await member.get('/tasks/user'); let syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await member2.post(`/tasks/${task._id}/approve/${member._id}`); await member.sync(); - expect(member.notifications.length).to.equal(3); + expect(member.notifications.length).to.equal(2); expect(member.notifications[1].type).to.equal('GROUP_TASK_APPROVED'); expect(member.notifications[1].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); - expect(member.notifications[2].type).to.equal('SCORED_TASK'); - expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); memberTasks = await member.get('/tasks/user'); syncedTask = find(memberTasks, findAssignedTask); @@ -125,12 +109,7 @@ describe('POST /tasks/:id/approve/:userId', () => { await member2.post(`/tasks/${task._id}/assign/${member._id}`); const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.sync(); await member2.sync(); @@ -157,14 +136,9 @@ describe('POST /tasks/:id/approve/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await member2.post(`/tasks/${task._id}/approve/${member._id}`); + await expect(user.post(`/tasks/${task._id}/approve/${member._id}`)) .to.eventually.be.rejected.and.to.eql({ code: 401, @@ -197,13 +171,7 @@ describe('POST /tasks/:id/approve/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); const groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`); @@ -226,13 +194,7 @@ describe('POST /tasks/:id/approve/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); const member2Tasks = await member2.get('/tasks/user'); @@ -258,13 +220,7 @@ describe('POST /tasks/:id/approve/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); const groupTasks = await user.get(`/tasks/group/${guild._id}`); @@ -287,21 +243,10 @@ describe('POST /tasks/:id/approve/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); const member2Tasks = await member2.get('/tasks/user'); const member2SyncedTask = find(member2Tasks, findAssignedTask); - await expect(member2.post(`/tasks/${member2SyncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member2.post(`/tasks/${member2SyncedTask._id}/score/up`); await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member2._id}`); diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js index 91026baeae..8472bc03aa 100644 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js +++ b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js @@ -61,13 +61,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => { let syncedTask = find(memberTasks, findAssignedTask); // score task to require approval - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${task._id}/needs-work/${member._id}`); [memberTasks] = await Promise.all([member.get('/tasks/user'), member.sync()]); @@ -114,12 +108,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => { let syncedTask = find(memberTasks, findAssignedTask); // score task to require approval - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/up`); const initialNotifications = member.notifications.length; @@ -172,13 +161,7 @@ describe('POST /tasks/:id/needs-work/:userId', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); - + await member.post(`/tasks/${syncedTask._id}/score/up`); await member2.post(`/tasks/${task._id}/approve/${member._id}`); await expect(user.post(`/tasks/${task._id}/needs-work/${member._id}`)) .to.eventually.be.rejected.and.to.eql({ diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js index 80710c701b..810ad517d1 100644 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js +++ b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js @@ -44,12 +44,11 @@ describe('POST /tasks/:id/score/:direction', () => { const syncedTask = find(memberTasks, findAssignedTask); const direction = 'up'; - await expect(member.post(`/tasks/${syncedTask._id}/score/${direction}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + const response = await member.post(`/tasks/${syncedTask._id}/score/${direction}`); + + expect(response.data.approvalRequested).to.equal(true); + expect(response.message).to.equal(t('taskApprovalHasBeenRequested')); + const updatedTask = await member.get(`/tasks/${syncedTask._id}`); await user.sync(); @@ -76,12 +75,7 @@ describe('POST /tasks/:id/score/:direction', () => { const syncedTask = find(memberTasks, findAssignedTask); const direction = 'up'; - await expect(member.post(`/tasks/${syncedTask._id}/score/${direction}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/${direction}`); const updatedTask = await member.get(`/tasks/${syncedTask._id}`); await user.sync(); await member2.sync(); @@ -111,12 +105,7 @@ describe('POST /tasks/:id/score/:direction', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/up`); await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) .to.eventually.be.rejected.and.eql({ @@ -130,12 +119,7 @@ describe('POST /tasks/:id/score/:direction', () => { const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); - await expect(member.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + await member.post(`/tasks/${syncedTask._id}/score/up`); await user.post(`/tasks/${task._id}/approve/${member._id}`); diff --git a/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js b/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js index 45443d4f06..74c76475a2 100644 --- a/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js +++ b/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js @@ -71,12 +71,10 @@ describe('PUT /tasks/:id', () => { const syncedTask = find(memberTasks, memberTask => memberTask.group.taskId === habit._id); // score up to trigger approval - await expect(member2.post(`/tasks/${syncedTask._id}/score/up`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalHasBeenRequested'), - }); + const response = await member2.post(`/tasks/${syncedTask._id}/score/up`); + + expect(response.data.approvalRequested).to.equal(true); + expect(response.message).to.equal(t('taskApprovalHasBeenRequested')); }); it('member updates a group task value - not allowed', async () => { diff --git a/website/client/config/storybook/config.js b/website/client/config/storybook/config.js index 01bba95033..fb3957a25e 100644 --- a/website/client/config/storybook/config.js +++ b/website/client/config/storybook/config.js @@ -1,6 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ import { configure } from '@storybook/vue'; +import './margin.css'; import '../../src/assets/scss/index.scss'; +import '../../src/assets/scss/spacing.scss'; import '../../src/assets/css/sprites.css'; import '../../src/assets/css/sprites/spritesmith-main-0.css'; diff --git a/website/client/config/storybook/margin.css b/website/client/config/storybook/margin.css new file mode 100644 index 0000000000..eaad293c27 --- /dev/null +++ b/website/client/config/storybook/margin.css @@ -0,0 +1,13 @@ +.background { + background: teal; + display: inline-block; +} + +.content { + color: white; + background: grey; +} + +.inline-block { + display: inline-block; +} diff --git a/website/client/src/assets/scss/button.scss b/website/client/src/assets/scss/button.scss index 482e731700..a19e96acf4 100644 --- a/website/client/src/assets/scss/button.scss +++ b/website/client/src/assets/scss/button.scss @@ -52,9 +52,11 @@ border-color: $purple-400; } - &:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus { - box-shadow: none; - border-color: $purple-400; + &:not(:disabled):not(.disabled) { + &:active:focus, &.active:focus { + box-shadow: none; + border-color: $purple-400; + } } &:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active { diff --git a/website/client/src/assets/scss/dropdown.scss b/website/client/src/assets/scss/dropdown.scss index 0acbce7864..4a078edd25 100644 --- a/website/client/src/assets/scss/dropdown.scss +++ b/website/client/src/assets/scss/dropdown.scss @@ -1,20 +1,27 @@ .dropdown > .btn { - padding: 9px 15.5px; + padding: 0.25rem 0.75rem; font-family: 'Roboto', sans-serif; font-size: 14px; font-weight: normal; line-height: 1.43; } +.dropdown-toggle:hover { + --caret-color: #{$purple-200}; +} + .dropdown.show > .dropdown-toggle:not(.btn-success) { color: $purple-200; - border-color: $purple-500 !important; + border-color: $purple-400 !important; box-shadow: none; + + &::after { + --caret-color: #{$purple-200}; + } } .dropdown-toggle::after { - margin-left: 16px; - border-top: 6px solid; + border-top-color: var(--caret-color); border-right: 5px solid transparent; border-left: 5px solid transparent; vertical-align: 0; @@ -23,14 +30,18 @@ .dropdown-menu { padding: 0px; border: none; - border-radius: 4px; - box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($white, 0.1); + border-radius: 2px; + box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24); + } +// shared dropdown-item styles .dropdown-item { + // header items & not selectList-items padding-left: 24px; padding-top: 8px; padding-bottom: 8px; + font-size: 14px; line-height: 1.71; color: $gray-50; @@ -42,8 +53,8 @@ } - &:active, &:hover, &.active { - background-color: rgba(#d5c8ff, 0.32); + &:active, &:hover, &:focus, &.active { + background-color: rgba($purple-600, 0.32); color: $purple-200; } @@ -86,16 +97,28 @@ .dropdown-toggle { width: 100% !important; + height: 32px; text-align: left; } .dropdown-toggle::after { position: absolute; - right: 16px; - top: 17px; + right: 12px; + top: 14px; } .dropdown-menu.show { width: 100% !important; } } + +// selectList.vue items sizing +.selectListItem .dropdown-item { + padding: 0.25rem 0.75rem; + height: 32px; + + &:active, &:hover, &:focus, &.active { + background-color: rgba($purple-600, 0.25); + color: $purple-300; + } +} diff --git a/website/client/src/assets/scss/form.scss b/website/client/src/assets/scss/form.scss index edfb99245e..f4c2dc3ba1 100644 --- a/website/client/src/assets/scss/form.scss +++ b/website/client/src/assets/scss/form.scss @@ -16,10 +16,10 @@ label small { } } -// Inputs and texteares +// Inputs and textareas input, textarea, input.form-control, textarea.form-control { - padding: 10px 16px; + padding: 10px 12px; border-radius: 2px; font-size: 14px; line-height: 1.43; @@ -31,14 +31,14 @@ input, textarea, input.form-control, textarea.form-control { } &:active:not(:disabled), &:focus:not(:disabled) { - border-color: $purple-500; + border-color: $purple-400; outline: 0; box-shadow: none; } &:disabled { opacity: 0.64; - background: $gray-500; + background: $gray-700; } &.input-search { @@ -68,11 +68,48 @@ input, textarea, input.form-control, textarea.form-control { } } -.input-group { - .input-group-prepend , .input-group-append { +.input-group-outer { + display: flex; + flex-direction: row; + + .input-group { + flex: 1; + } +} + +/** Colored Input-Groups, ignoring checklist */ +.input-group:not(.checklist-group) { + border-radius: 2px; + border: solid 1px $gray-400; + + &:hover { + border-color: $gray-300; + } + + &:focus, &:active, &:focus-within { + border: solid 1px $purple-400; + } + + .input-group-prepend , .input-group-append { background: $gray-600; - color: $gray-300; - border-radius: 2px; + } +} + +/** Generic Input Group Styles */ +.input-group { + height: 2rem; + + .input-group-prepend , .input-group-append { + color: $gray-200; + border: 0; + height: 30px; + width: 2rem; + margin: 0; + + &.grow { + width: initial; + min-width: 2rem; + } &.input-group-text { font-size: 14px; @@ -83,28 +120,30 @@ input, textarea, input.form-control, textarea.form-control { } &.input-group-icon { - border: solid 1px $gray-400; - border-right: none; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; + display: flex; + align-self: center; + align-items: center; + justify-items: center; + justify-content: center; + } + + .svg-icon { + margin: 0 !important; } &.streak-addon .svg-icon { width: 11.6px; height: 7.1px; - margin: 15px 13.4px 15.9px 13px; } &.positive-addon .svg-icon { width: 10px; height: 10px; - margin: 14px 14px; } &.negative-addon .svg-icon { width: 10px; height: 2px; - margin: 18px 14px; } } @@ -115,6 +154,19 @@ input, textarea, input.form-control, textarea.form-control { input:first-child { border-right: none !important; } + + input { + height: 30px; + border: 0; + background: $white !important; + } +} + +.input-group-spaced { + margin-left: 12px; + height: 2rem; + border-radius: 2px; + background-color: $gray-600; } .form-check { @@ -200,9 +252,13 @@ $bg-disabled-control: #34303a; align-items: center; } - .destroy-icon { - width: 14px; - height: 16px; + .destroy-icon.svg-icon { + margin-top: 1px !important; + + svg { + width: 14px; + height: 16px; + } } } diff --git a/website/client/src/assets/scss/icon.scss b/website/client/src/assets/scss/icon.scss index 5e5a9162b9..3d570b9ac0 100644 --- a/website/client/src/assets/scss/icon.scss +++ b/website/client/src/assets/scss/icon.scss @@ -1,14 +1,14 @@ .svg-icon { display: block; - transition: none !important; fill: currentColor; svg { display: block; - } + transition: none; - * { - transition: none !important; + path { + transition: none; + } } &.color { @@ -64,4 +64,4 @@ &:hover svg path { stroke: $gray-100; } -} \ No newline at end of file +} diff --git a/website/client/src/assets/scss/index.scss b/website/client/src/assets/scss/index.scss index 6842a80947..63dfcbc85f 100644 --- a/website/client/src/assets/scss/index.scss +++ b/website/client/src/assets/scss/index.scss @@ -37,3 +37,4 @@ @import './tiers'; @import './payments'; @import './datepicker.scss'; +@import './spacing'; diff --git a/website/client/src/assets/scss/misc.scss b/website/client/src/assets/scss/misc.scss index 164a05f0e7..410ddcd13a 100644 --- a/website/client/src/assets/scss/misc.scss +++ b/website/client/src/assets/scss/misc.scss @@ -14,4 +14,16 @@ border-right: 4px solid transparent; border-left: 4px solid transparent; border-bottom: 0; -} \ No newline at end of file +} + +* { + transition: none; +} + +.transition { + transition-duration: 0.15s; + transition-property: border-color, color; + transition-property: border-color, box-shadow, color; + transition-property: border-color, box-shadow, color; + transition-timing-function: ease-in; +} diff --git a/website/client/src/assets/scss/modal.scss b/website/client/src/assets/scss/modal.scss index efaf47bb0c..ae4ce79d9d 100644 --- a/website/client/src/assets/scss/modal.scss +++ b/website/client/src/assets/scss/modal.scss @@ -13,6 +13,7 @@ .modal { z-index: 1350; + padding-left: 0px !important; } .modal-dialog { diff --git a/website/client/src/assets/scss/spacing.scss b/website/client/src/assets/scss/spacing.scss new file mode 100644 index 0000000000..325c36003b --- /dev/null +++ b/website/client/src/assets/scss/spacing.scss @@ -0,0 +1,59 @@ +.m-75 { + margin: 0.75rem; // 12px +} + +.mx-75 { + margin-left: 0.75rem; + margin-right: 0.75rem; +} + +.my-75 { + margin-bottom: 0.75rem; + margin-top: 0.75rem; +} + +.mb-75 { + margin-bottom: 0.75rem; +} + +.ml-75 { + margin-left: 0.75rem; +} + +.mr-75 { + margin-right: 0.75rem; +} + +.mt-75 { + margin-top: 0.75rem; +} + +.p-75 { + padding: 0.75rem; +} + +.px-75 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.py-75 { + padding-bottom: 0.75rem; + padding-top: 0.75rem; +} + +.pb-75 { + padding-bottom: 0.75rem; +} + +.pl-75 { + padding-left: 0.75rem; +} + +.pr-75 { + padding-right: 0.75rem; +} + +.pt-75 { + padding-top: 0.75rem; +} diff --git a/website/client/src/assets/scss/task.scss b/website/client/src/assets/scss/task.scss index d651a574e7..66f6f35bf7 100644 --- a/website/client/src/assets/scss/task.scss +++ b/website/client/src/assets/scss/task.scss @@ -3,7 +3,8 @@ .habit-option-button { border: 2px solid $disabled-color; } - &:hover { + // TODO refactor to use more css-vars and less duplicate generated css code + &:hover, &:focus, &:active { .habit-option-button { border: 2px solid $active-color; } @@ -28,7 +29,7 @@ &-control { &-bg { background: $maroon-100 !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $maroon-100 !important; } @@ -40,6 +41,7 @@ &-modal { &-bg { background: $maroon-100 !important; } + &-headings { color: $white; } &-icon { color: $maroon-100 !important; } &-text { color: $red-1 !important; } &-content { @@ -58,7 +60,7 @@ &-control { &-bg { background: $red-100 !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $red-100 !important; } @@ -70,8 +72,8 @@ &-modal { &-bg { background: $red-100 !important; } + &-headings, &-text { color: $red-1 !important; } &-icon { color: $red-100 !important; } - &-text { color: $red-1 !important; } &-content { --svg-color: #{$red-100}; } @@ -89,7 +91,7 @@ &-control { &-bg { background: $orange-100 !important; - .habit-control:hover { background: rgba($orange-1, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($orange-1, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $orange-100 !important; } @@ -101,8 +103,8 @@ &-modal { &-bg { background: $orange-100 !important; } + &-headings, &-text { color: $orange-1 !important; } &-icon { color: $orange-100 !important; } - &-text { color: $orange-1 !important; } &-content { --svg-color: #{$orange-100}; } @@ -120,7 +122,7 @@ &-control { &-bg { background: $yellow-100 !important; - .habit-control:hover { background: rgba($yellow-1, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($yellow-1, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $yellow-100 !important; } @@ -132,8 +134,8 @@ &-modal { &-bg { background: $yellow-100 !important; } + &-headings, &-text { color: $yellow-1 !important; } &-icon { color: $yellow-100 !important; } - &-text { color: $yellow-1 !important; } @include modal-text-input($yellow-1); &-option-disabled:hover { .svg-icon { color: $yellow-100 !important; } @@ -151,7 +153,7 @@ &-control { &-bg { background: $green-100 !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $green-100 !important; } @@ -163,8 +165,8 @@ &-modal { &-bg { background: $green-100 !important; } + &-headings, &-text { color: $green-1 !important; } &-icon { color: $green-10 !important; } - &-text { color: $green-1 !important; } &-content { --svg-color: #{$green-100}; } @@ -183,7 +185,7 @@ &-control { &-bg { background: $teal-100 !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $teal-100 !important; } @@ -195,8 +197,8 @@ &-modal { &-bg { background: $teal-100 !important; } + &-headings, &-text { color: $teal-1 !important; } &-icon { color: $teal-100 !important; } - &-text { color: $teal-1 !important; } &-content { --svg-color: #{$teal-100}; } @@ -214,7 +216,7 @@ &-control { &-bg { background: $blue-100 !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $blue-100 !important; } @@ -226,8 +228,8 @@ &-modal { &-bg { background: $blue-100 !important; } + &-headings, &-text { color: $blue-1 !important; } &-icon { color: $blue-100 !important; } - &-text { color: $blue-1 !important; } &-content { --svg-color: #{$blue-100}; } @@ -246,7 +248,7 @@ &-control { &-bg { background: $purple-task !important; - .habit-control:hover { background: rgba($black, 0.5) !important; } + .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } .daily-todo-control:hover { background: rgba($white, 0.75) !important; } } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -256,6 +258,7 @@ &-modal { &-bg { background: $purple-300 !important; } + &-headings { color: $white; } &-icon { color: $purple-300 !important; } &-text { color: $black !important; } &-content { diff --git a/website/client/src/assets/scss/typography.scss b/website/client/src/assets/scss/typography.scss index a9caa6b285..267327b09b 100644 --- a/website/client/src/assets/scss/typography.scss +++ b/website/client/src/assets/scss/typography.scss @@ -53,7 +53,7 @@ h1 { h2 { font-size: 20px; - line-height: 1.2; + line-height: 1.4; margin-bottom: 16px; } @@ -73,3 +73,7 @@ h4 { font-family: 'Roboto Condensed', sans-serif; font-weight: bold; } + +.opacity-75 { + opacity: 0.75; +} diff --git a/website/client/src/assets/svg/information.svg b/website/client/src/assets/svg/information.svg index cb4a531a1e..c3d91e08ee 100644 --- a/website/client/src/assets/svg/information.svg +++ b/website/client/src/assets/svg/information.svg @@ -1,3 +1,3 @@ - + diff --git a/website/client/src/components/achievements/newStuff.vue b/website/client/src/components/achievements/newStuff.vue index e59592ee2a..53c427a383 100644 --- a/website/client/src/components/achievements/newStuff.vue +++ b/website/client/src/components/achievements/newStuff.vue @@ -13,20 +13,20 @@ v-html="html" > -