feat(outils): sélection open source, sommaire d'ancres et garde-fous (B6-M4)
28 outils vérifiés en 4 rubriques (open_source.selection), affichés en premier sous un sommaire d'ancres ; grille 2 colonnes dès 1024 px. Le test contrôle la sélection (champs, https, liste noire) et les doublons d'URL. Co-Authored-By: Claude Sonnet <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0136n5xMLHuaBDLcPJYCDjRW
This commit is contained in:
co-authored by
Claude Sonnet
parent
dfbac7dd12
commit
43ae065e26
+131
-6
@@ -95,8 +95,38 @@
|
||||
<template v-else-if="tab === 'open-source'">
|
||||
<p class="outils-intention">{{ outils.open_source.intention }}</p>
|
||||
|
||||
<section class="outils-section" aria-labelledby="sec-recommandes">
|
||||
<h2 id="sec-recommandes" class="outils-section__title">Recommandés</h2>
|
||||
<!-- Sommaire d'ancres : tout est déployé d'office, on saute au bloc voulu -->
|
||||
<nav class="os-sommaire" aria-label="Sommaire de l'onglet Open source">
|
||||
<ul class="os-sommaire__liste">
|
||||
<li v-for="a in sommaire" :key="a.id">
|
||||
<a :href="'#' + a.id" class="os-sommaire__lien" @click="allerAncre($event, a.id)">{{ a.libelle }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Sélection AEP : outils utiles à un architecte indépendant (B6-M3/M4) -->
|
||||
<template v-if="outils.open_source.selection">
|
||||
<p class="outils-section__desc">{{ outils.open_source.selection.intention }}</p>
|
||||
<section
|
||||
v-for="r in outils.open_source.selection.rubriques"
|
||||
:key="r.id"
|
||||
class="outils-section outils-section--ancre"
|
||||
:aria-labelledby="'sel-' + r.id"
|
||||
>
|
||||
<h2 :id="'sel-' + r.id" class="outils-section__title" tabindex="-1">{{ r.titre }}</h2>
|
||||
<p v-if="r.note" class="outils-section__desc">{{ r.note }}</p>
|
||||
<ul class="sel-grid">
|
||||
<li v-for="l in r.liens" :key="l.url" class="sel-item">
|
||||
<a :href="l.url" target="_blank" rel="noopener noreferrer" class="sel-item__nom">{{ l.nom }}</a>
|
||||
<p class="sel-item__desc">{{ l.desc }}</p>
|
||||
<p class="sel-item__meta">{{ metaSelection(l) }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<section class="outils-section outils-section--ancre" aria-labelledby="sec-recommandes">
|
||||
<h2 id="sec-recommandes" class="outils-section__title" tabindex="-1">Nos recommandations</h2>
|
||||
<div class="outil-cards-grid">
|
||||
<OutilCard
|
||||
v-for="outil in outils.open_source.recommandes"
|
||||
@@ -110,8 +140,8 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="outils-section outils-section--fmhy" aria-labelledby="sec-fmhy">
|
||||
<h2 id="sec-fmhy" class="outils-section__title">{{ outils.open_source.fmhy.titre }}</h2>
|
||||
<section class="outils-section outils-section--fmhy outils-section--ancre" aria-labelledby="sec-fmhy">
|
||||
<h2 id="sec-fmhy" class="outils-section__title" tabindex="-1">{{ outils.open_source.fmhy.titre }}</h2>
|
||||
<p class="outils-section__desc">{{ outils.open_source.fmhy.texte_intro }}</p>
|
||||
|
||||
<div v-for="g in outils.open_source.rubriques" :key="g.id" class="fmhy-usage">
|
||||
@@ -155,10 +185,10 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="outils.open_source.logiciels_pro" class="outils-section outils-section--placeholder" aria-labelledby="sec-logiciels">
|
||||
<section v-if="outils.open_source.logiciels_pro" class="outils-section outils-section--placeholder outils-section--ancre" aria-labelledby="sec-logiciels">
|
||||
<div class="placeholder-block">
|
||||
<span class="placeholder-block__badge">{{ outils.open_source.logiciels_pro.badge }}</span>
|
||||
<h2 id="sec-logiciels" class="placeholder-block__title">{{ outils.open_source.logiciels_pro.titre }}</h2>
|
||||
<h2 id="sec-logiciels" class="placeholder-block__title" tabindex="-1">{{ outils.open_source.logiciels_pro.titre }}</h2>
|
||||
<p class="placeholder-block__desc">{{ outils.open_source.logiciels_pro.description }}</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -220,6 +250,31 @@ function onTabKeydown(e: KeyboardEvent) {
|
||||
nextTick(() => tablistRef.value?.querySelector<HTMLElement>(`#outils-tab-${TABS[j].id}`)?.focus())
|
||||
}
|
||||
|
||||
// Open source : sommaire d'ancres = rubriques de la sélection + les trois autres blocs.
|
||||
const sommaire = computed(() => {
|
||||
const os = outils.value?.open_source
|
||||
if (!os) return []
|
||||
return [
|
||||
...(os.selection?.rubriques ?? []).map((r: any) => ({ id: `sel-${r.id}`, libelle: r.titre })),
|
||||
{ id: 'sec-recommandes', libelle: 'Nos recommandations' },
|
||||
{ id: 'sec-fmhy', libelle: 'Annuaire fmhy' },
|
||||
...(os.logiciels_pro ? [{ id: 'sec-logiciels', libelle: 'Logiciels pro' }] : []),
|
||||
]
|
||||
})
|
||||
|
||||
const metaSelection = (l: any) => [l.licence, (l.plateformes ?? []).join(', ')].filter(Boolean).join(' · ')
|
||||
|
||||
// Saut vers une ancre : défilement doux sauf préférence « moins d'animations », focus sur le titre
|
||||
// (clavier et lecteurs d'écran arrivent au bon endroit). L'URL ne bouge pas (?tab= intact).
|
||||
function allerAncre(e: Event, id: string) {
|
||||
e.preventDefault()
|
||||
const el = document.getElementById(id)
|
||||
if (!el) return
|
||||
const reduit = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
el.scrollIntoView({ behavior: reduit ? 'auto' : 'smooth', block: 'start' })
|
||||
el.focus({ preventScroll: true })
|
||||
}
|
||||
|
||||
useSeoMeta({
|
||||
title: () => `Outils — AEP${tab.value !== TAB_DEFAUT ? ' — ' + TABS.find((t) => t.id === tab.value)!.libelle : ''}`,
|
||||
description: 'Outils partagés entre architectes : simulateurs, open source, ressources libres pour partir de soi.',
|
||||
@@ -397,6 +452,76 @@ useSeoMeta({
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
/* ── Open source : sommaire d'ancres et sélection ───────────── */
|
||||
.outils-section--ancre { scroll-margin-top: var(--space-lg); }
|
||||
.outils-section--ancre :is(h2):focus { outline: none; }
|
||||
.outils-section--ancre :is(h2):focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-sm); }
|
||||
|
||||
.os-sommaire__liste {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-xs) var(--space-sm);
|
||||
}
|
||||
.os-sommaire__lien {
|
||||
display: inline-block;
|
||||
padding: var(--space-xs) var(--space-md);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--bg-alt);
|
||||
color: var(--text);
|
||||
font-size: 0.85rem;
|
||||
font-weight: var(--fw-medium);
|
||||
text-decoration: none;
|
||||
}
|
||||
.os-sommaire__lien:hover { border-color: var(--nav-primary-solid); }
|
||||
.os-sommaire__lien:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
|
||||
|
||||
.sel-grid {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.sel-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
.sel-item {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
padding: var(--space-md);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
}
|
||||
.sel-item__nom {
|
||||
align-self: flex-start;
|
||||
font-size: 0.95rem;
|
||||
font-weight: var(--fw-semibold);
|
||||
color: var(--nav-primary-solid);
|
||||
text-underline-offset: 2px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.sel-item__nom:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-sm); }
|
||||
.sel-item__desc {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.55;
|
||||
color: var(--text);
|
||||
}
|
||||
.sel-item__meta {
|
||||
margin: auto 0 0;
|
||||
padding-top: 0.2rem;
|
||||
font-size: 0.78rem;
|
||||
color: color-mix(in srgb, var(--text) 78%, transparent);
|
||||
}
|
||||
|
||||
/* ── Section FMHY ───────────────────────────────────────────── */
|
||||
.outils-section--fmhy {
|
||||
background: var(--bg-alt);
|
||||
|
||||
+407
-1
@@ -42,7 +42,413 @@
|
||||
]
|
||||
},
|
||||
"open_source": {
|
||||
"intention": "Des outils libres recommandés, puis un annuaire du web libre classé par usage. Choisis un usage et ouvre le lien.",
|
||||
"intention": "Des outils libres choisis pour un architecte indépendant, puis nos recommandations maison et un annuaire du web libre classé par usage. Choisis un bloc dans le sommaire ou fais défiler.",
|
||||
"selection": {
|
||||
"intention": "Une sélection d'outils libres utiles au quotidien d'un architecte indépendant : dictée, bureautique, dessin et modélisation, cartes et données publiques. Chacun a été ouvert et vérifié le 8 octobre 2026, avec sa licence et ses plateformes.",
|
||||
"rubriques": [
|
||||
{
|
||||
"id": "dictee-voix",
|
||||
"titre": "Dictée et voix",
|
||||
"note": "Ces outils font tourner Whisper sur ton ordinateur : rien ne part dans le cloud, ce qui compte quand tu dictes un CR de chantier ou un échange client.",
|
||||
"liens": [
|
||||
{
|
||||
"nom": "Handy",
|
||||
"url": "https://handy.computer/",
|
||||
"desc": "Raccourci clavier, tu parles, le texte s'insère au curseur dans n'importe quelle application : dicter un mail ou une note de chantier sans quitter le logiciel ouvert, avec transcription locale.",
|
||||
"source": "aep",
|
||||
"licence": "MIT",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v0.9.8 du 2026-10-03)"
|
||||
},
|
||||
{
|
||||
"nom": "Buzz",
|
||||
"url": "https://buzzcaptions.com/",
|
||||
"desc": "Transcrit un enregistrement de réunion ou de visite (fichier audio ou vidéo) en texte, SRT ou TXT, hors ligne : base brute pour un compte rendu.",
|
||||
"source": "aep",
|
||||
"licence": "MIT",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v1.4.5 du 2026-08-23)"
|
||||
},
|
||||
{
|
||||
"nom": "Vibe",
|
||||
"url": "https://github.com/thewh1teagle/vibe",
|
||||
"desc": "Transcription locale de fichiers audio et vidéo, interface simple : pratique pour transformer un vocal de visite en texte à retravailler.",
|
||||
"source": "aep",
|
||||
"licence": "MIT",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v3.2.2 du 2026-09-05)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "quotidien",
|
||||
"titre": "Le quotidien d'une agence",
|
||||
"note": "De quoi tenir un cabinet d'architecte sans abonnement : bureautique, courrier, notes, PDF, visio, devis et factures.",
|
||||
"liens": [
|
||||
{
|
||||
"nom": "LibreOffice",
|
||||
"url": "https://www.libreoffice.org/",
|
||||
"desc": "Rédiger CCTP, notes de calcul, tableurs de métrés et devis au format Word/Excel/PDF sans licence Microsoft.",
|
||||
"source": "aep",
|
||||
"licence": "MPL-2.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-08 (v26.8.1)"
|
||||
},
|
||||
{
|
||||
"nom": "Thunderbird",
|
||||
"url": "https://www.thunderbird.net/fr/",
|
||||
"desc": "Client mail et agenda pour centraliser plusieurs adresses (pro, projets, associatives) hors webmail, avec filtres et signatures.",
|
||||
"source": "aep",
|
||||
"licence": "MPL-2.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux",
|
||||
"Android"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026 (v157.0.1 sur le site le 2026-10-08)"
|
||||
},
|
||||
{
|
||||
"nom": "Joplin",
|
||||
"url": "https://joplinapp.org/",
|
||||
"desc": "Notes en markdown synchronisées sur téléphone et ordinateur (chiffrées de bout en bout) : carnet de chantier, listes de réserves, recherche rapide.",
|
||||
"source": "aep",
|
||||
"licence": "AGPL-3.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux",
|
||||
"Android",
|
||||
"iOS"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-09 (v3.7.21 du 2026-09-25)"
|
||||
},
|
||||
{
|
||||
"nom": "Stirling-PDF",
|
||||
"url": "https://github.com/Stirling-Tools/Stirling-PDF",
|
||||
"desc": "Fusionner, découper, compresser, signer ou passer en OCR un PDF (dossier de DP, pièces d'un marché) sans envoyer les plans chez un service tiers quand on l'installe en local.",
|
||||
"source": "aep",
|
||||
"licence": "MIT (cœur ; fonctions entreprise sous licence propriétaire, non nécessaires)",
|
||||
"plateformes": [
|
||||
"Web (auto-hébergé)",
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v3.1.0 du 2026-10-05)"
|
||||
},
|
||||
{
|
||||
"nom": "PDF Arranger",
|
||||
"url": "https://github.com/pdfarranger/pdfarranger",
|
||||
"desc": "Réordonner, pivoter, extraire ou fusionner les pages d'un PDF à la souris : composer un dossier de consultation propre en deux minutes.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-3.0",
|
||||
"plateformes": [
|
||||
"Linux",
|
||||
"Windows"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v1.14.0 du 2026-05-23, dépôt actif le 2026-10-01)"
|
||||
},
|
||||
{
|
||||
"nom": "Xournal++",
|
||||
"url": "https://xournalpp.github.io/",
|
||||
"desc": "Annoter un plan ou un PDF au stylet sur tablette ou écran tactile : markup de visite, retours sur un plan d'exécution.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-2.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-09 (v1.3.8 du 2026-09-26)"
|
||||
},
|
||||
{
|
||||
"nom": "Jitsi Meet",
|
||||
"url": "https://jitsi.org/jitsi-meet/",
|
||||
"desc": "Visioconférence sans compte, avec partage d'écran, pour une réunion de chantier à distance ou un rendez-vous client ; instance publique gratuite ou auto-hébergeable.",
|
||||
"source": "aep",
|
||||
"licence": "Apache-2.0",
|
||||
"plateformes": [
|
||||
"Web",
|
||||
"Android",
|
||||
"iOS"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-09 (version stable du 2026-09-14)"
|
||||
},
|
||||
{
|
||||
"nom": "CryptPad",
|
||||
"url": "https://cryptpad.org/",
|
||||
"desc": "Documents, tableurs et tableaux partagés en ligne, chiffrés : co-éditer un CR ou un planning avec un client sans lui demander de créer un compte.",
|
||||
"source": "aep",
|
||||
"licence": "AGPL-3.0",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v2026.9.0 du 2026-10-07)"
|
||||
},
|
||||
{
|
||||
"nom": "Dolibarr",
|
||||
"url": "https://www.dolibarr.org/",
|
||||
"desc": "ERP léger auto-hébergeable : devis, factures, suivi des paiements pour une agence ou un freelance qui veut sortir du tableur.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-3.0",
|
||||
"plateformes": [
|
||||
"Web (auto-hébergé)"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-09 (v24.0.1 du 2026-09-07)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dessiner-modeliser",
|
||||
"titre": "Dessiner, modéliser, construire",
|
||||
"note": "La chaîne libre de la CAO au BIM, de l'illustration à la maquette. FreeCAD et Bonsai sont sérieux mais demandent plusieurs semaines de prise en main.",
|
||||
"liens": [
|
||||
{
|
||||
"nom": "FreeCAD",
|
||||
"url": "https://www.freecad.org/",
|
||||
"desc": "Modélisation paramétrique 3D avec atelier BIM, coupes et mise en plan : modéliser un projet et sortir des plans sans licence.",
|
||||
"source": "aep",
|
||||
"licence": "LGPL-2.1",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (v1.1.4 du 2026-09-28)"
|
||||
},
|
||||
{
|
||||
"nom": "Bonsai (ex BlenderBIM)",
|
||||
"url": "https://bonsaibim.org/",
|
||||
"desc": "Créer et lire des modèles IFC (OpenBIM) dans Blender : produire un modèle BIM échangeable avec un bureau d'études sans passer par Revit ou ArchiCAD.",
|
||||
"source": "aep",
|
||||
"licence": "LGPL-3.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (build alpha du 2026-10-07, dépôt IfcOpenShell)"
|
||||
},
|
||||
{
|
||||
"nom": "Blender",
|
||||
"url": "https://www.blender.org/",
|
||||
"desc": "Modélisation, rendu photoréaliste et animation pour illustrer un concours ou une esquisse ; socle de Bonsai.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-3.0-or-later",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026 (v5.2 en téléchargement le 2026-10-08)"
|
||||
},
|
||||
{
|
||||
"nom": "LibreCAD",
|
||||
"url": "https://librecad.org/",
|
||||
"desc": "Dessin 2D en DXF : reprendre un relevé, redessiner un plan de masse ou préparer un fichier pour la découpe, sans licence AutoCAD (pas de DWG natif).",
|
||||
"source": "aep",
|
||||
"licence": "GPL-2.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-05 (v2.2.1.5 du 2026-05-02, dépôt actif le 2026-10-07)"
|
||||
},
|
||||
{
|
||||
"nom": "Inkscape",
|
||||
"url": "https://inkscape.org/fr/",
|
||||
"desc": "Dessin vectoriel : mettre au propre un schéma de principe, un plan-masse ou une planche de concours, export SVG et PDF.",
|
||||
"source": "aep",
|
||||
"licence": "GPL",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (commits du 2026-10-08)"
|
||||
},
|
||||
{
|
||||
"nom": "GIMP",
|
||||
"url": "https://www.gimp.org/",
|
||||
"desc": "Retouche d'image : traiter des photos de visite, détourer, préparer des photomontages et des planches.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-3.0-or-later",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (actualités du 2026-10-01)"
|
||||
},
|
||||
{
|
||||
"nom": "WikiHouse Skylark",
|
||||
"url": "https://github.com/wikihouseproject/Skylark",
|
||||
"desc": "Système constructif open source en blocs isolants, plans de fabrication CNC publiés : référence pour étudier ou proposer une ossature bois partagée ; à faire valider par un ingénieur structure.",
|
||||
"source": "aep",
|
||||
"licence": "CC BY-SA 4.0",
|
||||
"plateformes": [
|
||||
"Web (dépôt de fichiers CAO)"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-10 (commit du 2026-10-08)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cartes-territoire",
|
||||
"titre": "Cartes, cadastre et territoire",
|
||||
"note": "Les données publiques utiles avant une étude de faisabilité : parcelle, urbanisme, risques, histoire du site.",
|
||||
"liens": [
|
||||
{
|
||||
"nom": "QGIS",
|
||||
"url": "https://qgis.org/",
|
||||
"desc": "Système d'information géographique complet : croiser cadastre, PLU, relief et servitudes sur un même plan-masse, export DXF.",
|
||||
"source": "aep",
|
||||
"licence": "GPL-2.0",
|
||||
"plateformes": [
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "2026-09 (v3.44.15 du 2026-09-25)"
|
||||
},
|
||||
{
|
||||
"nom": "Géoportail (cartes.gouv.fr)",
|
||||
"url": "https://cartes.gouv.fr/explorer-les-cartes/",
|
||||
"desc": "Fonds IGN, cadastre, orthophotos et relief : repérer une parcelle, mesurer, imprimer un extrait ; l'ancien géoportail.gouv.fr redirige ici.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Cadastre – données ouvertes",
|
||||
"url": "https://cadastre.data.gouv.fr/",
|
||||
"desc": "Plan cadastral vectoriel et fichiers par commune en téléchargement libre, à charger dans QGIS pour un plan de situation.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Géoportail de l'Urbanisme",
|
||||
"url": "https://www.geoportail-urbanisme.gouv.fr/",
|
||||
"desc": "PLU, PLUi, cartes communales et servitudes opposables : la source officielle pour vérifier la règle d'une parcelle avant de rédiger une étude.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Géorisques",
|
||||
"url": "https://www.georisques.gouv.fr/",
|
||||
"desc": "Inondation, argiles, radon, sismicité, sites pollués pour une adresse : le contrôle de base avant d'acheter ou de chiffrer un projet.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Remonter le temps (IGN)",
|
||||
"url": "https://remonterletemps.ign.fr/",
|
||||
"desc": "Cartes et photos aériennes anciennes d'un lieu : lire l'histoire d'un site, repérer d'anciennes constructions ou d'anciens usages.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "API Carto (IGN)",
|
||||
"url": "https://apicarto.ign.fr/api/doc/",
|
||||
"desc": "Interroger parcelles, zonage et servitudes par API : base technique pour automatiser un plan de situation.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Demandes de valeurs foncières",
|
||||
"url": "https://app.dvf.etalab.gouv.fr/",
|
||||
"desc": "Prix de vente des biens par commune ou parcelle : étayer une fourchette d'estimation ou un argumentaire de réhabilitation.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
},
|
||||
{
|
||||
"nom": "Cartofriches (Cerema)",
|
||||
"url": "https://cartofriches.cerema.fr/cartofriches/",
|
||||
"desc": "Recensement national des friches : repérer des sites à reconvertir pour une approche de réhabilitation ou de renaturation.",
|
||||
"source": "aep",
|
||||
"licence": "Service public, gratuit",
|
||||
"plateformes": [
|
||||
"Web"
|
||||
],
|
||||
"verifie_le": "2026-10-08",
|
||||
"derniere_activite": "service public en ligne, ouvert le 2026-10-08"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"recommandes": [
|
||||
{
|
||||
"id": "dictee-universelle-groq",
|
||||
|
||||
@@ -117,6 +117,46 @@ verifie(
|
||||
verifie(Array.isArray(outils.open_source?.rubriques) && outils.open_source.rubriques.every((r) => r.liens?.length > 0), 'open_source.rubriques : une rubrique vide doit disparaître')
|
||||
verifie(!!outils.contribution?.texte && !!outils.contribution?.lien && !!outils.contribution?.cta, 'contribution incomplète')
|
||||
|
||||
// ── Open source : sélection (B6-M4) ───────────────────────────
|
||||
// Chaque lien de la sélection est vérifié par une personne (licence, date) ; la liste noire
|
||||
// piraterie s'applique déjà à toute chaîne d'outils.json (voir plus haut), sélection comprise.
|
||||
const sel = outils.open_source?.selection
|
||||
verifie(!!sel && typeof sel.intention === 'string' && sel.intention, 'open_source.selection : intention manquante')
|
||||
verifie(Array.isArray(sel?.rubriques) && sel.rubriques.length >= 1, 'open_source.selection : au moins une rubrique attendue')
|
||||
const idsRub = new Set()
|
||||
for (const r of sel?.rubriques ?? []) {
|
||||
const rub = `sélection « ${r.id ?? r.titre ?? '?'} »`
|
||||
verifie(typeof r.id === 'string' && r.id && !idsRub.has(r.id), `${rub} : id manquant ou en double`)
|
||||
idsRub.add(r.id)
|
||||
verifie(typeof r.titre === 'string' && r.titre, `${rub} : titre manquant`)
|
||||
verifie(Array.isArray(r.liens) && r.liens.length > 0, `${rub} : rubrique vide`)
|
||||
for (const l of r.liens ?? []) {
|
||||
const nom = `${rub} › ${l.nom ?? '?'}`
|
||||
verifie(typeof l.nom === 'string' && l.nom, `${nom} : nom manquant`)
|
||||
verifie(typeof l.url === 'string' && l.url.startsWith('https://'), `${nom} : url https manquante (${l.url})`)
|
||||
verifie(typeof l.desc === 'string' && l.desc, `${nom} : desc manquante`)
|
||||
verifie(typeof l.licence === 'string' && l.licence, `${nom} : licence manquante`)
|
||||
verifie(DATE.test(l.verifie_le ?? ''), `${nom} : verifie_le « ${l.verifie_le} » n'est pas AAAA-MM-JJ`)
|
||||
const bas = (l.url ?? '').toLowerCase()
|
||||
const hit = LISTE_NOIRE.find((d) => bas.includes(d))
|
||||
verifie(!hit, `${nom} : domaine de la liste noire « ${hit} »`)
|
||||
}
|
||||
}
|
||||
|
||||
// Aucun doublon d'URL dans tout open_source (sélection + recommandés + rubriques fmhy), à la barre finale et à la casse près.
|
||||
const norm = (u) => u.toLowerCase().replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/+$/, '')
|
||||
const vues = new Map()
|
||||
const urlsOS = [
|
||||
...(sel?.rubriques ?? []).flatMap((r) => (r.liens ?? []).map((l) => [`sélection › ${l.nom}`, l.url])),
|
||||
...(outils.open_source?.recommandes ?? []).filter((o) => o.url).map((o) => [`recommandé › ${o.titre}`, o.url]),
|
||||
...(outils.open_source?.rubriques ?? []).flatMap((r) => (r.liens ?? []).map((l) => [`fmhy › ${l.nom}`, l.url])),
|
||||
]
|
||||
for (const [qui, url] of urlsOS) {
|
||||
const k = norm(url)
|
||||
verifie(!vues.has(k), `open_source : URL en double « ${url} » (${vues.get(k)} et ${qui})`)
|
||||
vues.set(k, qui)
|
||||
}
|
||||
|
||||
if (echecs.length) {
|
||||
for (const e of echecs) console.log(`FAIL ${e}`)
|
||||
console.log(`\n${n - echecs.length}/${n} vérifications OK — ${echecs.length} échec(s)`)
|
||||
|
||||
Reference in New Issue
Block a user