+
SW
+
+
SOCIOWIRE.com
+
Wired to life
+
+ {authLabel}
+ {lastError && (
+
+ ({lastError})
+
+ )}
+
- ) : (
-
-
+
+
+
+
+ {["dark", "blue", "light"].map((t) => (
+
+ ))}
+
+
+ {authenticated ? (
+
+ {username}
+
+
+ ) : (
+
+ )}
+
+
+
+ {showAuth && (
+
+
e.stopPropagation()}
+ >
+
+
+
+
+
{mode === "login" ? (
-
) : (
-
)}
- )}
-
-
+
+ )}
+ >
);
}
diff --git a/src/components/Map/useUserPosition.js b/src/components/Map/useUserPosition.js
index 5cff856..892da1a 100644
--- a/src/components/Map/useUserPosition.js
+++ b/src/components/Map/useUserPosition.js
@@ -10,14 +10,16 @@ export function useUserPosition(mapRef, hasLastView) {
if (!map) return;
let cancelled = false;
+ let hasPos = false;
function saveUserPos(lat, lon) {
if (cancelled) return;
+ hasPos = true;
const coords = [lon, lat];
setUserPosition(coords);
try {
localStorage.setItem(LAST_POS_KEY, JSON.stringify({ lat, lon }));
- } catch {
+ } catch (e) {
// ignore
}
@@ -32,27 +34,27 @@ export function useUserPosition(mapRef, hasLastView) {
}
}
- // 1) dernière position user
+ // 1) dernière position user dans localStorage
try {
const raw = localStorage.getItem(LAST_POS_KEY);
if (raw) {
const p = JSON.parse(raw);
if (typeof p.lat === "number" && typeof p.lon === "number") {
+ hasPos = true;
setUserPosition([p.lon, p.lat]);
}
}
- } catch {
+ } catch (e) {
// ignore
}
- // 2) GPS → 3) IP backend
- function viaIpFallback() {
- (async () => {
- const ipCoords = await fetchIpLocation();
- if (!ipCoords || cancelled) return;
- const [lon, lat] = ipCoords;
- saveUserPos(lat, lon);
- })();
+ // 2) GPS → 3) IP backend (uniquement si on n'a VRAIMENT rien)
+ async function viaIpFallback() {
+ if (cancelled || hasPos) return;
+ const ipCoords = await fetchIpLocation();
+ if (!ipCoords || cancelled) return;
+ const [lon, lat] = ipCoords;
+ saveUserPos(lat, lon);
}
if ("geolocation" in navigator) {
@@ -62,7 +64,7 @@ export function useUserPosition(mapRef, hasLastView) {
saveUserPos(pos.coords.latitude, pos.coords.longitude);
},
() => {
- if (cancelled) return;
+ if (cancelled || hasPos) return;
viaIpFallback();
},
{
@@ -71,7 +73,8 @@ export function useUserPosition(mapRef, hasLastView) {
maximumAge: 30000,
}
);
- } else {
+ } else if (!hasPos) {
+ // pas de geolocation et aucune position connue → IP fallback
viaIpFallback();
}
diff --git a/src/main.jsx b/src/main.jsx
index d7caeed..afc3720 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -11,7 +11,8 @@ import "./styles/popup.css";
import "./styles/overlays.css";
import "./styles/posts.css";
import "./styles/theme.css";
-
+// dans main.jsx, avec les autres styles
+import "./styles/auth-modal.css";
import { AuthProvider } from "./auth/AuthContext.jsx";
ReactDOM.createRoot(document.getElementById("root")).render(
diff --git a/src/styles/auth-modal.css b/src/styles/auth-modal.css
new file mode 100644
index 0000000..8b5b478
--- /dev/null
+++ b/src/styles/auth-modal.css
@@ -0,0 +1,89 @@
+.auth-modal-backdrop {
+ position: fixed;
+ inset: 0;
+ background: rgba(15, 23, 42, 0.85);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 50;
+}
+
+.auth-modal {
+ width: 100%;
+ max-width: 360px;
+ background: #020617;
+ border-radius: 16px;
+ border: 1px solid rgba(148, 163, 184, 0.9);
+ box-shadow:
+ 0 18px 45px rgba(0, 0, 0, 0.9),
+ 0 0 24px rgba(56, 189, 248, 0.5);
+ padding: 0.9rem 1rem 1rem 1rem;
+ color: #e5e7eb;
+}
+
+.auth-modal-header {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin-bottom: 0.7rem;
+}
+
+.auth-tab {
+ border-radius: 999px;
+ border: 1px solid #4b5563;
+ background: #020617;
+ color: #e5e7eb;
+ font-size: 0.75rem;
+ padding: 0.25rem 0.7rem;
+ cursor: pointer;
+}
+
+.auth-tab-active {
+ background: #1e293b;
+ border-color: #60a5fa;
+}
+
+.auth-close {
+ margin-left: auto;
+ border: none;
+ background: transparent;
+ color: #9ca3af;
+ cursor: pointer;
+ font-size: 0.9rem;
+}
+
+.auth-form {
+ display: flex;
+ flex-direction: column;
+ gap: 0.45rem;
+}
+
+.auth-form label {
+ display: flex;
+ flex-direction: column;
+ font-size: 0.75rem;
+ gap: 0.15rem;
+}
+
+.auth-form input {
+ font-size: 0.8rem;
+ padding: 0.25rem 0.55rem;
+ border-radius: 999px;
+ border: 1px solid #4b5563;
+ background: #020617;
+ color: #e5e7eb;
+}
+
+.auth-row {
+ display: flex;
+ gap: 0.4rem;
+}
+
+.auth-row label {
+ flex: 1;
+}
+
+.auth-error {
+ font-size: 0.7rem;
+ color: #fecaca;
+}
diff --git a/src/styles/topbar.css b/src/styles/topbar.css
index 4b8848f..939e180 100644
--- a/src/styles/topbar.css
+++ b/src/styles/topbar.css
@@ -2,6 +2,7 @@
.topbar {
display: flex;
+ flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.6rem;
@@ -24,6 +25,7 @@
.title-block {
display: flex;
flex-direction: column;
+ min-width: 0;
}
.main-title {
@@ -36,14 +38,16 @@
opacity: 0.7;
}
-/* bloc de droite : thèmes + bouton login */
+/* bloc de droite : thèmes + boutons */
.topbar-right {
display: flex;
+ flex-wrap: wrap;
align-items: center;
+ justify-content: flex-end;
gap: 0.5rem;
+ margin-left: auto;
}
-/* petits boutons de thème (D / B / L) */
.theme-switch {
display: flex;
gap: 0.25rem;
@@ -69,7 +73,6 @@
box-shadow: 0 0 10px rgba(250, 204, 21, 0.7);
}
-/* bouton Login */
.btn-primary {
padding: 0.25rem 0.7rem;
font-size: 0.75rem;
@@ -79,3 +82,25 @@
color: #f9fafb;
cursor: pointer;
}
+
+.btn-secondary {
+ padding: 0.25rem 0.7rem;
+ font-size: 0.75rem;
+ border-radius: 999px;
+ border: 1px solid #60a5fa;
+ background: #1e293b;
+ color: #dbeafe;
+ cursor: pointer;
+}
+
+.btn-full {
+ width: 100%;
+}
+
+/* mobile */
+@media (max-width: 480px) {
+ .topbar-right {
+ width: 100%;
+ justify-content: flex-start;
+ }
+}