Skip to content

Self-hosted: side thumbnails on Journal entries - #1447

Merged
feruzm merged 2 commits into
developfrom
feature/journal-entry-thumbnails
Aug 12, 2026
Merged

Self-hosted: side thumbnails on Journal entries#1447
feruzm merged 2 commits into
developfrom
feature/journal-entry-thumbnails

Conversation

@feruzm

@feruzm feruzm commented Aug 12, 2026

Copy link
Copy Markdown
Member

Owner feedback from Journal's first visual pass: entries should show the post's image.

Adds a quiet side thumbnail beside the excerpt (marginalia, not a hero): resolved and proxied through render-helper exactly like the default card so no author-controlled URL ever reaches the src, lazy-loaded, radius from the theme token and hidden on the narrowest screens where it would crowd the 680px column. Entries without an image keep the pure text layout.

SPA suite 906 tests, typecheck green.

Owner feedback from the first visual pass: entries should carry the
post's image. A quiet side thumbnail rather than a hero, sized like
marginalia beside the excerpt, resolved and proxied by render-helper
exactly like the default card so no author-controlled URL reaches the
src, lazy-loaded and hidden on the narrowest screens where it would
crowd the measure-width column.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Missing Journal thumbnail tests ✗ Dismissed 📘 Rule violation ▣ Testability
Description
The PR adds a new image-resolution branch and conditional thumbnail rendering, including the
no-image text-only path, but no automated tests are added or updated to exercise these behaviors.
This leaves the new functional paths unverified.
Code

apps/self-hosted/src/themes/journal/journal-post-card.tsx[R31-34]

+  const imageUrl = useMemo(
+    () => catchPostImage(entryData, 400, 300) || null,
+    [entryData],
+  );
Relevance

●●● Strong

Team often adds/extends tests when new behavior paths are introduced.

PR-#1440

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance ID 2667972 requires automated coverage for every new functional path. The added
catchPostImage computation and imageUrl && rendering branch introduce behavior without any test
changes in the supplied diff.

Rule 2667972: Require tests for all new functional code paths
apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]
apps/self-hosted/src/themes/journal/journal-post-card.tsx[70-87]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Journal post card now resolves a post image and conditionally renders a lazy-loaded side thumbnail, but the new behavior has no corresponding automated tests.
## Issue Context
Add tests for an entry with an image, asserting the proxied image is rendered with lazy loading and the expected layout attributes, and an entry without an image, asserting the thumbnail is absent while the text content remains rendered.
## Fix Focus Areas
- apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]
- apps/self-hosted/src/themes/journal/[add or update corresponding test file]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Thumbnail proxy memo can become stale 🐞 Bug ☼ Reliability
Description
The new thumbnail URL is memoized only against entryData via useMemo, while the self-hosted app
configures the render-helper's proxy base independently at startup through setProxyBase. If the
image-proxy setting is changed at runtime while a Journal card remains mounted, the card can keep
rendering the old proxied URL because the memo's dependency array does not include the proxy
configuration.
Code

apps/self-hosted/src/themes/journal/journal-post-card.tsx[R31-34]

+  const imageUrl = useMemo(
+    () => catchPostImage(entryData, 400, 300) || null,
+    [entryData],
+  );
Relevance

● Weak

Similar “make UI reactive to runtime config changes” request was rejected as unnecessary.

PR-#1162

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
catchPostImage resolves and proxifies the image using the render-helper's currently configured proxy
base (set via setProxyBase in apps/self-hosted/src/index.tsx). The Journal card's useMemo recomputes
only when entryData changes, so if the proxy base changes independently while the card stays
mounted, the cached imageUrl is not recalculated and the thumbnail continues to point at the stale
proxy URL until entryData changes or the component remounts.

apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `imageUrl` memo in the Journal post card recomputes only when `entryData` changes, so it will not reflect a runtime change to the render-helper's image proxy base while the card remains mounted.
### Issue Context
`setProxyBase` is called once at startup from instance configuration (apps/self-hosted/src/index.tsx). `catchPostImage` reads that configured proxy base internally. If the proxy base can be updated at runtime (e.g. live config preview), any already-mounted card will keep showing a thumbnail proxied through the stale base.
### Fix Focus Areas
- apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]
Consider exposing the current proxy base as a reactive value (e.g. from InstanceConfigManager) and adding it to the memo's dependency array, or removing the memoization if recomputing on every render is cheap enough.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@feruzm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f334703b-9a88-469c-9f3d-0a59bbd75bcf

📥 Commits

Reviewing files that changed from the base of the PR and between 277b790 and 636ce2b.

📒 Files selected for processing (1)
  • apps/self-hosted/src/themes/journal/journal-post-card.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Self-hosted Journal: add side thumbnails to entry cards

✨ Enhancement 🕐 10-20 Minutes

Grey Divider

AI Description

• Show a small side thumbnail next to Journal entry excerpts when an image exists
• Resolve and proxy image URLs via render-helper to avoid untrusted author URLs in src
• Lazy-load thumbnails and hide them on narrow screens to preserve reading width
Diagram

graph TD
  A["JournalPostCard.tsx"] --> B["Compute summary"] --> C["catchPostImage (proxy)"] --> D["Render entry row"] --> E["Link to post route"]
  D --> F["Side thumbnail img"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extract a shared "PostThumbnail" component
  • ➕ Avoids duplicating image-resolution + sizing conventions across themes/components
  • ➕ Centralizes accessibility decisions (decorative vs informative image)
  • ➖ Adds abstraction overhead for a single theme-specific layout
  • ➖ May constrain Journal-specific styling choices (marginalia vs hero)
2. Add responsive srcset/sizes for the thumbnail
  • ➕ Better bandwidth/perf on mobile and high-DPI screens
  • ➕ Improves image quality control across breakpoints
  • ➖ More complexity in render-helper integration and testing
  • ➖ May be premature if proxy already serves appropriately sized variants

Recommendation: Current approach is sound: using render-helper’s catchPostImage keeps untrusted on-chain metadata from flowing directly into , and the conditional/hidden-on-small breakpoint preserves the Journal reading layout. Consider extracting a small shared thumbnail helper only if additional surfaces adopt the same pattern.

Files changed (1) +57 / -22

Enhancement (1) +57 / -22
journal-post-card.tsxAdd optional proxied side thumbnail to Journal entries +57/-22

Add optional proxied side thumbnail to Journal entries

• Introduces imageUrl derivation via render-helper catchPostImage to ensure only proxied URLs reach the img src. Updates the entry layout to a two-column flex row with a conditional, lazy-loaded side thumbnail that’s hidden on narrow screens and treated as decorative (aria-hidden/tabIndex -1).

apps/self-hosted/src/themes/journal/journal-post-card.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 048614387f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

src={imageUrl}
alt=""
loading="lazy"
className="hidden sm:block size-28 object-cover post-card-image-theme"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid the shared image-height override on the thumbnail

When the Journal theme renders this image, post-card-image-theme applies the unlayered rule in src/styles/components.css, whose height: var(--theme-post-card-image-height) overrides Tailwind's layered size-28 height. The Journal token sets that height to 200px, so the intended 112×112 marginal thumbnail actually renders 112×200; use only the radius token here or otherwise explicitly preserve the square height.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 636ce2b. The img no longer uses post-card-image-theme, whose unlayered height token (200px under Journal) overrode the layered Tailwind size. The radius token is applied directly via rounded-[var(--theme-post-card-image-radius)] and size-28 now controls both dimensions.

to="/$author/$permlink"
params={postParams}
search={postSearch}
className="shrink-0 mt-1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide the entire thumbnail flex item below sm

For image-bearing posts below the sm breakpoint, only the <img> is hidden while this Link remains a second flex item. Even though that item has zero width, the parent gap-5 still reserves a 20px gap, narrowing the text column on exactly the small screens where the thumbnail is meant not to crowd it; apply the responsive display classes to the link itself.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 636ce2b. hidden sm:block moved from the img to the Link wrapper, so below sm the whole flex item is gone and the row's gap-5 no longer reserves space for it.

@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Missing Journal thumbnail tests ✗ Dismissed 📘 Rule violation ▣ Testability
Description
The PR adds a new image-resolution branch and conditional thumbnail rendering, including the
no-image text-only path, but no automated tests are added or updated to exercise these behaviors.
This leaves the new functional paths unverified.
Code

apps/self-hosted/src/themes/journal/journal-post-card.tsx[R31-34]

+  const imageUrl = useMemo(
+    () => catchPostImage(entryData, 400, 300) || null,
+    [entryData],
+  );
Relevance

●●● Strong

Team often adds/extends tests when new behavior paths are introduced.

PR-#1440

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance ID 2667972 requires automated coverage for every new functional path. The added
catchPostImage computation and imageUrl && rendering branch introduce behavior without any test
changes in the supplied diff.

Rule 2667972: Require tests for all new functional code paths
apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]
apps/self-hosted/src/themes/journal/journal-post-card.tsx[70-87]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Journal post card now resolves a post image and conditionally renders a lazy-loaded side thumbnail, but the new behavior has no corresponding automated tests.

## Issue Context
Add tests for an entry with an image, asserting the proxied image is rendered with lazy loading and the expected layout attributes, and an entry without an image, asserting the thumbnail is absent while the text content remains rendered.

## Fix Focus Areas
- apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]
- apps/self-hosted/src/themes/journal/[add or update corresponding test file]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Thumbnail proxy memo can become stale 🐞 Bug ☼ Reliability
Description
The new thumbnail URL is memoized only against entryData via useMemo, while the self-hosted app
configures the render-helper's proxy base independently at startup through setProxyBase. If the
image-proxy setting is changed at runtime while a Journal card remains mounted, the card can keep
rendering the old proxied URL because the memo's dependency array does not include the proxy
configuration.
Code

apps/self-hosted/src/themes/journal/journal-post-card.tsx[R31-34]

+  const imageUrl = useMemo(
+    () => catchPostImage(entryData, 400, 300) || null,
+    [entryData],
+  );
Relevance

● Weak

Similar “make UI reactive to runtime config changes” request was rejected as unnecessary.

PR-#1162

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
catchPostImage resolves and proxifies the image using the render-helper's currently configured proxy
base (set via setProxyBase in apps/self-hosted/src/index.tsx). The Journal card's useMemo recomputes
only when entryData changes, so if the proxy base changes independently while the card stays
mounted, the cached imageUrl is not recalculated and the thumbnail continues to point at the stale
proxy URL until entryData changes or the component remounts.

apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `imageUrl` memo in the Journal post card recomputes only when `entryData` changes, so it will not reflect a runtime change to the render-helper's image proxy base while the card remains mounted.

### Issue Context
`setProxyBase` is called once at startup from instance configuration (apps/self-hosted/src/index.tsx). `catchPostImage` reads that configured proxy base internally. If the proxy base can be updated at runtime (e.g. live config preview), any already-mounted card will keep showing a thumbnail proxied through the stale base.

### Fix Focus Areas
- apps/self-hosted/src/themes/journal/journal-post-card.tsx[31-34]

Consider exposing the current proxy base as a reactive value (e.g. from InstanceConfigManager) and adding it to the memo's dependency array, or removing the memoization if recomputing on every render is cheap enough.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 75 rules
✅ Skills: 6 invoked
  add-feature
  add-query
  add-sdk-mutation
  add-test
  code-review
  debug
Review mode: 🚀 Fast: This is a localized, single-component UI change with contained image-resolution and layout logic, avoiding security, data, API, and other high-risk paths.

Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/self-hosted/src/themes/journal/journal-post-card.tsx
The shared post-card-image-theme class carries an unlayered height token
(200px under Journal) that overrides the Tailwind size, stretching the
square thumbnail; the radius token is applied directly instead. Hiding
below sm moves to the Link wrapper so the zero-width flex item stops
costing the row's gap on exactly the screens it was hidden for.
@feruzm
feruzm merged commit fc00443 into develop Aug 12, 2026
9 checks passed
@feruzm
feruzm deleted the feature/journal-entry-thumbnails branch August 12, 2026 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant