refactor: projet stand-alone sans dépendance aoe_technology_radar

- Intégration du code source du framework dans radar-app/ (vendoring)
- Suppression de la dépendance npm aoe_technology_radar
- Création de scripts build-radar.js et serve-radar.js pour remplacer le CLI techradar
- Adaptation de tous les scripts et Docker pour utiliser radar-app/ au lieu de .techradar
- Refactorisation complète de Dockerfile.business
- Mise à jour de la documentation (architecture, déploiement, développement)
- Mise à jour de .gitignore pour ignorer les artefacts de build de radar-app/
- Ajout de postcss dans les dépendances Docker pour le build Next.js

Le projet est maintenant complètement indépendant du package externe.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
syoul
2026-02-25 18:11:40 +01:00
parent cc8df1a4af
commit 9d8ae3d32a
125 changed files with 15583 additions and 123 deletions

View File

@@ -0,0 +1,119 @@
.header {
display: flex;
flex-wrap: wrap;
align-items: center;
margin: 0 0 20px;
}
.title {
margin: 0 30px 0 0;
}
.editLink {
position: absolute;
top: 10px;
right: 10px;
display: block;
width: 20px;
height: 20px;
opacity: 0;
transition: opacity 0.2s;
}
.revision {
padding: 30px 0 15px 35px;
margin-left: 20px;
border-left: 1px solid var(--border);
&:hover {
.editLink {
opacity: 1;
}
}
}
.release {
display: block;
text-align: center;
text-transform: uppercase;
font-size: 12px;
line-height: 1.2;
width: 50px;
height: 50px;
padding: 10px 0;
border-radius: 50%;
border: 1px solid var(--border);
background: var(--background);
float: left;
margin: -15px 0 0 -60px;
}
.notMaintainedIcon {
fill: currentColor;
width: 24px;
height: 24px;
margin: 8px auto;
}
.ring {
float: left;
margin: -45px 0 0 0;
}
.content {
position: relative;
background: var(--content);
color: var(--text);
border-radius: 6px;
padding: 30px 15px;
}
.content a {
color: var(--link);
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
@media (min-width: 768px) {
.revision {
padding: 30px 0 15px 50px;
margin-left: 38px;
}
.release {
font-size: 18px;
width: 75px;
height: 75px;
padding: 15px 0;
margin: -15px 0 0 -90px;
}
.ring {
margin-left: -15px;
}
.content {
padding: 30px;
}
}
/* special styles for revisions without content */
.revision.noContent {
.content {
background: none;
}
.ring {
margin-top: -20px;
}
}
.revision.hint {
.content {
font-size: 14px;
background: var(--border);
color: var(--foreground);
}
}

View File

@@ -0,0 +1,81 @@
import styles from "./ItemDetail.module.css";
import { RingBadge } from "@/components/Badge/Badge";
import { Attention, Edit } from "@/components/Icons";
import { Tag } from "@/components/Tags/Tags";
import { getEditUrl, getLabel, getReleases } from "@/lib/data";
import { Item } from "@/lib/types";
import { cn } from "@/lib/utils";
const latestReleases = getReleases().slice(-3);
function isNotMaintained(release: string) {
return !latestReleases.includes(release);
}
interface ItemProps {
item: Item;
}
export function ItemDetail({ item }: ItemProps) {
const notMaintainedText = getLabel("notUpdated");
return (
<>
<div className={styles.header}>
<h1 className={styles.title}>{item.title}</h1>
{item.tags?.map((tag) => <Tag key={tag} tag={tag} />)}
</div>
<div className={styles.revisions}>
{notMaintainedText && isNotMaintained(item.release) && (
<div className={cn(styles.revision, styles.hint)}>
<span className={styles.release}>
<Attention className={styles.notMaintainedIcon} />
</span>
<div className={styles.content}>{notMaintainedText}</div>
</div>
)}
<Revision
id={item.id}
release={item.release}
ring={item.ring}
body={item.body}
/>
{item.revisions?.map((revision, index) => (
<Revision key={index} id={item.id} {...revision} />
))}
</div>
</>
);
}
interface RevisionProps {
id: string;
release: string;
ring: string;
body?: string;
}
function Revision({ id, release, ring, body }: RevisionProps) {
const date = new Date(release);
const editLink = getEditUrl({ id, release });
const formattedDate = date.toLocaleDateString("en-US", {
month: "short",
year: "numeric",
});
return (
<div className={cn(styles.revision, !body && styles.noContent)}>
<time dateTime={release} className={styles.release}>
{formattedDate}
</time>
<div className={styles.content}>
<RingBadge className={styles.ring} ring={ring} size="large" />
{body ? <div dangerouslySetInnerHTML={{ __html: body }} /> : null}
{editLink && (
<a href={editLink} target="_blank" className={styles.editLink}>
<Edit />
</a>
)}
</div>
</div>
);
}