Move parsing of place photos to util
Can be used in gallery later
This commit is contained in:
@@ -6,6 +6,7 @@ import { humanizeOsmTag } from '../utils/format-text';
|
|||||||
import { getLocalizedName, getPlaceType } from '../utils/osm';
|
import { getLocalizedName, getPlaceType } from '../utils/osm';
|
||||||
import { mapToStorageSchema } from '../utils/place-mapping';
|
import { mapToStorageSchema } from '../utils/place-mapping';
|
||||||
import { getSocialInfo } from '../utils/social-links';
|
import { getSocialInfo } from '../utils/social-links';
|
||||||
|
import { parsePlacePhotos } from '../utils/nostr';
|
||||||
import Icon from '../components/icon';
|
import Icon from '../components/icon';
|
||||||
import PlaceEditForm from './place-edit-form';
|
import PlaceEditForm from './place-edit-form';
|
||||||
import PlaceListsManager from './place-lists-manager';
|
import PlaceListsManager from './place-lists-manager';
|
||||||
@@ -80,69 +81,12 @@ export default class PlaceDetails extends Component {
|
|||||||
|
|
||||||
get photos() {
|
get photos() {
|
||||||
const rawPhotos = this.nostrData.placePhotos;
|
const rawPhotos = this.nostrData.placePhotos;
|
||||||
if (!rawPhotos || rawPhotos.length === 0) return [];
|
const parsedPhotos = parsePlacePhotos(rawPhotos);
|
||||||
|
|
||||||
// Sort by created_at ascending (oldest first)
|
return parsedPhotos.map((photo) => ({
|
||||||
const sortedEvents = [...rawPhotos].sort(
|
...photo,
|
||||||
(a, b) => a.created_at - b.created_at
|
style: htmlSafe(`--slide-ratio: ${photo.aspectRatio};`),
|
||||||
);
|
}));
|
||||||
|
|
||||||
const allPhotos = [];
|
|
||||||
|
|
||||||
for (const event of sortedEvents) {
|
|
||||||
// Find all imeta tags
|
|
||||||
const imetas = event.tags.filter((t) => t[0] === 'imeta');
|
|
||||||
for (const imeta of imetas) {
|
|
||||||
let url = null;
|
|
||||||
let thumbUrl = null;
|
|
||||||
let blurhash = null;
|
|
||||||
let isLandscape = false;
|
|
||||||
let aspectRatio = 16 / 9; // default
|
|
||||||
|
|
||||||
for (const tag of imeta.slice(1)) {
|
|
||||||
if (tag.startsWith('url ')) {
|
|
||||||
url = tag.substring(4);
|
|
||||||
} else if (tag.startsWith('thumb ')) {
|
|
||||||
thumbUrl = tag.substring(6);
|
|
||||||
} else if (tag.startsWith('blurhash ')) {
|
|
||||||
blurhash = tag.substring(9);
|
|
||||||
} else if (tag.startsWith('dim ')) {
|
|
||||||
const dimStr = tag.substring(4);
|
|
||||||
const [width, height] = dimStr.split('x').map(Number);
|
|
||||||
if (width && height) {
|
|
||||||
aspectRatio = width / height;
|
|
||||||
if (width > height) {
|
|
||||||
isLandscape = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url) {
|
|
||||||
allPhotos.push({
|
|
||||||
url,
|
|
||||||
thumbUrl,
|
|
||||||
blurhash,
|
|
||||||
isLandscape,
|
|
||||||
aspectRatio,
|
|
||||||
style: htmlSafe(`--slide-ratio: ${aspectRatio};`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allPhotos.length === 0) return [];
|
|
||||||
|
|
||||||
// Find the first landscape photo
|
|
||||||
const firstLandscapeIndex = allPhotos.findIndex((p) => p.isLandscape);
|
|
||||||
|
|
||||||
if (firstLandscapeIndex > 0) {
|
|
||||||
// Move the first landscape photo to the front
|
|
||||||
const [firstLandscape] = allPhotos.splice(firstLandscapeIndex, 1);
|
|
||||||
allPhotos.unshift(firstLandscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allPhotos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|||||||
@@ -13,3 +13,76 @@ export function normalizeRelayUrl(url) {
|
|||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts and normalizes photo data from NIP-360 (Place Photos) events.
|
||||||
|
* Sorts chronologically and guarantees the first landscape photo (or first portrait) is at index 0.
|
||||||
|
*
|
||||||
|
* @param {Array} events NIP-360 events
|
||||||
|
* @returns {Array} Array of photo objects
|
||||||
|
*/
|
||||||
|
export function parsePlacePhotos(events) {
|
||||||
|
if (!events || events.length === 0) return [];
|
||||||
|
|
||||||
|
// Sort by created_at ascending (oldest first)
|
||||||
|
const sortedEvents = [...events].sort((a, b) => a.created_at - b.created_at);
|
||||||
|
|
||||||
|
const allPhotos = [];
|
||||||
|
|
||||||
|
for (const event of sortedEvents) {
|
||||||
|
// Find all imeta tags
|
||||||
|
const imetas = event.tags.filter((t) => t[0] === 'imeta');
|
||||||
|
for (const imeta of imetas) {
|
||||||
|
let url = null;
|
||||||
|
let thumbUrl = null;
|
||||||
|
let blurhash = null;
|
||||||
|
let isLandscape = false;
|
||||||
|
let aspectRatio = 16 / 9; // default
|
||||||
|
|
||||||
|
for (const tag of imeta.slice(1)) {
|
||||||
|
if (tag.startsWith('url ')) {
|
||||||
|
url = tag.substring(4);
|
||||||
|
} else if (tag.startsWith('thumb ')) {
|
||||||
|
thumbUrl = tag.substring(6);
|
||||||
|
} else if (tag.startsWith('blurhash ')) {
|
||||||
|
blurhash = tag.substring(9);
|
||||||
|
} else if (tag.startsWith('dim ')) {
|
||||||
|
const dimStr = tag.substring(4);
|
||||||
|
const [width, height] = dimStr.split('x').map(Number);
|
||||||
|
if (width && height) {
|
||||||
|
aspectRatio = width / height;
|
||||||
|
if (width > height) {
|
||||||
|
isLandscape = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
allPhotos.push({
|
||||||
|
eventId: event.id,
|
||||||
|
pubkey: event.pubkey,
|
||||||
|
createdAt: event.created_at,
|
||||||
|
url,
|
||||||
|
thumbUrl,
|
||||||
|
blurhash,
|
||||||
|
isLandscape,
|
||||||
|
aspectRatio,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allPhotos.length === 0) return [];
|
||||||
|
|
||||||
|
// Find the first landscape photo
|
||||||
|
const firstLandscapeIndex = allPhotos.findIndex((p) => p.isLandscape);
|
||||||
|
|
||||||
|
if (firstLandscapeIndex > 0) {
|
||||||
|
// Move the first landscape photo to the front
|
||||||
|
const [firstLandscape] = allPhotos.splice(firstLandscapeIndex, 1);
|
||||||
|
allPhotos.unshift(firstLandscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPhotos;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user