Merge branch 'master' of github.com:Human-Connection/Human-Connection into dependabot/npm_and_yarn/webapp/vue/test-utils-1.0.0-beta.30

This commit is contained in:
mattwr18 2020-01-16 13:19:33 +01:00
commit 83491e15c8
77 changed files with 4116 additions and 2611 deletions

1
.github/stale.yml vendored
View File

@ -6,6 +6,7 @@ daysUntilClose: 30
exemptLabels: exemptLabels:
- pinned - pinned
- security - security
- bounty
# Label to use when marking an issue as stale # Label to use when marking an issue as stale
staleLabel: stale staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable # Comment to post when marking an issue as stale. Set to `false` to disable

View File

@ -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.9.5",
"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.7.7", "@babel/cli": "~7.8.3",
"@babel/core": "~7.7.7", "@babel/core": "~7.8.3",
"@babel/node": "~7.7.7", "@babel/node": "~7.8.3",
"@babel/plugin-proposal-throw-expressions": "^7.7.4", "@babel/plugin-proposal-throw-expressions": "^7.8.3",
"@babel/preset-env": "~7.7.7", "@babel/preset-env": "~7.8.3",
"@babel/register": "~7.7.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",
@ -112,8 +112,8 @@
"eslint": "~6.8.0", "eslint": "~6.8.0",
"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-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",

File diff suppressed because it is too large Load Diff

View File

@ -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')

View File

@ -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()
}) })

View File

@ -243,7 +243,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();
}); });
@ -449,7 +449,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({

View File

@ -21,16 +21,16 @@
"version": "auto-changelog -p" "version": "auto-changelog -p"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.7.7", "@babel/core": "^7.8.3",
"@babel/preset-env": "^7.7.7", "@babel/preset-env": "^7.8.3",
"@babel/register": "^7.7.7", "@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.1", "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",

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
* {
box-sizing: border-box;
}
button {
padding: 0;
background: transparent;
border: none;
font-family: inherit;
font-size: inherit;
}

View File

@ -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);
@ -246,6 +250,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 Buttons
* @presenter Spacing
*/
$size-icon-base: 16px;
/** /**
* @tokens Shadow * @tokens Shadow
* @presenter Shadow * @presenter Shadow
@ -291,6 +310,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

View File

@ -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>

View File

@ -75,7 +75,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 Vue.nextTick() await Vue.nextTick()
await wrapper.find('.cancelBtn').trigger('submit') await wrapper.find('[data-test="cancel-button"]').trigger('submit')
expect(cancelMethodSpy).toHaveBeenCalledTimes(1) expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
}) })
@ -163,13 +163,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]])
}) })
}) })

View File

@ -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%' }" />
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '30%', xs: '30%' }">
<ds-button
:disabled="disabled && !update" :disabled="disabled && !update"
ghost @click="handleCancel"
class="cancelBtn" data-test="cancel-button"
@click.prevent="handleCancel" danger
> >
{{ $t('actions.cancel') }} {{ $t('actions.cancel') }}
</ds-button> </base-button>
</ds-flex-item> <base-button type="submit" :loading="loading" :disabled="disabled || errors" filled>
<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') }} {{ $t('post.comment.submit') }}
</ds-button> </base-button>
</ds-flex-item> </div>
</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>

View File

@ -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', () => {

View File

@ -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>

View File

@ -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
} }

View File

@ -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">

View File

@ -262,7 +262,7 @@ describe('ContributionForm.vue', () => {
describe('cancel', () => { describe('cancel', () => {
it('calls $router.back() when cancel button clicked', () => { it('calls $router.back() when cancel button clicked', () => {
cancelBtn = wrapper.find('.cancel-button') cancelBtn = wrapper.find('[data-test="cancel-button"]')
cancelBtn.trigger('click') cancelBtn.trigger('click')
expect(mocks.$router.back).toHaveBeenCalledTimes(1) expect(mocks.$router.back).toHaveBeenCalledTimes(1)
}) })

View File

@ -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>

View File

@ -62,7 +62,13 @@
/> />
</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"> <ds-button
icon="trash"
danger
filled
:disabled="!deleteEnabled"
@click="handleSubmit"
>
{{ $t('settings.deleteUserAccount.name') }} {{ $t('settings.deleteUserAccount.name') }}
</ds-button> </ds-button>
</ds-flex-item> </ds-flex-item>

View File

@ -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')
}) })

View File

@ -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>

View File

@ -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>

View File

@ -1,6 +1,6 @@
<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"
@ -14,17 +14,14 @@
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>
</ds-space> <base-button :disabled="disabled" filled name="submit" type="submit">
<ds-button :disabled="disabled" primary fullwidth name="submit" type="submit">
{{ $t('components.enter-nonce.form.next') }} {{ $t('components.enter-nonce.form.next') }}
</ds-button> </base-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>

View File

@ -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)
}) })
}) })

View File

@ -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>

View File

@ -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>

View File

@ -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', () => {

View File

@ -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" />

View File

@ -13,17 +13,18 @@
<ds-flex-item width="10%" /> <ds-flex-item width="10%" />
<ds-space margin-bottom="xx-small" /> <ds-space margin-bottom="xx-small" />
<ds-flex-item width="100%"> <ds-flex-item width="100%">
<div class="follow-button"> <div class="follow-filter-button">
<ds-button <base-button
data-test="filter-by-followed"
icon="user-plus"
circle
:filled="filteredByUsersFollowed"
@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"
:primary="filteredByUsersFollowed"
@click="toggleFilteredByFollowed(user.id)"
/> />
<ds-space margin-bottom="x-small" /> <ds-space margin-bottom="x-small" />
<ds-flex-item> <ds-flex-item>
@ -36,14 +37,9 @@
</ds-flex-item> </ds-flex-item>
<div v-for="emotion in emotionsArray" :key="emotion"> <div v-for="emotion in emotionsArray" :key="emotion">
<ds-flex-item :width="{ lg: '100%' }"> <ds-flex-item :width="{ lg: '100%' }">
<ds-button <base-button @click="toogleFilteredByEmotions(emotion)" class="emotions-buttons" circle>
size="large"
ghost
@click="toogleFilteredByEmotions(emotion)"
class="emotions-buttons"
>
<img :src="iconPath(emotion)" width="40" /> <img :src="iconPath(emotion)" width="40" />
</ds-button> </base-button>
<ds-space margin-bottom="x-small" /> <ds-space margin-bottom="x-small" />
<ds-flex-item class="emotions-mobile-space text-center"> <ds-flex-item class="emotions-mobile-space text-center">
<label class="emotions-label">{{ $t(`contribution.emotions-label.${emotion}`) }}</label> <label class="emotions-label">{{ $t(`contribution.emotions-label.${emotion}`) }}</label>
@ -99,7 +95,7 @@ export default {
#filter-posts-header { #filter-posts-header {
text-align: center; text-align: center;
} }
.follow-button { .follow-filter-button {
float: left; float: left;
} }
} }

View File

@ -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>

View File

@ -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>

View File

@ -51,11 +51,10 @@ describe('LoginForm', () => {
it('dispatches login with form data', () => { it('dispatches login with form data', () => {
fillIn(Wrapper()) fillIn(Wrapper())
expect(storeMocks.actions['auth/login']).toHaveBeenCalledWith( expect(storeMocks.actions['auth/login']).toHaveBeenCalledWith(expect.any(Object), {
expect.any(Object), email: 'email@example.org',
{ email: 'email@example.org', password: '1234' }, password: '1234',
undefined, })
)
}) })
}) })
}) })

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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 {

View File

@ -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')
}) })
}) })
}) })

View File

@ -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 {

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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" />

View File

@ -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="{

View File

@ -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>
`,
}))

View 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>

View File

@ -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', () => ({

View File

@ -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;

View File

@ -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')
})
}) })
it('uses a round tag', () => { describe('given a valid icon name and count above 100', () => {
expect(tag.classes()).toContain('ds-tag-round') beforeEach(() => {
propsData = { icon: 'comments', count: 750 }
wrapper = Wrapper()
count = wrapper.find('.count')
}) })
it('uses a primary button', () => { it('renders the icon', () => {
expect(tag.classes()).toContain('ds-tag-primary') expect(wrapper.find(BaseIcon).exists()).toBe(true)
})
it('renders the capped count with a plus', () => {
expect(count.text()).toEqual('99+')
}) })
}) })
}) })

View File

@ -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" />
`, `,
})) }))

View File

@ -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>

View File

@ -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 />',
}))

View File

@ -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>

View File

@ -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', () => {

View File

@ -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>

View File

@ -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

View File

@ -59,7 +59,7 @@
"dependencies": { "dependencies": {
"@human-connection/styleguide": "0.5.22", "@human-connection/styleguide": "0.5.22",
"@nuxtjs/apollo": "^4.0.0-rc19", "@nuxtjs/apollo": "^4.0.0-rc19",
"@nuxtjs/axios": "~5.9.2", "@nuxtjs/axios": "~5.9.3",
"@nuxtjs/dotenv": "~1.4.1", "@nuxtjs/dotenv": "~1.4.1",
"@nuxtjs/pwa": "^3.0.0-beta.19", "@nuxtjs/pwa": "^3.0.0-beta.19",
"@nuxtjs/sentry": "^3.0.1", "@nuxtjs/sentry": "^3.0.1",
@ -76,7 +76,7 @@
"jsonwebtoken": "~8.5.1", "jsonwebtoken": "~8.5.1",
"linkify-it": "~2.2.0", "linkify-it": "~2.2.0",
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"nuxt": "~2.10.2", "nuxt": "~2.11.0",
"nuxt-dropzone": "^1.0.4", "nuxt-dropzone": "^1.0.4",
"nuxt-env": "~0.1.0", "nuxt-env": "~0.1.0",
"stack-utils": "^2.0.1", "stack-utils": "^2.0.1",
@ -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.2.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.2.8", "@storybook/addon-actions": "^5.3.3",
"@storybook/addon-notes": "^5.2.8", "@storybook/addon-notes": "^5.3.3",
"@storybook/vue": "~5.2.8", "@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",
@ -115,13 +115,13 @@
"babel-plugin-require-context-hook": "^1.0.0", "babel-plugin-require-context-hook": "^1.0.0",
"babel-preset-vue": "~2.0.2", "babel-preset-vue": "~2.0.2",
"core-js": "~2.6.10", "core-js": "~2.6.10",
"css-loader": "~3.4.1", "css-loader": "~3.4.2",
"eslint": "~6.8.0", "eslint": "~6.8.0",
"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",
@ -143,6 +143,6 @@
"vue-jest": "~3.0.5", "vue-jest": "~3.0.5",
"vue-loader": "~15.8.3", "vue-loader": "~15.8.3",
"vue-svg-loader": "~0.15.0", "vue-svg-loader": "~0.15.0",
"vue-template-compiler": "^2.6.10" "vue-template-compiler": "^2.6.11"
} }
} }

View File

@ -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>

View File

@ -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"> <hc-paginate :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 HcPaginate from '~/components/Paginate/Paginate'
export default { export default {
components: {
HcPaginate,
},
data() { data() {
const pageSize = 15 const pageSize = 15
return { return {

View File

@ -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,14 +43,19 @@
</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="{
content: $t('contribution.newPost'),
placement: 'left',
delay: { show: 500 },
}"
class="post-add-button" class="post-add-button"
icon="plus" icon="plus"
size="x-large" filled
primary 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">
@ -238,7 +243,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;

View File

@ -73,9 +73,9 @@
@optimistic="optimisticFollow" @optimistic="optimisticFollow"
@update="updateFollow" @update="updateFollow"
/> />
<ds-button v-else fullwidth @click="unblock(user)"> <base-button v-else @click="unblock(user)" class="unblock-user-button">
{{ $t('settings.blocked-users.unblock') }} {{ $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,7 +215,8 @@
<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' }">
<base-button
v-if="myProfile" v-if="myProfile"
v-tooltip="{ v-tooltip="{
content: $t('contribution.newPost'), content: $t('contribution.newPost'),
@ -225,9 +226,10 @@
:path="{ name: 'post-create' }" :path="{ name: 'post-create' }"
class="profile-post-add-button" class="profile-post-add-button"
icon="plus" icon="plus"
size="large" circle
primary filled
/> />
</nuxt-link>
</ds-space> </ds-space>
</ds-grid-item> </ds-grid-item>
@ -554,4 +556,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>

View File

@ -58,7 +58,7 @@
</template> </template>
<template slot="unblock" slot-scope="scope"> <template slot="unblock" slot-scope="scope">
<ds-button size="small" @click="unblock(scope)"><ds-icon name="user-plus" /></ds-button> <base-button circle size="small" @click="unblock(scope)" icon="user-plus" />
</template> </template>
</ds-table> </ds-table>
</ds-card> </ds-card>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -118,11 +118,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)
}) })
}) })
@ -135,7 +135,7 @@ describe('my-social-media.vue', () => {
describe('editing social media link', () => { describe('editing social media link', () => {
beforeEach(async () => { beforeEach(async () => {
const editButton = wrapper.find('a[name="edit"]') const editButton = wrapper.find('.base-button[data-test="edit-button"]')
editButton.trigger('click') editButton.trigger('click')
await Vue.nextTick() await Vue.nextTick()
input = wrapper.find('input#editSocialMedia') input = wrapper.find('input#editSocialMedia')
@ -167,7 +167,7 @@ describe('my-social-media.vue', () => {
describe('deleting social media link', () => { describe('deleting social media link', () => {
beforeEach(async () => { beforeEach(async () => {
const deleteButton = wrapper.find('a[name="delete"]') const deleteButton = wrapper.find('.base-button[data-test="delete-button"]')
deleteButton.trigger('click') deleteButton.trigger('click')
await Vue.nextTick() await Vue.nextTick()
}) })

View File

@ -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> <base-button
<a name="delete" @click="handleDeleteSocialMedia(link)"> icon="trash"
<base-icon circle
:aria-label="$t('actions.delete')" ghost
class="icon-button" @click="handleDeleteSocialMedia(link)"
name="trash"
: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>

View File

@ -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>

View File

@ -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`) }}
</base-button>
</nuxt-link> </nuxt-link>
</ds-button>
</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>

View File

@ -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)

File diff suppressed because it is too large Load Diff

1130
yarn.lock

File diff suppressed because it is too large Load Diff