Merge remote-tracking branch 'origin/dev' into dev
All checks were successful
Build and Deploy / test-backend (push) Successful in 31s
PR Checks / prettier-autofix (pull_request) Successful in 10s
Build and Deploy / test-frontend (push) Successful in 1m6s
PR Checks / security-sast (pull_request) Successful in 31s
PR Checks / test-backend (pull_request) Successful in 28s
Build and Deploy / build-and-push (push) Successful in 30s
PR Checks / test-frontend (pull_request) Successful in 1m5s
Build and Deploy / deploy (push) Successful in 24s

This commit is contained in:
2026-03-13 17:41:55 +01:00
10 changed files with 53 additions and 23 deletions

View File

@@ -61,7 +61,7 @@ const appChildRoutes: Routes = [
'Scopri il team 3D fab e il laboratorio di stampa 3D con sedi in Ticino e Bienne.', 'Scopri il team 3D fab e il laboratorio di stampa 3D con sedi in Ticino e Bienne.',
}, },
}, },
/* { /* {
path: 'materials', path: 'materials',
loadComponent: () => loadComponent: () =>
import('./features/materials/materials-page.component').then( import('./features/materials/materials-page.component').then(

View File

@@ -130,7 +130,9 @@
<div class="cart-line-copy"> <div class="cart-line-copy">
<strong>{{ cartItemName(item) }}</strong> <strong>{{ cartItemName(item) }}</strong>
@if (cartItemVariant(item); as variant) { @if (cartItemVariant(item); as variant) {
<span class="cart-line-meta">{{ variant | translate }}</span> <span class="cart-line-meta">{{
variant | translate
}}</span>
} }
@if (cartItemColor(item); as color) { @if (cartItemColor(item); as color) {
<span class="cart-line-color"> <span class="cart-line-color">

View File

@@ -59,9 +59,11 @@ export class SeoService {
applyPageSeo(override: PageSeoOverride): void { applyPageSeo(override: PageSeoOverride): void {
const cleanPath = this.getCleanPath(this.router.url); const cleanPath = this.getCleanPath(this.router.url);
const lang = this.resolveLangFromPath(cleanPath); const lang = this.resolveLangFromPath(cleanPath);
const title = this.asString(override.title) ?? this.defaultTitleByLang[lang]; const title =
this.asString(override.title) ?? this.defaultTitleByLang[lang];
const description = const description =
this.asString(override.description) ?? this.defaultDescriptionByLang[lang]; this.asString(override.description) ??
this.defaultDescriptionByLang[lang];
const robots = this.asString(override.robots) ?? 'index, follow'; const robots = this.asString(override.robots) ?? 'index, follow';
const ogTitle = this.asString(override.ogTitle) ?? title; const ogTitle = this.asString(override.ogTitle) ?? title;
const ogDescription = this.asString(override.ogDescription) ?? description; const ogDescription = this.asString(override.ogDescription) ?? description;
@@ -135,7 +137,11 @@ export class SeoService {
): string | undefined { ): string | undefined {
const mapKey = `${key}ByLang`; const mapKey = `${key}ByLang`;
const localized = routeData[mapKey]; const localized = routeData[mapKey];
if (localized && typeof localized === 'object' && !Array.isArray(localized)) { if (
localized &&
typeof localized === 'object' &&
!Array.isArray(localized)
) {
const mapped = localized as SeoMap; const mapped = localized as SeoMap;
const byLang = this.asString(mapped[lang]); const byLang = this.asString(mapped[lang]);
if (byLang) { if (byLang) {
@@ -152,7 +158,10 @@ export class SeoService {
private resolveLangFromPath(path: string): SupportedLang { private resolveLangFromPath(path: string): SupportedLang {
const firstSegment = path.split('/').filter(Boolean)[0]?.toLowerCase(); const firstSegment = path.split('/').filter(Boolean)[0]?.toLowerCase();
if (firstSegment && this.supportedLangs.has(firstSegment as SupportedLang)) { if (
firstSegment &&
this.supportedLangs.has(firstSegment as SupportedLang)
) {
return firstSegment as SupportedLang; return firstSegment as SupportedLang;
} }
return 'it'; return 'it';

View File

@@ -212,10 +212,10 @@
<input <input
class="ui-form-control" class="ui-form-control"
type="text" type="text"
[(ngModel)]="categoryForm.slug" [(ngModel)]="categoryForm.slug"
name="categorySlug" name="categorySlug"
placeholder="desk-accessories" placeholder="desk-accessories"
/> />
<button <button
type="button" type="button"
class="ui-button ui-button--ghost" class="ui-button ui-button--ghost"

View File

@@ -1343,7 +1343,9 @@ export class AdminShopComponent implements OnInit, OnDestroy {
seoTitleEn: this.optionalValue(this.categoryForm.seoTitles['en']), seoTitleEn: this.optionalValue(this.categoryForm.seoTitles['en']),
seoTitleDe: this.optionalValue(this.categoryForm.seoTitles['de']), seoTitleDe: this.optionalValue(this.categoryForm.seoTitles['de']),
seoTitleFr: this.optionalValue(this.categoryForm.seoTitles['fr']), seoTitleFr: this.optionalValue(this.categoryForm.seoTitles['fr']),
seoDescription: this.optionalValue(this.categoryForm.seoDescriptions['it']), seoDescription: this.optionalValue(
this.categoryForm.seoDescriptions['it'],
),
seoDescriptionIt: this.optionalValue( seoDescriptionIt: this.optionalValue(
this.categoryForm.seoDescriptions['it'], this.categoryForm.seoDescriptions['it'],
), ),

View File

@@ -239,7 +239,8 @@
<div class="order-item-meta"> <div class="order-item-meta">
<span <span
>{{ "CHECKOUT.QTY" | translate }}: {{ item.quantity }}</span >{{ "CHECKOUT.QTY" | translate }}:
{{ item.quantity }}</span
> >
<span *ngIf="showItemMaterial(item)"> <span *ngIf="showItemMaterial(item)">
{{ "CHECKOUT.MATERIAL" | translate }}: {{ "CHECKOUT.MATERIAL" | translate }}:

View File

@@ -20,7 +20,9 @@
}}</a> }}</a>
@for (crumb of p.breadcrumbs; track crumb.id) { @for (crumb of p.breadcrumbs; track crumb.id) {
<span class="breadcrumbs__separator">/</span> <span class="breadcrumbs__separator">/</span>
<a class="breadcrumbs__item" [routerLink]="categoryLink(crumb.slug)" <a
class="breadcrumbs__item"
[routerLink]="categoryLink(crumb.slug)"
>{{ crumb.name }}</a >{{ crumb.name }}</a
> >
} }
@@ -143,12 +145,15 @@
<span>{{ selectedMaterial()?.label }}</span> <span>{{ selectedMaterial()?.label }}</span>
} }
@if ( @if (
colorLabel(activeVariant) !== selectedMaterial()?.label colorLabel(activeVariant) !==
selectedMaterial()?.label
) { ) {
@if (selectedMaterial()?.label) { @if (selectedMaterial()?.label) {
<span aria-hidden="true">·</span> <span aria-hidden="true">·</span>
} }
<span>{{ colorLabel(activeVariant) | translate }}</span> <span>{{
colorLabel(activeVariant) | translate
}}</span>
} }
</p> </p>
} }
@@ -174,7 +179,10 @@
</div> </div>
<div class="material-grid"> <div class="material-grid">
@for (material of materialOptions(); track material.key) { @for (
material of materialOptions();
track material.key
) {
<button <button
type="button" type="button"
class="material-option" class="material-option"

View File

@@ -15,10 +15,7 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { catchError, combineLatest, finalize, of, switchMap, tap } from 'rxjs'; import { catchError, combineLatest, finalize, of, switchMap, tap } from 'rxjs';
import { SeoService } from '../../core/services/seo.service'; import { SeoService } from '../../core/services/seo.service';
import { LanguageService } from '../../core/services/language.service'; import { LanguageService } from '../../core/services/language.service';
import { import { findColorHex, getColorHex } from '../../core/constants/colors.const';
findColorHex,
getColorHex,
} from '../../core/constants/colors.const';
import { AppButtonComponent } from '../../shared/components/app-button/app-button.component'; import { AppButtonComponent } from '../../shared/components/app-button/app-button.component';
import { AppCardComponent } from '../../shared/components/app-card/app-card.component'; import { AppCardComponent } from '../../shared/components/app-card/app-card.component';
import { StlViewerComponent } from '../../shared/components/stl-viewer/stl-viewer.component'; import { StlViewerComponent } from '../../shared/components/stl-viewer/stl-viewer.component';
@@ -381,7 +378,9 @@ export class ProductDetailComponent {
} }
colorLabel(variant: ShopProductVariantOption): string { colorLabel(variant: ShopProductVariantOption): string {
return variant.colorLabel || variant.colorName || variant.variantLabel || '-'; return (
variant.colorLabel || variant.colorName || variant.variantLabel || '-'
);
} }
colorHex(variant: ShopProductVariantOption | null | undefined): string { colorHex(variant: ShopProductVariantOption | null | undefined): string {

View File

@@ -84,7 +84,9 @@
<div class="cart-line-copy"> <div class="cart-line-copy">
<strong>{{ cartItemName(item) }}</strong> <strong>{{ cartItemName(item) }}</strong>
@if (cartItemVariant(item); as variant) { @if (cartItemVariant(item); as variant) {
<span class="cart-line-meta">{{ variant | translate }}</span> <span class="cart-line-meta">{{
variant | translate
}}</span>
} }
@if (cartItemColor(item); as color) { @if (cartItemColor(item); as color) {
<span class="cart-line-color"> <span class="cart-line-color">

View File

@@ -1,4 +1,11 @@
import { Component, input, output, signal, computed, inject } from '@angular/core'; import {
Component,
input,
output,
signal,
computed,
inject,
} from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { import {