create-snapify-app 0.0.0-stage → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +24 -0
- package/README.md +55 -2
- package/bin/create-snapify-app.mjs +174 -0
- package/lib/args.mjs +59 -0
- package/lib/copy.mjs +44 -0
- package/lib/env.mjs +84 -0
- package/lib/prompt.mjs +63 -0
- package/package.json +35 -4
- package/template/.env.example +79 -0
- package/template/.github/workflows/ci.yml +23 -0
- package/template/.github/workflows/deploy.yml +26 -0
- package/template/.github/workflows/ping.yml +8 -0
- package/template/.github/workflows/release.yml +67 -0
- package/template/.snapify-install.json +5 -0
- package/template/CHANGELOG.md +28 -0
- package/template/LICENSE +14 -0
- package/template/README.md +287 -0
- package/template/administrator.html +23 -0
- package/template/apps/client/src/App.tsx +765 -0
- package/template/apps/client/src/auth.css +400 -0
- package/template/apps/client/src/lib/api.ts +22 -0
- package/template/apps/client/src/main.tsx +20 -0
- package/template/apps/community/src/App.tsx +592 -0
- package/template/apps/community/src/main.tsx +20 -0
- package/template/apps/community/src/styles.css +24 -0
- package/template/apps/developers/src/App.tsx +643 -0
- package/template/apps/developers/src/main.tsx +17 -0
- package/template/apps/developers/src/pages.tsx +1587 -0
- package/template/apps/developers/src/styles.css +98 -0
- package/template/apps/developers/src/ui.tsx +179 -0
- package/template/apps/landing/src/App.tsx +598 -0
- package/template/apps/landing/src/LegalPages.tsx +158 -0
- package/template/apps/landing/src/OrderPage.tsx +381 -0
- package/template/apps/landing/src/SeoPages.tsx +923 -0
- package/template/apps/landing/src/copy.ts +195 -0
- package/template/apps/landing/src/main.tsx +20 -0
- package/template/apps/landing/src/styles.css +803 -0
- package/template/apps/landing/src/types.ts +19 -0
- package/template/apps/marketplace/src/App.tsx +1229 -0
- package/template/apps/marketplace/src/developer/DeveloperApp.tsx +1266 -0
- package/template/apps/marketplace/src/main.tsx +20 -0
- package/template/apps/marketplace/src/styles.css +1001 -0
- package/template/apps/shared/AuthContext.tsx +65 -0
- package/template/apps/shared/Logo.tsx +33 -0
- package/template/apps/shared/api.ts +47 -0
- package/template/apps/shared/ui.tsx +128 -0
- package/template/apps/superadmin/src/App.tsx +1264 -0
- package/template/apps/superadmin/src/lib/api.ts +20 -0
- package/template/apps/superadmin/src/lib/hooks.ts +20 -0
- package/template/apps/superadmin/src/main.tsx +16 -0
- package/template/apps/superadmin/src/pages/ClientsPage.tsx +185 -0
- package/template/apps/superadmin/src/pages/InvoicesPage.tsx +157 -0
- package/template/apps/superadmin/src/pages/NewsletterPage.tsx +212 -0
- package/template/apps/superadmin/src/pages/OrdersPage.tsx +195 -0
- package/template/apps/superadmin/src/pages/PaymentsPage.tsx +150 -0
- package/template/apps/superadmin/src/pages/PayoutsPage.tsx +133 -0
- package/template/apps/superadmin/src/pages/PublishersPage.tsx +151 -0
- package/template/apps/superadmin/src/pages/SeoControlPage.tsx +692 -0
- package/template/apps/superadmin/src/pages/SettingsPage.tsx +199 -0
- package/template/apps/superadmin/src/pages/SystemPage.tsx +109 -0
- package/template/apps/superadmin/src/pages/TicketsPage.tsx +201 -0
- package/template/apps/superadmin/src/pages/UsersPage.tsx +167 -0
- package/template/client.html +21 -0
- package/template/community/hamdiayari/akhbar/README.md +23 -0
- package/template/community/hamdiayari/akhbar/screenshot.jpg +0 -0
- package/template/community/hamdiayari/akhbar/snapify.theme.json +76 -0
- package/template/community/hamdiayari/akhbar/src/Brand.tsx +26 -0
- package/template/community/hamdiayari/akhbar/src/Footer.tsx +182 -0
- package/template/community/hamdiayari/akhbar/src/Header.tsx +191 -0
- package/template/community/hamdiayari/akhbar/src/Layout.tsx +49 -0
- package/template/community/hamdiayari/akhbar/src/Social.tsx +33 -0
- package/template/community/hamdiayari/akhbar/src/Ticker.tsx +86 -0
- package/template/community/hamdiayari/akhbar/src/Views.tsx +285 -0
- package/template/community/hamdiayari/akhbar/src/blocks/CollectionBlocks.tsx +672 -0
- package/template/community/hamdiayari/akhbar/src/blocks/ContentBlocks.tsx +305 -0
- package/template/community/hamdiayari/akhbar/src/blocks/ConversionBlocks.tsx +569 -0
- package/template/community/hamdiayari/akhbar/src/blocks/HeaderBlocks.tsx +287 -0
- package/template/community/hamdiayari/akhbar/src/index.tsx +51 -0
- package/template/community/hamdiayari/akhbar/src/kit.tsx +357 -0
- package/template/community/hamdiayari/akhbar/src/site.ts +96 -0
- package/template/community/hamdiayari/akhbar/src/styles.css +566 -0
- package/template/community/hamdiayari/akhbar-actualites/README.md +28 -0
- package/template/community/hamdiayari/akhbar-actualites/screenshot.jpg +0 -0
- package/template/community/hamdiayari/akhbar-actualites/snapify.module.json +107 -0
- package/template/community/hamdiayari/akhbar-actualites/src/admin/AudiencePage.tsx +185 -0
- package/template/community/hamdiayari/akhbar-actualites/src/admin/index.tsx +11 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/Archive.tsx +142 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/cards.tsx +152 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/index.tsx +71 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/posts.ts +103 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/styles.css +568 -0
- package/template/community/hamdiayari/akhbar-actualites/src/public/widgets.tsx +226 -0
- package/template/community/hamdiayari/akhbar-actualites/src/server.ts +119 -0
- package/template/community/hamdiayari/akhbar-actualites/src/types.ts +25 -0
- package/template/community/hamdiayari/akhbar-urgent/README.md +36 -0
- package/template/community/hamdiayari/akhbar-urgent/screenshot.jpg +0 -0
- package/template/community/hamdiayari/akhbar-urgent/snapify.module.json +64 -0
- package/template/community/hamdiayari/akhbar-urgent/src/admin/FlashesPage.tsx +229 -0
- package/template/community/hamdiayari/akhbar-urgent/src/admin/index.tsx +11 -0
- package/template/community/hamdiayari/akhbar-urgent/src/public/Ticker.tsx +81 -0
- package/template/community/hamdiayari/akhbar-urgent/src/public/index.tsx +63 -0
- package/template/community/hamdiayari/akhbar-urgent/src/public/styles.css +142 -0
- package/template/community/hamdiayari/akhbar-urgent/src/server.ts +101 -0
- package/template/community/hamdiayari/akhbar-urgent/src/types.ts +35 -0
- package/template/community.html +21 -0
- package/template/developers.html +24 -0
- package/template/docker-compose.db.yml +24 -0
- package/template/docs/BACKOFFICE_SNAPIFY.md +130 -0
- package/template/docs/CI_CD.md +66 -0
- package/template/docs/MODULES.md +346 -0
- package/template/docs/PLATFORM_DEPLOY.md +54 -0
- package/template/docs/logo.svg +10 -0
- package/template/drizzle/0000_init.sql +147 -0
- package/template/drizzle/0001_page_project.sql +5 -0
- package/template/drizzle/0002_modules.sql +23 -0
- package/template/drizzle/0003_themes.sql +4 -0
- package/template/drizzle/0004_security.sql +82 -0
- package/template/drizzle/0005_module_records.sql +16 -0
- package/template/drizzle/0006_avatars.sql +4 -0
- package/template/drizzle/0007_platform.sql +264 -0
- package/template/drizzle/0008_mp_validation.sql +3 -0
- package/template/drizzle/0009_saas_ops.sql +77 -0
- package/template/drizzle/0010_cms_chrome.sql +13 -0
- package/template/drizzle/0011_client_portal.sql +26 -0
- package/template/drizzle/meta/0000_snapshot.json +998 -0
- package/template/drizzle/meta/0001_snapshot.json +1004 -0
- package/template/drizzle/meta/_journal.json +90 -0
- package/template/drizzle.config.ts +16 -0
- package/template/ecosystem.snapify.cjs +24 -0
- package/template/for.html +1 -0
- package/template/index.html +29 -0
- package/template/landing.html +37 -0
- package/template/marketplace/catalog.json +373 -0
- package/template/marketplace/gallery/hamdiayari.preveris/01-home.jpg +0 -0
- package/template/marketplace/gallery/hamdiayari.recaptcha/01-reglages.jpg +0 -0
- package/template/marketplace/gallery/hamdiayari.recaptcha/02-logo.jpg +0 -0
- package/template/marketplace/gallery/novalabs.ai-articles/01-generer.jpg +0 -0
- package/template/marketplace/gallery/novalabs.ai-articles/02-fournisseur-ia.jpg +0 -0
- package/template/marketplace/gallery/novalabs.calendar/01-agenda-site.jpg +0 -0
- package/template/marketplace/gallery/novalabs.calendar/02-evenements-admin.jpg +0 -0
- package/template/marketplace/gallery/novalabs.calendar/03-reglages.jpg +0 -0
- package/template/marketplace/screenshots/hamdiayari.preveris-1.0.6.jpg +0 -0
- package/template/marketplace/screenshots/hamdiayari.recaptcha-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/hamdiayari.wp-seo-migrator-1.1.1.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.ai-articles-1.0.1.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.ai-chat-1.0.1.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.calendar-1.0.1.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.cart-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.checkout-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.customers-1.1.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.dogga-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.mahdia-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.shop-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.sidibou-1.0.0.jpg +0 -0
- package/template/marketplace/screenshots/novalabs.whatsapp-1.0.1.jpg +0 -0
- package/template/marketplace.html +21 -0
- package/template/metadata.json +7 -0
- package/template/modules/ai-articles/screenshot.jpg +0 -0
- package/template/modules/ai-articles/snapify.module.json +74 -0
- package/template/modules/ai-articles/src/admin/ArticlesPage.tsx +162 -0
- package/template/modules/ai-articles/src/admin/GeneratePage.tsx +118 -0
- package/template/modules/ai-articles/src/admin/index.tsx +12 -0
- package/template/modules/ai-articles/src/public/index.tsx +119 -0
- package/template/modules/ai-articles/src/server.ts +287 -0
- package/template/modules/ai-articles/src/types.ts +30 -0
- package/template/modules/ai-chat/screenshot.jpg +0 -0
- package/template/modules/ai-chat/snapify.module.json +217 -0
- package/template/modules/ai-chat/src/public.tsx +198 -0
- package/template/modules/ai-chat/src/server.ts +142 -0
- package/template/modules/ai-theme-studio/README.md +15 -0
- package/template/modules/ai-theme-studio/screenshot.jpg +0 -0
- package/template/modules/ai-theme-studio/snapify.module.json +175 -0
- package/template/modules/ai-theme-studio/src/admin/HistoryPage.tsx +91 -0
- package/template/modules/ai-theme-studio/src/admin/StudioPage.tsx +414 -0
- package/template/modules/ai-theme-studio/src/admin/index.tsx +11 -0
- package/template/modules/ai-theme-studio/src/lib/images.ts +240 -0
- package/template/modules/ai-theme-studio/src/lib/llm.ts +123 -0
- package/template/modules/ai-theme-studio/src/lib/normalize.ts +714 -0
- package/template/modules/ai-theme-studio/src/lib/prompts.ts +198 -0
- package/template/modules/ai-theme-studio/src/server.ts +137 -0
- package/template/modules/ai-theme-studio/src/types.ts +112 -0
- package/template/modules/calendar/screenshot.jpg +0 -0
- package/template/modules/calendar/snapify.module.json +45 -0
- package/template/modules/calendar/src/admin/EventsPage.tsx +217 -0
- package/template/modules/calendar/src/admin/index.tsx +11 -0
- package/template/modules/calendar/src/public/index.tsx +231 -0
- package/template/modules/calendar/src/server.ts +143 -0
- package/template/modules/calendar/src/types.ts +25 -0
- package/template/modules/cart/screenshot.jpg +0 -0
- package/template/modules/cart/snapify.module.json +90 -0
- package/template/modules/cart/src/admin/index.tsx +265 -0
- package/template/modules/cart/src/public/CartPage.tsx +198 -0
- package/template/modules/cart/src/public/index.tsx +261 -0
- package/template/modules/cart/src/public/useQuote.ts +67 -0
- package/template/modules/cart/src/server.ts +148 -0
- package/template/modules/cart/src/types.ts +31 -0
- package/template/modules/checkout/screenshot.jpg +0 -0
- package/template/modules/checkout/snapify.module.json +264 -0
- package/template/modules/checkout/src/admin/OrderDetailPage.tsx +304 -0
- package/template/modules/checkout/src/admin/badges.tsx +28 -0
- package/template/modules/checkout/src/admin/index.tsx +236 -0
- package/template/modules/checkout/src/public/CheckoutPage.tsx +461 -0
- package/template/modules/checkout/src/public/OrderPages.tsx +153 -0
- package/template/modules/checkout/src/public/index.tsx +23 -0
- package/template/modules/checkout/src/server.ts +383 -0
- package/template/modules/checkout/src/types.ts +70 -0
- package/template/modules/customers/screenshot.jpg +0 -0
- package/template/modules/customers/snapify.module.json +115 -0
- package/template/modules/customers/src/admin/CustomerDetailPage.tsx +274 -0
- package/template/modules/customers/src/admin/index.tsx +194 -0
- package/template/modules/customers/src/public/AccountPages.tsx +470 -0
- package/template/modules/customers/src/public/AddressForm.tsx +115 -0
- package/template/modules/customers/src/public/AuthPages.tsx +349 -0
- package/template/modules/customers/src/public/Avatar.tsx +29 -0
- package/template/modules/customers/src/public/ProfileSection.tsx +291 -0
- package/template/modules/customers/src/public/index.tsx +137 -0
- package/template/modules/customers/src/public/session.ts +51 -0
- package/template/modules/customers/src/server.ts +421 -0
- package/template/modules/customers/src/types.ts +53 -0
- package/template/modules/recaptcha/logo.jpg +0 -0
- package/template/modules/recaptcha/screenshot.jpg +0 -0
- package/template/modules/recaptcha/snapify.module.json +99 -0
- package/template/modules/recaptcha/src/public/index.tsx +94 -0
- package/template/modules/recaptcha/src/server.ts +65 -0
- package/template/modules/recaptcha/src/types.ts +18 -0
- package/template/modules/shop/screenshot.jpg +0 -0
- package/template/modules/shop/snapify.module.json +340 -0
- package/template/modules/shop/src/admin/CategoriesPage.tsx +224 -0
- package/template/modules/shop/src/admin/ProductEditor.tsx +313 -0
- package/template/modules/shop/src/admin/ProductsPage.tsx +307 -0
- package/template/modules/shop/src/admin/index.tsx +14 -0
- package/template/modules/shop/src/public/Catalog.tsx +244 -0
- package/template/modules/shop/src/public/NotFound.tsx +22 -0
- package/template/modules/shop/src/public/ProductPage.tsx +195 -0
- package/template/modules/shop/src/public/index.tsx +134 -0
- package/template/modules/shop/src/public/useFetch.ts +26 -0
- package/template/modules/shop/src/server.ts +493 -0
- package/template/modules/shop/src/shared.ts +41 -0
- package/template/modules/shop/src/types.ts +60 -0
- package/template/modules/whatsapp/screenshot.jpg +0 -0
- package/template/modules/whatsapp/snapify.module.json +121 -0
- package/template/modules/whatsapp/src/public.tsx +119 -0
- package/template/modules/wp-seo-migrator/ARCHITECTURE.md +113 -0
- package/template/modules/wp-seo-migrator/README.md +21 -0
- package/template/modules/wp-seo-migrator/fixtures/aioseo-sample.csv +3 -0
- package/template/modules/wp-seo-migrator/fixtures/sample-exporter.json +39 -0
- package/template/modules/wp-seo-migrator/fixtures/sample-page.html +12 -0
- package/template/modules/wp-seo-migrator/fixtures/sample.htaccess +3 -0
- package/template/modules/wp-seo-migrator/screenshot.jpg +0 -0
- package/template/modules/wp-seo-migrator/snapify.module.json +87 -0
- package/template/modules/wp-seo-migrator/src/admin/HistoryPage.tsx +64 -0
- package/template/modules/wp-seo-migrator/src/admin/WizardPage.tsx +788 -0
- package/template/modules/wp-seo-migrator/src/admin/i18n.ts +156 -0
- package/template/modules/wp-seo-migrator/src/admin/index.tsx +11 -0
- package/template/modules/wp-seo-migrator/src/connectors/CUSTOM_CONNECTOR.md +31 -0
- package/template/modules/wp-seo-migrator/src/connectors/csvSeoFactory.ts +106 -0
- package/template/modules/wp-seo-migrator/src/connectors/exporter.ts +96 -0
- package/template/modules/wp-seo-migrator/src/connectors/gscCsv.ts +53 -0
- package/template/modules/wp-seo-migrator/src/connectors/htaccess.ts +65 -0
- package/template/modules/wp-seo-migrator/src/connectors/htmlCrawler.ts +90 -0
- package/template/modules/wp-seo-migrator/src/connectors/index.ts +113 -0
- package/template/modules/wp-seo-migrator/src/connectors/pluginCsv.ts +77 -0
- package/template/modules/wp-seo-migrator/src/connectors/rankMathCsv.ts +77 -0
- package/template/modules/wp-seo-migrator/src/connectors/redirection.ts +62 -0
- package/template/modules/wp-seo-migrator/src/connectors/sitemap.ts +44 -0
- package/template/modules/wp-seo-migrator/src/connectors/utils.ts +111 -0
- package/template/modules/wp-seo-migrator/src/connectors/wxr.ts +103 -0
- package/template/modules/wp-seo-migrator/src/connectors/yoastCsv.ts +56 -0
- package/template/modules/wp-seo-migrator/src/pipeline/analyze.ts +158 -0
- package/template/modules/wp-seo-migrator/src/pipeline/htmlParse.ts +58 -0
- package/template/modules/wp-seo-migrator/src/pipeline/remoteAuto.ts +328 -0
- package/template/modules/wp-seo-migrator/src/server.ts +492 -0
- package/template/modules/wp-seo-migrator/src/types.ts +151 -0
- package/template/modules/wp-seo-migrator/tests/connectors-extra.test.ts +39 -0
- package/template/modules/wp-seo-migrator/tests/merge.test.ts +25 -0
- package/template/package-lock.json +6016 -0
- package/template/package.json +74 -0
- package/template/public/images/photos/caravane-chameaux-desert.webp +0 -0
- package/template/public/images/photos/hammamet-medina-plage.jpg +0 -0
- package/template/public/images/photos/maison-campagne-collines.webp +0 -0
- package/template/public/images/photos/maisons-troglodytes-desert.jpg +0 -0
- package/template/public/images/photos/panorama-ville.jpg +0 -0
- package/template/public/images/photos/preveris-accessibilite-erp.jpg +0 -0
- package/template/public/images/photos/preveris-collectivites.jpg +0 -0
- package/template/public/images/photos/preveris-etudes-plans.jpg +0 -0
- package/template/public/images/photos/preveris-hero-erp.jpg +0 -0
- package/template/public/images/photos/preveris-ssi-incendie.jpg +0 -0
- package/template/public/images/photos/preveris-suivi-hotel.jpg +0 -0
- package/template/public/images/photos/ruelle-bleue-medina.jpg +0 -0
- package/template/public/images/photos/sidi-bou-said-port.webp +0 -0
- package/template/public/images/photos/terrasse-blanche-mer-voilier.jpg +0 -0
- package/template/public/landing/hero-ai-cms.jpg +0 -0
- package/template/public/landing/shot-dogga.jpg +0 -0
- package/template/public/landing/shot-mahdia.jpg +0 -0
- package/template/public/landing/shot-sidibou.jpg +0 -0
- package/template/public/llms.txt +35 -0
- package/template/public/logo.svg +10 -0
- package/template/scripts/app-pack.ts +155 -0
- package/template/scripts/app-publish.ts +123 -0
- package/template/scripts/apply-ecommerce-home.ts +196 -0
- package/template/scripts/auto-deploy-poll.sh +13 -0
- package/template/scripts/db-backup.sh +16 -0
- package/template/scripts/db-restore.sh +11 -0
- package/template/scripts/deploy.sh +34 -0
- package/template/scripts/github-webhook-deploy.sh +7 -0
- package/template/scripts/install-new-modules.ts +96 -0
- package/template/scripts/refresh-demo-baseline.ts +9 -0
- package/template/scripts/reinstall-marketplace-packs.ts +51 -0
- package/template/scripts/restore-classic-home.ts +13 -0
- package/template/scripts/sdk-pack.ts +289 -0
- package/template/scripts/sdk-publish.ts +75 -0
- package/template/scripts/seed-demo-products.ts +120 -0
- package/template/scripts/seed-theme-content-packs.ts +42 -0
- package/template/scripts/snapify-module.ts +207 -0
- package/template/scripts/test-theme-switch.ts +24 -0
- package/template/sdk/admin.css +18 -0
- package/template/sdk/admin.ts +95 -0
- package/template/sdk/build.ts +249 -0
- package/template/sdk/commerce.ts +512 -0
- package/template/sdk/content.ts +76 -0
- package/template/sdk/icons.ts +101 -0
- package/template/sdk/image.ts +60 -0
- package/template/sdk/index.ts +500 -0
- package/template/sdk/package.ts +298 -0
- package/template/sdk/recaptcha.tsx +122 -0
- package/template/sdk/settings.ts +84 -0
- package/template/sdk/theme.css +29 -0
- package/template/sdk/theme.ts +100 -0
- package/template/sdk/ui/commerce.tsx +385 -0
- package/template/sdk/ui/orders.tsx +136 -0
- package/template/sdk-kit/CHANGELOG.md +17 -0
- package/template/sdk-kit/LICENSE.md +47 -0
- package/template/sdk-kit/README.md +81 -0
- package/template/sdk-kit/cli.ts +339 -0
- package/template/sdk-kit/create-snapify/README.md +28 -0
- package/template/sdk-kit/create-snapify/create-snapify.mjs +11 -0
- package/template/sdk-kit/create-snapify/package.template.json +16 -0
- package/template/sdk-kit/package.template.json +95 -0
- package/template/sdk-kit/templates/common/README.md.tpl +27 -0
- package/template/sdk-kit/templates/common/_gitignore +3 -0
- package/template/sdk-kit/templates/common/package.json.tpl +19 -0
- package/template/sdk-kit/templates/common/src/snapify-env.d.ts +2 -0
- package/template/sdk-kit/templates/common/tsconfig.json +15 -0
- package/template/sdk-kit/templates/module/snapify.module.json.tpl +33 -0
- package/template/sdk-kit/templates/module/src/admin.tsx +53 -0
- package/template/sdk-kit/templates/module/src/public.tsx +49 -0
- package/template/sdk-kit/templates/module/src/server.ts +30 -0
- package/template/sdk-kit/templates/module/src/types.ts +19 -0
- package/template/sdk-kit/templates/theme/snapify.theme.json.tpl +22 -0
- package/template/sdk-kit/templates/theme/src/Footer.tsx +40 -0
- package/template/sdk-kit/templates/theme/src/Header.tsx +47 -0
- package/template/sdk-kit/templates/theme/src/Views.tsx +36 -0
- package/template/sdk-kit/templates/theme/src/blocks.tsx +93 -0
- package/template/sdk-kit/templates/theme/src/index.tsx +30 -0
- package/template/sdk-kit/templates/theme/src/site.tsx +59 -0
- package/template/sdk-kit/templates/theme/src/styles.css +71 -0
- package/template/server/client/routes.ts +252 -0
- package/template/server/cms/analyticsStore.ts +180 -0
- package/template/server/cms/auth.ts +155 -0
- package/template/server/cms/blockCatalog.ts +342 -0
- package/template/server/cms/blocks.ts +521 -0
- package/template/server/cms/contentMigration.ts +1119 -0
- package/template/server/cms/defaults.ts +303 -0
- package/template/server/cms/permissions.ts +154 -0
- package/template/server/cms/restoreClassicHome.ts +183 -0
- package/template/server/cms/revisions.ts +99 -0
- package/template/server/cms/scheduler.ts +78 -0
- package/template/server/cms/seed.ts +72 -0
- package/template/server/cms/seoAnalyzer.ts +213 -0
- package/template/server/cms/store.ts +122 -0
- package/template/server/cms/themeContent.ts +1386 -0
- package/template/server/cms/themePacks/sidibou-branding.json +1 -0
- package/template/server/cms/themePacks/sidibou-home.json +1 -0
- package/template/server/cms/themePacks/sidibou-menus.json +1 -0
- package/template/server/cms/types.ts +432 -0
- package/template/server/community/routes.ts +410 -0
- package/template/server/db/client.ts +43 -0
- package/template/server/db/repository.ts +389 -0
- package/template/server/db/schema.ts +726 -0
- package/template/server/demo/cmsReset.ts +196 -0
- package/template/server/developers/sdk.ts +85 -0
- package/template/server/geoip.ts +15 -0
- package/template/server/http.ts +53 -0
- package/template/server/mail.ts +216 -0
- package/template/server/marketplace/catalog.ts +74 -0
- package/template/server/marketplace/packageValidate.ts +475 -0
- package/template/server/marketplace/payments.ts +193 -0
- package/template/server/marketplace/routes.ts +850 -0
- package/template/server/marketplace/signing.ts +116 -0
- package/template/server/marketplace/syncOfficial.ts +282 -0
- package/template/server/media/images.ts +63 -0
- package/template/server/middleware/adminAuth.ts +134 -0
- package/template/server/modules/legacy.ts +44 -0
- package/template/server/modules/manager.ts +1122 -0
- package/template/server/modules/marketplace.ts +178 -0
- package/template/server/modules/outbound.ts +178 -0
- package/template/server/modules/purchases.ts +149 -0
- package/template/server/modules/records.ts +168 -0
- package/template/server/modules/themeHtml.ts +32 -0
- package/template/server/modules/trust.ts +16 -0
- package/template/server/modules/types.ts +147 -0
- package/template/server/platform/auth.ts +223 -0
- package/template/server/platform/clientWelcome.ts +168 -0
- package/template/server/platform/clients.ts +139 -0
- package/template/server/platform/dailyImprove.ts +356 -0
- package/template/server/platform/flouci.ts +126 -0
- package/template/server/platform/host.ts +69 -0
- package/template/server/platform/hostingProviders.ts +143 -0
- package/template/server/platform/licenseOrders.ts +291 -0
- package/template/server/platform/money.ts +42 -0
- package/template/server/platform/passwords.ts +41 -0
- package/template/server/platform/region.ts +86 -0
- package/template/server/platform/routes.ts +225 -0
- package/template/server/platform/seed.ts +82 -0
- package/template/server/platform/settings.ts +72 -0
- package/template/server/routes/adminAccount.ts +403 -0
- package/template/server/routes/adminCms.ts +808 -0
- package/template/server/routes/adminSystem.ts +243 -0
- package/template/server/routes/adminUsers.ts +449 -0
- package/template/server/routes/googleOAuth.ts +327 -0
- package/template/server/routes/modules.ts +323 -0
- package/template/server/routes/publicCms.ts +313 -0
- package/template/server/routes/seoPublic.ts +158 -0
- package/template/server/security/accounts.ts +121 -0
- package/template/server/security/audit.ts +143 -0
- package/template/server/security/authTokens.ts +74 -0
- package/template/server/security/ip.ts +68 -0
- package/template/server/security/rateLimit.ts +85 -0
- package/template/server/security/retention.ts +46 -0
- package/template/server/security/secrets.ts +44 -0
- package/template/server/security/sessions.ts +140 -0
- package/template/server/security/totp.ts +101 -0
- package/template/server/superadmin/analytics.ts +109 -0
- package/template/server/superadmin/auth.ts +92 -0
- package/template/server/superadmin/backlinksCatalog.ts +210 -0
- package/template/server/superadmin/frSeoContent.ts +165 -0
- package/template/server/superadmin/landingSeo.ts +675 -0
- package/template/server/superadmin/ops.ts +238 -0
- package/template/server/superadmin/routes.ts +1095 -0
- package/template/server/superadmin/tnSeoContent.ts +130 -0
- package/template/server.ts +522 -0
- package/template/src/App.tsx +263 -0
- package/template/src/admin/AdminApp.tsx +162 -0
- package/template/src/admin/account/AuthLayout.tsx +57 -0
- package/template/src/admin/account/SecurityForms.tsx +276 -0
- package/template/src/admin/admin.css +127 -0
- package/template/src/admin/context/AuthContext.tsx +147 -0
- package/template/src/admin/context/SiteContext.tsx +50 -0
- package/template/src/admin/editor/BlockLibrary.tsx +173 -0
- package/template/src/admin/editor/BlocksPanel.tsx +396 -0
- package/template/src/admin/editor/EditorBits.tsx +106 -0
- package/template/src/admin/editor/PreviewFrame.tsx +145 -0
- package/template/src/admin/editor/RichTextEditor.tsx +276 -0
- package/template/src/admin/editor/SeoPanel.tsx +349 -0
- package/template/src/admin/editor/StyleEditor.tsx +114 -0
- package/template/src/admin/editor/blockSchemas.ts +699 -0
- package/template/src/admin/editor/fields.tsx +486 -0
- package/template/src/admin/layout/AdminShell.tsx +418 -0
- package/template/src/admin/layout/nav.ts +95 -0
- package/template/src/admin/lib/api.ts +408 -0
- package/template/src/admin/lib/audit.ts +141 -0
- package/template/src/admin/lib/format.ts +84 -0
- package/template/src/admin/lib/hooks.ts +125 -0
- package/template/src/admin/main.tsx +16 -0
- package/template/src/admin/modules/InstallDialog.tsx +160 -0
- package/template/src/admin/modules/SettingsForm.tsx +145 -0
- package/template/src/admin/modules/kit.tsx +127 -0
- package/template/src/admin/modules/labels.tsx +226 -0
- package/template/src/admin/pages/AccountSetupPage.tsx +62 -0
- package/template/src/admin/pages/AnalyticsPage.tsx +206 -0
- package/template/src/admin/pages/BrandingPage.tsx +154 -0
- package/template/src/admin/pages/DashboardPage.tsx +239 -0
- package/template/src/admin/pages/EngagementPage.tsx +168 -0
- package/template/src/admin/pages/FormsPage.tsx +435 -0
- package/template/src/admin/pages/GeneralPage.tsx +120 -0
- package/template/src/admin/pages/LoginPage.tsx +249 -0
- package/template/src/admin/pages/MaintenancePage.tsx +125 -0
- package/template/src/admin/pages/MarketplacePage.tsx +426 -0
- package/template/src/admin/pages/MediaPage.tsx +251 -0
- package/template/src/admin/pages/MenusPage.tsx +446 -0
- package/template/src/admin/pages/ModuleAdminPage.tsx +113 -0
- package/template/src/admin/pages/ModuleDetailPage.tsx +293 -0
- package/template/src/admin/pages/ModulesPage.tsx +135 -0
- package/template/src/admin/pages/NewsletterPage.tsx +193 -0
- package/template/src/admin/pages/PageEditorPage.tsx +322 -0
- package/template/src/admin/pages/PagesListPage.tsx +277 -0
- package/template/src/admin/pages/PostEditorPage.tsx +292 -0
- package/template/src/admin/pages/PostsListPage.tsx +187 -0
- package/template/src/admin/pages/ProfilePage.tsx +489 -0
- package/template/src/admin/pages/ResetPasswordPage.tsx +110 -0
- package/template/src/admin/pages/SeoPage.tsx +670 -0
- package/template/src/admin/pages/SettingsPage.tsx +189 -0
- package/template/src/admin/pages/ThemeCustomizePage.tsx +170 -0
- package/template/src/admin/pages/ThemesPage.tsx +292 -0
- package/template/src/admin/pages/UsersPage.tsx +57 -0
- package/template/src/admin/pages/WidgetsPage.tsx +200 -0
- package/template/src/admin/seo/GoogleSetup.tsx +529 -0
- package/template/src/admin/settings/EmailTab.tsx +293 -0
- package/template/src/admin/settings/OtherTabs.tsx +270 -0
- package/template/src/admin/settings/SecurityTab.tsx +172 -0
- package/template/src/admin/settings/controls.tsx +133 -0
- package/template/src/admin/ui/Pagination.tsx +170 -0
- package/template/src/admin/ui/SaveBar.tsx +77 -0
- package/template/src/admin/ui/TagInput.tsx +54 -0
- package/template/src/admin/ui/charts.tsx +108 -0
- package/template/src/admin/ui/media.tsx +265 -0
- package/template/src/admin/ui/overlays.tsx +239 -0
- package/template/src/admin/ui/primitives.tsx +544 -0
- package/template/src/admin/users/AuditTab.tsx +104 -0
- package/template/src/admin/users/RolesTab.tsx +368 -0
- package/template/src/admin/users/UsersTab.tsx +723 -0
- package/template/src/admin/users/shared.tsx +278 -0
- package/template/src/cms/icons.ts +7 -0
- package/template/src/components/CookieBanner.tsx +166 -0
- package/template/src/components/MaintenanceGate.tsx +66 -0
- package/template/src/components/SiteAnalytics.tsx +64 -0
- package/template/src/components/SnapifyLogo.tsx +44 -0
- package/template/src/components/cms/BlockRenderer.tsx +154 -0
- package/template/src/components/cms/WidgetArea.tsx +193 -0
- package/template/src/context/SiteConfigContext.tsx +130 -0
- package/template/src/demoBase.ts +23 -0
- package/template/src/index.css +90 -0
- package/template/src/main.tsx +16 -0
- package/template/src/modules/ModuleHost.tsx +197 -0
- package/template/src/preview.ts +63 -0
- package/template/src/runtime.ts +38 -0
- package/template/src/themes/ThemeHost.tsx +168 -0
- package/template/src/themes/fallback.tsx +71 -0
- package/template/src/types.ts +94 -0
- package/template/src/views/BlogPostView.tsx +68 -0
- package/template/src/views/CmsPageView.tsx +34 -0
- package/template/start-pm2.sh +3 -0
- package/template/superadmin.html +20 -0
- package/template/themes/ai-canvas/screenshot.jpg +0 -0
- package/template/themes/ai-canvas/snapify.theme.json +96 -0
- package/template/themes/ai-canvas/src/CeeSimulator.tsx +247 -0
- package/template/themes/ai-canvas/src/Footer.tsx +190 -0
- package/template/themes/ai-canvas/src/Header.tsx +324 -0
- package/template/themes/ai-canvas/src/Layout.tsx +56 -0
- package/template/themes/ai-canvas/src/NotFound.tsx +58 -0
- package/template/themes/ai-canvas/src/Post.tsx +26 -0
- package/template/themes/ai-canvas/src/SnapifyLogo.tsx +44 -0
- package/template/themes/ai-canvas/src/blocks/CollectionBlocks.tsx +711 -0
- package/template/themes/ai-canvas/src/blocks/ContentBlocks.tsx +318 -0
- package/template/themes/ai-canvas/src/blocks/ConversionBlocks.tsx +559 -0
- package/template/themes/ai-canvas/src/blocks/HeaderBlocks.tsx +341 -0
- package/template/themes/ai-canvas/src/index.tsx +54 -0
- package/template/themes/ai-canvas/src/kit.tsx +398 -0
- package/template/themes/ai-canvas/src/site.ts +29 -0
- package/template/themes/ai-canvas/src/styles.css +317 -0
- package/template/themes/dogga/screenshot.jpg +0 -0
- package/template/themes/dogga/snapify.theme.json +55 -0
- package/template/themes/dogga/src/Brand.tsx +41 -0
- package/template/themes/dogga/src/Footer.tsx +202 -0
- package/template/themes/dogga/src/Header.tsx +239 -0
- package/template/themes/dogga/src/Layout.tsx +43 -0
- package/template/themes/dogga/src/Views.tsx +71 -0
- package/template/themes/dogga/src/blocks/CollectionBlocks.tsx +674 -0
- package/template/themes/dogga/src/blocks/ContentBlocks.tsx +307 -0
- package/template/themes/dogga/src/blocks/ConversionBlocks.tsx +571 -0
- package/template/themes/dogga/src/blocks/HeaderBlocks.tsx +289 -0
- package/template/themes/dogga/src/index.tsx +53 -0
- package/template/themes/dogga/src/kit.tsx +362 -0
- package/template/themes/dogga/src/site.ts +56 -0
- package/template/themes/dogga/src/styles.css +396 -0
- package/template/themes/mahdia/screenshot.jpg +0 -0
- package/template/themes/mahdia/snapify.theme.json +65 -0
- package/template/themes/mahdia/src/Brand.tsx +39 -0
- package/template/themes/mahdia/src/Footer.tsx +210 -0
- package/template/themes/mahdia/src/Header.tsx +291 -0
- package/template/themes/mahdia/src/Layout.tsx +44 -0
- package/template/themes/mahdia/src/Views.tsx +79 -0
- package/template/themes/mahdia/src/blocks/CollectionBlocks.tsx +674 -0
- package/template/themes/mahdia/src/blocks/ContentBlocks.tsx +307 -0
- package/template/themes/mahdia/src/blocks/ConversionBlocks.tsx +571 -0
- package/template/themes/mahdia/src/blocks/HeaderBlocks.tsx +289 -0
- package/template/themes/mahdia/src/index.tsx +53 -0
- package/template/themes/mahdia/src/kit.tsx +362 -0
- package/template/themes/mahdia/src/site.ts +75 -0
- package/template/themes/mahdia/src/styles.css +446 -0
- package/template/themes/preveris/screenshot.jpg +0 -0
- package/template/themes/preveris/snapify.theme.json +126 -0
- package/template/themes/preveris/src/Brand.tsx +44 -0
- package/template/themes/preveris/src/Footer.tsx +202 -0
- package/template/themes/preveris/src/Header.tsx +239 -0
- package/template/themes/preveris/src/Layout.tsx +42 -0
- package/template/themes/preveris/src/Views.tsx +71 -0
- package/template/themes/preveris/src/blocks/CollectionBlocks.tsx +678 -0
- package/template/themes/preveris/src/blocks/ContentBlocks.tsx +307 -0
- package/template/themes/preveris/src/blocks/ConversionBlocks.tsx +571 -0
- package/template/themes/preveris/src/blocks/HeaderBlocks.tsx +299 -0
- package/template/themes/preveris/src/index.tsx +53 -0
- package/template/themes/preveris/src/kit.tsx +365 -0
- package/template/themes/preveris/src/site.ts +79 -0
- package/template/themes/preveris/src/styles.css +446 -0
- package/template/themes/sidibou/screenshot.jpg +0 -0
- package/template/themes/sidibou/snapify.theme.json +21 -0
- package/template/themes/sidibou/src/CeeSimulator.tsx +247 -0
- package/template/themes/sidibou/src/Footer.tsx +203 -0
- package/template/themes/sidibou/src/Header.tsx +324 -0
- package/template/themes/sidibou/src/Layout.tsx +53 -0
- package/template/themes/sidibou/src/NotFound.tsx +58 -0
- package/template/themes/sidibou/src/Post.tsx +26 -0
- package/template/themes/sidibou/src/SnapifyLogo.tsx +44 -0
- package/template/themes/sidibou/src/blocks/CollectionBlocks.tsx +711 -0
- package/template/themes/sidibou/src/blocks/ContentBlocks.tsx +318 -0
- package/template/themes/sidibou/src/blocks/ConversionBlocks.tsx +559 -0
- package/template/themes/sidibou/src/blocks/HeaderBlocks.tsx +341 -0
- package/template/themes/sidibou/src/index.tsx +54 -0
- package/template/themes/sidibou/src/kit.tsx +398 -0
- package/template/themes/sidibou/src/site.ts +28 -0
- package/template/themes/sidibou/src/styles.css +317 -0
- package/template/tsconfig.json +33 -0
- package/template/vite.config.ts +42 -0
|
@@ -0,0 +1,1119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapify
|
|
3
|
+
* © 2026 NOVALABS WEB DESIGN — Tunisie
|
|
4
|
+
* Contact : contact@novalabs.tn · +216 24 734 647
|
|
5
|
+
* Tous droits réservés. Toute reproduction, modification ou diffusion sans autorisation écrite est interdite.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Migration v2 : toutes les pages du site passent en blocs éditables depuis le backoffice.
|
|
9
|
+
* Reprend à l'identique le contenu des anciennes vues React (accueil, expertises, secteurs,
|
|
10
|
+
* réalisations, approche, contact, merci, pages légales) et crée les sous-pages manquantes.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
import type { BlockDataMap, BlockKind, BlockStyle, ButtonData, ProjectMeta } from './blocks';
|
|
16
|
+
import { button, uid } from './blocks';
|
|
17
|
+
import { BLOCK_CATALOG, isBlockKind } from './blockCatalog';
|
|
18
|
+
import type { CmsBlock, CmsPage, CmsSnapshot, ContactFormField, PageTemplate } from './types';
|
|
19
|
+
import { cmsNow, defaultSeoForPath } from './defaults';
|
|
20
|
+
import { CEE_SHEETS, EXPERTISES, FAQ_HOME, METHODE_STEPS, REALISATIONS, SECTEURS } from '../../src/data/siteData';
|
|
21
|
+
|
|
22
|
+
export const CONTENT_VERSION = 2;
|
|
23
|
+
|
|
24
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const PUBLIC_DIR = path.resolve(__dirname, '../../public');
|
|
26
|
+
|
|
27
|
+
/* ------------------------------------------------------------------ Aides */
|
|
28
|
+
|
|
29
|
+
function b<K extends BlockKind>(type: K, data: Partial<BlockDataMap[K]>, style: Partial<BlockStyle> = {}): CmsBlock {
|
|
30
|
+
return { id: uid('b'), type, data: { ...BLOCK_CATALOG[type].defaults(), ...data } as unknown as Record<string, unknown>, style };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const phoneButton = (variant: ButtonData['variant'] = 'secondary'): ButtonData => button('{{telephone}}', 'tel:{{telephoneLien}}', variant, 'phone');
|
|
34
|
+
const contactButton = (label = 'Parler de votre projet'): ButtonData => button(label, '/contact/');
|
|
35
|
+
|
|
36
|
+
const finalCta = (title: string, highlight: string, text: string, withPhone = true) =>
|
|
37
|
+
b('cta', {
|
|
38
|
+
variant: 'dark',
|
|
39
|
+
layout: 'centered',
|
|
40
|
+
title,
|
|
41
|
+
highlight,
|
|
42
|
+
text,
|
|
43
|
+
buttons: withPhone ? [contactButton(), phoneButton()] : [contactButton()],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const EXPERTISE_ICONS: Record<string, string> = {
|
|
47
|
+
froid: 'snowflake',
|
|
48
|
+
'recuperation-de-chaleur': 'flame',
|
|
49
|
+
'chauffage-traitement-air': 'wind',
|
|
50
|
+
'gtb-gtc': 'cpu',
|
|
51
|
+
'isolation-technique': 'shieldCheck',
|
|
52
|
+
'reglementation-cee': 'fileCheck',
|
|
53
|
+
};
|
|
54
|
+
const EXPERTISE_IMAGES: Record<string, string> = {
|
|
55
|
+
froid: '/images/photos/panorama-ville.jpg',
|
|
56
|
+
'recuperation-de-chaleur': '/images/photos/ruelle-bleue-medina.jpg',
|
|
57
|
+
'chauffage-traitement-air': '/images/photos/maison-campagne-collines.webp',
|
|
58
|
+
'gtb-gtc': '/images/photos/maison-campagne-collines.webp',
|
|
59
|
+
'isolation-technique': '/images/photos/ruelle-bleue-medina.jpg',
|
|
60
|
+
'reglementation-cee': '/images/photos/terrasse-blanche-mer-voilier.jpg',
|
|
61
|
+
};
|
|
62
|
+
const SECTOR_ICONS: Record<string, string> = { industrie: 'factory', tertiaire: 'building', 'residentiel-collectif': 'home' };
|
|
63
|
+
|
|
64
|
+
/* ------------------------------------------------------------------ Accueil */
|
|
65
|
+
|
|
66
|
+
function homeBlocks(): CmsBlock[] {
|
|
67
|
+
return [
|
|
68
|
+
b(
|
|
69
|
+
'hero',
|
|
70
|
+
{
|
|
71
|
+
layout: 'split',
|
|
72
|
+
badgeTag: 'CEE',
|
|
73
|
+
badgeText: 'Travaux finançables par les CEE · montage de A à Z',
|
|
74
|
+
title: 'Réduisez durablement la facture énergétique de vos',
|
|
75
|
+
rotatingWords: ['groupes froids.', 'chaufferies.', 'process industriels.', 'bâtiments.'],
|
|
76
|
+
subtitle:
|
|
77
|
+
"Industrie, tertiaire, résidentiel collectif : nous auditons, installons et mesurons les économies de vos installations. Preuves à l'appui, contrôle COFRAC à la clé.",
|
|
78
|
+
buttons: [contactButton(), button('Voir nos réalisations', '/realisations/', 'secondary', 'none')],
|
|
79
|
+
liveText: "Réponse d'un ingénieur sous {{delai}}",
|
|
80
|
+
trustItems: ['RGE Ventilation+', 'RGE Qualisol', 'SOCOTEC Cat. I'],
|
|
81
|
+
media: 'composition',
|
|
82
|
+
mainImage: '/images/photos/ruelle-bleue-medina.jpg',
|
|
83
|
+
mainImageAlt: 'Réseau électrique, éoliennes et panneaux solaires au coucher du soleil',
|
|
84
|
+
secondaryImage: '/images/photos/hammamet-medina-plage.jpg',
|
|
85
|
+
secondaryImageAlt: 'Ingénieure Snapify sur chantier',
|
|
86
|
+
secondaryCaption: 'Nos équipes sur site',
|
|
87
|
+
statValue: "jusqu'à -35 %",
|
|
88
|
+
statLabel: 'sur la consommation des groupes froids',
|
|
89
|
+
badgeCardTitle: 'Contrôle COFRAC',
|
|
90
|
+
badgeCardText: 'systématique après travaux',
|
|
91
|
+
chipText: '01 Conseil · 02 Ingénierie · 03 Suivi',
|
|
92
|
+
parallax: true,
|
|
93
|
+
marquee: ['Intermarché', 'Colorcon', 'Carrefour Market', 'CEDIM', 'Contrôle COFRAC', 'Fiches CEE', 'Décret BACS', 'Décret Tertiaire'],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
background: 'image',
|
|
97
|
+
backgroundImage: '/images/photos/terrasse-blanche-mer-voilier.jpg',
|
|
98
|
+
overlayTone: 'light',
|
|
99
|
+
overlay: 55,
|
|
100
|
+
decor: 'none',
|
|
101
|
+
paddingTop: 'sm',
|
|
102
|
+
paddingBottom: 'lg',
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
b(
|
|
106
|
+
'projects',
|
|
107
|
+
{
|
|
108
|
+
eyebrow: 'Preuves de terrain',
|
|
109
|
+
title: 'Nos réalisations,',
|
|
110
|
+
highlight: 'résultats mesurés.',
|
|
111
|
+
intro: 'Grande distribution, industrie pharmaceutique, plateformes logistiques : des chantiers réels, en site exploité.',
|
|
112
|
+
headerLinkLabel: 'Toutes nos réalisations',
|
|
113
|
+
headerLink: '/realisations/',
|
|
114
|
+
layout: 'featured',
|
|
115
|
+
showFilters: false,
|
|
116
|
+
limit: 4,
|
|
117
|
+
},
|
|
118
|
+
{ background: 'surface', decor: 'dots' }
|
|
119
|
+
),
|
|
120
|
+
b(
|
|
121
|
+
'cta',
|
|
122
|
+
{
|
|
123
|
+
variant: 'gradient',
|
|
124
|
+
layout: 'split',
|
|
125
|
+
eyebrow: 'Éligibilité CEE',
|
|
126
|
+
title: 'Vos travaux sont peut-être déjà financés.',
|
|
127
|
+
highlight: 'Vérifions-le ensemble.',
|
|
128
|
+
buttons: [button("Étude d'éligibilité gratuite", '/contact/', 'dark'), phoneButton('glass')],
|
|
129
|
+
image: '/images/photos/terrasse-blanche-mer-voilier.jpg',
|
|
130
|
+
imageAlt: 'Centrale solaire au coucher du soleil',
|
|
131
|
+
imageCaption: "De l'étude au chantier",
|
|
132
|
+
},
|
|
133
|
+
{ background: 'white', paddingTop: 'sm', paddingBottom: 'sm' }
|
|
134
|
+
),
|
|
135
|
+
b(
|
|
136
|
+
'cards',
|
|
137
|
+
{
|
|
138
|
+
eyebrow: 'Vos enjeux, nos réponses',
|
|
139
|
+
title: 'Vos consommations sont un coût.',
|
|
140
|
+
highlight: 'Elles deviennent une obligation.',
|
|
141
|
+
style: 'hoverDark',
|
|
142
|
+
columns: 2,
|
|
143
|
+
textPrefix: 'Réponse Snapify —',
|
|
144
|
+
items: [
|
|
145
|
+
{
|
|
146
|
+
id: uid('c'),
|
|
147
|
+
icon: 'trendingDown',
|
|
148
|
+
title: 'Des factures énergétiques trop élevées',
|
|
149
|
+
text: 'Nous identifions vos postes les plus consommateurs (froid, chauffage, process) et engageons les actions au meilleur retour sur investissement.',
|
|
150
|
+
tags: [],
|
|
151
|
+
linkLabel: 'Voir les solutions',
|
|
152
|
+
link: '/expertises/',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: uid('c'),
|
|
156
|
+
icon: 'shieldAlert',
|
|
157
|
+
title: 'Des obligations réglementaires (Décrets Tertiaire & BACS)',
|
|
158
|
+
text: 'Nous vous aidons à atteindre vos objectifs et à sécuriser votre conformité sans perturber vos exploitations.',
|
|
159
|
+
tags: [],
|
|
160
|
+
linkLabel: 'Comprendre les décrets',
|
|
161
|
+
link: '/expertises/reglementation-cee/',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
id: uid('c'),
|
|
165
|
+
icon: 'wrench',
|
|
166
|
+
title: 'Des installations techniques vieillissantes',
|
|
167
|
+
text: 'Groupes froids, chaufferies fioul, réseaux mal isolés : nous modernisons vos équipements sans interrompre votre activité.',
|
|
168
|
+
tags: [],
|
|
169
|
+
linkLabel: 'Nos technologies',
|
|
170
|
+
link: '/expertises/',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: uid('c'),
|
|
174
|
+
icon: 'badgePercent',
|
|
175
|
+
title: 'Un budget travaux à financer',
|
|
176
|
+
text: 'Nous montons et valorisons vos dossiers CEE pour réduire le reste à charge de vos travaux au strict minimum.',
|
|
177
|
+
tags: [],
|
|
178
|
+
linkLabel: 'Voir le montage CEE',
|
|
179
|
+
link: '/expertises/reglementation-cee/',
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{ background: 'white', decor: 'rings', paddingTop: 'sm' }
|
|
184
|
+
),
|
|
185
|
+
b(
|
|
186
|
+
'showcase',
|
|
187
|
+
{
|
|
188
|
+
eyebrow: 'Nos expertises',
|
|
189
|
+
title: 'Froid, chaleur, pilotage, isolation :',
|
|
190
|
+
highlight: 'agir sur chaque kWh.',
|
|
191
|
+
headerLinkLabel: 'Toutes les expertises',
|
|
192
|
+
headerLink: '/expertises/',
|
|
193
|
+
interval: 6,
|
|
194
|
+
items: EXPERTISES.map((e) => ({
|
|
195
|
+
id: uid('sh'),
|
|
196
|
+
icon: EXPERTISE_ICONS[e.slug],
|
|
197
|
+
title: e.title,
|
|
198
|
+
text: e.shortDesc,
|
|
199
|
+
image: EXPERTISE_IMAGES[e.slug],
|
|
200
|
+
chips: e.solutions.slice(0, 4).map((s) => s.title),
|
|
201
|
+
buttonLabel: "Découvrir l'expertise",
|
|
202
|
+
link: `/expertises/${e.slug}/`,
|
|
203
|
+
})),
|
|
204
|
+
},
|
|
205
|
+
{ background: 'soft', decor: 'diagonal', borderTop: true }
|
|
206
|
+
),
|
|
207
|
+
b(
|
|
208
|
+
'simulator',
|
|
209
|
+
{ eyebrow: 'Simulateur', title: 'Estimez votre potentiel', highlight: 'en quelques clics.', align: 'center' },
|
|
210
|
+
{ background: 'white', decor: 'grid', paddingBottom: 'md' }
|
|
211
|
+
),
|
|
212
|
+
b(
|
|
213
|
+
'steps',
|
|
214
|
+
{
|
|
215
|
+
eyebrow: 'Notre méthode',
|
|
216
|
+
title: '4 étapes,',
|
|
217
|
+
highlight: 'un livrable à chacune.',
|
|
218
|
+
align: 'center',
|
|
219
|
+
style: 'timeline',
|
|
220
|
+
deliverableLabel: 'Document remis',
|
|
221
|
+
items: METHODE_STEPS.map((s) => ({ id: uid('st'), num: s.num, title: s.title, text: s.description, deliverable: s.deliverable })),
|
|
222
|
+
buttons: [contactButton(), button('Découvrir notre approche complète', '/notre-approche/', 'link')],
|
|
223
|
+
},
|
|
224
|
+
{ background: 'soft', decor: 'dots', borderTop: true }
|
|
225
|
+
),
|
|
226
|
+
b(
|
|
227
|
+
'gallery',
|
|
228
|
+
{
|
|
229
|
+
eyebrow: 'Sur le terrain',
|
|
230
|
+
title: 'Des installations réelles,',
|
|
231
|
+
highlight: 'photographiées sur site.',
|
|
232
|
+
intro: "Le monde de l'énergie tel qu'il est vraiment : installations, réseaux et équipements photographiés sur le terrain.",
|
|
233
|
+
style: 'polaroid',
|
|
234
|
+
handNote: 'faites défiler →',
|
|
235
|
+
note: "Photos de chantiers Snapify et illustrations techniques d'installations réelles (Wikimedia Commons, licences CC BY / CC BY-SA / CC0).",
|
|
236
|
+
items: [
|
|
237
|
+
['terrasse-blanche-mer-voilier.jpg', 'Centrale solaire au couchant'],
|
|
238
|
+
['ruelle-bleue-medina.jpg', 'Réseau, nucléaire & renouvelables'],
|
|
239
|
+
['sidi-bou-said-port.webp', 'Éolien, solaire & réseau électrique'],
|
|
240
|
+
['panorama-ville.jpg', 'Meubles froids — grande distribution'],
|
|
241
|
+
['terrasse-blanche-mer-voilier.jpg', 'Réseaux & transition énergétique'],
|
|
242
|
+
['caravane-chameaux-desert.webp', 'Parc éolien en montagne'],
|
|
243
|
+
['maison-campagne-collines.webp', 'Supervision GTB en exploitation'],
|
|
244
|
+
['maisons-troglodytes-desert.jpg', 'Ferme solaire & éolienne'],
|
|
245
|
+
['ruelle-bleue-medina.jpg', 'Éolienne au coucher du soleil'],
|
|
246
|
+
['hammamet-medina-plage.jpg', 'Sobriété — relamping LED'],
|
|
247
|
+
['maisons-troglodytes-desert.jpg', 'Le mix énergétique en mutation'],
|
|
248
|
+
['caravane-chameaux-desert.webp', 'Autoproduction solaire'],
|
|
249
|
+
].map(([file, caption]) => ({ id: uid('g'), image: `/images/photos/${file}`, caption })),
|
|
250
|
+
},
|
|
251
|
+
{ background: 'white', paddingBottom: 'md' }
|
|
252
|
+
),
|
|
253
|
+
b(
|
|
254
|
+
'cta',
|
|
255
|
+
{
|
|
256
|
+
variant: 'dark',
|
|
257
|
+
layout: 'split',
|
|
258
|
+
badge: 'Échéance dans {{ans2030}}',
|
|
259
|
+
title: 'Décret Tertiaire & BACS : votre site est-il prêt ?',
|
|
260
|
+
text: '-40 % en 2030, -50 % en 2040, -60 % en 2050. GTB obligatoire au-delà de 290 kW, puis 70 kW en 2030.',
|
|
261
|
+
bigNumber: '-40%',
|
|
262
|
+
bigNumberLabel: 'de consommation',
|
|
263
|
+
bigNumberStrong: 'exigés en 2030',
|
|
264
|
+
backgroundImage: '/images/photos/maisons-troglodytes-desert.jpg',
|
|
265
|
+
buttons: [button('Vérifier ma conformité', '/expertises/reglementation-cee/')],
|
|
266
|
+
},
|
|
267
|
+
{ background: 'white', paddingTop: 'sm', paddingBottom: 'sm' }
|
|
268
|
+
),
|
|
269
|
+
b(
|
|
270
|
+
'panels',
|
|
271
|
+
{
|
|
272
|
+
eyebrow: 'Secteurs',
|
|
273
|
+
title: 'Industrie, tertiaire,',
|
|
274
|
+
highlight: 'résidentiel collectif.',
|
|
275
|
+
headerLinkLabel: 'Tous les secteurs',
|
|
276
|
+
headerLink: '/secteurs/',
|
|
277
|
+
items: SECTEURS.map((s) => ({
|
|
278
|
+
id: uid('p'),
|
|
279
|
+
icon: SECTOR_ICONS[s.slug],
|
|
280
|
+
image: s.image,
|
|
281
|
+
title: s.title,
|
|
282
|
+
text: s.shortDesc,
|
|
283
|
+
bullets: s.enjeux.slice(0, 2),
|
|
284
|
+
linkLabel: 'Découvrir le secteur',
|
|
285
|
+
link: `/secteurs/${s.slug}/`,
|
|
286
|
+
})),
|
|
287
|
+
},
|
|
288
|
+
{ background: 'white', decor: 'rings', paddingTop: 'sm' }
|
|
289
|
+
),
|
|
290
|
+
b(
|
|
291
|
+
'stats',
|
|
292
|
+
{
|
|
293
|
+
eyebrow: 'Snapify en chiffres',
|
|
294
|
+
title: 'Des engagements',
|
|
295
|
+
highlight: 'vérifiés par des tiers.',
|
|
296
|
+
style: 'cards',
|
|
297
|
+
countUp: true,
|
|
298
|
+
items: [
|
|
299
|
+
{ id: uid('k'), prefix: '-', value: '35', suffix: ' %', label: 'de consommation électrique', hint: "Jusqu'à, sur groupes froids et régulations HP" },
|
|
300
|
+
{ id: uid('k'), value: '100', suffix: ' %', label: 'dossiers CEE sécurisés', hint: 'Prise en charge administrative de A à Z' },
|
|
301
|
+
{ id: uid('k'), value: '48', suffix: ' h', label: 'délai de réponse', hint: "Contact direct avec un ingénieur d'études" },
|
|
302
|
+
{ id: uid('k'), value: 'France', label: 'déploiement national', hint: 'Interventions sur tout le territoire' },
|
|
303
|
+
],
|
|
304
|
+
},
|
|
305
|
+
{ background: 'image', backgroundImage: '/images/photos/maisons-troglodytes-desert.jpg', overlayTone: 'light', overlay: 85, borderTop: true, paddingBottom: 'sm' }
|
|
306
|
+
),
|
|
307
|
+
b(
|
|
308
|
+
'cta',
|
|
309
|
+
{
|
|
310
|
+
variant: 'light',
|
|
311
|
+
layout: 'split',
|
|
312
|
+
eyebrow: 'Partenaires CEE',
|
|
313
|
+
title: 'Mandataires, délégataires, fournisseurs : travaillons ensemble.',
|
|
314
|
+
text: 'Montage rigoureux des dossiers CEE, chantiers contrôlés par un organisme accrédité COFRAC, qualifications à jour : un partenaire fiable pour vos opérations.',
|
|
315
|
+
buttons: [button('Devenir partenaire', '/contact/', 'secondary')],
|
|
316
|
+
},
|
|
317
|
+
{ background: 'surface', paddingTop: 'none', paddingBottom: 'lg' }
|
|
318
|
+
),
|
|
319
|
+
b(
|
|
320
|
+
'checklist',
|
|
321
|
+
{
|
|
322
|
+
eyebrow: 'Garanties',
|
|
323
|
+
title: 'Qualifiés, assurés,',
|
|
324
|
+
highlight: 'contrôlés.',
|
|
325
|
+
cards: [
|
|
326
|
+
{
|
|
327
|
+
id: uid('ck'),
|
|
328
|
+
icon: 'shieldCheck',
|
|
329
|
+
tag: 'Qualifications Snapify',
|
|
330
|
+
entries: [
|
|
331
|
+
['RGE Ventilation+', "Traitement d'air haute performance"],
|
|
332
|
+
['RGE Qualisol CESI', 'Solaire thermique & ECS'],
|
|
333
|
+
['SOCOTEC Fluides Cat. I', 'Manipulation et mise en service froid'],
|
|
334
|
+
].map(([title, text]) => ({ id: uid('e'), title, text })),
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
id: uid('ck'),
|
|
338
|
+
icon: 'award',
|
|
339
|
+
tag: "Bureau d'études partenaire",
|
|
340
|
+
entries: [
|
|
341
|
+
['OPQIBI 1717', "Audit énergétique dans l'industrie"],
|
|
342
|
+
['OPQIBI 1905', 'Audit tertiaire et collectif'],
|
|
343
|
+
['Leo Energy', "Bureau d'études partenaire"],
|
|
344
|
+
].map(([title, text]) => ({ id: uid('e'), title, text })),
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
id: uid('ck'),
|
|
348
|
+
icon: 'check',
|
|
349
|
+
tag: 'Assurances & contrôle',
|
|
350
|
+
entries: [
|
|
351
|
+
['MIC Insurance', 'Responsabilité Civile Professionnelle'],
|
|
352
|
+
['Garantie décennale', 'Travaux et ouvrages techniques'],
|
|
353
|
+
['Contrôle COFRAC', 'Systématique post-travaux'],
|
|
354
|
+
].map(([title, text]) => ({ id: uid('e'), title, text })),
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
},
|
|
358
|
+
{ background: 'white', decor: 'diagonal' }
|
|
359
|
+
),
|
|
360
|
+
b(
|
|
361
|
+
'faq',
|
|
362
|
+
{
|
|
363
|
+
eyebrow: 'FAQ',
|
|
364
|
+
title: 'Questions fréquentes',
|
|
365
|
+
intro: "Interventions, délais, financements : l'essentiel avant de lancer votre projet.",
|
|
366
|
+
layout: 'split',
|
|
367
|
+
showContactCard: true,
|
|
368
|
+
contactLabel: 'Une autre question ?',
|
|
369
|
+
items: FAQ_HOME.map((f) => ({ id: uid('q'), question: f.question, answer: `<p>${f.answer}</p>` })),
|
|
370
|
+
},
|
|
371
|
+
{ background: 'surface', decor: 'dots', borderTop: true }
|
|
372
|
+
),
|
|
373
|
+
b(
|
|
374
|
+
'cta',
|
|
375
|
+
{
|
|
376
|
+
variant: 'dark',
|
|
377
|
+
layout: 'centered',
|
|
378
|
+
badge: 'Réponse sous {{delai}}',
|
|
379
|
+
title: 'Un projet ?',
|
|
380
|
+
highlight: 'Parlons-en.',
|
|
381
|
+
text: "Audit préliminaire, étude de dimensionnement ou montage CEE : un ingénieur Snapify analyse votre site et vous propose un plan d'action chiffré.",
|
|
382
|
+
buttons: [contactButton(), phoneButton()],
|
|
383
|
+
},
|
|
384
|
+
{ background: 'white', paddingTop: 'md' }
|
|
385
|
+
),
|
|
386
|
+
];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* ------------------------------------------------------------------ Expertises */
|
|
390
|
+
|
|
391
|
+
const methodCompact = () =>
|
|
392
|
+
b('steps', {
|
|
393
|
+
title: "Notre méthode d'intervention en 4 étapes",
|
|
394
|
+
intro: "De l'audit initial au contrôle d'étanchéité et mesure COFRAC.",
|
|
395
|
+
style: 'compact',
|
|
396
|
+
deliverableLabel: 'Document',
|
|
397
|
+
items: METHODE_STEPS.map((s) => ({ id: uid('st'), num: s.num, title: s.title, text: s.description, deliverable: s.deliverable })),
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
function expertisesBlocks(): CmsBlock[] {
|
|
401
|
+
return [
|
|
402
|
+
b('pageHeader', {
|
|
403
|
+
breadcrumb: true,
|
|
404
|
+
title: 'Nos expertises en performance énergétique',
|
|
405
|
+
intro:
|
|
406
|
+
"Chaque intervention Snapify commence par l'analyse de vos installations. Nous choisissons la solution adaptée, la dimensionnons, l'installons et mesurons les économies.",
|
|
407
|
+
}),
|
|
408
|
+
b(
|
|
409
|
+
'cards',
|
|
410
|
+
{
|
|
411
|
+
style: 'card',
|
|
412
|
+
columns: 3,
|
|
413
|
+
tagsLabel: 'Solutions & Fiches :',
|
|
414
|
+
items: EXPERTISES.map((e) => ({
|
|
415
|
+
id: uid('c'),
|
|
416
|
+
icon: EXPERTISE_ICONS[e.slug],
|
|
417
|
+
title: e.title,
|
|
418
|
+
text: e.shortDesc,
|
|
419
|
+
tags: e.ceeList.slice(0, 3),
|
|
420
|
+
linkLabel: "Découvrir l'expertise",
|
|
421
|
+
link: `/expertises/${e.slug}/`,
|
|
422
|
+
})),
|
|
423
|
+
},
|
|
424
|
+
{ paddingTop: 'sm' }
|
|
425
|
+
),
|
|
426
|
+
finalCta('Un projet ?', 'Parlons-en.', 'Nos experts vous répondent sous {{delai}}.'),
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function expertiseBlocks(slug: string): CmsBlock[] {
|
|
431
|
+
const e = EXPERTISES.find((x) => x.slug === slug)!;
|
|
432
|
+
const blocks: CmsBlock[] = [
|
|
433
|
+
b('pageHeader', {
|
|
434
|
+
breadcrumb: true,
|
|
435
|
+
parentLabel: 'Expertises',
|
|
436
|
+
parentLink: '/expertises/',
|
|
437
|
+
title: e.heroTitle,
|
|
438
|
+
intro: e.shortDesc,
|
|
439
|
+
buttons: [contactButton()],
|
|
440
|
+
image: EXPERTISE_IMAGES[slug],
|
|
441
|
+
imageAlt: e.title,
|
|
442
|
+
}),
|
|
443
|
+
b(
|
|
444
|
+
'cards',
|
|
445
|
+
{
|
|
446
|
+
title: 'Nos solutions techniques déployées',
|
|
447
|
+
style: 'card',
|
|
448
|
+
columns: 2,
|
|
449
|
+
tagsLabel: 'Fiches CEE éligibles :',
|
|
450
|
+
items: e.solutions.map((s) => ({ id: uid('c'), title: s.title, text: s.description, tags: [s.ceeFiches] })),
|
|
451
|
+
},
|
|
452
|
+
{ paddingTop: 'sm' }
|
|
453
|
+
),
|
|
454
|
+
];
|
|
455
|
+
if (slug === 'reglementation-cee') {
|
|
456
|
+
blocks.push(
|
|
457
|
+
b(
|
|
458
|
+
'table',
|
|
459
|
+
{
|
|
460
|
+
title: 'Répertoire officiel des Fiches CEE Snapify',
|
|
461
|
+
intro: "Recherchez par nom d'équipement ou code officiel (ex: BAT-TH-134, IND-UT-116).",
|
|
462
|
+
searchable: true,
|
|
463
|
+
searchPlaceholder: 'Rechercher une fiche…',
|
|
464
|
+
columns: ['Solution technique', 'Fiche Tertiaire', 'Fiche Industrie', 'Gains énergétiques typiques', 'Prise en charge CEE'],
|
|
465
|
+
rows: CEE_SHEETS.map((c) => ({ id: uid('r'), cells: [c.name, c.codeTertiaire, c.codeIndustrie, c.typicalSavings, c.coverageEstimate] })),
|
|
466
|
+
},
|
|
467
|
+
{ paddingTop: 'sm' }
|
|
468
|
+
)
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
blocks.push(
|
|
472
|
+
methodCompact(),
|
|
473
|
+
b(
|
|
474
|
+
'projects',
|
|
475
|
+
{ title: 'Chantiers associés', headerLinkLabel: 'Voir toutes les réalisations', headerLink: '/realisations/', layout: 'compact', showFilters: false, limit: 3 },
|
|
476
|
+
{ paddingTop: 'sm' }
|
|
477
|
+
),
|
|
478
|
+
finalCta(`Un projet concernant ${e.title.toLowerCase()} ?`, '', 'Nos ingénieurs analysent votre relevé technique sous {{delai}}.')
|
|
479
|
+
);
|
|
480
|
+
return blocks;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* ------------------------------------------------------------------ Secteurs */
|
|
484
|
+
|
|
485
|
+
function secteursBlocks(): CmsBlock[] {
|
|
486
|
+
return [
|
|
487
|
+
b('pageHeader', {
|
|
488
|
+
breadcrumb: true,
|
|
489
|
+
title: "Nos secteurs d'intervention",
|
|
490
|
+
intro:
|
|
491
|
+
'Snapify intervient exclusivement auprès des professionnels : usines, grande distribution, parcs tertiaires et gestionnaires de copropriétés partout en France.',
|
|
492
|
+
}),
|
|
493
|
+
b(
|
|
494
|
+
'cards',
|
|
495
|
+
{
|
|
496
|
+
style: 'image',
|
|
497
|
+
columns: 3,
|
|
498
|
+
tagsLabel: 'Équipements types :',
|
|
499
|
+
items: SECTEURS.map((s) => ({
|
|
500
|
+
id: uid('c'),
|
|
501
|
+
image: s.image,
|
|
502
|
+
title: s.title,
|
|
503
|
+
text: s.shortDesc,
|
|
504
|
+
tags: s.typicalEquipments,
|
|
505
|
+
linkLabel: 'Découvrir le secteur',
|
|
506
|
+
link: `/secteurs/${s.slug}/`,
|
|
507
|
+
})),
|
|
508
|
+
},
|
|
509
|
+
{ paddingTop: 'sm' }
|
|
510
|
+
),
|
|
511
|
+
finalCta('Un projet sur votre site ?', 'Parlons-en.', 'Nos ingénieurs vous répondent sous {{delai}}.'),
|
|
512
|
+
];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function secteurBlocks(slug: string): CmsBlock[] {
|
|
516
|
+
const s = SECTEURS.find((x) => x.slug === slug)!;
|
|
517
|
+
const hasProjects = REALISATIONS.some((r) => r.sector === s.title);
|
|
518
|
+
return [
|
|
519
|
+
b('pageHeader', {
|
|
520
|
+
breadcrumb: true,
|
|
521
|
+
parentLabel: 'Secteurs',
|
|
522
|
+
parentLink: '/secteurs/',
|
|
523
|
+
title: s.heroTitle,
|
|
524
|
+
intro: s.metaDesc,
|
|
525
|
+
buttons: [contactButton()],
|
|
526
|
+
image: s.image,
|
|
527
|
+
imageAlt: s.title,
|
|
528
|
+
}),
|
|
529
|
+
b('cards', { title: 'Vos enjeux prioritaires', style: 'numbered', columns: 3, items: s.enjeux.map((text) => ({ id: uid('c'), title: '', text, tags: [] })) }, { paddingTop: 'sm' }),
|
|
530
|
+
b(
|
|
531
|
+
'cards',
|
|
532
|
+
{
|
|
533
|
+
title: 'Nos réponses techniques adaptées',
|
|
534
|
+
style: 'minimal',
|
|
535
|
+
columns: 3,
|
|
536
|
+
items: s.solutions.map((sol) => ({
|
|
537
|
+
id: uid('c'),
|
|
538
|
+
icon: EXPERTISE_ICONS[sol.slug],
|
|
539
|
+
title: sol.title,
|
|
540
|
+
text: 'Expertise Snapify',
|
|
541
|
+
tags: [],
|
|
542
|
+
linkLabel: 'Voir la solution',
|
|
543
|
+
link: `/expertises/${sol.slug}/`,
|
|
544
|
+
})),
|
|
545
|
+
},
|
|
546
|
+
{ paddingTop: 'sm' }
|
|
547
|
+
),
|
|
548
|
+
...(hasProjects
|
|
549
|
+
? [
|
|
550
|
+
b(
|
|
551
|
+
'projects',
|
|
552
|
+
{
|
|
553
|
+
title: `Chantiers ${s.title}`,
|
|
554
|
+
headerLinkLabel: 'Voir toutes les réalisations',
|
|
555
|
+
headerLink: '/realisations/',
|
|
556
|
+
layout: 'grid',
|
|
557
|
+
filter: 'sector',
|
|
558
|
+
sector: s.title,
|
|
559
|
+
showFilters: false,
|
|
560
|
+
limit: 0,
|
|
561
|
+
},
|
|
562
|
+
{ paddingTop: 'sm' }
|
|
563
|
+
),
|
|
564
|
+
]
|
|
565
|
+
: []),
|
|
566
|
+
finalCta(`Un projet ${s.title.toLowerCase()} ?`, '', 'Nos ingénieurs vous répondent sous {{delai}}.'),
|
|
567
|
+
];
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/* ------------------------------------------------------------------ Réalisations */
|
|
571
|
+
|
|
572
|
+
function realisationsBlocks(): CmsBlock[] {
|
|
573
|
+
return [
|
|
574
|
+
b('pageHeader', {
|
|
575
|
+
breadcrumb: true,
|
|
576
|
+
title: 'Nos réalisations en performance énergétique',
|
|
577
|
+
intro: 'Grande distribution, industrie pharmaceutique, entrepôts : découvrez les chantiers audités, réalisés et suivis par Snapify partout en France.',
|
|
578
|
+
}),
|
|
579
|
+
b('projects', { layout: 'grid', filter: 'all', showFilters: true, limit: 0 }, { paddingTop: 'sm' }),
|
|
580
|
+
finalCta('Vous souhaitez des résultats comparables sur votre site ?', '', 'Nos ingénieurs réalisent un audit préliminaire sans engagement.', false),
|
|
581
|
+
];
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function projectMeta(r: (typeof REALISATIONS)[number], featured: boolean): ProjectMeta {
|
|
585
|
+
return {
|
|
586
|
+
client: r.client,
|
|
587
|
+
location: r.location,
|
|
588
|
+
department: r.department,
|
|
589
|
+
sector: r.sector,
|
|
590
|
+
solution: r.solution,
|
|
591
|
+
summary: r.shortDescription,
|
|
592
|
+
image: r.image,
|
|
593
|
+
ceeSheet: r.ceeSheet,
|
|
594
|
+
results: r.results,
|
|
595
|
+
featured,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function projectBlocks(r: (typeof REALISATIONS)[number]): CmsBlock[] {
|
|
600
|
+
return [
|
|
601
|
+
b('pageHeader', {
|
|
602
|
+
breadcrumb: true,
|
|
603
|
+
parentLabel: 'Réalisations',
|
|
604
|
+
parentLink: '/realisations/',
|
|
605
|
+
backLabel: 'Retour à toutes les réalisations',
|
|
606
|
+
backLink: '/realisations/',
|
|
607
|
+
eyebrow: `${r.sector} · ${r.location} (${r.department})`,
|
|
608
|
+
title: `${r.solution} — ${r.client}, ${r.location}`,
|
|
609
|
+
intro: r.shortDescription,
|
|
610
|
+
}),
|
|
611
|
+
b('image', { url: r.image, alt: `${r.solution} sur le site ${r.client}`, width: 'wide', rounded: true }, { paddingTop: 'none', paddingBottom: 'sm' }),
|
|
612
|
+
b('stats', { style: 'strip', countUp: false, items: r.metrics.map((m) => ({ id: uid('k'), label: m.label, value: m.value })) }, { paddingTop: 'none', paddingBottom: 'sm' }),
|
|
613
|
+
b(
|
|
614
|
+
'details',
|
|
615
|
+
{
|
|
616
|
+
sections: [
|
|
617
|
+
{ id: uid('s'), title: 'Le contexte & la problématique initiale', text: r.problem, bullets: [] },
|
|
618
|
+
{ id: uid('s'), title: "La solution d'ingénierie Snapify", text: r.solutionDetail, bullets: [] },
|
|
619
|
+
{ id: uid('s'), title: 'Les résultats & performances mesurées', text: '', bullets: r.results },
|
|
620
|
+
],
|
|
621
|
+
sideTitle: 'Fiche synthèse chantier',
|
|
622
|
+
facts: [
|
|
623
|
+
['Client', r.client],
|
|
624
|
+
['Localisation', `${r.location} (${r.department})`],
|
|
625
|
+
['Secteur', r.sector],
|
|
626
|
+
['Fiche CEE', r.ceeSheet || 'Standard CEE'],
|
|
627
|
+
['Contrôle', 'Audit COFRAC'],
|
|
628
|
+
].map(([label, value]) => ({ id: uid('f'), label, value })),
|
|
629
|
+
sideButton: button('Étudier un projet similaire', '/contact/'),
|
|
630
|
+
},
|
|
631
|
+
{ paddingTop: 'sm' }
|
|
632
|
+
),
|
|
633
|
+
finalCta('Un projet similaire ?', 'Parlons-en.', 'Nos ingénieurs vous répondent sous {{delai}}.'),
|
|
634
|
+
];
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/* ------------------------------------------------------------------ Approche, contact, merci */
|
|
638
|
+
|
|
639
|
+
function approcheBlocks(): CmsBlock[] {
|
|
640
|
+
return [
|
|
641
|
+
b('pageHeader', {
|
|
642
|
+
breadcrumb: true,
|
|
643
|
+
eyebrow: "Optimiser aujourd'hui. Performer demain.",
|
|
644
|
+
title: 'Conseil, ingénierie et suivi opérationnel',
|
|
645
|
+
intro:
|
|
646
|
+
"Plus qu'un simple accompagnement, Snapify conjugue innovation, expertise et fiabilité grâce à son triptyque Conseil, Ingénierie et Suivi opérationnel, sur l'ensemble du territoire national.",
|
|
647
|
+
buttons: [contactButton()],
|
|
648
|
+
}),
|
|
649
|
+
b(
|
|
650
|
+
'steps',
|
|
651
|
+
{
|
|
652
|
+
title: 'Notre méthode en 4 étapes',
|
|
653
|
+
intro: "Une démarche rigoureuse sans rupture d'activité avec un engagement contractuel à chaque jalon.",
|
|
654
|
+
style: 'list',
|
|
655
|
+
deliverableLabel: 'Document contractuel remis',
|
|
656
|
+
items: METHODE_STEPS.map((s) => ({ id: uid('st'), num: s.num, title: s.title, text: s.description, deliverable: s.deliverable })),
|
|
657
|
+
},
|
|
658
|
+
{ paddingTop: 'sm' }
|
|
659
|
+
),
|
|
660
|
+
b(
|
|
661
|
+
'checklist',
|
|
662
|
+
{
|
|
663
|
+
title: 'Qualifications et garanties',
|
|
664
|
+
intro: "Les accréditations qui sécurisent vos dossiers et garantissent l'éligibilité CEE.",
|
|
665
|
+
cards: [
|
|
666
|
+
{
|
|
667
|
+
id: uid('ck'),
|
|
668
|
+
icon: 'shieldCheck',
|
|
669
|
+
tag: 'Certifications Snapify',
|
|
670
|
+
title: 'Qualifications déposées',
|
|
671
|
+
entries: ['RGE Ventilation+', 'RGE Qualisol CESI', 'SOCOTEC Fluides Frigorigènes Cat. I'].map((title) => ({ id: uid('e'), title })),
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
id: uid('ck'),
|
|
675
|
+
icon: 'award',
|
|
676
|
+
tag: "Bureau d'études partenaire",
|
|
677
|
+
title: 'Leo Energy',
|
|
678
|
+
entries: ['OPQIBI 1717 — Audit énergétique industrie', 'OPQIBI 1905 — Audit tertiaire & collectif'].map((title) => ({ id: uid('e'), title })),
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
id: uid('ck'),
|
|
682
|
+
icon: 'check',
|
|
683
|
+
tag: 'Assurances',
|
|
684
|
+
title: 'MIC Insurance',
|
|
685
|
+
entries: ["RC Professionnelle travaux d'ingénierie", 'Garantie Décennale installations'].map((title) => ({ id: uid('e'), title })),
|
|
686
|
+
},
|
|
687
|
+
],
|
|
688
|
+
},
|
|
689
|
+
{ paddingTop: 'sm' }
|
|
690
|
+
),
|
|
691
|
+
b(
|
|
692
|
+
'textMedia',
|
|
693
|
+
{
|
|
694
|
+
eyebrow: 'Notre équipe',
|
|
695
|
+
title: 'Une équipe pluridisciplinaire',
|
|
696
|
+
highlight: 'mobilisée sur vos chantiers.',
|
|
697
|
+
html: "<p>Ingénieurs thermiciens, experts frigoristes certifiés catégorie I, chargés d'affaires CEE et techniciens de mise en service : une équipe pluridisciplinaire d'ingénierie mobilisée sur vos chantiers.</p>",
|
|
698
|
+
bullets: ['Ingénieurs thermiciens', 'Frigoristes certifiés catégorie I', "Chargés d'affaires CEE", 'Techniciens de mise en service'],
|
|
699
|
+
mediaType: 'image',
|
|
700
|
+
image: '/images/photos/hammamet-medina-plage.jpg',
|
|
701
|
+
imageAlt: 'Ingénieure Snapify sur chantier',
|
|
702
|
+
mediaPosition: 'right',
|
|
703
|
+
mediaStyle: 'polaroid',
|
|
704
|
+
caption: 'Nos équipes sur site',
|
|
705
|
+
ratio: 'landscape',
|
|
706
|
+
},
|
|
707
|
+
{ background: 'surface' }
|
|
708
|
+
),
|
|
709
|
+
finalCta('Un projet ?', 'Parlons-en.', 'Nos experts vous répondent sous {{delai}}.'),
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function contactBlocks(): CmsBlock[] {
|
|
714
|
+
return [
|
|
715
|
+
b(
|
|
716
|
+
'contactForm',
|
|
717
|
+
{
|
|
718
|
+
formId: 'contact-main',
|
|
719
|
+
title: 'Parlons de votre projet',
|
|
720
|
+
intro: "Présentez-nous votre site et votre problématique. Un ingénieur ou chargé d'affaires vous répond sous {{delai}}.",
|
|
721
|
+
phoneLabel: 'Ligne directe experts',
|
|
722
|
+
phoneHint: 'Engagement de rappel sous {{delai}}',
|
|
723
|
+
listTitle: 'Qualifications & Habilitations',
|
|
724
|
+
listItems: ['RGE Ventilation+', 'RGE Qualisol CESI', 'SOCOTEC Fluides Frigorigènes Catégorie I'],
|
|
725
|
+
submitLabel: 'Envoyer ma demande',
|
|
726
|
+
},
|
|
727
|
+
{ background: 'none', paddingTop: 'md' }
|
|
728
|
+
),
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function merciBlocks(): CmsBlock[] {
|
|
733
|
+
return [
|
|
734
|
+
b(
|
|
735
|
+
'cta',
|
|
736
|
+
{
|
|
737
|
+
variant: 'light',
|
|
738
|
+
layout: 'centered',
|
|
739
|
+
badge: 'Demande envoyée',
|
|
740
|
+
title: 'Merci, votre demande',
|
|
741
|
+
highlight: 'a bien été envoyée.',
|
|
742
|
+
text: "Un ingénieur ou chargé d'affaires Snapify vous répond sous {{delai}}. Pour toute demande urgente, vous pouvez joindre directement notre permanence technique au {{telephone}}.",
|
|
743
|
+
buttons: [button('Voir nos réalisations', '/realisations/'), button("Retour à l'accueil", '/', 'secondary', 'none'), phoneButton('link')],
|
|
744
|
+
},
|
|
745
|
+
{ background: 'none', paddingTop: 'lg', paddingBottom: 'xl' }
|
|
746
|
+
),
|
|
747
|
+
];
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/* ------------------------------------------------------------------ Pages légales */
|
|
751
|
+
|
|
752
|
+
const LEGAL: Record<string, { title: string; intro: string; html: string; cookiesButton?: boolean }> = {
|
|
753
|
+
'/mentions-legales/': {
|
|
754
|
+
title: 'Mentions légales',
|
|
755
|
+
intro:
|
|
756
|
+
"Dernière mise à jour : 2 octobre 2026 — Conformément aux dispositions des articles 6-III et 19 de la Loi n° 2004-575 du 21 juin 2004 pour la Confiance dans l'économie numérique (L.C.E.N.).",
|
|
757
|
+
html: `<h2>1. Éditeur de la plateforme</h2>
|
|
758
|
+
<p>Le site <strong>snapify.fr</strong> est édité par la société <strong>Snapify SAS</strong>, société par actions simplifiée au capital social de 50 000 €, immatriculée au Registre du Commerce et des Sociétés sous le numéro RCS Paris B 912 345 678.</p>
|
|
759
|
+
<ul><li>Siège social : Paris, France</li><li>Numéro de TVA intracommunautaire : FR 12 912345678</li><li>Téléphone : {{telephone}}</li><li>Directeur de la publication : Direction Générale Snapify</li></ul>
|
|
760
|
+
<h2>2. Hébergement</h2>
|
|
761
|
+
<p>Le site est hébergé par la société <strong>Ionos SE</strong> :</p>
|
|
762
|
+
<ul><li>Adresse : Elgendorfer Str. 57, 56410 Montabaur, Allemagne</li><li>Téléphone : 09 70 80 89 11</li><li>Site web : ionos.fr</li></ul>
|
|
763
|
+
<h2>3. Propriété intellectuelle & Marque Snapify</h2>
|
|
764
|
+
<p>L'ensemble des éléments constituant ce site (textes, méthodologies, logotypes, charte graphique, photographies de chantiers, fiches synthèses CEE) sont la propriété exclusive de Snapify SAS ou font l'objet d'une autorisation préalable expresse. La marque <strong>Snapify</strong> est une marque déposée protégée. Toute reproduction, représentation ou exploitation non autorisée constitue une contrefaçon sanctionnée par les articles L. 335-2 et suivants du Code de la propriété intellectuelle.</p>
|
|
765
|
+
<p>Les dénominations commerciales et logos de tiers (clients, partenaires) mentionnés sur le site sont utilisés avec leur accord ou à titre de référence contractuelle vérifiée.</p>
|
|
766
|
+
<h2>4. Partenariat d'ingénierie & qualifications</h2>
|
|
767
|
+
<p>Les qualifications d'ingénierie et d'audit énergétique <strong>OPQIBI 1717</strong> et <strong>OPQIBI 1905</strong> sont détenues et opérées par notre bureau d'études partenaire <strong>Leo Energy</strong>, dans le cadre de nos accords de cotraitance et d'assistance technique.</p>
|
|
768
|
+
<h2>5. Limitation de responsabilité</h2>
|
|
769
|
+
<p>Les simulations énergétiques et estimations CEE fournies sur le site ont un caractère informatif et ne constituent pas un engagement contractuel préalable. Tout dimensionnement définitif fait l'objet d'un audit terrain formalisé et d'un contrat d'ingénierie visé par nos experts.</p>`,
|
|
770
|
+
},
|
|
771
|
+
'/politique-de-confidentialite/': {
|
|
772
|
+
title: 'Politique de confidentialité',
|
|
773
|
+
intro: 'Conforme au Règlement Général sur la Protection des Données (RGPD 2016/679) et à la loi Informatique et Libertés.',
|
|
774
|
+
html: `<h2>1. Responsable de traitement</h2>
|
|
775
|
+
<p>Le responsable du traitement des données personnelles collectées via le site snapify.fr est la société <strong>Snapify SAS</strong>, joignable par téléphone au {{telephone}}.</p>
|
|
776
|
+
<h2>2. Données collectées & finalités</h2>
|
|
777
|
+
<p>Dans le cadre de l'utilisation de notre formulaire de contact et de dimensionnement, nous collectons les données professionnelles strictement nécessaires : nom, prénom, adresse e-mail professionnelle, numéro de téléphone, entreprise, fonction, typologie du site et descriptif du besoin.</p>
|
|
778
|
+
<p>Ces données sont traitées pour :</p>
|
|
779
|
+
<ul><li>Répondre sous {{delai}} à vos demandes d'études techniques et de devis.</li><li>Instruire les pré-études d'éligibilité aux Certificats d'Économies d'Énergie (CEE).</li><li>Le suivi de la relation commerciale B2B.</li></ul>
|
|
780
|
+
<h2>3. Durée de conservation</h2>
|
|
781
|
+
<p>Les données relatives à une demande de contact ou de projet sont conservées pendant une durée maximale de <strong>3 ans</strong> à compter du dernier contact émanant du prospect ou client.</p>
|
|
782
|
+
<h2>4. Vos droits & contact CNIL</h2>
|
|
783
|
+
<p>Conformément à la réglementation en vigueur, vous disposez d'un droit d'accès, de rectification, d'effacement, de limitation et d'opposition au traitement de vos données. Vous pouvez exercer ces droits en nous adressant une demande par téléphone ou courrier. Vous conservez également le droit d'introduire une réclamation auprès de la Commission Nationale de l'Informatique et des Libertés (CNIL, cnil.fr).</p>`,
|
|
784
|
+
},
|
|
785
|
+
'/cookies/': {
|
|
786
|
+
title: 'Gestion des cookies',
|
|
787
|
+
intro: "Transparence totale : maîtrisez vos choix de navigation et de mesure d'audience.",
|
|
788
|
+
html: `<h2>Mesurer, c'est notre métier.</h2>
|
|
789
|
+
<p>Ce site utilise des traceurs afin d'assurer son bon fonctionnement et, sous réserve de votre consentement explicite, de mesurer l'audience globale via Google Analytics 4 (Google Consent Mode v2 respecté).</p>
|
|
790
|
+
<h3>1. Cookies techniques indispensables (toujours actifs)</h3>
|
|
791
|
+
<p>Nécessaires à l'enregistrement de vos préférences de consentement, à la sécurité et à la fluidité de navigation. Ils ne requièrent pas de consentement préalable.</p>
|
|
792
|
+
<h3>2. Cookies de mesure d'audience (désactivés par défaut)</h3>
|
|
793
|
+
<p>Google Analytics 4 nous permet d'analyser anonymement le volume de fréquentation et les pages consultées afin d'optimiser l'ergonomie. Aucun cookie de mesure n'est déposé sans votre clic sur « Tout accepter ».</p>`,
|
|
794
|
+
cookiesButton: true,
|
|
795
|
+
},
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
function legalBlocks(p: string): CmsBlock[] {
|
|
799
|
+
const l = LEGAL[p];
|
|
800
|
+
return [
|
|
801
|
+
b('pageHeader', { breadcrumb: true, backLabel: "Retour à l'accueil", backLink: '/', title: l.title, intro: l.intro }, { width: 'narrow', paddingBottom: 'sm' }),
|
|
802
|
+
b('richText', { html: l.html, size: 'normal' }, { width: 'narrow', paddingTop: 'none', paddingBottom: l.cookiesButton ? 'sm' : 'xl' }),
|
|
803
|
+
...(l.cookiesButton
|
|
804
|
+
? [
|
|
805
|
+
b(
|
|
806
|
+
'cta',
|
|
807
|
+
{
|
|
808
|
+
variant: 'light',
|
|
809
|
+
layout: 'split',
|
|
810
|
+
title: 'Vos préférences',
|
|
811
|
+
text: 'Vous pouvez modifier votre choix à tout moment.',
|
|
812
|
+
buttons: [button('Modifier mes préférences cookies', '#preferences-cookies', 'primary', 'none')],
|
|
813
|
+
},
|
|
814
|
+
{ width: 'narrow', paddingTop: 'none', paddingBottom: 'xl' }
|
|
815
|
+
),
|
|
816
|
+
]
|
|
817
|
+
: []),
|
|
818
|
+
];
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/* ------------------------------------------------------------------ Définition des pages */
|
|
822
|
+
|
|
823
|
+
interface PageDef {
|
|
824
|
+
path: string;
|
|
825
|
+
title: string;
|
|
826
|
+
template: PageTemplate;
|
|
827
|
+
seoTitle: string;
|
|
828
|
+
metaDescription?: string;
|
|
829
|
+
noindex?: boolean;
|
|
830
|
+
blocks: () => CmsBlock[];
|
|
831
|
+
project?: ProjectMeta;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function pageDefinitions(): PageDef[] {
|
|
835
|
+
const defs: PageDef[] = [
|
|
836
|
+
{ path: '/', title: 'Accueil', template: 'landing', seoTitle: 'Snapify | Ingénierie & performance énergétique', blocks: homeBlocks },
|
|
837
|
+
{ path: '/expertises/', title: 'Expertises', template: 'default', seoTitle: 'Nos expertises en performance énergétique | Snapify', blocks: expertisesBlocks },
|
|
838
|
+
...EXPERTISES.map<PageDef>((e) => ({
|
|
839
|
+
path: `/expertises/${e.slug}/`,
|
|
840
|
+
title: e.title,
|
|
841
|
+
template: 'default',
|
|
842
|
+
seoTitle: `${e.heroTitle} | Snapify`,
|
|
843
|
+
metaDescription: e.metaDesc,
|
|
844
|
+
blocks: () => expertiseBlocks(e.slug),
|
|
845
|
+
})),
|
|
846
|
+
{ path: '/secteurs/', title: 'Secteurs', template: 'default', seoTitle: 'Industrie, tertiaire, résidentiel collectif | Snapify', blocks: secteursBlocks },
|
|
847
|
+
...SECTEURS.map<PageDef>((s) => ({
|
|
848
|
+
path: `/secteurs/${s.slug}/`,
|
|
849
|
+
title: s.title,
|
|
850
|
+
template: 'default',
|
|
851
|
+
seoTitle: `${s.heroTitle} | Snapify`,
|
|
852
|
+
metaDescription: s.metaDesc,
|
|
853
|
+
blocks: () => secteurBlocks(s.slug),
|
|
854
|
+
})),
|
|
855
|
+
{ path: '/realisations/', title: 'Réalisations', template: 'default', seoTitle: 'Nos réalisations en performance énergétique | Snapify', blocks: realisationsBlocks },
|
|
856
|
+
...REALISATIONS.map<PageDef>((r, i) => ({
|
|
857
|
+
path: `/realisations/${r.slug}/`,
|
|
858
|
+
title: `${r.client} — ${r.location}`,
|
|
859
|
+
template: 'project',
|
|
860
|
+
seoTitle: `${r.solution} — ${r.client} | Snapify`,
|
|
861
|
+
metaDescription: r.shortDescription,
|
|
862
|
+
blocks: () => projectBlocks(r),
|
|
863
|
+
project: projectMeta(r, i === 0),
|
|
864
|
+
})),
|
|
865
|
+
{ path: '/notre-approche/', title: 'Notre approche', template: 'default', seoTitle: 'Notre approche : conseil, ingénierie, suivi | Snapify', blocks: approcheBlocks },
|
|
866
|
+
{ path: '/contact/', title: 'Contact', template: 'default', seoTitle: 'Contact : parlez de votre projet | Snapify', blocks: contactBlocks },
|
|
867
|
+
{ path: '/contact/merci/', title: 'Merci', template: 'default', seoTitle: 'Merci pour votre demande | Snapify', noindex: true, blocks: merciBlocks },
|
|
868
|
+
...Object.entries(LEGAL).map<PageDef>(([p, l]) => ({ path: p, title: l.title, template: 'legal', seoTitle: `${l.title} | Snapify`, blocks: () => legalBlocks(p) })),
|
|
869
|
+
];
|
|
870
|
+
return defs;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/* ------------------------------------------------------------------ Blocs hérités (v1) */
|
|
874
|
+
|
|
875
|
+
type Legacy = Record<string, unknown>;
|
|
876
|
+
const str = (v: unknown) => (typeof v === 'string' ? v : '');
|
|
877
|
+
|
|
878
|
+
/** Convertit les blocs du premier éditeur (hero/cta/stats simplifiés) vers le modèle actuel. */
|
|
879
|
+
export function upgradeLegacyBlock(block: CmsBlock): CmsBlock | null {
|
|
880
|
+
if (!isBlockKind(block.type)) return null;
|
|
881
|
+
const d = (block.data || {}) as Legacy;
|
|
882
|
+
switch (block.type) {
|
|
883
|
+
case 'hero':
|
|
884
|
+
if (!('ctaLabel' in d) && !('variant' in d) && !('backgroundStyle' in d)) return block;
|
|
885
|
+
return {
|
|
886
|
+
id: block.id,
|
|
887
|
+
type: 'hero',
|
|
888
|
+
data: {
|
|
889
|
+
...BLOCK_CATALOG.hero.defaults(),
|
|
890
|
+
layout: 'centered',
|
|
891
|
+
badgeText: str(d.eyebrow),
|
|
892
|
+
badgeTag: '',
|
|
893
|
+
title: str(d.title),
|
|
894
|
+
subtitle: str(d.subtitle),
|
|
895
|
+
media: 'none',
|
|
896
|
+
buttons: [
|
|
897
|
+
...(d.ctaLabel && d.ctaPath ? [button(str(d.ctaLabel), str(d.ctaPath))] : []),
|
|
898
|
+
...(d.secondaryLabel && d.secondaryPath ? [button(str(d.secondaryLabel), str(d.secondaryPath), 'secondary', 'none')] : []),
|
|
899
|
+
],
|
|
900
|
+
},
|
|
901
|
+
style: d.backgroundImage
|
|
902
|
+
? { background: 'image', backgroundImage: str(d.backgroundImage), overlayTone: d.variant === 'light' ? 'light' : 'dark' }
|
|
903
|
+
: { background: d.variant === 'light' ? 'soft' : 'navy' },
|
|
904
|
+
};
|
|
905
|
+
case 'cta':
|
|
906
|
+
if (!('buttonLabel' in d) && Array.isArray(d.buttons)) return block;
|
|
907
|
+
return {
|
|
908
|
+
id: block.id,
|
|
909
|
+
type: 'cta',
|
|
910
|
+
data: {
|
|
911
|
+
...BLOCK_CATALOG.cta.defaults(),
|
|
912
|
+
variant: d.variant === 'dark' ? 'dark' : d.variant === 'light' ? 'light' : 'gradient',
|
|
913
|
+
title: str(d.title),
|
|
914
|
+
text: str(d.text),
|
|
915
|
+
buttons: d.buttonLabel && d.buttonPath ? [button(str(d.buttonLabel), str(d.buttonPath), d.variant === 'light' ? 'primary' : 'light')] : [],
|
|
916
|
+
},
|
|
917
|
+
style: block.style,
|
|
918
|
+
};
|
|
919
|
+
case 'stats': {
|
|
920
|
+
const items = Array.isArray(d.items) ? (d.items as Legacy[]) : [];
|
|
921
|
+
if (items.every((it) => typeof it.id === 'string')) return block;
|
|
922
|
+
return {
|
|
923
|
+
...block,
|
|
924
|
+
data: { ...BLOCK_CATALOG.stats.defaults(), ...d, items: items.map((it) => ({ id: uid('k'), value: str(it.value), label: str(it.label) })) },
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
default:
|
|
928
|
+
return block;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/* ------------------------------------------------------------------ Formulaire et médias */
|
|
933
|
+
|
|
934
|
+
const SELECT = (options: string[]) => ({ type: 'select' as const, options });
|
|
935
|
+
|
|
936
|
+
export function contactFormFields(): ContactFormField[] {
|
|
937
|
+
const f = (name: string, label: string, extra: Partial<ContactFormField>): ContactFormField => ({
|
|
938
|
+
id: `f-${name}`,
|
|
939
|
+
name,
|
|
940
|
+
label,
|
|
941
|
+
type: 'text',
|
|
942
|
+
required: true,
|
|
943
|
+
width: 'half',
|
|
944
|
+
...extra,
|
|
945
|
+
});
|
|
946
|
+
return [
|
|
947
|
+
f('vousEtes', 'Vous êtes', {
|
|
948
|
+
...SELECT([
|
|
949
|
+
'Client (entreprise, gestionnaire de site)',
|
|
950
|
+
'Bailleur, syndic ou gestionnaire de copropriété',
|
|
951
|
+
'Mandataire ou délégataire CEE',
|
|
952
|
+
'Fournisseur ou fabricant',
|
|
953
|
+
"Bureau d'études",
|
|
954
|
+
'Autre',
|
|
955
|
+
]),
|
|
956
|
+
placeholder: 'Sélectionnez votre profil…',
|
|
957
|
+
width: 'full',
|
|
958
|
+
}),
|
|
959
|
+
f('entreprise', 'Entreprise / Raison sociale', { placeholder: 'Ex : Intermarché, Safran…' }),
|
|
960
|
+
f('nomPrenom', 'Nom & prénom', { placeholder: 'Ex : Jean Dupont' }),
|
|
961
|
+
f('fonction', 'Fonction', { placeholder: 'Ex : Directeur technique, Responsable maintenance…' }),
|
|
962
|
+
f('email', 'E-mail professionnel', { type: 'email', placeholder: 'nom@entreprise.fr' }),
|
|
963
|
+
f('telephone', 'Téléphone', { type: 'tel', placeholder: '06 00 00 00 00' }),
|
|
964
|
+
f('typologieSite', 'Typologie de site', {
|
|
965
|
+
...SELECT(['Site industriel', 'Grande distribution / commerce', 'Bureaux', 'Entrepôt / logistique', 'Santé', 'Résidentiel collectif', 'Autre']),
|
|
966
|
+
placeholder: 'Sélectionnez…',
|
|
967
|
+
}),
|
|
968
|
+
f('natureBesoin', 'Nature du besoin', {
|
|
969
|
+
...SELECT([
|
|
970
|
+
'Froid commercial ou industriel',
|
|
971
|
+
'Récupération de chaleur',
|
|
972
|
+
'Pompe à chaleur / remplacement chaudière',
|
|
973
|
+
'Déstratification',
|
|
974
|
+
'GTB-GTC / décret BACS',
|
|
975
|
+
'Isolation technique',
|
|
976
|
+
'Audit et conseil',
|
|
977
|
+
'Décret tertiaire',
|
|
978
|
+
'Financement CEE',
|
|
979
|
+
'Partenariat',
|
|
980
|
+
'Autre',
|
|
981
|
+
]),
|
|
982
|
+
placeholder: 'Sélectionnez…',
|
|
983
|
+
}),
|
|
984
|
+
f('localisationSite', 'Localisation du site (ville ou dpt)', { placeholder: 'Ex : Lyon (69), Trévenans (90)…' }),
|
|
985
|
+
f('message', 'Message / problématique technique', { type: 'textarea', placeholder: 'Décrivez votre site, vos équipements et votre objectif.', width: 'full' }),
|
|
986
|
+
f('commentConnu', 'Comment avez-vous connu Snapify ?', {
|
|
987
|
+
...SELECT([
|
|
988
|
+
'Bouche-à-oreille / recommandation',
|
|
989
|
+
'Moteur de recherche (Google…)',
|
|
990
|
+
'Assistant IA (ChatGPT, Perplexity…)',
|
|
991
|
+
'Réseaux sociaux',
|
|
992
|
+
'Salon ou événement',
|
|
993
|
+
'Partenaire (mandataire, délégataire, fournisseur)',
|
|
994
|
+
'Autre',
|
|
995
|
+
]),
|
|
996
|
+
placeholder: 'Sélectionnez…',
|
|
997
|
+
width: 'full',
|
|
998
|
+
}),
|
|
999
|
+
f('rgpdAccepted', "J'accepte que Snapify utilise mes données pour traiter ma demande, conformément à la politique de confidentialité", {
|
|
1000
|
+
type: 'checkbox',
|
|
1001
|
+
width: 'full',
|
|
1002
|
+
}),
|
|
1003
|
+
];
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
const MIME: Record<string, string> = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.webp': 'image/webp', '.svg': 'image/svg+xml', '.mp4': 'video/mp4', '.webm': 'video/webm' };
|
|
1007
|
+
|
|
1008
|
+
function registerBundledMedia(snapshot: CmsSnapshot) {
|
|
1009
|
+
const known = new Set(snapshot.media.map((m) => m.url));
|
|
1010
|
+
for (const dir of ['images/photos', 'videos']) {
|
|
1011
|
+
let files: string[] = [];
|
|
1012
|
+
try {
|
|
1013
|
+
files = fs.readdirSync(path.join(PUBLIC_DIR, dir));
|
|
1014
|
+
} catch {
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
for (const file of files.sort()) {
|
|
1018
|
+
const mime = MIME[path.extname(file).toLowerCase()];
|
|
1019
|
+
const url = `/${dir}/${file}`;
|
|
1020
|
+
if (!mime || known.has(url)) continue;
|
|
1021
|
+
snapshot.media.push({
|
|
1022
|
+
id: uid('media'),
|
|
1023
|
+
filename: file,
|
|
1024
|
+
url,
|
|
1025
|
+
mimeType: mime,
|
|
1026
|
+
sizeBytes: fs.statSync(path.join(PUBLIC_DIR, dir, file)).size,
|
|
1027
|
+
alt: '',
|
|
1028
|
+
createdAt: cmsNow(),
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/* ------------------------------------------------------------------ Migration */
|
|
1035
|
+
|
|
1036
|
+
const PLACEHOLDER = 'Contenu géré depuis le backoffice';
|
|
1037
|
+
|
|
1038
|
+
/** URL de l'ancien site WordPress (redirections 301 permanentes). */
|
|
1039
|
+
const LEGACY_REDIRECTS: [string, string][] = [
|
|
1040
|
+
['/contactez-nous/', '/contact/'],
|
|
1041
|
+
['/nos-solutions/', '/expertises/'],
|
|
1042
|
+
['/nos-solutions-2/', '/expertises/'],
|
|
1043
|
+
['/nos-solutions-3/', '/expertises/'],
|
|
1044
|
+
['/nos-solutions-4/', '/expertises/'],
|
|
1045
|
+
['/nos-solutions-industrielles/', '/secteurs/industrie/'],
|
|
1046
|
+
['/isolation-des-murs-par-lexterieur/', '/expertises/'],
|
|
1047
|
+
['/combles-perdus/', '/expertises/'],
|
|
1048
|
+
['/fenetres-et-baies-vitrees/', '/expertises/'],
|
|
1049
|
+
['/category/residentiel/', '/secteurs/'],
|
|
1050
|
+
['/cas-2-maison-dhote-a-lyon/', '/realisations/'],
|
|
1051
|
+
['/cas-3-usine-andros-carquefou/', '/realisations/'],
|
|
1052
|
+
['/cas-4-appartement-t3-a-lille/', '/realisations/'],
|
|
1053
|
+
['/category/etude-de-cas/', '/realisations/'],
|
|
1054
|
+
['/sample-page/', '/'],
|
|
1055
|
+
['/hello-world/', '/'],
|
|
1056
|
+
['/elementor-209/', '/'],
|
|
1057
|
+
];
|
|
1058
|
+
|
|
1059
|
+
function isUntouched(page: CmsPage) {
|
|
1060
|
+
if (page.contentSource === 'react') return true;
|
|
1061
|
+
return page.blocks.length <= 1 && page.blocks.every((bl) => JSON.stringify(bl.data).includes(PLACEHOLDER));
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
export function migrateContentToBlocks(snapshot: CmsSnapshot): void {
|
|
1065
|
+
if ((snapshot.version ?? 1) >= CONTENT_VERSION) return;
|
|
1066
|
+
const now = cmsNow();
|
|
1067
|
+
|
|
1068
|
+
for (const def of pageDefinitions()) {
|
|
1069
|
+
const existing = snapshot.pages.find((p) => p.path === def.path);
|
|
1070
|
+
if (existing) {
|
|
1071
|
+
if (isUntouched(existing)) {
|
|
1072
|
+
existing.blocks = def.blocks();
|
|
1073
|
+
existing.template = def.template;
|
|
1074
|
+
if (def.project) existing.project = def.project;
|
|
1075
|
+
existing.seo = { ...existing.seo, seoTitle: def.seoTitle, ...(def.metaDescription ? { metaDescription: def.metaDescription } : {}) };
|
|
1076
|
+
existing.updatedAt = now;
|
|
1077
|
+
}
|
|
1078
|
+
existing.contentSource = 'cms';
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
snapshot.pages.push({
|
|
1082
|
+
id: uid('page'),
|
|
1083
|
+
path: def.path,
|
|
1084
|
+
title: def.title,
|
|
1085
|
+
status: 'published',
|
|
1086
|
+
publishedAt: now,
|
|
1087
|
+
contentSource: 'cms',
|
|
1088
|
+
template: def.template,
|
|
1089
|
+
blocks: def.blocks(),
|
|
1090
|
+
seo: {
|
|
1091
|
+
...defaultSeoForPath(def.path, def.title),
|
|
1092
|
+
seoTitle: def.seoTitle,
|
|
1093
|
+
...(def.metaDescription ? { metaDescription: def.metaDescription } : {}),
|
|
1094
|
+
...(def.noindex ? { noindex: true } : {}),
|
|
1095
|
+
},
|
|
1096
|
+
...(def.project ? { project: def.project } : {}),
|
|
1097
|
+
createdAt: now,
|
|
1098
|
+
updatedAt: now,
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
for (const page of snapshot.pages) {
|
|
1103
|
+
page.contentSource = 'cms';
|
|
1104
|
+
page.blocks = page.blocks.map(upgradeLegacyBlock).filter((x): x is CmsBlock => !!x);
|
|
1105
|
+
}
|
|
1106
|
+
for (const post of snapshot.posts) {
|
|
1107
|
+
post.blocks = post.blocks.map(upgradeLegacyBlock).filter((x): x is CmsBlock => !!x);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
const form = snapshot.forms.find((f) => f.id === 'contact-main');
|
|
1111
|
+
if (form && !form.fields.some((f) => f.name === 'fonction')) form.fields = contactFormFields();
|
|
1112
|
+
|
|
1113
|
+
for (const [from, to] of LEGACY_REDIRECTS) {
|
|
1114
|
+
if (!snapshot.redirects.some((r) => r.from === from)) snapshot.redirects.push({ from, to, permanent: true });
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
registerBundledMedia(snapshot);
|
|
1118
|
+
snapshot.version = CONTENT_VERSION;
|
|
1119
|
+
}
|