diff --git a/proposition_commerciale.html b/proposition_commerciale.html
new file mode 100644
index 0000000..551a686
--- /dev/null
+++ b/proposition_commerciale.html
@@ -0,0 +1,546 @@
+
+
+
+
+
+
✏️ Personnalisation
+
+
+
+
+
+
+
+
📋 Honoraires de location
+
+
Recalculé auto : (mission + EDL) × superficie
+
+
+
⚙️ Gestion & Assurances
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
🖼️ Icônes PWA — PropImmo
+
Cliquez pour télécharger les deux icônes nécessaires à l'installation.
+
+
+
+
![]()
+
icon-192.png
+
+
+
![]()
+
icon-512.png
+
+
+
+
+
+
+
+
+
+
+
+
+ Où placer ces fichiers ?
+ Déposez icon-192.png et icon-512.png
+ dans le même dossier que votre index.html,
+ manifest.json et service-worker.js.
+
+
+
+
+
+
diff --git a/pwa_manifest.json b/pwa_manifest.json
new file mode 100644
index 0000000..8c9af4c
--- /dev/null
+++ b/pwa_manifest.json
@@ -0,0 +1,26 @@
+{
+ "name": "Proposition Gestion Locative",
+ "short_name": "PropImmo",
+ "description": "Créez et envoyez des propositions de gestion locative en PDF",
+ "start_url": "./index.html",
+ "scope": "./",
+ "display": "standalone",
+ "background_color": "#1a2a4a",
+ "theme_color": "#1a2a4a",
+ "orientation": "portrait",
+ "lang": "fr",
+ "icons": [
+ {
+ "src": "icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "any maskable"
+ }
+ ]
+}
diff --git a/pwa_sw.js b/pwa_sw.js
new file mode 100644
index 0000000..194f43d
--- /dev/null
+++ b/pwa_sw.js
@@ -0,0 +1,37 @@
+const CACHE = 'prop-immo-v1';
+const ASSETS = [
+ './',
+ './index.html',
+ './manifest.json',
+ './icon-192.png',
+ './icon-512.png',
+ 'https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js'
+];
+
+self.addEventListener('install', e => {
+ e.waitUntil(
+ caches.open(CACHE).then(c => c.addAll(ASSETS).catch(() => {}))
+ );
+ self.skipWaiting();
+});
+
+self.addEventListener('activate', e => {
+ e.waitUntil(
+ caches.keys().then(keys =>
+ Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))
+ )
+ );
+ self.clients.claim();
+});
+
+self.addEventListener('fetch', e => {
+ e.respondWith(
+ fetch(e.request)
+ .then(res => {
+ const clone = res.clone();
+ caches.open(CACHE).then(c => c.put(e.request, clone));
+ return res;
+ })
+ .catch(() => caches.match(e.request))
+ );
+});