diff --git a/TODO-SEO.md b/TODO-SEO.md index 878b8f1..9a30412 100644 --- a/TODO-SEO.md +++ b/TODO-SEO.md @@ -35,7 +35,9 @@ - [x] **Google Search Console** — soumettre `https://myinfomate.be/sitemap.xml`, vérifier qu'il n'y a pas d'erreurs d'indexation - [x] **Bing Webmaster Tools** — même chose (souvent oublié, représente ~10% du trafic desktop) - [ ] **Lighthouse audit** — ouvrir Chrome DevTools sur myinfomate.be, onglet Lighthouse, mode Mobile → viser > 90. Les points rouges qui sortent sont à corriger en priorité. -- [ ] **LinkedIn entreprise Unov** — si pas encore actif, créer la page et pointer vers myinfomate.be. Google valorise les signaux sociaux B2B. +- [x] **LinkedIn** — page Unov existante + vitrine MyInfoMate créée le 2026-09-10 (`linkedin.com/showcase/myinfomate/`), les deux dans le schema du site. Posts : `DOCS/linkedin-posts-lancement.md` + +> Plan complet et suivi depuis le 2026-09-09 : **[audit-seo-geo.md](audit-seo-geo.md)** (§0 pour l'avancement). ### Contenu long-tail (impact élevé, effort éditorial) diff --git a/audit-seo-geo.md b/audit-seo-geo.md new file mode 100644 index 0000000..cdde39d --- /dev/null +++ b/audit-seo-geo.md @@ -0,0 +1,335 @@ +# Audit SEO / GEO — myinfomate-landing + +> Audit en lecture seule du repo `myinfomate-landing`, réalisé le 2026-09-09. +> Périmètre : code source uniquement. Aucun test réseau sur `https://myinfomate.be` n'a été fait — +> tout ce qui n'est pas dérivable du code est marqué **non vérifiable depuis le code**. + +--- + +## 0. Suivi d'avancement + +> Mis à jour le 2026-09-10. Les numéros renvoient au plan d'action du §6. + +| # | Action | État | +|---|---|---| +| 1 | Hiérarchie `h2`/`h3` | ✅ 2026-09-10 — libellé décoratif en `

`, titre de section en `h2`, cartes en `h3` (home + segments) | +| 2 | Schema `Organization` | ✅ 2026-09-10 — adresse, `vatID`, `taxID`, `areaServed`, `sameAs` LinkedIn Unov ; `url` passé à `https://unov.be` | +| 3 | 9 panneaux `ModulesSection` dans le DOM | ✅ 2026-09-10 — vérifié dans le HTML servi | +| 4 | Offres Essentiel/Pro/Premium + `AggregateOffer` | ✅ 2026-09-10 — `src/data/structured-data.ts`, HTVA (`valueAddedTaxIncluded: false`) | +| 5 | Liens morts `href="#"` | ✅ 2026-09-10 — logo et ACCUEIL → `/{lang}`, globe du footer → unov.be (home **et** segments, le 2ᵉ n'était pas relevé par l'audit) | +| M4 | TVA écrite dans les mentions légales | ✅ 2026-09-10 | +| M7 | Profils sociaux | ✅ 2026-09-10 — vitrine LinkedIn MyInfoMate créée, dans `sameAs` du `SoftwareApplication` ; fiche produit LinkedIn soumise pour évaluation | +| 6 | `llms.txt` FR + prix + `robots.txt` | ✅ 2026-09-10 — `llms.txt` en français (vocabulaire acheteur, grille complète, TVA), anglais déplacé dans `llms-en.txt`, les deux cités dans `robots.txt` | +| 7 | Prérendu statique | ✅ 2026-09-10 — `` dans `[lang]/layout.tsx` (layout racine par langue), pages légales dans le groupe `(legal)` avec leur propre layout, plus de `headers()` ni de `x-pathname`. **58 pages prérendues**, servies en `x-nextjs-cache: HIT` | +| 8 | `/{lang}/tarifs` | ✅ 2026-09-10 — grille + 7 FAQ tarifaires ×4 langues, `FAQPage` + offres ; lien « Tarifs » du menu (home et segments) pointe dessus ; grille extraite dans `components/PricingPlans.tsx` (était copiée deux fois) | +| 9 | `/{lang}/assistant-ia` | ✅ 2026-09-10 — **4 langues** (736 à 846 mots), 6 FAQ + `FAQPage` par langue, `hreflang` complet, liée depuis la section IA de la home et dans le sitemap. Section « Ce qu'il ne fait pas » assumée : dire les limites plutôt que survendre l'IA | +| — | Liens légaux du footer | ✅ 2026-09-10 — passés en `` (home, segments, signup) : **le lint du repo est à 0 erreur**, il en comptait 15 | +| — | Page CGU | ✅ 2026-09-10 — `/conditions-generales` publiée (~4 000 mots) : la case de consentement de `/signup` faisait accepter des CGU **introuvables**. Liée depuis les pieds de page et le sitemap. ⚠️ validation juridique toujours due | +| M4 | Frais de mise en place | ✅ 2026-09-10 — **décision de Thomas : pas de montant affiché.** À la place, dans les 4 langues : « frais de mise en place **uniques, chiffrés dans le devis** », et la FAQ de `/tarifs` dit ce qu'ils couvrent et qu'ils précèdent la signature (voir carte kanban 180) | +| 12 | Vocabulaire acheteur dans les 6 segments | 🟠 2026-09-10 — **français fait**. Nouvelles FAQ par segment : RGPD (les 6), marchés publics (5 — pas hôtels, secteur privé), accessibilité/Access-i (3). « Médiation numérique », « parcours de visite » et « cartel numérique » injectés dans les intros. **NL/EN/DE pas encore traduits** : les FAQ françaises sont plus fournies que les autres langues | +| 14 | Page marchés publics | 🟠 partiellement couvert par la FAQ des segments ; page dédiée toujours à faire | +| 10 | FAQ sur la homepage | ✅ 2026-09-10 — 8 questions ×4 langues + `FAQPage` (produit, prix, canaux, hors ligne, marque blanche, délai, hébergement des données). C'était la page qu'un LLM atteint en premier, et elle n'avait aucune FAQ | +| 13 | `BreadcrumbList` | ✅ 2026-09-10 — sur segments, cas clients (liste et détail), tarifs et assistant IA ; helper `breadcrumbSchema()` dans `structured-data.ts` | +| 21 | Dates du sitemap | ✅ 2026-09-10 — `lastModified: new Date()` (date du build sur les 55 URLs) remplacé par des dates réelles par famille de pages, constante `LAST_MODIFIED` en tête de `sitemap.ts` **à mettre à jour avec le contenu** | +| 12 bis | Traduction des FAQ segments | ✅ 2026-09-10 — **42 items** ajoutés en EN/NL/DE. Parité atteinte : 10 / 10 / 8 / 7 / 8 / 9 FAQ par segment dans les 4 langues | +| 16 | Images | ✅ 2026-09-10 — recompressées (palette PNG, `effort: 10`) : `app-screenshot-1` 731 → **232 Ko**, `app-screenshot-2` 547 → **185 Ko**, `myinfomate-logo` 240 → **57 Ko**. Qualité vérifiée à l'œil. `map_generated` déjà optimale. **1,1 Mo économisé.** `sharp` a servi en installation temporaire, il n'est **pas** ajouté aux dépendances | +| — | `google-maps-route.png` (699 Ko) | ⚠️ **référencé nulle part dans `src/`** — supprimable, mais je n'y touche pas sans ton accord | +| — | Captures d'écran de l'app | ✅ 2026-09-10 — remplacées par les **vraies captures de la V3** fournies par Thomas (app du Fort de Saint-Héribert) : accueil sombre en grille bento et fiche article dans les deux téléphones du hero, liste des sections dans le mockup « white label », où un cadre vide affichait une icône de palette. Anciennes captures `.png` supprimées, nouvelles en JPEG (129 / 121 / 107 Ko). **Textes alternatifs réécrits et localisés** dans les 4 langues — ils étaient en anglais et décrivaient l'ancienne interface | +| 14 | `/{lang}/marches-publics` | ✅ 2026-09-10 — 4 langues, 5 FAQ. Argument central : **Visit Namur, attribué sur cahier des charges publié**. Dit franchement l'absence de certification Access-i et d'audit, et renvoie au service marchés pour les seuils plutôt que de citer un chiffre non vérifié | +| 17 | `/{lang}/borne-kiosk` et `/{lang}/visite-hors-ligne` | ✅ 2026-09-10 — 4 langues, 4 FAQ chacune, adossées à Visit Namur et au Fort de Saint-Héribert. Gabarit partagé `components/ContentPage.tsx` | +| — | Optimisation d'images en prod | ✅ 2026-09-10 — **`sharp` ajouté aux dépendances, après mesure** : sans lui, `/_next/image` renvoyait le JPEG source (64 Ko) ; avec lui, du **WebP de 26 Ko**. ⚠️ à confirmer au premier build Docker (binaires `linuxmusl`) | +| — | Maillage interne vers les 5 pages produit | ✅ 2026-09-10 — colonne « Solutions » dans le pied de page de la **home et des pages segment** (3 colonnes vides récupérées), plus des liens **dans le contenu**, qui valent davantage : carte « Mode Kiosk » → `/borne-kiosk`, point « Contenu hors ligne » → `/visite-hors-ligne`, bandeau acheteur public sous la grille de `/tarifs` → `/marches-publics`. Compté sur les pages servies : chaque page produit reçoit 1 à 3 liens par page. **Sitemap : 67 URLs** | +| 15 | Pages légales en 4 langues | ✅ 2026-09-10 — mentions légales et confidentialité **traduites**, CGU laissées en français avec un **avis traduit** (« la version française fait foi ») et le corps marqué `lang="fr"` : traduire un contrat qu'un juriste va corriger, c'est du travail à refaire. Les 3 pages vivent sous `/{lang}/…`, les anciennes URLs redirigent vers la langue du visiteur | +| 18 | Pages comparatives | ✅ 2026-09-10 — `/fr/comparatif/myinfomate-vs-smartify` et `…-vs-stqry`, **prix relevés à la source le 10/09** (Smartify : 1 800 / 3 500 / 9 500 £ par an ; STQRY : 199 $/mois, +100 $ Pro, 2 000 $ de frais uniques d'app native), sources liées et datées. Chaque page dit **ce que le concurrent fait mieux**. ⚠️ Guideius et izi.TRAVEL écartés : le premier ne publie aucun prix, le second a un modèle gratuit non comparable | +| 20 | Blog `/fr/ressources` | ✅ 2026-09-10 — index + 2 articles (audioguide vs application, borne vs BYOD), schema `BlogPosting`. **Français seulement** ; les autres langues répondent 404, c'est volontaire | +| 11 | Témoignages clients | ⏸️ **écarté le 2026-09-10 par Thomas** — il ne souhaite pas solliciter les clients pour l'instant, même satisfaits. Le type `CasClient` reste sans champ témoignage : à rouvrir le jour où un client en propose un spontanément | +| 19 | Pages XR | ⬜ **deux pages à prévoir, pas une** : `/lunettes-connectees` et `/casque-vr`. À écrire quand chaque module sera démontrable — cf. `DOCS/v2/vr-quest-unity-plan.md` et `DOCS/rayban-meta-integration.md` | + +Tout est **stagé, pas encore committé** au 2026-09-10 (en attente de validation). + +Point connu : une URL inexistante (`/fr/xyz`) répond bien **404 + `noindex`**, mais son HTML initial est le shell d'erreur de Next ; la page 404 (`[lang]/not-found.tsx`) s'affiche après hydratation. Effet de l'absence de layout racine commun ; le corriger demanderait `experimental.globalNotFound`. Sans impact SEO. +Posts LinkedIn de lancement : `DOCS/linkedin-posts-lancement.md`. + +--- + +## 1. Verdict en 5 lignes + +1. **Oui, partiellement citable.** Le contenu textuel principal est rendu côté serveur (composants serveur + client components pré-rendus par Next), les prix sont en texte brut, `llms.txt` existe et est bon, et aucun crawler IA n'est bloqué. Un LLM interrogé sur « audioguide pour musée en Belgique » a de la matière. +2. **Mais le site n'est trouvable que sur des requêtes produit, pas sur les requêtes d'acheteur.** Les 6 pages segment sont bien construites (~1 130 mots FR + 6 FAQ chacune), mais il n'existe **aucune** page `/tarifs`, `/assistant-ia`, `/borne-kiosk`, `/visite-offline`, ni page lunettes connectées : le différenciateur IA n'a pas d'URL propre. +3. **Le vocabulaire de l'acheteur public belge est absent** : zéro occurrence de « médiation numérique », « scénographie », « cartel numérique », « accessibilité », « Access-i », « marché public », « RGPD » dans les ~5 700 lignes de contenu de `src/data/`. +4. **Deux fuites de contenu réelles** : 8 des 9 descriptions de modules de la homepage ne sont pas dans le HTML (`ModulesSection.tsx:135`), et aucune page n'est pré-rendue statiquement (`layout.tsx:36` force le SSR sur tout l'arbre). +5. **Les preuves clients sont là mais désincarnées** : 3 cas clients datés et nommés, mais aucun logo, aucun témoignage attribué, aucun lien sortant vers un site client ou une fiche store — c'est ce qui manque le plus à un dossier de marché public. + +--- + +## 2. Inventaire factuel + +### Framework et mode de rendu + +| Élément | Valeur | Source | +|---|---|---| +| Framework | Next.js **16.1.6**, React 19.2.3, App Router | `package.json:12-13` | +| CSS | Tailwind v4 (`@tailwindcss/postcss`) | `package.json:22` | +| Build | `output: "standalone"`, React Compiler activé | `next.config.ts:5-6` | +| Déploiement | Docker `node:22-alpine`, `node server.js` derrière Traefik | `Dockerfile:8-18`, `README.md` | +| Routing i18n | Middleware Next 16 (`src/proxy.ts`) → redirect vers `/{locale}` selon `Accept-Language` | `src/proxy.ts:28-32` | +| Locales | `fr`, `en`, `nl`, `de` — `fr` par défaut, html lang `fr-BE` / `nl-BE` | `src/i18n.ts:1-17` | +| **Mode de rendu effectif** | **SSR dynamique sur 100 % des pages de contenu — 0 page prérendue** | voir ci-dessous | + +**Le contenu texte est bien dans le HTML servi** — ce n'est pas une SPA client-only, donc le point critique redouté n'est pas présent. Deux composants seulement sont des client components porteurs de contenu (`SegmentPageClient.tsx:1`, `ModulesSection.tsx:1`) ; Next les rend quand même dans le HTML initial, donc leur texte est extractible **à l'exception de ce qui est conditionné par un `useState`** (voir bloquant B2). + +**En revanche, la génération statique ne fonctionne pas.** Le `prerender-manifest.json` du dernier build présent dans `.next/` (daté du 13/08) ne contient que trois routes prérendues : + +``` +PRERENDERED: ['/_global-error', '/icon.png', '/sitemap.xml'] +DYNAMIC: [] +``` + +Cause : `src/app/layout.tsx:36-37` appelle `await headers()` pour lire `x-pathname`. Cet accès aux headers de requête opte **tout l'arbre de routes** hors du rendu statique. Résultat : les `generateStaticParams()` déclarés dans `[lang]/page.tsx:27`, `[lang]/[segment]/page.tsx:9` et `[lang]/signup/page.tsx:25` ne produisent aucun HTML statique — chaque visite, y compris chaque crawl, déclenche un rendu React complet. + +### Routes trouvées + +| Route | Fichier | Titre (FR) | H1 | Contenu | +|---|---|---|---|---| +| `/{lang}` | `src/app/[lang]/page.tsx` | *MyInfoMate — Application guide visiteur pour musées & lieux* | `MyInfoMate - La solution facile pour créer, gérer et diffuser du contenu interactif` (`HomeClient.tsx:29-31`) | ~1 990 mots FR | +| `/{lang}/musees` | `[segment]/page.tsx` | *Application Guide de Visite pour Musées \| MyInfoMate* | `Votre musée mérite une application à la hauteur de vos collections` | ~1 134 mots FR, 6 FAQ | +| `/{lang}/offices-tourisme` | idem | même structure, meta propre | H1 hero segment | ~1 100 mots, 6 FAQ | +| `/{lang}/parcs-naturels` | idem | | | ~1 100 mots, 6 FAQ | +| `/{lang}/hotels-loisirs` | idem | | | ~1 100 mots, 6 FAQ | +| `/{lang}/evenements` | idem | | | ~1 100 mots, 6 FAQ | +| `/{lang}/education-culture` | idem | | | ~1 100 mots, 6 FAQ | +| `/{lang}/cas-clients` | `cas-clients/page.tsx` | listing | oui | court | +| `/{lang}/cas-clients/musee-de-la-fraise` | `cas-clients/[slug]/page.tsx` | *Musée de la Fraise — Premier client MyInfoMate \| Kiosk & App Mobile* | `De la vitrine au numérique : la naissance de MyInfoMate` (`:101`) | ~400 mots | +| `/{lang}/cas-clients/fort-de-saint-heribert` | idem | | | ~400 mots | +| `/{lang}/cas-clients/visit-namur` | idem | | | ~400 mots | +| `/{lang}/signup` | `signup/page.tsx` | *Créer mon compte — Plan Essentiel* | — | **`robots: {index:false}`** (`:41`) — correct | +| `/mentions-legales` | `app/mentions-legales/page.tsx` | *Mentions légales* | `Mentions légales` (`:18`) | FR uniquement, hors `[lang]` | +| `/confidentialite` | `app/confidentialite/page.tsx` | *Politique de confidentialité* | `Politique de confidentialité` (`:18`) | FR uniquement, hors `[lang]` | + +**Total indexable : 11 URLs × 4 langues + 2 pages légales = 46 URLs.** Cohérent avec `src/app/sitemap.ts`, qui génère exactement ces entrées avec `alternates.languages` par entrée (`sitemap.ts:8-15`). + +### Fondations techniques — état + +| Point | État | Détail | +|---|---|---| +| `robots.txt` | ✅ présent | `public/robots.txt` — `User-agent: *` / `Allow: /` / `Disallow: /api/` | +| Blocage crawlers IA | ✅ **aucun bloqué** | GPTBot, ClaudeBot, anthropic-ai, PerplexityBot, Google-Extended, CCBot, Bingbot sont **tous autorisés** par le `User-agent: *`. Aucune règle nominative, ni Allow ni Disallow (`robots.txt:1-3`) | +| `sitemap.xml` | ✅ généré + référencé | `src/app/sitemap.ts`, référencé `robots.txt:5` | +| `llms.txt` | ✅ présent et de bonne qualité | `public/llms.txt`, 85 lignes — produit, features, modes de déploiement, assistant IA, clients, pricing, société | +| Canonical | ✅ sur toutes les pages | `[lang]/page.tsx:60`, `[segment]/page.tsx:48`, `cas-clients/[slug]`, légales `:7` | +| hreflang | ✅ complet + `x-default` | `layout.tsx:68-71`, `[lang]/page.tsx:59-62`, et aussi dans `sitemap.ts:13` | +| Open Graph | ✅ | `layout.tsx:53-62` + per-page ; **OG image dynamique** `[lang]/opengraph-image.tsx` (edge runtime, 1200×630, locale-aware) et variante par segment | +| Twitter Card | ✅ `summary_large_image` | `layout.tsx:63-67` | +| Données structurées | ✅ **JSON-LD** (pas microdata) | Organization + WebSite + SoftwareApplication (home) ; FAQPage + SoftwareApplication (segments) ; Article (cas clients) | +| BreadcrumbList | ❌ absent | aucune occurrence dans le repo | +| Images | ⚠️ | `next/image` partout (donc WebP/AVIF à la volée), `priority` sur le hero (`HomeClient.tsx:53`), `alt` renseignés. Mais les sources sont des PNG lourds : `app-screenshot-1.png` 748 Ko, `google-maps-route.png` 715 Ko, `app-screenshot-2.png` 560 Ko, `myinfomate-logo.png` 246 Ko | +| Temps de chargement réel | **non vérifiable depuis le code** — le Lighthouse est d'ailleurs encore coché « à faire » dans `TODO-SEO.md:39` | + +--- + +## 3. Bloquants critiques + +### B1 — Aucune page n'est prérendue : tout est SSR à chaque requête + +**Fichier : `src/app/layout.tsx:36-37`** + +```ts +const h = await headers(); +const pathname = h.get("x-pathname") ?? "/"; +``` + +Cet appel dans le layout racine force le rendu dynamique de l'intégralité de l'application. `prerender-manifest.json` le confirme : trois routes prérendues, aucune page de contenu. Les `generateStaticParams()` déclarés dans trois fichiers sont inertes. + +*Conséquence* : pas de blocage d'indexation (le HTML est bien complet dans la réponse), mais un TTFB dépendant du serveur à chaque crawl, et la perte de toute mise en cache statique/CDN. Sur un VPS unique derrière Traefik (`README.md`), c'est le premier facteur de lenteur. + +*Correctif* : le layout racine n'a besoin de la locale que pour `` et des métadonnées de repli — or elle est déjà disponible via le segment `[lang]`. Déplacer `resolveLocale()` + `generateMetadata` vers un `src/app/[lang]/layout.tsx` (à créer) recevant `params.lang`, et laisser le layout racine muet. `[lang]/page.tsx:31` et `[segment]/page.tsx:16` définissent déjà leurs métadonnées complètes, donc le layout racine est en grande partie redondant. + +### B2 — 8 des 9 descriptions de modules de la homepage sont absentes du HTML + +**Fichier : `src/components/ModulesSection.tsx:20, 73, 125, 135`** + +```tsx +const [activeModule, setActiveModule] = useState(0); +... +

{modules[activeModule].title}

+

{modules[activeModule].description}

+``` + +Seul le module d'index 0 (Carte interactive) voit sa `description` et sa `value` rendues. Les huit autres — Quiz/jeux, Vidéo, Article, Agenda, **Offline**, Web, Statistiques, **Escape game** — n'existent dans le HTML que sous forme de libellé de bouton (`ModulesSection.tsx:59`). Or « mode offline » et « escape game » sont deux des arguments les plus différenciants : ils figurent dans `llms.txt:26,29` mais pas dans le HTML de la homepage. + +*Correctif* : rendre les neuf panneaux et masquer les inactifs en CSS (`hidden` / `aria-hidden`), exactement comme le fait déjà correctement la FAQ des pages segment (`SegmentPageClient.tsx:652` — collapse par `max-h-0`, contenu toujours présent dans le DOM). + +### B3 — Aucun schema `Offer` pour les plans Pro / Premium / Enterprise + +**Fichiers : `src/app/[lang]/page.tsx:100-110` et `[segment]/page.tsx:84-94`** + +Le `SoftwareApplication` ne déclare qu'une seule offre, à 39 €. Les prix 99 € et 179 € sont bien en texte brut dans le HTML (`SegmentPageClient.tsx:460` et suivantes) — donc lisibles par un LLM — mais invisibles pour Google Rich Results et pour tout agent qui s'appuie sur les données structurées. À la question « combien coûte MyInfoMate pour avoir l'assistant IA ? », un LLM devra deviner. + +*Correctif* : remplacer `offers` par un tableau de trois à quatre `Offer` (`name: "Essentiel" / "Pro" / "Premium"`, `price`, `priceCurrency: "EUR"`, périodicité), plus un `AggregateOffer` avec `lowPrice: 39` / `highPrice: 179`. + +--- + +## 4. Manques importants (existe mais mal fait) + +### M1 — Hiérarchie de titres inversée sur toutes les pages + +Le label décoratif en petites capitales est un `

`, et le vrai titre de section un `

`. Vérifiable partout : + +- `HomeClient.tsx:78-79` — `

{t.strategic.sectionLabel}

` puis `

{t.strategic.sectionTitle}

` +- `HomeClient.tsx:126-127`, `:181-182`, `:301-302`, `:421-422`, `:474-475` +- `SegmentPageClient.tsx:310-311`, `:333-334`, `:363-364`, `:398-399`, `:636-637` +- `ModulesSection.tsx:34-35` + +Un extracteur de plan de page lit donc « LE DÉFI DES MUSÉES » comme titre de niveau 2 et « Ce que vivent la plupart des musées » comme sous-titre : l'inverse exact. Correctif purement cosmétique — inverser les balises, garder les classes. + +### M2 — Le schema `Organization` n'ancre pas l'entreprise en Belgique + +**`src/app/[lang]/page.tsx:70-81`** ne contient que `name`, `url`, `logo`, `contactPoint`. Manquent `address` (PostalAddress : Rue René Copette 3, 5020 Namur, BE), `areaServed` (BE / FR / LU), `vatID` ou `taxID` (BCE 0776.895.467), et `sameAs` (aucun profil externe déclaré). Toutes ces données existent pourtant en clair dans `mentions-legales/page.tsx:24-28`. C'est le signal le plus direct qu'un LLM utilise pour répondre à « une solution **belge** ». + +### M3 — Les mentions légales sont hors du système i18n + +`src/app/mentions-legales/page.tsx` et `src/app/confidentialite/page.tsx` vivent hors de `[lang]`, sont explicitement exclues du middleware (`proxy.ts:5`), n'existent qu'en français et n'ont pas de `hreflang`. Un acheteur néerlandophone ou luxembourgeois qui vérifie la conformité de l'éditeur tombe sur du français. Le sitemap ne les référence qu'en une seule version (`sitemap.ts:66-77`). + +### M4 — TVA jamais écrite, RGPD jamais mis en avant côté commercial + +`mentions-legales/page.tsx:25` donne « Numéro d'entreprise BCE : 0776.895.467 » mais jamais le format TVA `BE 0776.895.467` — c'est pourtant la chaîne que cherche le service comptable d'une commune. Par ailleurs « RGPD » n'apparaît **que** dans `confidentialite/page.tsx` : `grep -ric "RGPD" src/data/*.ts` retourne 0. Le seul argument d'hébergement européen est une ligne de la page signup (`translations.ts:207`, « Hébergé en Europe ») — sur une page en `noindex`. + +### M5 — Cas clients : aucune preuve vérifiable de l'extérieur + +`src/data/cas-clients.ts` donne pour chaque client `client`, `year`, `location` (`:49-52`, `:223-225`, `:397-399`), mais l'interface `CasClient` (`:36-42`) ne prévoit **ni URL du site client, ni lien vers une fiche store, ni témoignage, ni logo**. + +- Aucun témoignage nommé : zéro occurrence de `quote` / `testimonial` / `author` dans le fichier. +- Aucun logo client : `public/` ne contient que le logo MyInfoMate et quatre screenshots génériques. +- Aucun lien sortant : pas un seul `href="http"` dans `cas-clients/[slug]/page.tsx`. +- Les « résultats » sont qualitatifs — `{value:'2021', label:'Premier déploiement'}`, `{value:'100%', label:'Autonomie éditoriale'}` (`cas-clients.ts:97-100`) : aucun chiffre de fréquentation, de nombre de POI, de langues ou de sessions. +- Le schema `Article` (`cas-clients/[slug]/page.tsx:56-65`) n'a ni `image`, ni `dateModified`, ni `about`/`mentions` pointant vers le lieu. + +Les chiffres concrets présents ailleurs restent maigres : `llms.txt:64-68` mentionne iBeacon, offline 100 %, iOS + Android — c'est le contenu le plus factuel du site, et il n'est pas dans le HTML. + +### M6 — Aucune date de mise à jour visible + +`sitemap.ts:18` fixe `lastModified: new Date()`, c'est-à-dire la date du build, appliquée uniformément à toutes les URLs : ce n'est pas un signal de fraîcheur, c'est du bruit. Aucune page n'affiche de date dans son HTML ; les cas clients affichent l'année du projet (`cas-clients/[slug]/page.tsx:99`), pas la date de rédaction. + +### M7 — Deux liens morts et aucun profil social + +- `HomeClient.tsx:766` : `` avec une icône « public » dans le footer — bouton social qui ne pointe nulle part. +- `NavBar.tsx:59` et `:149` : logo et « ACCUEIL » en `href="#"` (scroll JS) au lieu de `href={/${lang}}`. Un crawler n'a pas de lien de retour vers la home depuis le header. +- Aucun `sameAs` LinkedIn — la création de la page LinkedIn Unov est d'ailleurs encore ouverte dans `TODO-SEO.md:40`. + +### M8 — Images sources non optimisées + +748 Ko, 715 Ko et 560 Ko en PNG pour des screenshots d'app. `next/image` réencode, mais l'optimiseur travaille sur ces sources à chaque cache miss. `myinfomate-logo.png` (246 Ko) sert à la fois de favicon (`layout.tsx:52`), d'image OG de repli (`layout.tsx:61`) et d'image 32 px dans le footer (`HomeClient.tsx:755-760`). Le paquet `sharp` n'est pas dans `package.json` ; le comportement réel de l'optimiseur dans le conteneur `node:22-alpine` est **non vérifiable depuis le code**. + +--- + +## 5. Opportunités (n'existe pas et devrait exister) + +### O1 — Pages par intention manquantes + +Aucune de ces routes n'existe dans `src/app/` : + +| URL attendue | État | Commentaire | +|---|---|---| +| `/tarifs` | ❌ | Les prix ne vivent que dans des sections `#pricing` de la home et des six pages segment. Une requête « prix audioguide musée » n'a aucune page à faire remonter. Le contenu existe déjà (`SegmentPageClient.tsx:395-628`) — il suffit de l'extraire dans une route. | +| `/assistant-ia` | ❌ | **Le différenciateur n'a pas de page.** Il est une section de la home (`HomeClient.tsx:170-260`) et un paragraphe de `llms.txt:42-49`. Face à Guideius ou izi.TRAVEL, c'est l'argument qui n'existe nulle part ailleurs — et il n'est pas adressable. | +| `/borne-kiosk` | ❌ | Le kiosk n'est qu'un mode de déploiement dans `#deployment-modes` (`translations.ts:53`) ; le cas Visit Namur porte entièrement dessus. Mérite une page. | +| `/visite-offline-sans-reseau` | ❌ | Le mode offline est un module (`ModulesSection.tsx:12`) dont la description **n'est même pas dans le HTML** (bloquant B2). Le cas Fort de Saint-Héribert est un argument offline parfait (iBeacon, aucune couverture réseau). | +| `/musee-plein-air` | ❌ | Partiellement couvert par `/parcs-naturels`. | +| `/lunettes-connectees` | ❌ | Une seule occurrence dans tout le contenu : `translations.ts:60`, « Meta Quest et lunettes connectées », dans un bloc « à venir ». Pas de page, pas de schema. | +| `/application-office-de-tourisme` | ✅ équivalent | `/{lang}/offices-tourisme` existe et est complet. | + +### O2 — Vocabulaire de l'acheteur culturel : absent + +`grep -ric` sur `src/data/translations.ts`, `segments.ts`, `cas-clients.ts` : + +| Terme | Occurrences | +|---|---| +| « médiation numérique » | **0** | +| « scénographie » | **0** | +| « cartel numérique » | **0** | +| « accessibilité » | **0** | +| « Access-i » | **0** | +| « marché public » | **0** | +| « RGPD » | **0** (hors page confidentialité) | +| « réalité augmentée » | **0** | +| « BYOD » | 8 (bon) | +| « audioguide » / « audio guide » | 24 / 30 (bon) | +| « Namur » | 34 (bon, surtout via les cas clients) | +| « Wallonie » | 2 | +| « Belgique » | 3 (uniquement dans `cas-clients.ts`) | + +Le site parle la langue du produit, pas celle du conservateur ni celle du service marchés publics. « Médiation numérique » est le terme employé par les appels à projets de la Fédération Wallonie-Bruxelles : ne pas l'avoir écrit une seule fois est une occasion manquée gratuite. + +### O3 — Aucune page marchés publics + +Rien dans le repo sur les seuils, la procédure de marché de faible montant, la capacité à répondre à un cahier des charges, ni de document type. C'est pourtant l'objection numéro un d'une commune ou d'une province. + +### O4 — Aucune page comparative + +`src/app/` ne contient aucune route `comparatif`. Le comparatif existe **à l'intérieur** des pages segment (`Segment.comparison`, `segments.ts:23-26`) mais compare des catégories abstraites (« App visiteur générique », « Fiches pédagogiques papier »). Les seuls concurrents nommés le sont dans les meta descriptions (« Alternative à Smartify », `segments.ts:81`) et dans un pain point (`segments.ts:~120` : « Smartify, SmartGuide ou STQRY coûtent entre €100 et €925/mois »). **Aucune mention de Guideius, izi.TRAVEL, MySmartJourney, Musa Guide, Cirkwi ou Apptree** dans tout le repo — alors que ce sont les noms réellement tapés par un acheteur belge ou français. + +Ce n'est pas une erreur, c'est le levier GEO le plus rentable qui reste : les pages « alternative à X » sont exactement ce qu'un LLM ingère pour répondre à une question de comparaison. `TODO-SEO.md:56-59` les liste déjà comme à faire. + +### O5 — Aucun blog + +`src/app/` ne contient aucune route `blog`, `ressources` ou `articles`. `TODO-SEO.md:49-54` a déjà les cinq sujets d'articles identifiés ; aucun n'est écrit. Le seul contenu éditorial du site est du contenu produit — pas un texte ne répond à une question que se pose un responsable de musée avant d'avoir entendu parler de MyInfoMate. + +### O6 — `llms.txt` : bon fichier, trois angles morts + +`public/llms.txt` est de bonne facture (85 lignes, structuré, avec liens vers les trois cas clients). Ses faiblesses : + +- **Il est uniquement en anglais** (`llms.txt:3`) alors que le marché cible est francophone. Un LLM interrogé en français citera plus volontiers une source française. +- **Il n'est pas référencé dans `robots.txt`**, ni lié depuis le HTML. +- Les prix y sont incomplets (`llms.txt:74`, « Starting from €39/month ») alors que la grille 39 / 99 / 179 est publique sur le site. + +### O7 — Pas de FAQ sur la homepage + +Les six pages segment ont chacune six questions et un `FAQPage` JSON-LD (`[segment]/page.tsx:65-76`) — c'est très bien fait. La homepage n'a **aucune** FAQ ni `FAQPage`. C'est pourtant la page qu'un LLM atteint en premier. + +--- + +## 6. Plan d'action priorisé + +Trié par ratio impact / effort. **T** = correctif technique, **C** = écriture de contenu. + +| # | Action | Type | Impact | Effort | +|---|---|---|---|---| +| 1 | Inverser `h2`/`h3` sur les 12 sections concernées (`HomeClient.tsx:78,126,181,301,421,474` ; `SegmentPageClient.tsx:310,333,363,398,636` ; `ModulesSection.tsx:34`) | T | Moyen | **0,5 h** | +| 2 | Enrichir le schema `Organization` : `address`, `areaServed: ["BE","FR","LU"]`, `vatID: "BE0776895467"`, `sameAs` (`[lang]/page.tsx:70-81`) | T | **Fort** | **0,5 h** | +| 3 | Rendre les 9 panneaux de `ModulesSection` dans le DOM, masquer en CSS au lieu de `modules[activeModule]` (`ModulesSection.tsx:73,125`) — récupère « offline » et « escape game » dans le HTML | T | **Fort** | **1 h** | +| 4 | Passer `SoftwareApplication.offers` à un tableau de 3 `Offer` + `AggregateOffer` 39–179 € (`[lang]/page.tsx:100`, `[segment]/page.tsx:84`) | T | **Fort** | **1 h** | +| 5 | Corriger les liens morts : footer `href="#"` (`HomeClient.tsx:766`), logo et ACCUEIL de la NavBar (`NavBar.tsx:59,149`) → `/{lang}` | T | Moyen | **0,5 h** | +| 6 | Traduire `llms.txt` en français (ou publier FR + `llms-en.txt`), y ajouter la grille 39/99/179 et le référencer depuis `robots.txt` | C | **Fort** | **1,5 h** | +| 7 | Déplacer `resolveLocale()`/`generateMetadata` de `layout.tsx:36` vers un `[lang]/layout.tsx` → réactive le prérendu statique des 46 URLs | T | **Fort** | **2–3 h** | +| 8 | Créer `/{lang}/tarifs` en réutilisant la section pricing existante + une FAQ tarifaire | T+C | **Fort** | **3 h** | +| 9 | Créer `/{lang}/assistant-ia` — le différenciateur mérite son URL, avec FAQ et schema | C | **Fort** | **4 h** | +| 10 | Ajouter un `FAQPage` de 6–8 questions en bas de homepage (réutiliser le format de `segments.ts`) | C | Moyen | **3 h** | +| 11 | Ajouter au type `CasClient` : `clientUrl`, `storeUrls`, `testimonial {quote, name, role}` — et les remplir après accord des 3 clients | T+C | **Fort** | **4 h** + relance clients | +| 12 | Injecter le vocabulaire acheteur (« médiation numérique », « accessibilité », « scénographie », « parcours de visite », « RGPD », « hébergement européen ») dans `translations.ts` et les 6 segments FR | C | **Fort** | **4–6 h** | +| 13 | Ajouter `BreadcrumbList` sur les pages segment et cas clients | T | Faible | **1 h** | +| 14 | Créer `/{lang}/marches-publics` : seuils, marché de faible montant, capacité à répondre, coordonnées BCE/TVA | C | **Fort** (public belge) | **4 h** | +| 15 | Traduire `/mentions-legales` et `/confidentialite` en 4 langues et les faire passer sous `[lang]` (ajuster `proxy.ts:5`) | T+C | Moyen | **3 h** | +| 16 | Recompresser les 4 PNG de `public/` (748 / 715 / 560 / 246 Ko → cible < 150 Ko) et produire un logo 32 px distinct du logo OG | T | Moyen | **1 h** | +| 17 | Créer `/{lang}/borne-kiosk` et `/{lang}/visite-offline-sans-reseau`, adossées aux cas Visit Namur et Fort de Saint-Héribert | C | Moyen | **6 h** | +| 18 | Trois pages comparatives : `myinfomate-vs-izi-travel`, `myinfomate-vs-guideius`, `myinfomate-vs-smartify` — factuelles, sourcées, sans dénigrement | C | **Fort** (GEO) | **8 h** | +| 19 | Créer `/{lang}/lunettes-connectees` (à faire quand le module sera démontrable — cf. `DOCS/rayban-meta-integration.md`) | C | Faible aujourd'hui | **4 h** | +| 20 | Ouvrir un blog `/{lang}/ressources` avec les 5 articles déjà listés dans `TODO-SEO.md:49-54` | C | **Fort** à 6 mois | **20 h+** | +| 21 | Remplacer `lastModified: new Date()` par une date réelle par contenu (`sitemap.ts:18`) et afficher une date de mise à jour sur les cas clients | T | Faible | **2 h** | + +**Séquence recommandée.** Les items 1 à 6 tiennent en une demi-journée et corrigent l'essentiel des pertes gratuites. L'item 7 est le seul chantier technique de fond. Les items 8, 9, 12 et 14 sont ceux qui changent réellement la réponse d'un LLM à « quelle solution d'audioguide pour mon musée en Belgique ? ». + +--- + +## Annexe — ce qui est déjà bien fait + +À ne pas casser : + +- Le contenu textuel est intégralement dans le HTML servi — ce n'est pas une SPA client-only. +- Aucun crawler IA n'est bloqué (`robots.txt:1-2`). +- `llms.txt` existe et est structuré — la majorité des concurrents n'en ont pas. +- Les six pages segment sont de vraies pages d'intention : ~1 130 mots FR, pain points, features, comparatif, six FAQ, le tout en quatre langues, avec `FAQPage` JSON-LD. +- Les FAQ des pages segment sont collapsées en CSS (`max-h-0`, `SegmentPageClient.tsx:652`) et non conditionnées par un `useState` : le texte est bien dans le DOM. C'est le bon pattern — exactement ce que `ModulesSection` ne fait pas. +- `hreflang` complet avec `x-default`, sur chaque page **et** dans le sitemap. +- `/signup` est correctement en `noindex, follow` (`signup/page.tsx:41`). +- OG image générée dynamiquement et localisée, avec une variante par segment. +- Les prix (39 / 99 / 179 €) sont en texte brut dans le HTML, pas en image. diff --git a/package-lock.json b/package-lock.json index 615afc4..4d9d1b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "16.1.6", "react": "19.2.3", - "react-dom": "19.2.3" + "react-dom": "19.2.3", + "sharp": "^0.35.4" }, "devDependencies": { "@tailwindcss/postcss": "^4", @@ -290,10 +291,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", "optional": true, "dependencies": { "tslib": "^2.4.0" @@ -507,67 +507,80 @@ } }, "node_modules/@img/colour": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", - "license": "MIT", - "optional": true, + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "engines": { "node": ">=18" } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz", + "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" + "@img/sharp-libvips-darwin-arm64": "1.3.3" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz", + "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" + "@img/sharp-libvips-darwin-x64": "1.3.3" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz", + "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -577,13 +590,12 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz", + "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -593,13 +605,12 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz", + "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==", "cpu": [ "arm" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -609,13 +620,12 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz", + "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -625,13 +635,12 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz", + "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==", "cpu": [ "ppc64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -641,13 +650,12 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz", + "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==", "cpu": [ "riscv64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -657,13 +665,12 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz", + "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==", "cpu": [ "s390x" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -673,13 +680,12 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz", + "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -689,13 +695,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz", + "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -705,13 +710,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz", + "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -721,252 +725,255 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz", + "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==", "cpu": [ "arm" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" + "@img/sharp-libvips-linux-arm": "1.3.3" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz", + "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" + "@img/sharp-libvips-linux-arm64": "1.3.3" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz", + "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==", "cpu": [ "ppc64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" + "@img/sharp-libvips-linux-ppc64": "1.3.3" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz", + "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==", "cpu": [ "riscv64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" + "@img/sharp-libvips-linux-riscv64": "1.3.3" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz", + "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==", "cpu": [ "s390x" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" + "@img/sharp-libvips-linux-s390x": "1.3.3" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz", + "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" + "@img/sharp-libvips-linux-x64": "1.3.3" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz", + "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz", + "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + "@img/sharp-libvips-linuxmusl-x64": "1.3.3" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz", + "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz", + "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==", "cpu": [ "wasm32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.7.0" + "@img/sharp-wasm32": "0.35.4" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz", + "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz", + "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==", "cpu": [ "ia32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz", + "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" @@ -2782,7 +2789,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -5031,6 +5037,438 @@ } } }, + "node_modules/next/node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/next/node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -5059,6 +5497,62 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/next/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/next/node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -5696,56 +6190,57 @@ } }, "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz", + "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==", "dependencies": { - "@img/colour": "^1.0.0", + "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", - "semver": "^7.7.3" + "semver": "^7.8.5" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" + "@img/sharp-darwin-arm64": "0.35.4", + "@img/sharp-darwin-x64": "0.35.4", + "@img/sharp-freebsd-wasm32": "0.35.4", + "@img/sharp-libvips-darwin-arm64": "1.3.3", + "@img/sharp-libvips-darwin-x64": "1.3.3", + "@img/sharp-libvips-linux-arm": "1.3.3", + "@img/sharp-libvips-linux-arm64": "1.3.3", + "@img/sharp-libvips-linux-ppc64": "1.3.3", + "@img/sharp-libvips-linux-riscv64": "1.3.3", + "@img/sharp-libvips-linux-s390x": "1.3.3", + "@img/sharp-libvips-linux-x64": "1.3.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", + "@img/sharp-libvips-linuxmusl-x64": "1.3.3", + "@img/sharp-linux-arm": "0.35.4", + "@img/sharp-linux-arm64": "0.35.4", + "@img/sharp-linux-ppc64": "0.35.4", + "@img/sharp-linux-riscv64": "0.35.4", + "@img/sharp-linux-s390x": "0.35.4", + "@img/sharp-linux-x64": "0.35.4", + "@img/sharp-linuxmusl-arm64": "0.35.4", + "@img/sharp-linuxmusl-x64": "0.35.4", + "@img/sharp-webcontainers-wasm32": "0.35.4", + "@img/sharp-win32-arm64": "0.35.4", + "@img/sharp-win32-ia32": "0.35.4", + "@img/sharp-win32-x64": "0.35.4" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/sharp/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "optional": true, + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "bin": { "semver": "bin/semver.js" }, diff --git a/package.json b/package.json index 6ec9653..865bacf 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dependencies": { "next": "16.1.6", "react": "19.2.3", - "react-dom": "19.2.3" + "react-dom": "19.2.3", + "sharp": "^0.35.4" }, "browserslist": [ "last 2 Chrome versions", diff --git a/public/app-map.jpg b/public/app-map.jpg new file mode 100644 index 0000000..65fb80e Binary files /dev/null and b/public/app-map.jpg differ diff --git a/public/app-screenshot-1.jpg b/public/app-screenshot-1.jpg new file mode 100644 index 0000000..4e71a57 Binary files /dev/null and b/public/app-screenshot-1.jpg differ diff --git a/public/app-screenshot-1.png b/public/app-screenshot-1.png deleted file mode 100644 index de4325c..0000000 Binary files a/public/app-screenshot-1.png and /dev/null differ diff --git a/public/app-screenshot-2.jpg b/public/app-screenshot-2.jpg new file mode 100644 index 0000000..bafd5b1 Binary files /dev/null and b/public/app-screenshot-2.jpg differ diff --git a/public/app-screenshot-2.png b/public/app-screenshot-2.png deleted file mode 100644 index c341489..0000000 Binary files a/public/app-screenshot-2.png and /dev/null differ diff --git a/public/app-screenshot-3.jpg b/public/app-screenshot-3.jpg new file mode 100644 index 0000000..65668a3 Binary files /dev/null and b/public/app-screenshot-3.jpg differ diff --git a/public/google-maps-route.png b/public/google-maps-route.png deleted file mode 100644 index c2f839d..0000000 Binary files a/public/google-maps-route.png and /dev/null differ diff --git a/public/llms-en.txt b/public/llms-en.txt new file mode 100644 index 0000000..236f127 --- /dev/null +++ b/public/llms-en.txt @@ -0,0 +1,91 @@ +# MyInfoMate + +> MyInfoMate is a SaaS platform that digitalizes the visitor experience for cultural venues, tourism offices, parks, hotels, and events. It enables venue managers to create, manage and distribute interactive content on mobile apps, tablet kiosks, and web — with no coding required. + +Developed by **Unov**, based in Namur, Wallonia (Belgium). +Contact: contact@unov.be +Website: https://myinfomate.be +French version of this file: https://myinfomate.be/llms.txt + +## What is MyInfoMate? + +MyInfoMate is a content management and distribution platform (CMS) for any venue that welcomes visitors. It provides: +- A back-office web interface to create and manage interactive visitor journeys +- A white-label native mobile app (iOS & Android) for visitors on their own devices (BYOD) +- A tablet kiosk app for fixed installations +- A web app accessible from any browser, no install needed + +All deployments are managed from a single CMS. Content can be updated in real time from a browser. + +## Key Features + +- **Interactive Maps**: Real-time geolocation, clickable points of interest, route navigation +- **Games & Quizzes**: Treasure hunts, knowledge quizzes, gamified trails, escape games with narrative and riddles +- **Audio & Video**: Immersive audio guides, HD video, multimedia content +- **Articles & PDF**: Descriptive sheets, brochures, digitized catalogs +- **Agenda & Events**: Dynamic event calendar and scheduling +- **Offline Access**: Automatic content download for areas without Wi-Fi or 4G +- **Web & Social Content**: Embedded forms, social feeds, external links +- **Statistics & Data**: Visitor behavior analytics, engagement tracking, content popularity +- **Escape Game & Trails**: The only CMS on the market with a full escape game module built in +- **AI Visitor Assistant**: Generative AI guide available 24/7, multilingual, scoped strictly to the venue's content +- **Push Notifications**: Real-time alerts to visitors +- **Automatic Translation**: Content auto-translated across languages +- **White Label**: Full interface customization with venue's brand, logo, colors, and typography + +## Deployment Modes + +1. **Mobile App (BYOD)** — visitors use their own smartphone; white-label app published on App Store & Google Play +2. **Tablet Kiosk** — robust pre-installed app on venue-managed tablet fleets +3. **Web App** — accessible from any modern browser, no install required +4. **VR & AR** (coming soon) — immersive experiences on Meta Quest and connected glasses + +## AI Assistant + +The MyInfoMate AI assistant is a generative AI guide integrated into the visitor app: +- Answers visitor questions in their own language (French, English, Dutch, German, and more) +- Knows the venue's content: points of interest, exhibitions, services +- Maintains conversation context throughout the visit +- Strictly scoped to the venue — no off-topic responses +- Available 24/7 + +## Target Venues + +- **Museums & Heritage**: digitize collections, create multimedia trails, multilingual smart guide +- **Tourism Offices**: city/region maps, event agendas, 24/7 AI assistant +- **Parks & Natural Sites**: trail markers, biodiversity content, offline quizzes and treasure hunts +- **Hotels & Leisure**: interactive estate map, services, virtual concierge +- **Events & Exhibitions**: festivals, trade shows, fairs — interactive maps, real-time agenda +- **Education & Culture**: campuses, science centers, libraries — guided content per space + +## Customer References + +Real venues using MyInfoMate (Belgium): + +- **Musée de la Fraise de Wépion** (2021) — first MyInfoMate customer. Started with a tablet kiosk solution (the original use case that drove the creation of MyInfoMate), then extended to a visitor mobile app covering the museum and the fruit garden trail. Demonstrates the no-code CMS autonomy for a small museum team. Case study: https://myinfomate.be/en/cas-clients/musee-de-la-fraise + +- **Fort de Saint-Héribert** (2023) — first mobile deployment of MyInfoMate, on a historic underground fort. 100% offline mode (no Wi-Fi possible in the galleries), iBeacon beacons for indoor location tracking, QR codes, audio guide, iOS + Android. Case study: https://myinfomate.be/en/cas-clients/fort-de-saint-heribert + +- **Visit Namur** (Tourist Office of Namur, 2024) — interactive tablet kiosks deployed at the tourism office. Interactive city map with geolocated points of interest, real-time events agenda, itinerary planning. Case study: https://myinfomate.be/en/cas-clients/visit-namur + +All case studies index: https://myinfomate.be/en/cas-clients + +## Pricing + +Monthly subscription, prices excluding VAT. Full pricing: https://myinfomate.be/en#pricing + +- **Essentiel — €39/month**: visitor web app + kiosk mode, CMS back-office, all content sections, 1 GB storage, basic visitor stats. No commitment. 14-day free trial, no credit card required. +- **Pro — €99/month**: everything in Essentiel + your own white-label mobile app on the App Store & Google Play, offline mode + BLE beacons, push notifications, 15 GB storage. Setup fee + 12-month commitment. +- **Premium — €179/month**: everything in Pro + AI visitor assistant (≈ 2,000 visitor questions / month), automatic translation, advanced stats, 50 GB storage. Setup fee + 12-month commitment. +- **Enterprise — custom quote**: multi-site organizations, unlimited storage, custom AI quota, enhanced SLA, dedicated support, custom development. + +Multi-year contracts (2–3 years, annual billing) available with preferential rates. + +## Company + +**Unov** — software company based in Namur, Belgium. +Address: Rue René Copette 3, 5020 Namur, Belgium — VAT BE 0776.895.467 +MyInfoMate is already deployed in Namur and across Wallonia. +Email: contact@unov.be +Website: https://myinfomate.be +LinkedIn: https://www.linkedin.com/showcase/myinfomate/ diff --git a/public/llms.txt b/public/llms.txt index dc0caf2..dabac19 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -1,85 +1,83 @@ # MyInfoMate -> MyInfoMate is a SaaS platform that digitalizes the visitor experience for cultural venues, tourism offices, parks, hotels, and events. It enables venue managers to create, manage and distribute interactive content on mobile apps, tablet kiosks, and web — with no coding required. +> MyInfoMate est une plateforme SaaS belge de médiation numérique pour les lieux qui accueillent du public : musées, sites patrimoniaux, offices de tourisme, parcs naturels, hôtels et événements. Depuis un seul back-office, sans code, le lieu crée ses contenus et parcours de visite et les diffuse sur une application mobile à son nom, sur des bornes tablettes et sur le web. -Developed by **Unov**, based in Namur, Wallonia (Belgium). -Contact: contact@unov.be -Website: https://myinfomate.be +Éditeur : **Unov**, Namur, Wallonie (Belgique). +Contact : contact@unov.be — +32 498 07 95 35 +Site : https://myinfomate.be +English version of this file: https://myinfomate.be/llms-en.txt -## What is MyInfoMate? +## En bref -MyInfoMate is a content management and distribution platform (CMS) for any venue that welcomes visitors. It provides: -- A back-office web interface to create and manage interactive visitor journeys -- A white-label native mobile app (iOS & Android) for visitors on their own devices (BYOD) -- A tablet kiosk app for fixed installations -- A web app accessible from any browser, no install needed +- Application guide de visite / audioguide numérique pour musées et lieux culturels +- Back-office no-code : l'équipe du lieu met elle-même à jour textes, images, audio, vidéo et agenda, en temps réel +- Trois canaux alimentés par le même contenu : application mobile (BYOD), borne tablette (kiosk), application web sans installation +- Application en marque blanche : logo, couleurs et typographie du lieu, publiée sur l'App Store et Google Play +- Assistant IA visiteur multilingue, limité aux contenus du lieu +- Mode hors ligne pour les sites sans réseau (caves, forts, sites en plein air) +- Déjà déployé en Wallonie ; interface et support en français, anglais, néerlandais et allemand -All deployments are managed from a single CMS. Content can be updated in real time from a browser. +## Fonctionnalités -## Key Features +- **Cartes & plans** : carte interactive, géolocalisation en temps réel, points d'intérêt cliquables, itinéraires +- **Audio & vidéo** : audioguides, vidéos HD, témoignages +- **Jeux & quiz** : quiz, chasses au trésor, parcours gamifiés +- **Escape game & parcours** : escape games avec narration et énigmes, chasses au trésor, parcours guidés séquentiels — module d'escape game complet intégré au CMS +- **Articles & PDF** : fiches descriptives, brochures, catalogues numérisés +- **Agenda & événements** : programmation dynamique (expositions, conférences, ateliers) +- **Accès hors ligne** : téléchargement des contenus pour une visite sans 4G ni Wi-Fi ; balises BLE (iBeacon) et QR codes pour déclencher les contenus sur place +- **Contenu web & social** : formulaires, réseaux sociaux, liens externes +- **Statistiques** : fréquentation, contenus populaires, engagement +- **Notifications push** et **traduction automatique** des contenus +- **Marque blanche** : personnalisation complète de l'interface -- **Interactive Maps**: Real-time geolocation, clickable points of interest, route navigation -- **Games & Quizzes**: Treasure hunts, knowledge quizzes, gamified trails, escape games with narrative and riddles -- **Audio & Video**: Immersive audio guides, HD video, multimedia content -- **Articles & PDF**: Descriptive sheets, brochures, digitized catalogs -- **Agenda & Events**: Dynamic event calendar and scheduling -- **Offline Access**: Automatic content download for areas without Wi-Fi or 4G -- **Web & Social Content**: Embedded forms, social feeds, external links -- **Statistics & Data**: Visitor behavior analytics, engagement tracking, content popularity -- **Escape Game & Trails**: The only CMS on the market with a full escape game module built in -- **AI Visitor Assistant**: Generative AI guide available 24/7, multilingual, scoped strictly to the venue's content -- **Push Notifications**: Real-time alerts to visitors -- **Automatic Translation**: Content auto-translated across languages -- **White Label**: Full interface customization with venue's brand, logo, colors, and typography +## Modes de déploiement -## Deployment Modes +1. **Application mobile (BYOD)** — le visiteur utilise son propre smartphone ; application à la marque du lieu sur l'App Store et Google Play +2. **Borne tablette (kiosk)** — application pré-installée sur les tablettes du lieu, pour l'accueil ou les salles +3. **Application web** — ouverte depuis un navigateur ou un QR code, sans installation +4. **Réalité virtuelle & augmentée** (à venir) — expériences immersives sur Meta Quest et lunettes connectées -1. **Mobile App (BYOD)** — visitors use their own smartphone; white-label app published on App Store & Google Play -2. **Tablet Kiosk** — robust pre-installed app on venue-managed tablet fleets -3. **Web App** — accessible from any modern browser, no install required -4. **VR & AR** (coming soon) — immersive experiences on Meta Quest and connected glasses +## Assistant IA visiteur -## AI Assistant +- Répond aux questions des visiteurs dans leur langue (français, anglais, néerlandais, allemand, et d'autres) +- S'appuie uniquement sur les contenus du lieu : points d'intérêt, expositions, services — pas de réponses hors sujet +- Garde le contexte de la conversation pendant toute la visite +- Disponible 24 h/24 +- Inclus dans le plan Premium (≈ 2 000 questions de visiteurs par mois) -The MyInfoMate AI assistant is a generative AI guide integrated into the visitor app: -- Answers visitor questions in their own language (French, English, Dutch, German, and more) -- Knows the venue's content: points of interest, exhibitions, services -- Maintains conversation context throughout the visit -- Strictly scoped to the venue — no off-topic responses -- Available 24/7 +## Pour qui -## Target Venues +- **Musées & patrimoine** : parcours multimédias, audioguide multilingue, collections numérisées — https://myinfomate.be/fr/musees +- **Offices de tourisme** : carte de la ville ou de la région, agenda des événements, borne d'accueil, assistant 24 h/24 — https://myinfomate.be/fr/offices-tourisme +- **Parcs & sites naturels** : sentiers balisés, biodiversité, jeux de piste, visite hors ligne — https://myinfomate.be/fr/parcs-naturels +- **Hôtels & loisirs** : carte du domaine, services, concierge virtuel — https://myinfomate.be/fr/hotels-loisirs +- **Événementiel** : festivals, salons, foires — plan interactif, agenda en temps réel — https://myinfomate.be/fr/evenements +- **Éducation & culture** : campus, centres de science, bibliothèques — https://myinfomate.be/fr/education-culture -- **Museums & Heritage**: digitize collections, create multimedia trails, multilingual smart guide -- **Tourism Offices**: city/region maps, event agendas, 24/7 AI assistant -- **Parks & Natural Sites**: trail markers, biodiversity content, offline quizzes and treasure hunts -- **Hotels & Leisure**: interactive estate map, services, virtual concierge -- **Events & Exhibitions**: festivals, trade shows, fairs — interactive maps, real-time agenda -- **Education & Culture**: campuses, science centers, libraries — guided content per space +## Références clients (Belgique) -## Customer References +- **Musée de la Fraise de Wépion** (2021) — premier client MyInfoMate. Borne tablette en novembre 2021, puis application mobile couvrant le musée et le jardin de petits fruits. L'équipe du musée gère ses contenus en autonomie. https://myinfomate.be/fr/cas-clients/musee-de-la-fraise +- **Fort de Saint-Héribert** (2023) — application mobile iOS et Android 100 % hors ligne dans un fort souterrain sans réseau : contenu téléchargé à l'entrée, balises iBeacon dans les galeries, QR codes, audioguide. https://myinfomate.be/fr/cas-clients/fort-de-saint-heribert +- **Visit Namur** (office du tourisme de Namur, 2024) — bornes interactives : carte de la ville, points d'intérêt géolocalisés, agenda des événements, itinéraires. https://myinfomate.be/fr/cas-clients/visit-namur -Real venues using MyInfoMate (Belgium): +Tous les cas clients : https://myinfomate.be/fr/cas-clients -- **Musée de la Fraise de Wépion** (2021) — first MyInfoMate customer. Started with a tablet kiosk solution (the original use case that drove the creation of MyInfoMate), then extended to a visitor mobile app covering the museum and the fruit garden trail. Demonstrates the no-code CMS autonomy for a small museum team. Case study: https://myinfomate.be/fr/cas-clients/musee-de-la-fraise +## Tarifs -- **Fort de Saint-Héribert** (2023) — first mobile deployment of MyInfoMate, on a historic underground fort. 100% offline mode (no Wi-Fi possible in the galleries), iBeacon beacons for indoor location tracking, QR codes, audio guide, iOS + Android. Case study: https://myinfomate.be/fr/cas-clients/fort-de-saint-heribert +Abonnement mensuel, prix hors TVA. Grille complète : https://myinfomate.be/fr#pricing -- **Visit Namur** (Tourist Office of Namur, 2024) — interactive tablet kiosks deployed at the tourism office. Interactive city map with geolocated points of interest, real-time events agenda, itinerary planning. Case study: https://myinfomate.be/fr/cas-clients/visit-namur +- **Essentiel — 39 €/mois** : application web visiteur + mode kiosk, back-office, toutes les sections de contenu, 1 Go de stockage, statistiques de base. Sans engagement. Essai gratuit de 14 jours, sans carte bancaire. +- **Pro — 99 €/mois** : Essentiel + application mobile à votre marque sur l'App Store et Google Play, hors ligne + balises BLE, notifications push, 15 Go de stockage. Frais de mise en place + engagement 12 mois. +- **Premium — 179 €/mois** : Pro + assistant IA visiteur (≈ 2 000 questions/mois), traduction automatique, statistiques avancées, 50 Go de stockage. Frais de mise en place + engagement 12 mois. +- **Enterprise — sur devis** : organisations multi-sites, stockage illimité, quota IA sur mesure, SLA renforcé, accompagnement dédié, développements spécifiques. -All case studies index: https://myinfomate.be/fr/cas-clients +Engagements de 2 ou 3 ans possibles, avec facturation annuelle et tarif préférentiel (adapté aux financements pluriannuels). -## Pricing +## Société -Subscription-based (monthly, excl. VAT). Starting from **€39/month**. -- No commitment for basic plans -- Setup fee + 12-month commitment for native mobile app plans -- Enterprise: custom quote for multi-site organizations or specific needs (custom development, enhanced SLA) -- Multi-year contracts (2–3 years) available with preferential rates - -## Company - -**Unov** — software company based in Namur, Belgium. -MyInfoMate is already deployed in Namur and across Wallonia. -Email: contact@unov.be -Website: https://myinfomate.be +**Unov** — éditeur de logiciels, Namur (Belgique). +Rue René Copette 3, 5020 Namur — TVA BE 0776.895.467 +Données hébergées en Europe. +Mentions légales : https://myinfomate.be/mentions-legales — Confidentialité : https://myinfomate.be/confidentialite +LinkedIn : https://www.linkedin.com/showcase/myinfomate/ diff --git a/public/map_generated.png b/public/map_generated.png deleted file mode 100644 index 7a9419e..0000000 Binary files a/public/map_generated.png and /dev/null differ diff --git a/public/myinfomate-logo.png b/public/myinfomate-logo.png index 21dbf98..3f36b8e 100644 Binary files a/public/myinfomate-logo.png and b/public/myinfomate-logo.png differ diff --git a/public/robots.txt b/public/robots.txt index 858ff24..1179cf8 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -3,3 +3,6 @@ Allow: / Disallow: /api/ Sitemap: https://myinfomate.be/sitemap.xml + +# Résumé du produit pour les assistants IA / product summary for LLMs +# https://myinfomate.be/llms.txt (fr) — https://myinfomate.be/llms-en.txt (en) diff --git a/src/app/[lang]/HomeClient.tsx b/src/app/[lang]/HomeClient.tsx index 1bf81c8..44a22e8 100644 --- a/src/app/[lang]/HomeClient.tsx +++ b/src/app/[lang]/HomeClient.tsx @@ -1,4 +1,5 @@ import Image from 'next/image'; +import Link from 'next/link'; import { resolveImage } from '@/data/stitch-images'; import translations, { Language } from '@/data/translations'; import { getAllCasClients } from '@/data/cas-clients'; @@ -6,6 +7,7 @@ import NavBar from '@/components/NavBar'; import Reveal from '@/components/Reveal'; import ModulesSection from '@/components/ModulesSection'; import ContactForm from '@/components/ContactForm'; +import PricingPlans from '@/components/PricingPlans'; export default function Home({ lang }: { lang: Language }) { const t = translations[lang]; @@ -47,23 +49,23 @@ export default function Home({ lang }: { lang: Language }) {
Modern Interactive Map Interface -
+

{t.mockup.mapTitle}

{t.mockup.mapSubtitle}

- MyInfoMate agenda module on mobile + {t.imgAlt.appHome}
- MyInfoMate tours module on mobile + {t.imgAlt.appArticle}
@@ -75,8 +77,8 @@ export default function Home({ lang }: { lang: Language }) {
-

{t.strategic.sectionLabel}

-

{t.strategic.sectionTitle}

+

{t.strategic.sectionLabel}

+

{t.strategic.sectionTitle}

@@ -84,7 +86,7 @@ export default function Home({ lang }: { lang: Language }) { sync
-

{t.strategic.feature1Title}

+

{t.strategic.feature1Title}

{t.strategic.feature1Desc}

@@ -93,7 +95,7 @@ export default function Home({ lang }: { lang: Language }) { code_off
-

{t.strategic.feature2Title}

+

{t.strategic.feature2Title}

{t.strategic.feature2Desc}

@@ -102,8 +104,12 @@ export default function Home({ lang }: { lang: Language }) { download_for_offline
-

{t.strategic.feature3Title}

+

{t.strategic.feature3Title}

{t.strategic.feature3Desc}

+ + {t.footer.pageOffline} + arrow_forward +
@@ -111,7 +117,7 @@ export default function Home({ lang }: { lang: Language }) { dashboard_customize
-

{t.strategic.feature4Title}

+

{t.strategic.feature4Title}

{t.strategic.feature4Desc}

@@ -123,8 +129,8 @@ export default function Home({ lang }: { lang: Language }) {
-

{t.deployment.sectionLabel}

-

{t.deployment.sectionTitle}

+

{t.deployment.sectionLabel}

+

{t.deployment.sectionTitle}

{t.deployment.sectionDesc}

@@ -132,21 +138,25 @@ export default function Home({ lang }: { lang: Language }) {
smartphone
-

{t.deployment.mode1Title}

+

{t.deployment.mode1Title}

{t.deployment.mode1Desc}

tablet_android
-

{t.deployment.mode2Title}

+

{t.deployment.mode2Title}

{t.deployment.mode2Desc}

+ + {t.footer.pageKiosk} + arrow_forward +
language
-

{t.deployment.mode3Title}

+

{t.deployment.mode3Title}

{t.deployment.mode3Desc}

@@ -156,7 +166,7 @@ export default function Home({ lang }: { lang: Language }) {
view_in_ar
-

{t.deployment.mode4Title}

+

{t.deployment.mode4Title}

{t.deployment.mode4Desc}

@@ -178,11 +188,15 @@ export default function Home({ lang }: { lang: Language }) { auto_awesome {t.ai.badge} -

{t.ai.sectionLabel}

-

+

{t.ai.sectionLabel}

+

{t.ai.titleBefore}{t.ai.titleHighlight}{t.ai.titleAfter} -

+

{t.ai.desc}

+ + {t.ai.learnMore} + arrow_forward +
@@ -229,28 +243,28 @@ export default function Home({ lang }: { lang: Language }) {
translate
-

{t.ai.feature1Title}

+

{t.ai.feature1Title}

{t.ai.feature1Desc}

manage_search
-

{t.ai.feature2Title}

+

{t.ai.feature2Title}

{t.ai.feature2Desc}

forum
-

{t.ai.feature3Title}

+

{t.ai.feature3Title}

{t.ai.feature3Desc}

tune
-

{t.ai.feature4Title}

+

{t.ai.feature4Title}

{t.ai.feature4Desc}

@@ -270,8 +284,14 @@ export default function Home({ lang }: { lang: Language }) {
-
- palette +
+ {t.imgAlt.appWhitelabel}
@@ -298,8 +318,8 @@ export default function Home({ lang }: { lang: Language }) {
-

{t.whitelabel.sectionLabel}

-

{t.whitelabel.title}

+

{t.whitelabel.sectionLabel}

+

{t.whitelabel.title}

  • @@ -324,7 +344,7 @@ export default function Home({ lang }: { lang: Language }) {
    -

    {t.audience.title}

    +

    {t.audience.title}

    {t.audience.subtitle}

    @@ -333,7 +353,7 @@ export default function Home({ lang }: { lang: Language }) {
    museum
    -

    {t.audience.item1Title}

    +

    {t.audience.item1Title}

    {t.audience.item1Desc}

    {t.audience.item1Cta} @@ -346,7 +366,7 @@ export default function Home({ lang }: { lang: Language }) {
    travel_explore
    -

    {t.audience.item2Title}

    +

    {t.audience.item2Title}

    {t.audience.item2Desc}

    {t.audience.item2Cta} @@ -359,7 +379,7 @@ export default function Home({ lang }: { lang: Language }) {
    park
    -

    {t.audience.item3Title}

    +

    {t.audience.item3Title}

    {t.audience.item3Desc}

    {t.audience.item3Cta} @@ -372,7 +392,7 @@ export default function Home({ lang }: { lang: Language }) {
    hotel
    -

    {t.audience.item4Title}

    +

    {t.audience.item4Title}

    {t.audience.item4Desc}

    {t.audience.item4Cta} @@ -385,7 +405,7 @@ export default function Home({ lang }: { lang: Language }) {
    festival
    -

    {t.audience.item5Title}

    +

    {t.audience.item5Title}

    {t.audience.item5Desc}

    {t.audience.item5Cta} @@ -398,7 +418,7 @@ export default function Home({ lang }: { lang: Language }) {
    school
    -

    {t.audience.item6Title}

    +

    {t.audience.item6Title}

    {t.audience.item6Desc}

    {t.audience.item6Cta} @@ -418,8 +438,8 @@ export default function Home({ lang }: { lang: Language }) {
    -

    {t.casClients.sectionLabel}

    -

    {t.casClients.title}

    +

    {t.casClients.sectionLabel}

    +

    {t.casClients.title}

    {t.casClients.subtitle}

    @@ -438,9 +458,9 @@ export default function Home({ lang }: { lang: Language }) { {client.year}
    -

    +

    {client.client} -

    +

    {ct.description}

    @@ -471,231 +491,33 @@ export default function Home({ lang }: { lang: Language }) {
    -

    {t.pricing.sectionLabel}

    -

    {t.pricing.sectionTitle}

    +

    {t.pricing.sectionLabel}

    +

    {t.pricing.sectionTitle}

    {t.pricing.sectionDesc}

    -
    - -
    -
    -

    Essentiel

    - - language - {t.pricing.channelWeb} - -
    - €39 - {t.pricing.perMonth} -
    -

    {t.pricing.htva} · {t.pricing.noCommitment}

    -
    -
      - {[t.pricing.features.webAndKiosk, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - 1 GB {t.pricing.features.storage} -
    • -
    • - check_circle - {t.pricing.features.stats} — {t.pricing.features.statsBasicLabel} -
    • - {[t.pricing.features.nativeApp, t.pricing.features.offlineBeacons, t.pricing.features.pushNotif, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => ( -
    • - cancel - {f} -
    • - ))} -
    - - {t.pricing.ctaStartTrial} - -
    -
    - -
    - - -
    -
    -

    Premium

    - - smartphone - {t.pricing.channelNative} - -
    - €179 - {t.pricing.perMonth} -
    -

    {t.pricing.htva}

    -

    {t.pricing.setupFeeNote}

    -
    -
      - {[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - 50 GB {t.pricing.features.storage} -
    • - {[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - {t.pricing.features.statsAdvancedFeature} -
    • -
    • - check_circle - - {t.pricing.features.ai} — ≈ 2 000 {t.pricing.features.questionsPerMonth} - {t.pricing.features.aiNeedMore} → Enterprise - -
    • -
    • - check_circle - {t.pricing.features.autoTranslation} -
    • -
    - - {t.pricing.ctaContact} - -
    -
    - -
    -
    -

    Enterprise

    - - smartphone - {t.pricing.channelNative} - -
    - {t.pricing.enterprisePrice} -
    -

    {t.pricing.enterpriseDesc}

    -
    -
      - {[ - t.pricing.features.webAndKiosk, - t.pricing.features.nativeApp, - t.pricing.features.backoffice, - t.pricing.features.sections, - t.pricing.features.multiSite, - ].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - {t.pricing.features.customStorage} -
    • -
    • - check_circle - {t.pricing.features.customAiQuota} -
    • - {[ - t.pricing.features.statsAdvancedFeature, - t.pricing.features.offlineBeacons, - t.pricing.features.pushNotif, - t.pricing.features.autoTranslation, - t.pricing.features.slaEnhanced, - t.pricing.features.dedicatedSupport, - t.pricing.features.customDev, - ].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    - - {t.pricing.ctaContact} - -
    -
    -
    - -
    -
    - calendar_month -
    -

    {t.pricing.multiYearLabel}

    -

    {t.pricing.multiYearDesc}

    -
    -
    - - {t.pricing.multiYearCta} - -
    + +
    +
    + + {/* FAQ */} +
    +
    + +

    {t.homeFaq.sectionLabel}

    +

    {t.homeFaq.title}

    +
    + {t.homeFaq.items.map((item) => ( +
    + +

    {item.question}

    + expand_more +
    +

    {item.answer}

    +
    + ))} +
    @@ -736,8 +558,8 @@ export default function Home({ lang }: { lang: Language }) {
    -

    {t.contact.sectionLabel}

    -

    {t.contact.title}

    +

    {t.contact.sectionLabel}

    +

    {t.contact.title}

    {t.contact.subtitle}

    @@ -763,7 +585,7 @@ export default function Home({ lang }: { lang: Language }) {

    {t.footer.desc}

    -
    -

    {t.footer.casClientsLink}

    +

    {t.footer.pagesTitle}

    +
      + {[ + { href: `/${lang}/tarifs`, label: t.footer.pageTarifs }, + { href: `/${lang}/assistant-ia`, label: t.footer.pageAssistant }, + { href: `/${lang}/borne-kiosk`, label: t.footer.pageKiosk }, + { href: `/${lang}/visite-hors-ligne`, label: t.footer.pageOffline }, + { href: `/${lang}/marches-publics`, label: t.footer.pagePublic }, + // Blog en français uniquement pour l'instant. + ...(lang === 'fr' + ? [ + { href: '/fr/ressources', label: 'Ressources' }, + { href: '/fr/comparatif/myinfomate-vs-smartify', label: 'Comparatifs' }, + ] + : []), + ].map((page) => ( +
    • + + {page.label} + +
    • + ))} +
    +
    +
    +

    {t.footer.casClientsLink}

      {casClients.map((c) => (
    • @@ -790,7 +636,7 @@ export default function Home({ lang }: { lang: Language }) {
    -

    {t.footer.contactTitle}

    +

    {t.footer.contactTitle}

    • location_on @@ -810,8 +656,9 @@ export default function Home({ lang }: { lang: Language }) {

      {t.footer.copyright}

      - {t.footer.legal} - {t.footer.privacy} + {t.footer.legal} + {t.footer.privacy} + {t.footer.terms}
    diff --git a/src/app/[lang]/[segment]/SegmentPageClient.tsx b/src/app/[lang]/[segment]/SegmentPageClient.tsx index 3cc6b0b..5932463 100644 --- a/src/app/[lang]/[segment]/SegmentPageClient.tsx +++ b/src/app/[lang]/[segment]/SegmentPageClient.tsx @@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation'; import { resolveImage } from '@/data/stitch-images'; import translations, { Language } from '@/data/translations'; import type { Segment } from '@/data/segments'; +import PricingPlans from '@/components/PricingPlans'; const LANGUAGES: { code: Language; label: string; name: string }[] = [ { code: 'fr', label: 'FR', name: 'Français' }, @@ -156,7 +157,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang: {t.nav.ai} {t.nav.audience} - + {t.pricing.sectionLabel}
    @@ -222,7 +223,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang: { label: t.mobileMenu.features, href: `/${lang}#features` }, { label: t.mobileMenu.ai, href: `/${lang}#ai-assistant` }, { label: t.mobileMenu.audience, href: `/${lang}#audience` }, - { label: t.pricing.sectionLabel.toUpperCase(), href: '#pricing' }, + { label: t.pricing.sectionLabel.toUpperCase(), href: `/${lang}/tarifs` }, { label: t.mobileMenu.contact, href: '#contact' }, ].map((item) => (
    -

    {s.painPoints.label}

    -

    {s.painPoints.title}

    +

    {s.painPoints.label}

    +

    {s.painPoints.title}

    {s.painPoints.items.map((item, i) => ( @@ -317,7 +318,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    {item.icon}
    -

    {item.title}

    +

    {item.title}

    {item.desc}

    @@ -330,8 +331,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    -

    {s.features.label}

    -

    {s.features.title}

    +

    {s.features.label}

    +

    {s.features.title}

    {s.features.desc}

    @@ -341,7 +342,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    {item.icon}
    -

    {item.title}

    +

    {item.title}

    {item.desc}

    @@ -360,8 +361,20 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:

    -

    {s.comparison.label}

    -

    {s.comparison.title}

    +

    {s.comparison.label}

    +

    {s.comparison.title}

    + {lang === 'fr' && ( +
    + + MyInfoMate ou Smartify + arrow_forward + + + MyInfoMate ou STQRY + arrow_forward + +
    + )}
    {s.comparison.items.map((item, i) => ( @@ -395,237 +408,11 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    -

    {t.pricing.sectionLabel}

    -

    {t.pricing.sectionTitle}

    +

    {t.pricing.sectionLabel}

    +

    {t.pricing.sectionTitle}

    {t.pricing.sectionDesc}

    -
    - - {/* Essentiel */} - -
    -
    -

    Essentiel

    - - language - {t.pricing.channelWeb} - -
    - €39 - {t.pricing.perMonth} -
    -

    {t.pricing.htva} · {t.pricing.noCommitment}

    -
    -
      - {[t.pricing.features.webAndKiosk, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - 1 GB {t.pricing.features.storage} -
    • -
    • - check_circle - {t.pricing.features.stats} — {t.pricing.features.statsBasicLabel} -
    • - {[t.pricing.features.nativeApp, t.pricing.features.offlineBeacons, t.pricing.features.pushNotif, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => ( -
    • - cancel - {f} -
    • - ))} -
    - - {t.pricing.ctaStartTrial} - -
    -
    - - {/* Pro */} - -
    -
    - {t.pricing.recommended} -
    -
    -

    Pro

    - - smartphone - {t.pricing.channelNative} - -
    - €99 - {t.pricing.perMonth} -
    -

    {t.pricing.htva}

    -

    {t.pricing.setupFeeNote}

    -
    -
      - {[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - 15 GB {t.pricing.features.storage} -
    • - {[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - {t.pricing.features.stats} — {t.pricing.features.statsBasicLabel} -
    • - {[t.pricing.features.statsAdvancedFeature, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => ( -
    • - cancel - {f} -
    • - ))} -
    - -
    -
    - - {/* Premium */} - -
    -
    -

    Premium

    - - smartphone - {t.pricing.channelNative} - -
    - €179 - {t.pricing.perMonth} -
    -

    {t.pricing.htva}

    -

    {t.pricing.setupFeeNote}

    -
    -
      - {[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - 50 GB {t.pricing.features.storage} -
    • - {[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - {t.pricing.features.statsAdvancedFeature} -
    • -
    • - check_circle - - {t.pricing.features.ai} — ≈ 2 000 {t.pricing.features.questionsPerMonth} - {t.pricing.features.aiNeedMore} → Enterprise - -
    • -
    • - check_circle - {t.pricing.features.autoTranslation} -
    • -
    - -
    -
    - - {/* Enterprise */} - -
    -
    -

    Enterprise

    - - smartphone - {t.pricing.channelNative} - -
    - {t.pricing.enterprisePrice} -
    -

    {t.pricing.enterpriseDesc}

    -
    -
      - {[ - t.pricing.features.webAndKiosk, - t.pricing.features.nativeApp, - t.pricing.features.backoffice, - t.pricing.features.sections, - t.pricing.features.multiSite, - ].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    • - check_circle - {t.pricing.features.customStorage} -
    • -
    • - check_circle - {t.pricing.features.customAiQuota} -
    • - {[ - t.pricing.features.statsAdvancedFeature, - t.pricing.features.offlineBeacons, - t.pricing.features.pushNotif, - t.pricing.features.autoTranslation, - t.pricing.features.slaEnhanced, - t.pricing.features.dedicatedSupport, - t.pricing.features.customDev, - ].map((f) => ( -
    • - check_circle - {f} -
    • - ))} -
    - -
    -
    - -
    - -
    -
    - calendar_month -
    -

    {t.pricing.multiYearLabel}

    -

    {t.pricing.multiYearDesc}

    -
    -
    - -
    -
    +
    @@ -633,8 +420,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    -

    {s.faq.label}

    -

    {s.faq.title}

    +

    {s.faq.label}

    +

    {s.faq.title}

    {s.faq.items.map((item, i) => ( @@ -696,8 +483,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
    -
    -

    {t.footer.contactTitle}

    +

    {t.footer.pagesTitle}

    +
      + {[ + { href: `/${lang}/tarifs`, label: t.footer.pageTarifs }, + { href: `/${lang}/assistant-ia`, label: t.footer.pageAssistant }, + { href: `/${lang}/borne-kiosk`, label: t.footer.pageKiosk }, + { href: `/${lang}/visite-hors-ligne`, label: t.footer.pageOffline }, + { href: `/${lang}/marches-publics`, label: t.footer.pagePublic }, + // Blog en français uniquement pour l'instant. + ...(lang === 'fr' + ? [ + { href: '/fr/ressources', label: 'Ressources' }, + { href: '/fr/comparatif/myinfomate-vs-smartify', label: 'Comparatifs' }, + ] + : []), + ].map((page) => ( +
    • + + {page.label} + +
    • + ))} +
    +
    +
    diff --git a/src/app/[lang]/[segment]/page.tsx b/src/app/[lang]/[segment]/page.tsx index dbdceb4..dd50356 100644 --- a/src/app/[lang]/[segment]/page.tsx +++ b/src/app/[lang]/[segment]/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getSegmentData, getAllSegmentSlugs } from '@/data/segments'; import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n'; +import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data'; import SegmentPageClient from './SegmentPageClient'; const SITE_URL = 'https://myinfomate.be'; @@ -81,23 +82,23 @@ export default async function SegmentPage({ name: 'MyInfoMate', applicationCategory: 'BusinessApplication', operatingSystem: 'iOS, Android, Web', - offers: { - '@type': 'Offer', - price: '39', - priceCurrency: 'EUR', - priceSpecification: { - '@type': 'UnitPriceSpecification', - price: '39', - priceCurrency: 'EUR', - unitText: 'MONTH', - }, - }, + offers: softwareOffers, + sameAs: [MYINFOMATE_LINKEDIN], description: data.meta[lang].description, url: `${SITE_URL}/${lang}/${segment}`, }; + const breadcrumb = breadcrumbSchema([ + { name: 'MyInfoMate', path: `/${lang}` }, + { name: data.translations[lang].hero.badge, path: `/${lang}/${segment}` }, + ]); + return ( <> +