feat(front-end): contact form and about separated
This commit is contained in:
@@ -20,6 +20,10 @@ export const routes: Routes = [
|
||||
{
|
||||
path: 'about',
|
||||
loadChildren: () => import('./features/about/about.routes').then(m => m.ABOUT_ROUTES)
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
loadChildren: () => import('./features/contact/contact.routes').then(m => m.CONTACT_ROUTES)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
<a routerLink="/" class="brand">3D <span class="highlight">fab</span></a>
|
||||
|
||||
<nav class="nav-links">
|
||||
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">{{ 'NAV.HOME' | translate }}</a>
|
||||
<a routerLink="/cal" routerLinkActive="active" [routerLinkActiveOptions]="{exact: false}">{{ 'NAV.CALCULATOR' | translate }}</a>
|
||||
<a routerLink="/shop" routerLinkActive="active">{{ 'NAV.SHOP' | translate }}</a>
|
||||
<a routerLink="/about" routerLinkActive="active">{{ 'NAV.ABOUT' | translate }}</a>
|
||||
<a routerLink="/contact" routerLinkActive="active">{{ 'NAV.CONTACT' | translate }}</a>
|
||||
</nav>
|
||||
|
||||
<div class="actions">
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ContactFormComponent } from './components/contact-form/contact-form.component';
|
||||
import { AppCardComponent } from '../../shared/components/app-card/app-card.component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-about-page',
|
||||
standalone: true,
|
||||
imports: [TranslateModule, ContactFormComponent, AppCardComponent],
|
||||
imports: [TranslateModule],
|
||||
template: `
|
||||
<section class="about-hero">
|
||||
<div class="container">
|
||||
@@ -37,14 +36,25 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp
|
||||
|
||||
<h3>{{ 'ABOUT.TARGET_TITLE' | translate }}</h3>
|
||||
<p class="text-muted">{{ 'ABOUT.TARGET_TEXT' | translate }}</p>
|
||||
|
||||
<h3>{{ 'ABOUT.TEAM_TITLE' | translate }}</h3>
|
||||
<div class="team-grid">
|
||||
<div class="team-member">
|
||||
<div class="placeholder-img"></div>
|
||||
<p>Member 1</p>
|
||||
</div>
|
||||
<div class="team-member">
|
||||
<div class="placeholder-img"></div>
|
||||
<p>Member 2</p>
|
||||
</div>
|
||||
<div class="team-member">
|
||||
<div class="placeholder-img"></div>
|
||||
<p>Member 3</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact">
|
||||
<app-card>
|
||||
<h2>{{ 'ABOUT.CONTACT_US' | translate }}</h2>
|
||||
<app-contact-form></app-contact-form>
|
||||
</app-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`,
|
||||
styles: [`
|
||||
@@ -91,6 +101,22 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp
|
||||
font-weight: 600;
|
||||
}
|
||||
.text-muted { color: var(--color-text-muted); }
|
||||
.team-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
.team-member {
|
||||
text-align: center;
|
||||
}
|
||||
.placeholder-img {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
background: var(--color-neutral-100);
|
||||
border-radius: var(--radius-md);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class AboutPageComponent {}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppInputComponent } from '../../../../shared/components/app-input/app-input.component';
|
||||
import { AppButtonComponent } from '../../../../shared/components/app-button/app-button.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-form',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, TranslateModule, AppInputComponent, AppButtonComponent],
|
||||
template: `
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<app-input formControlName="name" label="Nome" placeholder="Il tuo nome"></app-input>
|
||||
<app-input formControlName="email" type="email" label="Email" placeholder="tuo@email.com"></app-input>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Messaggio</label>
|
||||
<textarea formControlName="message" class="form-control" rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<app-button type="submit" [disabled]="form.invalid || sent()">
|
||||
{{ sent() ? 'Inviato!' : ('ABOUT.SEND' | translate) }}
|
||||
</app-button>
|
||||
</div>
|
||||
</form>
|
||||
`,
|
||||
styles: [`
|
||||
.form-group { display: flex; flex-direction: column; margin-bottom: var(--space-4); }
|
||||
label { font-size: 0.875rem; font-weight: 500; margin-bottom: var(--space-2); color: var(--color-text); }
|
||||
.form-control {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
width: 100%;
|
||||
background: var(--color-bg-card);
|
||||
color: var(--color-text);
|
||||
font-family: inherit;
|
||||
&:focus { outline: none; border-color: var(--color-brand); }
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class ContactFormComponent {
|
||||
form: FormGroup;
|
||||
sent = signal(false);
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
this.form = this.fb.group({
|
||||
name: ['', Validators.required],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
message: ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.form.valid) {
|
||||
// Mock submit
|
||||
this.sent.set(true);
|
||||
setTimeout(() => {
|
||||
this.sent.set(false);
|
||||
this.form.reset();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
import { Component, signal, effect } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppInputComponent } from '../../../../shared/components/app-input/app-input.component';
|
||||
import { AppButtonComponent } from '../../../../shared/components/app-button/app-button.component';
|
||||
|
||||
interface FilePreview {
|
||||
file: File;
|
||||
url?: string;
|
||||
type: 'image' | 'pdf' | '3d' | 'other';
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-form',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, TranslateModule, AppInputComponent, AppButtonComponent],
|
||||
template: `
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<!-- Request Type -->
|
||||
<div class="form-group">
|
||||
<label>{{ 'CONTACT.REQ_TYPE_LABEL' | translate }} *</label>
|
||||
<select formControlName="requestType" class="form-control">
|
||||
<option *ngFor="let type of requestTypes" [value]="type.value">
|
||||
{{ type.label | translate }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Email -->
|
||||
<app-input formControlName="email" type="email" label="Email *" placeholder="tuo@email.com" class="col"></app-input>
|
||||
<!-- Phone -->
|
||||
<app-input formControlName="phone" type="tel" [label]="('CONTACT.PHONE' | translate)" placeholder="+39 000 000 0000" class="col"></app-input>
|
||||
</div>
|
||||
|
||||
<!-- Name (Always Required) -->
|
||||
<app-input formControlName="name" label="Nome *" placeholder="Il tuo nome"></app-input>
|
||||
|
||||
<!-- Company Toggle & Fields -->
|
||||
<div class="form-group checkbox-group">
|
||||
<input type="checkbox" formControlName="isCompany" id="isCompany">
|
||||
<label for="isCompany">{{ 'CONTACT.IS_COMPANY' | translate }}</label>
|
||||
</div>
|
||||
|
||||
<div *ngIf="form.get('isCompany')?.value" class="company-fields">
|
||||
<app-input formControlName="companyName" [label]="('CONTACT.COMPANY_NAME' | translate) + ' *'" placeholder="Nome Azienda"></app-input>
|
||||
<app-input formControlName="referencePerson" [label]="('CONTACT.REF_PERSON' | translate) + ' *'" placeholder="Persona di Riferimento"></app-input>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Messaggio *</label>
|
||||
<textarea formControlName="message" class="form-control" rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- File Upload Section -->
|
||||
<div class="form-group">
|
||||
<label>{{ 'CONTACT.UPLOAD_LABEL' | translate }}</label>
|
||||
<p class="hint">{{ 'CONTACT.UPLOAD_HINT' | translate }}</p>
|
||||
|
||||
<div class="drop-zone" (click)="fileInput.click()"
|
||||
(dragover)="onDragOver($event)" (drop)="onDrop($event)">
|
||||
<input #fileInput type="file" multiple (change)="onFileSelected($event)" hidden
|
||||
accept=".jpg,.jpeg,.png,.pdf,.stl,.step,.stp,.3mf,.obj">
|
||||
<p>{{ 'CONTACT.DROP_FILES' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="file-grid" *ngIf="files().length > 0">
|
||||
<div class="file-item" *ngFor="let file of files(); let i = index">
|
||||
<button type="button" class="remove-btn" (click)="removeFile(i)">×</button>
|
||||
<img *ngIf="file.type === 'image'" [src]="file.url" class="preview-img">
|
||||
<div *ngIf="file.type !== 'image'" class="file-icon">
|
||||
<span *ngIf="file.type === 'pdf'">PDF</span>
|
||||
<span *ngIf="file.type === '3d'">3D</span>
|
||||
</div>
|
||||
<div class="file-name" [title]="file.file.name">{{ file.file.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<app-button type="submit" [disabled]="form.invalid || sent()">
|
||||
{{ sent() ? 'Inviato!' : ('CONTACT.SEND' | translate) }}
|
||||
</app-button>
|
||||
</div>
|
||||
</form>
|
||||
`,
|
||||
styles: [`
|
||||
.form-group { display: flex; flex-direction: column; margin-bottom: var(--space-4); }
|
||||
label { font-size: 0.875rem; font-weight: 500; margin-bottom: var(--space-2); color: var(--color-text); }
|
||||
.hint { font-size: 0.75rem; color: var(--color-text-muted); margin-bottom: var(--space-2); }
|
||||
|
||||
.form-control {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
width: 100%;
|
||||
background: var(--color-bg-card);
|
||||
color: var(--color-text);
|
||||
font-family: inherit;
|
||||
&:focus { outline: none; border-color: var(--color-brand); }
|
||||
}
|
||||
|
||||
select.form-control {
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 1rem center;
|
||||
background-size: 1em;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
|
||||
@media(min-width: 768px) {
|
||||
flex-direction: row;
|
||||
.col { flex: 1; margin-bottom: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Modify direct app-input child of row if possible or target host */
|
||||
app-input.col {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
input[type="checkbox"] { width: auto; margin: 0; }
|
||||
label { margin: 0; }
|
||||
}
|
||||
|
||||
.company-fields {
|
||||
padding-left: var(--space-4);
|
||||
border-left: 2px solid var(--color-border);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.drop-zone {
|
||||
border: 2px dashed var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-muted);
|
||||
transition: all 0.2s;
|
||||
&:hover { border-color: var(--color-brand); color: var(--color-brand); }
|
||||
}
|
||||
|
||||
.file-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
||||
.file-item {
|
||||
position: relative;
|
||||
background: var(--color-neutral-100);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview-img {
|
||||
width: 100%; height: 100%; object-fit: cover; position: absolute; top:0; left:0;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-weight: 700; color: var(--color-text-muted); font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 0.65rem; color: var(--color-text); white-space: nowrap; overflow: hidden;
|
||||
text-overflow: ellipsis; width: 100%; text-align: center; position: absolute; bottom: 2px;
|
||||
padding: 0 4px; z-index: 2; background: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
position: absolute; top: 2px; right: 2px; z-index: 10;
|
||||
background: rgba(0,0,0,0.5); color: white; border: none; border-radius: 50%;
|
||||
width: 18px; height: 18px; font-size: 12px; cursor: pointer;
|
||||
display: flex; align-items: center; justify-content: center; line-height: 1;
|
||||
&:hover { background: red; }
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class ContactFormComponent {
|
||||
form: FormGroup;
|
||||
sent = signal(false);
|
||||
files = signal<FilePreview[]>([]);
|
||||
|
||||
requestTypes = [
|
||||
{ value: 'custom', label: 'CONTACT.REQ_TYPE_CUSTOM' },
|
||||
{ value: 'series', label: 'CONTACT.REQ_TYPE_SERIES' },
|
||||
{ value: 'consult', label: 'CONTACT.REQ_TYPE_CONSULT' },
|
||||
{ value: 'question', label: 'CONTACT.REQ_TYPE_QUESTION' }
|
||||
];
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
this.form = this.fb.group({
|
||||
requestType: ['custom', Validators.required],
|
||||
name: ['', Validators.required],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
phone: [''],
|
||||
message: ['', Validators.required],
|
||||
isCompany: [false],
|
||||
companyName: [''],
|
||||
referencePerson: ['']
|
||||
});
|
||||
|
||||
// Handle conditional validation for Company fields
|
||||
this.form.get('isCompany')?.valueChanges.subscribe(isCompany => {
|
||||
const companyNameControl = this.form.get('companyName');
|
||||
const refPersonControl = this.form.get('referencePerson');
|
||||
|
||||
if (isCompany) {
|
||||
companyNameControl?.setValidators([Validators.required]);
|
||||
refPersonControl?.setValidators([Validators.required]);
|
||||
} else {
|
||||
companyNameControl?.clearValidators();
|
||||
refPersonControl?.clearValidators();
|
||||
}
|
||||
companyNameControl?.updateValueAndValidity();
|
||||
refPersonControl?.updateValueAndValidity();
|
||||
});
|
||||
}
|
||||
|
||||
onFileSelected(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
if (input.files) this.handleFiles(Array.from(input.files));
|
||||
}
|
||||
|
||||
onDragOver(event: DragEvent) {
|
||||
event.preventDefault(); event.stopPropagation();
|
||||
}
|
||||
|
||||
onDrop(event: DragEvent) {
|
||||
event.preventDefault(); event.stopPropagation();
|
||||
if (event.dataTransfer?.files) this.handleFiles(Array.from(event.dataTransfer.files));
|
||||
}
|
||||
|
||||
handleFiles(newFiles: File[]) {
|
||||
const currentFiles = this.files();
|
||||
if (currentFiles.length + newFiles.length > 15) {
|
||||
alert("Max 15 files limit reached.");
|
||||
return;
|
||||
}
|
||||
|
||||
newFiles.forEach(file => {
|
||||
const type = this.getFileType(file);
|
||||
const preview: FilePreview = { file, type };
|
||||
|
||||
if (type === 'image') {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
preview.url = e.target?.result as string;
|
||||
this.files.update(files => [...files]);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
this.files.update(files => [...files, preview]);
|
||||
});
|
||||
}
|
||||
|
||||
removeFile(index: number) {
|
||||
this.files.update(files => files.filter((_, i) => i !== index));
|
||||
}
|
||||
|
||||
getFileType(file: File): 'image' | 'pdf' | '3d' | 'other' {
|
||||
if (file.type.startsWith('image/')) return 'image';
|
||||
if (file.type === 'application/pdf') return 'pdf';
|
||||
const ext = file.name.split('.').pop()?.toLowerCase();
|
||||
if (['stl', 'step', 'stp', '3mf', 'obj'].includes(ext || '')) return '3d';
|
||||
return 'other';
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.form.valid) {
|
||||
const formData = {
|
||||
...this.form.value,
|
||||
files: this.files().map(f => f.file)
|
||||
};
|
||||
console.log('Form Submit:', formData);
|
||||
|
||||
this.sent.set(true);
|
||||
setTimeout(() => {
|
||||
this.sent.set(false);
|
||||
this.form.reset({ requestType: 'custom', isCompany: false });
|
||||
this.files.set([]);
|
||||
}, 3000);
|
||||
} else {
|
||||
this.form.markAllAsTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
frontend/src/app/features/contact/contact-page.component.ts
Normal file
42
frontend/src/app/features/contact/contact-page.component.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ContactFormComponent } from './components/contact-form/contact-form.component';
|
||||
import { AppCardComponent } from '../../shared/components/app-card/app-card.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-page',
|
||||
standalone: true,
|
||||
imports: [CommonModule, TranslateModule, ContactFormComponent, AppCardComponent],
|
||||
template: `
|
||||
<section class="contact-hero">
|
||||
<div class="container">
|
||||
<h1>{{ 'CONTACT.TITLE' | translate }}</h1>
|
||||
<p class="subtitle">Siamo qui per aiutarti. Compila il modulo sottostante per qualsiasi richiesta.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container content">
|
||||
<app-card>
|
||||
<app-contact-form></app-contact-form>
|
||||
</app-card>
|
||||
</div>
|
||||
`,
|
||||
styles: [`
|
||||
.contact-hero {
|
||||
padding: 5rem 0 3.5rem;
|
||||
background: var(--color-bg);
|
||||
text-align: center;
|
||||
}
|
||||
.subtitle {
|
||||
color: var(--color-text-muted);
|
||||
max-width: 640px;
|
||||
margin: var(--space-3) auto 0;
|
||||
}
|
||||
.content {
|
||||
padding: 3rem 0 5rem;
|
||||
max-width: 800px;
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class ContactPageComponent {}
|
||||
8
frontend/src/app/features/contact/contact.routes.ts
Normal file
8
frontend/src/app/features/contact/contact.routes.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export const CONTACT_ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./contact-page.component').then(m => m.ContactPageComponent)
|
||||
}
|
||||
];
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"NAV": {
|
||||
"HOME": "Home",
|
||||
"CALCULATOR": "Calculator",
|
||||
"SHOP": "Shop",
|
||||
"ABOUT": "About"
|
||||
"ABOUT": "About",
|
||||
"CONTACT": "Contact Us"
|
||||
},
|
||||
"FOOTER": {
|
||||
"PRIVACY": "Privacy",
|
||||
@@ -58,7 +60,22 @@
|
||||
"SERVICE_4": "File verification and optimization for printing",
|
||||
"TARGET_TITLE": "Who is it for",
|
||||
"TARGET_TEXT": "Small businesses, freelancers, makers and customers looking for a ready-made product from the shop.",
|
||||
"CONTACT_US": "Contact Us",
|
||||
"SEND": "Send Message"
|
||||
"TEAM_TITLE": "Our Team"
|
||||
},
|
||||
"CONTACT": {
|
||||
"TITLE": "Contact Us",
|
||||
"SEND": "Send Message",
|
||||
"REQ_TYPE_LABEL": "Type of Request",
|
||||
"REQ_TYPE_CUSTOM": "Custom Quote",
|
||||
"REQ_TYPE_SERIES": "Series Production",
|
||||
"REQ_TYPE_CONSULT": "Consultation",
|
||||
"REQ_TYPE_QUESTION": "General Questions",
|
||||
"PHONE": "Phone",
|
||||
"IS_COMPANY": "Are you a company?",
|
||||
"COMPANY_NAME": "Company Name",
|
||||
"REF_PERSON": "Reference Person",
|
||||
"UPLOAD_LABEL": "Attachments",
|
||||
"UPLOAD_HINT": "Max 15 files. Supported: Images, PDF, STL, STEP, 3MF, OBJ",
|
||||
"DROP_FILES": "Drop files here or click to upload"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"NAV": {
|
||||
"HOME": "Home",
|
||||
"CALCULATOR": "Calcolatore",
|
||||
"SHOP": "Shop",
|
||||
"ABOUT": "Chi Siamo"
|
||||
"ABOUT": "Chi Siamo",
|
||||
"CONTACT": "Contattaci"
|
||||
},
|
||||
"FOOTER": {
|
||||
"PRIVACY": "Privacy",
|
||||
@@ -63,7 +65,22 @@
|
||||
"SERVICE_4": "Verifica file e ottimizzazione per la stampa",
|
||||
"TARGET_TITLE": "Per chi è",
|
||||
"TARGET_TEXT": "Piccole aziende, freelance, smanettoni e clienti che cercano un prodotto già pronto dallo shop.",
|
||||
"CONTACT_US": "Contattaci",
|
||||
"SEND": "Invia Messaggio"
|
||||
"TEAM_TITLE": "Il Nostro Team"
|
||||
},
|
||||
"CONTACT": {
|
||||
"TITLE": "Contattaci",
|
||||
"SEND": "Invia Messaggio",
|
||||
"REQ_TYPE_LABEL": "Tipo di Richiesta",
|
||||
"REQ_TYPE_CUSTOM": "Preventivo Personalizzato",
|
||||
"REQ_TYPE_SERIES": "Stampa in Serie",
|
||||
"REQ_TYPE_CONSULT": "Consulenza",
|
||||
"REQ_TYPE_QUESTION": "Domande Generali",
|
||||
"PHONE": "Telefono",
|
||||
"IS_COMPANY": "Sei un'azienda?",
|
||||
"COMPANY_NAME": "Ragione Sociale",
|
||||
"REF_PERSON": "Persona di Riferimento",
|
||||
"UPLOAD_LABEL": "Allegati",
|
||||
"UPLOAD_HINT": "Max 15 file. Supportati: Immagini, PDF, STL, STEP, 3MF, OBJ",
|
||||
"DROP_FILES": "Trascina qui i file o clicca per caricare"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user