Piattaforma ITI TECHNOLOGY: monorepo, Medusa, API, sito, area riservata e deploy
Deploy stack su Proxmox / deploy (push) Failing after 3s
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
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
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))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user