From b22be1234eeab7bea67172bc4b9e3084af21a835 Mon Sep 17 00:00:00 2001 From: "pearu.sarv" Date: Mon, 2 Feb 2026 16:07:28 +0200 Subject: [PATCH] feat(progress-bar): Add community progress bar #299 --- .../progress-bar/progress-bar.component.html | 20 +++++ .../progress-bar/progress-bar.component.scss | 56 ++++++++++++ .../progress-bar/progress-bar.component.ts | 30 +++++++ .../progress-bar/progress-bar.stories.ts | 86 +++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 community/components/helpers/progress-bar/progress-bar.component.html create mode 100644 community/components/helpers/progress-bar/progress-bar.component.scss create mode 100644 community/components/helpers/progress-bar/progress-bar.component.ts create mode 100644 community/components/helpers/progress-bar/progress-bar.stories.ts diff --git a/community/components/helpers/progress-bar/progress-bar.component.html b/community/components/helpers/progress-bar/progress-bar.component.html new file mode 100644 index 00000000..ffc65cf6 --- /dev/null +++ b/community/components/helpers/progress-bar/progress-bar.component.html @@ -0,0 +1,20 @@ + + +{{ value() }}% + +@if (feedbackText(); as feedback) { + +} diff --git a/community/components/helpers/progress-bar/progress-bar.component.scss b/community/components/helpers/progress-bar/progress-bar.component.scss new file mode 100644 index 00000000..f625fe7d --- /dev/null +++ b/community/components/helpers/progress-bar/progress-bar.component.scss @@ -0,0 +1,56 @@ +@use "@tedi-design-system/core/bootstrap-utility/breakpoints"; + +.tedi-progress { + --_bar-height: var(--progress-bar-height, 8px); + --_bar-radius: var(--progress-bar-radius, 4px); + --_bar-background: var(--progress-bar-background-passive, #f9f9f9); + --_bar-border: var(--progress-bar-border-default, #838494); + --_progress-background: var(--progress-bar-background-active, #005aa3); + + display: grid; + grid-template-areas: "bar bar" ". indicator"; + grid-template-rows: 24px; + grid-template-columns: 1fr auto; + column-gap: var(--layout-grid-gutters-08, 8px); + + &__bar { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + grid-area: bar; + height: var(--_bar-height); + border-radius: var(--_bar-radius); + border: 1px solid var(--_bar-border); + width: 100%; + align-self: center; + + &::-webkit-progress-bar { + background: var(--_bar-background); + border-radius: var(--_bar-radius); + } + + &::-webkit-progress-value { + background: var(--_progress-background); + border-radius: var(--_bar-radius); + } + + &::-moz-progress-bar { + background: var(--_progress-background); + border-radius: var(--_bar-radius); + } + } + + &__indicator { + grid-area: indicator; + } + + &--small { + --_bar-height: var(--progress-bar-height-sm, 4px); + } + + &--horizontal { + @include breakpoints.media-breakpoint-up(sm) { + grid-template-areas: "bar indicator"; + } + } +} diff --git a/community/components/helpers/progress-bar/progress-bar.component.ts b/community/components/helpers/progress-bar/progress-bar.component.ts new file mode 100644 index 00000000..911581c7 --- /dev/null +++ b/community/components/helpers/progress-bar/progress-bar.component.ts @@ -0,0 +1,30 @@ +import { booleanAttribute, ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from "@angular/core"; +import { ComponentInputs, FeedbackTextComponent, generateUUID, LabelComponent } from "@tedi-design-system/angular/tedi"; + +@Component({ + selector: "tedi-progress-bar", + imports: [FeedbackTextComponent, LabelComponent], + templateUrl: "./progress-bar.component.html", + styleUrl: "./progress-bar.component.scss", + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + "[class.tedi-progress]": "true", + "[class.tedi-progress--small]": "small()", + "[class.tedi-progress--horizontal]": "direction() === 'horizontal'", + }, +}) +export class ProgressBarComponent { + progressId = input(); + value = input(0); + direction = input<'horizontal' | 'vertical'>("horizontal"); + small = input(false, { transform: booleanAttribute }); + feedbackText = input>(); + + feedbackTextId = computed(() => { + if (this.feedbackText()) { + return generateUUID(); + } + return; + }); +} diff --git a/community/components/helpers/progress-bar/progress-bar.stories.ts b/community/components/helpers/progress-bar/progress-bar.stories.ts new file mode 100644 index 00000000..e77b6d56 --- /dev/null +++ b/community/components/helpers/progress-bar/progress-bar.stories.ts @@ -0,0 +1,86 @@ +import { Meta, moduleMetadata, StoryObj } from "@storybook/angular"; +import { ProgressBarComponent } from "./progress-bar.component"; + +export default { + title: "Community/Helpers/ProgressBar", + component: ProgressBarComponent, + decorators: [ + moduleMetadata({ + imports: [ProgressBarComponent], + }), + ], + argTypes: { + progressId: { + description: + "Optional id for the progress element to bind with label etc.", + control: "text", + table: { + type: { summary: "string" }, + }, + }, + value: { + description: "Progress value between 0 and 100", + control: { type: "number", min: 0, max: 100, step: 1 }, + table: { + type: { summary: "number" }, + defaultValue: { summary: "0" }, + }, + }, + direction: { + description: "Orientation of the progress bar", + control: { type: "radio" }, + options: ["horizontal", "vertical"], + table: { + type: { summary: "'horizontal' | 'vertical'" }, + defaultValue: { summary: "horizontal" }, + }, + }, + small: { + description: "Whether it's the small variant", + control: "boolean", + table: { + type: { summary: "boolean" }, + defaultValue: { summary: "false" }, + }, + }, + feedbackText: { + description: + "Optional feedback text displayed alongside the progress bar. Accepts `FeedbackTextComponent` inputs.", + control: "object", + table: { + type: { summary: "ComponentInputs" }, + }, + }, + }, +} as Meta; + +export const Default: StoryObj = { + args: { + value: 50, + direction: "horizontal", + small: false, + }, +}; + +export const Small: StoryObj = { + args: { + value: 50, + direction: "horizontal", + small: true, + }, +}; + +export const WithFeedback: StoryObj = { + args: { + value: 50, + feedbackText: { text: "Uploading…", type: "hint", position: "left" }, + }, +}; + +export const Vertical: StoryObj = { + args: { + value: 50, + feedbackText: { text: "Uploading…", type: "hint", position: "left" }, + direction: "vertical", + }, +};