From e50b5a4ce4b5d56919a78f96446d42a4b76899c7 Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Fri, 17 Jan 2020 14:36:53 +0100 Subject: [PATCH 1/3] chore(helpers): fix action logger demos when switching canvas/docs --- .../stories/index.stories.mdx | 76 +++++++++++-------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/packages/helpers/sb-action-logger/stories/index.stories.mdx b/packages/helpers/sb-action-logger/stories/index.stories.mdx index d1beeddfb..9f59c9a40 100644 --- a/packages/helpers/sb-action-logger/stories/index.stories.mdx +++ b/packages/helpers/sb-action-logger/stories/index.stories.mdx @@ -21,31 +21,42 @@ import '../../sb-action-logger.js'; A visual element to show action logs in Storybook demos `sb-action-logger` - {html` - -
To log: Hello, World!
- - - `} + {() => { + const uid = Math.random().toString(36).substr(2, 10); + return html` + +
To log: Hello, World!
+ + + `; + }}
+You need some reference to your logger. Above example shows this by using a unique ID. + +```js +const uid = Math.random().toString(36).substr(2, 10); +``` + +This connects the logger element to the trigger. + ```html
To log: Hello, World!
- + ``` -Note that you need some reference to your logger. Above example shows this by using a unique ID. - ## Features: - A public method `log` to log things to the action logger. @@ -70,12 +81,15 @@ npm i sb-action-logger ### Custom Title - {html` - - - `} + {() => { + const uid = Math.random().toString(36).substr(2, 10); + return html` + + + `; + }} @@ -101,16 +115,16 @@ Maybe in the future I will abstract this component to a more generic (ugly) one If you use an action logger inside your Story in Storybook, you will also see it in your canvas, and this may not be your intention. -One idea I have is that we can simplify the usage further by making this a Storybook (docs-)plugin or decorator or whatever. -I am not too familiar with them at the moment, but it would be cool if someone can simply enable an action logger option on a particular Story inside their .mdx, -and then actions are automatically logged to the visual logger below it. Would need to figure out how to catch the action and pass it to the visual logger element. +One idea is to simplify the usage further by making this a Storybook (docs-)plugin or decorator or whatever. +It would be cool if someone can simply enable an action logger option on a particular Story inside their .mdx, +and then actions are automatically logged to the visual logger below it. +Would need to figure out how to catch the action and pass it to the visual logger element. -I have not investigated yet on the how, but that is the rough idea. Feel free to help out here :) +Isn't investigated yet on the how, but that is the rough idea. ## Future -I plan on adding more features. -They can always be found in the test folder where I specify new features as tests first, and then I skip them until I implement them. Easy to find them that way. -If the feature you'd like is not in the tests, I probably did not think about it yet or did not plan to do it yet, so in that case feel free to make an issue so we can add it. +New planned features can be found in the test folder where they are specified as skipped tests. +If the feature you'd like is not in the tests, feel free to make an issue so we can add it. -I'm happy to accept pull requests for skipped tests (features to be added), see the CONTRIBUTING.md on GitHub for more details on how to contribute to this codebase. +See our CONTRIBUTING.md for more guidelines on how to contribute. From 288c2531e66a10a5fbe085d8ed69e2c676f818c8 Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Fri, 17 Jan 2020 16:08:13 +0100 Subject: [PATCH 2/3] feat(helpers): add handling duplicate consecutive logs to action logger --- karma.conf.js | 2 +- .../sb-action-logger/src/SbActionLogger.js | 102 ++++++++++++++---- .../stories/index.stories.mdx | 12 +-- .../test/sb-action-logger.test.js | 27 +++-- 4 files changed, 104 insertions(+), 39 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 61bff4482..00921513f 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -12,7 +12,7 @@ module.exports = config => { // npm run test -- --grep test/foo/bar.test.js // npm run test -- --grep test/bar/* { - pattern: config.grep ? config.grep : 'packages/*/test/**/*.test.js', + pattern: config.grep ? config.grep : 'packages/**/*/test/**/*.test.js', type: 'module', }, ], diff --git a/packages/helpers/sb-action-logger/src/SbActionLogger.js b/packages/helpers/sb-action-logger/src/SbActionLogger.js index 80595a9d7..e9404d834 100644 --- a/packages/helpers/sb-action-logger/src/SbActionLogger.js +++ b/packages/helpers/sb-action-logger/src/SbActionLogger.js @@ -21,6 +21,8 @@ export class SbActionLogger extends LitElement { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); display: block; + font-family: 'Nunito Sans', -apple-system, '.SFNSText-Regular', 'San Francisco', + BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif; } .header__info { @@ -88,6 +90,7 @@ export class SbActionLogger extends LitElement { .logger__log { padding: 16px; + display: flex; } .logger__log:not(:last-child) { @@ -102,6 +105,16 @@ export class SbActionLogger extends LitElement { white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } + + .logger__log-count { + line-height: 8px; + font-size: 12px; + padding: 4px; + border-radius: 4px; + margin-right: 8px; + color: white; + background-color: #777; + } `; } @@ -111,6 +124,10 @@ export class SbActionLogger extends LitElement { this.__logCounter = 0; } + get loggerEl() { + return this.shadowRoot.querySelector('.logger'); + } + /** * Renders the passed content as a node, and appends it to the logger * Only supports simple values, will be interpreted to a String @@ -119,14 +136,15 @@ export class SbActionLogger extends LitElement { * @param {} content Content to be logged to the action logger */ log(content) { - const loggerEl = this.shadowRoot.querySelector('.logger'); - const offlineRenderContainer = document.createElement('div'); - render(this._logTemplate(content), offlineRenderContainer); - // TODO: Feature, combine duplicate consecutive logs as 1 dom element and add a counter for dupes - loggerEl.appendChild(offlineRenderContainer.firstElementChild); - this.__logCounter += 1; + if (this.__isConsecutiveDuplicateLog(content)) { + this.__handleConsecutiveDuplicateLog(); + } else { + this.__appendLog(content); + this.loggerEl.scrollTo({ top: this.loggerEl.scrollHeight, behavior: 'smooth' }); + } + + this.__logCounter += 1; // increment total log counter this.__animateCue(); - loggerEl.scrollTo({ top: loggerEl.scrollHeight, behavior: 'smooth' }); } /** @@ -143,6 +161,60 @@ export class SbActionLogger extends LitElement { `; } + render() { + return html` +
+
+

${this.title}

+
${this.__logCounter}
+ +
+
+
+
+
+
+ `; + } + + __appendLog(content) { + const offlineRenderContainer = document.createElement('div'); + render(this._logTemplate(content), offlineRenderContainer); + this.loggerEl.appendChild(offlineRenderContainer.firstElementChild); + } + + __isConsecutiveDuplicateLog(content) { + if ( + this.loggerEl.lastElementChild && + this.loggerEl.lastElementChild.querySelector('code').textContent.trim() === content + ) { + return true; + } + return false; + } + + __handleConsecutiveDuplicateLog() { + if (!this.loggerEl.lastElementChild.querySelector('.logger__log-count')) { + this.__prependLogCounterElement(); + } + + // Increment log counter for these duplicate logs + const logCounter = this.loggerEl.lastElementChild.querySelector('.logger__log-count'); + let incrementedLogCount = logCounter.textContent; + incrementedLogCount = parseInt(incrementedLogCount, 10) + 1; + logCounter.innerText = incrementedLogCount; + } + + __prependLogCounterElement() { + const countEl = document.createElement('div'); + countEl.classList.add('logger__log-count'); + countEl.innerText = 1; + this.loggerEl.lastElementChild.insertBefore( + countEl, + this.loggerEl.lastElementChild.firstElementChild, + ); + } + __animateCue() { const cueEl = this.shadowRoot.querySelector('.header__log-cue-overlay'); cueEl.classList.remove('header__log-cue-overlay--slide'); @@ -159,20 +231,4 @@ export class SbActionLogger extends LitElement { loggerEl.innerHTML = ''; this.__logCounter = 0; } - - render() { - return html` -
-
-

${this.title}

-
${this.__logCounter}
- -
-
-
-
-
-
- `; - } } diff --git a/packages/helpers/sb-action-logger/stories/index.stories.mdx b/packages/helpers/sb-action-logger/stories/index.stories.mdx index 9f59c9a40..071d09a28 100644 --- a/packages/helpers/sb-action-logger/stories/index.stories.mdx +++ b/packages/helpers/sb-action-logger/stories/index.stories.mdx @@ -24,18 +24,18 @@ A visual element to show action logs in Storybook demos `sb-action-logger` {() => { const uid = Math.random().toString(36).substr(2, 10); return html` -
To log: Hello, World!
+
Or to log: What's up, Planet!
+ `; }} diff --git a/packages/helpers/sb-action-logger/test/sb-action-logger.test.js b/packages/helpers/sb-action-logger/test/sb-action-logger.test.js index 80a7a45e8..6aa0a2d8b 100644 --- a/packages/helpers/sb-action-logger/test/sb-action-logger.test.js +++ b/packages/helpers/sb-action-logger/test/sb-action-logger.test.js @@ -91,22 +91,31 @@ describe('sb-action-logger', () => { expect(el.shadowRoot.querySelector('.logger').children.length).to.equal(0); }); - it('duplicate consecutive logs are kept as one', async () => { + it('duplicate consecutive logs are kept as one, adds a visual counter', async () => { const el = await fixture(html` `); - expect(el).to.be.true; + + el.log('Hello, World!'); + el.log('Hello, World!'); + el.log('Hello, World!'); // 3 consecutive dupes + el.log('Hello, Earth!'); + el.log('Hello, World!'); + el.log('Hello, Planet!'); + el.log('Hello, Planet!'); // 2 consecutive dupes + + const loggerEl = el.shadowRoot.querySelector('.logger'); + + const firstLog = loggerEl.firstElementChild; + const lastLog = loggerEl.lastElementChild; + + expect(loggerEl.children.length).to.equal(4); + expect(firstLog.querySelector('.logger__log-count').innerText).to.equal('3'); + expect(lastLog.querySelector('.logger__log-count').innerText).to.equal('2'); }); }); describe('Potential Additional Features', () => { - it.skip('duplicate consecutive adds a visual counter to count per duplicate', async () => { - const el = await fixture(html` - - `); - expect(el).to.be.true; - }); - // This is handy if you don't want to keep track of updates it.skip('can be set to mode=simple for only showing a single log statement', async () => { const el = await fixture(html` From d25793758f57af075e13801d6fefcd239b43fa2b Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Fri, 17 Jan 2020 16:32:36 +0100 Subject: [PATCH 3/3] feat(helpers): add simple mode to action logger --- .../sb-action-logger/custom-elements.json | 6 +++ .../sb-action-logger/src/SbActionLogger.js | 8 +++- .../stories/index.stories.mdx | 37 +++++++++++++++++++ .../test/sb-action-logger.test.js | 25 ++++++++++--- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/packages/helpers/sb-action-logger/custom-elements.json b/packages/helpers/sb-action-logger/custom-elements.json index 22cb809c4..fb97ea31b 100644 --- a/packages/helpers/sb-action-logger/custom-elements.json +++ b/packages/helpers/sb-action-logger/custom-elements.json @@ -10,6 +10,12 @@ "type": "String", "description": "The title of action logger", "default": "Action Logger" + }, + { + "name": "simple", + "type": "Boolean", + "description": "Simple mode, which only shows a single log", + "default": "false" } ], "events": [], diff --git a/packages/helpers/sb-action-logger/src/SbActionLogger.js b/packages/helpers/sb-action-logger/src/SbActionLogger.js index e9404d834..bdb5defed 100644 --- a/packages/helpers/sb-action-logger/src/SbActionLogger.js +++ b/packages/helpers/sb-action-logger/src/SbActionLogger.js @@ -6,6 +6,7 @@ export class SbActionLogger extends LitElement { static get properties() { return { title: { type: String, reflect: true }, + simple: { type: Boolean, reflect: true }, __logCounter: { type: Number }, }; } @@ -136,6 +137,12 @@ export class SbActionLogger extends LitElement { * @param {} content Content to be logged to the action logger */ log(content) { + this.__animateCue(); + + if (this.simple) { + this.__clearLogs(); + } + if (this.__isConsecutiveDuplicateLog(content)) { this.__handleConsecutiveDuplicateLog(); } else { @@ -144,7 +151,6 @@ export class SbActionLogger extends LitElement { } this.__logCounter += 1; // increment total log counter - this.__animateCue(); } /** diff --git a/packages/helpers/sb-action-logger/stories/index.stories.mdx b/packages/helpers/sb-action-logger/stories/index.stories.mdx index 071d09a28..e72421293 100644 --- a/packages/helpers/sb-action-logger/stories/index.stories.mdx +++ b/packages/helpers/sb-action-logger/stories/index.stories.mdx @@ -63,6 +63,8 @@ This connects the logger element to the trigger. - Overridable `title` property. - Clear button to clear logs - A counter to count the total amount of logs +- Stacks consecutive duplicate logs and shows a counter +- `simple` property/attribute to only show a single log ## How to use @@ -78,8 +80,40 @@ npm i sb-action-logger ## Variations +### Simple mode + +Simple mode essentially means there is only ever 1 log. +Duplicates are not counted or stacked, but you will still see the visual cue. + + + {() => { + const uid = Math.random().toString(36).substr(2, 10); + return html` +
To log: Hello, World!
+ +
Or to log: What's up, Planet!
+ + + `; + }} +
+ +```html + +``` + ### Custom Title +You can customize the action logger title with the `.title` property. + {() => { const uid = Math.random().toString(36).substr(2, 10); @@ -92,6 +126,9 @@ npm i sb-action-logger }} +```html + +``` ## Rationale diff --git a/packages/helpers/sb-action-logger/test/sb-action-logger.test.js b/packages/helpers/sb-action-logger/test/sb-action-logger.test.js index 6aa0a2d8b..3f7681ea4 100644 --- a/packages/helpers/sb-action-logger/test/sb-action-logger.test.js +++ b/packages/helpers/sb-action-logger/test/sb-action-logger.test.js @@ -113,17 +113,30 @@ describe('sb-action-logger', () => { expect(firstLog.querySelector('.logger__log-count').innerText).to.equal('3'); expect(lastLog.querySelector('.logger__log-count').innerText).to.equal('2'); }); - }); - describe('Potential Additional Features', () => { - // This is handy if you don't want to keep track of updates - it.skip('can be set to mode=simple for only showing a single log statement', async () => { + it('can be set to simple mode for only showing a single log statement', async () => { const el = await fixture(html` `); - expect(el).to.be.true; - }); + el.log('Hello, World!'); + const loggerEl = el.shadowRoot.querySelector('.logger'); + expect(loggerEl.children.length).to.equal(1); + expect(loggerEl.firstElementChild.querySelector('code').innerText).to.equal('Hello, World!'); + + el.log('Hello, Earth!'); + expect(loggerEl.children.length).to.equal(1); + expect(loggerEl.firstElementChild.querySelector('code').innerText).to.equal('Hello, Earth!'); + + el.log('Hello, Planet!'); + el.log('Hello, Planet!'); + expect(loggerEl.children.length).to.equal(1); + expect(loggerEl.firstElementChild.querySelector('code').innerText).to.equal('Hello, Planet!'); + expect(loggerEl.firstElementChild.querySelector('.logger__log-count')).to.be.null; + }); + }); + + describe('Potential Additional Features', () => { it.skip('fires a sb-action-logged event when something is logged to the logger', async () => { const el = await fixture(html`