feat(web): update color selector
All checks were successful
Build, Test and Deploy / test-backend (push) Successful in 27s
Build, Test and Deploy / build-and-push (push) Successful in 24s
Build, Test and Deploy / deploy (push) Successful in 6s

This commit is contained in:
2026-02-06 13:25:41 +01:00
parent bcdeafe119
commit 13790f2055
10 changed files with 380 additions and 55 deletions

View File

@@ -72,11 +72,14 @@ export class CalculatorPageComponent {
details += `- File:\n`;
req.items.forEach(item => {
details += ` * ${item.file.name} (Qtà: ${item.quantity})\n`;
details += ` * ${item.file.name} (Qtà: ${item.quantity}`;
if (item.color) {
details += `, Colore: ${item.color}`;
}
details += `)\n`;
});
if (req.mode === 'advanced') {
if (req.color) details += `- Colore: ${req.color}\n`;
if (req.infillDensity) details += `- Infill: ${req.infillDensity}%\n`;
}

View File

@@ -3,7 +3,10 @@
<div class="section">
@if (selectedFile()) {
<div class="viewer-wrapper">
<app-stl-viewer [file]="selectedFile()"></app-stl-viewer>
<app-stl-viewer
[file]="selectedFile()"
[color]="getSelectedFileColor()">
</app-stl-viewer>
<!-- Close button removed as requested -->
</div>
}
@@ -29,15 +32,25 @@
</div>
<div class="card-body">
<div class="qty-group">
<label>Qtà</label>
<input
type="number"
min="1"
[value]="item.quantity"
(change)="updateItemQuantity(i, $event)"
class="qty-input"
(click)="$event.stopPropagation()">
<div class="card-controls">
<div class="qty-group">
<label>QTÀ</label>
<input
type="number"
min="1"
[value]="item.quantity"
(change)="updateItemQuantity(i, $event)"
class="qty-input"
(click)="$event.stopPropagation()">
</div>
<div class="color-group">
<label>COLORE</label>
<app-color-selector
[selectedColor]="item.color"
(colorSelected)="updateItemColor(i, $event)">
</app-color-selector>
</div>
</div>
<button type="button" class="btn-remove" (click)="removeItem(i); $event.stopPropagation()" title="Remove file">
@@ -81,12 +94,6 @@
@if (mode() === 'advanced') {
<div class="grid">
<app-select
formControlName="color"
[label]="'CALC.COLOR' | translate"
[options]="colors"
></app-select>
<app-select
formControlName="infillPattern"
[label]="'CALC.PATTERN' | translate"

View File

@@ -16,18 +16,18 @@
/* Grid Layout for Files */
.items-grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-3);
grid-template-columns: 1fr 1fr; /* Force 2 columns on mobile */
gap: var(--space-2); /* Tighten gap for mobile */
margin-top: var(--space-4);
margin-bottom: var(--space-4);
@media(min-width: 640px) {
grid-template-columns: 1fr 1fr;
gap: var(--space-3);
}
}
.file-card {
padding: var(--space-3);
padding: var(--space-2); /* Reduced from space-3 */
background: var(--color-neutral-100);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
@@ -35,7 +35,9 @@
cursor: pointer;
display: flex;
flex-direction: column;
gap: var(--space-2);
gap: 4px; /* Reduced gap */
position: relative; /* For absolute positioning of remove btn */
min-width: 0; /* Allow flex item to shrink below content size if needed */
&:hover { border-color: var(--color-neutral-300); }
&.active {
@@ -47,11 +49,13 @@
.card-header {
overflow: hidden;
padding-right: 25px; /* Adjusted */
margin-bottom: 2px;
}
.file-name {
font-weight: 500;
font-size: 0.85rem;
font-size: 0.8rem; /* Smaller font */
color: var(--color-text);
display: block;
white-space: nowrap;
@@ -61,34 +65,64 @@
.card-body {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 0;
}
.qty-group {
.card-controls {
display: flex;
align-items: center;
gap: var(--space-2);
label { font-size: 0.75rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
align-items: flex-end; /* Align bottom of input and color circle */
gap: 16px; /* Space between Qty and Color */
width: 100%;
}
.qty-group, .color-group {
display: flex;
flex-direction: column; /* Stack label and input */
align-items: flex-start;
gap: 0px;
label {
font-size: 0.6rem;
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
margin-bottom: 2px;
}
}
.color-group {
align-items: flex-start; /* Align label left */
/* margin-right removed */
/* Override margin in selector for this context */
::ng-deep .color-selector-container {
margin-left: 0;
}
}
.qty-input {
width: 40px;
padding: 2px 4px;
width: 36px; /* Slightly smaller */
padding: 1px 2px;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
text-align: center;
font-size: 0.9rem;
font-size: 0.85rem;
background: white;
height: 24px; /* Explicit height to match color circle somewhat */
&:focus { outline: none; border-color: var(--color-brand); }
}
.btn-remove {
width: 24px;
height: 24px;
position: absolute;
top: 4px;
right: 4px;
width: 18px;
height: 18px;
border-radius: 4px;
border: 1px solid transparent; // var(--color-border);
background: transparent; // white;
border: none;
background: transparent;
color: var(--color-text-muted);
font-weight: bold;
cursor: pointer;
@@ -96,12 +130,11 @@
align-items: center;
justify-content: center;
transition: all 0.2s;
font-size: 0.9rem;
font-size: 0.8rem;
&:hover {
background: var(--color-danger-100);
color: var(--color-danger-500);
border-color: var(--color-danger-200);
}
}

View File

@@ -7,17 +7,20 @@ import { AppSelectComponent } from '../../../../shared/components/app-select/app
import { AppDropzoneComponent } from '../../../../shared/components/app-dropzone/app-dropzone.component';
import { AppButtonComponent } from '../../../../shared/components/app-button/app-button.component';
import { StlViewerComponent } from '../../../../shared/components/stl-viewer/stl-viewer.component';
import { ColorSelectorComponent } from '../../../../shared/components/color-selector/color-selector.component';
import { QuoteRequest } from '../../services/quote-estimator.service';
import { getColorHex } from '../../../../core/constants/colors.const';
interface FormItem {
file: File;
quantity: number;
color: string;
}
@Component({
selector: 'app-upload-form',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, TranslateModule, AppInputComponent, AppSelectComponent, AppDropzoneComponent, AppButtonComponent, StlViewerComponent],
imports: [CommonModule, ReactiveFormsModule, TranslateModule, AppInputComponent, AppSelectComponent, AppDropzoneComponent, AppButtonComponent, StlViewerComponent, ColorSelectorComponent],
templateUrl: './upload-form.component.html',
styleUrl: './upload-form.component.scss'
})
@@ -44,15 +47,6 @@ export class UploadFormComponent {
{ label: 'Alta definizione', value: 'High' }
];
colors = [
{ label: 'Black', value: 'Black' },
{ label: 'White', value: 'White' },
{ label: 'Gray', value: 'Gray' },
{ label: 'Red', value: 'Red' },
{ label: 'Blue', value: 'Blue' },
{ label: 'Green', value: 'Green' },
{ label: 'Yellow', value: 'Yellow' }
];
infillPatterns = [
{ label: 'Grid', value: 'grid' },
{ label: 'Gyroid', value: 'gyroid' },
@@ -69,7 +63,7 @@ export class UploadFormComponent {
quality: ['Standard', Validators.required],
notes: [''],
// Advanced fields
color: ['Black'],
// Color removed from global form
infillDensity: [20, [Validators.min(0), Validators.max(100)]],
infillPattern: ['grid'],
supportEnabled: [false]
@@ -85,7 +79,8 @@ export class UploadFormComponent {
if (file.size > MAX_SIZE) {
hasError = true;
} else {
validItems.push({ file, quantity: 1 });
// Default color is Black
validItems.push({ file, quantity: 1, color: 'Black' });
}
}
@@ -129,6 +124,18 @@ export class UploadFormComponent {
}
}
// Helper to get color of currently selected file
getSelectedFileColor(): string {
const file = this.selectedFile();
if (!file) return '#facf0a'; // Default
const item = this.items().find(i => i.file === file);
if (item) {
return getColorHex(item.color);
}
return '#facf0a';
}
updateItemQuantity(index: number, event: Event) {
const input = event.target as HTMLInputElement;
let val = parseInt(input.value, 10);
@@ -141,6 +148,14 @@ export class UploadFormComponent {
});
}
updateItemColor(index: number, newColor: string) {
this.items.update(current => {
const updated = [...current];
updated[index] = { ...updated[index], color: newColor };
return updated;
});
}
removeItem(index: number) {
this.items.update(current => {
const updated = [...current];
@@ -155,7 +170,7 @@ export class UploadFormComponent {
onSubmit() {
if (this.form.valid && this.items().length > 0) {
this.submitRequest.emit({
items: this.items(), // Pass the items array
items: this.items(), // Pass the items array including colors
...this.form.value,
mode: this.mode()
});

View File

@@ -5,11 +5,11 @@ import { map, catchError } from 'rxjs/operators';
import { environment } from '../../../../environments/environment';
export interface QuoteRequest {
items: { file: File, quantity: number }[];
items: { file: File, quantity: number, color?: string }[];
material: string;
quality: string;
notes?: string;
color?: string;
// color removed from global scope
infillDensity?: number;
infillPattern?: string;
supportEnabled?: boolean;
@@ -69,8 +69,11 @@ export class QuoteEstimatorService {
formData.append('machine', 'bambu_a1');
formData.append('filament', this.mapMaterial(request.material));
formData.append('quality', this.mapQuality(request.quality));
// Send color for both modes if present, defaulting to Black
formData.append('material_color', item.color || 'Black');
if (request.mode === 'advanced') {
if (request.color) formData.append('material_color', request.color);
if (request.infillDensity) formData.append('infill_density', request.infillDensity.toString());
if (request.infillPattern) formData.append('infill_pattern', request.infillPattern);
if (request.supportEnabled) formData.append('support_enabled', 'true');