From e3620c7f421a763bd550045a4d5ce6bd06db93a4 Mon Sep 17 00:00:00 2001 From: karim hassan Date: Mon, 18 Aug 2025 19:30:47 +0000 Subject: [PATCH] Day:1 --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 14 +++ data/db.json | 190 +++++++++++++++++++++++++++++++++++++ package.json | 6 ++ public/admin.html | 27 ++++++ public/assets/css/app.css | 27 ++++++ public/assets/img/logo.svg | 6 ++ public/assets/js/app.js | 12 +++ public/events.html | 18 ++++ public/index.html | 28 ++++++ public/register.html | 32 +++++++ public/reglement.html | 10 ++ server.mjs | 146 ++++++++++++++++++++++++++++ start.sh | 5 + sync.sh | 25 +++++ sync2.sh | 16 ++++ 16 files changed, 562 insertions(+) create mode 100644 README.md create mode 100644 data/db.json create mode 100644 package.json create mode 100644 public/admin.html create mode 100644 public/assets/css/app.css create mode 100644 public/assets/img/logo.svg create mode 100644 public/assets/js/app.js create mode 100644 public/events.html create mode 100644 public/index.html create mode 100644 public/register.html create mode 100644 public/reglement.html create mode 100644 server.mjs create mode 100755 start.sh create mode 100755 sync.sh create mode 100755 sync2.sh diff --git a/.DS_Store b/.DS_Store index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..3e99647ead68962a86cf4a11ae4c0fe0682c90be 100644 GIT binary patch literal 6148 zcmeHKO>fgc5S?vJ>$D){08%+1S>hUnxCdH^iyP7d2QD>&1E65XR%_~dqu6N%+U-t`iZ7|s))s7pjHoYC1q_=Ryl`z_lr zE!-*i8831rg@wRTQ9FM}NwV7v#a&t*|XS&_~ZAxl!EynB-siChfjyhuvL4Rwdx zaXaJg!{u`S@Sx}U{$SPfmcH*l?Rf|LhpSb`een3nvy<_8eo@FPB@GE|fXeO}yoOIG zGz7Q|XGJcHQ?xUuLnm}hM>L|Bz&>42(vpZrxVa2F5Iv!bMX+KN+%I$ zw9zVH6=*83sjFQ+|Bruv|8J6P%_?9OSStmDGYUsTOv#+Bw~ i<5(5=DBgoBL!ZY5U|_J;h!&Xr5l}MNU={eM3j73yW0~Io delta 62 zcmZoMXfc=|#>AjHu~2NHo+2v)5HM~`T*bUufrFi8Gb@K62T*deAjfy+$^0UUjEs{_ QMU*G|^KfjA5m~_u0KiTTI{*Lx diff --git a/README.md b/README.md new file mode 100644 index 0000000..d703d38 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# SuperSunday — V1 (prod, port 8080) + +## Démarrage +```bash +chmod +x start.sh +./start.sh +# http://localhost:8080 +``` + +## Fonctionnalités +- Liste d'événements +- Inscription + téléchargement iCal +- Admin: consultation des inscriptions +- Seeds réalistes (8 éditions winter + live démo + futur) diff --git a/data/db.json b/data/db.json new file mode 100644 index 0000000..fc3b274 --- /dev/null +++ b/data/db.json @@ -0,0 +1,190 @@ +{ + "config": { + "siteName": "Padel24Play — V1 (8080)", + "currency": "EUR", + "priceEur": 48, + "refundWindowHours": 48 + }, + "users": [ + { + "email": "admin@supersunday.com", + "password": "password123", + "role": "admin", + "name": "Admin" + }, + { + "email": "player@supersunday.com", + "password": "password123", + "role": "user", + "name": "Player" + } + ], + "events": [ + { + "id": "ss-winter-1", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #1", + "date": "2025-10-05T08:00:00", + "end": "2025-10-05T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-2", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #2", + "date": "2025-10-19T08:00:00", + "end": "2025-10-19T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-3", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #3", + "date": "2025-11-02T08:00:00", + "end": "2025-11-02T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-4", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #4", + "date": "2025-11-16T08:00:00", + "end": "2025-11-16T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-5", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #5", + "date": "2025-11-30T08:00:00", + "end": "2025-11-30T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-6", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #6", + "date": "2025-12-14T08:00:00", + "end": "2025-12-14T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-7", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #7", + "date": "2025-12-28T08:00:00", + "end": "2025-12-28T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-winter-8", + "kind": "Americano", + "name": "SuperSunday — Winter Edition #8", + "date": "2026-01-11T08:00:00", + "end": "2026-01-11T11:00:00", + "location": "Sport City Woluwe" + }, + { + "id": "ss-live-now", + "kind": "Americano", + "name": "SuperSunday — LIVE (démo)", + "date": "2025-08-18T18:33:23", + "end": "2025-08-18T21:33:23", + "location": "TC Églantiers" + }, + { + "id": "ss-futur-1", + "kind": "Americano", + "name": "SuperSunday — Inscription ouverte", + "date": "2025-08-28T19:03:23", + "end": "2025-08-28T22:03:23", + "location": "Sport City Woluwe" + } + ], + "registrations": [ + { + "id": "reg_seed_1", + "createdAt": "2025-08-18T19:03:23.597Z", + "eventId": "ss-live-now", + "player": { + "name": "SmashQueen", + "email": "smashqueen@demo.local", + "phone": "+32471000000", + "level": "Avancé" + }, + "payment": "card", + "status": "confirmé", + "paymentStatus": "paid" + }, + { + "id": "reg_seed_2", + "createdAt": "2025-08-18T19:03:23.600Z", + "eventId": "ss-winter-1", + "player": { + "name": "PadelKing42", + "email": "padelking42@demo.local", + "phone": "+32471000001", + "level": "Intermédiaire" + }, + "payment": "paypal", + "status": "en_attente", + "paymentStatus": "pending" + }, + { + "id": "reg_seed_3", + "createdAt": "2025-08-18T19:03:23.600Z", + "eventId": "ss-live-now", + "player": { + "name": "MrVibora", + "email": "mrvibora@demo.local", + "phone": "+32471000002", + "level": "Débutant" + }, + "payment": "onspot", + "status": "confirmé", + "paymentStatus": "paid" + }, + { + "id": "reg_seed_4", + "createdAt": "2025-08-18T19:03:23.600Z", + "eventId": "ss-winter-1", + "player": { + "name": "LaBandeja", + "email": "labandeja@demo.local", + "phone": "+32471000003", + "level": "Avancé" + }, + "payment": "card", + "status": "en_attente", + "paymentStatus": "pending" + }, + { + "id": "reg_seed_5", + "createdAt": "2025-08-18T19:03:23.600Z", + "eventId": "ss-live-now", + "player": { + "name": "MissChiquita", + "email": "misschiquita@demo.local", + "phone": "+32471000004", + "level": "Intermédiaire" + }, + "payment": "paypal", + "status": "confirmé", + "paymentStatus": "paid" + }, + { + "id": "reg_seed_6", + "createdAt": "2025-08-18T19:03:23.600Z", + "eventId": "ss-winter-1", + "player": { + "name": "VoléeMagique", + "email": "volemagique@demo.local", + "phone": "+32471000005", + "level": "Débutant" + }, + "payment": "onspot", + "status": "en_attente", + "paymentStatus": "pending" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..783f0a0 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "name": "supersunday-v1-base", + "version": "1.0.0", + "type": "module", + "scripts": { "start": "node server.mjs" } +} diff --git a/public/admin.html b/public/admin.html new file mode 100644 index 0000000..30f4ec5 --- /dev/null +++ b/public/admin.html @@ -0,0 +1,27 @@ + + +
+

🛠️ Admin — Inscriptions

+
+
+
JoueurEmailPaiementStatut
+

Version prod de base — paiements temps réel & effets à venir.

+
+
+ + diff --git a/public/assets/css/app.css b/public/assets/css/app.css new file mode 100644 index 0000000..48961f9 --- /dev/null +++ b/public/assets/css/app.css @@ -0,0 +1,27 @@ +:root{ color-scheme:dark; --bg:#0a0f1f; --card:rgba(255,255,255,.06); --line:rgba(255,255,255,.12); --txt:#eaf2ff; --acc:#27b0ff; --good:#22c55e; --bad:#ef4444 } +*{ box-sizing:border-box } +html,body{ margin:0; padding:0; background:radial-gradient(1000px 600px at 10% -10%, #122040 0%, transparent 60%), var(--bg); color:var(--txt); font-family: ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial } +a{ color:#9ad1ff; text-decoration:none } +.container{ max-width:1100px; margin:0 auto; padding:24px } +.nav{ position:sticky; top:0; z-index:10; backdrop-filter: blur(10px); background: rgba(6,12,24,.6); border-bottom:1px solid var(--line) } +.nav .inner{ display:flex; gap:16px; align-items:center; padding:12px 20px } +.brand{ display:flex; gap:10px; align-items:center; font-weight:900; letter-spacing:.3px } +.badge{ background:linear-gradient(135deg,#0ea5e9,#2563eb); padding:6px 10px; border-radius:10px; font-size:12px; font-weight:800; color:white } +.spacer{ flex:1 } +.btn{ background:linear-gradient(135deg,#0ea5e9,#2563eb); color:white; padding:10px 14px; border:0; border-radius:12px; cursor:pointer; font-weight:700; box-shadow:0 10px 24px rgba(37,99,235,.25) } +.row{ display:flex; gap:14px; flex-wrap:wrap } +.card{ background:var(--card); border:1px solid var(--line); border-radius:16px; padding:16px } +h1{ font-size:28px; margin:18px 0 } +table{ width:100%; border-collapse: collapse } +th,td{ border-top:1px solid var(--line); padding:10px 8px; text-align:left } +small{ opacity:.8 } +.hero{ display:grid; grid-template-columns: 1.2fr .8fr; gap:22px; align-items:center } +@media (max-width:900px){ .hero{ grid-template-columns:1fr } } +.pill{ border:1px solid var(--line); border-radius:999px; padding:6px 10px; display:inline-flex; gap:6px; align-items:center } +input,select{ background:#0f1b36; color:var(--txt); border:1px solid var(--line); border-radius:10px; padding:10px 12px; width:100% } +label{ font-size:13px; opacity:.9 } +.grid{ display:grid; gap:12px } +.grid-2{ grid-template-columns: 1fr 1fr } +.grid-3{ grid-template-columns: repeat(3, 1fr) } +footer{ margin-top:40px; opacity:.7; font-size:13px; border-top:1px solid var(--line); padding-top:14px } +.notice{ padding:10px 12px; border:1px dashed var(--line); border-radius:12px; background: rgba(255,255,255,.04) } diff --git a/public/assets/img/logo.svg b/public/assets/img/logo.svg new file mode 100644 index 0000000..6b476b7 --- /dev/null +++ b/public/assets/img/logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/js/app.js b/public/assets/js/app.js new file mode 100644 index 0000000..e3a18cf --- /dev/null +++ b/public/assets/js/app.js @@ -0,0 +1,12 @@ +async function api(path, opts={}){ + const res = await fetch(path, { headers:{ 'content-type':'application/json' }, ...opts }); + if (!res.ok) throw new Error(await res.text()); + const ct = res.headers.get('content-type')||''; + return ct.includes('application/json')? res.json() : res.text(); +} +document.addEventListener('DOMContentLoaded', async ()=>{ + try { + const cfg = await api('/api/config'); + const el = document.querySelector('.title'); if (el) el.textContent = cfg.siteName || 'Padel24Play'; + } catch {} +}); diff --git a/public/events.html b/public/events.html new file mode 100644 index 0000000..ba05acc --- /dev/null +++ b/public/events.html @@ -0,0 +1,18 @@ + + +
+

📅 Événements

+
+
NomTypeDateLieu
+
+
+ + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..6e8981c --- /dev/null +++ b/public/index.html @@ -0,0 +1,28 @@ + + +
+
+
+

🎉 SuperSunday — V1 (prod)

+

Base propre prête à tester (port 8080) — événements, inscriptions, iCal.

+ +

Version sans effets “waouw” pour rester simple. On les ajoutera en brique.

+
+
+

Ce qui est dedans

+
    +
  • 8 éditions Winter (tous les 14 jours dès dim. 5 oct. 2025, 08:00–11:00)
  • +
  • Un live démo (pour les inscriptions) et un futur ouvert
  • +
  • Formulaire d’inscription + iCal
  • +
+
+
+
+ diff --git a/public/register.html b/public/register.html new file mode 100644 index 0000000..cca8a61 --- /dev/null +++ b/public/register.html @@ -0,0 +1,32 @@ + + +
+

📝 Inscription

+
+
+
+
+
+
+
+
+
+

+
+
+ + diff --git a/public/reglement.html b/public/reglement.html new file mode 100644 index 0000000..5c55c7f --- /dev/null +++ b/public/reglement.html @@ -0,0 +1,10 @@ + + +
+

📜 Règlement (extrait)

+

Americano, fair‑play, BYE équitables, remboursement jusqu’à J‑2 (48h), iCal après inscription.

+
diff --git a/server.mjs b/server.mjs new file mode 100644 index 0000000..673ac3f --- /dev/null +++ b/server.mjs @@ -0,0 +1,146 @@ +import http from 'http'; +import { readFile, writeFile, stat } from 'fs/promises'; +import { createReadStream } from 'fs'; +import path from 'path'; +import url from 'url'; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); +const PORT = process.env.PORT || 8080; +const DATA_DIR = path.join(__dirname, 'data'); +const DB_PATH = path.join(DATA_DIR, 'db.json'); + +const mime = { '.html':'text/html; charset=utf-8','.css':'text/css; charset=utf-8','.js':'application/javascript; charset=utf-8','.json':'application/json; charset=utf-8','.svg':'image/svg+xml','.png':'image/png','.ico':'image/x-icon','.webp':'image/webp' }; + +function send(res, code, body, headers={}){ res.writeHead(code, { 'content-type':'text/plain; charset=utf-8', ...headers }); res.end(body); } + +async function ensureDb(){ + try { await stat(DB_PATH); } + catch { + const base = new Date(Date.UTC(2025, 9, 5, 8, 0, 0)); // 5 Oct 2025 08:00 UTC + const events = []; + for (let i=0;i<8;i++){ + const start = new Date(base.getTime() + i*14*24*3600*1000); + const end = new Date(start.getTime() + 3*3600*1000); + events.push({ id:`ss-winter-${i+1}`, kind:"Americano", name:`SuperSunday — Winter Edition #${i+1}`, date:start.toISOString().slice(0,19), end:end.toISOString().slice(0,19), location:"Sport City Woluwe" }); + } + const now = new Date(); + events.push( + { id:"ss-live-now", kind:"Americano", name:"SuperSunday — LIVE (démo)", date: new Date(now.getTime()-30*60*1000).toISOString().slice(0,19), end: new Date(now.getTime()+2.5*3600*1000).toISOString().slice(0,19), location:"TC Églantiers" }, + { id:"ss-futur-1", kind:"Americano", name:"SuperSunday — Inscription ouverte", date: new Date(now.getTime()+10*24*3600*1000).toISOString().slice(0,19), end: new Date(now.getTime()+10*24*3600*1000+3*3600*1000).toISOString().slice(0,19), location:"Sport City Woluwe" } + ); + const names = ["SmashQueen","PadelKing42","MrVibora","LaBandeja","MissChiquita","VoléeMagique"]; + const regs = names.map((n,i)=>({ + id:`reg_seed_${i+1}`, createdAt:new Date().toISOString(), eventId: i%2===0? "ss-live-now" : "ss-winter-1", + player:{ name:n, email:`${n.replace(/[^a-z0-9]/ig,'').toLowerCase()}@demo.local`, phone:`+3247${(1000000+i).toString().padStart(7,'0')}`, level: i%3===0? "Avancé": (i%3===1? "Intermédiaire":"Débutant") }, + payment:i%3===0? "card": (i%3===1? "paypal":"onspot"), status: i%2===0? "confirmé":"en_attente", paymentStatus: i%2===0? "paid":"pending" + })); + await writeFile(DB_PATH, JSON.stringify({ + config:{ siteName:"Padel24Play — V1 (8080)", currency:"EUR", priceEur:48, refundWindowHours:48 }, + users:[ + { email:"admin@supersunday.com", password:"password123", role:"admin", name:"Admin"}, + { email:"player@supersunday.com", password:"password123", role:"user", name:"Player"} + ], + events, registrations: regs + }, null, 2)); + } +} +async function loadDb(){ await ensureDb(); return JSON.parse(await readFile(DB_PATH,'utf-8')); } +async function saveDb(d){ await writeFile(DB_PATH, JSON.stringify(d,null,2)); } + +function sendJson(res, obj){ send(res, 200, JSON.stringify(obj), {'content-type':'application/json'}); } + +async function parseBody(req){ + return new Promise((resolve,reject)=>{ + let data=''; req.on('data',c=> data+=c); req.on('end', ()=>{ + try{ + const ct = req.headers['content-type']||''; + if (!data) return resolve({}); + if (ct.includes('application/json')) return resolve(JSON.parse(data)); + if (ct.includes('application/x-www-form-urlencoded')){ + const out={}; data.split('&').forEach(kv=>{ const [k,v] = kv.split('='); out[decodeURIComponent(k)] = decodeURIComponent((v||'').replace(/\\+/g,' ')); }); + return resolve(out); + } + resolve({ raw:data }); + }catch(e){ reject(e); } + }); + }); +} + +async function serveStatic(req,res){ + const publicDir = path.join(__dirname, 'public'); + let pathname = url.parse(req.url).pathname || '/'; + if (pathname === '/') pathname = '/index.html'; + const filePath = path.join(publicDir, pathname); + try { + const st = await stat(filePath); + if (!st.isDirectory()){ + const ext = path.extname(filePath).toLowerCase(); + res.writeHead(200, {'content-type': mime[ext] || 'application/octet-stream'}); + createReadStream(filePath).pipe(res); + return true; + } + }catch{} + return false; +} + +function isoToV(s){ return s.replace(/[-:]/g,'').replace('T','')+'Z'; } + +async function handleApi(req,res){ + const { pathname, query } = url.parse(req.url, true); + + if (pathname === '/api/config' && req.method==='GET'){ + const d = await loadDb(); return sendJson(res, d.config); + } + + if (pathname === '/api/events' && req.method==='GET'){ + const d = await loadDb(); return sendJson(res, d.events); + } + if (pathname === '/api/registrations' && req.method==='GET'){ + const d = await loadDb(); const list = query.eventId ? d.registrations.filter(r=> r.eventId===query.eventId) : d.registrations; + return sendJson(res, list); + } + if (pathname === '/api/registrations' && req.method==='POST'){ + const d = await loadDb(); const body = await parseBody(req); + const id = 'reg_'+Math.random().toString(36).slice(2,10); + const rec = { id, createdAt:new Date().toISOString(), status:'en_attente', paymentStatus:'pending', ...body }; + d.registrations.push(rec); await saveDb(d); + return sendJson(res, rec); + } + + if (pathname.startsWith('/api/ical/') && req.method==='GET'){ + const regId = pathname.split('/').pop(); + const d = await loadDb(); const reg = d.registrations.find(r=> r.id===regId); + if (!reg) return send(res,404,'Not found'); + const ev = d.events.find(e=> e.id===reg.eventId); + if (!ev) return send(res,404,'Event not found'); + const ics = [ + 'BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//P24P//SuperSunday//FR', + 'BEGIN:VEVENT', + `UID:${reg.id}@p24p`, + `DTSTAMP:${isoToV(ev.date)}`, + `DTSTART:${isoToV(ev.date)}`, + `DTEND:${isoToV(ev.end)}`, + `SUMMARY:${ev.name}`, + `LOCATION:${ev.location}`, + `DESCRIPTION:Inscription ${reg.player?.name||''}`, + 'END:VEVENT','END:VCALENDAR' + ].join('\\r\\n'); + return send(res,200,ics,{'content-type':'text/calendar; charset=utf-8','content-disposition':`attachment; filename="${reg.id}.ics"`}); + } + + return false; +} + +const server = http.createServer(async (req,res)=>{ + try{ + if (req.url.startsWith('/api/')){ + const ok = await handleApi(req,res); + if (ok===false) return send(res,404,'API not found'); + return; + } + const ok = await serveStatic(req,res); + if (!ok) send(res,404,'Not found'); + }catch(e){ console.error(e); send(res,500,'Server error'); } +}); + +server.listen(PORT, ()=> console.log(`✅ SuperSunday V1 (prod) http://localhost:${PORT}`)); diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..1518835 --- /dev/null +++ b/start.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo "🚀 SuperSunday V1 (prod) on :8080" +export PORT=8080 +export ENABLE_EFFECTS=0 +node server.mjs diff --git a/sync.sh b/sync.sh new file mode 100755 index 0000000..ac696f2 --- /dev/null +++ b/sync.sh @@ -0,0 +1,25 @@ +{\rtf1\ansi\ansicpg1252\cocoartf2822 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 .AppleSystemUIFontMonospaced-Regular;} +{\colortbl;\red255\green255\blue255;\red135\green5\blue129;\red0\green0\blue0;\red181\green0\blue19; +\red50\green91\blue97;\red13\green100\blue1;\red151\green0\blue126;} +{\*\expandedcolortbl;;\cssrgb\c60784\c13725\c57647;\csgray\c0;\cssrgb\c76863\c10196\c8627; +\cssrgb\c24706\c43137\c45490;\cssrgb\c0\c45490\c0;\cssrgb\c66667\c5098\c56863;} +\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 + +\f0\fs26 \cf2 #!/bin/bash\cf3 \ +set -e\ +MSG=\cf4 "\cf5 $\{1:-chore: quick sync\}\cf4 "\cf3 \ +\ +\cf6 # S\'92assure qu\'92on est dans un repo\cf3 \ +git rev-parse --is-inside-work-tree >/dev/null 2>&1 || \{ echo \cf4 "Pas un d\'e9p\'f4t Git"\cf3 ; exit 1; \}\ +\ +\cf6 # Ajoute, commit et push\cf3 \ +git add -A\ +\cf7 if\cf3 ! git diff --cached --quiet; \cf7 then\cf3 \ + git commit -m \cf4 "\cf5 $MSG\cf4 "\cf3 \ +\cf7 else\cf3 \ + echo \cf4 "Rien \'e0 committer."\cf3 \ +\cf7 fi\cf3 \ +git push\ +echo \cf4 "\uc0\u9989 Sync OK"} \ No newline at end of file diff --git a/sync2.sh b/sync2.sh new file mode 100755 index 0000000..651fd28 --- /dev/null +++ b/sync2.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e +MSG="${1:-chore: quick sync}" + +# S’assure qu’on est dans un repo +git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "Pas un dépôt Git"; exit 1; } + +# Ajoute, commit et push +git add -A +if ! git diff --cached --quiet; then + git commit -m "$MSG" +else + echo "Rien à committer." +fi +git push +echo "✅ Sync OK"