From ba9743384513b9a59b28d156b6a569937480e887 Mon Sep 17 00:00:00 2001 From: "Grigorii K. Shartsev" Date: Wed, 24 Jul 2024 15:15:42 +0200 Subject: [PATCH] feat(NcCounterBubble): add count and limit props instead of slot Signed-off-by: Grigorii K. Shartsev --- .../NcCounterBubble/NcCounterBubble.vue | 148 ++++++++++++++++-- .../NcCounterBubble/NcCounterBubble.spec.js | 68 ++++++++ 2 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 tests/unit/components/NcCounterBubble/NcCounterBubble.spec.js diff --git a/src/components/NcCounterBubble/NcCounterBubble.vue b/src/components/NcCounterBubble/NcCounterBubble.vue index d1b5d4a057..0c1c3ddf6f 100644 --- a/src/components/NcCounterBubble/NcCounterBubble.vue +++ b/src/components/NcCounterBubble/NcCounterBubble.vue @@ -8,27 +8,129 @@ ### Normal Counter ``` -314+ + ``` -### Outlined Counter (e.g team mentions) +### Limited ``` -314+ + + + ``` -### Highlighted Counter (e.g direct mentions) +### Style type ``` -314+ + + + ``` +### Custom content + +Deprecated. Use the `count` prop instead. + +``` +314+ +```` + @@ -42,7 +144,7 @@ export default { type: String, default: '', validator(value) { - return ['highlighted', 'outlined', ''].indexOf(value) !== -1 + return ['highlighted', 'outlined', ''].includes(value) }, }, @@ -55,6 +157,28 @@ export default { type: Boolean, default: false, }, + + /** + * The count to display in the counter bubble. + * Alternatively, you can pass any value to the default slot. + */ + count: { + type: Number, + required: false, + default: 0, + }, + + /** + * The maximal count number to be display. If the count is higher then "max+" is displayed. + * For example, with limit 999, 1000 will be displayed as "999+". + * Only works if the count is set via the `count` prop and not via the default slot. + * Set 0 to disable the limit. + */ + limit: { + type: Number, + required: false, + default: 999, + }, }, computed: { @@ -65,6 +189,12 @@ export default { active: this.active, } }, + + countWithLimit() { + return this.count && this.limit && this.count > this.limit + ? `${this.limit}+` + : this.count + }, }, } @@ -78,8 +208,7 @@ export default { max-width: var(--default-clickable-area); min-width: calc(1lh + 2 * var(--default-grid-baseline)); // Make it not narrower than a circle text-align: center; - text-overflow: ellipsis; - line-height: 1em; + line-height: 1; padding: var(--default-grid-baseline); border-radius: var(--border-radius-pill); background-color: var(--color-primary-element-light); @@ -106,6 +235,7 @@ export default { background: transparent; box-shadow: inset 0 0 0 2px; } + &--outlined.active { color: var(--color-main-background); box-shadow: inset 0 0 0 2px; diff --git a/tests/unit/components/NcCounterBubble/NcCounterBubble.spec.js b/tests/unit/components/NcCounterBubble/NcCounterBubble.spec.js new file mode 100644 index 0000000000..cb5b527d87 --- /dev/null +++ b/tests/unit/components/NcCounterBubble/NcCounterBubble.spec.js @@ -0,0 +1,68 @@ +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { describe, it, expect } from '@jest/globals' +import { mount } from '@vue/test-utils' +import NcCounterBubble from '../../../../src/components/NcCounterBubble/NcCounterBubble.vue' + +describe('NcCounterBubble', () => { + describe('displaying count', () => { + it('should render content', () => { + const wrapper = mount(NcCounterBubble, { slots: { default: '314+' } }) + expect(wrapper.text()).toBe('314+') + }) + + it('should render count from prop', () => { + const wrapper = mount(NcCounterBubble, { propsData: { count: 314 } }) + expect(wrapper.text()).toBe('314') + }) + }) + + describe('using limit', () => { + it('should render count less than 999 as it is', () => { + const wrapper = mount(NcCounterBubble, { propsData: { count: 999 } }) + expect(wrapper.text()).toBe('999') + }) + + it('should render count more than 999 as 999+ by default', () => { + const wrapper = mount(NcCounterBubble, { propsData: { count: 1000 } }) + expect(wrapper.text()).toBe('999+') + }) + + it('should render count more than limit as limit+', () => { + const wrapper = mount(NcCounterBubble, { propsData: { count: 10, limit: 9 } }) + expect(wrapper.text()).toBe('9+') + }) + + it('should render count without limit when limit is 0', () => { + const wrapper = mount(NcCounterBubble, { propsData: { count: 10000000000, limit: 0 } }) + expect(wrapper.text()).toBe('10000000000') + }) + }) + + describe('with styling', () => { + it('should not have any additional classes', () => { + const wrapper = mount(NcCounterBubble) + expect(wrapper.classes('counter-bubble__counter--highlighted')).toBeFalsy() + expect(wrapper.classes('counter-bubble__counter--outlined')).toBeFalsy() + expect(wrapper.classes('active')).toBeFalsy() + }) + + it('should have class "counter-bubble__counter--highlighted" when type="highlighted"', () => { + const wrapper = mount(NcCounterBubble, { propsData: { type: 'highlighted' } }) + expect(wrapper.classes('counter-bubble__counter--highlighted')).toBeTruthy() + }) + + it('should have class "counter-bubble__counter--outlined" when type="outlined"', () => { + const wrapper = mount(NcCounterBubble, { propsData: { type: 'outlined' } }) + expect(wrapper.classes('counter-bubble__counter--outlined')).toBeTruthy() + }) + + it('should have class "active" when active', () => { + const wrapper = mount(NcCounterBubble, { propsData: { active: true } }) + expect(wrapper.classes('active')).toBeTruthy() + }) + }) +})