ref https://linear.app/ghost/issue/ENG-1235
- problem: today, when a publisher removes the "free" tier from the
Portal settings, it doesn't disable free signups entirely. It removes
the free tier from the Portal UI, but free signup is still possible via
other avenues (signup form in themes, embeddable signup form on another
site, direct API call). This creates confusion/frustration for
publishers who thought they disabled free signups, but are still getting
unwanted free signups (spam). There is no way to disable free signups
entirely.
- solution: introduced a new "paid-members only" subscription access
setting, which blocks all free signups at the API level. If chosen, the
free tier is hidden in Portal and all free signup are blocked at the API
level with a readable error message (`This site only accepts paid
members.`)
![CleanShot 2024-12-10 at 09 09
28@2x](https://github.com/user-attachments/assets/c71b38b4-0d23-429c-a743-00772e82c787)
ref bb9a69e
ref https://linear.app/ghost/issue/ENG-1753/labs-flags-cleanup
- We promoted i18n to GA several weeks ago now, and it's going fine
- Removing the UI first to reduce confusion before cleaning up all the other references to the flag
- Also changed the i18n test to set the language back at the end of the test, to ensure no conflicts
closes https://linear.app/ghost/issue/PLG-300
- we're not planning on making any more comments improvements behind this flag so it can be removed
- all conditionals using it have been cleaned up previously when feature went GA
refs
[AP-627](https://linear.app/ghost/issue/AP-627/sanitising-note-content)
Adding client side filtering of the notifications in
`admin-x-activitypub` - This is a stop-gap until we have a dedicated
endpoint for returning notifications. Filtering includes:
- Do not show our own likes
- Only show `like` notifications when it is on our own posts
- Only show replies to our own posts
ref https://linear.app/ghost/issue/DES-1021/create-posts-app
Part of establishing React patterns in Ghost is to build a well-defined
and fairly self-encapsulated app through which we can test assumptions
and define best practices. Our guinea pig is Post analytics for this
purpose. This PR creates a new React app (posts) using Shade (the new
design system).
ref
bb9a69edfe
- We promoted i18n to GA several weeks ago now, and it's going fine
- Removing the UI first to reduce confusion
- This is before clearning up all the other references to the flag
no issue
This reverts commit 040b290fbd.
- the commit has broken browser tests, reverting to get back in a green state
- will be re-introduced in a follow-up PR
refs
[AP-629](https://linear.app/ghost/issue/AP-629/notes-say-they-error-but-post-correctly)
Fixed intermittent error when posting a note in `admin-x-activitypub`
The error was intermittent due to it only occurring when a specific set
of steps occurred, and the query cache being periodically cleared.
The error itself was due to incorrectly expecting the `outbox:${handle}`
query to be an array when it was in fact an object.
This PR also resolves and issue where the reply count for new notes
would display `NaN` (because the `replyCount` property was not present
on newly created notes)
closes https://linear.app/ghost/issue/DES-548/update-portal-notification-style
Portal popup notification styles look outdated and harsh. Also in-popup notifications have several visual design issues such as positioning, alignment, typography and so on. This PR fixes these issues by applying a much more standard design to Portal notifications.
ref ENG-745
- added permission related errors to list of error types to be handled
- previously, generic error messages were displayed when permission
errors are thrown
- this would make it possible to display the actual message returned
from the API in toasts
ref DES-898
- previously, the name field in Portal account settings used to be required which caused an issue users were not able to update their email address without adding name first
- now the name field is optional makes it possible to update the email address without adding name, or remove their name as well
- it was intended not to wire this up to "Display name in signup form" setting in Portal for the simplicity
ref DES-547
- when Portal popup is opened and the browser scroll bar is visible, it
used to make layout shift, because we were hiding the scrollbar
- now it applies right margin to body element and the trigger button by
calculating the scrollbar width only when the browser scroll bar is
visible
- it also preservers the current right margin for those elements and
makes the calculation based on that
ref DES-933
- when three dot buttons are clicked in the theme management modal, the
menu alignment was wrong
- this fixes the issue by aligning the button and the menu by the right
edge
ref ONC-225
- Ensures newsletter preferences are hidden in the Portal when email functionality is disabled.
- Adds conditional logic in NewsletterManagement.js to check for the hasNewslettersEnabled prop.
- Updates tests in AccountEmailPage.test.js and AccountHomePage.test.js to cover scenarios where newsletters are disabled.
- Improves user experience by preventing the display of irrelevant settings when email is turned off.
ref https://linear.app/ghost/issue/AP-633/reader-view-customization-options, https://linear.app/ghost/issue/AP-631/estimated-reading-time-in-reader-view
- Improved typography, spacing and alignment.
- Improved selection of font sizes from the reader view customization popover.
- Added a button to reset reader view customization settings to default, in case user ends up in a state they’re not happy with and want to go back to a sensible default.
- Added preview to typeface selection component so it’s easier to see what you’re selecting.
- Disabled background clicks on all AP modals for a more consistent experience and to avoid accidental clicks.
- Changed the reading progress indicator increments from 1 to 5 to attract less attention while the user is reading.
no issue
- contains two edge-case bug fixes, one related to pagination when deleting a comment and another that works around issues arising from potentially unstable API sorting
closes https://linear.app/ghost/issue/PLG-305
- adds deduplication of comments when fetching top-level pages
- avoids problems where the underlying sort is unstable (e.g. "best" as likes are changing) resulting in an already loaded comment appearing on a later-loaded page
- doesn't solve for missing comments between pages but does prevent invalid local state that can lead to buggy UI
closes https://linear.app/ghost/issue/PLG-304
- added a refresh of the comments list when a top-level comment with no replies is deleted so the pagination resets and replies aren't missed when loading more due to a shift in the underlying paginated data
no issue
- contains two minor bug fixes for edit name/expertise buttons on the main form and incorrect replies-left-to-load counts after deleting replies
closes https://linear.app/ghost/issue/PLG-303
- when deleting a reply our "replies left" calculation was getting out of sync because the `count.replies` state on the parent comment wasn't being updated, the result was for each comment deleted we were displaying 1 more reply that was still to load
- updated the `deleteComment` action to also modify the parent comment's `count.replies` value when a reply was deleted ensuring our "replies left" calculation remains correct
closes https://linear.app/ghost/issue/PLG-302
- switching from `onClick` to `onMouseDown` allows the button events to fire and be picked up by the popup-opening handler before the click causes a blur event on the main form to fire which removes the expertise buttons
- we have a test for adding expertise via the main form which was giving us a false positive due to the way Playwright handles events, unfortunately I couldn't find a way to adjust that to match the real-world behaviour without ending up with a test that always fails
ref https://linear.app/ghost/issue/DES-1033/icon-implementation
The Storybook structure contained Lucide icons under "Components", but
it's an experimental component. This commit creates an Experimental
component group in Shade and updates the corresponding docs.
closes https://linear.app/ghost/issue/DES-1033/icon-implementation
In Shade right now there's no support for icons, which is a fundamental
building block in any design system. We use Streamline Icons which
unfortunately don't have an out-of-the-box React support like e.g.
Lucide Icons. This PR adds support for custom icons to be used directly
from Shade by importing SVG's from a directory and creating React
components dynamically. It also adds a grid view of all available icons
in Storybook so it's easy to get an overview of available icons and copy
their React component.
ref
https://linear.app/ghost/issue/DES-1020/create-new-react-app-for-shade
Shade is our new design system that follows React best practices and
leverages third-party libraries extensively. It's built on ShadCN/UI
which is one of the most popular React UI libraries today. This commit
adds an (almost) empty React app, set up to be the a starting point of
Shade.
ref https://linear.app/ghost/issue/PLG-267
- updated delete comment action so it removes comments rather than just updating their status to `'deleted'`
- deleted comments that still have replies have their status updated so the replies remain visible
- matches updated API behaviour where deleted comments are not shown at all
closes https://linear.app/ghost/issue/PLG-297
- we were setting the comment count Admin API browse comments response meta pagination data which will never be correct because it only counts top-level comments for pagination purposes
- we have a public comment counts endpoint that is already fetched, there's no need to override that when using the Admin API because the overall count doesn't change across API's, even when the Admin API includes hidden comments because those don't impact the visible count
- updated test setup so the title and count is shown so it can be asserted against
- updated mocked api to correctly return count of all published comments+replies
closes https://linear.app/ghost/issue/PLG-273
- removed previous fix which only worked on last comment but not last reply
- keeping track of last comment/reply spread a lot of domain knowledge around for a UI-only concern and wouldn't scale if we have other dropdowns in the future
- added `useOutOfViewportClasses` hook
- accepts an object with top/bottom/right/left containing default and outOfViewPort classes
- applies the correct classes using the DOM rather than React so that we avoid re-renders and associated flickering or broken rendering
ref https://linear.app/ghost/issue/PLG-296/
When logged in as an Admin, comments-ui switches comment reads from the Members API over to the Admin API so that hidden comments can be displayed to allow moderation activities. However, the Admin API not using member authentication and CORS preventing the front-end members auth cookie being passed over to the Admin API domain meant that the logged-in member's likes were missing when fetching via the Admin API as there is no available reference to the logged in member.
This change works around the problem by introducing an `impersonate_member_uuid` param to the comments read/browse endpoints of the Admin API. When passed, the provided uuid is used to simulate that member being logged in so that likes are correctly shown.
- Introduced `impersonation_member_id` parameter to resolve issues with admin API not returning correct "liked" status for comments when an admin is logged in.
- Updated API endpoints in `comment-replies.js` and `comments.js` to handle `impersonation_member_id`.
- Adjusted `CommentsController` to validate and process the `impersonation_member_id` parameter before passing it to database queries.
- Enhanced test coverage to ensure proper handling of the new parameter and accurate "liked" status behavior.
REF https://linear.app/ghost/issue/PLG-298/
- When you're typing a comment, and exit the input field, it collapses into a non-editable state; you first have to click on it again to "open" the form. This means you can't select the text or instantly start typing again. When the input has a value, we should stop it from closing.
- added custom `useEditor` hook that wraps TipTap and exposes both the `editor` and `hasContent` props keeping logic out of the consuming components
---------
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>