diff --git a/cypress/integration/common/post.js b/cypress/integration/common/post.js index 7a47c116e..d0298c5a3 100644 --- a/cypress/integration/common/post.js +++ b/cypress/integration/common/post.js @@ -30,7 +30,7 @@ Then("my comment should be successfully created", () => { }); Then("I should see my comment", () => { - cy.get("div.comment p") + cy.get("article.comment-card p") .should("contain", "Human Connection rocks") .get(".user-avatar img") .should("have.attr", "src") @@ -40,12 +40,12 @@ Then("I should see my comment", () => { }); Then("I should see the entirety of my comment", () => { - cy.get("div.comment") + cy.get("article.comment-card") .should("not.contain", "show more") }); Then("I should see an abreviated version of my comment", () => { - cy.get("div.comment") + cy.get("article.comment-card") .should("contain", "show more") }); @@ -60,7 +60,7 @@ Then("it should create a mention in the CommentForm", () => { }) When("I open the content menu of post {string}", (title)=> { - cy.contains('.post-card', title) + cy.contains('.post-teaser', title) .find('.content-menu .base-button') .click() }) @@ -77,9 +77,10 @@ Then("there is no button to pin a post", () => { }) And("the post with title {string} has a ribbon for pinned posts", (title) => { - cy.get("article.post-card").contains(title) + cy.get(".post-teaser").contains(title) .parent() - .find("div.ribbon.ribbon--pinned") + .parent() + .find(".ribbon.--pinned") .should("contain", "Announcement") }) @@ -111,7 +112,7 @@ Then("I add all required fields", () => { .get(".categories-select .base-button") .first() .click() - .get('.ds-flex-item > .ds-form-item .ds-select ') + .get('.base-card > .select-field input') .click() .get('.ds-select-option') .eq(languages.findIndex(l => l.code === 'en')) @@ -119,7 +120,7 @@ Then("I add all required fields", () => { }) Then("the post was saved successfully with the {string} teaser image", condition => { - cy.get(".ds-card-content > .ds-heading") + cy.get(".base-card > .title") .should("contain", condition === 'updated' ? 'to be updated' : 'new post') .get(".content") .should("contain", condition === 'updated' ? 'successfully updated' : 'new post content') @@ -128,25 +129,22 @@ Then("the post was saved successfully with the {string} teaser image", condition .and("contains", condition === 'updated' ? 'humanconnection' : 'onourjourney') }) -Then("the first image should be removed from the preview", () => { - cy.fixture("humanconnection.png").as('postTeaserImage').then(function() { - cy.get("#postdropzone") - .children() - .get('img.thumbnail-preview') - .should('have.length', 1) - .and('have.attr', 'src') - .and('contain', this.postTeaserImage) - }) +Then("the first image should not be displayed anymore", () => { + cy.get(".hero-image") + .children() + .get('.hero-image > .image') + .should('have.length', 1) + .and('have.attr', 'src') }) Then('the {string} post was saved successfully without a teaser image', condition => { - cy.get(".ds-card-content > .ds-heading") + cy.get(".base-card > .title") .should("contain", condition === 'updated' ? 'to be updated' : 'new post') .get(".content") .should("contain", condition === 'updated' ? 'successfully updated' : 'new post content') .get('.post-page') .should('exist') - .get('.post-page img.ds-card-image') + .get('.hero-image > .image') .should('not.exist') }) @@ -156,12 +154,12 @@ Then('I should be able to remove it', () => { }) When('my post has a teaser image', () => { - cy.get('.contribution-image') + cy.get('.contribution-form .image') .should('exist') .and('have.attr', 'src') }) Then('I should be able to remove the image', () => { - cy.get('.delete-image') + cy.get('.dz-message > .base-button') .click() -}) \ No newline at end of file +}) diff --git a/cypress/integration/common/profile.js b/cypress/integration/common/profile.js index c22c20392..a0be8a2cf 100644 --- a/cypress/integration/common/profile.js +++ b/cypress/integration/common/profile.js @@ -29,7 +29,7 @@ When("I visit another user's profile page", () => { }); Then("I cannot upload a picture", () => { - cy.get(".ds-card-content") + cy.get(".base-card") .children() .should("not.have.id", "customdropzone") .should("have.class", "user-avatar"); diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js index f209ceef7..fe7a31363 100644 --- a/cypress/integration/common/report.js +++ b/cypress/integration/common/report.js @@ -12,7 +12,7 @@ let annoyingUserWhoMutedModeratorTitle = 'Fake news' const savePostTitle = $post => { return $post .first() - .find('.ds-heading') + .find('.title') .first() .invoke('text') .then(title => { @@ -51,7 +51,7 @@ Given('I am logged in with a {string} role', role => { }) When('I click on "Report Post" from the content menu of the post', () => { - cy.contains('.ds-card', davidIrvingPostTitle) + cy.contains('.base-card', davidIrvingPostTitle) .find('.content-menu .base-button') .click({force: true}) @@ -61,7 +61,7 @@ When('I click on "Report Post" from the content menu of the post', () => { }) When('I click on "Report User" from the content menu in the user info box', () => { - cy.contains('.ds-card', davidIrvingPostTitle) + cy.contains('.base-card', davidIrvingPostTitle) .get('.user-content-menu .base-button') .click({ force: true }) @@ -78,7 +78,7 @@ When('I click on the author', () => { When('I report the author', () => { cy.get('.page-name-profile-id-slug').then(() => { - invokeReportOnElement('.ds-card').then(() => { + invokeReportOnElement('.base-card').then(() => { cy.get('button') .contains('Send') .click() @@ -169,7 +169,7 @@ Then('each list item links to the post page', () => { Then('I can visit the post page', () => { cy.contains(annoyingUserWhoMutedModeratorTitle).click() cy.location('pathname').should('contain', '/post') - .get('h3').should('contain', annoyingUserWhoMutedModeratorTitle) + .get('title').should('contain', annoyingUserWhoMutedModeratorTitle) }) When("they have a post someone has reported", () => { diff --git a/cypress/integration/common/search.js b/cypress/integration/common/search.js index c42ec3ff0..1feece77e 100644 --- a/cypress/integration/common/search.js +++ b/cypress/integration/common/search.js @@ -1,6 +1,6 @@ import { When, Then } from "cypress-cucumber-preprocessor/steps"; When("I search for {string}", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value); }); @@ -25,7 +25,7 @@ Then("the search should contain the annoying user", () => { expect($li).to.have.length(1); }) cy.get(".ds-select-dropdown .user-teaser .slug").should("contain", '@spammy-spammer'); - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type("{esc}"); }) @@ -44,21 +44,21 @@ Then("I should see the following users in the select dropdown:", table => { }); When("I type {string} and press Enter", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value) .type("{enter}", { force: true }); }); When("I type {string} and press escape", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value) .type("{esc}"); }); Then("the search field should clear", () => { - cy.get(".searchable-input .ds-select-search").should("have.text", ""); + cy.get(".searchable-input .ds-select input").should("have.text", ""); }); When("I select a post entry", () => { diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js index e8e968a5e..3dcff141d 100644 --- a/cypress/integration/common/settings.js +++ b/cypress/integration/common/settings.js @@ -80,7 +80,7 @@ Then('I should be on the {string} page', page => { .should(loc => { expect(loc.pathname).to.eq(page) }) - .get('h3') + .get('h2') .should('contain', 'Social media') }) @@ -112,7 +112,7 @@ Given('I have added a social media link', () => { }) Then('they should be able to see my social media links', () => { - cy.get('.ds-card-content') + cy.get('.base-card') .contains('Where else can I find Peter Pan?') .get('a[href="https://freeradical.zone/peter-pan"]') .should('have.length', 1) diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index f411efa90..2a87e3d83 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -73,7 +73,7 @@ Given("the {string} user searches for {string}", (_, postTitle) => { }) }) .then(user => cy.login(user)) - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(postTitle); }); @@ -295,14 +295,14 @@ Then("I select a category", () => { }); When("I choose {string} as the language for the post", (languageCode) => { - cy.get('.ds-flex-item > .ds-form-item .ds-select ') + cy.get('.contribution-form .ds-select') .click().get('.ds-select-option') .eq(languages.findIndex(l => l.code === languageCode)).click() }) Then("the post shows up on the landing page at position {int}", index => { cy.openPage("landing"); - const selector = `.post-card:nth-child(${index}) > .ds-card-content`; + const selector = `.post-teaser:nth-child(${index}) > .base-card`; cy.get(selector).should("contain", lastPost.title); cy.get(selector).should("contain", lastPost.content); }); @@ -312,16 +312,16 @@ Then("I get redirected to {string}", route => { }); Then("the post was saved successfully", () => { - cy.get(".ds-card-content > .ds-heading").should("contain", lastPost.title); + cy.get(".base-card > .title").should("contain", lastPost.title); cy.get(".content").should("contain", lastPost.content); }); Then(/^I should see only ([0-9]+) posts? on the landing page/, postCount => { - cy.get(".post-card").should("have.length", postCount); + cy.get(".post-teaser").should("have.length", postCount); }); Then("the first post on the landing page has the title:", title => { - cy.get(".post-card:first").should("contain", title); + cy.get(".post-teaser:first").should("contain", title); }); Then( @@ -388,7 +388,7 @@ Then("I can login successfully with password {string}", password => { When("open the notification menu and click on the first item", () => { cy.get(".notifications-menu").invoke('show').click(); // "invoke('show')" because of the delay for show the menu - cy.get(".notification-mention-post") + cy.get(".notification .link") .first() .click({ force: true @@ -424,7 +424,7 @@ When("mention {string} in the text", mention => { Then("the notification gets marked as read", () => { cy.get(".notifications-menu-popover .notification") .first() - .should("have.class", "read"); + .should("have.class", "--read"); }); Then("there are no notifications in the top menu", () => { @@ -510,14 +510,14 @@ Given('{string} wrote a post {string}', (_, title) => { }); Then("the list of posts of this user is empty", () => { - cy.get(".ds-card-content").not(".post-link"); + cy.get(".base-card").not(".post-link"); cy.get(".main-container").find(".ds-space.hc-empty"); }); Then("I get removed from his follower collection", () => { - cy.get(".ds-card-content").not(".post-link"); + cy.get(".base-card").not(".post-link"); cy.get(".main-container").contains( - ".ds-card-content", + ".base-card", "is not followed by anyone" ); }); @@ -581,7 +581,7 @@ Then("I see only one post with the title {string}", title => { }); Then("they should not see the comment form", () => { - cy.get(".ds-card-footer").children().should('not.have.class', 'comment-form') + cy.get(".base-card").children().should('not.have.class', 'comment-form') }) Then("they should see a text explaining why commenting is not possible", () => { @@ -600,11 +600,11 @@ Then("I {string} see {string} from the content menu in the user info box", (cond }) Then('I should not see {string} button', button => { - cy.get('.ds-card-content .action-buttons') + cy.get('.base-card .action-buttons') .should('have.length', 1) }) Then('I should see the {string} button', button => { - cy.get('.ds-card-content .action-buttons .base-button') + cy.get('.base-card .action-buttons .base-button') .should('contain', button) }) diff --git a/cypress/integration/post/ImageUploader.feature b/cypress/integration/post/ImageUploader.feature index 2e9f1f5b9..1bbd80c78 100644 --- a/cypress/integration/post/ImageUploader.feature +++ b/cypress/integration/post/ImageUploader.feature @@ -35,7 +35,7 @@ Feature: Upload Teaser Image And confirm crop And I should be able to "change" a teaser image And confirm crop - And the first image should be removed from the preview + And the first image should not be displayed anymore Scenario: Add image, then delete it When I click on the big plus icon in the bottom right corner to create post @@ -44,4 +44,4 @@ Feature: Upload Teaser Image And I add all required fields And I click on "Save" Then I get redirected to ".../new-post" - And the "new" post was saved successfully without a teaser image \ No newline at end of file + And the "new" post was saved successfully without a teaser image diff --git a/cypress/integration/user_profile/BlockUser.feature b/cypress/integration/user_profile/BlockUser.feature index 256d79dfb..b5c510286 100644 --- a/cypress/integration/user_profile/BlockUser.feature +++ b/cypress/integration/user_profile/BlockUser.feature @@ -55,6 +55,6 @@ Feature: Block a User Scenario: Blocked users should not see link or button to unblock, only blocking users Given a user has blocked me When I visit the profile page of the annoying user - And I "should not" see "Unblock user" from the content menu in the user info box And I should see the "Follow" button - And I should not see "Unblock user" button \ No newline at end of file + And I should not see "Unblock user" button + And I "should not" see "Unblock user" from the content menu in the user info box diff --git a/webapp/assets/_new/styles/resets.scss b/webapp/assets/_new/styles/resets.scss index 2784add5f..144f22d10 100644 --- a/webapp/assets/_new/styles/resets.scss +++ b/webapp/assets/_new/styles/resets.scss @@ -9,3 +9,13 @@ button { font-family: inherit; font-size: inherit; } + +h1, +h2, +h3, +h4, +h5, +h6, +p { + margin: 0; +} diff --git a/webapp/assets/_new/styles/tokens.scss b/webapp/assets/_new/styles/tokens.scss index 90ec527ea..4ab30177b 100644 --- a/webapp/assets/_new/styles/tokens.scss +++ b/webapp/assets/_new/styles/tokens.scss @@ -211,7 +211,8 @@ $letter-spacing-x-small: -0.015em; * @presenter Opacity */ -$opacity-soft: 0.65; +$opacity-base: 1; +$opacity-soft: 0.7; $opacity-disabled: 0.5; /** @@ -264,12 +265,23 @@ $size-avatar-large: 114px; $size-button-base: 36px; $size-button-small: 26px; +/** + * @tokens Size Images + * @presenter Spacing + */ + +$size-image-max-height: 2000px; +$size-image-cropper-max-height: 600px; +$size-image-cropper-min-height: 400px; +$size-image-uploader-min-height: 200px; + /** * @tokens Size Icons * @presenter Spacing */ $size-icon-base: 16px; + $size-icon-large: 60px; /** * @tokens Shadow @@ -285,6 +297,12 @@ $box-shadow-active: 0 0 6px 1px rgba(20, 100, 160, 0.5); $box-shadow-inset: inset 0 0 20px 1px rgba(0,0,0,.15); $box-shadow-small-inset: inset 0 0 0 1px rgba(0,0,0,.05); +/** + * @tokens Effects + */ + +$blur-radius: 22px; + /** * @tokens Animation Duration */ @@ -316,7 +334,8 @@ $z-index-page-submenu: 2500; $z-index-page-header: 2000; $z-index-page-sidebar: 1500; $z-index-sticky: 100; -$z-index-post-card-link: 5; +$z-index-post-teaser-link: 5; +$z-index-surface: 1; /** * @tokens Media Query diff --git a/webapp/assets/styles/main.scss b/webapp/assets/styles/main.scss index fbab1d78f..d6821e013 100644 --- a/webapp/assets/styles/main.scss +++ b/webapp/assets/styles/main.scss @@ -13,6 +13,8 @@ $easeOut: cubic-bezier(0.19, 1, 0.22, 1); content: ''; display: block; position: absolute; + top: 0; + left: 0; width: 100%; height: 100%; z-index: 2; @@ -141,10 +143,9 @@ hr { } } -.ds-card .ds-section { +.base-card > .ds-section { padding: 0; - margin-left: -$space-base; - margin-right: -$space-base; + margin: -$space-base; .ds-container { padding: $space-base; diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.vue b/webapp/components/CategoriesSelect/CategoriesSelect.vue index 54c0d3524..b7d71de2d 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.vue +++ b/webapp/components/CategoriesSelect/CategoriesSelect.vue @@ -1,30 +1,18 @@ + + diff --git a/webapp/components/Comment/Comment.vue b/webapp/components/Comment/Comment.vue deleted file mode 100644 index 5c47a3656..000000000 --- a/webapp/components/Comment/Comment.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - - diff --git a/webapp/components/Comment/Comment.spec.js b/webapp/components/CommentCard/CommentCard.spec.js similarity index 95% rename from webapp/components/Comment/Comment.spec.js rename to webapp/components/CommentCard/CommentCard.spec.js index 1ba238bf5..b18ab67c0 100644 --- a/webapp/components/Comment/Comment.spec.js +++ b/webapp/components/CommentCard/CommentCard.spec.js @@ -1,5 +1,5 @@ import { config, mount } from '@vue/test-utils' -import Comment from './Comment.vue' +import CommentCard from './CommentCard.vue' import Vuex from 'vuex' const localVue = global.localVue @@ -8,11 +8,17 @@ localVue.directive('scrollTo', jest.fn()) config.stubs['client-only'] = '' config.stubs['nuxt-link'] = '' -describe('Comment.vue', () => { +describe('CommentCard.vue', () => { let propsData, mocks, stubs, getters, wrapper, Wrapper beforeEach(() => { - propsData = {} + propsData = { + comment: { + id: 'comment007', + author: { id: 'some-user' }, + }, + postId: 'post42', + } mocks = { $t: jest.fn(), $toast: { @@ -26,6 +32,7 @@ describe('Comment.vue', () => { truncate: a => a, removeHtml: a => a, }, + $route: { hash: '' }, $scrollTo: jest.fn(), $apollo: { mutate: jest.fn().mockResolvedValue({ @@ -55,7 +62,7 @@ describe('Comment.vue', () => { const store = new Vuex.Store({ getters, }) - return mount(Comment, { + return mount(CommentCard, { store, propsData, mocks, diff --git a/webapp/components/Comment/Comment.story.js b/webapp/components/CommentCard/CommentCard.story.js similarity index 92% rename from webapp/components/Comment/Comment.story.js rename to webapp/components/CommentCard/CommentCard.story.js index 291b6cb11..1749999f3 100644 --- a/webapp/components/Comment/Comment.story.js +++ b/webapp/components/CommentCard/CommentCard.story.js @@ -1,6 +1,6 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' -import Comment from './Comment' +import CommentCard from './CommentCard' import helpers from '~/storybook/helpers' helpers.init() @@ -41,14 +41,14 @@ const comment = { __typename: 'Comment', } -storiesOf('Comment', module) +storiesOf('CommentCard', module) .addDecorator(withA11y) .addDecorator(helpers.layout) .add('Basic comment', () => ({ - components: { Comment }, + components: { CommentCard }, store: helpers.store, data: () => ({ comment, }), - template: ``, + template: ``, })) diff --git a/webapp/components/CommentCard/CommentCard.vue b/webapp/components/CommentCard/CommentCard.vue new file mode 100644 index 000000000..d805d26ee --- /dev/null +++ b/webapp/components/CommentCard/CommentCard.vue @@ -0,0 +1,216 @@ + + + + diff --git a/webapp/components/CommentForm/CommentForm.spec.js b/webapp/components/CommentForm/CommentForm.spec.js index 420ab26fb..b940c561d 100644 --- a/webapp/components/CommentForm/CommentForm.spec.js +++ b/webapp/components/CommentForm/CommentForm.spec.js @@ -153,10 +153,10 @@ describe('CommentForm.vue', () => { expect(closeMethodSpy).toHaveBeenCalledTimes(1) }) - it('emits `showEditCommentMenu` event', async () => { + it('emits `finishEditing` event', async () => { wrapper.vm.updateEditorContent('ok') await wrapper.find('form').trigger('submit') - expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]]) + expect(wrapper.emitted('finishEditing')).toBeTruthy() }) }) @@ -167,10 +167,10 @@ describe('CommentForm.vue', () => { expect(closeMethodSpy).toHaveBeenCalledTimes(1) }) - it('emits `showEditCommentMenu` event', async () => { + it('emits `finishEditing` event', async () => { wrapper.vm.updateEditorContent('ok') await wrapper.find('[data-test="cancel-button"]').trigger('submit') - expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]]) + expect(wrapper.emitted('finishEditing')).toBeTruthy() }) }) diff --git a/webapp/components/CommentForm/CommentForm.vue b/webapp/components/CommentForm/CommentForm.vue index 9e4158876..422530259 100644 --- a/webapp/components/CommentForm/CommentForm.vue +++ b/webapp/components/CommentForm/CommentForm.vue @@ -1,8 +1,7 @@ @@ -72,7 +71,7 @@ export default { this.$refs.editor.clear() }, closeEditWindow() { - this.$emit('showEditCommentMenu', false) + this.$emit('finishEditing') }, handleCancel() { if (!this.update) { @@ -146,10 +145,13 @@ export default { diff --git a/webapp/components/DeleteData/DeleteData.spec.js b/webapp/components/DeleteData/DeleteData.spec.js index 3529c1b7b..e9205fa5a 100644 --- a/webapp/components/DeleteData/DeleteData.spec.js +++ b/webapp/components/DeleteData/DeleteData.spec.js @@ -88,7 +88,7 @@ describe('DeleteData.vue', () => { describe('calls the delete user mutation', () => { beforeEach(() => { - enableDeletionInput = wrapper.find('.enable-deletion-input input') + enableDeletionInput = wrapper.find('.ds-input') enableDeletionInput.setValue(deleteAccountName) deleteAccountBtn = wrapper.find('[data-test="delete-button"]') }) @@ -107,7 +107,7 @@ describe('DeleteData.vue', () => { it("deletes a user's posts if requested", () => { mocks.$t.mockImplementation(() => deleteContributionsMessage) - enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0) + enableContributionDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(0) enableContributionDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -122,7 +122,7 @@ describe('DeleteData.vue', () => { it("deletes a user's comments if requested", () => { mocks.$t.mockImplementation(() => deleteCommentsMessage) - enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1) + enableCommentDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(1) enableCommentDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -137,10 +137,10 @@ describe('DeleteData.vue', () => { it("deletes a user's posts and comments if requested", () => { mocks.$t.mockImplementation(() => deleteContributionsMessage) - enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0) + enableContributionDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(0) enableContributionDeletionCheckbox.trigger('click') mocks.$t.mockImplementation(() => deleteCommentsMessage) - enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1) + enableCommentDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(1) enableCommentDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -166,7 +166,7 @@ describe('DeleteData.vue', () => { describe('error handling', () => { it('shows an error toaster when the mutation rejects', async () => { - enableDeletionInput = wrapper.find('.enable-deletion-input input') + enableDeletionInput = wrapper.find('.ds-input') enableDeletionInput.setValue(deleteAccountName) await Vue.nextTick() deleteAccountBtn = wrapper.find('[data-test="delete-button"]') diff --git a/webapp/components/DeleteData/DeleteData.vue b/webapp/components/DeleteData/DeleteData.vue index 66a31205a..1157fc922 100644 --- a/webapp/components/DeleteData/DeleteData.vue +++ b/webapp/components/DeleteData/DeleteData.vue @@ -1,80 +1,46 @@ + + diff --git a/webapp/components/Editor/Editor.story.js b/webapp/components/Editor/Editor.story.js index 8efcf3f4c..381c2e7ea 100644 --- a/webapp/components/Editor/Editor.story.js +++ b/webapp/components/Editor/Editor.story.js @@ -40,9 +40,9 @@ storiesOf('Editor', module) return { components: { ctx }, template: ` - + - + `, } }) diff --git a/webapp/components/Editor/SuggestionList.vue b/webapp/components/Editor/SuggestionList.vue index 3d480d187..5e9c146a0 100644 --- a/webapp/components/Editor/SuggestionList.vue +++ b/webapp/components/Editor/SuggestionList.vue @@ -89,7 +89,7 @@ export default { } &.hint { - opacity: 0.7; + opacity: $opacity-soft; pointer-events: none; } } diff --git a/webapp/components/FilterMenu/FilterMenu.spec.js b/webapp/components/FilterMenu/FilterMenu.spec.js index d70af323f..283db979e 100644 --- a/webapp/components/FilterMenu/FilterMenu.spec.js +++ b/webapp/components/FilterMenu/FilterMenu.spec.js @@ -12,10 +12,10 @@ describe('FilterMenu.vue', () => { mocks = { $t: () => {} } }) - describe('given a user', () => { + describe('given a hashtag', () => { beforeEach(() => { propsData = { - hashtag: null, + hashtag: 'Frieden', } }) @@ -27,19 +27,14 @@ describe('FilterMenu.vue', () => { wrapper = Wrapper() }) - it('does not render a card if there are no hashtags', () => { - expect(wrapper.is('.ds-card')).toBe(true) - }) - - it('renders a card if there are hashtags', () => { - propsData.hashtag = 'Frieden' + it('renders a card', () => { wrapper = Wrapper() - expect(wrapper.is('.ds-card')).toBe(true) + expect(wrapper.is('.base-card')).toBe(true) }) - describe('click "clear-search-button" button', () => { + describe('click clear search button', () => { it('emits clearSearch', () => { - wrapper.find('[name="clear-search-button"]').trigger('click') + wrapper.find('.base-button').trigger('click') expect(wrapper.emitted().clearSearch).toHaveLength(1) }) }) diff --git a/webapp/components/FilterMenu/FilterMenu.vue b/webapp/components/FilterMenu/FilterMenu.vue index e56925e56..afe6a3d7a 100644 --- a/webapp/components/FilterMenu/FilterMenu.vue +++ b/webapp/components/FilterMenu/FilterMenu.vue @@ -1,32 +1,22 @@ diff --git a/webapp/components/TeaserImage/TeaserImage.spec.js b/webapp/components/ImageUploader/ImageUploader.spec.js similarity index 56% rename from webapp/components/TeaserImage/TeaserImage.spec.js rename to webapp/components/ImageUploader/ImageUploader.spec.js index dd89c8cfd..e2e9f8d05 100644 --- a/webapp/components/TeaserImage/TeaserImage.spec.js +++ b/webapp/components/ImageUploader/ImageUploader.spec.js @@ -1,9 +1,9 @@ import { mount } from '@vue/test-utils' -import TeaserImage from './TeaserImage.vue' +import ImageUploader from './ImageUploader.vue' const localVue = global.localVue -describe('TeaserImage.vue', () => { +describe('ImageUploader.vue', () => { let wrapper let mocks @@ -17,7 +17,7 @@ describe('TeaserImage.vue', () => { }) describe('mount', () => { const Wrapper = () => { - return mount(TeaserImage, { mocks, localVue }) + return mount(ImageUploader, { mocks, localVue }) } beforeEach(() => { wrapper = Wrapper() @@ -28,21 +28,10 @@ describe('TeaserImage.vue', () => { const message = 'File upload failed' const fileError = { status: 'error' } - it('defaults to error false', () => { - expect(wrapper.vm.error).toEqual(false) - }) - it('shows an error toaster when verror is called', () => { - wrapper.vm.verror(fileError, message) + wrapper.vm.onDropzoneError(fileError, message) expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, message) }) - - it('changes error status from false to true to false', () => { - wrapper.vm.verror(fileError, message) - expect(wrapper.vm.error).toEqual(true) - jest.runAllTimers() - expect(wrapper.vm.error).toEqual(false) - }) }) }) }) diff --git a/webapp/components/ImageUploader/ImageUploader.vue b/webapp/components/ImageUploader/ImageUploader.vue new file mode 100644 index 000000000..36f9b8485 --- /dev/null +++ b/webapp/components/ImageUploader/ImageUploader.vue @@ -0,0 +1,200 @@ + + + + diff --git a/webapp/components/LocaleSwitch/LocaleSwitch.spec.js b/webapp/components/LocaleSwitch/LocaleSwitch.spec.js index ee28b742a..812ff9253 100644 --- a/webapp/components/LocaleSwitch/LocaleSwitch.spec.js +++ b/webapp/components/LocaleSwitch/LocaleSwitch.spec.js @@ -1,10 +1,12 @@ -import { mount } from '@vue/test-utils' +import { config, mount } from '@vue/test-utils' import LocaleSwitch from './LocaleSwitch.vue' import Vuex from 'vuex' const localVue = global.localVue +config.stubs['client-only'] = '' + describe('LocaleSwitch.vue', () => { let wrapper, mocks, computed, deutschLanguageItem, getters diff --git a/webapp/components/LocaleSwitch/LocaleSwitch.vue b/webapp/components/LocaleSwitch/LocaleSwitch.vue index 564de20f7..5c0d901c9 100644 --- a/webapp/components/LocaleSwitch/LocaleSwitch.vue +++ b/webapp/components/LocaleSwitch/LocaleSwitch.vue @@ -1,35 +1,37 @@ diff --git a/webapp/components/Notification/Notification.spec.js b/webapp/components/Notification/Notification.spec.js index 750f59b3a..537babfae 100644 --- a/webapp/components/Notification/Notification.spec.js +++ b/webapp/components/Notification/Notification.spec.js @@ -63,7 +63,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.commented_on_post', ) }) @@ -79,9 +79,9 @@ describe('Notification', () => { wrapper = Wrapper() expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -90,8 +90,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) @@ -113,7 +113,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.mentioned_in_post', ) }) @@ -125,9 +125,9 @@ describe('Notification', () => { wrapper = Wrapper() expect(wrapper.text()).toContain('@jenny-rostock is the best on this post.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -136,8 +136,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) @@ -163,7 +163,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.mentioned_in_comment', ) }) @@ -182,9 +182,9 @@ describe('Notification', () => { expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -193,8 +193,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) diff --git a/webapp/components/Notification/Notification.vue b/webapp/components/Notification/Notification.vue index 2a4942716..acb83b028 100644 --- a/webapp/components/Notification/Notification.vue +++ b/webapp/components/Notification/Notification.vue @@ -1,37 +1,23 @@ diff --git a/webapp/components/NotificationList/NotificationList.spec.js b/webapp/components/NotificationList/NotificationList.spec.js index f70b7a482..075891f14 100644 --- a/webapp/components/NotificationList/NotificationList.spec.js +++ b/webapp/components/NotificationList/NotificationList.spec.js @@ -73,7 +73,7 @@ describe('NotificationList.vue', () => { describe('click on a notification', () => { beforeEach(() => { - wrapper.find('.notification-mention-post').trigger('click') + wrapper.find('.notification > .link').trigger('click') }) it("emits 'markAsRead' with the id of the notification source", () => { diff --git a/webapp/components/NotificationsTable/NotificationsTable.story.js b/webapp/components/NotificationsTable/NotificationsTable.story.js index 84deb31c9..1d27f6532 100644 --- a/webapp/components/NotificationsTable/NotificationsTable.story.js +++ b/webapp/components/NotificationsTable/NotificationsTable.story.js @@ -3,7 +3,7 @@ import { withA11y } from '@storybook/addon-a11y' import { action } from '@storybook/addon-actions' import NotificationsTable from '~/components/NotificationsTable/NotificationsTable' import helpers from '~/storybook/helpers' -import { post } from '~/components/PostCard/PostCard.story.js' +import { post } from '~/components/PostTeaser/PostTeaser.story.js' import { user } from '~/components/UserTeaser/UserTeaser.story.js' helpers.init() diff --git a/webapp/components/PostCard/PostCard.vue b/webapp/components/PostCard/PostCard.vue deleted file mode 100644 index d5a6d509b..000000000 --- a/webapp/components/PostCard/PostCard.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - - diff --git a/webapp/components/PostCard/PostCard.spec.js b/webapp/components/PostTeaser/PostTeaser.spec.js similarity index 85% rename from webapp/components/PostCard/PostCard.spec.js rename to webapp/components/PostTeaser/PostTeaser.spec.js index 28ce10b9e..1e90cd1cf 100644 --- a/webapp/components/PostCard/PostCard.spec.js +++ b/webapp/components/PostTeaser/PostTeaser.spec.js @@ -2,14 +2,14 @@ import { config, shallowMount, mount, RouterLinkStub } from '@vue/test-utils' import Vuex from 'vuex' -import PostCard from './PostCard.vue' +import PostTeaser from './PostTeaser.vue' const localVue = global.localVue config.stubs['client-only'] = '' config.stubs['v-popover'] = '' -describe('PostCard', () => { +describe('PostTeaser', () => { let store let stubs let mocks @@ -22,11 +22,13 @@ describe('PostCard', () => { propsData = { post: { id: 'p23', + disabled: false, + shoutedCount: 0, + commentsCount: 0, name: 'It is a post', author: { id: 'u1', }, - disabled: false, }, } stubs = { @@ -55,7 +57,7 @@ describe('PostCard', () => { describe('shallowMount', () => { Wrapper = () => { store = new Vuex.Store({ getters }) - return shallowMount(PostCard, { + return shallowMount(PostTeaser, { store, propsData, mocks, @@ -63,6 +65,13 @@ describe('PostCard', () => { }) } + it('has no validation errors', () => { + const spy = jest.spyOn(global.console, 'error') + Wrapper() + expect(spy).not.toBeCalled() + spy.mockReset() + }) + beforeEach(jest.useFakeTimers) describe('test Post callbacks', () => { @@ -99,7 +108,7 @@ describe('PostCard', () => { const store = new Vuex.Store({ getters, }) - return mount(PostCard, { + return mount(PostTeaser, { stubs, mocks, propsData, @@ -111,6 +120,7 @@ describe('PostCard', () => { describe('given a post', () => { beforeEach(() => { propsData.post = { + ...propsData.post, title: "It's a title", } }) diff --git a/webapp/components/PostCard/PostCard.story.js b/webapp/components/PostTeaser/PostTeaser.story.js similarity index 85% rename from webapp/components/PostCard/PostCard.story.js rename to webapp/components/PostTeaser/PostTeaser.story.js index 5857167f3..db3350c5b 100644 --- a/webapp/components/PostCard/PostCard.story.js +++ b/webapp/components/PostTeaser/PostTeaser.story.js @@ -1,6 +1,6 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' -import HcPostCard from './PostCard.vue' +import PostTeaser from './PostTeaser.vue' import helpers from '~/storybook/helpers' helpers.init() @@ -44,24 +44,24 @@ export const post = { __typename: 'Post', } -storiesOf('Post Card', module) +storiesOf('PostTeaser', module) .addDecorator(withA11y) .addDecorator(helpers.layout) .add('without image', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post, }), template: ` - `, })) .add('with image', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post: { @@ -70,27 +70,23 @@ storiesOf('Post Card', module) }, }), template: ` - `, })) .add('pinned by admin', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post: { ...post, - pinnedBy: { - id: '4711', - name: 'Ad Min', - role: 'admin', - }, + pinned: true, }, }), template: ` - diff --git a/webapp/components/PostTeaser/PostTeaser.vue b/webapp/components/PostTeaser/PostTeaser.vue new file mode 100644 index 000000000..851ee4f2c --- /dev/null +++ b/webapp/components/PostTeaser/PostTeaser.vue @@ -0,0 +1,207 @@ + + + + diff --git a/webapp/components/Ribbon/index.vue b/webapp/components/Ribbon/index.vue index c8c09c194..7be3b040d 100644 --- a/webapp/components/Ribbon/index.vue +++ b/webapp/components/Ribbon/index.vue @@ -45,13 +45,13 @@ export default { border-style: solid; border-color: $background-color-secondary transparent transparent $background-color-secondary; } -} -.ribbon--pinned { - background-color: $color-warning-active; + &.--pinned { + background-color: $color-warning; - &::before { - border-color: $color-warning transparent transparent $color-warning; + &::before { + border-color: $color-warning transparent transparent $color-warning; + } } } diff --git a/webapp/components/TeaserImage/TeaserImage.vue b/webapp/components/TeaserImage/TeaserImage.vue deleted file mode 100644 index 4893de7c0..000000000 --- a/webapp/components/TeaserImage/TeaserImage.vue +++ /dev/null @@ -1,257 +0,0 @@ - - - - diff --git a/webapp/components/UserTeaser/UserTeaser.story.js b/webapp/components/UserTeaser/UserTeaser.story.js index 488576bd5..73b34cb76 100644 --- a/webapp/components/UserTeaser/UserTeaser.story.js +++ b/webapp/components/UserTeaser/UserTeaser.story.js @@ -80,7 +80,7 @@ storiesOf('UserTeaser', module) }), template: ` -