{"id":62,"date":"2026-01-17T18:24:53","date_gmt":"2026-01-17T17:24:53","guid":{"rendered":"https:\/\/www.disquaires.org\/?page_id=62"},"modified":"2026-06-17T13:30:36","modified_gmt":"2026-06-17T11:30:36","slug":"les-adherents","status":"publish","type":"page","link":"https:\/\/www.disquaires.org\/index.php\/les-adherents\/","title":{"rendered":"Les Adh\u00e9rents"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Adh\u00e9rents ADIN<\/title>\n\n<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet\/1.9.4\/leaflet.min.css\"\/>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=DM+Serif+Display:ital@0;1&#038;family=DM+Sans:wght@300;400;500&#038;display=swap\" rel=\"stylesheet\">\n\n<style>\n  :root {\n    --vert:   #2D5016;\n    --creme:  #F5F0E8;\n    --noir:   #1A1A1A;\n    --gris:   #6B6B6B;\n    --border: #D4CCBB;\n  }\n\n  * { box-sizing: border-box; margin: 0; padding: 0; }\n\n  #adin-wrap {\n    font-family: 'DM Sans', sans-serif;\n    color: var(--noir);\n    background: var(--creme);\n    max-width: 80%;\n    margin: 0 auto;\n  }\n\n  \/* \u2500\u2500 TABS \u2500\u2500 *\/\n  .tabs { display: flex; border-bottom: 2px solid var(--border); }\n  .tab-btn {\n    padding: 12px 28px;\n    background: none;\n    border: none;\n    font-family: 'DM Sans', sans-serif;\n    font-size: 14px;\n    font-weight: 500;\n    letter-spacing: .06em;\n    text-transform: uppercase;\n    color: var(--gris);\n    cursor: pointer;\n    border-bottom: 3px solid transparent;\n    margin-bottom: -2px;\n    transition: all .2s;\n  }\n  .tab-btn.active { color: var(--vert); border-bottom-color: var(--vert); }\n  .tab-btn:hover:not(.active) { color: var(--noir); }\n\n  \/* \u2500\u2500 CARTE \u2500\u2500 *\/\n  #map { width: 100%; height: 540px; border-radius: 0 0 4px 4px; background: #e8e0d0; }\n\n  \/* \u2500\u2500 FILTRE \u2500\u2500 *\/\n  .filter-bar {\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    padding: 14px 0 16px;\n    flex-wrap: wrap;\n  }\n  .filter-bar label {\n    font-size: 13px; color: var(--gris); font-weight: 500;\n    letter-spacing: .04em; text-transform: uppercase;\n  }\n  #search-input {\n    flex: 1; min-width: 200px;\n    padding: 8px 14px;\n    border: 1.5px solid var(--border);\n    border-radius: 3px;\n    font-family: 'DM Sans', sans-serif;\n    font-size: 14px;\n    background: white;\n    outline: none;\n    transition: border-color .2s;\n  }\n  #search-input:focus { border-color: var(--vert); }\n  #count-label { font-size: 13px; color: var(--gris); margin-left: auto; white-space: nowrap; }\n\n  \/* \u2500\u2500 PANELS \u2500\u2500 *\/\n  #list-panel { display: none; padding-top: 8px; }\n  #list-panel.active { display: block; }\n  #map-panel { display: none; }\n  #map-panel.active { display: block; }\n\n  \/* \u2500\u2500 GRILLE \u2500\u2500 *\/\n  .disquaire-grid {\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n    gap: 16px;\n    padding-bottom: 24px;\n  }\n  .card {\n    background: white;\n    border: 1.5px solid var(--border);\n    border-radius: 4px;\n    padding: 20px;\n    transition: border-color .2s, transform .15s;\n    display: flex; flex-direction: column; gap: 8px;\n  }\n  .card:hover { border-color: var(--vert); transform: translateY(-2px); }\n  .card-name { font-family: 'DM Serif Display', serif; font-size: 18px; color: var(--noir); line-height: 1.2; }\n  .card-adresse { font-size: 13px; color: var(--gris); }\n  .card-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }\n  .card-link {\n    display: inline-flex; align-items: center; gap: 5px;\n    font-size: 12px; font-weight: 500;\n    color: var(--vert); text-decoration: none;\n    border: 1.5px solid var(--vert); border-radius: 2px;\n    padding: 3px 9px; transition: background .15s, color .15s;\n  }\n  .card-link:hover { background: var(--vert); color: white; }\n  .card-link.social { color: var(--gris); border-color: var(--border); }\n  .card-link.social:hover { background: var(--gris); color: white; border-color: var(--gris); }\n\n  \/* \u2500\u2500 POPUP \u2500\u2500 *\/\n  .leaflet-popup-content-wrapper {\n    border-radius: 4px !important;\n    box-shadow: 0 4px 20px rgba(0,0,0,.15) !important;\n    border: 1.5px solid var(--border);\n  }\n  .popup-inner { font-family: 'DM Sans', sans-serif; min-width: 180px; }\n  .popup-name { font-family: 'DM Serif Display', serif; font-size: 16px; color: var(--noir); margin-bottom: 4px; }\n  .popup-adresse { font-size: 12px; color: var(--gris); margin-bottom: 10px; }\n  .popup-links { display: flex; flex-wrap: wrap; gap: 6px; }\n  .popup-link {\n    font-size: 12px; font-weight: 500;\n    color: var(--vert); text-decoration: none;\n    border: 1.5px solid var(--vert); border-radius: 2px;\n    padding: 2px 8px; transition: background .15s, color .15s;\n  }\n  .popup-link:hover { background: var(--vert); color: white; }\n\n  \/* \u2500\u2500 LOADING \u2500\u2500 *\/\n  #loading { padding: 60px 0; text-align: center; color: var(--gris); font-size: 14px; }\n  .spinner {\n    width: 28px; height: 28px;\n    border: 3px solid var(--border); border-top-color: var(--vert);\n    border-radius: 50%; animation: spin .7s linear infinite;\n    margin: 0 auto 14px;\n  }\n  @keyframes spin { to { transform: rotate(360deg); } }\n\n  \/* \u2500\u2500 MARQUEUR \u2500\u2500 *\/\n  .marker-dot {\n    width: 14px; height: 14px;\n    background: var(--vert); border: 2.5px solid white;\n    border-radius: 50%; box-shadow: 0 2px 6px rgba(0,0,0,.3);\n  }\n<\/style>\n<\/head>\n<body>\n\n<div id=\"adin-wrap\">\n\n  <div class=\"tabs\">\n    <button class=\"tab-btn active\" data-tab=\"map\">\ud83d\uddfa Carte<\/button>\n    <button class=\"tab-btn\" data-tab=\"list\">\u2630 Liste<\/button>\n  <\/div>\n\n  <div class=\"filter-bar\">\n    <label for=\"search-input\">Rechercher<\/label>\n    <input type=\"text\" id=\"search-input\" placeholder=\"Nom, ville, code postal\u2026\">\n    <span id=\"count-label\"><\/span>\n  <\/div>\n\n  <div id=\"map-panel\" class=\"active\">\n    <div id=\"map\"><\/div>\n  <\/div>\n\n  <div id=\"list-panel\">\n    <div id=\"loading\"><div class=\"spinner\"><\/div>Chargement des adh\u00e9rents\u2026<\/div>\n    <div class=\"disquaire-grid\" id=\"grid\" style=\"display:none\"><\/div>\n  <\/div>\n\n<\/div>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet\/1.9.4\/leaflet.min.js\"><\/script>\n<script>\n\n\/\/ \u2500\u2500 Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst API_URL = \"https:\/\/script.google.com\/macros\/s\/AKfycbwLOCrpc0clEYZQ0C-ycJagOrZDP_PB03xCB4KPptBMK-2mZgMq3mXCTEpvpQoNqeEUzw\/exec\";\n\n\/\/ \u2500\u2500 \u00c9tat \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet allData = [];\nlet markers = [];\nlet leafletMap;\n\n\/\/ \u2500\u2500 Init carte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction initMap() {\n  leafletMap = L.map('map', { zoomControl: true }).setView([46.6, 2.3], 5);\n  L.tileLayer('https:\/\/{s}.basemaps.cartocdn.com\/light_all\/{z}\/{x}\/{y}{r}.png', {\n    attribution: '\u00a9 OpenStreetMap \u00a9 CARTO',\n    maxZoom: 19\n  }).addTo(leafletMap);\n}\n\n\/\/ \u2500\u2500 Ic\u00f4ne marqueur \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction makeIcon() {\n  return L.divIcon({\n    className: '',\n    html: '<div class=\"marker-dot\"><\/div>',\n    iconSize: [14, 14], iconAnchor: [7, 7], popupAnchor: [0, -10]\n  });\n}\n\n\/\/ \u2500\u2500 G\u00e9ocodage Nominatim \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function geocode(row) {\n  if (row.lat && row.lng) {\n    const lat = parseFloat(row.lat), lng = parseFloat(row.lng);\n    if (!isNaN(lat) && !isNaN(lng)) return { lat, lng };\n  }\n  const q = [row.adresse, \"France\"].filter(Boolean).join(\", \");\n  try {\n    await new Promise(r => setTimeout(r, 1100));\n    const res = await fetch(\n      `https:\/\/nominatim.openstreetmap.org\/search?format=json&limit=1&q=${encodeURIComponent(q)}`,\n      { headers: { 'Accept-Language': 'fr' } }\n    );\n    const j = await res.json();\n    if (j.length) return { lat: parseFloat(j[0].lat), lng: parseFloat(j[0].lon) };\n  } catch(e) {}\n  return null;\n}\n\n\/\/ \u2500\u2500 URL s\u00e9curis\u00e9e \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction safeUrl(url) {\n  if (!url || !url.trim()) return null;\n  return url.trim().startsWith(\"http\") ? url.trim() : \"https:\/\/\" + url.trim();\n}\n\n\/\/ \u2500\u2500 Popup carte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction popupHTML(row) {\n  let links = \"\";\n  if (safeUrl(row.site))      links += `<a class=\"popup-link\" href=\"${safeUrl(row.site)}\" target=\"_blank\">Site web<\/a>`;\n  if (safeUrl(row.instagram)) links += `<a class=\"popup-link\" href=\"${safeUrl(row.instagram)}\" target=\"_blank\">Instagram<\/a>`;\n  if (safeUrl(row.facebook))  links += `<a class=\"popup-link\" href=\"${safeUrl(row.facebook)}\" target=\"_blank\">Facebook<\/a>`;\n  return `<div class=\"popup-inner\">\n    <div class=\"popup-name\">${row.nom}<\/div>\n    <div class=\"popup-adresse\">${row.adresse}<\/div>\n    ${links ? `<div class=\"popup-links\">${links}<\/div>` : \"\"}\n  <\/div>`;\n}\n\n\/\/ \u2500\u2500 Carte disquaire (liste) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction cardHTML(row) {\n  let links = \"\";\n  if (safeUrl(row.site))      links += `<a class=\"card-link\" href=\"${safeUrl(row.site)}\" target=\"_blank\">\ud83c\udf10 Site web<\/a>`;\n  if (safeUrl(row.instagram)) links += `<a class=\"card-link social\" href=\"${safeUrl(row.instagram)}\" target=\"_blank\">Instagram<\/a>`;\n  if (safeUrl(row.facebook))  links += `<a class=\"card-link social\" href=\"${safeUrl(row.facebook)}\" target=\"_blank\">Facebook<\/a>`;\n  if (safeUrl(row.linkedin))  links += `<a class=\"card-link social\" href=\"${safeUrl(row.linkedin)}\" target=\"_blank\">LinkedIn<\/a>`;\n  if (row.tel)                links += `<a class=\"card-link social\" href=\"tel:${row.tel}\">\ud83d\udcde ${row.tel}<\/a>`;\n\n  const div = document.createElement('div');\n  div.className = 'card';\n  div.dataset.search = (row.nom + \" \" + row.adresse).toLowerCase();\n  div.innerHTML = `\n    <div class=\"card-name\">${row.nom}<\/div>\n    <div class=\"card-adresse\">${row.adresse}<\/div>\n    ${links ? `<div class=\"card-links\">${links}<\/div>` : \"\"}\n  `;\n  return div;\n}\n\n\/\/ \u2500\u2500 Chargement depuis Google Sheets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function loadData() {\n  try {\n    const res = await fetch(API_URL);\n    const raw = await res.json();\n    const str = v => (v === undefined || v === null ? \"\" : String(v)).trim();\n    allData = raw\n      .filter(r => str(r[\"Nom du disquaire\"]))\n      .map(r => ({\n        nom:       str(r[\"Nom du disquaire\"]),\n        adresse:   str(r[\"Adresse postale\"]),\n        tel:       str(r[\"T\u00e9l\u00e9phone\"]),\n        email:     str(r[\"Email\"]),\n        site:      str(r[\"Site web\"]),\n        facebook:  str(r[\"Facebook\"]),\n        instagram: str(r[\"Instagram\"]),\n        linkedin:  str(r[\"Linkedin\"]),\n        lat:       str(r[\"lat\"]),\n        lng:       str(r[\"lng\"]),\n      }));\n    renderList(allData);\n    renderMap(allData);\n  } catch(e) {\n    document.getElementById('loading').innerHTML =\n      `<p style=\"color:#c0392b;font-size:14px;max-width:480px;margin:0 auto\">\n        \u26a0\ufe0f Impossible de charger les donn\u00e9es.<br><small>${e}<\/small>\n      <\/p>`;\n  }\n}\n\n\/\/ \u2500\u2500 Rendu carte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function renderMap(rows) {\n  markers.forEach(m => leafletMap.removeLayer(m));\n  markers = [];\n  for (const row of rows) {\n    const pos = await geocode(row);\n    if (!pos) continue;\n    const m = L.marker([pos.lat, pos.lng], { icon: makeIcon() })\n      .bindPopup(popupHTML(row), { maxWidth: 260 })\n      .addTo(leafletMap);\n    markers.push(m);\n  }\n}\n\n\/\/ \u2500\u2500 Rendu liste \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction renderList(rows) {\n  const grid = document.getElementById('grid');\n  document.getElementById('loading').style.display = 'none';\n  grid.style.display = 'grid';\n  grid.innerHTML = '';\n  rows.forEach(r => grid.appendChild(cardHTML(r)));\n  updateCount(rows.length);\n}\n\nfunction updateCount(n) {\n  document.getElementById('count-label').textContent = n + \" disquaire\" + (n > 1 ? \"s\" : \"\");\n}\n\n\/\/ \u2500\u2500 Recherche \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.getElementById('search-input').addEventListener('input', function() {\n  const q = this.value.toLowerCase().trim();\n  let visible = 0;\n  document.querySelectorAll('.card').forEach(c => {\n    const match = !q || c.dataset.search.includes(q);\n    c.style.display = match ? '' : 'none';\n    if (match) visible++;\n  });\n  updateCount(visible);\n  renderMap(allData.filter(r => !q || (r.nom + \" \" + r.adresse).toLowerCase().includes(q)));\n});\n\n\/\/ \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.querySelectorAll('.tab-btn').forEach(btn => {\n  btn.addEventListener('click', function() {\n    document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));\n    this.classList.add('active');\n    const tab = this.dataset.tab;\n    document.getElementById('map-panel').classList.toggle('active', tab === 'map');\n    document.getElementById('list-panel').classList.toggle('active', tab === 'list');\n    if (tab === 'map') leafletMap.invalidateSize();\n  });\n});\n\n\/\/ \u2500\u2500 D\u00e9marrage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ninitMap();\nloadData();\n<\/script>\n<\/body>\n<\/html>\n\n\n","protected":false},"excerpt":{"rendered":"<p>Adh\u00e9rents ADIN \ud83d\uddfa Carte \u2630 Liste Rechercher Chargement des adh\u00e9rents\u2026<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-62","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/pages\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/comments?post=62"}],"version-history":[{"count":21,"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/pages\/62\/revisions"}],"predecessor-version":[{"id":175,"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/pages\/62\/revisions\/175"}],"wp:attachment":[{"href":"https:\/\/www.disquaires.org\/index.php\/wp-json\/wp\/v2\/media?parent=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}