Pharmacies De Garde Tanger
Phardegarde est un site qui fournit des informations sur les pharmacies de garde tanger. Il aide les habitants et les visiteurs à trouver rapidement les pharmacies de garde tanger ouvertes la nuit, les week-ends et les jours fériés.
#pharmacies-widget-fr * {
box-sizing: border-box;
}
#pharmacies-widget-fr {
font-family: Arial, sans-serif;
background: #f4f6fb;
padding: 20px 14px 35px;
direction: ltr;
}
#pharmacies-widget-fr .pw-wrap {
max-width: 1100px;
margin: 0 auto;
}
#pharmacies-widget-fr .pw-header {
text-align: center;
margin-bottom: 20px;
}
#pharmacies-widget-fr .pw-header h2 {
margin: 0;
font-size: 30px;
font-weight: 800;
color: #1a1a2e;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
#pharmacies-widget-fr .pw-date {
margin-top: 8px;
color: #666;
font-size: 14px;
}
#pharmacies-widget-fr .pw-notice {
background: #fff8e1;
border-left: 4px solid #f5a623;
border-radius: 10px;
padding: 12px 16px;
margin-bottom: 22px;
color: #7a5c00;
font-size: 14px;
line-height: 1.7;
}
#pharmacies-widget-fr .pw-status {
background: #ffffff;
border-radius: 12px;
padding: 14px 16px;
margin-bottom: 18px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
color: #444;
font-size: 14px;
}
#pharmacies-widget-fr .pw-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
}
@media (max-width: 900px) {
#pharmacies-widget-fr .pw-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 560px) {
#pharmacies-widget-fr .pw-grid {
grid-template-columns: 1fr;
}
}
#pharmacies-widget-fr .pw-card {
background: #fff;
border-radius: 18px;
padding: 18px 16px 16px;
box-shadow: 0 4px 18px rgba(0,0,0,0.07);
display: flex;
flex-direction: column;
gap: 10px;
position: relative;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
min-height: 250px;
}
#pharmacies-widget-fr .pw-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 28px rgba(0,0,0,0.12);
}
#pharmacies-widget-fr .pw-card::before {
content: '';
position: absolute;
top: -12px;
left: -12px;
width: 60px;
height: 60px;
border-radius: 50%;
opacity: 0.08;
}
#pharmacies-widget-fr .c1::before { background: #e53935; }
#pharmacies-widget-fr .c2::before { background: #1e88e5; }
#pharmacies-widget-fr .c3::before { background: #43a047; }
#pharmacies-widget-fr .c4::before { background: #fb8c00; }
#pharmacies-widget-fr .c5::before { background: #8e24aa; }
#pharmacies-widget-fr .c6::before { background: #00897b; }
#pharmacies-widget-fr .pw-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
border-radius: 20px;
font-size: 12px;
font-weight: 700;
width: fit-content;
}
#pharmacies-widget-fr .pw-badge.ok {
background: #e8f5e9;
color: #2e7d32;
}
#pharmacies-widget-fr .pw-badge.partial {
background: #fff3e0;
color: #ef6c00;
}
#pharmacies-widget-fr .pw-badge.unknown {
background: #eceff1;
color: #455a64;
}
#pharmacies-widget-fr .pw-title {
font-size: 18px;
font-weight: 800;
color: #1a1a2e;
line-height: 1.5;
padding-right: 50px;
}
#pharmacies-widget-fr .pw-pill {
position: absolute;
top: 14px;
right: 14px;
width: 42px;
height: 42px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 18px;
font-weight: bold;
}
#pharmacies-widget-fr .c1 .pw-pill { background: #e53935; }
#pharmacies-widget-fr .c2 .pw-pill { background: #1e88e5; }
#pharmacies-widget-fr .c3 .pw-pill { background: #43a047; }
#pharmacies-widget-fr .c4 .pw-pill { background: #fb8c00; }
#pharmacies-widget-fr .c5 .pw-pill { background: #8e24aa; }
#pharmacies-widget-fr .c6 .pw-pill { background: #00897b; }
#pharmacies-widget-fr .pw-info {
display: flex;
flex-direction: column;
gap: 8px;
}
#pharmacies-widget-fr .pw-row {
display: flex;
align-items: flex-start;
gap: 9px;
font-size: 14px;
color: #444;
line-height: 1.6;
word-break: break-word;
}
#pharmacies-widget-fr .pw-row .pw-ico {
width: 16px;
flex-shrink: 0;
text-align: center;
margin-top: 2px;
}
#pharmacies-widget-fr .pw-row a {
color: #1976d2;
font-weight: 700;
text-decoration: none;
}
#pharmacies-widget-fr .pw-row a:hover {
text-decoration: underline;
}
#pharmacies-widget-fr .pw-map-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 14px;
border-radius: 10px;
font-size: 14px;
font-weight: 700;
text-decoration: none;
color: #fff;
margin-top: auto;
transition: opacity 0.2s, transform 0.15s;
}
#pharmacies-widget-fr .pw-map-btn:hover {
opacity: 0.9;
transform: scale(0.98);
}
#pharmacies-widget-fr .c1 .pw-map-btn { background: linear-gradient(135deg, #e53935, #ef9a9a); }
#pharmacies-widget-fr .c2 .pw-map-btn { background: linear-gradient(135deg, #1e88e5, #90caf9); }
#pharmacies-widget-fr .c3 .pw-map-btn { background: linear-gradient(135deg, #43a047, #a5d6a7); }
#pharmacies-widget-fr .c4 .pw-map-btn { background: linear-gradient(135deg, #fb8c00, #ffcc80); }
#pharmacies-widget-fr .c5 .pw-map-btn { background: linear-gradient(135deg, #8e24aa, #ce93d8); }
#pharmacies-widget-fr .c6 .pw-map-btn { background: linear-gradient(135deg, #00897b, #80cbc4); }
#pharmacies-widget-fr .pw-footer {
margin-top: 28px;
background: #fff;
border-radius: 14px;
padding: 18px 20px;
font-size: 14px;
color: #555;
line-height: 1.8;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
#pharmacies-widget-fr .pw-footer strong {
display: block;
font-size: 15px;
color: #1a1a2e;
margin-bottom: 8px;
}
#pharmacies-widget-fr .pw-loading,
#pharmacies-widget-fr .pw-empty,
#pharmacies-widget-fr .pw-error {
background: #fff;
border-radius: 16px;
padding: 30px 20px;
text-align: center;
box-shadow: 0 4px 18px rgba(0,0,0,0.07);
grid-column: 1 / -1;
}
#pharmacies-widget-fr .pw-spinner {
width: 42px;
height: 42px;
border: 4px solid #e3f2fd;
border-top-color: #1e88e5;
border-radius: 50%;
margin: 0 auto 12px;
animation: pw-spin 1s linear infinite;
}
@keyframes pw-spin {
to { transform: rotate(360deg); }
}
(function () {
const CONFIG = {
city: "Casablanca",
country: "Morocco",
limit: 6,
radius: 6000
};
const root = document.getElementById("pharmacies-widget-fr");
if (!root) return;
root.innerHTML = `
`;
const statusBox = root.querySelector("#pw-status");
const grid = root.querySelector("#pw-grid");
const dateBox = root.querySelector("#pw-date");
const colors = ["c1", "c2", "c3", "c4", "c5", "c6"];
function escapeHtml(str) {
return String(str || "")
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function formatDateFr() {
const now = new Date();
dateBox.textContent = now.toLocaleDateString("fr-FR", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
}
function buildMapUrl(lat, lon) {
return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(lat + "," + lon)}`;
}
function normalizePhone(phone) {
return String(phone || "").replace(/[^\d+]/g, "");
}
function getBadge(item) {
if (item.opening_hours) {
return { cls: "ok", label: "Horaires disponibles" };
}
if (item.phone) {
return { cls: "partial", label: "Infos partielles" };
}
return { cls: "unknown", label: "Infos limitées" };
}
function haversine(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) *
Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)));
}
async function geocodeCity(city, country) {
const url = `https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&city=${encodeURIComponent(city)}&country=${encodeURIComponent(country)}`;
const res = await fetch(url, {
headers: {
"Accept": "application/json"
}
});
if (!res.ok) throw new Error("Impossible de localiser la ville.");
const data = await res.json();
if (!Array.isArray(data) || !data.length) {
throw new Error("Ville introuvable.");
}
return {
lat: parseFloat(data[0].lat),
lon: parseFloat(data[0].lon),
name: data[0].display_name || city
};
}
async function fetchPharmacies(lat, lon, radius) {
const query = `
[out:json][timeout:25];
(
node["amenity"="pharmacy"](around:${radius},${lat},${lon});
way["amenity"="pharmacy"](around:${radius},${lat},${lon});
relation["amenity"="pharmacy"](around:${radius},${lat},${lon});
);
out center tags;
`.trim();
const res = await fetch("https://overpass-api.de/api/interpreter", {
method: "POST",
headers: {
"Content-Type": "text/plain;charset=UTF-8"
},
body: query
});
if (!res.ok) {
throw new Error("Erreur lors du chargement des pharmacies.");
}
const data = await res.json();
return Array.isArray(data.elements) ? data.elements : [];
}
function normalizeItem(item, centerLat, centerLon) {
const tags = item.tags || {};
const lat = item.lat || (item.center && item.center.lat);
const lon = item.lon || (item.center && item.center.lon);
if (!lat || !lon) return null;
const name = tags.name || "Pharmacie";
const phone = tags.phone || tags["contact:phone"] || "";
const opening_hours = tags.opening_hours || "";
const website = tags.website || tags["contact:website"] || "";
const parts = [];
if (tags["addr:housenumber"]) parts.push(tags["addr:housenumber"]);
if (tags["addr:street"]) parts.push(tags["addr:street"]);
const street = parts.join(" ").trim();
const city = tags["addr:city"] || tags["addr:town"] || tags["addr:village"] || CONFIG.city;
const full_address = [street, city].filter(Boolean).join(", ") || "Adresse non disponible";
return {
name,
phone,
opening_hours,
website,
city,
full_address,
lat: parseFloat(lat),
lon: parseFloat(lon),
distance: haversine(centerLat, centerLon, parseFloat(lat), parseFloat(lon)).toFixed(2),
map_url: buildMapUrl(lat, lon)
};
}
function renderItems(items) {
if (!items.length) {
grid.innerHTML = `
${
item.website
? `
`
: ""
}
Voir sur la carte
`;
}).join("");
}
async function init() {
try {
formatDateFr();
statusBox.textContent = "Recherche de la ville configurée...";
const cityData = await geocodeCity(CONFIG.city, CONFIG.country);
statusBox.textContent = `Chargement des pharmacies autour de ${CONFIG.city}...`;
const rawItems = await fetchPharmacies(cityData.lat, cityData.lon, CONFIG.radius);
const items = rawItems
.map(item => normalizeItem(item, cityData.lat, cityData.lon))
.filter(Boolean)
.sort((a, b) => parseFloat(a.distance) - parseFloat(b.distance))
.slice(0, CONFIG.limit);
renderItems(items);
statusBox.textContent = `${items.length} pharmacie(s) chargée(s) automatiquement pour ${CONFIG.city}.`;
} catch (err) {
grid.innerHTML = `
💊 Pharmacies proches
Initialisation du chargement...
Chargement des pharmacies...
Information importante
Ce service fonctionne automatiquement sans intervention humaine et voici les horaires officiels
Aucune pharmacie trouvée dans cette zone.
`;
return;
}
grid.innerHTML = items.map((item, i) => {
const color = colors[i % colors.length];
const badge = getBadge(item);
return `
💊
${escapeHtml(badge.label)}
${escapeHtml(item.name)}
📍
${escapeHtml(item.city)}
🏠
${escapeHtml(item.full_address)}
📏
${escapeHtml(item.distance)} km
📞
${item.phone ? `${escapeHtml(item.phone)}` : "Téléphone non disponible"}
🕒
${item.opening_hours ? escapeHtml(item.opening_hours) : "Horaires non disponibles"}
🌐
${escapeHtml(err.message || "Erreur de chargement.")}
`;
statusBox.textContent = "Impossible de charger les données.";
}
}
init();
})();