feat: add impact-colored tags to post modals
- Update renderTagPills to accept topicImpacts and apply color classes - Tags colored by impact: negative=red, neutral=blue, positive=green - Add CSS for tag color classes (sw-tag-negative, sw-tag-neutral, sw-tag-positive) - Tags display below title in post modals Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
91e024e156
commit
9e6f3f8029
|
|
@ -524,7 +524,7 @@ function getCameraStreamUrl(postData) {
|
|||
return embedUrl;
|
||||
}
|
||||
|
||||
function renderTagPills(tags) {
|
||||
function renderTagPills(tags, topicImpacts = {}) {
|
||||
if (!Array.isArray(tags) || tags.length === 0) return "";
|
||||
const uniq = [];
|
||||
const seen = new Set();
|
||||
|
|
@ -536,16 +536,25 @@ function renderTagPills(tags) {
|
|||
if (uniq.length >= 6) break;
|
||||
}
|
||||
if (uniq.length === 0) return "";
|
||||
|
||||
// Get impact color class: negative=red, neutral=blue, positive=green
|
||||
const getImpactClass = (tag) => {
|
||||
const impact = topicImpacts?.[tag] ?? topicImpacts?.[tag.toLowerCase()] ?? 0;
|
||||
if (impact < 0) return "sw-tag-negative";
|
||||
if (impact > 0) return "sw-tag-positive";
|
||||
return "sw-tag-neutral";
|
||||
};
|
||||
|
||||
return `
|
||||
<div class="sw-modal-tags">
|
||||
${uniq.map((t) => `<span class="sw-modal-tag">#${escapeHtml(t)}</span>`).join("")}
|
||||
${uniq.map((t) => `<span class="sw-modal-tag ${getImpactClass(t)}">#${escapeHtml(t)}</span>`).join("")}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function setModalTags(modalWrap, post) {
|
||||
if (!modalWrap) return;
|
||||
const tagsHtml = renderTagPills(post?.event_tags || post?.tags);
|
||||
const tagsHtml = renderTagPills(post?.event_tags || post?.tags, post?.topic_impacts);
|
||||
const existing = modalWrap.querySelector(".sw-modal-tags");
|
||||
if (tagsHtml) {
|
||||
if (existing) {
|
||||
|
|
@ -1281,7 +1290,7 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
|||
const isCluster = isClusterMainPost(postData);
|
||||
const clusterItems = Array.isArray(postData?.cluster_items) ? postData.cluster_items : [];
|
||||
const clusterCount = Array.isArray(postData?.cluster_members) ? postData.cluster_members.length : 0;
|
||||
const tagPills = renderTagPills(postData?.event_tags || postData?.tags);
|
||||
const tagPills = renderTagPills(postData?.event_tags || postData?.tags, postData?.topic_impacts);
|
||||
const heatmapPill = HEATMAP_ENABLED
|
||||
? `<div class="sw-stat-pill sw-heatmap-pill" data-action="cluster-heatmap">🔥 Heat map</div>`
|
||||
: "";
|
||||
|
|
@ -1336,7 +1345,9 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
|||
</div>
|
||||
|
||||
<div class="sw-cluster-title">${escapeHtml(postData?.cluster_title || postData?.title || "Untitled")}</div>
|
||||
${tagPills}
|
||||
<div class="sw-modal-title-meta" style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
||||
${tagPills}
|
||||
</div>
|
||||
|
||||
<div class="sw-cluster-body">
|
||||
<div class="sw-cluster-left">
|
||||
|
|
@ -1575,7 +1586,9 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
|||
</div>
|
||||
</div>
|
||||
<div class="sw-modal-title">${escapeHtml(data?.headline || postData?.title || "Untitled")}</div>
|
||||
${tagPills}
|
||||
<div class="sw-modal-title-meta" style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
||||
${tagPills}
|
||||
</div>
|
||||
|
||||
<div class="sw-modal-summary">
|
||||
${escapeHtml(data?.summary || postData?.snippet || "")}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export function getCameraStreamUrl(postData) {
|
|||
return embedUrl;
|
||||
}
|
||||
|
||||
export function renderTagPills(tags) {
|
||||
export function renderTagPills(tags, topicImpacts = {}) {
|
||||
if (!Array.isArray(tags) || tags.length === 0) return "";
|
||||
const uniq = [];
|
||||
const seen = new Set();
|
||||
|
|
@ -102,16 +102,25 @@ export function renderTagPills(tags) {
|
|||
if (uniq.length >= 6) break;
|
||||
}
|
||||
if (uniq.length === 0) return "";
|
||||
|
||||
// Get impact color class: negative=red, neutral=blue, positive=green
|
||||
const getImpactClass = (tag) => {
|
||||
const impact = topicImpacts?.[tag] ?? topicImpacts?.[tag.toLowerCase()] ?? 0;
|
||||
if (impact < 0) return "sw-tag-negative";
|
||||
if (impact > 0) return "sw-tag-positive";
|
||||
return "sw-tag-neutral";
|
||||
};
|
||||
|
||||
return `
|
||||
<div class="sw-modal-tags">
|
||||
${uniq.map((t) => `<span class="sw-modal-tag">#${escapeHtml(t)}</span>`).join("")}
|
||||
${uniq.map((t) => `<span class="sw-modal-tag ${getImpactClass(t)}">#${escapeHtml(t)}</span>`).join("")}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
export function setModalTags(modalWrap, post) {
|
||||
if (!modalWrap) return;
|
||||
const tagsHtml = renderTagPills(post?.event_tags || post?.tags);
|
||||
const tagsHtml = renderTagPills(post?.event_tags || post?.tags, post?.topic_impacts);
|
||||
const existing = modalWrap.querySelector(".sw-modal-tags");
|
||||
if (tagsHtml) {
|
||||
if (existing) {
|
||||
|
|
|
|||
|
|
@ -11,23 +11,23 @@
|
|||
export const TEMPLATE_SPECS = {
|
||||
polaroid: {
|
||||
mini_spec: {
|
||||
size: { w: 100, h: 130 },
|
||||
size: { w: 80, h: 104 },
|
||||
background: { type: "solid", value: "#ffffff" },
|
||||
radius: 4,
|
||||
radius: 3,
|
||||
layers: [
|
||||
{ id: "image", type: "image", x: 5, y: 5, w: 90, h: 90, bind: "data.image", radius: 2 },
|
||||
{ id: "title", type: "text", x: 5, y: 98, w: 90, h: 18, bind: "data.headline", style: "text.polaroidTitle", maxLines: 2 },
|
||||
{ id: "author", type: "text", x: 5, y: 116, w: 90, h: 10, bind: "data.source", style: "text.polaroidCaption", maxLines: 1 },
|
||||
{ id: "image", type: "image", x: 4, y: 4, w: 72, h: 72, bind: "data.image", radius: 2 },
|
||||
{ id: "title", type: "text", x: 4, y: 78, w: 72, h: 14, bind: "data.headline", style: "text.polaroidTitle", maxLines: 2 },
|
||||
{ id: "author", type: "text", x: 4, y: 92, w: 72, h: 8, bind: "data.source", style: "text.polaroidCaption", maxLines: 1 },
|
||||
],
|
||||
},
|
||||
full_spec: {
|
||||
size: { w: 190, h: 230 },
|
||||
size: { w: 150, h: 180 },
|
||||
background: { type: "solid", value: "#ffffff" },
|
||||
radius: 8,
|
||||
radius: 6,
|
||||
layers: [
|
||||
{ id: "image", type: "image", x: 10, y: 10, w: 170, h: 170, bind: "data.image", radius: 4 },
|
||||
{ id: "author", type: "text", x: 10, y: 185, w: 170, h: 18, bind: "data.source", style: "text.polaroidCaption", maxLines: 1 },
|
||||
{ id: "caption", type: "text", x: 10, y: 205, w: 170, h: 22, bind: "data.headline", style: "text.polaroidText", maxLines: 2 },
|
||||
{ id: "image", type: "image", x: 8, y: 8, w: 134, h: 134, bind: "data.image", radius: 3 },
|
||||
{ id: "author", type: "text", x: 8, y: 146, w: 134, h: 14, bind: "data.source", style: "text.polaroidCaption", maxLines: 1 },
|
||||
{ id: "caption", type: "text", x: 8, y: 162, w: 134, h: 16, bind: "data.headline", style: "text.polaroidText", maxLines: 2 },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -309,15 +309,13 @@ export function getTemplateKeyForPost(post) {
|
|||
return 'camera';
|
||||
}
|
||||
|
||||
// If content_type is empty/unknown but post has images, show as polaroid
|
||||
// This handles posts where content_type wasn't set but images exist
|
||||
const hasImage = !!(post?.image_small || post?.image_medium || post?.image_large || post?.image || post?.thumbnail_url || post?.media_url);
|
||||
// Detect videos/cameras by URL if content_type not set
|
||||
const hasVideo = !!(post?.video_url || post?.embed_url);
|
||||
if (!ct && hasImage && !hasVideo) {
|
||||
return 'polaroid';
|
||||
if (!ct && hasVideo) {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
// Default: category-based template
|
||||
// Default: category-based template (news, breaking, etc.)
|
||||
return normCat(post);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1297,6 +1297,22 @@ body[data-theme="light"] .sw-modal-x{
|
|||
color: var(--sw-modal-text, #e5e7eb);
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
/* Tag impact colors */
|
||||
.sw-modal-tag.sw-tag-negative{
|
||||
background: rgba(239, 68, 68, 0.25);
|
||||
color: #fca5a5;
|
||||
border: 1px solid rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
.sw-modal-tag.sw-tag-neutral{
|
||||
background: rgba(59, 130, 246, 0.25);
|
||||
color: #93c5fd;
|
||||
border: 1px solid rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
.sw-modal-tag.sw-tag-positive{
|
||||
background: rgba(34, 197, 94, 0.25);
|
||||
color: #86efac;
|
||||
border: 1px solid rgba(34, 197, 94, 0.4);
|
||||
}
|
||||
.sw-cluster-body{
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 44%) minmax(240px, 56%);
|
||||
|
|
|
|||
Loading…
Reference in New Issue