- ({ + ({ url: photo.url, thumbnailUrl: photo.thumbnailUrl, caption: photo.caption, @@ -152,8 +58,8 @@

Photos

- ({ + ({ url: attachment.url, thumbnailUrl: attachment.thumbnailUrl, caption: attachment.caption, @@ -216,17 +122,6 @@ margin-bottom: $unit-3x; } - .post-type-badge { - background: $blue-60; - color: white; - padding: $unit-half $unit-2x; - border-radius: 50px; - font-size: 0.75rem; - font-weight: 500; - text-transform: uppercase; - letter-spacing: 0.05em; - } - .post-date { font-size: 0.9rem; color: $grey-40; @@ -419,4 +314,4 @@ text-underline-offset: 0.15em; } } - + \ No newline at end of file diff --git a/src/lib/components/Slideshow.svelte b/src/lib/components/Slideshow.svelte index 531ac38..db0ae58 100644 --- a/src/lib/components/Slideshow.svelte +++ b/src/lib/components/Slideshow.svelte @@ -33,31 +33,32 @@ // Calculate columns based on breakpoints const columnsPerRow = $derived(windowWidth <= 400 ? 3 : windowWidth <= 600 ? 4 : 6) - + // Make maxThumbnails responsive - use fewer thumbnails on smaller screens const responsiveMaxThumbnails = $derived( maxThumbnails ? (windowWidth <= 400 ? 3 : windowWidth <= 600 ? 4 : maxThumbnails) : undefined ) - + const showMoreThumbnail = $derived( responsiveMaxThumbnails && totalCount && totalCount > responsiveMaxThumbnails - 1 ) - + // Determine how many thumbnails to show const displayItems = $derived( !responsiveMaxThumbnails || !showMoreThumbnail ? items : items.slice(0, responsiveMaxThumbnails - 1) // Show actual thumbnails, leave last slot for "+N" ) - + const remainingCount = $derived( showMoreThumbnail ? (totalCount || items.length) - (responsiveMaxThumbnails - 1) : 0 ) - + const totalSlots = $derived( responsiveMaxThumbnails ? responsiveMaxThumbnails - : Math.ceil((displayItems.length + (showMoreThumbnail ? 1 : 0)) / columnsPerRow) * columnsPerRow + : Math.ceil((displayItems.length + (showMoreThumbnail ? 1 : 0)) / columnsPerRow) * + columnsPerRow ) // Convert items to image URLs for lightbox @@ -105,16 +106,16 @@
openLightbox()}> - {items[selectedIndex].alt {#if items[selectedIndex].caption}
{items[selectedIndex].caption}
{/if}
- + {#if showThumbnails}
{#each Array(totalSlots) as _, index} @@ -125,9 +126,9 @@ onclick={() => selectImage(index)} aria-label="View image {index + 1}" > - {displayItems[index].alt || alt} thumbnail {index + 1} {:else if index === displayItems.length && showMoreThumbnail} @@ -137,14 +138,14 @@ aria-label="View all {totalCount || items.length} photos" > {#if items[displayItems.length]} - View all photos {:else if items[items.length - 1]} - View all photos @@ -162,7 +163,7 @@
{/if} - + \ No newline at end of file + diff --git a/src/lib/components/UniverseAlbumCard.svelte b/src/lib/components/UniverseAlbumCard.svelte index ff411a6..e504e81 100644 --- a/src/lib/components/UniverseAlbumCard.svelte +++ b/src/lib/components/UniverseAlbumCard.svelte @@ -1,177 +1,79 @@ -
-
-
-
Album
- + + {#if slideshowItems.length > 0} +
+ 1} + maxThumbnails={6} + totalCount={album.photosCount} + showMoreLink="/photos/{album.slug}" + />
+ {/if} - {#if slideshowItems.length > 0} -
- 1} - maxThumbnails={6} - totalCount={album.photosCount} - showMoreLink="/photos/{album.slug}" - /> -
+
+

+ e.preventDefault()} tabindex="-1">{album.title} +

+ + {#if album.description} +

{album.description}

{/if} - -
-

- {album.title} -

- - {#if album.location || album.date} -
- {#if album.date} - 📅 {formatDate(album.date)} - {/if} - {#if album.location} - 📍 {album.location} - {/if} -
- {/if} - - {#if album.description} -

{album.description}

- {/if} -
- -
-
+ + \ No newline at end of file diff --git a/src/lib/components/UniverseCard.svelte b/src/lib/components/UniverseCard.svelte new file mode 100644 index 0000000..7cb03f3 --- /dev/null +++ b/src/lib/components/UniverseCard.svelte @@ -0,0 +1,162 @@ + + + + + diff --git a/src/lib/components/UniverseFeed.svelte b/src/lib/components/UniverseFeed.svelte index 4f6ac16..12873e7 100644 --- a/src/lib/components/UniverseFeed.svelte +++ b/src/lib/components/UniverseFeed.svelte @@ -26,7 +26,7 @@ .universe-feed { display: flex; flex-direction: column; - gap: $unit-4x; + gap: $unit-3x; } .empty-state { diff --git a/src/lib/components/UniversePostCard.svelte b/src/lib/components/UniversePostCard.svelte index 2069c15..e2582a3 100644 --- a/src/lib/components/UniversePostCard.svelte +++ b/src/lib/components/UniversePostCard.svelte @@ -1,161 +1,64 @@ -
-
-
-
- {getPostTypeLabel(post.postType || 'post')} -
- -
+ + {#if post.title} +

+ e.preventDefault()} tabindex="-1">{post.title} +

+ {/if} - {#if post.title} -

- {post.title} -

- {/if} - - {#if post.linkUrl} - - - {/if} - -
- {#if post.excerpt} -

{post.excerpt}

- {:else if post.content} -

{getContentExcerpt(post.content)}

+ {#if post.linkUrl} + + + {/if} - {#if post.attachments && Array.isArray(post.attachments) && post.attachments.length > 0} -
-
- 📎 {post.attachments.length} attachment{post.attachments.length > 1 ? 's' : ''} -
-
+
+ {#if post.excerpt} +

{post.excerpt}

+ {:else if post.content} +

{getContentExcerpt(post.content)}

{/if} - -
-
+ + {#if post.postType === 'essay'} +

+ e.preventDefault()} tabindex="-1">Continue reading +

+ {/if} + + {#if post.attachments && Array.isArray(post.attachments) && post.attachments.length > 0} +
+
+ 📎 {post.attachments.length} attachment{post.attachments.length > 1 ? 's' : ''} +
+
+ {/if} + diff --git a/src/lib/utils/content.ts b/src/lib/utils/content.ts new file mode 100644 index 0000000..66bff41 --- /dev/null +++ b/src/lib/utils/content.ts @@ -0,0 +1,89 @@ +// Render Edra/BlockNote JSON content to HTML +export const renderEdraContent = (content: any): string => { + if (!content) return '' + + // Handle both { blocks: [...] } and { content: [...] } formats + const blocks = content.blocks || content.content || [] + if (!Array.isArray(blocks)) return '' + + const renderBlock = (block: any): string => { + switch (block.type) { + case 'heading': + const level = block.attrs?.level || block.level || 1 + const headingText = block.content || block.text || '' + return `${headingText}` + + case 'paragraph': + const paragraphText = block.content || block.text || '' + if (!paragraphText) return '


' + return `

${paragraphText}

` + + case 'bulletList': + case 'ul': + const listItems = (block.content || []) + .map((item: any) => { + const itemText = item.content || item.text || '' + return `
  • ${itemText}
  • ` + }) + .join('') + return `
      ${listItems}
    ` + + case 'orderedList': + case 'ol': + const orderedItems = (block.content || []) + .map((item: any) => { + const itemText = item.content || item.text || '' + return `
  • ${itemText}
  • ` + }) + .join('') + return `
      ${orderedItems}
    ` + + case 'blockquote': + const quoteText = block.content || block.text || '' + return `

    ${quoteText}

    ` + + case 'codeBlock': + case 'code': + const codeText = block.content || block.text || '' + const language = block.attrs?.language || block.language || '' + return `
    ${codeText}
    ` + + case 'image': + const src = block.attrs?.src || block.src || '' + const alt = block.attrs?.alt || block.alt || '' + const caption = block.attrs?.caption || block.caption || '' + return `
    ${alt}${caption ? `
    ${caption}
    ` : ''}
    ` + + case 'hr': + case 'horizontalRule': + return '
    ' + + default: + // For simple text content + const text = block.content || block.text || '' + if (text) { + return `

    ${text}

    ` + } + return '' + } + } + + return blocks.map(renderBlock).join('') +} + +// Extract text content from Edra JSON for excerpt +export const getContentExcerpt = (content: any, maxLength = 200): string => { + if (!content || !content.content) return '' + + const extractText = (node: any): string => { + if (node.text) return node.text + if (node.content && Array.isArray(node.content)) { + return node.content.map(extractText).join(' ') + } + return '' + } + + const text = content.content.map(extractText).join(' ').trim() + if (text.length <= maxLength) return text + return text.substring(0, maxLength).trim() + '...' +} \ No newline at end of file diff --git a/src/lib/utils/date.ts b/src/lib/utils/date.ts new file mode 100644 index 0000000..a97f509 --- /dev/null +++ b/src/lib/utils/date.ts @@ -0,0 +1,8 @@ +export function formatDate(dateString: string): string { + const date = new Date(dateString) + return date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }) +} \ No newline at end of file