Merge branch 'main' into feat/complete-en-th-translations

Risolve i conflitti su codice-etico mantenendo traduzioni EN/TH, companyConfig e link agli allegati.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Javaxman
2026-07-31 14:36:35 +02:00
6 changed files with 1572 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,73 @@
* Codice etico — riferimenti a prodotti e domini **separati in dati**:
* aggiungere una riga a `productLines` e, se serve, un `ConformityBlock` in
* `conformityBlocks` senza riscrivere la pagina intera.
*
* ═══════════════════════════════════════════════════════════════════════════
* CONFIGURAZIONE SOCIETARIA — compilare per rendere effettivo il documento.
* ═══════════════════════════════════════════════════════════════════════════
*/
import type { SupportedLocale } from './home/navigation';
/**
* Dati societari da personalizzare.
* Una volta compilati, il Codice Etico è formalmente effettivo.
*/
export const companyConfig = {
/** Ragione sociale ufficiale (se diversa dal marchio NexStudio) */
officialName: 'NexStudio',
/** Sede legale */
headquarters: 'Bangkok, Thailandia',
/** Partita IVA / codice fiscale thailandese */
taxId: '[DA INSERIRE]',
/** Numero registrazione società */
registrationNumber: '[DA INSERIRE]',
/** Approvatore del Codice Etico */
approver: {
/** Organo che approva (es. "Amministratore Delegato") */
role: '[DA INSERIRE — es. Amministratore Delegato]',
/** Nome e cognome del firmatario */
fullName: '[DA INSERIRE]',
/** Data di approvazione effettiva */
approvalDate: '[DA INSERIRE — es. 21 aprile 2026]',
},
/** Responsabile aggiornamenti del Codice */
updateOwner: {
role: 'Legal & Compliance, con supporto di DPO e CISO',
},
/** Governance — nomi dei ruoli chiave */
roles: {
ceo: '[DA INSERIRE]',
cto: '[DA INSERIRE]',
ciso: '[DA INSERIRE]',
dpo: '[DA INSERIRE]',
legal: '[DA INSERIRE]',
hr: '[DA INSERIRE]',
ethicsCommittee: '[DA INSERIRE o "non ancora costituito"]',
},
/** Contatti email */
contacts: {
privacy: 'privacy@nexstudio.com',
security: 'security@nexstudio.com',
ethics: 'ethics@nexstudio.com',
legal: 'legal@nexstudio.com',
hr: 'hr@nexstudio.com',
},
/** Audit e revisione */
review: {
/** Frequenza revisione del Codice */
frequency: 'minimo annuale o a fronte di mutamenti rilevanti',
/** Data ultima revisione */
lastReviewDate: '[DA INSERIRE]',
/** Data prossima revisione prevista */
nextReviewDate: '[DA INSERIRE]',
},
};
export type ConformityBlock = {
id: string;
anchorId: string;
@ -109,7 +173,7 @@ type CodiceEticoLocale = {
intro: string;
items: readonly string[];
};
allegati: { title: string; items: readonly string[] };
allegati: { title: string; items: readonly string[]; linkLabel: string };
approvazione: {
title: string;
items: readonly LabeledItem[];
@ -540,6 +604,7 @@ const codiceEticoByLocale: Record<SupportedLocale, CodiceEticoLocale> = {
},
allegati: {
title: '18. Allegati e moduli (inclusi)',
linkLabel: 'Scarica e consulta tutti i template operativi nella pagina dedicata →',
items: [
'Dichiarazione personale di adesione al Codice (da firmare in onboarding).',
'Template NDA e clausole minime per fornitori e sub-processori.',
@ -1030,6 +1095,7 @@ const codiceEticoByLocale: Record<SupportedLocale, CodiceEticoLocale> = {
},
allegati: {
title: '18. Annexes and forms (included)',
linkLabel: 'Download and browse all operational templates on the dedicated page →',
items: [
'Personal declaration of adhesion to the Code (to be signed at onboarding).',
'NDA template and minimum clauses for vendors and sub-processors.',
@ -1520,6 +1586,7 @@ const codiceEticoByLocale: Record<SupportedLocale, CodiceEticoLocale> = {
},
allegati: {
title: '18. ภาคผนวกและแบบฟอร์ม (รวมอยู่)',
linkLabel: 'ดาวน์โหลดและเรียกดูเทมเพลตปฏิบัติการทั้งหมดในหน้าเฉพาะ →',
items: [
'ประกาศยอมรับประมวลส่วนบุคคล (ลงนามตอนปฐมนิเทศ)',
'เทมเพลต NDA และข้อสัญญาน้อยสุดสำหรับผู้ให้บริการและผู้ประมวลผลช่วง',

109
src/pages/allegati.astro Normal file
View File

@ -0,0 +1,109 @@
---
import SubpageLayout from '../layouts/SubpageLayout.astro';
import { getAllegatiCodiceEtico } from '../data/allegati-codice-etico';
const path = Astro.url.pathname;
const localeMatch = path.match(/^\/(en|th)(\/|$)/);
const currentLocale = (localeMatch?.[1] ?? 'it') as 'it' | 'en' | 'th';
const a = getAllegatiCodiceEtico(currentLocale);
const { page, allegati } = a;
const link = 'text-sky-400/90 underline-offset-2 hover:text-sky-300 hover:underline';
const isLabeledFields = (item: unknown): item is { label: string; fields: string[] } =>
typeof item === 'object' && item !== null && 'label' in item && 'fields' in item;
const isLabeledText = (item: unknown): item is { label: string; text: string } =>
typeof item === 'object' && item !== null && 'label' in item && 'text' in item;
---
<SubpageLayout
title={page.title}
description={page.description}
heading={page.heading}
lead={page.lead}
>
<p class="mb-8 text-sm">
<a class={link} href={`/${currentLocale === 'it' ? '' : currentLocale + '/'}codice-etico`}>
{page.backLabel}
</a>
</p>
<div class="space-y-16">
{
allegati.map((allegato) => (
<section id={allegato.id} class="scroll-mt-8">
<h2 class="border-b border-nx-border pb-2 text-xl font-bold text-nx-fg">
{allegato.heading}
</h2>
<p class="mt-1 text-sm text-nx-muted">{allegato.description}</p>
{allegato.intro ? (
<p class="mt-4 text-sm italic text-nx-muted/90">{allegato.intro}</p>
) : null}
<div class="mt-6 space-y-6">
{
allegato.sections.map((section) => (
<div>
{section.title ? (
<h3 class="mb-3 text-base font-semibold text-nx-fg">{section.title}</h3>
) : null}
{section.intro ? (
<p class="mb-3 text-sm text-nx-muted">{section.intro}</p>
) : null}
{Array.isArray(section.content) ? (
section.content.length > 0 && typeof section.content[0] === 'string' ? (
<ul class="list-disc space-y-1.5 pl-5 text-sm leading-relaxed sm:text-base">
{(section.content as string[]).map((item) => (
<li>{item}</li>
))}
</ul>
) : section.content.length > 0 && isLabeledFields(section.content[0]) ? (
<dl class="space-y-3">
{(section.content as { label: string; fields: string[] }[]).map((item) => (
<div class="border-l-2 border-nx-border pl-4">
<dt class="text-sm font-medium text-nx-fg">{item.label}</dt>
<dd class="mt-0.5 font-mono text-sm text-nx-muted">
{item.fields.join(' | ')}
</dd>
</div>
))}
</dl>
) : section.content.length > 0 && isLabeledText(section.content[0]) ? (
<dl class="space-y-3">
{(section.content as { label: string; text: string }[]).map((item) => (
<div class="border-l-2 border-nx-border pl-4">
<dt class="text-sm font-semibold text-nx-fg">{item.label}</dt>
<dd class="mt-0.5 text-sm leading-relaxed text-nx-muted">{item.text}</dd>
</div>
))}
</dl>
) : (
<p class="text-sm text-nx-muted">{String(section.content)}</p>
)
) : (
<p class="text-sm leading-relaxed sm:text-base">{String(section.content)}</p>
)}
{section.note ? (
<p class="mt-3 border-l-2 border-sky-500/30 pl-4 text-sm leading-relaxed text-nx-muted">
{section.note}
</p>
) : null}
</div>
))
}
</div>
{allegato.footer ? (
<p class="mt-8 border-t border-nx-border pt-4 text-sm text-nx-fg">
{allegato.footer}
</p>
) : null}
</section>
))
}
</div>
</SubpageLayout>

View File

@ -270,6 +270,11 @@ const isLabeled = (item: string | { label: string; text: string }): item is { la
</ul>
<h2 id="allegati">{c.allegati.title}</h2>
<p class="mb-4 text-sm">
<a class={link} href={`/${currentLocale === 'it' ? '' : currentLocale + '/'}allegati`}>
{c.allegati.linkLabel}
</a>
</p>
<ul>
{c.allegati.items.map((item) => <li>{item}</li>)}
</ul>

View File

@ -0,0 +1,5 @@
---
import Page from '../allegati.astro';
---
<Page />

View File

@ -0,0 +1,5 @@
---
import Page from '../allegati.astro';
---
<Page />