Conversation
The /about/paper page was crashing because Book is in content_type_names[:all] (used in the paper.html.erb view loop) but routes are generated from content_types[:all], which doesn't include Book. Added a standalone route and controller action for Book, similar to how Timeline is handled. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace loop of ~33 individual MAX(id) queries with a single UNION ALL query that fetches all max IDs in one database roundtrip. Also exclude Books from the Community Contribution Breakdown since they are just collections of Documents (avoiding double-counting). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The attribute_categories method was eager loading ALL attribute values for ALL entities belonging to a user. For a user with many entities, this caused queries taking 2+ seconds. ContentSerializer already fetches attribute values separately with a scoped query (Attribute.where(entity_id: content.id)), so the eager-loaded values were never used. Changed eager_load(attribute_fields: :attribute_values) to eager_load(:attribute_fields) to keep field loading but eliminate the expensive values query. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tooltip-bottom class and data-tooltip attributes to the Card View and List View toggle buttons so users can see what each icon does. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Transform circular notification bell and user avatar buttons into book-shaped (3:4 aspect ratio) buttons to match the notebook theme. Also increase search bar height and standardize borders across all navbar elements for visual consistency. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add eager loading for timeline_events and precompute statistics in the controller instead of computing them inline in the view. This reduces queries from ~2N+1 to 2-3 for pages with N timelines. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Completely redesign /worldbuilding/books with 13 sections showcasing the full power of the Books feature: analytics, writing goals, worldbuilding integration, document analysis, status workflow, and more. Add "Complete Your Writing Toolkit" cross-sell section to both Books and Timeline pages, displaying Timelines -> Documents -> Books with equal-height cards and "You are here" indicator. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use chartjs-plugin-annotation to draw a dashed line at the daily goal threshold instead of rendering goals as columns. This fixes the issue where Chartkick rendered both datasets as columns despite the mixed chart type configuration. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new marketing/information page at /worldbuilding/documents to showcase the Documents feature, following the pattern used for Books and Timelines. The page includes sections for: - Hero with "Capture Ideas. Craft Stories." tagline - Value proposition highlighting connected writing - Core features (folder organization, status workflow, free tier) - Writing environment features (autosave, word count, streaks) - 8-step status workflow visualization - Worldbuilding integration for linking characters/locations/items - AI-powered document analysis (premium feature) - Revision history and export options - Additional features (universe focus, collaboration, dark mode, privacy) - Platform stats and trust messaging - Related writing tools navigation (Books, Documents, Timelines) - Content type icon grid Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use lightweight StringScanner-based counter for documents over 300KB to avoid ~28MB peak memory from WordCountAnalyzer gem's string transformations. Jobs now use count_with_fallback for reliability. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reorganize the 13 event types into story structure phases (Beginning, Rising Action, Climax & Turning Points, Resolution) with visual section dividers. Add improved card design with left border accents, circular icon containers, and hover effects. Highlight the Climax card with a gradient background. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change Timelines and Documents links in the "Complete Your Writing Toolkit" section to point to worldbuilding marketing pages instead of the app pages. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduces database queries per dashboard load from ~770 to ~15-20 by: - Adding composite index on (user_id, for_date) for word_count_updates - Replacing find_by loops with bulk queries using sanitize_sql_array - Adding batch_words_written_on_dates for efficient multi-date lookups - Adding dates_with_writing_activity for streak calculation - Refactoring MainController to use batch methods instead of per-date calls Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The navbar search bar and icons extended too close to the edge when pages have right sidebars. Increased right padding from pr-2 to pr-4 lg:pr-6 for better visual alignment with content below. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…page - Add manual route for Timeline (not in content_types[:all]) alongside Books and Documents - Add Writing Tools section to help center with links to Timelines, Documents, and Books guides Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Books, Documents, and Timelines are writing tools rather than worldbuilding content types, so they now live under /writing/ instead of /worldbuilding/: - /writing/books - /writing/documents - /writing/timelines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add hero section with notebook-blue background, help icon, and welcoming headline - Add meta description for SEO - Remove back arrow header (not useful for SEO visitors) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…-width Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add three new help guides addressing gaps identified in audit: - Managing Your Account: profile, security, notifications, billing - Your Data: Data Vault, export formats, recycle bin, archives, storage - Troubleshooting & FAQ: common issues for universes, content, collaboration Add Quick Links section to Help Center index linking to Data Vault, Billing FAQ, Privacy Policy, Forums, and Referrals. Redesign Billing FAQ page from Materialize to Tailwind CSS with collapsible details elements and consistent styling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the timelines user route definition earlier in routes.rb to ensure the route helper is available before Thredded engine mounts and captures the main_app helpers. This fixes a timing issue where the route helper could be missing during boot. Also add defensive error handling in the badge partial to gracefully skip the favorite link if the route helper is unavailable. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Increases panel width from w-80 (320px) to w-96 (384px) on lg screens and w-112 (448px) on xl screens for better readability. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update book ordering queries to use :name instead of :title since the books table column was renamed in migration 20260111091916. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded inline styles with Tailwind classes that include dark mode variants. The link text was dark gray on a dark background, making it nearly invisible. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The timeline page now shows the sum of the timeline's own word count plus all its events' word counts, giving a more accurate representation of the total content. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When editing a link field's display style in the Appearance tab, the linkable_types from the General tab were being lost because the form only submitted the display_style field, causing the JSON field_options column to be fully replaced. Add hidden fields to preserve linkable_types when updating appearance. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pinning or unpinning an image now updates the content's updated_at timestamp, causing the page to appear in "recently edited" views. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract pagination into a reusable partial and render it both above and below the content grid for easier navigation on pages with 50+ items. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ethod-3uvyhf Fix subscription history invoice display and plan name handling
The billing row in the Tailwind navbar's account dropdown emitted a hardcoded "PREMIUM" badge for every logged-in user, so users on the free plan (selected_billing_plan_id = 1) saw it too. Gate the label and its color on User#on_premium_plan?, matching the behavior of the Materialize sidenav badge, and show "STARTER" in gray for users who aren't on a premium plan. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JxqvazvvQw1MDnXVTDyhf2
…rd-user-2j1ec2 Show subscription plan status in navbar billing link
Add tabindex="-1" to the "Markdown formatting help" link so tabbing from the post content textarea goes straight to the submit button, letting users tab+enter to submit. The link stays clickable for mouse users. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgELkknCnf32kJgVqNZVxh
Archiving a field in the template editor sets attribute_fields.hidden, and the editor tells the user the field "appears in your template and content pages" while it's active. The older page views honored that (app/views/content/form/_panel.html.erb still skips hidden fields), but the Tailwind show/edit views render whatever ContentSerializer hands them, and the serializer loaded every field in a category regardless of its hidden flag. Archived fields with answers therefore reappeared on pages after the redesign, leaving deleting the field as the only way to get rid of them. Filter hidden fields out of ContentSerializer so every surface built on it -- show, edit, quick reference, changelog, the smart sidebar, and the category completion percentages -- drops them together. Answers are left untouched, so restoring a field in the template editor brings its content straight back. Name fields are kept even if hidden, since pages are built around having one and the editor never offers to archive them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7JcoLsyP2qYbBsDipRKVT
…p-x8tww5 Remove markdown help link from tab order
…ility-93t4pj Keep archived fields off content pages
…m-him8td Keep page sidebars from sliding under the site nav rail on tablet widths
…al9msk Fix document headers rendering as normal text
…-visibility-ud1jak Add comprehensive authorization tests for Book privacy
…th-yazvri Hide post actions menu for logged-out users
…riptions-p0cs3l Fix parallel Stripe subscriptions and improve subscription sync
…to tailwind-redesign
…screens-9k19e1 Fix dropdown menu alignment in content index
…ule86 Handle deleted/archived pages in smart sidebar gracefully
The field archive toggle relied on the browser's native title attribute, which renders unstyled and only after a long hover delay. Switch it to the existing CSS tooltip system (tooltip-left + data-tooltip) already used by the category card's archive and edit buttons, so it appears instantly and matches the rest of the template editor. Also stop the archive JS from writing title back onto the buttons after a toggle (which would have re-introduced the native tooltip on the category button, stacked on top of its styled one), and add an aria-label so the icon-only button keeps an accessible name now that title is gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JuwsMm7Vmw8o1sPUHR4QPT
…ebook into tailwind-redesign
Documents the current state of the content#edit gallery tab (bugs, image display contexts, cover selection) and a phased plan covering panel polish, no-reload uploads, a per-image focal point / crop editor, and a single site-wide image renderer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
…ploads Phase 1 and 2 of the gallery UX plan (docs/gallery_ux_plan.md). - Add ContentImage presenter wrapping ImageUpload and BasilCommission so views and JSON responses treat every gallery image the same way. - Add ImageUploadAuthorizer / BasilCommissionAuthorizer (via a shared ContentImageAuthorization rule) and use them for pin, sort, notes, privacy and delete, so anyone who can edit a page can manage its images. - Replace the two duplicated card branches with one _card partial: cover chip on the image, a labelled Set-as-cover button, a real circular drag handle that also works on touch, move up/down buttons, inline two-step delete, per-image privacy toggle, dimensions/size meta, notes that save only when changed, larger (600px) thumbnails, lazy loading. - Move the inline gallery script into a Stimulus gallery controller and drop the document-wide MutationObserver. - Add ImageUploadService (quota charge/refund) and a JSON POST /image_uploads endpoint; the gallery now uploads through a drop zone with per-file progress, clipboard paste and retry, and appends the rendered card without reloading. The old cocoon form remains as the no-JS fallback. - Delete credits bandwidth back to the uploader and returns the new remaining quota; the sidebar count and empty state update live. - Add cropperjs dependency for the upcoming image editor. - Tests for the presenter, service and upload/delete/privacy endpoints. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
Phases 3, 3b and 4 of docs/gallery_ux_plan.md. Framing data - Migration adds crops (JSON, normalised rectangles per shape), focal_x/y, width/height and crops_generated_at to image_uploads and basil_commissions. - ImagePresets defines the three display shapes used across the site: banner 3:1 (1500x500), card 3:2 (900x600), square 1:1 (600x600). - HasImageFraming (both models) validates crops against the preset ratio, computes the automatic crop around the focal point, and exposes the CSS object-position fallback. ImageUpload captures oriented pixel dimensions on upload. Editor - Cropper.js based modal on the gallery tab (image_editor_controller.js): shape tabs with auto/custom state, ratio-locked crop box with pan and zoom, rule-of-thirds grid, focal point mode, live previews rendered in the real hero/card/thumbnail chrome, notes and privacy, cover toggle, keyboard shortcuts, #gallery/<image> deep links. The modal lives on <body> so the transformed page layout cannot clip it. - PATCH endpoints for uploads and Basil images accept crops, focal point, notes and privacy. Derivatives - Paperclip cropper processor cuts banner/card/square styles from the stored rectangle (or the focal-point auto crop) before resizing. - ImageDerivativeService regenerates upload styles (keeping the stored filename so the original is never orphaned) and builds cropped ActiveStorage variants for Basil images. GenerateImageCropsJob runs after framing changes; rake gallery:backfill_* tasks cover old uploads. Rendering - HasImageUploads#cover_image picks the pinned image (else first/random) as a ContentImage; content_image_tag(content, :card) serves the preset derivative, or the largest general size with the focal point as object-position until derivatives exist, or the type placeholder. - Hero header, content cards, card index, context sidenav, square thumbs, Open Graph tags and the remaining common call sites use the helper. The hero keeps a 3:1 shape from the md breakpoint (aspect-banner). Also: sequential client-side uploads, quota charge and store in one transaction, Paperclip test files isolated under tmp/, tests for framing, derivatives, helper and endpoints. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
…ghtbox, mobile uploads, a11y, N+1 and legacy cleanup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
Round two, steps 1 to 3 of docs/gallery_ux_plan.md section 7. - cover_for on both image tables: an image can be the cover for specific shapes (banner, card, thumbnail, link preview) while the pin stays the default; ContentCoverService keeps one holder per shape per page and toggle_image_pin accepts an optional preset param. - Card and editor get a split cover button with a per-shape menu, chips on the image, and "Used now" labels under each editor preview. - New social preset (40:21, 1200x630) with its own style, editor tab and link-card preview; Open Graph / Twitter tags use it with summary_large_image and explicit dimensions (content_social_meta). - Shape derivatives are now WebP (quality 82, stripped), with reduced banner_sm (750x250) and square_sm (200x200) sizes and a 1600px xlarge WebP for the lightbox and editor. Basil variants request WebP too. - content_image_tag emits width/height, decoding=async, a banner srcset with sizes, and a size: :small option used on the tiny thumbnail boxes. - S3 objects get a one-year Cache-Control in production; the backfill task now also produces xlarge for existing uploads. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
- content/show/_gallery_content renders through ContentImage.gallery_for (same order and privacy rules as the editor), serves the large derivative in the grid with the focal point, shows notes as captions and the cover chip, and no longer uses inline onclick handlers. - New lightbox Stimulus controller: keyboard (arrows, Home/End, Esc), swipe on touch, focus trap and return, "3 of 8" counter, captions, open-original link and, for editors, an "Edit framing" deep link. Shows the 1600px WebP instead of the original. - Old global modal functions and the gallery CSS block removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
- ImageUploadService converts HEIC/HEIF uploads (iPhone photos) to JPEG with ImageMagick before storing, so every derivative and the editor work in any browser. - The drop zone accepts .heic/.heif, adds a "Take a photo" button on touch devices (capture=environment), and an off-by-default "Shrink large photos before uploading" toggle (remembered per browser) that resizes JPEG/PNG/ WebP photos over 2500px in the browser and reports the saving per file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
- Editor: focus trap, roving tabindex with arrow-key navigation between shape tabs, initial focus on the active tab, a live region announcing shape and framing changes, a keyboard shortcuts sheet (?), a focusable focal point, and contrast fixes on the auto/custom chip and help text. - Gallery cards: privacy button carries its state in aria-label and aria-pressed; toasts announce with role=status. - Cropper handles grow to 20px on touch devices; transitions respect prefers-reduced-motion. - Lightbox events are bound by hand so they survive moving the dialog to <body> (arrow keys and buttons now work), and the show page is audited. Verified with axe-core (wcag2a/aa, wcag21aa, best-practice) on the gallery tab, the open editor and the lightbox in both light and dark mode: zero violations; keyboard traversal stays inside the dialogs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
Round two, steps 7 and 8. N+1 cleanup - ApplicationController#preload_cover_images loads image_uploads and basil_commissions (with blobs) for a whole list in a fixed number of queries, resetting stale associations first. Generic ContentPage rows from User#content (the dashboard, content index, Basil index, recent content) now carry the same cover API through page_type + id and a bulk preload path. - The hand-built image pool caches in the content, users and browse controllers are gone; their views render through content_image_tag. - Added a request test asserting a flat image query count on the character index and the dashboard. Retired paths - Every remaining caller of random_image_including_private, first_public_image, pinned_or_random_image_including_private, custom_thumbnail_url, custom_public_thumbnail_url, get_preview_image and combine_and_sort_gallery_images now uses cover_image / cover_image_url / content_image_tag (about 50 call sites, including RSS, which keeps the legacy JPEG sizes for feed readers). - HasImageUploads is reduced to cover_image, cover_image?, cover_image_url, clear_cover_image_cache and header_asset_for; ContentPage's duplicate overrides and ApplicationHelper's gallery helpers are deleted. PageCollection's own header image is header_image_url. - Dead partials (content/_form, content/form/_panel and gallery, form/images/_gallery and _edit_list, field_types/_migration_link, content/list/_cards, display/_image_card_header) and the old image_uploads.js are removed, along with their tests. - A lint test fails the build if any retired helper name reappears under app/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZJAZpUXf5my4TEFX7NqBA
Lists the characters connected to a book underneath Book Details, using the characters that document analysis linked to the book's chapters and falling back to the book's universe roster when no chapters have been analyzed yet. Each entry links to the character page and shows its thumbnail (or the Character icon) plus its role. The list is capped at twelve entries with a "+N more" summary, and every character is run through can_read? so private pages never leak onto a publicly viewable book. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pi5eSNA1PW88BGQMRGJM7E
The timeline editor positions its desktop Search / Filter panel and its pull-out tabs next to the site navigation rail by reading site_navigation_sidebar_visible from localStorage itself, treating a missing value as "collapsed" (64px). The rail, owned by the layout, treats a missing value as "open" (224px). For anyone who has never toggled the rail, the two disagree: the rail (z-50) paints over the panel (z-30), hiding the tag checkboxes and the toggle tab, so clicking where the tag checkbox sits lands on the rail and nothing happens. Derive siteNavExpanded from the layout's own showSidebar state (the editor is nested inside the body's x-data), falling back to the same "open unless explicitly collapsed" rule when that scope is absent. The value is now live, so the storage listener and the 100ms localStorage poll that kept a copy in sync are gone. Verified in a browser at 1400px: with no stored preference the panel now opens at 224px beside the expanded rail, the Foreshadowing checkbox is clickable and filters 3 events down to 1, and collapsing/expanding the rail moves the panel and tabs immediately. Tablet (800px) and phone (400px) paths were already correct and still pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GbxTemBuHWrTzh7xQQJExW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The /about/paper page was crashing because Book is in content_type_names[:all]
(used in the paper.html.erb view loop) but routes are generated from
content_types[:all], which doesn't include Book. Added a standalone route
and controller action for Book, similar to how Timeline is handled.
Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com