From 672f184f62fa20421c0d5f98f0871398ad853faf Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Sun, 8 Mar 2026 16:16:26 +0100 Subject: [PATCH] feat(where): align checkin parsing and simplify where layout --- _data/whereCheckins.js | 219 +++++++++++++++++++++++------- _includes/layouts/where.njk | 11 +- theme/_data/whereCheckins.js | 219 +++++++++++++++++++++++------- theme/_includes/layouts/where.njk | 11 +- theme/where.njk | 11 +- 5 files changed, 344 insertions(+), 127 deletions(-) diff --git a/_data/whereCheckins.js b/_data/whereCheckins.js index f9b9e78..3ffb0cd 100644 --- a/_data/whereCheckins.js +++ b/_data/whereCheckins.js @@ -2,16 +2,24 @@ * Where/Checkin data * * Reads local check-ins created by this site's Micropub endpoint. - * A post is treated as a check-in when frontmatter includes checkin/location - * metadata, coordinates, or a checkin-like category. + * Supports OwnYourSwarm JSON mode and simple mode payloads once they are + * written to local markdown content. */ import matter from "gray-matter"; -import { readdirSync, readFileSync } from "node:fs"; +import { existsSync, readdirSync, readFileSync } from "node:fs"; import { extname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; -const CONTENT_DIR = fileURLToPath(new URL("../content", import.meta.url)); +function resolveContentDir() { + const candidates = ["../content", "../../content"].map((value) => + fileURLToPath(new URL(value, import.meta.url)) + ); + return candidates.find((dirPath) => existsSync(dirPath)) || candidates[0]; +} + +const CONTENT_DIR = resolveContentDir(); +const SWARM_HOST = "swarmapp.com"; function first(value) { if (Array.isArray(value)) return value[0]; @@ -42,14 +50,14 @@ function asNumber(value) { return Number.isFinite(num) ? num : null; } -function joinLocation(locality, region, country) { - return [locality, region, country].filter(Boolean).join(", "); -} - function uniqueStrings(values) { return [...new Set(values.filter(Boolean))]; } +function joinLocation(locality, region, country) { + return [locality, region, country].filter(Boolean).join(", "); +} + function toRelativePath(filePath) { return relative(CONTENT_DIR, filePath).replace(/\\/g, "/"); } @@ -72,15 +80,61 @@ function walkMarkdownFiles(dirPath) { return files; } +function toPropertiesObject(value) { + if (!value || typeof value !== "object") return {}; + if (value.properties && typeof value.properties === "object") { + return value.properties; + } + return value; +} + +function getEntryProperties(frontmatter) { + return toPropertiesObject(frontmatter.properties); +} + +function isSwarmUrl(url) { + return asText(url).toLowerCase().includes(SWARM_HOST); +} + +function parseGeoUri(value) { + const raw = asText(value).trim(); + const match = raw.match(/^geo:\s*([-+]?\d+(?:\.\d+)?),\s*([-+]?\d+(?:\.\d+)?)/i); + if (!match) { + return { + latitude: null, + longitude: null, + }; + } + + const latitude = Number(match[1]); + const longitude = Number(match[2]); + + return { + latitude: Number.isFinite(latitude) ? latitude : null, + longitude: Number.isFinite(longitude) ? longitude : null, + }; +} + +function extractSimpleModeVenueName(contentValue) { + const text = asText(contentValue).trim(); + if (!text) return ""; + + const match = text.match(/^Checked in (?:at|to)\s+(.+?)(?:\.\s|$)/i); + return match ? match[1].trim() : ""; +} + function parsePersonCard(card) { if (!card || typeof card !== "object") return null; - const props = card.properties || {}; + const props = toPropertiesObject(card); const urls = asArray(props.url).map((url) => asText(url)).filter(Boolean); const photos = asArray(props.photo).map((photo) => asText(photo)).filter(Boolean); return { - name: asText(first(asArray(props.name))), + name: + asText(first(asArray(props.name))) || + asText(props.firstName) || + "", url: urls[0] || "", urls, photo: photos[0] || "", @@ -98,9 +152,15 @@ function parseCategory(categoryValues) { } if (!value || typeof value !== "object") continue; - const type = Array.isArray(value.type) ? value.type : []; - if (type.includes("h-card")) { + const type = Array.isArray(value.type) ? value.type : []; + const looksLikePersonTag = + type.includes("h-card") || + Boolean(value.properties) || + value.name !== undefined || + value.url !== undefined; + + if (looksLikePersonTag) { const person = parsePersonCard(value); if (person && (person.name || person.url)) { people.push(person); @@ -121,101 +181,159 @@ function parseCategory(categoryValues) { function isCheckinFrontmatter(frontmatter, relativePath) { if (relativePath === "pages/where.md") return false; - const categories = asArray(frontmatter.category) + const properties = getEntryProperties(frontmatter); + + const checkinValue = + properties.checkin ?? + frontmatter.checkin ?? + frontmatter["check-in"]; + + const syndicationValues = asArray(properties.syndication ?? frontmatter.syndication) + .map((value) => asText(value)) + .filter(Boolean); + + const categories = asArray(properties.category ?? frontmatter.category) .map((value) => asText(value).toLowerCase()) .filter(Boolean); - const hasCheckinField = frontmatter.checkin !== undefined || frontmatter["check-in"] !== undefined; - const hasLocationField = frontmatter.location !== undefined; - const hasCoordinates = frontmatter.latitude !== undefined || frontmatter.longitude !== undefined; - const hasCheckinCategory = categories.includes("where") || categories.includes("checkin") || categories.includes("swarm"); + const locationValue = properties.location ?? frontmatter.location; + const geoCoords = parseGeoUri(first(asArray(locationValue))); - return hasCheckinField || hasLocationField || hasCoordinates || hasCheckinCategory; + const hasCheckinField = checkinValue !== undefined; + const hasSwarmSyndication = syndicationValues.some((url) => isSwarmUrl(url)); + const hasLocationField = locationValue !== undefined; + const hasCoordinates = + properties.latitude !== undefined || + properties.longitude !== undefined || + frontmatter.latitude !== undefined || + frontmatter.longitude !== undefined || + (geoCoords.latitude !== null && geoCoords.longitude !== null); + + const hasCheckinCategory = + categories.includes("where") || + categories.includes("checkin") || + categories.includes("swarm"); + + return hasCheckinField || hasSwarmSyndication || (hasCheckinCategory && (hasLocationField || hasCoordinates)); } function normalizeCheckin(frontmatter, relativePath) { - const checkinValue = first(asArray(frontmatter.checkin ?? frontmatter["check-in"])); - const locationValue = first(asArray(frontmatter.location)); + const properties = getEntryProperties(frontmatter); - const checkinProps = - checkinValue && typeof checkinValue === "object" && checkinValue.properties - ? checkinValue.properties - : {}; - const locationProps = - locationValue && typeof locationValue === "object" && locationValue.properties - ? locationValue.properties - : {}; + const checkinValue = first( + asArray(properties.checkin ?? frontmatter.checkin ?? frontmatter["check-in"]) + ); + const locationValue = first(asArray(properties.location ?? frontmatter.location)); + + const checkinProps = toPropertiesObject(checkinValue); + const locationProps = toPropertiesObject(locationValue); + const locationGeo = parseGeoUri(locationValue); const venueUrlsFromCard = asArray(checkinProps.url).map((url) => asText(url)).filter(Boolean); - const venueUrlFromSimpleMode = typeof checkinValue === "string" ? checkinValue : ""; - const venueUrls = venueUrlFromSimpleMode - ? [venueUrlFromSimpleMode, ...venueUrlsFromCard] - : venueUrlsFromCard; + const venueUrlFromSimpleMode = + typeof checkinValue === "string" ? checkinValue : asText(checkinValue?.value); + const venueUrls = uniqueStrings( + venueUrlFromSimpleMode ? [venueUrlFromSimpleMode, ...venueUrlsFromCard] : venueUrlsFromCard + ); const venueUrl = venueUrls[0] || ""; const venueWebsiteUrl = venueUrls[1] || ""; const venueSocialUrl = venueUrls[2] || ""; + const contentValue = first(asArray(properties.content ?? frontmatter.content)); + const simpleModeVenueName = extractSimpleModeVenueName(contentValue); + const name = asText(first(asArray(checkinProps.name))) || + simpleModeVenueName || asText(frontmatter.title) || "Unknown place"; const locality = asText(first(asArray(checkinProps.locality))) || asText(first(asArray(locationProps.locality))) || + asText(properties.locality) || asText(frontmatter.locality); const region = asText(first(asArray(checkinProps.region))) || asText(first(asArray(locationProps.region))) || + asText(properties.region) || asText(frontmatter.region); const country = asText(first(asArray(checkinProps["country-name"]))) || asText(first(asArray(locationProps["country-name"]))) || + asText(properties["country-name"]) || asText(frontmatter["country-name"]); const postalCode = asText(first(asArray(checkinProps["postal-code"]))) || asText(first(asArray(locationProps["postal-code"]))) || + asText(properties["postal-code"]) || asText(frontmatter["postal-code"]); const latitude = asNumber(checkinProps.latitude) ?? asNumber(locationProps.latitude) ?? - asNumber(frontmatter.latitude); + asNumber(properties.latitude) ?? + asNumber(frontmatter.latitude) ?? + locationGeo.latitude; const longitude = asNumber(checkinProps.longitude) ?? asNumber(locationProps.longitude) ?? - asNumber(frontmatter.longitude); + asNumber(properties.longitude) ?? + asNumber(frontmatter.longitude) ?? + locationGeo.longitude; const published = - asText(first(asArray(frontmatter.published))) || + asText(first(asArray(properties.published ?? frontmatter.published))) || asText(frontmatter.date); - const syndicationUrls = asArray(frontmatter.syndication) + const syndicationUrls = asArray(properties.syndication ?? frontmatter.syndication) .map((url) => asText(url)) .filter(Boolean); const syndication = - syndicationUrls.find((url) => url.includes("swarmapp.com")) || + syndicationUrls.find((url) => isSwarmUrl(url)) || syndicationUrls[0] || ""; - const visibility = asText(frontmatter.visibility).toLowerCase(); + const visibility = asText( + first(asArray(properties.visibility ?? frontmatter.visibility)) + ).toLowerCase(); - const categoryValues = asArray(frontmatter.category); + const categoryValues = asArray(properties.category ?? frontmatter.category); const category = parseCategory(categoryValues); - const checkedInByValue = first(asArray(frontmatter["checked-in-by"] ?? frontmatter.checkedInBy)); + const checkedInByValue = first( + asArray( + properties["checked-in-by"] ?? + frontmatter["checked-in-by"] ?? + frontmatter.checkedInBy + ) + ); const checkedInBy = parsePersonCard(checkedInByValue); - const photos = asArray(frontmatter.photo) - .map((photo) => { - if (typeof photo === "string") return photo; - if (photo && typeof photo === "object") { - return asText(photo.url || photo.value || photo.src || ""); - } - return ""; - }) - .filter(Boolean); + const addedPhotos = + frontmatter.add && typeof frontmatter.add === "object" + ? asArray(frontmatter.add.photo) + : []; + const photoValues = [ + ...asArray(properties.photo ?? frontmatter.photo), + ...addedPhotos, + ]; + const photos = uniqueStrings( + photoValues + .map((photo) => { + if (typeof photo === "string") return photo; + if (photo && typeof photo === "object") { + return asText(photo.url || photo.value || photo.src || ""); + } + return ""; + }) + .filter(Boolean) + ); + + if (!checkinValue && !syndication && latitude === null && longitude === null) { + return null; + } const mapUrl = latitude !== null && longitude !== null @@ -265,6 +383,7 @@ function normalizeCheckins(items) { const checkins = []; for (const item of items) { + if (!item) continue; if (seen.has(item.id)) continue; seen.add(item.id); checkins.push(item); @@ -310,7 +429,7 @@ export default async function () { if (!isCheckinFrontmatter(frontmatter, relativePath)) continue; const checkin = normalizeCheckin(frontmatter, relativePath); - items.push(checkin); + if (checkin) items.push(checkin); } catch (error) { errors.push(`[whereCheckins] Skipped ${relativePath}: ${error.message}`); } diff --git a/_includes/layouts/where.njk b/_includes/layouts/where.njk index 1067005..e4ad309 100644 --- a/_includes/layouts/where.njk +++ b/_includes/layouts/where.njk @@ -15,14 +15,10 @@ withSidebar: true {{ content | safe }} {% endif %} - {% if whereCheckins.available %} -

- Loaded {{ whereCheckins.stats.total }} check-ins{% if whereCheckins.stats.withCoordinates %} ({{ whereCheckins.stats.withCoordinates }} with coordinates){% endif %}. -

- {% endif %} {% if checkins.length %} +

Latest check-ins

{% for checkin in checkins %}
@@ -35,7 +31,7 @@ withSidebar: true
-

+

{% if checkin.venueUrl %} {{ checkin.name }} {% else %} @@ -87,9 +83,6 @@ withSidebar: true {% endif %}
- {% if checkin.syndication %} - Swarm - {% endif %} {% if checkin.mapUrl %} Map {% endif %} diff --git a/theme/_data/whereCheckins.js b/theme/_data/whereCheckins.js index f9b9e78..3ffb0cd 100644 --- a/theme/_data/whereCheckins.js +++ b/theme/_data/whereCheckins.js @@ -2,16 +2,24 @@ * Where/Checkin data * * Reads local check-ins created by this site's Micropub endpoint. - * A post is treated as a check-in when frontmatter includes checkin/location - * metadata, coordinates, or a checkin-like category. + * Supports OwnYourSwarm JSON mode and simple mode payloads once they are + * written to local markdown content. */ import matter from "gray-matter"; -import { readdirSync, readFileSync } from "node:fs"; +import { existsSync, readdirSync, readFileSync } from "node:fs"; import { extname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; -const CONTENT_DIR = fileURLToPath(new URL("../content", import.meta.url)); +function resolveContentDir() { + const candidates = ["../content", "../../content"].map((value) => + fileURLToPath(new URL(value, import.meta.url)) + ); + return candidates.find((dirPath) => existsSync(dirPath)) || candidates[0]; +} + +const CONTENT_DIR = resolveContentDir(); +const SWARM_HOST = "swarmapp.com"; function first(value) { if (Array.isArray(value)) return value[0]; @@ -42,14 +50,14 @@ function asNumber(value) { return Number.isFinite(num) ? num : null; } -function joinLocation(locality, region, country) { - return [locality, region, country].filter(Boolean).join(", "); -} - function uniqueStrings(values) { return [...new Set(values.filter(Boolean))]; } +function joinLocation(locality, region, country) { + return [locality, region, country].filter(Boolean).join(", "); +} + function toRelativePath(filePath) { return relative(CONTENT_DIR, filePath).replace(/\\/g, "/"); } @@ -72,15 +80,61 @@ function walkMarkdownFiles(dirPath) { return files; } +function toPropertiesObject(value) { + if (!value || typeof value !== "object") return {}; + if (value.properties && typeof value.properties === "object") { + return value.properties; + } + return value; +} + +function getEntryProperties(frontmatter) { + return toPropertiesObject(frontmatter.properties); +} + +function isSwarmUrl(url) { + return asText(url).toLowerCase().includes(SWARM_HOST); +} + +function parseGeoUri(value) { + const raw = asText(value).trim(); + const match = raw.match(/^geo:\s*([-+]?\d+(?:\.\d+)?),\s*([-+]?\d+(?:\.\d+)?)/i); + if (!match) { + return { + latitude: null, + longitude: null, + }; + } + + const latitude = Number(match[1]); + const longitude = Number(match[2]); + + return { + latitude: Number.isFinite(latitude) ? latitude : null, + longitude: Number.isFinite(longitude) ? longitude : null, + }; +} + +function extractSimpleModeVenueName(contentValue) { + const text = asText(contentValue).trim(); + if (!text) return ""; + + const match = text.match(/^Checked in (?:at|to)\s+(.+?)(?:\.\s|$)/i); + return match ? match[1].trim() : ""; +} + function parsePersonCard(card) { if (!card || typeof card !== "object") return null; - const props = card.properties || {}; + const props = toPropertiesObject(card); const urls = asArray(props.url).map((url) => asText(url)).filter(Boolean); const photos = asArray(props.photo).map((photo) => asText(photo)).filter(Boolean); return { - name: asText(first(asArray(props.name))), + name: + asText(first(asArray(props.name))) || + asText(props.firstName) || + "", url: urls[0] || "", urls, photo: photos[0] || "", @@ -98,9 +152,15 @@ function parseCategory(categoryValues) { } if (!value || typeof value !== "object") continue; - const type = Array.isArray(value.type) ? value.type : []; - if (type.includes("h-card")) { + const type = Array.isArray(value.type) ? value.type : []; + const looksLikePersonTag = + type.includes("h-card") || + Boolean(value.properties) || + value.name !== undefined || + value.url !== undefined; + + if (looksLikePersonTag) { const person = parsePersonCard(value); if (person && (person.name || person.url)) { people.push(person); @@ -121,101 +181,159 @@ function parseCategory(categoryValues) { function isCheckinFrontmatter(frontmatter, relativePath) { if (relativePath === "pages/where.md") return false; - const categories = asArray(frontmatter.category) + const properties = getEntryProperties(frontmatter); + + const checkinValue = + properties.checkin ?? + frontmatter.checkin ?? + frontmatter["check-in"]; + + const syndicationValues = asArray(properties.syndication ?? frontmatter.syndication) + .map((value) => asText(value)) + .filter(Boolean); + + const categories = asArray(properties.category ?? frontmatter.category) .map((value) => asText(value).toLowerCase()) .filter(Boolean); - const hasCheckinField = frontmatter.checkin !== undefined || frontmatter["check-in"] !== undefined; - const hasLocationField = frontmatter.location !== undefined; - const hasCoordinates = frontmatter.latitude !== undefined || frontmatter.longitude !== undefined; - const hasCheckinCategory = categories.includes("where") || categories.includes("checkin") || categories.includes("swarm"); + const locationValue = properties.location ?? frontmatter.location; + const geoCoords = parseGeoUri(first(asArray(locationValue))); - return hasCheckinField || hasLocationField || hasCoordinates || hasCheckinCategory; + const hasCheckinField = checkinValue !== undefined; + const hasSwarmSyndication = syndicationValues.some((url) => isSwarmUrl(url)); + const hasLocationField = locationValue !== undefined; + const hasCoordinates = + properties.latitude !== undefined || + properties.longitude !== undefined || + frontmatter.latitude !== undefined || + frontmatter.longitude !== undefined || + (geoCoords.latitude !== null && geoCoords.longitude !== null); + + const hasCheckinCategory = + categories.includes("where") || + categories.includes("checkin") || + categories.includes("swarm"); + + return hasCheckinField || hasSwarmSyndication || (hasCheckinCategory && (hasLocationField || hasCoordinates)); } function normalizeCheckin(frontmatter, relativePath) { - const checkinValue = first(asArray(frontmatter.checkin ?? frontmatter["check-in"])); - const locationValue = first(asArray(frontmatter.location)); + const properties = getEntryProperties(frontmatter); - const checkinProps = - checkinValue && typeof checkinValue === "object" && checkinValue.properties - ? checkinValue.properties - : {}; - const locationProps = - locationValue && typeof locationValue === "object" && locationValue.properties - ? locationValue.properties - : {}; + const checkinValue = first( + asArray(properties.checkin ?? frontmatter.checkin ?? frontmatter["check-in"]) + ); + const locationValue = first(asArray(properties.location ?? frontmatter.location)); + + const checkinProps = toPropertiesObject(checkinValue); + const locationProps = toPropertiesObject(locationValue); + const locationGeo = parseGeoUri(locationValue); const venueUrlsFromCard = asArray(checkinProps.url).map((url) => asText(url)).filter(Boolean); - const venueUrlFromSimpleMode = typeof checkinValue === "string" ? checkinValue : ""; - const venueUrls = venueUrlFromSimpleMode - ? [venueUrlFromSimpleMode, ...venueUrlsFromCard] - : venueUrlsFromCard; + const venueUrlFromSimpleMode = + typeof checkinValue === "string" ? checkinValue : asText(checkinValue?.value); + const venueUrls = uniqueStrings( + venueUrlFromSimpleMode ? [venueUrlFromSimpleMode, ...venueUrlsFromCard] : venueUrlsFromCard + ); const venueUrl = venueUrls[0] || ""; const venueWebsiteUrl = venueUrls[1] || ""; const venueSocialUrl = venueUrls[2] || ""; + const contentValue = first(asArray(properties.content ?? frontmatter.content)); + const simpleModeVenueName = extractSimpleModeVenueName(contentValue); + const name = asText(first(asArray(checkinProps.name))) || + simpleModeVenueName || asText(frontmatter.title) || "Unknown place"; const locality = asText(first(asArray(checkinProps.locality))) || asText(first(asArray(locationProps.locality))) || + asText(properties.locality) || asText(frontmatter.locality); const region = asText(first(asArray(checkinProps.region))) || asText(first(asArray(locationProps.region))) || + asText(properties.region) || asText(frontmatter.region); const country = asText(first(asArray(checkinProps["country-name"]))) || asText(first(asArray(locationProps["country-name"]))) || + asText(properties["country-name"]) || asText(frontmatter["country-name"]); const postalCode = asText(first(asArray(checkinProps["postal-code"]))) || asText(first(asArray(locationProps["postal-code"]))) || + asText(properties["postal-code"]) || asText(frontmatter["postal-code"]); const latitude = asNumber(checkinProps.latitude) ?? asNumber(locationProps.latitude) ?? - asNumber(frontmatter.latitude); + asNumber(properties.latitude) ?? + asNumber(frontmatter.latitude) ?? + locationGeo.latitude; const longitude = asNumber(checkinProps.longitude) ?? asNumber(locationProps.longitude) ?? - asNumber(frontmatter.longitude); + asNumber(properties.longitude) ?? + asNumber(frontmatter.longitude) ?? + locationGeo.longitude; const published = - asText(first(asArray(frontmatter.published))) || + asText(first(asArray(properties.published ?? frontmatter.published))) || asText(frontmatter.date); - const syndicationUrls = asArray(frontmatter.syndication) + const syndicationUrls = asArray(properties.syndication ?? frontmatter.syndication) .map((url) => asText(url)) .filter(Boolean); const syndication = - syndicationUrls.find((url) => url.includes("swarmapp.com")) || + syndicationUrls.find((url) => isSwarmUrl(url)) || syndicationUrls[0] || ""; - const visibility = asText(frontmatter.visibility).toLowerCase(); + const visibility = asText( + first(asArray(properties.visibility ?? frontmatter.visibility)) + ).toLowerCase(); - const categoryValues = asArray(frontmatter.category); + const categoryValues = asArray(properties.category ?? frontmatter.category); const category = parseCategory(categoryValues); - const checkedInByValue = first(asArray(frontmatter["checked-in-by"] ?? frontmatter.checkedInBy)); + const checkedInByValue = first( + asArray( + properties["checked-in-by"] ?? + frontmatter["checked-in-by"] ?? + frontmatter.checkedInBy + ) + ); const checkedInBy = parsePersonCard(checkedInByValue); - const photos = asArray(frontmatter.photo) - .map((photo) => { - if (typeof photo === "string") return photo; - if (photo && typeof photo === "object") { - return asText(photo.url || photo.value || photo.src || ""); - } - return ""; - }) - .filter(Boolean); + const addedPhotos = + frontmatter.add && typeof frontmatter.add === "object" + ? asArray(frontmatter.add.photo) + : []; + const photoValues = [ + ...asArray(properties.photo ?? frontmatter.photo), + ...addedPhotos, + ]; + const photos = uniqueStrings( + photoValues + .map((photo) => { + if (typeof photo === "string") return photo; + if (photo && typeof photo === "object") { + return asText(photo.url || photo.value || photo.src || ""); + } + return ""; + }) + .filter(Boolean) + ); + + if (!checkinValue && !syndication && latitude === null && longitude === null) { + return null; + } const mapUrl = latitude !== null && longitude !== null @@ -265,6 +383,7 @@ function normalizeCheckins(items) { const checkins = []; for (const item of items) { + if (!item) continue; if (seen.has(item.id)) continue; seen.add(item.id); checkins.push(item); @@ -310,7 +429,7 @@ export default async function () { if (!isCheckinFrontmatter(frontmatter, relativePath)) continue; const checkin = normalizeCheckin(frontmatter, relativePath); - items.push(checkin); + if (checkin) items.push(checkin); } catch (error) { errors.push(`[whereCheckins] Skipped ${relativePath}: ${error.message}`); } diff --git a/theme/_includes/layouts/where.njk b/theme/_includes/layouts/where.njk index 1d095d7..cd0ea80 100644 --- a/theme/_includes/layouts/where.njk +++ b/theme/_includes/layouts/where.njk @@ -15,14 +15,10 @@ withSidebar: true {{ content | safe }}
{% endif %} - {% if whereCheckins.available %} -

- Loaded {{ whereCheckins.stats.total }} check-ins{% if whereCheckins.stats.withCoordinates %} ({{ whereCheckins.stats.withCoordinates }} with coordinates){% endif %}. -

- {% endif %} {% if checkins.length %} +

Latest check-ins

{% for checkin in checkins %}
@@ -35,7 +31,7 @@ withSidebar: true
-

+

{% if checkin.venueUrl %} {{ checkin.name }} {% else %} @@ -87,9 +83,6 @@ withSidebar: true {% endif %}
- {% if checkin.syndication %} - Swarm - {% endif %} {% if checkin.mapUrl %} Map {% endif %} diff --git a/theme/where.njk b/theme/where.njk index 0105c9f..caed4ea 100644 --- a/theme/where.njk +++ b/theme/where.njk @@ -12,14 +12,10 @@ withSidebar: true

Recent check-ins captured by this site via Micropub.

- {% if whereCheckins.available %} -

- Loaded {{ whereCheckins.stats.total }} check-ins{% if whereCheckins.stats.withCoordinates %} ({{ whereCheckins.stats.withCoordinates }} with coordinates){% endif %}. -

- {% endif %} {% if checkins.length %} +

Latest check-ins

{% for checkin in checkins %}
@@ -32,7 +28,7 @@ withSidebar: true
-

+

{% if checkin.venueUrl %} {{ checkin.name }} {% else %} @@ -84,9 +80,6 @@ withSidebar: true {% endif %}
- {% if checkin.syndication %} - Swarm - {% endif %} {% if checkin.mapUrl %} Map {% endif %}