diff --git a/changelog/12295.txt b/changelog/12295.txt new file mode 100644 index 0000000000000..144ad0f58e02b --- /dev/null +++ b/changelog/12295.txt @@ -0,0 +1,3 @@ +```release-note:feature +ui: Creates new StatText component +``` \ No newline at end of file diff --git a/ui/README.md b/ui/README.md index 050be9aca7e47..7f9a1ad674e93 100644 --- a/ui/README.md +++ b/ui/README.md @@ -178,7 +178,32 @@ Note that placing a param inside brackets (e.g. `[closedLabel=More options]` ind 2. Generate a new story with `ember generate story [name-of-component]` 3. Inside the newly generated `stories` file, add at least one example of the component. If the component should be interactive, enable the [Storybook Knobs addon](https://github.com/storybooks/storybook/tree/master/addons/knobs). -4. Generate the `notes` file for the component with `yarn gen-story-md [name-of-component] [name-of-engine-or-addon]` (e.g. `yarn gen-md alert-banner core`). This will generate markdown documentation of the component and place it at `vault/ui/stories/[name-of-component].md`. If your component is a template-only component, you will need to manually create the markdown file. +4. Generate the `notes` file for the component with `yarn gen-story-md [name-of-component] [name-of-engine-or-addon]` (e.g. `yarn gen-md alert-banner core`). This will generate markdown documentation of the component and place it at `vault/ui/stories/[name-of-component].md`. If your component is a template-only component, you will need to manually create the markdown file. The markdown file will need to be imported in your `[component-name].stories.js` file (e.g. `import notes from './[name-of-component].md'`). +5. The completed `[component-name].stories.js` file should look something like this (with knobs): +````js +import hbs from 'htmlbars-inline-precompile'; +import { storiesOf } from '@storybook/ember'; +import { text, withKnobs } from '@storybook/addon-knobs'; +import notes from './stat-text.md'; + +storiesOf('MyComponent', module) + .addParameters({ options: { showPanel: true } }) + .addDecorator(withKnobs()) + .add( + `MyComponent`, + () => ({ + template: hbs` +
My Component
+ + `, + context: { + param: text('param', 'My parameter'), + anotherParam: boolean('anotherParam', true) + }, + }), + { notes } + ); +```` See the [Storybook Docs](https://storybook.js.org/docs/basics/introduction/) for more information on writing stories. diff --git a/ui/app/styles/components/stat-text.scss b/ui/app/styles/components/stat-text.scss new file mode 100644 index 0000000000000..814d8a87bedb1 --- /dev/null +++ b/ui/app/styles/components/stat-text.scss @@ -0,0 +1,101 @@ +.stat-text-container { + line-height: normal; + + &.l, + &.m { + .stat-label { + font-size: $size-5; + font-weight: $font-weight-semibold; + line-height: inherit; + } + .stat-text { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-700; + line-height: inherit; + } + .stat-value { + font-size: $size-3; + font-weight: $font-weight-normal; + margin-top: $spacing-s; + } + } + + &.s { + .stat-label { + font-size: $size-5; + font-weight: $font-weight-semibold; + line-height: inherit; + } + .stat-text { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-700; + line-height: inherit; + } + .stat-value { + font-size: $size-5; + font-weight: $font-weight-normal; + margin-top: $spacing-s; + } + } + + &.l-no-subText { + .stat-label { + font-size: $size-5; + font-weight: $font-weight-semibold; + line-height: inherit; + } + .stat-text { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-700; + line-height: inherit; + } + .stat-value { + font-size: $size-3; + font-weight: $font-weight-normal; + margin-top: $spacing-xxs; + } + } + + &.m-no-subText { + .stat-label { + font-size: $size-8; + font-weight: $font-weight-bold; + line-height: inherit; + } + .stat-text { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-700; + line-height: inherit; + } + .stat-value { + font-size: $size-5; + font-weight: $font-weight-normal; + margin-top: $spacing-xxs; + } + } + + &.s-no-subText { + .stat-label { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-500; + line-height: inherit; + } + .stat-text { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-700; + line-height: inherit; + } + .stat-value { + font-size: $size-8; + font-weight: $font-weight-normal; + color: $ui-gray-800; + line-height: inherit; + } + } +} diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss index a2d5b1abafd15..cc4400750871c 100644 --- a/ui/app/styles/core.scss +++ b/ui/app/styles/core.scss @@ -101,6 +101,7 @@ @import './components/shamir-progress'; @import './components/sidebar'; @import './components/splash-page'; +@import './components/stat-text'; @import './components/status-menu'; @import './components/tabs'; @import './components/text-file'; diff --git a/ui/app/styles/utils/_bulma_variables.scss b/ui/app/styles/utils/_bulma_variables.scss index bc20bb541356a..ff5aa2ca503a0 100644 --- a/ui/app/styles/utils/_bulma_variables.scss +++ b/ui/app/styles/utils/_bulma_variables.scss @@ -28,9 +28,10 @@ $family-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto' $family-monospace: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; $family-primary: $family-sans; $body-size: 14px; -$size-3: (24/14) + 0rem; -$size-7: (13/14) + 0rem; -$size-8: (12/14) + 0rem; +$size-3: (24/14) + 0rem; // ~1.714rem +$size-5: 1.25rem; +$size-7: (13/14) + 0rem; // ~.929rem +$size-8: (12/14) + 0rem; // ~.857rem $size-9: 0.75rem; $size-10: 0.5rem; $size-11: 0.25rem; diff --git a/ui/lib/core/addon/components/stat-text.js b/ui/lib/core/addon/components/stat-text.js new file mode 100644 index 0000000000000..e001c643bf4fa --- /dev/null +++ b/ui/lib/core/addon/components/stat-text.js @@ -0,0 +1,21 @@ +/** + * @module StatText + * StatText components are used to display a label and associated value beneath, with the option to include a description. + * + * @example + * ```js + * + * ``` + * @param {string} label=null - The label for the statistic + * @param {string} value=null - Value passed in, usually a number or statistic + * @param {string} size=null - Sizing changes whether or not there is subtext. If there is subtext 's' and 'l' are valid sizes. If no subtext, then 'm' is also acceptable. + * @param {string} [subText] - SubText is optional and will display below the label + */ + +import Component from '@glimmer/component'; +import layout from '../templates/components/stat-text'; +import { setComponentTemplate } from '@ember/component'; + +class StatTextComponent extends Component {} + +export default setComponentTemplate(layout, StatTextComponent); diff --git a/ui/lib/core/addon/templates/components/stat-text.hbs b/ui/lib/core/addon/templates/components/stat-text.hbs new file mode 100644 index 0000000000000..9d4bb916d16d9 --- /dev/null +++ b/ui/lib/core/addon/templates/components/stat-text.hbs @@ -0,0 +1,7 @@ +
+
{{@label}}
+ {{#if @subText}} +
{{@subText}}
+ {{/if}} +
{{@value}}
+
diff --git a/ui/lib/core/app/components/stat-text.js b/ui/lib/core/app/components/stat-text.js new file mode 100644 index 0000000000000..a15c6b560fcbc --- /dev/null +++ b/ui/lib/core/app/components/stat-text.js @@ -0,0 +1 @@ +export { default } from 'core/components/stat-text'; diff --git a/ui/lib/core/stories/stat-text.md b/ui/lib/core/stories/stat-text.md new file mode 100644 index 0000000000000..d156bfe83516a --- /dev/null +++ b/ui/lib/core/stories/stat-text.md @@ -0,0 +1,26 @@ + + +## StatText +StatText components are used to display a label and associated value beneath, with the option to include a description. + +**Params** + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| label | string | null | The label for the statistic | +| value | string | null | Value passed in, usually a number or statistic | +| size | string | null | Sizing changes whether or not there is subtext. If there is subtext 's' and 'l' are valid sizes. If no subtext, then 'm' is also acceptable. | +| [subText] | string | | SubText is optional and will display below the label | + +**Example** + +```js + +``` + +**See** + +- [Uses of StatText](https://github.com/hashicorp/vault/search?l=Handlebars&q=StatText+OR+stat-text) +- [StatText Source Code](https://github.com/hashicorp/vault/blob/master/ui/lib/core/addon/components/stat-text.js) + +--- diff --git a/ui/lib/core/stories/stat-text.stories.js b/ui/lib/core/stories/stat-text.stories.js new file mode 100644 index 0000000000000..3217838b47011 --- /dev/null +++ b/ui/lib/core/stories/stat-text.stories.js @@ -0,0 +1,28 @@ +import hbs from 'htmlbars-inline-precompile'; +import { storiesOf } from '@storybook/ember'; +import { text, withKnobs } from '@storybook/addon-knobs'; +import notes from './stat-text.md'; + +storiesOf('StatText', module) + .addParameters({ options: { showPanel: true } }) + .addDecorator(withKnobs()) + .add( + `StatText`, + () => ({ + template: hbs` +
StatText Component
+ + `, + context: { + label: text('label', 'Active Clients'), + value: text('value', '4,198'), + size: text('size', 'l'), + subText: text('subText', 'These are your active clients'), + }, + }), + { notes } + ); diff --git a/ui/tests/integration/components/stat-text-test.js b/ui/tests/integration/components/stat-text-test.js new file mode 100644 index 0000000000000..2c1f2bf61af72 --- /dev/null +++ b/ui/tests/integration/components/stat-text-test.js @@ -0,0 +1,29 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | StatText', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + await render(hbs``); + + assert.dom('[data-test-stat-text-container]').exists('renders element'); + }); + + test('it renders passed in attributes', async function(assert) { + this.set('label', 'A Label'); + this.set('value', '9,999'); + this.set('size', 'l'); + this.set('subText', 'This is my description'); + + await render( + hbs`` + ); + + assert.dom('.stat-label').hasText(this.label, 'renders label'); + assert.dom('.stat-text').hasText(this.subText, 'renders subtext'); + assert.dom('.stat-value').hasText(this.value, 'renders value'); + }); +});