Deploy stack su Proxmox / deploy (push) Failing after 3s
Monorepo npm con apps/public (Angular SSR), apps/private (Angular SPA), apps/api (Fastify), packages/shared e packages/styles; Medusa 2.21 in medusa/; infrastruttura Docker (Postgres PostGIS+pgvector, Redis, Caddy, backup) e workflow Gitea Actions per il deploy via SSH a ogni push su master. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jQyT6dR9czzGwqb7FkG6u
140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import { ChangeDetectionStrategy, Component, computed, effect, inject, input } from '@angular/core'
|
|
import { RouterLink } from '@angular/router'
|
|
import { COMPANY_PAGES, companyPagePath, findCompanyPage } from '../../content/company-pages'
|
|
import { SITE_CONFIG } from '../core/app-config'
|
|
import { SeoService } from '../core/seo.service'
|
|
import { breadcrumbJsonLd } from '../core/structured-data'
|
|
import { PageHeader } from '../shared/page-header'
|
|
import { PlaceholderBadge } from '../shared/placeholder-badge'
|
|
|
|
/**
|
|
* /azienda e /azienda/:pagina, generate da src/content/company/<slug>.ts. /azienda mostra la prima pagina
|
|
* (Chi siamo); gli slug sconosciuti non arrivano qui (canMatch → 404).
|
|
*/
|
|
@Component({
|
|
selector: 'app-company-page',
|
|
imports: [RouterLink, PageHeader, PlaceholderBadge],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
template: `
|
|
@let p = page();
|
|
<app-page-header [heading]="p.title" [lead]="p.lead" [crumbs]="crumbs()">
|
|
<app-placeholder-badge badge [show]="p.placeholder" />
|
|
</app-page-header>
|
|
<div class="container layout">
|
|
<nav class="subnav" aria-label="Azienda">
|
|
<ul>
|
|
@for (item of pages; track item.slug) {
|
|
<li>
|
|
<a [routerLink]="path(item)" [attr.aria-current]="item === p ? 'page' : null">{{ item.title }}</a>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</nav>
|
|
<article>
|
|
@for (section of p.sections; track section.heading) {
|
|
<section>
|
|
<h2>{{ section.heading }}</h2>
|
|
@for (paragraph of section.paragraphs; track $index) {
|
|
<p>{{ paragraph }}</p>
|
|
}
|
|
@if (section.items?.length) {
|
|
<ul class="items">
|
|
@for (item of section.items; track $index) {
|
|
<li>{{ item }}</li>
|
|
}
|
|
</ul>
|
|
}
|
|
</section>
|
|
}
|
|
@if (p.cta; as cta) {
|
|
<a class="btn btn--primary" [routerLink]="cta.path" [queryParams]="cta.query ?? null">{{ cta.label }}</a>
|
|
}
|
|
</article>
|
|
</div>
|
|
`,
|
|
styles: `
|
|
@use 'mixins' as mq;
|
|
|
|
.layout {
|
|
display: grid;
|
|
gap: var(--space-6);
|
|
padding-block: var(--space-6) var(--space-8);
|
|
|
|
@include mq.up(lg) {
|
|
grid-template-columns: 220px 1fr;
|
|
gap: var(--space-8);
|
|
}
|
|
}
|
|
.subnav ul {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-2);
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
|
|
@include mq.up(lg) {
|
|
flex-direction: column;
|
|
position: sticky;
|
|
top: calc(var(--header-height) + var(--space-5));
|
|
}
|
|
}
|
|
.subnav a {
|
|
display: flex;
|
|
align-items: center;
|
|
min-height: 44px;
|
|
padding-inline: var(--space-3);
|
|
border-radius: var(--radius-md);
|
|
color: var(--color-ink);
|
|
text-decoration: none;
|
|
|
|
&[aria-current='page'] {
|
|
background: var(--color-primary-soft);
|
|
color: var(--color-primary);
|
|
font-weight: var(--font-weight-semibold);
|
|
}
|
|
}
|
|
article {
|
|
max-width: 70ch;
|
|
}
|
|
section {
|
|
margin-bottom: var(--space-6);
|
|
}
|
|
h2 {
|
|
font-size: var(--font-size-2xl);
|
|
}
|
|
.items {
|
|
padding-left: var(--space-5);
|
|
|
|
li {
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
}
|
|
`,
|
|
})
|
|
export default class CompanyPage {
|
|
/** Parametro di route (assente su /azienda). */
|
|
readonly pagina = input<string>()
|
|
|
|
protected readonly pages = COMPANY_PAGES
|
|
protected readonly path = companyPagePath
|
|
protected readonly page = computed(() => findCompanyPage(this.pagina() ?? '') ?? COMPANY_PAGES[0]!)
|
|
protected readonly crumbs = computed(() =>
|
|
this.pagina() ? [{ label: 'Azienda', path: '/azienda' }, { label: this.page().title }] : [{ label: 'Azienda' }],
|
|
)
|
|
|
|
constructor() {
|
|
const seo = inject(SeoService)
|
|
const { siteUrl } = inject(SITE_CONFIG)
|
|
effect(() => {
|
|
const page = this.page()
|
|
const path = companyPagePath(page)
|
|
seo.setPage({ title: page.title, description: page.description, path })
|
|
seo.setJsonLd(
|
|
'breadcrumb',
|
|
breadcrumbJsonLd(siteUrl, path === '/azienda' ? [{ name: 'Azienda', path }] : [{ name: 'Azienda', path: '/azienda' }, { name: page.title, path }]),
|
|
)
|
|
})
|
|
}
|
|
}
|