mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge branch 'master' of github.com:Human-Connection/Human-Connection into 279-blacklist-users-content
This commit is contained in:
commit
851babeac3
@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/joi": "^17.0.2",
|
"@hapi/joi": "^17.0.2",
|
||||||
"@sentry/node": "^5.11.0",
|
"@sentry/node": "^5.11.1",
|
||||||
"apollo-cache-inmemory": "~1.6.5",
|
"apollo-cache-inmemory": "~1.6.5",
|
||||||
"apollo-client": "~2.6.8",
|
"apollo-client": "~2.6.8",
|
||||||
"apollo-link-context": "~1.0.19",
|
"apollo-link-context": "~1.0.19",
|
||||||
@ -62,20 +62,20 @@
|
|||||||
"linkifyjs": "~2.1.8",
|
"linkifyjs": "~2.1.8",
|
||||||
"lodash": "~4.17.14",
|
"lodash": "~4.17.14",
|
||||||
"merge-graphql-schemas": "^1.7.6",
|
"merge-graphql-schemas": "^1.7.6",
|
||||||
"metascraper": "^5.9.5",
|
"metascraper": "^5.10.2",
|
||||||
"metascraper-audio": "^5.9.5",
|
"metascraper-audio": "^5.9.5",
|
||||||
"metascraper-author": "^5.9.5",
|
"metascraper-author": "^5.10.3",
|
||||||
"metascraper-clearbit-logo": "^5.3.0",
|
"metascraper-clearbit-logo": "^5.3.0",
|
||||||
"metascraper-date": "^5.9.5",
|
"metascraper-date": "^5.10.3",
|
||||||
"metascraper-description": "^5.9.5",
|
"metascraper-description": "^5.9.5",
|
||||||
"metascraper-image": "^5.9.5",
|
"metascraper-image": "^5.9.5",
|
||||||
"metascraper-lang": "^5.9.5",
|
"metascraper-lang": "^5.10.3",
|
||||||
"metascraper-lang-detector": "^4.10.2",
|
"metascraper-lang-detector": "^4.10.2",
|
||||||
"metascraper-logo": "^5.9.5",
|
"metascraper-logo": "^5.10.3",
|
||||||
"metascraper-publisher": "^5.9.5",
|
"metascraper-publisher": "^5.10.3",
|
||||||
"metascraper-soundcloud": "^5.9.5",
|
"metascraper-soundcloud": "^5.9.5",
|
||||||
"metascraper-title": "^5.9.5",
|
"metascraper-title": "^5.10.3",
|
||||||
"metascraper-url": "^5.9.5",
|
"metascraper-url": "^5.10.3",
|
||||||
"metascraper-video": "^5.9.5",
|
"metascraper-video": "^5.9.5",
|
||||||
"metascraper-youtube": "^5.9.5",
|
"metascraper-youtube": "^5.9.5",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.0.4",
|
||||||
@ -97,12 +97,12 @@
|
|||||||
"xregexp": "^4.2.4"
|
"xregexp": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "~7.8.0",
|
"@babel/cli": "~7.8.3",
|
||||||
"@babel/core": "~7.7.7",
|
"@babel/core": "~7.8.3",
|
||||||
"@babel/node": "~7.8.0",
|
"@babel/node": "~7.8.3",
|
||||||
"@babel/plugin-proposal-throw-expressions": "^7.8.0",
|
"@babel/plugin-proposal-throw-expressions": "^7.8.3",
|
||||||
"@babel/preset-env": "~7.8.2",
|
"@babel/preset-env": "~7.8.3",
|
||||||
"@babel/register": "~7.8.0",
|
"@babel/register": "~7.8.3",
|
||||||
"apollo-server-testing": "~2.9.16",
|
"apollo-server-testing": "~2.9.16",
|
||||||
"babel-core": "~7.0.0-0",
|
"babel-core": "~7.0.0-0",
|
||||||
"babel-eslint": "~10.0.3",
|
"babel-eslint": "~10.0.3",
|
||||||
|
|||||||
1221
backend/yarn.lock
1221
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@ Given('I am logged in with a {string} role', role => {
|
|||||||
|
|
||||||
When('I click on "Report Post" from the content menu of the post', () => {
|
When('I click on "Report Post" from the content menu of the post', () => {
|
||||||
cy.contains('.ds-card', davidIrvingPostTitle)
|
cy.contains('.ds-card', davidIrvingPostTitle)
|
||||||
.find('.content-menu-trigger')
|
.find('.content-menu .base-button')
|
||||||
.click({force: true})
|
.click({force: true})
|
||||||
|
|
||||||
cy.get('.popover .ds-menu-item-link')
|
cy.get('.popover .ds-menu-item-link')
|
||||||
@ -54,7 +54,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', () => {
|
When('I click on "Report User" from the content menu in the user info box', () => {
|
||||||
cy.contains('.ds-card', davidIrvingPostTitle)
|
cy.contains('.ds-card', davidIrvingPostTitle)
|
||||||
.get('.user-content-menu .content-menu-trigger')
|
.get('.user-content-menu .base-button')
|
||||||
.click({ force: true })
|
.click({ force: true })
|
||||||
|
|
||||||
cy.get('.popover .ds-menu-item-link')
|
cy.get('.popover .ds-menu-item-link')
|
||||||
|
|||||||
@ -119,7 +119,7 @@ Then('they should be able to see my social media links', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
When('I delete a social media link', () => {
|
When('I delete a social media link', () => {
|
||||||
cy.get("a[name='delete']")
|
cy.get(".base-button[title='Delete']")
|
||||||
.click()
|
.click()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ Then('it gets deleted successfully', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
When('I start editing a social media link', () => {
|
When('I start editing a social media link', () => {
|
||||||
cy.get("a[name='edit']")
|
cy.get(".base-button[title='Edit']")
|
||||||
.click()
|
.click()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -252,7 +252,7 @@ When("I type in the following text:", text => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Then("I select a category", () => {
|
Then("I select a category", () => {
|
||||||
cy.get("span")
|
cy.get(".base-button")
|
||||||
.contains("Just for Fun")
|
.contains("Just for Fun")
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
@ -453,7 +453,7 @@ When("I ", name => {
|
|||||||
When(
|
When(
|
||||||
"I click on {string} from the content menu in the user info box",
|
"I click on {string} from the content menu in the user info box",
|
||||||
button => {
|
button => {
|
||||||
cy.get(".user-content-menu .content-menu-trigger").click();
|
cy.get(".user-content-menu .base-button").click();
|
||||||
cy.get(".popover .ds-menu-item-link")
|
cy.get(".popover .ds-menu-item-link")
|
||||||
.contains(button)
|
.contains(button)
|
||||||
.click({
|
.click({
|
||||||
|
|||||||
@ -21,16 +21,16 @@
|
|||||||
"version": "auto-changelog -p"
|
"version": "auto-changelog -p"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.8.0",
|
"@babel/core": "^7.8.3",
|
||||||
"@babel/preset-env": "^7.8.2",
|
"@babel/preset-env": "^7.8.3",
|
||||||
"@babel/register": "^7.8.0",
|
"@babel/register": "^7.8.3",
|
||||||
"auto-changelog": "^1.16.2",
|
"auto-changelog": "^1.16.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"codecov": "^3.6.1",
|
"codecov": "^3.6.1",
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^6.0.3",
|
||||||
"cucumber": "^6.0.5",
|
"cucumber": "^6.0.5",
|
||||||
"cypress": "^3.8.2",
|
"cypress": "^3.8.2",
|
||||||
"cypress-cucumber-preprocessor": "^1.19.0",
|
"cypress-cucumber-preprocessor": "^2.0.1",
|
||||||
"cypress-file-upload": "^3.5.3",
|
"cypress-file-upload": "^3.5.3",
|
||||||
"cypress-plugin-retries": "^1.5.2",
|
"cypress-plugin-retries": "^1.5.2",
|
||||||
"date-fns": "^2.9.0",
|
"date-fns": "^2.9.0",
|
||||||
|
|||||||
65
webapp/assets/_new/styles/mixins/buttonStates.scss
Normal file
65
webapp/assets/_new/styles/mixins/buttonStates.scss
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
@mixin buttonStates($color-scheme: primary, $filled: false) {
|
||||||
|
$main-color: $color-primary;
|
||||||
|
$active-color: $color-primary-dark;
|
||||||
|
$hover-color: $color-primary-light;
|
||||||
|
|
||||||
|
@if $color-scheme == danger {
|
||||||
|
$main-color: $color-danger;
|
||||||
|
$active-color: $color-danger-dark;
|
||||||
|
$hover-color: $color-danger-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
color: $main-color;
|
||||||
|
border-color: $main-color;
|
||||||
|
background-color: transparent;
|
||||||
|
transition: background-color $duration-short;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: $border-size-base dashed $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:enabled {
|
||||||
|
&:hover {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
border-color: $main-color;
|
||||||
|
background-color: $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
border-color: $active-color;
|
||||||
|
background-color: $active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: $color-neutral-60;
|
||||||
|
border-color: $color-neutral-60;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $filled {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
border-color: $main-color;
|
||||||
|
background-color: $main-color;
|
||||||
|
|
||||||
|
&:enabled {
|
||||||
|
&:hover {
|
||||||
|
border-color: $hover-color;
|
||||||
|
background-color: $hover-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
border-color: $active-color;
|
||||||
|
background-color: $active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
background-color: $color-neutral-60;
|
||||||
|
border-color: $color-neutral-60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
webapp/assets/_new/styles/resets.scss
Normal file
11
webapp/assets/_new/styles/resets.scss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
@ -4,6 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$color-primary: rgb(23, 181, 63);
|
$color-primary: rgb(23, 181, 63);
|
||||||
|
$color-primary-light: rgb(96, 214, 98);
|
||||||
|
$color-primary-dark: rgb(25, 122, 49);
|
||||||
$color-primary-active: rgb(25, 194, 67);
|
$color-primary-active: rgb(25, 194, 67);
|
||||||
$color-primary-inverse: rgb(241, 253, 244);
|
$color-primary-inverse: rgb(241, 253, 244);
|
||||||
$color-secondary: rgb(0, 142, 230);
|
$color-secondary: rgb(0, 142, 230);
|
||||||
@ -13,6 +15,8 @@
|
|||||||
$color-success-active: rgb(26, 203, 71);
|
$color-success-active: rgb(26, 203, 71);
|
||||||
$color-success-inverse: rgb(241, 253, 244);
|
$color-success-inverse: rgb(241, 253, 244);
|
||||||
$color-danger: rgb(219, 57, 36);
|
$color-danger: rgb(219, 57, 36);
|
||||||
|
$color-danger-light: rgb(242, 97, 65);
|
||||||
|
$color-danger-dark: rgb(158, 43, 28);
|
||||||
$color-danger-active: rgb(224, 81, 62);
|
$color-danger-active: rgb(224, 81, 62);
|
||||||
$color-danger-inverse: rgb(253, 243, 242);
|
$color-danger-inverse: rgb(253, 243, 242);
|
||||||
$color-warning: rgb(230, 121, 25);
|
$color-warning: rgb(230, 121, 25);
|
||||||
@ -236,6 +240,13 @@ $size-height-xlarge: 60px;
|
|||||||
$size-height-footer: 64px;
|
$size-height-footer: 64px;
|
||||||
$size-tappable-square: 44px;
|
$size-tappable-square: 44px;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tokens Size Width
|
||||||
|
* @presenter Spacing
|
||||||
|
*/
|
||||||
|
|
||||||
|
$size-width-paginate: 100px;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tokens Size Avatar
|
* @tokens Size Avatar
|
||||||
* @presenter Spacing
|
* @presenter Spacing
|
||||||
@ -246,6 +257,21 @@ $size-avatar-base: 44px;
|
|||||||
$size-avatar-large: 64px;
|
$size-avatar-large: 64px;
|
||||||
$size-avatar-x-large: 114px;
|
$size-avatar-x-large: 114px;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tokens Size Buttons
|
||||||
|
* @presenter Spacing
|
||||||
|
*/
|
||||||
|
|
||||||
|
$size-button-base: 36px;
|
||||||
|
$size-button-small: 26px;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tokens Size Icons
|
||||||
|
* @presenter Spacing
|
||||||
|
*/
|
||||||
|
|
||||||
|
$size-icon-base: 16px;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tokens Shadow
|
* @tokens Shadow
|
||||||
* @presenter Shadow
|
* @presenter Shadow
|
||||||
@ -291,6 +317,7 @@ $z-index-page-submenu: 2500;
|
|||||||
$z-index-page-header: 2000;
|
$z-index-page-header: 2000;
|
||||||
$z-index-page-sidebar: 1500;
|
$z-index-page-sidebar: 1500;
|
||||||
$z-index-sticky: 100;
|
$z-index-sticky: 100;
|
||||||
|
$z-index-post-card-link: 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tokens Media Query
|
* @tokens Media Query
|
||||||
|
|||||||
@ -175,3 +175,7 @@ hr {
|
|||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-arrow {
|
||||||
|
font-size: $font-size-xx-small;
|
||||||
|
}
|
||||||
|
|||||||
@ -3,16 +3,16 @@
|
|||||||
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'xx-small' }">
|
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'xx-small' }">
|
||||||
<div v-for="category in categories" :key="category.id">
|
<div v-for="category in categories" :key="category.id">
|
||||||
<ds-flex-item>
|
<ds-flex-item>
|
||||||
<ds-button
|
<base-button
|
||||||
size="small"
|
|
||||||
:data-test="categoryButtonsId(category.id)"
|
:data-test="categoryButtonsId(category.id)"
|
||||||
@click.prevent="toggleCategory(category.id)"
|
@click="toggleCategory(category.id)"
|
||||||
:primary="isActive(category.id)"
|
:filled="isActive(category.id)"
|
||||||
:disabled="isDisabled(category.id)"
|
:disabled="isDisabled(category.id)"
|
||||||
|
:icon="category.icon"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<base-icon :name="category.icon" />
|
|
||||||
{{ $t(`contribution.category.name.${category.slug}`) }}
|
{{ $t(`contribution.category.name.${category.slug}`) }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
</div>
|
</div>
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
|
|||||||
@ -74,7 +74,7 @@ describe('CommentForm.vue', () => {
|
|||||||
|
|
||||||
it('calls `clear` method when the cancel button is clicked', async () => {
|
it('calls `clear` method when the cancel button is clicked', async () => {
|
||||||
wrapper.vm.updateEditorContent('ok')
|
wrapper.vm.updateEditorContent('ok')
|
||||||
await wrapper.find('.cancelBtn').trigger('submit')
|
await wrapper.find('[data-test="cancel-button"]').trigger('submit')
|
||||||
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -162,13 +162,13 @@ describe('CommentForm.vue', () => {
|
|||||||
describe('cancel button is clicked', () => {
|
describe('cancel button is clicked', () => {
|
||||||
it('calls `closeEditWindow` method', async () => {
|
it('calls `closeEditWindow` method', async () => {
|
||||||
wrapper.vm.updateEditorContent('ok')
|
wrapper.vm.updateEditorContent('ok')
|
||||||
await wrapper.find('.cancelBtn').trigger('submit')
|
await wrapper.find('[data-test="cancel-button"]').trigger('submit')
|
||||||
expect(closeMethodSpy).toHaveBeenCalledTimes(1)
|
expect(closeMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits `showEditCommentMenu` event', async () => {
|
it('emits `showEditCommentMenu` event', async () => {
|
||||||
wrapper.vm.updateEditorContent('ok')
|
wrapper.vm.updateEditorContent('ok')
|
||||||
await wrapper.find('.cancelBtn').trigger('submit')
|
await wrapper.find('[data-test="cancel-button"]').trigger('submit')
|
||||||
expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]])
|
expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,28 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-form v-model="form" @submit="handleSubmit">
|
<ds-form v-model="form" @submit="handleSubmit" class="comment-form">
|
||||||
<template slot-scope="{ errors }">
|
<template slot-scope="{ errors }">
|
||||||
<ds-card>
|
<ds-card>
|
||||||
<!-- with client-only the content is not shown -->
|
<!-- with client-only the content is not shown -->
|
||||||
<hc-editor ref="editor" :users="users" :value="form.content" @input="updateEditorContent" />
|
<hc-editor ref="editor" :users="users" :value="form.content" @input="updateEditorContent" />
|
||||||
<ds-space />
|
<div class="buttons">
|
||||||
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
<base-button
|
||||||
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
:disabled="disabled && !update"
|
||||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '30%', xs: '30%' }">
|
@click="handleCancel"
|
||||||
<ds-button
|
data-test="cancel-button"
|
||||||
:disabled="disabled && !update"
|
danger
|
||||||
ghost
|
>
|
||||||
class="cancelBtn"
|
{{ $t('actions.cancel') }}
|
||||||
@click.prevent="handleCancel"
|
</base-button>
|
||||||
>
|
<base-button type="submit" :loading="loading" :disabled="disabled || errors" filled>
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('post.comment.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-flex-item>
|
</div>
|
||||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '40%', xs: '40%' }">
|
|
||||||
<ds-button type="submit" :loading="loading" :disabled="disabled || errors" primary>
|
|
||||||
{{ $t('post.comment.submit') }}
|
|
||||||
</ds-button>
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
@ -146,3 +140,17 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.comment-form {
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin: $space-small 0;
|
||||||
|
|
||||||
|
> .base-button {
|
||||||
|
margin-left: $space-x-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -63,12 +63,7 @@ describe('CommentList.vue', () => {
|
|||||||
|
|
||||||
it('displays a comments counter', () => {
|
it('displays a comments counter', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('span.ds-tag').text()).toEqual('1')
|
expect(wrapper.find('.count').text()).toEqual('1')
|
||||||
})
|
|
||||||
|
|
||||||
it('displays a comments counter', () => {
|
|
||||||
wrapper = Wrapper()
|
|
||||||
expect(wrapper.find('span.ds-tag').text()).toEqual('1')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('scrollToAnchor mixin', () => {
|
describe('scrollToAnchor mixin', () => {
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="comments">
|
<div id="comments" class="comment-list">
|
||||||
<h3 style="margin-top: -10px;">
|
<h3 class="title">
|
||||||
<counter-icon icon="comments" :count="post.comments.length">
|
<counter-icon icon="comments" :count="post.comments.length" />
|
||||||
{{ $t('common.comment', null, 0) }}
|
{{ $t('common.comment', null, 0) }}
|
||||||
</counter-icon>
|
|
||||||
</h3>
|
</h3>
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
<div v-if="post.comments && post.comments.length" id="comments" class="comments">
|
<div v-if="post.comments && post.comments.length" id="comments" class="comments">
|
||||||
@ -50,3 +49,15 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.comment-list {
|
||||||
|
> .title {
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
> .counter-icon {
|
||||||
|
margin-right: $space-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -46,7 +46,7 @@ describe('ContentMenu.vue', () => {
|
|||||||
store,
|
store,
|
||||||
localVue,
|
localVue,
|
||||||
})
|
})
|
||||||
menuToggle = wrapper.find('.content-menu-trigger')
|
menuToggle = wrapper.find('[data-test="content-menu-button"]')
|
||||||
menuToggle.trigger('click')
|
menuToggle.trigger('click')
|
||||||
return wrapper
|
return wrapper
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,14 @@
|
|||||||
<dropdown class="content-menu" :placement="placement" offset="5">
|
<dropdown class="content-menu" :placement="placement" offset="5">
|
||||||
<template slot="default" slot-scope="{ toggleMenu }">
|
<template slot="default" slot-scope="{ toggleMenu }">
|
||||||
<slot name="button" :toggleMenu="toggleMenu">
|
<slot name="button" :toggleMenu="toggleMenu">
|
||||||
<ds-button class="content-menu-trigger" size="small" ghost @click.prevent="toggleMenu">
|
<base-button
|
||||||
<base-icon name="ellipsis-v" />
|
data-test="content-menu-button"
|
||||||
</ds-button>
|
icon="ellipsis-v"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
ghost
|
||||||
|
@click="toggleMenu"
|
||||||
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
<div slot="popover" slot-scope="{ toggleMenu }" class="content-menu-popover">
|
<div slot="popover" slot-scope="{ toggleMenu }" class="content-menu-popover">
|
||||||
|
|||||||
@ -100,17 +100,12 @@
|
|||||||
|
|
||||||
<ds-space />
|
<ds-space />
|
||||||
<div slot="footer" style="text-align: right">
|
<div slot="footer" style="text-align: right">
|
||||||
<ds-button
|
<base-button data-test="cancel-button" :disabled="loading" @click="$router.back()" danger>
|
||||||
class="cancel-button"
|
|
||||||
:disabled="loading"
|
|
||||||
ghost
|
|
||||||
@click.prevent="$router.back()"
|
|
||||||
>
|
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('actions.cancel') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-button type="submit" icon="check" :loading="loading" :disabled="errors" primary>
|
<base-button type="submit" icon="check" :loading="loading" :disabled="errors" filled>
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</div>
|
</div>
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
</ds-card>
|
</ds-card>
|
||||||
|
|||||||
@ -81,7 +81,7 @@ describe('DeleteData.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('does not call the delete user mutation if deleteEnabled is false', () => {
|
it('does not call the delete user mutation if deleteEnabled is false', () => {
|
||||||
deleteAccountBtn = wrapper.find('.ds-button-danger')
|
deleteAccountBtn = wrapper.find('[data-test="delete-button"]')
|
||||||
deleteAccountBtn.trigger('click')
|
deleteAccountBtn.trigger('click')
|
||||||
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
|
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
@ -90,7 +90,7 @@ describe('DeleteData.vue', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
enableDeletionInput = wrapper.find('.enable-deletion-input input')
|
enableDeletionInput = wrapper.find('.enable-deletion-input input')
|
||||||
enableDeletionInput.setValue(deleteAccountName)
|
enableDeletionInput.setValue(deleteAccountName)
|
||||||
deleteAccountBtn = wrapper.find('.ds-button-danger')
|
deleteAccountBtn = wrapper.find('[data-test="delete-button"]')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('if deleteEnabled is true and only deletes user by default', () => {
|
it('if deleteEnabled is true and only deletes user by default', () => {
|
||||||
@ -168,7 +168,7 @@ describe('DeleteData.vue', () => {
|
|||||||
it('shows an error toaster when the mutation rejects', async () => {
|
it('shows an error toaster when the mutation rejects', async () => {
|
||||||
enableDeletionInput = wrapper.find('.enable-deletion-input input')
|
enableDeletionInput = wrapper.find('.enable-deletion-input input')
|
||||||
enableDeletionInput.setValue(deleteAccountName)
|
enableDeletionInput.setValue(deleteAccountName)
|
||||||
deleteAccountBtn = wrapper.find('.ds-button-danger')
|
deleteAccountBtn = wrapper.find('[data-test="delete-button"]')
|
||||||
await deleteAccountBtn.trigger('click')
|
await deleteAccountBtn.trigger('click')
|
||||||
// second submission causes mutation to reject
|
// second submission causes mutation to reject
|
||||||
await deleteAccountBtn.trigger('click')
|
await deleteAccountBtn.trigger('click')
|
||||||
|
|||||||
@ -55,16 +55,19 @@
|
|||||||
<ds-space margin-bottom="xx-small" />
|
<ds-space margin-bottom="xx-small" />
|
||||||
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'large' }">
|
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'large' }">
|
||||||
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1.75 }">
|
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1.75 }">
|
||||||
<ds-input
|
<ds-input v-model="enableDeletionValue" class="enable-deletion-input" />
|
||||||
v-model="enableDeletionValue"
|
|
||||||
@input="enableDeletion"
|
|
||||||
class="enable-deletion-input"
|
|
||||||
/>
|
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1 }">
|
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '100%', lg: 1 }">
|
||||||
<ds-button icon="trash" danger :disabled="!deleteEnabled" @click="handleSubmit">
|
<base-button
|
||||||
|
icon="trash"
|
||||||
|
danger
|
||||||
|
filled
|
||||||
|
:disabled="!deleteEnabled"
|
||||||
|
data-test="delete-button"
|
||||||
|
@click="handleSubmit"
|
||||||
|
>
|
||||||
{{ $t('settings.deleteUserAccount.name') }}
|
{{ $t('settings.deleteUserAccount.name') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
@ -82,7 +85,6 @@ export default {
|
|||||||
return {
|
return {
|
||||||
deleteContributions: false,
|
deleteContributions: false,
|
||||||
deleteComments: false,
|
deleteComments: false,
|
||||||
deleteEnabled: false,
|
|
||||||
enableDeletionValue: null,
|
enableDeletionValue: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -90,16 +92,14 @@ export default {
|
|||||||
...mapGetters({
|
...mapGetters({
|
||||||
currentUser: 'auth/user',
|
currentUser: 'auth/user',
|
||||||
}),
|
}),
|
||||||
|
deleteEnabled() {
|
||||||
|
return this.enableDeletionValue === this.currentUser.name
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
logout: 'auth/logout',
|
logout: 'auth/logout',
|
||||||
}),
|
}),
|
||||||
enableDeletion() {
|
|
||||||
if (this.enableDeletionValue === this.currentUser.name) {
|
|
||||||
this.deleteEnabled = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
const resourceArgs = []
|
const resourceArgs = []
|
||||||
if (this.deleteContributions) {
|
if (this.deleteContributions) {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ describe('DonationInfo.vue', () => {
|
|||||||
it('displays a call to action button', () => {
|
it('displays a call to action button', () => {
|
||||||
expect(
|
expect(
|
||||||
Wrapper()
|
Wrapper()
|
||||||
.find('.ds-button')
|
.find('.base-button')
|
||||||
.text(),
|
.text(),
|
||||||
).toBe('donations.donate-now')
|
).toBe('donations.donate-now')
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="donation-info">
|
<div class="donation-info">
|
||||||
<progress-bar :title="title" :label="label" :goal="goal" :progress="progress" />
|
<progress-bar :title="title" :label="label" :goal="goal" :progress="progress" />
|
||||||
<a target="_blank" href="https://human-connection.org/spenden/">
|
<a target="_blank" href="https://human-connection.org/spenden/">
|
||||||
<ds-button primary>{{ $t('donations.donate-now') }}</ds-button>
|
<base-button filled>{{ $t('donations.donate-now') }}</base-button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -65,10 +65,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-arrow {
|
|
||||||
font-size: $font-size-xx-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -326,85 +326,4 @@ li > p {
|
|||||||
margin: 0 0 $space-x-small;
|
margin: 0 0 $space-x-small;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ProseMirror[contenteditable='false'] {
|
|
||||||
.embed-close-button {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-container {
|
|
||||||
position: relative;
|
|
||||||
padding: 0;
|
|
||||||
margin: $space-small auto;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: $border-radius-base;
|
|
||||||
border: 1px solid $color-neutral-70;
|
|
||||||
background-color: $color-neutral-90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-content {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: $space-small 0 0 $space-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
p,
|
|
||||||
a {
|
|
||||||
display: block;
|
|
||||||
margin: 0 0 0 $space-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-preview-image {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
max-height: 450px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-preview-image--clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-html {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-overlay {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
padding: $space-large;
|
|
||||||
background-color: $color-neutral-100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-buttons {
|
|
||||||
button {
|
|
||||||
margin-right: $space-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-checkbox {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
input {
|
|
||||||
margin-right: $space-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-close-button {
|
|
||||||
position: absolute;
|
|
||||||
top: $space-x-small;
|
|
||||||
right: $space-x-small;
|
|
||||||
background-color: rgba(250, 249, 250, 0.6);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-button size="small" :ghost="!isActive" @click.prevent="onClick" :icon="icon">
|
<base-button size="small" circle :ghost="!isActive" @click="onClick" :icon="icon">
|
||||||
<span v-if="label">{{ label }}</span>
|
<span v-if="label">{{ label }}</span>
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -65,13 +65,13 @@ describe('EmbedComponent.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('shows the description', () => {
|
it('shows the description', () => {
|
||||||
expect(wrapper.find('.embed-content p').text()).toBe(
|
expect(wrapper.find('.content p').text()).toBe(
|
||||||
'Salut tout le monde ! Aujourd’hui, une vidéo sur le scepticisme, nous allons parler médiumnité avec le cas de Bruno CHARVET : « Bruno, un nouveau message ». Merci de rester respectueux dans les commentaires : SOURCES : Les sources des vi...',
|
'Salut tout le monde ! Aujourd’hui, une vidéo sur le scepticisme, nous allons parler médiumnité avec le cas de Bruno CHARVET : « Bruno, un nouveau message ». Merci de rester respectueux dans les commentaires : SOURCES : Les sources des vi...',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows preview Images for link', () => {
|
it('shows preview Images for link', () => {
|
||||||
expect(wrapper.find('.embed-preview-image').exists()).toBe(true)
|
expect(wrapper.find('.preview').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ describe('EmbedComponent.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('show the desciption', () => {
|
it('show the desciption', () => {
|
||||||
expect(wrapper.find('.embed-content p').text()).toBe(
|
expect(wrapper.find('.content p').text()).toBe(
|
||||||
'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
|
'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -121,12 +121,12 @@ describe('EmbedComponent.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('shows a simple link when a user closes the embed preview', () => {
|
it('shows a simple link when a user closes the embed preview', () => {
|
||||||
wrapper.find('.embed-close-button').trigger('click')
|
wrapper.find('.close-button').trigger('click')
|
||||||
expect(wrapper.vm.showLinkOnly).toBe(true)
|
expect(wrapper.vm.showLinkOnly).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('opens the data privacy overlay when a user clicks on the preview image', () => {
|
it('opens the data privacy overlay when a user clicks on the preview image', () => {
|
||||||
wrapper.find('.embed-preview-image--clickable').trigger('click')
|
wrapper.find('.preview.--clickable').trigger('click')
|
||||||
expect(wrapper.vm.showOverlay).toBe(true)
|
expect(wrapper.vm.showOverlay).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -135,19 +135,19 @@ describe('EmbedComponent.vue', () => {
|
|||||||
wrapper.setData({ showOverlay: true })
|
wrapper.setData({ showOverlay: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('when user agress', () => {
|
it('when user agrees', () => {
|
||||||
wrapper.find('.ds-button-primary').trigger('click')
|
wrapper.find('[data-test="play-now-button"]').trigger('click')
|
||||||
expect(wrapper.vm.showEmbed).toBe(true)
|
expect(wrapper.vm.showEmbed).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not show iframe when user clicks to cancel', () => {
|
it('does not show iframe when user clicks to cancel', () => {
|
||||||
wrapper.find('.ds-button-ghost').trigger('click')
|
wrapper.find('[data-test="cancel-button"]').trigger('click')
|
||||||
expect(wrapper.vm.showEmbed).toBe(false)
|
expect(wrapper.vm.showEmbed).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("doesn't set permanently", () => {
|
describe("doesn't set permanently", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper.find('.ds-button-primary').trigger('click')
|
wrapper.find('[data-test="play-now-button"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it("if user doesn't give consent", () => {
|
it("if user doesn't give consent", () => {
|
||||||
@ -162,7 +162,7 @@ describe('EmbedComponent.vue', () => {
|
|||||||
describe('sets permanently', () => {
|
describe('sets permanently', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper.find('input[type=checkbox]').trigger('click')
|
wrapper.find('input[type=checkbox]').trigger('click')
|
||||||
wrapper.find('.ds-button-primary').trigger('click')
|
wrapper.find('[data-test="play-now-button"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('changes setting permanetly when user requests', () => {
|
it('changes setting permanetly when user requests', () => {
|
||||||
@ -194,7 +194,7 @@ describe('EmbedComponent.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('does not display image to click', () => {
|
it('does not display image to click', () => {
|
||||||
expect(wrapper.find('.embed-preview-image--clickable').exists()).toBe(false)
|
expect(wrapper.find('.preview.--clickable').exists()).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,17 +2,17 @@
|
|||||||
<a v-if="showLinkOnly" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
|
<a v-if="showLinkOnly" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
|
||||||
{{ dataEmbedUrl }}
|
{{ dataEmbedUrl }}
|
||||||
</a>
|
</a>
|
||||||
<ds-container v-else width="small" class="embed-container">
|
<ds-container v-else width="small" class="embed-component">
|
||||||
<section class="embed-content">
|
<section class="content">
|
||||||
<div v-if="showEmbed" v-html="embedHtml" class="embed-html" />
|
<div v-if="showEmbed" v-html="embedHtml" class="html" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<img
|
<img
|
||||||
v-if="embedHtml && embedImage"
|
v-if="embedHtml && embedImage"
|
||||||
:src="embedImage"
|
:src="embedImage"
|
||||||
class="embed-preview-image embed-preview-image--clickable"
|
class="preview --clickable"
|
||||||
@click.prevent="openOverlay()"
|
@click.prevent="openOverlay()"
|
||||||
/>
|
/>
|
||||||
<img v-else-if="embedImage" :src="embedImage" class="embed-preview-image" />
|
<img v-else-if="embedImage" :src="embedImage" class="preview" />
|
||||||
</template>
|
</template>
|
||||||
<h4 v-if="embedTitle">{{ embedTitle }}</h4>
|
<h4 v-if="embedTitle">{{ embedTitle }}</h4>
|
||||||
<p v-if="embedDescription">{{ embedDescription }}</p>
|
<p v-if="embedDescription">{{ embedDescription }}</p>
|
||||||
@ -20,25 +20,27 @@
|
|||||||
{{ dataEmbedUrl }}
|
{{ dataEmbedUrl }}
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
<aside v-if="showOverlay" class="embed-overlay">
|
<aside v-if="showOverlay" class="overlay">
|
||||||
<h3>{{ $t('editor.embed.data_privacy_warning') }}</h3>
|
<h3>{{ $t('editor.embed.data_privacy_warning') }}</h3>
|
||||||
<ds-text>{{ $t('editor.embed.data_privacy_info') }} {{ embedPublisher }}</ds-text>
|
<ds-text>{{ $t('editor.embed.data_privacy_info') }} {{ embedPublisher }}</ds-text>
|
||||||
<div class="embed-buttons">
|
<div class="buttons">
|
||||||
<ds-button primary @click.prevent="allowEmbed()">
|
<base-button primary @click="allowEmbed()" data-test="play-now-button">
|
||||||
{{ $t('editor.embed.play_now') }}
|
{{ $t('editor.embed.play_now') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-button ghost @click.prevent="closeOverlay()">{{ $t('actions.cancel') }}</ds-button>
|
<base-button @click="closeOverlay()" data-test="cancel-button">
|
||||||
|
{{ $t('actions.cancel') }}
|
||||||
|
</base-button>
|
||||||
</div>
|
</div>
|
||||||
<label class="embed-checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" v-model="checkedAlwaysAllowEmbeds" />
|
<input type="checkbox" v-model="checkedAlwaysAllowEmbeds" />
|
||||||
<span>{{ $t('editor.embed.always_allow') }}</span>
|
<span>{{ $t('editor.embed.always_allow') }}</span>
|
||||||
</label>
|
</label>
|
||||||
</aside>
|
</aside>
|
||||||
<ds-button
|
<base-button
|
||||||
icon="close"
|
icon="close"
|
||||||
ghost
|
|
||||||
size="small"
|
size="small"
|
||||||
class="embed-close-button"
|
circle
|
||||||
|
class="close-button"
|
||||||
@click.prevent="removeEmbed()"
|
@click.prevent="removeEmbed()"
|
||||||
/>
|
/>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
@ -151,3 +153,86 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.embed-component {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
margin: $space-small auto;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: $border-radius-base;
|
||||||
|
border: 1px solid $color-neutral-70;
|
||||||
|
background-color: $color-neutral-90;
|
||||||
|
|
||||||
|
> .content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: $space-small 0 0 $space-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
margin: 0 0 0 $space-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
.html {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview.--clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
padding: $space-large;
|
||||||
|
background-color: $color-neutral-100;
|
||||||
|
|
||||||
|
> .buttons {
|
||||||
|
.base-button {
|
||||||
|
margin-right: $space-small;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .checkbox {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin-right: $space-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: $space-x-small;
|
||||||
|
right: $space-x-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror[contenteditable='false'] {
|
||||||
|
.close-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
61
webapp/components/EmotionButton/EmotionButton.vue
Normal file
61
webapp/components/EmotionButton/EmotionButton.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="emotion-button">
|
||||||
|
<base-button :id="emotion" circle ghost @click="$emit('toggleEmotion', emotion)">
|
||||||
|
<img class="image" :src="emojiPath" />
|
||||||
|
</base-button>
|
||||||
|
<label class="label" :for="emotion">{{ $t(`contribution.emotions-label.${emotion}`) }}</label>
|
||||||
|
<p v-if="emotionCount !== null" class="count">{{ emotionCount }}x</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'EmotionButton',
|
||||||
|
props: {
|
||||||
|
emojiPath: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
emotion: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
emotionCount: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.emotion-button {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> .base-button {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
padding: $space-xxx-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .label {
|
||||||
|
margin-top: $space-x-small;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .count {
|
||||||
|
margin: $space-x-small 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
max-width: $size-button-base;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,27 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-flex :gutter="{ lg: 'large' }" class="emotions-flex">
|
<div class="emotions-button-group">
|
||||||
<div v-for="emotion in Object.keys(PostsEmotionsCountByEmotion)" :key="emotion">
|
<emotion-button
|
||||||
<ds-flex-item :width="{ lg: '100%' }">
|
v-for="emotion in Object.keys(PostsEmotionsCountByEmotion)"
|
||||||
<hc-emotions-button
|
:key="emotion"
|
||||||
@toggleEmotion="toggleEmotion"
|
:emojiPath="iconPath(emotion)"
|
||||||
:PostsEmotionsCountByEmotion="PostsEmotionsCountByEmotion"
|
:emotion="emotion"
|
||||||
:iconPath="iconPath(emotion)"
|
:emotionCount="PostsEmotionsCountByEmotion[emotion]"
|
||||||
:emotion="emotion"
|
@toggleEmotion="toggleEmotion"
|
||||||
/>
|
/>
|
||||||
</ds-flex-item>
|
</div>
|
||||||
</div>
|
|
||||||
</ds-flex>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import HcEmotionsButton from '~/components/EmotionsButton/EmotionsButton'
|
import EmotionButton from '~/components/EmotionButton/EmotionButton'
|
||||||
import { PostsEmotionsByCurrentUser } from '~/graphql/PostQuery.js'
|
import { PostsEmotionsByCurrentUser } from '~/graphql/PostQuery.js'
|
||||||
import PostMutations from '~/graphql/PostMutations.js'
|
import PostMutations from '~/graphql/PostMutations.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
HcEmotionsButton,
|
EmotionButton,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
post: { type: Object, default: () => {} },
|
post: { type: Object, default: () => {} },
|
||||||
@ -113,3 +112,9 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.emotions-button-group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<ds-button size="large" ghost @click="toggleEmotion(emotion)" class="emotions-buttons">
|
|
||||||
<img :src="iconPath" width="40" />
|
|
||||||
</ds-button>
|
|
||||||
<ds-space margin-bottom="xx-small" />
|
|
||||||
<div class="emotions-mobile-space">
|
|
||||||
<p class="emotions-label">{{ $t(`contribution.emotions-label.${emotion}`) }}</p>
|
|
||||||
<p style="display: inline" :key="PostsEmotionsCountByEmotion[emotion]">
|
|
||||||
{{ PostsEmotionsCountByEmotion[emotion] }}x
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
iconPath: { type: String, default: null },
|
|
||||||
PostsEmotionsCountByEmotion: { type: Object, default: () => {} },
|
|
||||||
emotion: { type: String, default: null },
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleEmotion(emotion) {
|
|
||||||
this.$emit('toggleEmotion', emotion)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss">
|
|
||||||
.emotions-flex {
|
|
||||||
justify-content: space-evenly;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotions-label {
|
|
||||||
font-size: $font-size-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotions-buttons {
|
|
||||||
&:hover {
|
|
||||||
background-color: $background-color-base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 960px) {
|
|
||||||
.emotions-mobile-space {
|
|
||||||
margin-bottom: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,30 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-space margin-top="large" margin-bottom="xxx-small">
|
<ds-form
|
||||||
<ds-form
|
class="enter-nonce"
|
||||||
v-model="formData"
|
v-model="formData"
|
||||||
:schema="formSchema"
|
:schema="formSchema"
|
||||||
@submit="handleSubmitVerify"
|
@submit="handleSubmitVerify"
|
||||||
@input="handleInput"
|
@input="handleInput"
|
||||||
@input-valid="handleInputValid"
|
@input-valid="handleInputValid"
|
||||||
>
|
>
|
||||||
<ds-input
|
<ds-input
|
||||||
:placeholder="$t('components.enter-nonce.form.nonce')"
|
:placeholder="$t('components.enter-nonce.form.nonce')"
|
||||||
model="nonce"
|
model="nonce"
|
||||||
name="nonce"
|
name="nonce"
|
||||||
id="nonce"
|
id="nonce"
|
||||||
icon="question-circle"
|
icon="question-circle"
|
||||||
/>
|
/>
|
||||||
<ds-space margin-botton="large">
|
<ds-text>
|
||||||
<ds-text>
|
{{ $t('components.enter-nonce.form.description') }}
|
||||||
{{ $t('components.enter-nonce.form.description') }}
|
</ds-text>
|
||||||
</ds-text>
|
<base-button :disabled="disabled" filled name="submit" type="submit">
|
||||||
</ds-space>
|
{{ $t('components.enter-nonce.form.next') }}
|
||||||
<ds-button :disabled="disabled" primary fullwidth name="submit" type="submit">
|
</base-button>
|
||||||
{{ $t('components.enter-nonce.form.next') }}
|
|
||||||
</ds-button>
|
|
||||||
</ds-form>
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</ds-space>
|
</ds-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -64,3 +61,11 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.enter-nonce {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: $space-large 0 $space-xxx-small 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -39,7 +39,7 @@ describe('FilterMenu.vue', () => {
|
|||||||
|
|
||||||
describe('click "clear-search-button" button', () => {
|
describe('click "clear-search-button" button', () => {
|
||||||
it('emits clearSearch', () => {
|
it('emits clearSearch', () => {
|
||||||
wrapper.find({ name: 'clear-search-button' }).trigger('click')
|
wrapper.find('[name="clear-search-button"]').trigger('click')
|
||||||
expect(wrapper.emitted().clearSearch).toHaveLength(1)
|
expect(wrapper.emitted().clearSearch).toHaveLength(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -6,15 +6,16 @@
|
|||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item>
|
<ds-flex-item>
|
||||||
<div class="filter-menu-buttons">
|
<div class="filter-menu-buttons">
|
||||||
<ds-button
|
<base-button
|
||||||
|
name="clear-search-button"
|
||||||
|
icon="close"
|
||||||
|
circle
|
||||||
|
@click="clearSearch"
|
||||||
v-tooltip="{
|
v-tooltip="{
|
||||||
content: this.$t('filter-menu.clearSearch'),
|
content: this.$t('filter-menu.clearSearch'),
|
||||||
placement: 'left',
|
placement: 'left',
|
||||||
delay: { show: 500 },
|
delay: { show: 500 },
|
||||||
}"
|
}"
|
||||||
name="clear-search-button"
|
|
||||||
icon="close"
|
|
||||||
@click="clearSearch"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
|
|||||||
@ -12,10 +12,11 @@
|
|||||||
<ds-flex>
|
<ds-flex>
|
||||||
<ds-flex-item width="10%" />
|
<ds-flex-item width="10%" />
|
||||||
<ds-flex-item width="100%">
|
<ds-flex-item width="100%">
|
||||||
<ds-button
|
<base-button
|
||||||
|
circle
|
||||||
icon="check"
|
icon="check"
|
||||||
@click.stop.prevent="resetCategories"
|
@click="resetCategories"
|
||||||
:primary="!filteredCategoryIds.length"
|
:filled="!filteredCategoryIds.length"
|
||||||
/>
|
/>
|
||||||
<ds-flex-item>
|
<ds-flex-item>
|
||||||
<label class="category-labels">{{ $t('filter-posts.categories.all') }}</label>
|
<label class="category-labels">{{ $t('filter-posts.categories.all') }}</label>
|
||||||
@ -37,10 +38,11 @@
|
|||||||
<ds-flex v-for="category in chunk[index - 1]" :key="category.id" class="categories-menu">
|
<ds-flex v-for="category in chunk[index - 1]" :key="category.id" class="categories-menu">
|
||||||
<ds-flex class="categories-menu">
|
<ds-flex class="categories-menu">
|
||||||
<ds-flex-item width="100%" class="categories-menu-item">
|
<ds-flex-item width="100%" class="categories-menu-item">
|
||||||
<ds-button
|
<base-button
|
||||||
|
circle
|
||||||
:icon="category.icon"
|
:icon="category.icon"
|
||||||
:primary="filteredCategoryIds.includes(category.id)"
|
:filled="filteredCategoryIds.includes(category.id)"
|
||||||
@click.stop.prevent="toggleCategory(category.id)"
|
@click="toggleCategory(category.id)"
|
||||||
/>
|
/>
|
||||||
<ds-space margin-bottom="small" />
|
<ds-space margin-bottom="small" />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
|
|||||||
@ -92,7 +92,7 @@ describe('FilterPosts.vue', () => {
|
|||||||
it('starts with all categories button active', () => {
|
it('starts with all categories button active', () => {
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
allCategoriesButton = wrapper.findAll('button').at(1)
|
allCategoriesButton = wrapper.findAll('button').at(1)
|
||||||
expect(allCategoriesButton.attributes().class).toContain('ds-button-primary')
|
expect(allCategoriesButton.attributes().class).toContain('--filled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls TOGGLE_CATEGORY when clicked', () => {
|
it('calls TOGGLE_CATEGORY when clicked', () => {
|
||||||
@ -111,35 +111,35 @@ describe('FilterPosts.vue', () => {
|
|||||||
expect(mutations['posts/TOGGLE_LANGUAGE']).toHaveBeenCalledWith({}, 'en')
|
expect(mutations['posts/TOGGLE_LANGUAGE']).toHaveBeenCalledWith({}, 'en')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets category button attribute `primary` when corresponding category is filtered', () => {
|
it('sets category button attribute `filled` when corresponding category is filtered', () => {
|
||||||
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
|
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
democracyAndPoliticsButton = wrapper.findAll('button').at(4)
|
democracyAndPoliticsButton = wrapper.findAll('button').at(4)
|
||||||
expect(democracyAndPoliticsButton.attributes().class).toContain('ds-button-primary')
|
expect(democracyAndPoliticsButton.attributes().class).toContain('--filled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets language button attribute `primary` when corresponding language is filtered', () => {
|
it('sets language button attribute `filled` when corresponding language is filtered', () => {
|
||||||
getters['posts/filteredLanguageCodes'] = jest.fn(() => ['es'])
|
getters['posts/filteredLanguageCodes'] = jest.fn(() => ['es'])
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
spanishButton = wrapper
|
spanishButton = wrapper
|
||||||
.findAll('button.language-buttons')
|
.findAll('button.language-buttons')
|
||||||
.at(languages.findIndex(l => l.code === 'es'))
|
.at(languages.findIndex(l => l.code === 'es'))
|
||||||
expect(spanishButton.attributes().class).toContain('ds-button-primary')
|
expect(spanishButton.attributes().class).toContain('--filled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets "filter-by-followed-authors-only" button attribute `primary`', () => {
|
it('sets "filter-by-followed" button attribute `filled`', () => {
|
||||||
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
expect(
|
expect(wrapper.find('.base-button[data-test="filter-by-followed"]').classes('--filled')).toBe(
|
||||||
wrapper.find({ name: 'filter-by-followed-authors-only' }).classes('ds-button-primary'),
|
true,
|
||||||
).toBe(true)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('click "filter-by-followed-authors-only" button', () => {
|
describe('click "filter-by-followed" button', () => {
|
||||||
let wrapper
|
let wrapper
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = openFilterPosts()
|
wrapper = openFilterPosts()
|
||||||
wrapper.find({ name: 'filter-by-followed-authors-only' }).trigger('click')
|
wrapper.find('.base-button[data-test="filter-by-followed"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls TOGGLE_FILTER_BY_FOLLOWED', () => {
|
it('calls TOGGLE_FILTER_BY_FOLLOWED', () => {
|
||||||
@ -150,7 +150,7 @@ describe('FilterPosts.vue', () => {
|
|||||||
describe('click on an "emotions-buttons" button', () => {
|
describe('click on an "emotions-buttons" button', () => {
|
||||||
it('calls TOGGLE_EMOTION when clicked', () => {
|
it('calls TOGGLE_EMOTION when clicked', () => {
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
happyEmotionButton = wrapper.findAll('button.emotions-buttons').at(1)
|
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
||||||
happyEmotionButton.trigger('click')
|
happyEmotionButton.trigger('click')
|
||||||
expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
|
expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
|
||||||
})
|
})
|
||||||
@ -158,7 +158,7 @@ describe('FilterPosts.vue', () => {
|
|||||||
it('sets the attribute `src` to colorized image', () => {
|
it('sets the attribute `src` to colorized image', () => {
|
||||||
getters['posts/filteredByEmotions'] = jest.fn(() => ['happy'])
|
getters['posts/filteredByEmotions'] = jest.fn(() => ['happy'])
|
||||||
const wrapper = openFilterPosts()
|
const wrapper = openFilterPosts()
|
||||||
happyEmotionButton = wrapper.findAll('button.emotions-buttons').at(1)
|
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
||||||
const happyEmotionButtonImage = happyEmotionButton.find('img')
|
const happyEmotionButtonImage = happyEmotionButton.find('img')
|
||||||
expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg')
|
expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg')
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<dropdown ref="menu" :placement="placement" :offset="offset">
|
<dropdown ref="menu" :placement="placement" :offset="offset">
|
||||||
<ds-button
|
<base-button
|
||||||
slot="default"
|
slot="default"
|
||||||
icon="filter"
|
icon="filter"
|
||||||
:primary="filterActive"
|
:filled="filterActive"
|
||||||
:ghost="!filterActive"
|
:ghost="!filterActive"
|
||||||
slot-scope="{ toggleMenu }"
|
slot-scope="{ toggleMenu }"
|
||||||
@click.prevent="toggleMenu()"
|
@click.prevent="toggleMenu()"
|
||||||
>
|
>
|
||||||
<base-icon class="dropdown-arrow" name="angle-down" />
|
<base-icon class="dropdown-arrow" name="angle-down" />
|
||||||
</ds-button>
|
</base-button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<ds-container>
|
<ds-container>
|
||||||
<categories-filter-menu-items :chunk="chunk" />
|
<categories-filter-menu-items :chunk="chunk" />
|
||||||
|
|||||||
@ -6,58 +6,42 @@
|
|||||||
</ds-flex>
|
</ds-flex>
|
||||||
<ds-flex :gutter="{ lg: 'large' }">
|
<ds-flex :gutter="{ lg: 'large' }">
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
:width="{ base: '100%', sm: '100%', md: '100%', lg: '10%' }"
|
:width="{ base: '100%', sm: '100%', md: '10%', lg: '10%' }"
|
||||||
class="categories-menu-item"
|
class="follow-filter"
|
||||||
>
|
>
|
||||||
<ds-flex>
|
<base-button
|
||||||
<ds-flex-item width="10%" />
|
data-test="filter-by-followed"
|
||||||
<ds-space margin-bottom="xx-small" />
|
icon="user-plus"
|
||||||
<ds-flex-item width="100%">
|
circle
|
||||||
<div class="follow-button">
|
:filled="filteredByUsersFollowed"
|
||||||
<ds-button
|
@click="toggleFilteredByFollowed(user.id)"
|
||||||
v-tooltip="{
|
v-tooltip="{
|
||||||
content: this.$t('contribution.filterFollow'),
|
content: this.$t('contribution.filterFollow'),
|
||||||
placement: 'left',
|
placement: 'left',
|
||||||
delay: { show: 500 },
|
delay: { show: 500 },
|
||||||
}"
|
}"
|
||||||
name="filter-by-followed-authors-only"
|
/>
|
||||||
icon="user-plus"
|
<label class="follow-label">{{ $t('filter-posts.followers.label') }}</label>
|
||||||
:primary="filteredByUsersFollowed"
|
|
||||||
@click="toggleFilteredByFollowed(user.id)"
|
|
||||||
/>
|
|
||||||
<ds-space margin-bottom="x-small" />
|
|
||||||
<ds-flex-item>
|
|
||||||
<label class="follow-label">{{ $t('filter-posts.followers.label') }}</label>
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-space />
|
|
||||||
</div>
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<div v-for="emotion in emotionsArray" :key="emotion">
|
<emotion-button
|
||||||
<ds-flex-item :width="{ lg: '100%' }">
|
v-for="emotion in emotionsArray"
|
||||||
<ds-button
|
:key="emotion"
|
||||||
size="large"
|
:emojiPath="iconPath(emotion)"
|
||||||
ghost
|
:emotion="emotion"
|
||||||
@click="toogleFilteredByEmotions(emotion)"
|
@toggleEmotion="toogleFilteredByEmotions(emotion)"
|
||||||
class="emotions-buttons"
|
/>
|
||||||
>
|
|
||||||
<img :src="iconPath(emotion)" width="40" />
|
|
||||||
</ds-button>
|
|
||||||
<ds-space margin-bottom="x-small" />
|
|
||||||
<ds-flex-item class="emotions-mobile-space text-center">
|
|
||||||
<label class="emotions-label">{{ $t(`contribution.emotions-label.${emotion}`) }}</label>
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex-item>
|
|
||||||
</div>
|
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import EmotionButton from '~/components/EmotionButton/EmotionButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
EmotionButton,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
user: { type: Object, required: true },
|
user: { type: Object, required: true },
|
||||||
},
|
},
|
||||||
@ -95,13 +79,22 @@ export default {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.follow-filter.ds-flex-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: $space-base;
|
||||||
|
|
||||||
|
> .follow-label {
|
||||||
|
margin-top: $space-x-small;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 960px) {
|
@media only screen and (max-width: 960px) {
|
||||||
#filter-posts-header {
|
#filter-posts-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.follow-button {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
|
|||||||
@ -12,10 +12,11 @@
|
|||||||
<ds-flex>
|
<ds-flex>
|
||||||
<ds-flex-item width="10%" />
|
<ds-flex-item width="10%" />
|
||||||
<ds-flex-item width="100%">
|
<ds-flex-item width="100%">
|
||||||
<ds-button
|
<base-button
|
||||||
icon="check"
|
icon="check"
|
||||||
@click.stop.prevent="resetLanguages"
|
circle
|
||||||
:primary="!filteredLanguageCodes.length"
|
:filled="!filteredLanguageCodes.length"
|
||||||
|
@click="resetLanguages"
|
||||||
/>
|
/>
|
||||||
<ds-flex-item>
|
<ds-flex-item>
|
||||||
<label class="language-labels">{{ $t('filter-posts.language.all') }}</label>
|
<label class="language-labels">{{ $t('filter-posts.language.all') }}</label>
|
||||||
@ -32,13 +33,14 @@
|
|||||||
<ds-flex v-for="language in locales" :key="language.code" class="languages-menu">
|
<ds-flex v-for="language in locales" :key="language.code" class="languages-menu">
|
||||||
<ds-flex class="languages-menu">
|
<ds-flex class="languages-menu">
|
||||||
<ds-flex-item width="100%" class="language-menu-item">
|
<ds-flex-item width="100%" class="language-menu-item">
|
||||||
<ds-button
|
<base-button
|
||||||
class="language-buttons"
|
class="language-buttons"
|
||||||
:primary="filteredLanguageCodes.includes(language.code)"
|
circle
|
||||||
@click.stop.prevent="toggleLanguage(language.code)"
|
:filled="filteredLanguageCodes.includes(language.code)"
|
||||||
|
@click="toggleLanguage(language.code)"
|
||||||
>
|
>
|
||||||
{{ language.code.toUpperCase() }}
|
{{ language.code.toUpperCase() }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-space margin-bottom="small" />
|
<ds-space margin-bottom="small" />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex>
|
<ds-flex>
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-button
|
<base-button
|
||||||
|
class="follow-button"
|
||||||
:disabled="disabled || !followId"
|
:disabled="disabled || !followId"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:icon="icon"
|
:icon="icon"
|
||||||
:primary="isFollowed && !hovered"
|
:filled="isFollowed && !hovered"
|
||||||
:danger="isFollowed && hovered"
|
:danger="isFollowed && hovered"
|
||||||
fullwidth
|
|
||||||
@mouseenter.native="onHover"
|
@mouseenter.native="onHover"
|
||||||
@mouseleave.native="hovered = false"
|
@mouseleave.native="hovered = false"
|
||||||
@click.prevent="toggle"
|
@click.prevent="toggle"
|
||||||
>
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -83,3 +83,10 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.follow-button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ds-space class="load-more" margin-top="large" style="text-align: center">
|
|
||||||
<ds-button :loading="loading" icon="arrow-down" ghost @click="$emit('click')">
|
|
||||||
{{ $t('actions.loadMore') }}
|
|
||||||
</ds-button>
|
|
||||||
</ds-space>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
loading: { type: Boolean, default: false },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -50,16 +50,9 @@
|
|||||||
<ds-space margin-bottom="large">
|
<ds-space margin-bottom="large">
|
||||||
<nuxt-link to="/password-reset/request">{{ $t('login.forgotPassword') }}</nuxt-link>
|
<nuxt-link to="/password-reset/request">{{ $t('login.forgotPassword') }}</nuxt-link>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-button
|
<base-button :loading="pending" filled name="submit" type="submit" icon="sign-in">
|
||||||
:loading="pending"
|
|
||||||
primary
|
|
||||||
fullwidth
|
|
||||||
name="submit"
|
|
||||||
type="submit"
|
|
||||||
icon="sign-in"
|
|
||||||
>
|
|
||||||
{{ $t('login.login') }}
|
{{ $t('login.login') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-space margin-top="large" margin-bottom="x-small">
|
<ds-space margin-top="large" margin-bottom="x-small">
|
||||||
{{ $t('login.no-account') }}
|
{{ $t('login.no-account') }}
|
||||||
<nuxt-link to="/registration/signup">{{ $t('login.register') }}</nuxt-link>
|
<nuxt-link to="/registration/signup">{{ $t('login.register') }}</nuxt-link>
|
||||||
@ -113,6 +106,11 @@ export default {
|
|||||||
}
|
}
|
||||||
.login-card {
|
.login-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
.base-button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.login-locale-switch {
|
.login-locale-switch {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@ -10,11 +10,16 @@
|
|||||||
<p v-html="message" />
|
<p v-html="message" />
|
||||||
|
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button class="cancel" :icon="modalData.buttons.cancel.icon" @click="cancel">
|
<base-button
|
||||||
|
class="cancel"
|
||||||
|
:danger="!modalData.buttons.confirm.danger"
|
||||||
|
:icon="modalData.buttons.cancel.icon"
|
||||||
|
@click="cancel"
|
||||||
|
>
|
||||||
{{ $t(modalData.buttons.cancel.textIdent) }}
|
{{ $t(modalData.buttons.cancel.textIdent) }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
|
|
||||||
<ds-button
|
<base-button
|
||||||
:danger="modalData.buttons.confirm.danger"
|
:danger="modalData.buttons.confirm.danger"
|
||||||
class="confirm"
|
class="confirm"
|
||||||
:icon="modalData.buttons.confirm.icon"
|
:icon="modalData.buttons.confirm.icon"
|
||||||
@ -22,7 +27,7 @@
|
|||||||
@click="confirm"
|
@click="confirm"
|
||||||
>
|
>
|
||||||
{{ $t(modalData.buttons.confirm.textIdent) }}
|
{{ $t(modalData.buttons.confirm.textIdent) }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-modal>
|
</ds-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -4,11 +4,10 @@
|
|||||||
<p v-html="message" />
|
<p v-html="message" />
|
||||||
|
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button class="cancel" @click="cancel">{{ $t('disable.cancel') }}</ds-button>
|
<base-button class="cancel" @click="cancel">{{ $t('disable.cancel') }}</base-button>
|
||||||
|
<base-button danger filled class="confirm" icon="exclamation-circle" @click="confirm">
|
||||||
<ds-button danger class="confirm" icon="exclamation-circle" @click="confirm">
|
|
||||||
{{ $t('disable.submit') }}
|
{{ $t('disable.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-modal>
|
</ds-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -29,12 +29,13 @@
|
|||||||
</small>
|
</small>
|
||||||
<ds-space />
|
<ds-space />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<ds-button class="cancel" icon="close" @click="cancel">
|
<base-button class="cancel" icon="close" @click="cancel">
|
||||||
{{ $t('report.cancel') }}
|
{{ $t('report.cancel') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
|
|
||||||
<ds-button
|
<base-button
|
||||||
danger
|
danger
|
||||||
|
filled
|
||||||
class="confirm"
|
class="confirm"
|
||||||
icon="exclamation-circle"
|
icon="exclamation-circle"
|
||||||
:disabled="!form.reasonCategory"
|
:disabled="!form.reasonCategory"
|
||||||
@ -42,7 +43,7 @@
|
|||||||
@click="confirm"
|
@click="confirm"
|
||||||
>
|
>
|
||||||
{{ $t('report.submit') }}
|
{{ $t('report.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-modal>
|
</ds-modal>
|
||||||
</template>
|
</template>
|
||||||
@ -161,7 +162,7 @@ export default {
|
|||||||
.ds-modal {
|
.ds-modal {
|
||||||
max-width: 600px !important;
|
max-width: 600px !important;
|
||||||
}
|
}
|
||||||
.ds-radio-option:not(.ds-button) {
|
.ds-radio-option {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
.ds-radio-option-label {
|
.ds-radio-option-label {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { config, shallowMount } from '@vue/test-utils'
|
import { config, mount } from '@vue/test-utils'
|
||||||
import NotificationMenu from './NotificationMenu'
|
import NotificationMenu from './NotificationMenu'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
localVue.filter('truncate', string => string)
|
localVue.filter('truncate', string => string)
|
||||||
|
|
||||||
config.stubs.dropdown = '<span class="dropdown"><slot /></span>'
|
config.stubs.dropdown = '<span class="dropdown"><slot :toggleMenu="() => null" /></span>'
|
||||||
|
|
||||||
describe('NotificationMenu.vue', () => {
|
describe('NotificationMenu.vue', () => {
|
||||||
let wrapper
|
let wrapper
|
||||||
@ -22,9 +22,9 @@ describe('NotificationMenu.vue', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('shallowMount', () => {
|
describe('mount', () => {
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return shallowMount(NotificationMenu, {
|
return mount(NotificationMenu, {
|
||||||
data,
|
data,
|
||||||
mocks,
|
mocks,
|
||||||
localVue,
|
localVue,
|
||||||
@ -33,7 +33,7 @@ describe('NotificationMenu.vue', () => {
|
|||||||
|
|
||||||
it('counter displays 0', () => {
|
it('counter displays 0', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('ds-button-stub').text()).toEqual('0')
|
expect(wrapper.find('.count').text()).toEqual('0')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('no dropdown is rendered', () => {
|
it('no dropdown is rendered', () => {
|
||||||
@ -67,12 +67,12 @@ describe('NotificationMenu.vue', () => {
|
|||||||
|
|
||||||
it('counter displays 0', () => {
|
it('counter displays 0', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('ds-button-stub').text()).toEqual('0')
|
expect(wrapper.find('.count').text()).toEqual('0')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('button is not primary', () => {
|
it('counter is not colored', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('ds-button-stub').props('primary')).toBe(false)
|
expect(wrapper.find('.count').classes()).toContain('--inactive')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -130,12 +130,12 @@ describe('NotificationMenu.vue', () => {
|
|||||||
|
|
||||||
it('displays the number of unread notifications', () => {
|
it('displays the number of unread notifications', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('ds-button-stub').text()).toEqual('2')
|
expect(wrapper.find('.count').text()).toEqual('2')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders primary button', () => {
|
it('renders the counter in red', () => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
expect(wrapper.find('ds-button-stub').props('primary')).toBe(true)
|
expect(wrapper.find('.count').classes()).toContain('--danger')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-button v-if="!notifications.length" class="notifications-menu" disabled icon="bell">
|
<base-button v-if="!notifications.length" class="notifications-menu" disabled ghost circle>
|
||||||
{{ unreadNotificationsCount }}
|
<counter-icon icon="bell" :count="unreadNotificationsCount" danger />
|
||||||
</ds-button>
|
</base-button>
|
||||||
<dropdown v-else class="notifications-menu" offset="8" :placement="placement">
|
<dropdown v-else class="notifications-menu" offset="8" :placement="placement">
|
||||||
<template slot="default" slot-scope="{ toggleMenu }">
|
<template slot="default" slot-scope="{ toggleMenu }">
|
||||||
<ds-button :primary="!!unreadNotificationsCount" icon="bell" @click.prevent="toggleMenu">
|
<base-button @click="toggleMenu" ghost circle>
|
||||||
{{ unreadNotificationsCount }}
|
<counter-icon icon="bell" :count="unreadNotificationsCount" danger />
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<div class="notifications-menu-popover">
|
<div class="notifications-menu-popover">
|
||||||
@ -22,17 +22,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Dropdown from '~/components/Dropdown'
|
|
||||||
import { NOTIFICATIONS_POLL_INTERVAL } from '~/constants/notifications'
|
import { NOTIFICATIONS_POLL_INTERVAL } from '~/constants/notifications'
|
||||||
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
|
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
|
||||||
import NotificationList from '../NotificationList/NotificationList'
|
|
||||||
import unionBy from 'lodash/unionBy'
|
import unionBy from 'lodash/unionBy'
|
||||||
|
|
||||||
|
import CounterIcon from '~/components/_new/generic/CounterIcon/CounterIcon'
|
||||||
|
import Dropdown from '~/components/Dropdown'
|
||||||
|
import NotificationList from '../NotificationList/NotificationList'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NotificationMenu',
|
name: 'NotificationMenu',
|
||||||
components: {
|
components: {
|
||||||
NotificationList,
|
CounterIcon,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
|
NotificationList,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -90,8 +93,13 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.notifications-menu {
|
.notifications-menu {
|
||||||
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.base-button {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notifications-menu-popover {
|
.notifications-menu-popover {
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ds-flex direction="row-reverse">
|
|
||||||
<ds-flex-item width="50px">
|
|
||||||
<ds-button @click="next" :disabled="!hasNext" icon="arrow-right" primary />
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-flex-item width="50px">
|
|
||||||
<ds-button @click="back" :disabled="!hasPrevious" icon="arrow-left" primary />
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
hasNext: { type: Boolean, default: false },
|
|
||||||
hasPrevious: { type: Boolean, default: false },
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
back() {
|
|
||||||
this.$emit('back')
|
|
||||||
},
|
|
||||||
next() {
|
|
||||||
this.$emit('next')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -24,9 +24,9 @@
|
|||||||
/>
|
/>
|
||||||
<password-strength :password="formData.password" />
|
<password-strength :password="formData.password" />
|
||||||
<ds-space margin-top="base">
|
<ds-space margin-top="base">
|
||||||
<ds-button :loading="loading" :disabled="errors" primary>
|
<base-button :loading="loading" :disabled="errors" filled type="submit">
|
||||||
{{ $t('settings.security.change-password.button') }}
|
{{ $t('settings.security.change-password.button') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</template>
|
</template>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
|
|||||||
@ -24,9 +24,9 @@
|
|||||||
/>
|
/>
|
||||||
<password-strength :password="formData.password" />
|
<password-strength :password="formData.password" />
|
||||||
<ds-space margin-top="base" margin-bottom="xxx-small">
|
<ds-space margin-top="base" margin-bottom="xxx-small">
|
||||||
<ds-button :loading="$apollo.loading" :disabled="errors" primary>
|
<base-button :loading="$apollo.loading" :disabled="errors" filled type="submit">
|
||||||
{{ $t('settings.security.change-password.button') }}
|
{{ $t('settings.security.change-password.button') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</template>
|
</template>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
|
|||||||
@ -20,17 +20,16 @@
|
|||||||
<ds-space margin-botton="large">
|
<ds-space margin-botton="large">
|
||||||
<ds-text align="left">{{ $t('components.password-reset.request.form.description') }}</ds-text>
|
<ds-text align="left">{{ $t('components.password-reset.request.form.description') }}</ds-text>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-button
|
<base-button
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:loading="$apollo.loading"
|
:loading="$apollo.loading"
|
||||||
primary
|
filled
|
||||||
fullwidth
|
|
||||||
name="submit"
|
name="submit"
|
||||||
type="submit"
|
type="submit"
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
>
|
>
|
||||||
{{ $t('components.password-reset.request.form.submit') }}
|
{{ $t('components.password-reset.request.form.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
|||||||
@ -192,6 +192,8 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-menu {
|
.content-menu {
|
||||||
|
position: relative;
|
||||||
|
z-index: $z-index-post-card-link;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: $space-xx-small;
|
margin-left: $space-xx-small;
|
||||||
margin-right: -$space-x-small;
|
margin-right: -$space-x-small;
|
||||||
|
|||||||
@ -102,10 +102,11 @@
|
|||||||
v-html="$t('components.registration.signup.form.no-political')"
|
v-html="$t('components.registration.signup.form.no-political')"
|
||||||
></label>
|
></label>
|
||||||
</ds-text>
|
</ds-text>
|
||||||
<ds-button
|
<base-button
|
||||||
style="float: right;"
|
style="float: right;"
|
||||||
icon="check"
|
icon="check"
|
||||||
type="submit"
|
type="submit"
|
||||||
|
filled
|
||||||
:loading="$apollo.loading"
|
:loading="$apollo.loading"
|
||||||
:disabled="
|
:disabled="
|
||||||
errors ||
|
errors ||
|
||||||
@ -115,10 +116,9 @@
|
|||||||
!noCommercial ||
|
!noCommercial ||
|
||||||
!noPolitical
|
!noPolitical
|
||||||
"
|
"
|
||||||
primary
|
|
||||||
>
|
>
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -30,17 +30,16 @@
|
|||||||
name="email"
|
name="email"
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
/>
|
/>
|
||||||
<ds-button
|
<base-button
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:loading="$apollo.loading"
|
:loading="$apollo.loading"
|
||||||
primary
|
filled
|
||||||
fullwidth
|
|
||||||
name="submit"
|
name="submit"
|
||||||
type="submit"
|
type="submit"
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
>
|
>
|
||||||
{{ $t('components.registration.signup.form.submit') }}
|
{{ $t('components.registration.signup.form.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
|
|||||||
@ -4,11 +4,10 @@
|
|||||||
<p v-html="message" />
|
<p v-html="message" />
|
||||||
|
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button class="cancel" @click="cancel">{{ $t('release.cancel') }}</ds-button>
|
<base-button class="cancel" @click="cancel">{{ $t('release.cancel') }}</base-button>
|
||||||
|
<base-button danger filled class="confirm" icon="exclamation-circle" @click="confirm">
|
||||||
<ds-button danger class="confirm" icon="exclamation-circle" @click="confirm">
|
|
||||||
{{ $t('release.submit') }}
|
{{ $t('release.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-modal>
|
</ds-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-space margin="xx-small" class="text-align-center">
|
<ds-space margin="xx-small" class="text-align-center">
|
||||||
<ds-button
|
<base-button
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:ghost="!shouted"
|
:filled="shouted"
|
||||||
:primary="shouted"
|
|
||||||
size="x-large"
|
|
||||||
icon="bullhorn"
|
icon="bullhorn"
|
||||||
|
circle
|
||||||
@click="toggle"
|
@click="toggle"
|
||||||
/>
|
/>
|
||||||
<ds-space margin-bottom="xx-small" />
|
<ds-space margin-bottom="xx-small" />
|
||||||
|
|||||||
@ -9,10 +9,18 @@
|
|||||||
@vdropzone-thumbnail="transformImage"
|
@vdropzone-thumbnail="transformImage"
|
||||||
>
|
>
|
||||||
<div class="crop-overlay" ref="cropperOverlay" v-show="showCropper">
|
<div class="crop-overlay" ref="cropperOverlay" v-show="showCropper">
|
||||||
<ds-button @click.stop.prevent="cropImage" class="crop-confirm" primary>
|
<base-button @click="cropImage" class="crop-confirm" filled>
|
||||||
{{ $t('contribution.teaserImage.cropperConfirm') }}
|
{{ $t('contribution.teaserImage.cropperConfirm') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-button @click="cancelCrop" class="crop-cancel" icon="close"></ds-button>
|
<base-button
|
||||||
|
class="crop-cancel"
|
||||||
|
icon="close"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
danger
|
||||||
|
filled
|
||||||
|
@click="cancelCrop"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="{
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
import { storiesOf } from '@storybook/vue'
|
||||||
|
import helpers from '~/storybook/helpers'
|
||||||
|
import BaseButton from './BaseButton.vue'
|
||||||
|
|
||||||
|
storiesOf('Generic/BaseButton', module)
|
||||||
|
.addDecorator(helpers.layout)
|
||||||
|
|
||||||
|
.add('default', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button>Click me</base-button>
|
||||||
|
<base-button disabled>Disabled</base-button>
|
||||||
|
<base-button loading>Loading</base-button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('icon', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button icon="edit">With Text</base-button>
|
||||||
|
<base-button icon="bullhorn" />
|
||||||
|
<base-button icon="trash" disabled />
|
||||||
|
<base-button icon="trash" loading />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('circle', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button circle icon="eye" />
|
||||||
|
<base-button circle>EN</base-button>
|
||||||
|
<base-button circle disabled icon="eye-slash" />
|
||||||
|
<base-button circle loading icon="eye-slash" />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('danger', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button danger>Danger</base-button>
|
||||||
|
<base-button danger disabled>Disabled</base-button>
|
||||||
|
<base-button danger loading>Loading</base-button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('filled', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button filled>Filled</base-button>
|
||||||
|
<base-button filled danger>Filled Danger</base-button>
|
||||||
|
<base-button filled disabled>Disabled</base-button>
|
||||||
|
<base-button filled loading>Loading</base-button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('small', () => ({
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button size="small">Small</base-button>
|
||||||
|
<base-button size="small" circle>S</base-button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('ghost', () => ({
|
||||||
|
// TODO: add documentation --> ghost button should only be used for very special occasions
|
||||||
|
// e.g. for the ContentMenu + for the EditorMenuBarButtons
|
||||||
|
components: { BaseButton },
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<base-button size="small" icon="ellipsis-v" circle ghost />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
144
webapp/components/_new/generic/BaseButton/BaseButton.vue
Normal file
144
webapp/components/_new/generic/BaseButton/BaseButton.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
:class="buttonClass"
|
||||||
|
:disabled="loading"
|
||||||
|
:type="type"
|
||||||
|
@click.capture="event => $emit('click', event)"
|
||||||
|
>
|
||||||
|
<base-icon v-if="icon" :name="icon" />
|
||||||
|
<loading-spinner v-if="loading" />
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LoadingSpinner from '~/components/_new/generic/LoadingSpinner/LoadingSpinner'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
LoadingSpinner,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
circle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
danger: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
filled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
ghost: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'regular',
|
||||||
|
validator(value) {
|
||||||
|
return value.match(/(small|regular)/)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'button',
|
||||||
|
validator(value) {
|
||||||
|
return value.match(/(button|submit)/)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
buttonClass() {
|
||||||
|
let buttonClass = 'base-button'
|
||||||
|
|
||||||
|
if (this.$slots.default === undefined) buttonClass += ' --icon-only'
|
||||||
|
if (this.circle) buttonClass += ' --circle'
|
||||||
|
if (this.danger) buttonClass += ' --danger'
|
||||||
|
if (this.loading) buttonClass += ' --loading'
|
||||||
|
if (this.size === 'small') buttonClass += ' --small'
|
||||||
|
|
||||||
|
if (this.filled) buttonClass += ' --filled'
|
||||||
|
else if (this.ghost) buttonClass += ' --ghost'
|
||||||
|
|
||||||
|
return buttonClass
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~/assets/_new/styles/mixins/buttonStates.scss';
|
||||||
|
|
||||||
|
.base-button {
|
||||||
|
@include buttonStates;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: $size-button-base;
|
||||||
|
padding: 0 $space-x-small;
|
||||||
|
vertical-align: bottom;
|
||||||
|
border: $border-size-base solid;
|
||||||
|
border-radius: $border-radius-x-large;
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.--danger {
|
||||||
|
@include buttonStates($color-scheme: danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--filled {
|
||||||
|
@include buttonStates($filled: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--danger.--filled {
|
||||||
|
@include buttonStates($color-scheme: danger, $filled: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--circle {
|
||||||
|
width: $size-button-base;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--ghost {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--small {
|
||||||
|
height: $size-button-small;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
|
||||||
|
&.--circle {
|
||||||
|
width: $size-button-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.--icon-only) > .base-icon {
|
||||||
|
margin-right: $space-xx-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled.--loading {
|
||||||
|
color: $color-neutral-80;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .loading-spinner {
|
||||||
|
position: absolute;
|
||||||
|
height: $size-button-small;
|
||||||
|
color: $color-neutral-60;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--filled > .loading-spinner {
|
||||||
|
color: $color-neutral-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -29,7 +29,7 @@ const iconStyles = `
|
|||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
`
|
`
|
||||||
|
|
||||||
storiesOf('BaseIcon', module)
|
storiesOf('Generic/BaseIcon', module)
|
||||||
.addDecorator(helpers.layout)
|
.addDecorator(helpers.layout)
|
||||||
|
|
||||||
.add('pure icon', () => ({
|
.add('pure icon', () => ({
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.base-icon {
|
.base-icon {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
> .svg {
|
> .svg {
|
||||||
height: 1.2em;
|
height: 1.2em;
|
||||||
|
|||||||
@ -5,33 +5,41 @@ import BaseIcon from '../BaseIcon/BaseIcon'
|
|||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
describe('CounterIcon.vue', () => {
|
describe('CounterIcon.vue', () => {
|
||||||
let propsData, wrapper, tag
|
let propsData, wrapper, count
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(CounterIcon, { propsData, localVue })
|
return mount(CounterIcon, { propsData, localVue })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('given a valid icon name and count', () => {
|
describe('given a valid icon name and count below 100', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
propsData = { icon: 'comments', count: 1 }
|
propsData = { icon: 'comments', count: 42 }
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
tag = wrapper.find('.ds-tag')
|
count = wrapper.find('.count')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders BaseIcon', () => {
|
it('renders the icon', () => {
|
||||||
expect(wrapper.find(BaseIcon).exists()).toBe(true)
|
expect(wrapper.find(BaseIcon).exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders the count', () => {
|
it('renders the count', () => {
|
||||||
expect(tag.text()).toEqual('1')
|
expect(count.text()).toEqual('42')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a valid icon name and count above 100', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = { icon: 'comments', count: 750 }
|
||||||
|
wrapper = Wrapper()
|
||||||
|
count = wrapper.find('.count')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses a round tag', () => {
|
it('renders the icon', () => {
|
||||||
expect(tag.classes()).toContain('ds-tag-round')
|
expect(wrapper.find(BaseIcon).exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses a primary button', () => {
|
it('renders the capped count with a plus', () => {
|
||||||
expect(tag.classes()).toContain('ds-tag-primary')
|
expect(count.text()).toEqual('99+')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,18 +2,33 @@ import { storiesOf } from '@storybook/vue'
|
|||||||
import helpers from '~/storybook/helpers'
|
import helpers from '~/storybook/helpers'
|
||||||
import CounterIcon from './CounterIcon.vue'
|
import CounterIcon from './CounterIcon.vue'
|
||||||
|
|
||||||
storiesOf('CounterIcon', module)
|
storiesOf('Generic/CounterIcon', module)
|
||||||
.addDecorator(helpers.layout)
|
.addDecorator(helpers.layout)
|
||||||
.add('flag icon with button in slot position', () => ({
|
|
||||||
|
.add('default', () => ({
|
||||||
components: { CounterIcon },
|
components: { CounterIcon },
|
||||||
data() {
|
|
||||||
return { icon: 'flag', count: 3 }
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<counter-icon icon="pizza" :count="count">
|
<counter-icon icon="flag" :count="3" />
|
||||||
<ds-button ghost primary>
|
`,
|
||||||
Report Details
|
}))
|
||||||
</ds-button>
|
|
||||||
</counter-icon>
|
.add('high count', () => ({
|
||||||
|
components: { CounterIcon },
|
||||||
|
template: `
|
||||||
|
<counter-icon icon="comments" :count="150" />
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('danger', () => ({
|
||||||
|
components: { CounterIcon },
|
||||||
|
template: `
|
||||||
|
<counter-icon icon="bell" :count="42" danger />
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
.add('count is 0', () => ({
|
||||||
|
components: { CounterIcon },
|
||||||
|
template: `
|
||||||
|
<counter-icon icon="bell" :count="0" />
|
||||||
`,
|
`,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -1,29 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<span>
|
<span class="counter-icon">
|
||||||
<base-icon :name="icon" />
|
<base-icon :name="icon" />
|
||||||
<ds-tag
|
<span :class="counterClass">{{ cappedCount }}</span>
|
||||||
style="margin-top: -4px; margin-left: -12px; position: absolute;"
|
|
||||||
color="primary"
|
|
||||||
size="small"
|
|
||||||
round
|
|
||||||
>
|
|
||||||
{{ count }}
|
|
||||||
</ds-tag>
|
|
||||||
<span class="counter-icon-text">
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
icon: { type: String, required: true },
|
icon: { type: String, required: true },
|
||||||
count: { type: Number, required: true },
|
count: { type: Number, required: true },
|
||||||
|
danger: { type: Boolean, default: false },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
cappedCount() {
|
||||||
|
return this.count <= 99 ? this.count : '99+'
|
||||||
|
},
|
||||||
|
counterClass() {
|
||||||
|
let counterClass = 'count'
|
||||||
|
if (this.danger) counterClass += ' --danger'
|
||||||
|
if (this.count === 0) counterClass += ' --inactive'
|
||||||
|
|
||||||
|
return counterClass
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
|
||||||
.counter-icon-text {
|
<style lang="scss">
|
||||||
margin-left: $space-xx-small;
|
.counter-icon {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> .count {
|
||||||
|
position: absolute;
|
||||||
|
top: -$space-xx-small;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: $size-icon-base;
|
||||||
|
min-width: $size-icon-base;
|
||||||
|
padding: 3px; // magic number to center count
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: translateX(50%);
|
||||||
|
|
||||||
|
color: $color-neutral-100;
|
||||||
|
background-color: $color-primary;
|
||||||
|
font-size: 10px; // magic number to center count
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&.--danger {
|
||||||
|
background-color: $color-danger;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--inactive {
|
||||||
|
background-color: $color-neutral-60;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { storiesOf } from '@storybook/vue'
|
||||||
|
import helpers from '~/storybook/helpers'
|
||||||
|
import LoadingSpinner from './LoadingSpinner.vue'
|
||||||
|
|
||||||
|
storiesOf('Generic/LoadingSpinner', module)
|
||||||
|
.addDecorator(helpers.layout)
|
||||||
|
|
||||||
|
.add('default', () => ({
|
||||||
|
components: { LoadingSpinner },
|
||||||
|
template: '<loading-spinner />',
|
||||||
|
}))
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<svg viewBox="0 0 50 50" class="loading-spinner">
|
||||||
|
<circle cx="25" cy="25" r="20" class="circle" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'LoadingSpinner',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.loading-spinner {
|
||||||
|
height: $size-button-base;
|
||||||
|
overflow: hidden;
|
||||||
|
stroke: currentColor;
|
||||||
|
animation: rotate 16s linear infinite;
|
||||||
|
|
||||||
|
> .circle {
|
||||||
|
fill: none;
|
||||||
|
stroke-width: 5;
|
||||||
|
stroke-linecap: round;
|
||||||
|
animation: dash 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dash {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 1, 150;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 90, 150;
|
||||||
|
stroke-dashoffset: -35;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 90, 150;
|
||||||
|
stroke-dashoffset: -124;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
100% {
|
||||||
|
transform: rotate(2160deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,39 +1,35 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
|
|
||||||
import Paginate from './Paginate'
|
import PaginationButtons from './PaginationButtons'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
describe('Paginate.vue', () => {
|
describe('PaginationButtons.vue', () => {
|
||||||
let propsData, wrapper, nextButton, backButton
|
let propsData = {}
|
||||||
|
let wrapper
|
||||||
beforeEach(() => {
|
let nextButton
|
||||||
propsData = {}
|
let backButton
|
||||||
})
|
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(Paginate, { propsData, localVue })
|
return mount(PaginationButtons, { propsData, localVue })
|
||||||
}
|
}
|
||||||
describe('mount', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper = Wrapper()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
describe('next button', () => {
|
describe('next button', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
propsData.hasNext = true
|
propsData.hasNext = true
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
nextButton = wrapper.findAll('.ds-button').at(0)
|
nextButton = wrapper.find('[data-test="next-button"]')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is disabled by default', () => {
|
it('is disabled by default', () => {
|
||||||
propsData = {}
|
propsData = {}
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
nextButton = wrapper.findAll('.ds-button').at(0)
|
nextButton = wrapper.find('[data-test="next-button"]')
|
||||||
expect(nextButton.attributes().disabled).toEqual('disabled')
|
expect(nextButton.attributes().disabled).toEqual('disabled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is not disabled if hasNext is true', () => {
|
it('is enabled if hasNext is true', () => {
|
||||||
expect(nextButton.attributes().disabled).toBeUndefined()
|
expect(nextButton.attributes().disabled).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -47,17 +43,17 @@ describe('Paginate.vue', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
propsData.hasPrevious = true
|
propsData.hasPrevious = true
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
backButton = wrapper.findAll('.ds-button').at(1)
|
backButton = wrapper.find('[data-test="previous-button"]')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is disabled by default', () => {
|
it('is disabled by default', () => {
|
||||||
propsData = {}
|
propsData = {}
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
backButton = wrapper.findAll('.ds-button').at(1)
|
backButton = wrapper.find('[data-test="previous-button"]')
|
||||||
expect(backButton.attributes().disabled).toEqual('disabled')
|
expect(backButton.attributes().disabled).toEqual('disabled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is not disabled if hasPrevious is true', () => {
|
it('is enabled if hasPrevious is true', () => {
|
||||||
expect(backButton.attributes().disabled).toBeUndefined()
|
expect(backButton.attributes().disabled).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { storiesOf } from '@storybook/vue'
|
import { storiesOf } from '@storybook/vue'
|
||||||
import { withA11y } from '@storybook/addon-a11y'
|
import { withA11y } from '@storybook/addon-a11y'
|
||||||
import { action } from '@storybook/addon-actions'
|
import { action } from '@storybook/addon-actions'
|
||||||
import Paginate from '~/components/Paginate/Paginate'
|
import PaginationButtons from '~/components/_new/generic/PaginationButtons/PaginationButtons'
|
||||||
import helpers from '~/storybook/helpers'
|
import helpers from '~/storybook/helpers'
|
||||||
|
|
||||||
helpers.init()
|
helpers.init()
|
||||||
|
|
||||||
storiesOf('Paginate', module)
|
storiesOf('PaginationButtons', module)
|
||||||
.addDecorator(withA11y)
|
.addDecorator(withA11y)
|
||||||
.addDecorator(helpers.layout)
|
.addDecorator(helpers.layout)
|
||||||
.add('basic pagination', () => ({
|
.add('basic pagination', () => ({
|
||||||
components: { Paginate },
|
components: { PaginationButtons },
|
||||||
data: () => ({
|
data: () => ({
|
||||||
hasNext: true,
|
hasNext: true,
|
||||||
hasPrevious: false,
|
hasPrevious: false,
|
||||||
@ -19,7 +19,7 @@ storiesOf('Paginate', module)
|
|||||||
back: action('back'),
|
back: action('back'),
|
||||||
next: action('next'),
|
next: action('next'),
|
||||||
},
|
},
|
||||||
template: `<paginate
|
template: `<pagination-buttons
|
||||||
:hasNext="hasNext"
|
:hasNext="hasNext"
|
||||||
:hasPrevious="hasPrevious"
|
:hasPrevious="hasPrevious"
|
||||||
@back="back"
|
@back="back"
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pagination-buttons">
|
||||||
|
<base-button
|
||||||
|
@click="$emit('back')"
|
||||||
|
:disabled="!hasPrevious"
|
||||||
|
icon="arrow-left"
|
||||||
|
circle
|
||||||
|
data-test="previous-button"
|
||||||
|
/>
|
||||||
|
<base-button
|
||||||
|
@click="$emit('next')"
|
||||||
|
:disabled="!hasNext"
|
||||||
|
icon="arrow-right"
|
||||||
|
circle
|
||||||
|
data-test="next-button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
hasNext: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
hasPrevious: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.pagination-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: $size-width-paginate;
|
||||||
|
margin: $space-x-small auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -7,7 +7,7 @@
|
|||||||
</client-only>
|
</client-only>
|
||||||
</div>
|
</div>
|
||||||
<reports-table :reports="reports" @confirm="openModal" />
|
<reports-table :reports="reports" @confirm="openModal" />
|
||||||
<paginate :hasNext="hasNext" :hasPrevious="hasPrevious" @back="back" @next="next" />
|
<pagination-buttons :hasNext="hasNext" :hasPrevious="hasPrevious" @back="back" @next="next" />
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@ -15,13 +15,13 @@ import { mapMutations } from 'vuex'
|
|||||||
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
||||||
import ReportsTable from '~/components/features/ReportsTable/ReportsTable'
|
import ReportsTable from '~/components/features/ReportsTable/ReportsTable'
|
||||||
import { reportsListQuery, reviewMutation } from '~/graphql/Moderation.js'
|
import { reportsListQuery, reviewMutation } from '~/graphql/Moderation.js'
|
||||||
import Paginate from '~/components/Paginate/Paginate'
|
import PaginationButtons from '~/components/_new/generic/PaginationButtons/PaginationButtons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DropdownFilter,
|
DropdownFilter,
|
||||||
ReportsTable,
|
ReportsTable,
|
||||||
Paginate,
|
PaginationButtons,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const pageSize = 25
|
const pageSize = 25
|
||||||
|
|||||||
@ -40,7 +40,7 @@ describe('ReportRow', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
propsData = { ...propsData, report: reports[1] }
|
propsData = { ...propsData, report: reports[1] }
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
confirmButton = wrapper.find('.ds-button-danger')
|
confirmButton = wrapper.find('.base-button.--danger')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders a confirm button', () => {
|
it('renders a confirm button', () => {
|
||||||
|
|||||||
@ -11,9 +11,9 @@
|
|||||||
<span class="user-count">
|
<span class="user-count">
|
||||||
{{ $t('moderation.reports.numberOfUsers', { count: report.filed.length }) }}
|
{{ $t('moderation.reports.numberOfUsers', { count: report.filed.length }) }}
|
||||||
</span>
|
</span>
|
||||||
<ds-button size="small" @click="showFiledReports = !showFiledReports">
|
<base-button size="small" @click="showFiledReports = !showFiledReports">
|
||||||
{{ $t('moderation.reports.moreDetails') }}
|
{{ $t('moderation.reports.moreDetails') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<!-- Content Column -->
|
<!-- Content Column -->
|
||||||
@ -61,16 +61,17 @@
|
|||||||
<span v-if="report.closed" class="title">
|
<span v-if="report.closed" class="title">
|
||||||
{{ $t('moderation.reports.decided') }}
|
{{ $t('moderation.reports.decided') }}
|
||||||
</span>
|
</span>
|
||||||
<ds-button
|
<base-button
|
||||||
v-else
|
v-else
|
||||||
danger
|
danger
|
||||||
|
filled
|
||||||
data-test="confirm"
|
data-test="confirm"
|
||||||
size="small"
|
size="small"
|
||||||
:icon="statusIconName"
|
:icon="statusIconName"
|
||||||
@click="$emit('confirm-report')"
|
@click="$emit('confirm-report')"
|
||||||
>
|
>
|
||||||
{{ $t('moderation.reports.decideButton') }}
|
{{ $t('moderation.reports.decideButton') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-flex-item class="search-heading">
|
<ds-heading soft size="h5" class="search-heading">
|
||||||
<ds-heading soft size="h5">
|
{{ $t(`search.heading.${resourceType}`) }}
|
||||||
{{ $t(`search.heading.${resourceType}`) }}
|
</ds-heading>
|
||||||
</ds-heading>
|
|
||||||
</ds-flex-item>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
@ -14,13 +12,16 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.search-heading {
|
.search-heading.ds-heading {
|
||||||
display: flex;
|
margin: -$space-x-small;
|
||||||
flex-wrap: wrap;
|
padding: $space-x-small;
|
||||||
font-weight: bold;
|
background-color: $color-neutral-100;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
background-color: white;
|
}
|
||||||
margin: -8px;
|
|
||||||
padding: 8px;
|
// override styleguide styles
|
||||||
|
.search-heading.ds-heading:first-child {
|
||||||
|
margin-top: -$space-x-small;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -32,81 +32,79 @@ describe('SearchableInput.vue', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
describe('testing custom functions', () => {
|
let select
|
||||||
let select
|
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
select = wrapper.find('.ds-select')
|
||||||
|
select.trigger('focus')
|
||||||
|
select.element.value = 'abcd'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('opens the dropdown when focused', () => {
|
||||||
|
expect(wrapper.find('.ds-select-dropdown').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes the dropdown when blurred', () => {
|
||||||
|
select.trigger('blur')
|
||||||
|
expect(wrapper.find('.ds-select-is-open').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes the dropdown when cleared with esc key', () => {
|
||||||
|
select.trigger('input')
|
||||||
|
select.trigger('keyup.esc')
|
||||||
|
expect(wrapper.find('.ds-select-is-open').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes the unprocessedSearchInput as the value changes', () => {
|
||||||
|
select.trigger('input')
|
||||||
|
expect(select.element.value).toBe('abcd')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('searches for the term when enter is pressed', async () => {
|
||||||
|
select.element.value = 'ab'
|
||||||
|
select.trigger('input')
|
||||||
|
select.trigger('keyup.enter')
|
||||||
|
await expect(wrapper.emitted().query[0]).toEqual(['ab'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls onDelete when the delete key is pressed', () => {
|
||||||
|
const spy = jest.spyOn(wrapper.vm, 'onDelete')
|
||||||
|
select.trigger('input')
|
||||||
|
select.trigger('keyup.delete')
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navigating to resource', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
propsData = { options: searchResults }
|
||||||
|
wrapper = Wrapper()
|
||||||
select = wrapper.find('.ds-select')
|
select = wrapper.find('.ds-select')
|
||||||
select.trigger('focus')
|
select.trigger('focus')
|
||||||
select.element.value = 'abcd'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('opens the select dropdown when focused on', () => {
|
it('pushes to post page', async () => {
|
||||||
expect(wrapper.find('.is-open').exists()).toBe(true)
|
select.element.value = 'Post'
|
||||||
})
|
|
||||||
|
|
||||||
it('opens the select dropdown and blurs after focused on', () => {
|
|
||||||
select.trigger('blur')
|
|
||||||
expect(wrapper.find('.is-open').exists()).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('is clearable', () => {
|
|
||||||
select.trigger('input')
|
select.trigger('input')
|
||||||
select.trigger('keyup.esc')
|
const post = wrapper.find('.search-post')
|
||||||
expect(wrapper.find('.is-open').exists()).toBe(false)
|
post.trigger('click')
|
||||||
})
|
await Vue.nextTick().then(() => {
|
||||||
|
expect(mocks.$router.push).toHaveBeenCalledWith({
|
||||||
it('changes the unprocessedSearchInput as the value changes', () => {
|
name: 'post-id-slug',
|
||||||
select.trigger('input')
|
params: { id: 'post-by-jenny', slug: 'user-post-by-jenny' },
|
||||||
expect(select.element.value).toBe('abcd')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('searches for the term when enter is pressed', async () => {
|
|
||||||
select.element.value = 'ab'
|
|
||||||
select.trigger('input')
|
|
||||||
select.trigger('keyup.enter')
|
|
||||||
await expect(wrapper.emitted().query[0]).toEqual(['ab'])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls onDelete when the delete key is pressed', () => {
|
|
||||||
const spy = jest.spyOn(wrapper.vm, 'onDelete')
|
|
||||||
select.trigger('input')
|
|
||||||
select.trigger('keyup.delete')
|
|
||||||
expect(spy).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('navigating to resource', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
propsData = { options: searchResults }
|
|
||||||
wrapper = Wrapper()
|
|
||||||
select = wrapper.find('.ds-select')
|
|
||||||
select.trigger('focus')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('pushes to post page', async () => {
|
|
||||||
select.element.value = 'Post'
|
|
||||||
select.trigger('input')
|
|
||||||
const post = wrapper.find('.search-post')
|
|
||||||
post.trigger('click')
|
|
||||||
await Vue.nextTick().then(() => {
|
|
||||||
expect(mocks.$router.push).toHaveBeenCalledWith({
|
|
||||||
name: 'post-id-slug',
|
|
||||||
params: { id: 'post-by-jenny', slug: 'user-post-by-jenny' },
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it("pushes to user's profile", async () => {
|
it("pushes to user's profile", async () => {
|
||||||
select.element.value = 'Bob'
|
select.element.value = 'Bob'
|
||||||
select.trigger('input')
|
select.trigger('input')
|
||||||
const users = wrapper.findAll('.userinfo')
|
const users = wrapper.findAll('.userinfo')
|
||||||
const bob = users.filter(item => item.text() === '@bob-der-baumeister')
|
const bob = users.filter(item => item.text() === '@bob-der-baumeister')
|
||||||
bob.trigger('click')
|
bob.trigger('click')
|
||||||
await Vue.nextTick().then(() => {
|
await Vue.nextTick().then(() => {
|
||||||
expect(mocks.$router.push).toHaveBeenCalledWith({
|
expect(mocks.$router.push).toHaveBeenCalledWith({
|
||||||
name: 'profile-id-slug',
|
name: 'profile-id-slug',
|
||||||
params: { id: 'u2', slug: 'bob-der-baumeister' },
|
params: { id: 'u2', slug: 'bob-der-baumeister' },
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,60 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="searchable-input" aria-label="search" role="search">
|
||||||
class="searchable-input"
|
<ds-select
|
||||||
aria-label="search"
|
type="search"
|
||||||
role="search"
|
icon="search"
|
||||||
:class="{
|
v-model="searchValue"
|
||||||
'is-active': isActive,
|
:id="id"
|
||||||
'is-open': isOpen,
|
label-prop="id"
|
||||||
}"
|
:icon-right="null"
|
||||||
>
|
:options="options"
|
||||||
<div class="field">
|
:loading="loading"
|
||||||
<div class="control">
|
:filter="item => item"
|
||||||
<ds-button v-if="isActive" icon="close" ghost class="search-clear-btn" @click="clear" />
|
:no-options-available="emptyText"
|
||||||
<ds-select
|
:auto-reset-search="!searchValue"
|
||||||
type="search"
|
:placeholder="$t('search.placeholder')"
|
||||||
icon="search"
|
@focus.capture.native="onFocus"
|
||||||
v-model="searchValue"
|
@input.native="handleInput"
|
||||||
:id="id"
|
@keyup.enter.native="onEnter"
|
||||||
label-prop="id"
|
@keyup.delete.native="onDelete"
|
||||||
:icon-right="isActive ? 'close' : null"
|
@keyup.esc.native="clear"
|
||||||
:options="options"
|
@blur.capture.native="onBlur"
|
||||||
:loading="loading"
|
@input.exact="onSelect"
|
||||||
:filter="item => item"
|
>
|
||||||
:no-options-available="emptyText"
|
<template #option="{ option }">
|
||||||
:auto-reset-search="!searchValue"
|
<search-heading v-if="isFirstOfType(option)" :resource-type="option.__typename" />
|
||||||
:placeholder="$t('search.placeholder')"
|
<p
|
||||||
@click.capture.native="isOpen = true"
|
v-if="option.__typename === 'User'"
|
||||||
@focus.capture.native="onFocus"
|
:class="{ 'option-with-heading': isFirstOfType(option) }"
|
||||||
@input.native="handleInput"
|
|
||||||
@keyup.enter.native="onEnter"
|
|
||||||
@keyup.delete.native="onDelete"
|
|
||||||
@keyup.esc.native="clear"
|
|
||||||
@blur.capture.native="onBlur"
|
|
||||||
@input.exact="onSelect"
|
|
||||||
>
|
>
|
||||||
<template #option="{ option }">
|
<hc-user :user="option" :showPopover="false" />
|
||||||
<span v-if="isFirstOfType(option)" class="search-heading">
|
</p>
|
||||||
<search-heading :resource-type="option.__typename" />
|
<p
|
||||||
</span>
|
v-if="option.__typename === 'Post'"
|
||||||
<span
|
:class="{ 'option-with-heading': isFirstOfType(option) }"
|
||||||
v-if="option.__typename === 'User'"
|
>
|
||||||
:class="{ 'option-with-heading': isFirstOfType(option), 'flex-span': true }"
|
<search-post :option="option" />
|
||||||
>
|
</p>
|
||||||
<hc-user :user="option" :showPopover="false" />
|
</template>
|
||||||
</span>
|
</ds-select>
|
||||||
<span
|
<base-button v-if="isActive" icon="close" circle ghost size="small" @click="clear" />
|
||||||
v-if="option.__typename === 'Post'"
|
|
||||||
:class="{ 'option-with-heading': isFirstOfType(option), 'flex-span': true }"
|
|
||||||
>
|
|
||||||
<search-post :option="option" />
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</ds-select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import SearchHeading from '~/components/generic/SearchHeading/SearchHeading.vue'
|
import SearchHeading from '~/components/generic/SearchHeading/SearchHeading.vue'
|
||||||
@ -75,7 +61,6 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isOpen: false,
|
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
value: '',
|
value: '',
|
||||||
unprocessedSearchInput: '',
|
unprocessedSearchInput: '',
|
||||||
@ -101,12 +86,10 @@ export default {
|
|||||||
},
|
},
|
||||||
onFocus(event) {
|
onFocus(event) {
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
this.isOpen = true
|
|
||||||
},
|
},
|
||||||
handleInput(event) {
|
handleInput(event) {
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
this.value = event.target ? event.target.value.replace(/\s+/g, ' ').trim() : ''
|
this.value = event.target ? event.target.value.replace(/\s+/g, ' ').trim() : ''
|
||||||
this.isOpen = true
|
|
||||||
this.unprocessedSearchInput = this.value
|
this.unprocessedSearchInput = this.value
|
||||||
if (isEmpty(this.value) || this.value.replace(/\s+/g, '').length < 3) {
|
if (isEmpty(this.value) || this.value.replace(/\s+/g, '').length < 3) {
|
||||||
return
|
return
|
||||||
@ -120,7 +103,6 @@ export default {
|
|||||||
* TODO: on enter we should go to a dedicated search page!?
|
* TODO: on enter we should go to a dedicated search page!?
|
||||||
*/
|
*/
|
||||||
onEnter(event) {
|
onEnter(event) {
|
||||||
this.isOpen = false
|
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
if (!this.pending) {
|
if (!this.pending) {
|
||||||
this.previousSearchTerm = this.unprocessedSearchInput
|
this.previousSearchTerm = this.unprocessedSearchInput
|
||||||
@ -137,7 +119,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
clear() {
|
clear() {
|
||||||
this.isOpen = false
|
|
||||||
this.unprocessedSearchInput = ''
|
this.unprocessedSearchInput = ''
|
||||||
this.previousSearchTerm = ''
|
this.previousSearchTerm = ''
|
||||||
this.searchValue = ''
|
this.searchValue = ''
|
||||||
@ -146,11 +127,9 @@ export default {
|
|||||||
},
|
},
|
||||||
onBlur(event) {
|
onBlur(event) {
|
||||||
this.searchValue = this.previousSearchTerm
|
this.searchValue = this.previousSearchTerm
|
||||||
this.isOpen = false
|
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
},
|
},
|
||||||
onSelect(item) {
|
onSelect(item) {
|
||||||
this.isOpen = false
|
|
||||||
this.goToResource(item)
|
this.goToResource(item)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.searchValue = this.previousSearchTerm
|
this.searchValue = this.previousSearchTerm
|
||||||
@ -170,58 +149,32 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.searchable-input {
|
.searchable-input {
|
||||||
display: flex;
|
|
||||||
align-self: center;
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
$padding-left: $space-x-small;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.ds-form-item {
|
||||||
|
flex-basis: 100%;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ds-select-dropdown {
|
||||||
|
max-height: 70vh;
|
||||||
|
box-shadow: $box-shadow-x-large;
|
||||||
|
}
|
||||||
|
|
||||||
.option-with-heading {
|
.option-with-heading {
|
||||||
margin-top: $space-x-small;
|
margin-top: $space-x-small;
|
||||||
padding-top: $space-xx-small;
|
padding-top: $space-xx-small;
|
||||||
}
|
}
|
||||||
.flex-span {
|
|
||||||
display: flex;
|
.base-button {
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.ds-select-dropdown {
|
|
||||||
transition: box-shadow 100ms;
|
|
||||||
max-height: 70vh;
|
|
||||||
}
|
|
||||||
&.is-open {
|
|
||||||
.ds-select-dropdown {
|
|
||||||
box-shadow: $box-shadow-x-large;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ds-select-dropdown-message {
|
|
||||||
opacity: 0.5;
|
|
||||||
padding-left: $padding-left;
|
|
||||||
}
|
|
||||||
.search-clear-btn {
|
|
||||||
right: 0;
|
|
||||||
z-index: 10;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
right: $space-xx-small;
|
||||||
width: 36px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.ds-select {
|
|
||||||
z-index: $z-index-dropdown + 1;
|
|
||||||
}
|
|
||||||
.ds-select-option-hover {
|
|
||||||
.ds-text-size-small,
|
|
||||||
.ds-text-size-small-x {
|
|
||||||
color: $text-color-soft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.field {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.control {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -4,21 +4,21 @@
|
|||||||
<ds-container class="main-navigation-container" style="padding: 10px 10px;">
|
<ds-container class="main-navigation-container" style="padding: 10px 10px;">
|
||||||
<div>
|
<div>
|
||||||
<ds-flex class="main-navigation-flex">
|
<ds-flex class="main-navigation-flex">
|
||||||
<ds-flex-item :width="{ lg: '3.5%' }" />
|
<ds-flex-item :width="{ base: '142px' }">
|
||||||
<ds-flex-item :width="{ base: '80%', sm: '80%', md: '80%', lg: '15%' }">
|
|
||||||
<nuxt-link :to="{ name: 'index' }" v-scroll-to="'.main-navigation'">
|
<nuxt-link :to="{ name: 'index' }" v-scroll-to="'.main-navigation'">
|
||||||
<ds-logo />
|
<ds-logo />
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
:width="{ base: '20%', sm: '20%', md: '20%', lg: '0%' }"
|
:width="{ base: '40%', sm: '40%', md: '40%', lg: '0%' }"
|
||||||
class="mobile-hamburger-menu"
|
class="mobile-hamburger-menu"
|
||||||
>
|
>
|
||||||
<ds-button icon="bars" @click="toggleMobileMenuView" right />
|
<base-button icon="bars" @click="toggleMobileMenuView" circle />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
:width="{ base: '85%', sm: '85%', md: '50%', lg: '50%' }"
|
:width="{ base: '45%', sm: '45%', md: '45%', lg: '50%' }"
|
||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
|
style="flex-shrink: 0; flex-grow: 1;"
|
||||||
id="nav-search-box"
|
id="nav-search-box"
|
||||||
v-if="isLoggedIn"
|
v-if="isLoggedIn"
|
||||||
>
|
>
|
||||||
@ -26,8 +26,8 @@
|
|||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
v-if="isLoggedIn"
|
v-if="isLoggedIn"
|
||||||
:width="{ base: '15%', sm: '15%', md: '10%', lg: '10%' }"
|
|
||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
|
style="flex-grow: 0; flex-basis: auto;"
|
||||||
>
|
>
|
||||||
<client-only>
|
<client-only>
|
||||||
<filter-posts
|
<filter-posts
|
||||||
@ -38,10 +38,8 @@
|
|||||||
/>
|
/>
|
||||||
</client-only>
|
</client-only>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '10%', lg: '2%' }" />
|
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
:width="{ base: '100%', sm: '100%', md: '100%', lg: '13%' }"
|
style="background-color: white; flex-basis: auto;"
|
||||||
style="background-color:white"
|
|
||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -50,6 +48,7 @@
|
|||||||
'desktop-view': !toggleMobileMenu,
|
'desktop-view': !toggleMobileMenu,
|
||||||
'hide-mobile-menu': !toggleMobileMenu,
|
'hide-mobile-menu': !toggleMobileMenu,
|
||||||
}"
|
}"
|
||||||
|
style="flex-basis: auto;"
|
||||||
>
|
>
|
||||||
<client-only>
|
<client-only>
|
||||||
<locale-switch class="topbar-locale-switch" placement="top" offset="8" />
|
<locale-switch class="topbar-locale-switch" placement="top" offset="8" />
|
||||||
@ -164,17 +163,21 @@ export default {
|
|||||||
}
|
}
|
||||||
.main-navigation-right {
|
.main-navigation-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
.main-navigation-right .desktop-view {
|
.main-navigation-right .desktop-view {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
@media only screen and (min-width: 960px) {
|
.ds-flex-item.mobile-hamburger-menu {
|
||||||
|
margin-left: auto;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 730px) {
|
||||||
.mobile-hamburger-menu {
|
.mobile-hamburger-menu {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 960px) {
|
@media only screen and (max-width: 730px) {
|
||||||
#nav-search-box,
|
#nav-search-box,
|
||||||
.main-navigation-right {
|
.main-navigation-right {
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export default {
|
|||||||
/*
|
/*
|
||||||
** Global CSS
|
** Global CSS
|
||||||
*/
|
*/
|
||||||
css: ['~assets/styles/main.scss'],
|
css: ['~assets/_new/styles/resets.scss', '~assets/styles/main.scss'],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Global processed styles
|
** Global processed styles
|
||||||
|
|||||||
@ -96,13 +96,13 @@
|
|||||||
"zxcvbn": "^4.4.2"
|
"zxcvbn": "^4.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "~7.7.7",
|
"@babel/core": "~7.8.3",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/preset-env": "~7.7.7",
|
"@babel/preset-env": "~7.8.3",
|
||||||
"@storybook/addon-a11y": "^5.2.8",
|
"@storybook/addon-a11y": "^5.3.3",
|
||||||
"@storybook/addon-actions": "^5.3.2",
|
"@storybook/addon-actions": "^5.3.3",
|
||||||
"@storybook/addon-notes": "^5.3.1",
|
"@storybook/addon-notes": "^5.3.3",
|
||||||
"@storybook/vue": "~5.3.1",
|
"@storybook/vue": "~5.3.3",
|
||||||
"@vue/cli-shared-utils": "~4.1.2",
|
"@vue/cli-shared-utils": "~4.1.2",
|
||||||
"@vue/eslint-config-prettier": "~6.0.0",
|
"@vue/eslint-config-prettier": "~6.0.0",
|
||||||
"@vue/server-test-utils": "~1.0.0-beta.30",
|
"@vue/server-test-utils": "~1.0.0-beta.30",
|
||||||
@ -120,8 +120,8 @@
|
|||||||
"eslint-config-prettier": "~6.9.0",
|
"eslint-config-prettier": "~6.9.0",
|
||||||
"eslint-config-standard": "~14.1.0",
|
"eslint-config-standard": "~14.1.0",
|
||||||
"eslint-loader": "~3.0.3",
|
"eslint-loader": "~3.0.3",
|
||||||
"eslint-plugin-import": "~2.19.1",
|
"eslint-plugin-import": "~2.20.0",
|
||||||
"eslint-plugin-jest": "~23.3.0",
|
"eslint-plugin-jest": "~23.6.0",
|
||||||
"eslint-plugin-node": "~11.0.0",
|
"eslint-plugin-node": "~11.0.0",
|
||||||
"eslint-plugin-prettier": "~3.1.2",
|
"eslint-plugin-prettier": "~3.1.2",
|
||||||
"eslint-plugin-promise": "~4.2.1",
|
"eslint-plugin-promise": "~4.2.1",
|
||||||
@ -135,7 +135,7 @@
|
|||||||
"mutation-observer": "^1.0.3",
|
"mutation-observer": "^1.0.3",
|
||||||
"node-sass": "~4.13.0",
|
"node-sass": "~4.13.0",
|
||||||
"prettier": "~1.19.1",
|
"prettier": "~1.19.1",
|
||||||
"sass-loader": "~8.0.0",
|
"sass-loader": "~8.0.2",
|
||||||
"storybook-design-token": "^0.5.0",
|
"storybook-design-token": "^0.5.0",
|
||||||
"storybook-vue-router": "^1.0.7",
|
"storybook-vue-router": "^1.0.7",
|
||||||
"style-loader": "~0.23.1",
|
"style-loader": "~0.23.1",
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
placeholder="1200"
|
placeholder="1200"
|
||||||
icon="money"
|
icon="money"
|
||||||
/>
|
/>
|
||||||
<ds-button primary type="submit" :disabled="!formData.goal || !formData.progress">
|
<base-button filled type="submit" :disabled="!formData.goal || !formData.progress">
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
/>
|
/>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item width="30px">
|
<ds-flex-item width="30px">
|
||||||
<ds-button primary type="submit" icon="search" :loading="$apollo.loading" />
|
<base-button filled circle type="submit" icon="search" :loading="$apollo.loading" />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
</ds-form>
|
</ds-form>
|
||||||
@ -50,14 +50,7 @@
|
|||||||
{{ scope.row.createdAt | dateTime }}
|
{{ scope.row.createdAt | dateTime }}
|
||||||
</template>
|
</template>
|
||||||
</ds-table>
|
</ds-table>
|
||||||
<ds-flex direction="row-reverse">
|
<pagination-buttons :hasNext="hasNext" :hasPrevious="hasPrevious" @next="next" @back="back" />
|
||||||
<ds-flex-item width="50px">
|
|
||||||
<ds-button @click="next" :disabled="!hasNext" icon="arrow-right" primary />
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-flex-item width="50px">
|
|
||||||
<ds-button @click="back" :disabled="!hasPrevious" icon="arrow-left" primary />
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-card>
|
</ds-card>
|
||||||
<ds-card v-else>
|
<ds-card v-else>
|
||||||
<ds-placeholder>{{ $t('admin.users.empty') }}</ds-placeholder>
|
<ds-placeholder>{{ $t('admin.users.empty') }}</ds-placeholder>
|
||||||
@ -69,8 +62,12 @@
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { isEmail } from 'validator'
|
import { isEmail } from 'validator'
|
||||||
import normalizeEmail from '~/components/utils/NormalizeEmail'
|
import normalizeEmail from '~/components/utils/NormalizeEmail'
|
||||||
|
import PaginationButtons from '~/components/_new/generic/PaginationButtons/PaginationButtons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
PaginationButtons,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
const pageSize = 15
|
const pageSize = 15
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -126,11 +126,6 @@ describe('PostIndex', () => {
|
|||||||
.trigger('click')
|
.trigger('click')
|
||||||
expect(mutations['posts/SELECT_ORDER']).toHaveBeenCalledWith({}, 'createdAt_asc')
|
expect(mutations['posts/SELECT_ORDER']).toHaveBeenCalledWith({}, 'createdAt_asc')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('updates offset when a user clicks on the load more button', () => {
|
|
||||||
wrapper.find('.load-more button').trigger('click')
|
|
||||||
expect(wrapper.vm.offset).toEqual(12)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<!--<donation-info /> -->
|
<!--<donation-info /> -->
|
||||||
<div>
|
<div>
|
||||||
<a target="_blank" href="https://human-connection.org/spenden/">
|
<a target="_blank" href="https://human-connection.org/spenden/">
|
||||||
<ds-button primary>{{ $t('donations.donate-now') }}</ds-button>
|
<base-button filled>{{ $t('donations.donate-now') }}</base-button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="sorting-dropdown">
|
<div class="sorting-dropdown">
|
||||||
@ -43,19 +43,22 @@
|
|||||||
</template>
|
</template>
|
||||||
</masonry-grid>
|
</masonry-grid>
|
||||||
<client-only>
|
<client-only>
|
||||||
<ds-button
|
<nuxt-link :to="{ name: 'post-create' }">
|
||||||
v-tooltip="{ content: $t('contribution.newPost'), placement: 'left', delay: { show: 500 } }"
|
<base-button
|
||||||
:path="{ name: 'post-create' }"
|
v-tooltip="{
|
||||||
class="post-add-button"
|
content: $t('contribution.newPost'),
|
||||||
icon="plus"
|
placement: 'left',
|
||||||
size="x-large"
|
delay: { show: 500 },
|
||||||
primary
|
}"
|
||||||
/>
|
class="post-add-button"
|
||||||
|
icon="plus"
|
||||||
|
filled
|
||||||
|
circle
|
||||||
|
/>
|
||||||
|
</nuxt-link>
|
||||||
</client-only>
|
</client-only>
|
||||||
<client-only>
|
<client-only>
|
||||||
<infinite-loading v-if="hasMore" @infinite="showMoreContributions">
|
<infinite-loading v-if="hasMore" @infinite="showMoreContributions" />
|
||||||
<hc-load-more :loading="$apollo.loading" @click="showMoreContributions" />
|
|
||||||
</infinite-loading>
|
|
||||||
</client-only>
|
</client-only>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -65,7 +68,6 @@
|
|||||||
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
||||||
import HcEmpty from '~/components/Empty/Empty'
|
import HcEmpty from '~/components/Empty/Empty'
|
||||||
import HcPostCard from '~/components/PostCard/PostCard.vue'
|
import HcPostCard from '~/components/PostCard/PostCard.vue'
|
||||||
import HcLoadMore from '~/components/LoadMore.vue'
|
|
||||||
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
|
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
|
||||||
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
|
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
@ -78,7 +80,6 @@ export default {
|
|||||||
// DonationInfo,
|
// DonationInfo,
|
||||||
FilterMenu,
|
FilterMenu,
|
||||||
HcPostCard,
|
HcPostCard,
|
||||||
HcLoadMore,
|
|
||||||
HcEmpty,
|
HcEmpty,
|
||||||
MasonryGrid,
|
MasonryGrid,
|
||||||
MasonryGridItem,
|
MasonryGridItem,
|
||||||
@ -238,7 +239,10 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-add-button {
|
.base-button.--circle.post-add-button {
|
||||||
|
height: 54px;
|
||||||
|
width: 54px;
|
||||||
|
font-size: 26px;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import NotificationsPage from './index.vue'
|
|||||||
|
|
||||||
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
||||||
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
|
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
|
||||||
import Paginate from '~/components/Paginate/Paginate'
|
import PaginationButtons from '~/components/_new/generic/PaginationButtons/PaginationButtons'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -122,14 +122,14 @@ describe('PostIndex', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Paginate', () => {
|
describe('PaginationButtons', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('next: given a user is on the first page', () => {
|
describe('next: given a user is on the first page', () => {
|
||||||
it('adds offset to pageSize to skip first x notifications and display next page', () => {
|
it('adds offset to pageSize to skip first x notifications and display next page', () => {
|
||||||
wrapper.find(Paginate).vm.$emit('next')
|
wrapper.find(PaginationButtons).vm.$emit('next')
|
||||||
expect(wrapper.vm.offset).toEqual(12)
|
expect(wrapper.vm.offset).toEqual(12)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -137,7 +137,7 @@ describe('PostIndex', () => {
|
|||||||
describe('back: given a user is on the third page', () => {
|
describe('back: given a user is on the third page', () => {
|
||||||
it('sets offset when back is emitted', () => {
|
it('sets offset when back is emitted', () => {
|
||||||
wrapper.setData({ offset: 24 })
|
wrapper.setData({ offset: 24 })
|
||||||
wrapper.find(Paginate).vm.$emit('back')
|
wrapper.find(PaginationButtons).vm.$emit('back')
|
||||||
expect(wrapper.vm.offset).toEqual(12)
|
expect(wrapper.vm.offset).toEqual(12)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -15,21 +15,21 @@
|
|||||||
@markNotificationAsRead="markNotificationAsRead"
|
@markNotificationAsRead="markNotificationAsRead"
|
||||||
:notifications="notifications"
|
:notifications="notifications"
|
||||||
/>
|
/>
|
||||||
<paginate :hasNext="hasNext" :hasPrevious="hasPrevious" @back="back" @next="next" />
|
<pagination-buttons :hasNext="hasNext" :hasPrevious="hasPrevious" @back="back" @next="next" />
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
|
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
|
||||||
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
|
||||||
import Paginate from '~/components/Paginate/Paginate'
|
import PaginationButtons from '~/components/_new/generic/PaginationButtons/PaginationButtons'
|
||||||
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
|
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DropdownFilter,
|
DropdownFilter,
|
||||||
NotificationsTable,
|
NotificationsTable,
|
||||||
Paginate,
|
PaginationButtons,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const pageSize = 12
|
const pageSize = 12
|
||||||
|
|||||||
@ -12,7 +12,12 @@
|
|||||||
>
|
>
|
||||||
<aside v-show="post.imageBlurred" class="blur-toggle">
|
<aside v-show="post.imageBlurred" class="blur-toggle">
|
||||||
<img v-show="blurred" :src="post.image | proxyApiUrl" class="preview" />
|
<img v-show="blurred" :src="post.image | proxyApiUrl" class="preview" />
|
||||||
<ds-button :icon="blurred ? 'eye' : 'eye-slash'" primary @click="blurred = !blurred" />
|
<base-button
|
||||||
|
:icon="blurred ? 'eye' : 'eye-slash'"
|
||||||
|
filled
|
||||||
|
circle
|
||||||
|
@click="blurred = !blurred"
|
||||||
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
<hc-user :user="post.author" :date-time="post.createdAt">
|
<hc-user :user="post.author" :date-time="post.createdAt">
|
||||||
<template v-slot:dateTime>
|
<template v-slot:dateTime>
|
||||||
@ -59,13 +64,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<ds-space margin-top="x-large">
|
<ds-space margin-top="x-large">
|
||||||
<ds-flex :gutter="{ lg: 'small' }">
|
<ds-flex :gutter="{ lg: 'small' }">
|
||||||
<ds-flex-item
|
<ds-flex-item :width="{ lg: '75%', md: '75%', sm: '75%', base: '100%' }">
|
||||||
:width="{ lg: '75%', md: '75%', sm: '75%' }"
|
|
||||||
class="emotions-buttons-mobile"
|
|
||||||
>
|
|
||||||
<hc-emotions :post="post" />
|
<hc-emotions :post="post" />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item :width="{ lg: '10%', md: '3%', sm: '3%' }" />
|
|
||||||
<!-- Shout Button -->
|
<!-- Shout Button -->
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
:width="{ lg: '15%', md: '22%', sm: '22%', base: '100%' }"
|
:width="{ lg: '15%', md: '22%', sm: '22%', base: '100%' }"
|
||||||
|
|||||||
@ -88,68 +88,6 @@ describe('ProfileSlug', () => {
|
|||||||
it('displays name of the user', () => {
|
it('displays name of the user', () => {
|
||||||
expect(wrapper.text()).toContain('Bob the builder')
|
expect(wrapper.text()).toContain('Bob the builder')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('load more button', () => {
|
|
||||||
const aPost = {
|
|
||||||
title: 'I am a post',
|
|
||||||
content: 'This is my content',
|
|
||||||
contentExcerpt: 'This is my content',
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('currently no posts available (e.g. after tab switching)', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.setData({ posts: [], hasMore: false })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('displays no "load more" button', () => {
|
|
||||||
expect(wrapper.find('.load-more').exists()).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('apollo client in `loading` state', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.vm.$apollo.loading = true
|
|
||||||
})
|
|
||||||
|
|
||||||
it('never displays more than one loading spinner', () => {
|
|
||||||
expect(wrapper.findAll('.ds-spinner')).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('displays a loading spinner below the posts list', () => {
|
|
||||||
expect(wrapper.find('.ds-spinner').exists()).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('pagination returned at least as many posts as pageSize', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
const posts = [1, 2, 3, 4, 5, 6].map(id => {
|
|
||||||
return {
|
|
||||||
...aPost,
|
|
||||||
id,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
wrapper.setData({ posts })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('displays "load more" button', () => {
|
|
||||||
expect(wrapper.find('.load-more').exists()).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('apollo client in `loading` state', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.vm.$apollo.loading = true
|
|
||||||
})
|
|
||||||
|
|
||||||
it('never displays more than one loading spinner', () => {
|
|
||||||
expect(wrapper.findAll('.ds-spinner')).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('displays a loading spinner below the posts list', () => {
|
|
||||||
expect(wrapper.find('.load-more .ds-spinner').exists()).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -73,9 +73,9 @@
|
|||||||
@optimistic="optimisticFollow"
|
@optimistic="optimisticFollow"
|
||||||
@update="updateFollow"
|
@update="updateFollow"
|
||||||
/>
|
/>
|
||||||
<ds-button v-else fullwidth @click="unmuteUser(user)">
|
<base-button v-else @click="unmuteUser(user)" class="unblock-user-button">
|
||||||
{{ $t('settings.muted-users.unmute') }}
|
{{ $t('settings.blocked-users.unblock') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<template v-if="user.about">
|
<template v-if="user.about">
|
||||||
@ -215,19 +215,21 @@
|
|||||||
|
|
||||||
<ds-grid-item :row-span="2" column-span="fullWidth">
|
<ds-grid-item :row-span="2" column-span="fullWidth">
|
||||||
<ds-space centered>
|
<ds-space centered>
|
||||||
<ds-button
|
<nuxt-link :to="{ name: 'post-create' }">
|
||||||
v-if="myProfile"
|
<base-button
|
||||||
v-tooltip="{
|
v-if="myProfile"
|
||||||
content: $t('contribution.newPost'),
|
v-tooltip="{
|
||||||
placement: 'left',
|
content: $t('contribution.newPost'),
|
||||||
delay: { show: 500 },
|
placement: 'left',
|
||||||
}"
|
delay: { show: 500 },
|
||||||
:path="{ name: 'post-create' }"
|
}"
|
||||||
class="profile-post-add-button"
|
:path="{ name: 'post-create' }"
|
||||||
icon="plus"
|
class="profile-post-add-button"
|
||||||
size="large"
|
icon="plus"
|
||||||
primary
|
circle
|
||||||
/>
|
filled
|
||||||
|
/>
|
||||||
|
</nuxt-link>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</ds-grid-item>
|
</ds-grid-item>
|
||||||
|
|
||||||
@ -260,9 +262,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</masonry-grid>
|
</masonry-grid>
|
||||||
<client-only>
|
<client-only>
|
||||||
<infinite-loading v-if="hasMore" @infinite="showMoreContributions">
|
<infinite-loading v-if="hasMore" @infinite="showMoreContributions" />
|
||||||
<hc-load-more :loading="$apollo.loading" @click="showMoreContributions" />
|
|
||||||
</infinite-loading>
|
|
||||||
</client-only>
|
</client-only>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
@ -276,7 +276,6 @@ import HcPostCard from '~/components/PostCard/PostCard.vue'
|
|||||||
import HcFollowButton from '~/components/FollowButton.vue'
|
import HcFollowButton from '~/components/FollowButton.vue'
|
||||||
import HcCountTo from '~/components/CountTo.vue'
|
import HcCountTo from '~/components/CountTo.vue'
|
||||||
import HcBadges from '~/components/Badges.vue'
|
import HcBadges from '~/components/Badges.vue'
|
||||||
import HcLoadMore from '~/components/LoadMore.vue'
|
|
||||||
import HcEmpty from '~/components/Empty/Empty'
|
import HcEmpty from '~/components/Empty/Empty'
|
||||||
import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
||||||
import HcUpload from '~/components/Upload'
|
import HcUpload from '~/components/Upload'
|
||||||
@ -305,7 +304,6 @@ export default {
|
|||||||
HcFollowButton,
|
HcFollowButton,
|
||||||
HcCountTo,
|
HcCountTo,
|
||||||
HcBadges,
|
HcBadges,
|
||||||
HcLoadMore,
|
|
||||||
HcEmpty,
|
HcEmpty,
|
||||||
HcAvatar,
|
HcAvatar,
|
||||||
ContentMenu,
|
ContentMenu,
|
||||||
@ -564,4 +562,8 @@ export default {
|
|||||||
.profile-post-add-button {
|
.profile-post-add-button {
|
||||||
box-shadow: $box-shadow-x-large;
|
box-shadow: $box-shadow-x-large;
|
||||||
}
|
}
|
||||||
|
.unblock-user-button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -16,12 +16,12 @@
|
|||||||
<ds-text>
|
<ds-text>
|
||||||
{{ $t('settings.embeds.status.change.question') }}
|
{{ $t('settings.embeds.status.change.question') }}
|
||||||
</ds-text>
|
</ds-text>
|
||||||
<ds-button @click="submit" :primary="!disabled" :disabled="!disabled">
|
<base-button @click="submit" :filled="!disabled" :disabled="!disabled">
|
||||||
{{ $t('settings.embeds.status.change.deny') }}
|
{{ $t('settings.embeds.status.change.deny') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-button @click="submit" :primary="disabled" :disabled="disabled">
|
<base-button @click="submit" :filled="disabled" :disabled="disabled">
|
||||||
{{ $t('settings.embeds.status.change.allow') }}
|
{{ $t('settings.embeds.status.change.allow') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
|
|
||||||
<p>{{ $t('settings.embeds.info-description') }}</p>
|
<p>{{ $t('settings.embeds.info-description') }}</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@ -31,9 +31,9 @@
|
|||||||
:placeholder="$t('settings.data.labelBio')"
|
:placeholder="$t('settings.data.labelBio')"
|
||||||
/>
|
/>
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button icon="check" :disabled="errors" type="submit" :loading="loadingData" primary>
|
<base-button icon="check" :disabled="errors" type="submit" :loading="loadingData" filled>
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -58,9 +58,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template slot="unmuteUser" slot-scope="scope">
|
<template slot="unmuteUser" slot-scope="scope">
|
||||||
<ds-button size="small" @click="unmuteUser(scope)">
|
<base-button circle size="small" @click="unmuteUser(scope)" icon="user-plus" />
|
||||||
<ds-icon name="user-plus" />
|
|
||||||
</ds-button>
|
|
||||||
</template>
|
</template>
|
||||||
</ds-table>
|
</ds-table>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
|
|||||||
@ -17,9 +17,9 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button class="submit-button" icon="check" :disabled="errors" type="submit" primary>
|
<base-button class="submit-button" icon="check" :disabled="errors" type="submit" filled>
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -19,9 +19,9 @@
|
|||||||
<ds-space class="backendErrors" v-if="backendErrors">
|
<ds-space class="backendErrors" v-if="backendErrors">
|
||||||
<ds-text align="center" bold color="danger">{{ backendErrors.message }}</ds-text>
|
<ds-text align="center" bold color="danger">{{ backendErrors.message }}</ds-text>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-button icon="check" :disabled="errors" type="submit" primary>
|
<base-button icon="check" :disabled="errors" type="submit" filled>
|
||||||
{{ $t('actions.save') }}
|
{{ $t('actions.save') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -119,11 +119,11 @@ describe('my-social-media.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('displays the edit button', () => {
|
it('displays the edit button', () => {
|
||||||
expect(wrapper.find('a[name="edit"]').exists()).toBe(true)
|
expect(wrapper.find('.base-button[data-test="edit-button"]').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('displays the delete button', () => {
|
it('displays the delete button', () => {
|
||||||
expect(wrapper.find('a[name="delete"]').exists()).toBe(true)
|
expect(wrapper.find('.base-button[data-test="delete-button"]').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ describe('my-social-media.vue', () => {
|
|||||||
|
|
||||||
describe('editing social media link', () => {
|
describe('editing social media link', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const editButton = wrapper.find('a[name="edit"]')
|
const editButton = wrapper.find('.base-button[data-test="edit-button"]')
|
||||||
editButton.trigger('click')
|
editButton.trigger('click')
|
||||||
input = wrapper.find('input#editSocialMedia')
|
input = wrapper.find('input#editSocialMedia')
|
||||||
})
|
})
|
||||||
@ -169,7 +169,7 @@ describe('my-social-media.vue', () => {
|
|||||||
|
|
||||||
describe('deleting social media link', () => {
|
describe('deleting social media link', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const deleteButton = wrapper.find('a[name="delete"]')
|
const deleteButton = wrapper.find('.base-button[data-test="delete-button"]')
|
||||||
deleteButton.trigger('click')
|
deleteButton.trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -24,22 +24,22 @@
|
|||||||
{{ link.url }}
|
{{ link.url }}
|
||||||
</a>
|
</a>
|
||||||
<span class="divider">|</span>
|
<span class="divider">|</span>
|
||||||
<a name="edit" @click="handleEditSocialMedia(link)">
|
<base-button
|
||||||
<base-icon
|
icon="edit"
|
||||||
:aria-label="$t('actions.edit')"
|
circle
|
||||||
class="icon-button"
|
ghost
|
||||||
name="edit"
|
@click="handleEditSocialMedia(link)"
|
||||||
:title="$t('actions.edit')"
|
:title="$t('actions.edit')"
|
||||||
/>
|
data-test="edit-button"
|
||||||
</a>
|
/>
|
||||||
<a name="delete" @click="handleDeleteSocialMedia(link)">
|
<base-button
|
||||||
<base-icon
|
icon="trash"
|
||||||
:aria-label="$t('actions.delete')"
|
circle
|
||||||
class="icon-button"
|
ghost
|
||||||
name="trash"
|
@click="handleDeleteSocialMedia(link)"
|
||||||
:title="$t('actions.delete')"
|
:title="$t('actions.delete')"
|
||||||
/>
|
data-test="delete-button"
|
||||||
</a>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</ds-list-item>
|
</ds-list-item>
|
||||||
</ds-list>
|
</ds-list>
|
||||||
@ -54,12 +54,12 @@
|
|||||||
:placeholder="$t('settings.social-media.placeholder')"
|
:placeholder="$t('settings.social-media.placeholder')"
|
||||||
/>
|
/>
|
||||||
<ds-space margin-top="base">
|
<ds-space margin-top="base">
|
||||||
<ds-button primary :disabled="disabled">
|
<base-button filled :disabled="disabled" type="submit">
|
||||||
{{ editingLink.id ? $t('actions.save') : $t('settings.social-media.submit') }}
|
{{ editingLink.id ? $t('actions.save') : $t('settings.social-media.submit') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
<ds-button v-if="editingLink.id" id="cancel" ghost @click="handleCancel()">
|
<base-button v-if="editingLink.id" id="cancel" danger @click="handleCancel()">
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('actions.cancel') }}
|
||||||
</ds-button>
|
</base-button>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
@ -226,5 +226,10 @@ export default {
|
|||||||
.ds-list-item-prefix {
|
.ds-list-item-prefix {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ds-list-item-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<input id="allow-shouts" type="checkbox" v-model="shoutsAllowed" />
|
<input id="allow-shouts" type="checkbox" v-model="shoutsAllowed" />
|
||||||
<label for="allow-shouts">{{ $t('settings.privacy.make-shouts-public') }}</label>
|
<label for="allow-shouts">{{ $t('settings.privacy.make-shouts-public') }}</label>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-button primary @click="submit" :disabled="disabled">{{ $t('actions.save') }}</ds-button>
|
<base-button filled @click="submit" :disabled="disabled">{{ $t('actions.save') }}</base-button>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
<ds-container width="medium">
|
<ds-container width="medium">
|
||||||
<ds-card icon="balance-scale" :header="$t(`termsAndConditions.newTermsAndConditions`)" centered>
|
<ds-card icon="balance-scale" :header="$t(`termsAndConditions.newTermsAndConditions`)" centered>
|
||||||
<p>
|
<p>
|
||||||
<ds-button>
|
<nuxt-link :to="{ name: 'terms-and-conditions' }" target="_blank">
|
||||||
<nuxt-link class="post-link" :to="{ name: 'terms-and-conditions' }" target="_blank">
|
<base-button>
|
||||||
{{ $t(`termsAndConditions.termsAndConditionsNewConfirmText`) }}
|
{{ $t(`termsAndConditions.termsAndConditionsNewConfirmText`) }}
|
||||||
</nuxt-link>
|
</base-button>
|
||||||
</ds-button>
|
</nuxt-link>
|
||||||
</p>
|
</p>
|
||||||
<ds-text>
|
<ds-text>
|
||||||
<input id="checkbox" type="checkbox" v-model="checked" :checked="checked" />
|
<input id="checkbox" type="checkbox" v-model="checked" :checked="checked" />
|
||||||
@ -17,7 +17,9 @@
|
|||||||
</ds-text>
|
</ds-text>
|
||||||
|
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<ds-button primary @click="submit" :disabled="!checked">{{ $t(`actions.save`) }}</ds-button>
|
<base-button filled @click="submit" :disabled="!checked">
|
||||||
|
{{ $t(`actions.save`) }}
|
||||||
|
</base-button>
|
||||||
</template>
|
</template>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import { addParameters, configure } from '@storybook/vue'
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import { action } from '@storybook/addon-actions'
|
import { action } from '@storybook/addon-actions'
|
||||||
|
// eslint-disable-next-line import/no-webpack-loader-syntax
|
||||||
|
import '!style-loader!css-loader!sass-loader!../assets/_new/styles/resets.scss'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
Vue.component('nuxt-link', {
|
Vue.component('nuxt-link', {
|
||||||
@ -54,4 +56,12 @@ function loadStories() {
|
|||||||
req.keys().forEach(req)
|
req.keys().forEach(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sort stories alphabetically
|
||||||
|
addParameters({
|
||||||
|
options: {
|
||||||
|
storySort: (a, b) =>
|
||||||
|
a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, { numeric: true }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
configure(loadStories, module)
|
configure(loadStories, module)
|
||||||
|
|||||||
1965
webapp/yarn.lock
1965
webapp/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user