mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 2048: fix(shared-barcode, crm-customer-card): improve barcode rendering with transp...
fix(shared-barcode, crm-customer-card): improve barcode rendering with transparent SVG background Enhance barcode component flexibility by separating container and SVG background colors. The SVG barcode now defaults to transparent background while maintaining container background control, enabling better integration with various card designs. Changes: - Add separate svgBackground input for SVG element (default: transparent) - Keep background input for container styling (default: #ffffff) - Add containerWidth and containerHeight inputs for flexible sizing - Update customer card to remove explicit white background on barcode - Add opacity styling for inactive customer cards - Enhance test coverage for new background and sizing inputs The separation of concerns allows the barcode to adapt to parent container backgrounds while maintaining consistent rendering across different contexts. Ref: #5498
This commit is contained in:
committed by
Lorenz Hilpert
parent
949101a1ed
commit
8b852cbd7a
@@ -1,6 +1,7 @@
|
||||
<!-- Card container: 337×213px, rounded-2xl, shadow -->
|
||||
<div
|
||||
class="relative flex h-[14.8125rem] w-[21.0625rem] flex-col bg-isa-black"
|
||||
class="relative flex h-[14.8125rem] w-[21.0625rem] flex-col"
|
||||
[class.opacity-40]="!card().isActive"
|
||||
[attr.data-what]="'customer-card'"
|
||||
[attr.data-which]="card().code"
|
||||
>
|
||||
@@ -11,13 +12,11 @@
|
||||
<div>
|
||||
<!-- Card type label (grey) -->
|
||||
<div class="isa-text-body-2-bold text-center text-isa-neutral-500">
|
||||
{{ card().isPrimary ? 'Kundenkarte Nr.:' : 'Mitarbeitendenkarte Nr.:' }}
|
||||
Kundenkarte Nr.:
|
||||
</div>
|
||||
|
||||
<!-- Card number (white, large) -->
|
||||
<div
|
||||
class="isa-text-subtitle-1-bold w-[150px] text-center text-isa-white"
|
||||
>
|
||||
<div class="isa-text-subtitle-1-bold text-center text-isa-white">
|
||||
{{ card().code }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,7 +29,6 @@
|
||||
[width]="barcodeWidth"
|
||||
[margin]="barcodeMargin"
|
||||
[format]="'CODE128'"
|
||||
[background]="'#ffffff'"
|
||||
[attr.data-what]="'card-barcode'"
|
||||
[attr.data-which]="card().code"
|
||||
class="rounded-[0.25rem] overflow-hidden"
|
||||
|
||||
@@ -7,7 +7,10 @@ vi.mock('jsbarcode', () => ({
|
||||
default: vi.fn((element, value, options) => {
|
||||
// Simulate JsBarcode by adding a rect element to the SVG
|
||||
if (element && element.tagName === 'svg') {
|
||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
const rect = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'rect',
|
||||
);
|
||||
rect.setAttribute('data-value', value);
|
||||
rect.setAttribute('data-format', options?.format || 'CODE128');
|
||||
element.appendChild(rect);
|
||||
@@ -108,7 +111,7 @@ describe('BarcodeComponent', () => {
|
||||
expect(component.lineColor()).toBe('#FF0000');
|
||||
});
|
||||
|
||||
it('should pass background input to directive', () => {
|
||||
it('should pass container background input', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('background', '#F0F0F0');
|
||||
fixture.detectChanges();
|
||||
@@ -116,6 +119,30 @@ describe('BarcodeComponent', () => {
|
||||
expect(component.background()).toBe('#F0F0F0');
|
||||
});
|
||||
|
||||
it('should pass svgBackground input to directive', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('svgBackground', '#FFFFFF');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.svgBackground()).toBe('#FFFFFF');
|
||||
});
|
||||
|
||||
it('should pass containerWidth input', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('containerWidth', '20rem');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.containerWidth()).toBe('20rem');
|
||||
});
|
||||
|
||||
it('should pass containerHeight input', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('containerHeight', '6rem');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.containerHeight()).toBe('6rem');
|
||||
});
|
||||
|
||||
it('should pass fontSize input to directive', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('fontSize', 24);
|
||||
@@ -169,13 +196,34 @@ describe('BarcodeComponent', () => {
|
||||
expect(component.lineColor()).toBe('#000000');
|
||||
});
|
||||
|
||||
it('should use default background #ffffff', () => {
|
||||
it('should use default container background #ffffff', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.background()).toBe('#ffffff');
|
||||
});
|
||||
|
||||
it('should use default svgBackground transparent', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.svgBackground()).toBe('transparent');
|
||||
});
|
||||
|
||||
it('should use default containerWidth 12.5rem', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.containerWidth()).toBe('12.5rem');
|
||||
});
|
||||
|
||||
it('should use default containerHeight 5.5rem', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.containerHeight()).toBe('5.5rem');
|
||||
});
|
||||
|
||||
it('should use default fontSize 20', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
@@ -191,6 +239,41 @@ describe('BarcodeComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Host Styling', () => {
|
||||
it('should apply container width style', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('containerWidth', '25rem');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.style.width).toBe('25rem');
|
||||
});
|
||||
|
||||
it('should apply container height style', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('containerHeight', '8rem');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.style.height).toBe('8rem');
|
||||
});
|
||||
|
||||
it('should apply background color style', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.componentRef.setInput('background', '#EEEEEE');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.style.backgroundColor).toBe(
|
||||
'rgb(238, 238, 238)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should apply flex display style', () => {
|
||||
fixture.componentRef.setInput('value', '123');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.style.display).toBe('flex');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Barcode Rendering', () => {
|
||||
it('should render barcode with custom value', () => {
|
||||
fixture.componentRef.setInput('value', '987654321');
|
||||
|
||||
@@ -3,11 +3,18 @@ import { BarcodeDirective } from './barcode.directive';
|
||||
|
||||
/**
|
||||
* Component wrapper for the barcode directive that provides an easier-to-use API.
|
||||
* Renders a Code 128 barcode as an SVG element.
|
||||
* Renders a Code 128 barcode as an SVG element within a container.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <shared-barcode [value]="'123456789'" [width]="2" [height]="100" />
|
||||
* <shared-barcode
|
||||
* [value]="'123456789'"
|
||||
* [width]="2"
|
||||
* [height]="100"
|
||||
* [containerWidth]="'300px'"
|
||||
* [containerHeight]="'88px'"
|
||||
* [background]="'#ffffff'"
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
@@ -23,12 +30,20 @@ import { BarcodeDirective } from './barcode.directive';
|
||||
[height]="height()"
|
||||
[displayValue]="displayValue()"
|
||||
[lineColor]="lineColor()"
|
||||
[background]="background()"
|
||||
[background]="svgBackground()"
|
||||
[fontSize]="fontSize()"
|
||||
[margin]="margin()"
|
||||
></svg>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'[style.width]': 'containerWidth()',
|
||||
'[style.height]': 'containerHeight()',
|
||||
'[style.background-color]': 'background()',
|
||||
'[style.display]': '"flex"',
|
||||
'[style.align-items]': '"center"',
|
||||
'[style.justify-content]': '"center"',
|
||||
},
|
||||
})
|
||||
export class BarcodeComponent {
|
||||
/**
|
||||
@@ -62,10 +77,15 @@ export class BarcodeComponent {
|
||||
lineColor = input<string>('#000000');
|
||||
|
||||
/**
|
||||
* Background color (default: #ffffff)
|
||||
* Background color of the container (default: #ffffff)
|
||||
*/
|
||||
background = input<string>('#ffffff');
|
||||
|
||||
/**
|
||||
* Background color of the SVG barcode itself (default: transparent)
|
||||
*/
|
||||
svgBackground = input<string>('transparent');
|
||||
|
||||
/**
|
||||
* Font size for the human-readable text (default: 20)
|
||||
*/
|
||||
@@ -75,4 +95,14 @@ export class BarcodeComponent {
|
||||
* Margin around the barcode in pixels (default: 10)
|
||||
*/
|
||||
margin = input<number>(10);
|
||||
|
||||
/**
|
||||
* Width of the container (default: 12.5rem)
|
||||
*/
|
||||
containerWidth = input<string>('12.5rem');
|
||||
|
||||
/**
|
||||
* Height of the container (default: 5.5rem)
|
||||
*/
|
||||
containerHeight = input<string>('5.5rem');
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@ vi.mock('jsbarcode', () => ({
|
||||
default: vi.fn((element, value, options) => {
|
||||
// Simulate JsBarcode by adding a rect element to the SVG
|
||||
if (element && element.tagName === 'svg') {
|
||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
const rect = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'rect',
|
||||
);
|
||||
rect.setAttribute('data-value', value);
|
||||
rect.setAttribute('data-format', options?.format || 'CODE128');
|
||||
element.appendChild(rect);
|
||||
@@ -168,11 +171,7 @@ describe('BarcodeDirective', () => {
|
||||
standalone: true,
|
||||
imports: [BarcodeDirective],
|
||||
template: `
|
||||
<svg
|
||||
sharedBarcode
|
||||
[value]="'123456'"
|
||||
[lineColor]="'#FF0000'"
|
||||
></svg>
|
||||
<svg sharedBarcode [value]="'123456'" [lineColor]="'#FF0000'"></svg>
|
||||
`,
|
||||
})
|
||||
class ColorTestComponent {}
|
||||
@@ -190,11 +189,7 @@ describe('BarcodeDirective', () => {
|
||||
standalone: true,
|
||||
imports: [BarcodeDirective],
|
||||
template: `
|
||||
<svg
|
||||
sharedBarcode
|
||||
[value]="'123456'"
|
||||
[background]="'#F0F0F0'"
|
||||
></svg>
|
||||
<svg sharedBarcode [value]="'123456'" [background]="'#F0F0F0'"></svg>
|
||||
`,
|
||||
})
|
||||
class BackgroundTestComponent {}
|
||||
@@ -206,6 +201,21 @@ describe('BarcodeDirective', () => {
|
||||
expect(svg).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render with transparent background by default', () => {
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [BarcodeDirective],
|
||||
template: ` <svg sharedBarcode [value]="'123456'"></svg> `,
|
||||
})
|
||||
class DefaultBackgroundTestComponent {}
|
||||
|
||||
const bgFixture = TestBed.createComponent(DefaultBackgroundTestComponent);
|
||||
bgFixture.detectChanges();
|
||||
|
||||
const svg = bgFixture.nativeElement.querySelector('svg');
|
||||
expect(svg).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render with custom font size', () => {
|
||||
@Component({
|
||||
standalone: true,
|
||||
|
||||
@@ -56,9 +56,9 @@ export class BarcodeDirective implements OnDestroy {
|
||||
lineColor = input<string>('#000000');
|
||||
|
||||
/**
|
||||
* Background color (default: #ffffff)
|
||||
* Background color of the SVG barcode itself (default: transparent)
|
||||
*/
|
||||
background = input<string>('#ffffff');
|
||||
background = input<string>('transparent');
|
||||
|
||||
/**
|
||||
* Font size for the human-readable text (default: 20)
|
||||
@@ -112,14 +112,10 @@ export class BarcodeDirective implements OnDestroy {
|
||||
format: this.format(),
|
||||
}));
|
||||
} catch (error) {
|
||||
this.#logger.error(
|
||||
'Failed to render barcode',
|
||||
error as Error,
|
||||
() => ({
|
||||
value,
|
||||
format: this.format(),
|
||||
})
|
||||
);
|
||||
this.#logger.error('Failed to render barcode', error as Error, () => ({
|
||||
value,
|
||||
format: this.format(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user