feat: add progress bar component with styles and integration into the application

This commit is contained in:
Lorenz Hilpert
2025-03-24 15:26:14 +01:00
parent b97ad4f24b
commit 9001850c1f
22 changed files with 298 additions and 18 deletions

View File

@@ -38,7 +38,7 @@
],
"styles": [
"@angular/cdk/overlay-prebuilt.css",
"libs/ui/buttons/src/styles.scss",
"apps/isa-app/src/ui.scss",
"apps/isa-app/src/styles.scss"
],
"scripts": []
@@ -117,7 +117,7 @@
"configDir": "apps/isa-app/.storybook",
"browserTarget": "isa-app:build",
"compodoc": false,
"styles": ["apps/isa-app/src/styles.scss"]
"styles": ["apps/isa-app/src/ui.scss", "apps/isa-app/src/styles.scss"]
},
"configurations": {
"ci": {

2
apps/isa-app/src/ui.scss Normal file
View File

@@ -0,0 +1,2 @@
@use "../../../libs/ui/buttons/src/buttons.scss";
@use "../../../libs/ui/progress-bar/src/lib/progress-bar.scss";

View File

@@ -2,7 +2,7 @@ import { argsToTemplate, type Meta, type StoryObj, moduleMetadata } from '@story
import { IconButtonColor, IconButtonSize, IconButtonComponent } from '@isa/ui/buttons';
// import { within } from '@storybook/testing-library';
// import { expect } from '@storybook/jest';
import * as IsaIcons from '@isa/icons';
import { IsaIcons } from '@isa/icons';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
type UiIconButtonComponentInputs = {

View File

@@ -1,6 +1,6 @@
import { InfoButtonComponent } from '@isa/ui/buttons';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import * as IsaIcons from '@isa/icons';
import { IsaIcons } from '@isa/icons';
import { argsToTemplate, moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
type InfoButtonComponentInputs = {

View File

@@ -0,0 +1,41 @@
import { type Meta, type StoryObj } from '@storybook/angular';
import { ProgressBarComponent, ProgressBarMode } from '@isa/ui/progress-bar';
export interface ProgressBarComponentInputs {
value: number;
maxValue: number;
mode: ProgressBarMode;
}
const meta: Meta<ProgressBarComponentInputs> = {
component: ProgressBarComponent,
title: 'ui/progress-bar/ProgressBar',
argTypes: {
value: {
control: 'number',
},
maxValue: {
control: 'number',
},
mode: {
control: 'select',
options: Object.values(ProgressBarMode),
},
},
args: {
value: 50,
maxValue: 100,
mode: ProgressBarMode.Determinate,
},
};
export default meta;
type Story = StoryObj<ProgressBarComponentInputs>;
export const Determinate: Story = {
args: {
mode: ProgressBarMode.Determinate,
value: 30,
},
};

View File

@@ -1,16 +1,8 @@
import {
isaArtikelCd,
isaArtikelEbook,
isaArtikelKartoniert,
isaArtikelDigital,
isaArtikelGame,
isaArtikelTaschenbuch,
isaArtikelSonstige,
isaArtikelTolino,
isaNavigationArtikelsuche,
} from './icons';
import * as icons from './icons';
export const ProductFormatIconGroup = {
tb: isaArtikelTaschenbuch,
hc: isaArtikelKartoniert,
tb: icons.isaArtikelTaschenbuch,
hc: icons.isaArtikelKartoniert,
};
export const IsaIcons = icons;

View File

@@ -1,6 +1,7 @@
@if (returnProcess(); as process) {
<div class="return-process-item-header">
<h3 class="isa-text-subtitle-2-bold">Rückgabe informationen</h3>
<ui-progress-bar mode="indeterminate"></ui-progress-bar>
</div>
<div class="return-process-item-body">
<img

View File

@@ -5,6 +5,7 @@ import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { ProductFormatIconGroup } from '@isa/icons';
import { LowerCasePipe } from '@angular/common';
import { ReturnProcessQuestionsComponent } from '../return-process-questions/return-process-questions.component';
import { ProgressBarComponent } from '@isa/ui/progress-bar';
@Component({
selector: 'lib-return-process-item',
@@ -12,7 +13,13 @@ import { ReturnProcessQuestionsComponent } from '../return-process-questions/ret
styleUrls: ['./return-process-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ProductImageDirective, NgIconComponent, LowerCasePipe, ReturnProcessQuestionsComponent],
imports: [
ProductImageDirective,
NgIconComponent,
LowerCasePipe,
ReturnProcessQuestionsComponent,
ProgressBarComponent,
],
providers: [provideIcons(ProductFormatIconGroup)],
})
export class ReturnProcessItemComponent {

View File

@@ -0,0 +1,7 @@
# ui-progress-bar
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ui-progress-bar` to execute the unit tests.

View File

@@ -0,0 +1,34 @@
import nx from '@nx/eslint-plugin';
import baseConfig from '../../../eslint.config.mjs';
export default [
...baseConfig,
...nx.configs['flat/angular'],
...nx.configs['flat/angular-template'],
{
files: ['**/*.ts'],
rules: {
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'ui',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'ui',
style: 'kebab-case',
},
],
},
},
{
files: ['**/*.html'],
// Override or add rules here
rules: {},
},
];

View File

@@ -0,0 +1,21 @@
export default {
displayName: 'ui-progress-bar',
preset: '../../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: '../../../coverage/libs/ui/progress-bar',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};

View File

@@ -0,0 +1,20 @@
{
"name": "ui-progress-bar",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/ui/progress-bar/src",
"prefix": "ui",
"projectType": "library",
"tags": [],
"targets": {
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/ui/progress-bar/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
}
}

View File

@@ -0,0 +1 @@
export * from './lib/progress-bar.component';

View File

@@ -0,0 +1,34 @@
.ui-progress-bar {
display: inline-flex;
height: 0.5rem;
width: 10rem;
@apply bg-isa-neutral-300 rounded-full;
}
.ui-progress-bar__bar {
@apply inline-flex h-full bg-isa-accent-blue rounded-full;
}
.ui-progress-bar__determinate {
transition: width 300ms ease-in-out;
}
.ui-progress-bar__indeterminate {
overflow: hidden;
.ui-progress-bar__bar {
animation: progress-bar-indeterminate 3s infinite;
}
}
@keyframes progress-bar-indeterminate {
0% {
transform: translateX(-95%);
}
50% {
transform: translateX(95%);
}
100% {
transform: translateX(-95%);
}
}

View File

@@ -0,0 +1,51 @@
import {
ChangeDetectionStrategy,
Component,
computed,
input,
ViewEncapsulation,
} from '@angular/core';
export const ProgressBarMode = {
Determinate: 'determinate',
Indeterminate: 'indeterminate',
} as const;
export type ProgressBarMode = (typeof ProgressBarMode)[keyof typeof ProgressBarMode];
@Component({
selector: 'ui-progress-bar',
template: ` <div class="ui-progress-bar__bar" [style.width]="width()"></div> `,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
standalone: true,
imports: [],
host: {
'[class]': '["ui-progress-bar", modeClass()]',
},
})
export class ProgressBarComponent {
mode = input<ProgressBarMode>(ProgressBarMode.Determinate);
modeClass = computed(() => {
return `ui-progress-bar__${this.mode()}`;
});
/**
* Value between 0 and 100 representing the percentage of the bar filled.
*/
value = input<number>(50);
maxValue = input<number>(100);
width = computed(() => {
if (this.mode() === ProgressBarMode.Indeterminate) {
return '100%';
}
const value = this.value();
const maxValue = this.maxValue();
return `${(value / maxValue) * 100}%`;
});
}

View File

@@ -0,0 +1 @@
@use "./lib//progress-bar";

View File

@@ -0,0 +1,6 @@
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv({
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});

View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es2022",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"extends": "../../../tsconfig.base.json",
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

View File

@@ -0,0 +1,17 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": []
},
"exclude": [
"src/**/*.spec.ts",
"src/test-setup.ts",
"jest.config.ts",
"src/**/*.test.ts"
],
"include": ["src/**/*.ts"]
}

View File

@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"target": "es2016",
"types": ["jest", "node"]
},
"files": ["src/test-setup.ts"],
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

View File

@@ -63,6 +63,7 @@
"@isa/ui/empty-state": ["libs/ui/empty-state/src/index.ts"],
"@isa/ui/input-controls": ["libs/ui/input-controls/src/index.ts"],
"@isa/ui/item-rows": ["libs/ui/item-rows/src/index.ts"],
"@isa/ui/progress-bar": ["libs/ui/progress-bar/src/index.ts"],
"@isa/ui/search-bar": ["libs/ui/search-bar/src/index.ts"],
"@isa/ui/toolbar": ["libs/ui/toolbar/src/index.ts"],
"@isa/utils/z-safe-parse": ["libs/utils/z-safe-parse/src/index.ts"],