Files
iti-technology/apps/public/src/app/pages/solution.ts
T
Lorenzo SanesiandClaude Opus 5.5 b83ce039fb
Deploy stack su Proxmox / deploy (push) Failing after 3s
Piattaforma ITI TECHNOLOGY: monorepo, Medusa, API, sito, area riservata e deploy
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
2026-10-20 09:30:48 +02:00

100 lines
3.3 KiB
TypeScript

import { ChangeDetectionStrategy, Component, computed, effect, inject, input } from '@angular/core'
import { RouterLink } from '@angular/router'
import { findSolution, solutionsOf } from '../../content/catalog'
import { SITE_CONFIG } from '../core/app-config'
import { SeoService } from '../core/seo.service'
import { breadcrumbJsonLd, faqJsonLd } from '../core/structured-data'
import { PageHeader } from '../shared/page-header'
import { PlaceholderBadge } from '../shared/placeholder-badge'
import { SolutionBody } from '../shared/solution-body'
/**
* /soluzioni/:area/:soluzione, generata da src/content/solutions/<area>/<soluzione>.ts.
* Coppie sconosciute → 404 (canMatch).
*/
@Component({
selector: 'app-solution-page',
imports: [RouterLink, PageHeader, PlaceholderBadge, SolutionBody],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (data(); as d) {
<app-page-header
[heading]="d.solution.title"
[lead]="d.solution.tagline"
[crumbs]="[{ label: d.area.label, path: '/soluzioni/' + d.area.slug }, { label: d.solution.title }]"
[area]="d.area.slug"
>
<app-placeholder-badge badge [show]="d.solution.placeholder" />
</app-page-header>
<div class="container body">
<app-solution-body [content]="d.solution" />
@if (siblings().length) {
<nav class="siblings" aria-labelledby="siblings-title">
<h2 id="siblings-title">Altre soluzioni {{ d.area.label }}</h2>
<ul>
@for (s of siblings(); track s.slug) {
<li><a [routerLink]="['/soluzioni', d.area.slug, s.slug]">{{ s.title }}</a></li>
}
</ul>
</nav>
}
</div>
}
`,
styles: `
.body {
padding-block: var(--space-6) var(--space-4);
}
.siblings {
margin-block: var(--space-7);
h2 {
font-size: var(--font-size-xl);
}
ul {
display: flex;
flex-wrap: wrap;
gap: var(--space-3);
margin: 0;
padding: 0;
list-style: none;
}
a {
display: inline-flex;
align-items: center;
min-height: 44px;
padding: var(--space-2) var(--space-4);
border: 1px solid var(--color-line);
border-radius: var(--radius-pill);
text-decoration: none;
}
}
`,
})
export default class SolutionPage {
readonly area = input.required<string>()
readonly soluzione = input.required<string>()
protected readonly data = computed(() => findSolution(this.area(), this.soluzione()))
protected readonly siblings = computed(() => solutionsOf(this.area()).filter((s) => s.slug !== this.soluzione()))
constructor() {
const seo = inject(SeoService)
const { siteUrl } = inject(SITE_CONFIG)
effect(() => {
const d = this.data()
if (!d) return
const areaPath = `/soluzioni/${d.area.slug}`
const path = `${areaPath}/${d.solution.slug}`
seo.setPage({ title: `${d.solution.title} - ${d.area.label}`, description: d.solution.description, path, image: d.solution.image.src })
seo.setJsonLd(
'breadcrumb',
breadcrumbJsonLd(siteUrl, [
{ name: d.area.label, path: areaPath },
{ name: d.solution.title, path },
]),
)
if (d.solution.faq.length) seo.setJsonLd('faq', faqJsonLd(d.solution.faq))
})
}
}