Improve map UX, theming, and privacy page
This commit is contained in:
parent
55ecfbd34e
commit
909715c2d7
|
|
@ -17,6 +17,7 @@
|
||||||
<meta property="og:image" content="https://sociowire.com/icons/og-image.png" />
|
<meta property="og:image" content="https://sociowire.com/icons/og-image.png" />
|
||||||
<meta property="og:url" content="https://sociowire.com" />
|
<meta property="og:url" content="https://sociowire.com" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
|
<meta name="facebook-domain-verification" content="o4iph92mh9fgqx58sn1b77ia08h8cp" />
|
||||||
|
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>SocioWire Privacy Policy</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Georgia", "Times New Roman", serif;
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
max-width: 820px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 48px 24px 72px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 34px;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 28px 0 8px;
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.meta {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #475569;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 20px 22px;
|
||||||
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<div class="card">
|
||||||
|
<h1>Privacy Policy</h1>
|
||||||
|
<div class="meta">Last updated: 2025-12-27</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
SocioWire respects your privacy. This policy explains what data we collect, how we use it,
|
||||||
|
and your choices.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>What we collect</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Account data you provide (username, email, profile image).</li>
|
||||||
|
<li>Content you create (posts, comments, media, location selections).</li>
|
||||||
|
<li>Usage data (views, likes, shares, and basic analytics).</li>
|
||||||
|
<li>Device and browser data for security and performance.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>How we use data</h2>
|
||||||
|
<ul>
|
||||||
|
<li>To operate the platform and deliver core features.</li>
|
||||||
|
<li>To personalize your feed and recommendations.</li>
|
||||||
|
<li>To improve safety, moderation, and service reliability.</li>
|
||||||
|
<li>To provide analytics for performance and growth.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Sharing</h2>
|
||||||
|
<p>
|
||||||
|
We do not sell personal data. We share data only with service providers required to run
|
||||||
|
SocioWire (hosting, analytics, storage) or when required by law.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Public vs private content</h2>
|
||||||
|
<p>
|
||||||
|
Content marked as public is visible to anyone. Private, group, or custom content is limited
|
||||||
|
to the audience you select.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Data retention</h2>
|
||||||
|
<p>
|
||||||
|
We keep data as long as necessary to provide the service. You can request deletion of your
|
||||||
|
account or content.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Your choices</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Update your profile or privacy settings at any time.</li>
|
||||||
|
<li>Control who can see your posts and media.</li>
|
||||||
|
<li>Request deletion by contacting us.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Contact</h2>
|
||||||
|
<p>
|
||||||
|
Email: <a href="mailto:support@sociowire.com">support@sociowire.com</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -565,11 +565,14 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick,
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-oauth btn-oauth-facebook"
|
className="btn-oauth btn-oauth-facebook"
|
||||||
disabled={true}
|
disabled={loading}
|
||||||
title="Facebook SSO coming soon"
|
onClick={() => {
|
||||||
|
trackEvent("login_provider_click", { provider: "facebook" });
|
||||||
|
loginWithProvider && loginWithProvider("facebook");
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-brands fa-facebook-f"></i>
|
<i className="fa-brands fa-facebook-f"></i>
|
||||||
<span>Facebook (soon)</span>
|
<span>Continue with Facebook</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ export default function MapView({
|
||||||
const [uploadingImage, setUploadingImage] = useState(false);
|
const [uploadingImage, setUploadingImage] = useState(false);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [saveError, setSaveError] = useState("");
|
const [saveError, setSaveError] = useState("");
|
||||||
|
const [createStep, setCreateStep] = useState(0);
|
||||||
|
|
||||||
const bottomCategories = FILTER_CATEGORY_MAP[mainFilter] || ["All"];
|
const bottomCategories = FILTER_CATEGORY_MAP[mainFilter] || ["All"];
|
||||||
|
|
||||||
|
|
@ -559,6 +560,7 @@ export default function MapView({
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsCreating(true);
|
setIsCreating(true);
|
||||||
|
setCreateStep(0);
|
||||||
setDraftTitle("");
|
setDraftTitle("");
|
||||||
setDraftBody("");
|
setDraftBody("");
|
||||||
setDraftImage("");
|
setDraftImage("");
|
||||||
|
|
@ -866,6 +868,31 @@ export default function MapView({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="create-stepper">
|
||||||
|
{["Pin", "Details", "Share"].map((label, idx) => (
|
||||||
|
<div
|
||||||
|
key={label}
|
||||||
|
className={
|
||||||
|
"create-step" +
|
||||||
|
(idx === createStep ? " create-step-current" : "") +
|
||||||
|
(idx <= createStep ? " create-step-active" : "")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="create-step-dot">{idx + 1}</div>
|
||||||
|
<div className="create-step-label">{label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="create-step-progress">
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
width: `${(createStep / 2) * 100}%`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{createStep === 0 && (
|
||||||
|
<div className="create-step-body">
|
||||||
<span className="crosshair-label">
|
<span className="crosshair-label">
|
||||||
Move the map, aim with the crosshair — your wire will be pinned
|
Move the map, aim with the crosshair — your wire will be pinned
|
||||||
there.
|
there.
|
||||||
|
|
@ -905,80 +932,48 @@ export default function MapView({
|
||||||
value={draftTitle}
|
value={draftTitle}
|
||||||
onChange={(e) => setDraftTitle(e.target.value)}
|
onChange={(e) => setDraftTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
<div className="create-hint">Give it a clear, punchy headline.</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{createStep === 1 && (
|
||||||
|
<div className="create-step-body">
|
||||||
<textarea
|
<textarea
|
||||||
className="create-textarea"
|
className="create-textarea"
|
||||||
rows={2}
|
rows={3}
|
||||||
placeholder="Context (optional)..."
|
placeholder="Context (optional)..."
|
||||||
value={draftBody}
|
value={draftBody}
|
||||||
onChange={(e) => setDraftBody(e.target.value)}
|
onChange={(e) => setDraftBody(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="create-privacy-row">
|
|
||||||
<label>Post visibility</label>
|
|
||||||
<select
|
|
||||||
value={postVisibility}
|
|
||||||
onChange={(e) => {
|
|
||||||
const next = e.target.value;
|
|
||||||
setPostVisibility(next);
|
|
||||||
if (next !== "group") setPostGroupId("");
|
|
||||||
if (next !== "custom") setPostUsers("");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option value="public">Public</option>
|
|
||||||
<option value="private">Private</option>
|
|
||||||
<option value="group">Group</option>
|
|
||||||
<option value="custom">Custom</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
{postVisibility === "group" ? (
|
|
||||||
<input
|
|
||||||
className="create-input"
|
|
||||||
placeholder="Group ID"
|
|
||||||
value={postGroupId}
|
|
||||||
onChange={(e) => setPostGroupId(e.target.value)}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{postVisibility === "custom" ? (
|
|
||||||
<input
|
|
||||||
className="create-input"
|
|
||||||
placeholder="Usernames (comma separated)"
|
|
||||||
value={postUsers}
|
|
||||||
onChange={(e) => setPostUsers(e.target.value)}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className="create-image-option">
|
<div className="create-image-option">
|
||||||
<label style={{ display: "flex", alignItems: "center", gap: "8px", cursor: "pointer" }}>
|
<label className="create-checkbox">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={useCustomImage}
|
checked={useCustomImage}
|
||||||
onChange={(e) => setUseCustomImage(e.target.checked)}
|
onChange={(e) => setUseCustomImage(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
<span>Use custom image instead of category icon</span>
|
<span>Use a custom image instead of the category icon</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{useCustomImage && (
|
{useCustomImage && (
|
||||||
<div className="create-image-panel">
|
<div className="create-image-panel">
|
||||||
<div style={{ display: "flex", gap: "8px" }}>
|
<div className="create-image-row">
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
onChange={handleImageFileChange}
|
onChange={handleImageFileChange}
|
||||||
disabled={uploadingImage}
|
disabled={uploadingImage}
|
||||||
style={{ flex: 1 }}
|
|
||||||
/>
|
/>
|
||||||
{uploadingImage && <span>Uploading...</span>}
|
{uploadingImage && (
|
||||||
|
<span className="create-uploading">Uploading...</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{draftImagePreview && (
|
{draftImagePreview && (
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
<div className="create-image-preview-row">
|
||||||
<img
|
<img src={draftImagePreview} alt="Preview" />
|
||||||
src={draftImagePreview}
|
|
||||||
alt="Preview"
|
|
||||||
style={{ width: "40px", height: "40px", objectFit: "cover", borderRadius: "6px" }}
|
|
||||||
/>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -986,14 +981,13 @@ export default function MapView({
|
||||||
setDraftImagePreview("");
|
setDraftImagePreview("");
|
||||||
setDraftImage("");
|
setDraftImage("");
|
||||||
}}
|
}}
|
||||||
style={{ padding: "4px 8px", fontSize: "11px" }}
|
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div style={{ fontSize: "12px", color: "#888" }}>
|
<div className="create-muted">
|
||||||
Or paste an image URL:
|
Or paste an image URL:
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
|
|
@ -1043,10 +1037,95 @@ export default function MapView({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{createStep === 2 && (
|
||||||
|
<div className="create-step-body">
|
||||||
|
<div className="create-privacy-row">
|
||||||
|
<label>Post visibility</label>
|
||||||
|
<select
|
||||||
|
value={postVisibility}
|
||||||
|
onChange={(e) => {
|
||||||
|
const next = e.target.value;
|
||||||
|
setPostVisibility(next);
|
||||||
|
if (next !== "group") setPostGroupId("");
|
||||||
|
if (next !== "custom") setPostUsers("");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="public">Public</option>
|
||||||
|
<option value="private">Private</option>
|
||||||
|
<option value="group">Group</option>
|
||||||
|
<option value="custom">Custom</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{postVisibility === "group" ? (
|
||||||
|
<input
|
||||||
|
className="create-input"
|
||||||
|
placeholder="Group ID"
|
||||||
|
value={postGroupId}
|
||||||
|
onChange={(e) => setPostGroupId(e.target.value)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{postVisibility === "custom" ? (
|
||||||
|
<input
|
||||||
|
className="create-input"
|
||||||
|
placeholder="Usernames (comma separated)"
|
||||||
|
value={postUsers}
|
||||||
|
onChange={(e) => setPostUsers(e.target.value)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className="create-review-card">
|
||||||
|
<div className="create-review-media">
|
||||||
|
{useCustomImage && (draftImagePreview || draftImage) ? (
|
||||||
|
<img src={draftImagePreview || draftImage} alt="Preview" />
|
||||||
|
) : (
|
||||||
|
<div className="create-review-icon">
|
||||||
|
<i className={getSubcatIcon(draftCategory, draftSubCategory)} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="create-review-meta">
|
||||||
|
<div className="create-review-title">
|
||||||
|
{draftTitle || "Untitled wire"}
|
||||||
|
</div>
|
||||||
|
<div className="create-review-sub">
|
||||||
|
{draftCategory} · {draftSubCategory}
|
||||||
|
</div>
|
||||||
|
<div className="create-review-body">
|
||||||
|
{draftBody || "Add a quick line of context if you want."}
|
||||||
|
</div>
|
||||||
|
<div className="create-review-visibility">
|
||||||
|
Visibility: {postVisibility}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{saveError && <div className="create-error">{saveError}</div>}
|
{saveError && <div className="create-error">{saveError}</div>}
|
||||||
|
|
||||||
<div className="create-actions">
|
<div className="create-actions">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="create-back"
|
||||||
|
onClick={() => setCreateStep((s) => Math.max(0, s - 1))}
|
||||||
|
disabled={createStep === 0}
|
||||||
|
>
|
||||||
|
Back
|
||||||
|
</button>
|
||||||
|
<div className="create-actions-right">
|
||||||
|
{createStep < 2 ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="chip-pill"
|
||||||
|
onClick={() => setCreateStep((s) => Math.min(2, s + 1))}
|
||||||
|
disabled={!draftTitle.trim() || uploadingImage}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
<button
|
<button
|
||||||
className="chip-pill"
|
className="chip-pill"
|
||||||
onClick={handleSubmitPost}
|
onClick={handleSubmitPost}
|
||||||
|
|
@ -1054,6 +1133,8 @@ export default function MapView({
|
||||||
>
|
>
|
||||||
{isSaving ? "Posting..." : "Post"}
|
{isSaving ? "Posting..." : "Post"}
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ const SW_ANIM_MS = 840;
|
||||||
|
|
||||||
import CardRenderer from "../Cards/CardRenderer";
|
import CardRenderer from "../Cards/CardRenderer";
|
||||||
import { cardTokens } from "../../theme/cardTokens";
|
import { cardTokens } from "../../theme/cardTokens";
|
||||||
import { getTemplateSpecForPost, adaptPostToTemplateData } from "./templateSpecs";
|
import { getTemplateSpecForPost, getTemplateKeyForPost, adaptPostToTemplateData } from "./templateSpecs";
|
||||||
import { getMarkerColorForCategory } from "./postPriority";
|
import { getMarkerColorForCategory } from "./postPriority";
|
||||||
import { loadAuth } from "../../auth/authStorage";
|
import { loadAuth } from "../../auth/authStorage";
|
||||||
import {
|
import {
|
||||||
|
|
@ -40,6 +40,44 @@ function applyAvatar(el, username, url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolvePostImage(post) {
|
||||||
|
return normalizeImageUrl(
|
||||||
|
post?.image_small ||
|
||||||
|
post?.image ||
|
||||||
|
post?.image_large ||
|
||||||
|
post?.media_url ||
|
||||||
|
post?.image_url ||
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshMarkerFromPost(map, postId, fresh) {
|
||||||
|
if (!map || !fresh) return;
|
||||||
|
const ref = map.__swMarkersRef;
|
||||||
|
const list = ref?.current || [];
|
||||||
|
for (const item of list) {
|
||||||
|
if (!item || item.id !== postId) continue;
|
||||||
|
const nextPost = { ...(item.post || {}), ...(fresh || {}) };
|
||||||
|
item.post = nextPost;
|
||||||
|
if (!item.el) continue;
|
||||||
|
item.el.__post = nextPost;
|
||||||
|
const nextKey = getTemplateKeyForPost(nextPost);
|
||||||
|
const nextImg = resolvePostImage(nextPost);
|
||||||
|
const nextTitle = (nextPost?.title || "").toString();
|
||||||
|
if (
|
||||||
|
item.el.__lastTemplateKey !== nextKey ||
|
||||||
|
item.el.__lastImage !== nextImg ||
|
||||||
|
item.el.__lastTitle !== nextTitle
|
||||||
|
) {
|
||||||
|
if (item.type === "simple" && item.el.__renderSimple) {
|
||||||
|
try { item.el.__renderSimple(); } catch {}
|
||||||
|
} else if (item.el.__renderCompact) {
|
||||||
|
try { item.el.__renderCompact(); } catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadAvatar(username) {
|
async function loadAvatar(username) {
|
||||||
const key = (username || "").toLowerCase().trim();
|
const key = (username || "").toLowerCase().trim();
|
||||||
if (!key) return "";
|
if (!key) return "";
|
||||||
|
|
@ -514,6 +552,7 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
||||||
let postData = { ...(post || {}) };
|
let postData = { ...(post || {}) };
|
||||||
const data = adaptPostToTemplateData(postData);
|
const data = adaptPostToTemplateData(postData);
|
||||||
const cat = normCatLabel(postData);
|
const cat = normCatLabel(postData);
|
||||||
|
const templateKey = getTemplateKeyForPost(postData);
|
||||||
const relTime = formatRelativeTime(getPostTime(postData));
|
const relTime = formatRelativeTime(getPostTime(postData));
|
||||||
const author = (postData?.author || postData?.Author || "").toString().trim();
|
const author = (postData?.author || postData?.Author || "").toString().trim();
|
||||||
const sub = (postData?.sub_category || postData?.subCategory || "").toString().trim();
|
const sub = (postData?.sub_category || postData?.subCategory || "").toString().trim();
|
||||||
|
|
@ -561,7 +600,7 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
||||||
|
|
||||||
// Keep size behavior from your CSS (max-width/min(92vw,...), max-height etc.)
|
// Keep size behavior from your CSS (max-width/min(92vw,...), max-height etc.)
|
||||||
modalWrap.innerHTML = `
|
modalWrap.innerHTML = `
|
||||||
<div class="post-card sw-expanded-shell sw-modal">
|
<div class="post-card sw-expanded-shell sw-modal" data-template="${escapeHtml(templateKey)}" data-category="${escapeHtml((postData?.category || "").toString().toUpperCase())}">
|
||||||
<div class="sw-modal-toprow">
|
<div class="sw-modal-toprow">
|
||||||
<div class="sw-modal-left">
|
<div class="sw-modal-left">
|
||||||
<div class="sw-modal-badge">${escapeHtml(cat)}</div>
|
<div class="sw-modal-badge">${escapeHtml(cat)}</div>
|
||||||
|
|
@ -830,6 +869,7 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
||||||
if (!fresh) return;
|
if (!fresh) return;
|
||||||
postData = { ...postData, ...fresh };
|
postData = { ...postData, ...fresh };
|
||||||
applyPostDetails(modalWrap, postData);
|
applyPostDetails(modalWrap, postData);
|
||||||
|
refreshMarkerFromPost(map, postID, postData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1027,6 +1067,7 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the
|
||||||
requestAnimationFrame(() => root.classList.add("sw-appear-in"));
|
requestAnimationFrame(() => root.classList.add("sw-appear-in"));
|
||||||
root.className = "post-pin post-pin--compact";
|
root.className = "post-pin post-pin--compact";
|
||||||
root.style.zIndex = "1";
|
root.style.zIndex = "1";
|
||||||
|
root.__post = post;
|
||||||
|
|
||||||
function unmountIfAny() {
|
function unmountIfAny() {
|
||||||
if (root.__swUnmount) {
|
if (root.__swUnmount) {
|
||||||
|
|
@ -1053,9 +1094,13 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the
|
||||||
|
|
||||||
const wrap = root.querySelector(".sw-template-mini-wrap");
|
const wrap = root.querySelector(".sw-template-mini-wrap");
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
const spec = getTemplateSpecForPost(post, "mini");
|
const activePost = root.__post || post;
|
||||||
const data = adaptPostToTemplateData(post);
|
const spec = getTemplateSpecForPost(activePost, "mini");
|
||||||
root.__swUnmount = mountCard(wrap, spec, data, theme, post);
|
const data = adaptPostToTemplateData(activePost);
|
||||||
|
root.__lastTemplateKey = getTemplateKeyForPost(activePost);
|
||||||
|
root.__lastImage = data?.image || "";
|
||||||
|
root.__lastTitle = data?.headline || "";
|
||||||
|
root.__swUnmount = mountCard(wrap, spec, data, theme, activePost);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOcclusion(markersRef);
|
clearOcclusion(markersRef);
|
||||||
|
|
@ -1116,11 +1161,6 @@ export function createSimpleMarkerForPost(post, mapRef, markersRef, expandedElRe
|
||||||
const lngLat = [lon, lat];
|
const lngLat = [lon, lat];
|
||||||
|
|
||||||
// Pas d'offset pour les marqueurs simples (ils sont petits)
|
// Pas d'offset pour les marqueurs simples (ils sont petits)
|
||||||
const color = getMarkerColorForCategory(post?.category);
|
|
||||||
const img = normalizeImageUrl(
|
|
||||||
post?.image_small || post?.image || post?.image_large || post?.media_url || "",
|
|
||||||
);
|
|
||||||
|
|
||||||
const root = document.createElement("div");
|
const root = document.createElement("div");
|
||||||
root.classList.add("sw-appear");
|
root.classList.add("sw-appear");
|
||||||
requestAnimationFrame(() => root.classList.add("sw-appear-in"));
|
requestAnimationFrame(() => root.classList.add("sw-appear-in"));
|
||||||
|
|
@ -1131,6 +1171,17 @@ export function createSimpleMarkerForPost(post, mapRef, markersRef, expandedElRe
|
||||||
root.style.display = "flex";
|
root.style.display = "flex";
|
||||||
root.style.flexDirection = "column";
|
root.style.flexDirection = "column";
|
||||||
root.style.alignItems = "center";
|
root.style.alignItems = "center";
|
||||||
|
root.__post = post;
|
||||||
|
|
||||||
|
function renderSimple() {
|
||||||
|
const activePost = root.__post || post;
|
||||||
|
const color = getMarkerColorForCategory(activePost?.category);
|
||||||
|
const img = normalizeImageUrl(
|
||||||
|
activePost?.image_small || activePost?.image || activePost?.image_large || activePost?.media_url || "",
|
||||||
|
);
|
||||||
|
root.__lastTemplateKey = getTemplateKeyForPost(activePost);
|
||||||
|
root.__lastImage = img || "";
|
||||||
|
root.__lastTitle = (activePost?.title || "").toString();
|
||||||
|
|
||||||
// Marqueur pin avec image en haut et pointe en bas
|
// Marqueur pin avec image en haut et pointe en bas
|
||||||
root.innerHTML = `
|
root.innerHTML = `
|
||||||
|
|
@ -1188,16 +1239,20 @@ export function createSimpleMarkerForPost(post, mapRef, markersRef, expandedElRe
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
">
|
">
|
||||||
<div style="font-weight: 900; font-size: 12px; color: #e8f5ff; margin-bottom: 4px;">
|
<div style="font-weight: 900; font-size: 12px; color: #e8f5ff; margin-bottom: 4px;">
|
||||||
${escapeHtml(post?.title || "Untitled")}
|
${escapeHtml(activePost?.title || "Untitled")}
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 10px; color: rgba(232, 245, 255, 0.8);">
|
<div style="font-size: 10px; color: rgba(232, 245, 255, 0.8);">
|
||||||
${escapeHtml((post?.snippet || "").substring(0, 80))}${(post?.snippet || "").length > 80 ? "..." : ""}
|
${escapeHtml((activePost?.snippet || "").substring(0, 80))}${(activePost?.snippet || "").length > 80 ? "..." : ""}
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 6px; font-size: 9px; color: rgba(232, 245, 255, 0.6);">
|
<div style="margin-top: 6px; font-size: 9px; color: rgba(232, 245, 255, 0.6);">
|
||||||
${normCatLabel(post)} • ${formatRelativeTime(post?.created_at || post?.CreatedAt)}
|
${normCatLabel(activePost)} • ${formatRelativeTime(activePost?.created_at || activePost?.CreatedAt)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSimple();
|
||||||
|
root.__renderSimple = renderSimple;
|
||||||
|
|
||||||
const markerEl = root.querySelector(".sw-simple-marker");
|
const markerEl = root.querySelector(".sw-simple-marker");
|
||||||
const hoverCard = root.querySelector(".sw-simple-hover-card");
|
const hoverCard = root.querySelector(".sw-simple-hover-card");
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { fetchPosts, fetchSmartFeed, fetchUnifiedSearch } from "../../api/client
|
||||||
import { categoryCode, matchesSubFilter, matchesTimeFilter } from "./mapFilter";
|
import { categoryCode, matchesSubFilter, matchesTimeFilter } from "./mapFilter";
|
||||||
import { getCoords, getViewFromMap, haversineKm } from "./mapGeo";
|
import { getCoords, getViewFromMap, haversineKm } from "./mapGeo";
|
||||||
import { createMarkerForPost, createSimpleMarkerForPost } from "./markerManager";
|
import { createMarkerForPost, createSimpleMarkerForPost } from "./markerManager";
|
||||||
|
import { getTemplateKeyForPost } from "./templateSpecs";
|
||||||
import { prioritizePosts } from "./postPriority";
|
import { prioritizePosts } from "./postPriority";
|
||||||
import { trackEvent } from "../../utils/analytics";
|
import { trackEvent } from "../../utils/analytics";
|
||||||
|
|
||||||
|
|
@ -38,6 +39,21 @@ function asText(v) {
|
||||||
return String(v);
|
return String(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTemplateKey(post) {
|
||||||
|
return getTemplateKeyForPost(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePostImage(post) {
|
||||||
|
return (
|
||||||
|
post?.image_small ||
|
||||||
|
post?.image ||
|
||||||
|
post?.image_large ||
|
||||||
|
post?.media_url ||
|
||||||
|
post?.image_url ||
|
||||||
|
""
|
||||||
|
).toString();
|
||||||
|
}
|
||||||
|
|
||||||
function postHaystack(p) {
|
function postHaystack(p) {
|
||||||
const title = asText(p?.title || p?.text || p?.body || "");
|
const title = asText(p?.title || p?.text || p?.body || "");
|
||||||
const snippet = asText(p?.snippet || p?.summary || p?.content || "");
|
const snippet = asText(p?.snippet || p?.summary || p?.content || "");
|
||||||
|
|
@ -439,6 +455,7 @@ export function usePostsEngine({
|
||||||
(visible) => {
|
(visible) => {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
if (!map) return;
|
if (!map) return;
|
||||||
|
map.__swMarkersRef = markersRef;
|
||||||
|
|
||||||
// If user is reading an expanded overlay, don't touch markers
|
// If user is reading an expanded overlay, don't touch markers
|
||||||
if (expandedElRef?.current) return;
|
if (expandedElRef?.current) return;
|
||||||
|
|
@ -491,6 +508,27 @@ export function usePostsEngine({
|
||||||
try { item?.marker?.remove?.(); } catch {}
|
try { item?.marker?.remove?.(); } catch {}
|
||||||
}, 840);
|
}, 840);
|
||||||
} else {
|
} else {
|
||||||
|
const entry = wanted.get(id);
|
||||||
|
if (entry?.post) {
|
||||||
|
item.post = entry.post;
|
||||||
|
if (item.el) {
|
||||||
|
item.el.__post = entry.post;
|
||||||
|
const nextKey = getTemplateKey(entry.post);
|
||||||
|
const nextImg = resolvePostImage(entry.post);
|
||||||
|
const nextTitle = (entry.post?.title || "").toString();
|
||||||
|
if (
|
||||||
|
item.el.__lastTemplateKey !== nextKey ||
|
||||||
|
item.el.__lastImage !== nextImg ||
|
||||||
|
item.el.__lastTitle !== nextTitle
|
||||||
|
) {
|
||||||
|
if (item.type === "simple" && item.el.__renderSimple) {
|
||||||
|
try { item.el.__renderSimple(); } catch {}
|
||||||
|
} else if (item.el.__renderCompact) {
|
||||||
|
try { item.el.__renderCompact(); } catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
next.push(item);
|
next.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -695,7 +733,13 @@ export function usePostsEngine({
|
||||||
if (Array.isArray(newPosts)) {
|
if (Array.isArray(newPosts)) {
|
||||||
for (const p of newPosts) {
|
for (const p of newPosts) {
|
||||||
const key = getPostKey(p);
|
const key = getPostKey(p);
|
||||||
if (key && !byId.has(key)) byId.set(key, p);
|
if (!key) continue;
|
||||||
|
const prior = byId.get(key);
|
||||||
|
if (prior) {
|
||||||
|
byId.set(key, { ...prior, ...p });
|
||||||
|
} else {
|
||||||
|
byId.set(key, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -853,6 +897,12 @@ export function usePostsEngine({
|
||||||
|
|
||||||
const counts = payload?.counts || null;
|
const counts = payload?.counts || null;
|
||||||
const truth = payload?.truth || null;
|
const truth = payload?.truth || null;
|
||||||
|
const postPatch =
|
||||||
|
payload?.post ||
|
||||||
|
payload?.post_data ||
|
||||||
|
payload?.postData ||
|
||||||
|
payload?.data ||
|
||||||
|
null;
|
||||||
const truthScore = Number(
|
const truthScore = Number(
|
||||||
truth?.truth_score ??
|
truth?.truth_score ??
|
||||||
truth?.TruthScore ??
|
truth?.TruthScore ??
|
||||||
|
|
@ -867,7 +917,7 @@ export function usePostsEngine({
|
||||||
updated.push(p);
|
updated.push(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const next = { ...p };
|
const next = { ...p, ...(postPatch || {}) };
|
||||||
if (counts) {
|
if (counts) {
|
||||||
if (Number.isFinite(counts.view_count)) next.view_count = counts.view_count;
|
if (Number.isFinite(counts.view_count)) next.view_count = counts.view_count;
|
||||||
if (Number.isFinite(counts.like_count)) next.like_count = counts.like_count;
|
if (Number.isFinite(counts.like_count)) next.like_count = counts.like_count;
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,14 @@
|
||||||
border: 1px solid rgba(56, 189, 248, 0.2);
|
border: 1px solid rgba(56, 189, 248, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .island-viewer-modal{
|
||||||
|
background: linear-gradient(135deg, rgba(3, 12, 40, 0.95) 0%, rgba(2, 8, 28, 0.98) 100%);
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .island-viewer-container{
|
||||||
|
background: linear-gradient(135deg, #0b1b3b 0%, #0f224d 60%, #163264 100%);
|
||||||
|
border-color: rgba(96, 165, 250, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes slideUp {
|
@keyframes slideUp {
|
||||||
from {
|
from {
|
||||||
transform: translateY(20px);
|
transform: translateY(20px);
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@
|
||||||
bottom:8%;
|
bottom:8%;
|
||||||
transform:translateX(-50%);
|
transform:translateX(-50%);
|
||||||
width:92%;
|
width:92%;
|
||||||
max-width:520px;
|
max-width:560px;
|
||||||
max-height:45vh;
|
max-height:62vh;
|
||||||
overflow-y:auto;
|
overflow-y:auto;
|
||||||
background: rgba(15, 23, 42, 0.96);
|
background: rgba(15, 23, 42, 0.96);
|
||||||
border-radius:16px;
|
border-radius:16px;
|
||||||
|
|
@ -170,6 +170,60 @@
|
||||||
padding:.1rem .3rem;
|
padding:.1rem .3rem;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
|
.create-stepper{
|
||||||
|
display:flex;
|
||||||
|
justify-content:space-between;
|
||||||
|
align-items:center;
|
||||||
|
gap:.4rem;
|
||||||
|
margin:.3rem 0 .35rem;
|
||||||
|
}
|
||||||
|
.create-step{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
gap:.35rem;
|
||||||
|
color:#64748b;
|
||||||
|
font-size:.68rem;
|
||||||
|
text-transform:uppercase;
|
||||||
|
letter-spacing:.08em;
|
||||||
|
}
|
||||||
|
.create-step-active{
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
.create-step-dot{
|
||||||
|
width:18px;
|
||||||
|
height:18px;
|
||||||
|
border-radius:50%;
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;
|
||||||
|
font-size:.65rem;
|
||||||
|
background:#0f172a;
|
||||||
|
border:1px solid #334155;
|
||||||
|
color:#cbd5f5;
|
||||||
|
}
|
||||||
|
.create-step-current .create-step-dot{
|
||||||
|
background:linear-gradient(120deg, #38bdf8, #22c55e);
|
||||||
|
border-color:transparent;
|
||||||
|
color:#0f172a;
|
||||||
|
font-weight:700;
|
||||||
|
}
|
||||||
|
.create-step-label{
|
||||||
|
font-weight:600;
|
||||||
|
}
|
||||||
|
.create-step-progress{
|
||||||
|
height:4px;
|
||||||
|
background:rgba(148, 163, 184, 0.15);
|
||||||
|
border-radius:999px;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
.create-step-progress span{
|
||||||
|
display:block;
|
||||||
|
height:100%;
|
||||||
|
background:linear-gradient(90deg, #38bdf8, #22c55e);
|
||||||
|
}
|
||||||
|
.create-step-body{
|
||||||
|
margin-top:.5rem;
|
||||||
|
}
|
||||||
.create-row{
|
.create-row{
|
||||||
display:flex;
|
display:flex;
|
||||||
align-items:center;
|
align-items:center;
|
||||||
|
|
@ -180,6 +234,11 @@
|
||||||
font-size:.75rem;
|
font-size:.75rem;
|
||||||
color:#cbd5f5;
|
color:#cbd5f5;
|
||||||
}
|
}
|
||||||
|
.create-hint{
|
||||||
|
margin-top:.2rem;
|
||||||
|
font-size:.7rem;
|
||||||
|
color:#94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
.create-row select{
|
.create-row select{
|
||||||
flex:1;
|
flex:1;
|
||||||
|
|
@ -210,12 +269,60 @@
|
||||||
resize:none;
|
resize:none;
|
||||||
font-size:.78rem;
|
font-size:.78rem;
|
||||||
}
|
}
|
||||||
|
.create-image-option{
|
||||||
|
margin-top:.4rem;
|
||||||
|
}
|
||||||
|
.create-checkbox{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
gap:.5rem;
|
||||||
|
font-size:.72rem;
|
||||||
|
color:#e5e7eb;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
.create-image-panel{
|
.create-image-panel{
|
||||||
display:flex;
|
display:flex;
|
||||||
flex-direction:column;
|
flex-direction:column;
|
||||||
gap:.4rem;
|
gap:.4rem;
|
||||||
margin-top:.35rem;
|
margin-top:.35rem;
|
||||||
}
|
}
|
||||||
|
.create-image-row{
|
||||||
|
display:flex;
|
||||||
|
gap:.5rem;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
.create-image-row input[type="file"]{
|
||||||
|
flex:1;
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
.create-uploading{
|
||||||
|
font-size:.7rem;
|
||||||
|
color:#38bdf8;
|
||||||
|
}
|
||||||
|
.create-image-preview-row{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
gap:.5rem;
|
||||||
|
}
|
||||||
|
.create-image-preview-row img{
|
||||||
|
width:44px;
|
||||||
|
height:44px;
|
||||||
|
border-radius:8px;
|
||||||
|
object-fit:cover;
|
||||||
|
border:1px solid rgba(148, 163, 184, 0.5);
|
||||||
|
}
|
||||||
|
.create-image-preview-row button{
|
||||||
|
background:transparent;
|
||||||
|
border:1px solid rgba(148, 163, 184, 0.4);
|
||||||
|
color:#e2e8f0;
|
||||||
|
padding:.2rem .45rem;
|
||||||
|
border-radius:999px;
|
||||||
|
font-size:.68rem;
|
||||||
|
}
|
||||||
|
.create-muted{
|
||||||
|
font-size:.7rem;
|
||||||
|
color:#94a3b8;
|
||||||
|
}
|
||||||
.create-privacy-row{
|
.create-privacy-row{
|
||||||
display:flex;
|
display:flex;
|
||||||
align-items:center;
|
align-items:center;
|
||||||
|
|
@ -242,9 +349,169 @@
|
||||||
color:#f97373;
|
color:#f97373;
|
||||||
}
|
}
|
||||||
.create-actions{
|
.create-actions{
|
||||||
margin-top:.4rem;
|
margin-top:.6rem;
|
||||||
display:flex;
|
display:flex;
|
||||||
justify-content:flex-end;
|
justify-content:space-between;
|
||||||
|
align-items:center;
|
||||||
|
gap:.5rem;
|
||||||
|
}
|
||||||
|
.create-actions-right{
|
||||||
|
display:flex;
|
||||||
|
gap:.45rem;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
.create-back{
|
||||||
|
background:transparent;
|
||||||
|
border:1px solid rgba(148, 163, 184, 0.4);
|
||||||
|
color:#cbd5f5;
|
||||||
|
padding:.35rem .8rem;
|
||||||
|
border-radius:999px;
|
||||||
|
font-size:.72rem;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
.create-back:disabled{
|
||||||
|
opacity:.45;
|
||||||
|
cursor:not-allowed;
|
||||||
|
}
|
||||||
|
.create-review-card{
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns:72px 1fr;
|
||||||
|
gap:.7rem;
|
||||||
|
padding:.6rem;
|
||||||
|
margin-top:.5rem;
|
||||||
|
border-radius:12px;
|
||||||
|
border:1px solid rgba(148, 163, 184, 0.35);
|
||||||
|
background:rgba(2, 6, 23, 0.7);
|
||||||
|
}
|
||||||
|
.create-review-media{
|
||||||
|
width:72px;
|
||||||
|
height:72px;
|
||||||
|
border-radius:12px;
|
||||||
|
overflow:hidden;
|
||||||
|
background:rgba(30, 41, 59, 0.85);
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;
|
||||||
|
}
|
||||||
|
.create-review-media img{
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
object-fit:cover;
|
||||||
|
}
|
||||||
|
.create-review-icon{
|
||||||
|
width:46px;
|
||||||
|
height:46px;
|
||||||
|
border-radius:14px;
|
||||||
|
background:rgba(56, 189, 248, 0.2);
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;
|
||||||
|
color:#38bdf8;
|
||||||
|
font-size:1.1rem;
|
||||||
|
}
|
||||||
|
.create-review-meta{
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
gap:.2rem;
|
||||||
|
}
|
||||||
|
.create-review-title{
|
||||||
|
font-size:.85rem;
|
||||||
|
color:#e2e8f0;
|
||||||
|
font-weight:600;
|
||||||
|
}
|
||||||
|
.create-review-sub{
|
||||||
|
font-size:.7rem;
|
||||||
|
color:#94a3b8;
|
||||||
|
}
|
||||||
|
.create-review-body{
|
||||||
|
font-size:.74rem;
|
||||||
|
color:#cbd5f5;
|
||||||
|
max-height:3.8em;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
.create-review-visibility{
|
||||||
|
font-size:.68rem;
|
||||||
|
color:#38bdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .create-post-panel{
|
||||||
|
background: rgba(12, 20, 60, 0.96);
|
||||||
|
border-color: rgba(96, 165, 250, 0.95);
|
||||||
|
box-shadow: 0 16px 40px rgba(2,8,26,.85), 0 0 24px rgba(56,189,248,.5);
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-row select,
|
||||||
|
body[data-theme="blue"] .create-input,
|
||||||
|
body[data-theme="blue"] .create-textarea,
|
||||||
|
body[data-theme="blue"] .create-privacy-row select{
|
||||||
|
background: #0b1b3b;
|
||||||
|
border-color: rgba(96, 165, 250, 0.5);
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-step{
|
||||||
|
color:#94a3b8;
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-step-active{
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-step-dot{
|
||||||
|
background:#0b1b3b;
|
||||||
|
border-color: rgba(96, 165, 250, 0.6);
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-back{
|
||||||
|
border-color: rgba(96, 165, 250, 0.55);
|
||||||
|
color:#e2e8f0;
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .create-review-card{
|
||||||
|
background: rgba(3, 10, 28, 0.7);
|
||||||
|
border-color: rgba(96, 165, 250, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"] .create-post-panel{
|
||||||
|
background: rgba(248, 250, 252, 0.98);
|
||||||
|
border-color: rgba(148, 163, 184, 0.9);
|
||||||
|
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.15);
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-row select,
|
||||||
|
body[data-theme="light"] .create-input,
|
||||||
|
body[data-theme="light"] .create-textarea,
|
||||||
|
body[data-theme="light"] .create-privacy-row select{
|
||||||
|
background:#ffffff;
|
||||||
|
border-color: rgba(148, 163, 184, 0.7);
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-step{
|
||||||
|
color:#64748b;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-step-active{
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-step-dot{
|
||||||
|
background:#ffffff;
|
||||||
|
border-color: rgba(148, 163, 184, 0.7);
|
||||||
|
color:#334155;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-step-current .create-step-dot{
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-hint,
|
||||||
|
body[data-theme="light"] .create-muted{
|
||||||
|
color:#64748b;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-back{
|
||||||
|
border-color: rgba(148, 163, 184, 0.7);
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-review-card{
|
||||||
|
background: rgba(241, 245, 249, 0.95);
|
||||||
|
border-color: rgba(148, 163, 184, 0.6);
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-review-title{
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .create-review-body{
|
||||||
|
color:#334155;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip-pill{
|
.chip-pill{
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
.sw-centered-modal .post-card.sw-expanded-shell {
|
.sw-centered-modal .post-card.sw-expanded-shell {
|
||||||
background: rgba(15, 23, 42, 0.98) !important; /* transparence intacte */
|
background: rgba(15, 23, 42, 0.98) !important; /* transparence intacte */
|
||||||
border: 3px solid #000 !important; /* contour plus épais */
|
border: 3px solid #000 !important; /* contour plus épais */
|
||||||
box-shadow: 0 12px 30px rgba(0,0,0,0.7), 0 0 16px rgba(56,189,248,0.5) !important;
|
box-shadow: 0 12px 30px rgba(0,0,0,0.7), 0 0 16px var(--sw-modal-accent-glow, rgba(56,189,248,0.5)) !important;
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
color: #e5e7eb !important; /* texte blanc clair */
|
color: #e5e7eb !important; /* texte blanc clair */
|
||||||
width: min(94vw, 460px) !important;
|
width: min(94vw, 460px) !important;
|
||||||
|
|
@ -70,36 +70,59 @@
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
--sw-modal-accent: #38bdf8;
|
||||||
|
--sw-modal-accent-soft: rgba(56,189,248,0.28);
|
||||||
|
--sw-modal-accent-glow: rgba(56,189,248,0.5);
|
||||||
|
--sw-modal-accent-text: #D7F3FF;
|
||||||
|
--sw-modal-text: #e5e7eb;
|
||||||
|
--sw-modal-meta: #9eb7ff;
|
||||||
|
--sw-modal-pill-text: #c7e3ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Couleur badge par catégorie dans grosse carte */
|
/* Couleur principale par catégorie/template pour grosse carte */
|
||||||
.sw-centered-modal [data-category="NEWS"] .sw-modal-badge {
|
.sw-centered-modal [data-template="news"]{
|
||||||
background: rgba(56,189,248,0.35) !important;
|
--sw-modal-accent: #38bdf8;
|
||||||
border-color: #38bdf8 !important;
|
--sw-modal-accent-soft: rgba(56,189,248,0.28);
|
||||||
color: #D7F3FF !important;
|
--sw-modal-accent-glow: rgba(56,189,248,0.5);
|
||||||
|
--sw-modal-accent-text: #D7F3FF;
|
||||||
}
|
}
|
||||||
.sw-centered-modal [data-category="EVENT"] .sw-modal-badge {
|
.sw-centered-modal [data-template="breaking"]{
|
||||||
background: rgba(168,85,247,0.35) !important;
|
--sw-modal-accent: #f43f5e;
|
||||||
border-color: #a855f7 !important;
|
--sw-modal-accent-soft: rgba(244,63,94,0.26);
|
||||||
color: #F3E8FF !important;
|
--sw-modal-accent-glow: rgba(244,63,94,0.5);
|
||||||
|
--sw-modal-accent-text: #FFE4E6;
|
||||||
}
|
}
|
||||||
.sw-centered-modal [data-category="FRIENDS"] .sw-modal-badge {
|
.sw-centered-modal [data-template="finance"]{
|
||||||
background: rgba(34,197,94,0.35) !important;
|
--sw-modal-accent: #14b8a6;
|
||||||
border-color: #22c55e !important;
|
--sw-modal-accent-soft: rgba(20,184,166,0.26);
|
||||||
color: #D1FAE5 !important;
|
--sw-modal-accent-glow: rgba(20,184,166,0.5);
|
||||||
|
--sw-modal-accent-text: #CCFBF1;
|
||||||
}
|
}
|
||||||
.sw-centered-modal [data-category="MARKET"] .sw-modal-badge {
|
.sw-centered-modal [data-template="market"]{
|
||||||
background: rgba(250,204,21,0.35) !important;
|
--sw-modal-accent: #facc15;
|
||||||
border-color: #facc15 !important;
|
--sw-modal-accent-soft: rgba(250,204,21,0.26);
|
||||||
color: #FEFCE8 !important;
|
--sw-modal-accent-glow: rgba(250,204,21,0.5);
|
||||||
|
--sw-modal-accent-text: #FEF9C3;
|
||||||
|
}
|
||||||
|
.sw-centered-modal [data-template="friends"]{
|
||||||
|
--sw-modal-accent: #22c55e;
|
||||||
|
--sw-modal-accent-soft: rgba(34,197,94,0.26);
|
||||||
|
--sw-modal-accent-glow: rgba(34,197,94,0.5);
|
||||||
|
--sw-modal-accent-text: #D1FAE5;
|
||||||
|
}
|
||||||
|
.sw-centered-modal [data-template="events"]{
|
||||||
|
--sw-modal-accent: #a855f7;
|
||||||
|
--sw-modal-accent-soft: rgba(168,85,247,0.26);
|
||||||
|
--sw-modal-accent-glow: rgba(168,85,247,0.5);
|
||||||
|
--sw-modal-accent-text: #EDE9FE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hero (image en haut) + titre + stats : lisibles */
|
/* Hero (image en haut) + titre + stats : lisibles */
|
||||||
.sw-modal-hero {
|
.sw-modal-hero {
|
||||||
background: rgba(15, 23, 42, 0.98) !important; /* transparence intacte */
|
background: radial-gradient(circle at 30% 30%, var(--sw-modal-accent-soft, rgba(56,189,248,0.18)), rgba(3,14,32,0.98)) !important;
|
||||||
border: 3px solid #000 !important; /* contour plus épais */
|
border: 3px solid #000 !important; /* contour plus épais */
|
||||||
box-shadow: 0 12px 30px rgba(0,0,0,0.7), 0 0 16px rgba(56,189,248,0.5) !important;
|
box-shadow: 0 12px 30px rgba(0,0,0,0.7), 0 0 16px var(--sw-modal-accent-glow, rgba(56,189,248,0.5)) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sw-centered-modal.sw-modal-fullscreen{
|
.sw-centered-modal.sw-modal-fullscreen{
|
||||||
|
|
@ -119,19 +142,21 @@
|
||||||
}
|
}
|
||||||
.sw-modal-title,
|
.sw-modal-title,
|
||||||
.sw-modal-summary,
|
.sw-modal-summary,
|
||||||
.sw-stat-pill,
|
|
||||||
.sw-modal-meta,
|
|
||||||
.sw-livechat-title,
|
.sw-livechat-title,
|
||||||
.sw-chat-line,
|
.sw-chat-line,
|
||||||
.sw-livechat-input {
|
.sw-livechat-input {
|
||||||
color: #e5e7eb !important; /* texte blanc partout */
|
color: var(--sw-modal-text, #e5e7eb) !important; /* texte blanc partout */
|
||||||
|
}
|
||||||
|
.sw-modal-meta{
|
||||||
|
color: var(--sw-modal-meta, #9eb7ff) !important;
|
||||||
}
|
}
|
||||||
.sw-stat-pill {
|
.sw-stat-pill {
|
||||||
|
color: var(--sw-modal-pill-text, #c7e3ff) !important;
|
||||||
background: rgba(148, 163, 184, 0.25) !important;
|
background: rgba(148, 163, 184, 0.25) !important;
|
||||||
border: 1px solid rgba(148, 163, 184, 0.5) !important;
|
border: 1px solid rgba(148, 163, 184, 0.5) !important;
|
||||||
}
|
}
|
||||||
.sw-cta-primary {
|
.sw-cta-primary {
|
||||||
background: rgba(56,189,248,0.35) !important;
|
background: var(--sw-modal-accent-soft, rgba(56,189,248,0.35)) !important;
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
}
|
}
|
||||||
.sw-livechat-input {
|
.sw-livechat-input {
|
||||||
|
|
@ -474,8 +499,8 @@ body[data-theme="light"] .sw-chat-bubble::before{
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: .04em;
|
letter-spacing: .04em;
|
||||||
color: #d7f3ff;
|
color: var(--sw-modal-accent-text, #d7f3ff);
|
||||||
background: rgba(56,189,248,0.16);
|
background: var(--sw-modal-accent-soft, rgba(56,189,248,0.16));
|
||||||
border: 3px solid #000 !important; /* contour plus épais */
|
border: 3px solid #000 !important; /* contour plus épais */
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
@ -506,8 +531,8 @@ body[data-theme="light"] .sw-chat-bubble::before{
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-card-btn{
|
.post-card-btn{
|
||||||
background: rgba(56,189,248,0.14);
|
background: var(--sw-modal-accent-soft, rgba(56,189,248,0.14));
|
||||||
border: 1px solid rgba(56,189,248,0.35);
|
border: 1px solid var(--sw-modal-accent, rgba(56,189,248,0.35));
|
||||||
color: #e8f5ff;
|
color: #e8f5ff;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
|
|
@ -539,9 +564,9 @@ body[data-theme="light"] .sw-chat-bubble::before{
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
letter-spacing: .06em;
|
letter-spacing: .06em;
|
||||||
background: rgba(56,189,248,0.16);
|
background: var(--sw-modal-accent-soft, rgba(56,189,248,0.16));
|
||||||
border: 3px solid #000 !important; /* contour plus épais */
|
border: 3px solid #000 !important; /* contour plus épais */
|
||||||
color:#D7F3FF;
|
color: var(--sw-modal-accent-text, #D7F3FF);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,11 +616,46 @@ body[data-theme="light"] .sw-chat-bubble::before{
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
border: 3px solid #000 !important; /* contour plus épais */
|
border: 3px solid #000 !important; /* contour plus épais */
|
||||||
background: radial-gradient(circle at 30% 30%, rgba(56,189,248,0.18), rgba(3,14,32,0.98));
|
background: radial-gradient(circle at 30% 30%, var(--sw-modal-accent-soft, rgba(56,189,248,0.18)), rgba(3,14,32,0.98));
|
||||||
box-shadow: 0 10px 24px rgba(0,0,0,0.35);
|
box-shadow: 0 10px 24px rgba(0,0,0,0.35), 0 0 18px var(--sw-modal-accent-glow, rgba(56,189,248,0.45));
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"] .sw-centered-modal .post-card.sw-expanded-shell{
|
||||||
|
--sw-modal-text: #0f172a;
|
||||||
|
--sw-modal-meta: #64748b;
|
||||||
|
--sw-modal-pill-text: #0f172a;
|
||||||
|
--sw-modal-accent-text: #0f172a;
|
||||||
|
background: rgba(248, 250, 252, 0.98) !important;
|
||||||
|
border-color: rgba(148, 163, 184, 0.8) !important;
|
||||||
|
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.12), 0 0 14px rgba(148, 163, 184, 0.5) !important;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .sw-modal-title{
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .sw-modal-summary{
|
||||||
|
color:#334155;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .sw-modal-meta{
|
||||||
|
color:#64748b;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .sw-modal-hero-fallback{
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
body[data-theme="light"] .sw-modal-hero-fallback-inner{
|
||||||
|
border-color: rgba(148, 163, 184, 0.5);
|
||||||
|
color:#0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"] .sw-centered-modal .post-card.sw-expanded-shell .sw-stat-pill{
|
||||||
|
background: rgba(148, 163, 184, 0.18) !important;
|
||||||
|
border-color: rgba(148, 163, 184, 0.4) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .sw-centered-modal .post-card.sw-expanded-shell{
|
||||||
|
--sw-modal-meta: #b3ccff;
|
||||||
|
}
|
||||||
|
|
||||||
.sw-modal-hero-row{
|
.sw-modal-hero-row{
|
||||||
display:flex;
|
display:flex;
|
||||||
gap:16px;
|
gap:16px;
|
||||||
|
|
@ -881,9 +941,9 @@ body[data-theme="light"] .sw-modal-hero-fallback{
|
||||||
|
|
||||||
.sw-stat-pill{
|
.sw-stat-pill{
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color:#c7e3ff;
|
color: var(--sw-modal-pill-text, #c7e3ff);
|
||||||
background: rgba(3, 14, 32, 0.58);
|
background: rgba(3, 14, 32, 0.58);
|
||||||
border: 1px solid rgba(90, 190, 255, 0.22);
|
border: 1px solid var(--sw-modal-accent, rgba(90, 190, 255, 0.22));
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
|
|
@ -904,7 +964,7 @@ body[data-theme="light"] .sw-modal-hero-fallback{
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color:#e8f5ff;
|
color:#e8f5ff;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
background: rgba(56,189,248,0.22);
|
background: var(--sw-modal-accent-soft, rgba(56,189,248,0.22));
|
||||||
box-shadow: 0 10px 18px rgba(0,0,0,0.35);
|
box-shadow: 0 10px 18px rgba(0,0,0,0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -972,6 +1032,20 @@ body[data-theme="light"] .sw-modal-hero-fallback{
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .sw-centered-backdrop{
|
||||||
|
background: rgba(6, 16, 46, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"] .sw-centered-backdrop{
|
||||||
|
background: rgba(226, 232, 240, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"] .sw-modal-x{
|
||||||
|
background: rgba(226, 232, 240, 0.9);
|
||||||
|
color:#0f172a;
|
||||||
|
border-color: rgba(148, 163, 184, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
/* SW_MINI_SMOOTH_MOVE */
|
/* SW_MINI_SMOOTH_MOVE */
|
||||||
.post-pin{
|
.post-pin{
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@
|
||||||
animation: slideUp 0.3s ease;
|
animation: slideUp 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .user-profile-modal{
|
||||||
|
background: rgba(3, 10, 32, 0.86);
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .user-profile-container{
|
||||||
|
background: linear-gradient(135deg, #0b1b3b 0%, #0f224d 100%);
|
||||||
|
border: 1px solid rgba(96, 165, 250, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
.user-profile-close {
|
.user-profile-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0.75rem;
|
top: 0.75rem;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,18 @@
|
||||||
border: 1px solid rgba(148, 163, 184, 0.1);
|
border: 1px solid rgba(148, 163, 184, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[data-theme="blue"] .island-universe-modal{
|
||||||
|
background: linear-gradient(135deg, rgba(3, 10, 32, 0.96) 0%, rgba(6, 12, 36, 0.98) 100%);
|
||||||
|
}
|
||||||
|
body[data-theme="blue"] .island-universe-container{
|
||||||
|
background: linear-gradient(135deg, #0b1b3b 0%, #0f224d 45%, #162f5c 100%);
|
||||||
|
border-color: rgba(96, 165, 250, 0.35);
|
||||||
|
box-shadow:
|
||||||
|
0 30px 100px rgba(2, 8, 26, 0.85),
|
||||||
|
0 0 0 1px rgba(96, 165, 250, 0.2),
|
||||||
|
inset 0 1px 0 0 rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
.island-universe-close {
|
.island-universe-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1rem;
|
top: 1rem;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue