ref https://github.com/TryGhost/Ghost/pull/21788#discussion_r1869802093
- Introduced `setCommentsIsLoading` action to handle the loading state
of comments dynamically.
- Updated `setOrder` function to dispatch the `setCommentsIsLoading`
action, ensuring proper UI feedback during asynchronous operations.
ref https://linear.app/ghost/issue/AP-625/implement-notification-grouping-for-follows-and-likes
- Improved handling for notification clicks of various types: single follower notification opens that follower in the drawer, multiple followers expands the followers list, liked post opens the article in the wide drawer, liked note opens the note in the narrow drawer
- Improved hover and click states for profile names, usernames and avatars. Now it's more obvious what's clickable, and clicking on any of these elements in any context opens that profile in the drawer.
- Created a handleProfileClick utility since we're using it in a lot of places.
- Removed unnecessary types
- Made the HTML structure more semantic
ref https://linear.app/ghost/issue/AP-625/implement-notification-grouping-for-follows-and-likes
- Added basic frontend grouping for Follow and Like notifications, so the page is easier to scan through. For each loaded batch of notifications we check if they can be grouped (all follows get grouped, all likes for a certain post get grouped) and then merge those grouped pages of notifications.
- Improved UI for notifications, with notification type icons for each group.
- Added a utility for truncating text.
closes https://linear.app/ghost/issue/PLG-294
- making the `replied to: [removed]` text a link was a bit confusing because clicking it does nothing
- if the replied-to comment doesn't exist (e.g. hidden/deleted and not returned in API response) or has been unpublished we replace the `<a>` with a `<span>` to remove the link behaviour
no issue
- keeps logic inside `<CommentHeader>` single-purpose
- allows for cleaner code when adding logic to remove the link when the replied-to comment is removed
- switched `queryByText` to `getByText` in the test to make debugging easier, the latter will print the current DOM if it fails to find an element
# Conflicts:
# apps/comments-ui/src/components/content/Comment.tsx
REF https://linear.app/ghost/issue/PLG-284
When clicking on a replied-to reference, you scroll up to the parent comment. To guide the eye, the parent comment is highlighted with a yellow background.
- added `dispatchAction` to the `ActionHandler` function call arguments, allowing actions to call other actions
- added `commentIdToHighlight` app context state and associated `highlightComment` action to set it
- updated `Comment` (and related sub-components) to match `commentIdToHighlight` when rendering to determine whether to apply highlighting of comment contents
- for the highlight, `<mark>` is used to wrap any paragraphs inside the comment contents and appropriate tailwind highlight animation classes applied
- uses the inline `<mark>` element so that background highlight only applies to the text bounding boxes rather than the entire wrapping element
---------
Co-authored-by: Ronald Langeveld <hi@ronaldlangeveld.com>
ref [DES-949](https://linear.app/tryghost/issue/DES-949/177e604501
This adds custom fonts feature allowing users to select heading and body
fonts for their themes from a curated list. This allows publishers to
have more control over their brand, and allows themes to have a wider
range of styles to appeal to different audiences.
Without custom fonts support, themes will continue to work as normal,
but users won't be able to customize their typography. As for the
official themes, all of them will support custom fonts.
ref DES-1011
- previously, we were hiding the old font settings from the official themes without checking if they support the custom fonts or not
- now we use the gscan warning info to check this — only when there's support, we hide the settings which means users with the older version will get the old settings back
- also added two new tests for this procedure
PLG-280
- Added a loading state implementation when changing the ordering of
comments.
- This improves the overall UX particularly with slower connections.
- Due to the nature of how comments and ordering are handled, we
approached it with a simple state that determines whether it's done
loading or not around the API query.
---------
Co-authored-by: Sanne de Vries <sannedv@protonmail.com>
ref https://linear.app/ghost/issue/AP-622/add-support-for-rich-text-formatting-of-notes
- Until now we only had plain text with line breaks and links inside `note` objects. But WordPress is very flexible and allows users to put almost all of their blocks inside a `note`, like headings, lists and blockquotes. We now support those in Ghost, but with minimal formatting to keep the feed clean and easy to scan through.
no issue
- bumped minor to delay comments-ui update until next Ghost release
- includes numerous styling fixes, display of replies when editing a comment, and updates to in-reply-to snippets when deleting/hiding comments
closes https://linear.app/ghost/issue/PLG-263/
When hiding a reply as an Admin, if there were other replies that referenced it then those snippets would still show the hidden content because there was no immediate update in the comments-ui client. This made it look like hidden content would still be visible even though at the API level snippets were entirely removed so no other user would see it.
- added client-side handling so in-reply-to snippets immediately show `[hidden/removed]` which means we don't have to fetch every reply from the API
- updated the API to use `[hidden/removed]` as the snippet when referencing a hidden reply instead of removing all `in_reply_to_` data
- keeping `in_reply_to_id` and `in_reply_to_snippet` means comments-ui still displays the replied-to reference text (albeit not directly showing the API-supplied string so `[hidden/removed]` can be translated)
- returns the full `in_reply_to_snippet` text for Admin API requests so that showing a comment that has been loaded from the API can immediately show the contents for any displayed references to the comment
REF https://linear.app/ghost/issue/PLG-274/
- Currently, replies are hidden when the parent comment is being edited. This PR ensures that replies remain visible when the parent comment is being edited.
- To achieve this, the `CommentComponent` now checks if the parent comment is being edited. If so, the comment content is swapped by the EditForm, while the comment's avatar, header, menu, and replies remain visible.
- The Form component now only renders the FormEditor. A FormWrapper component is used to wrap the avatar and comment header.
- This Form component is used in the EditForm without the FormWrapper, as it is already wrapped in the CommentComponent.
- The ReplyForm and the MainForm use the FormWrapper.
- The Avatar component now also accepts a `member` prop, which is used to display the avatar image. This is because it's no longer used inside the Form component.
ref https://linear.app/ghost/issue/AP-613/make-drawer-wider-when-displaying-articles-on-larger-screens
- Added a prop to Modal which allows you to interact with the page
behind the Modal, so the main navigation could still be used while the
Article modal is opened
- Removed the breakpoint we only use in one place, and switched to using
an arbitrary Tailwind breakpoint that matches the one in admin instead
closes
https://linear.app/ghost/issue/ENG-1807/further-deprecate-amp-by-removing-the-ui
- AMP has been deprecated for a year, and will be removed in Ghost 6.0
- As the next step towards removing it, we're removing the UI, meaning
new sites can't enable it
- This will hopefully help the transition to dropping it be smoother and
especially prevent newer users from spending a lot of time on AMP in the
run up to it going away
- NOTE: this only removes the UI. All the logic remains, you can still enable AMP via the API/settings table in the DB.
refs
[AP-614](https://linear.app/ghost/issue/AP-614/investigate-client-loading-issues)
Refactored data loading to be more performant in admin-x-activitypub:
- Utilised tanstack query for suggested profiles instead of rolling our
own custom hook. This allows us to utilise tanstack for caching
- Refactored how data is loaded for the Inbox / Feed view - Queries are
no longer cleared when switching between the 2 layouts
- Refactored how activity data is key'd to make caching more
deterministic as well as allow mutating a specific activity cache (i.e
when adding a note, ensure it only gets added the the feed activities)
- Removed redundant `excludeNonFollowers` parameter - This is no longer
used by the API
Just a bunch of minor refactorings in admin-x-activitypub:
- Reorganised api methods
- Reorganised api query hooks
- Reorganised api tests
- Removed redundant `getActor` api method
- Colocate `Search` type with component
- Moved `ViewProfileModal` to `modals`
- Refactored profile
- Remove redundant `useFollowersForUser`
- Remove redundant `useBrowseInboxForUser`
- Removed redundant acceptance tests
ref https://linear.app/ghost/issue/AP-613/make-drawer-wider-when-displaying-articles-on-larger-screens
- The drawer view for viewing Articles was only slightly wider than the
one for viewing Posts. Since we've decided to make a bigger separation
between these 2 types of post, we wanted to make the drawer almost full
width (excluding the main navigation sidebar).
- This also removes the backdrop from drawer view so the interaction
would be lighter.
- To achieve this we're adding another CSS breakpoint so it would match
the one used in Admin. We didn’t have one since our DS was mostly used
in isolation in Settings.
close https://linear.app/ghost/issue/AP-574/clean-up-iframe-css
- When we began working on ActivityPub integration, we reused the styles from our default Source theme and added default Ghost card styles. This meant we could quickly have nice-looking posts in the admin, but also meant we have some unnecessary lines of CSS. This is now cleane up, resulting in a ~40% smaller file.
fix https://linear.app/ghost/issue/ENG-1804/remove-lexicalmultiplayer-code
- this experiment never went anywhere and we'll probably change our plan
in the future, so this commit cleans up all the relevant code in this
repo for the feature, in order to cut down on the code we have
ref https://linear.app/ghost/issue/AP-609/give-inbox-ui-more-room-to-breathe
- Posts in the inbox view used the same font colors and sizes for
elements of different importance. Now the contrast and hierarchy of
elements is improved which makes it easier to browse the posts.
- Larger border radius on hover better fits the size of posts.
fixes
https://linear.app/ghost/issue/DES-953/newsletter-unsubscribe-modal-is-unclear-leading-to-repeated
Previously, when clicking 'Unsubscribe' in an email, landing on this
modal it was unclear what had just happened if you didn't read the text
below the title, causing people to click the toggles repeatedly.
We've now added a toast notification to make it clear what has just happened,
and if you click the toggles, the notification also shows.
Ideally, we'd be able to stack these notifications in case you hit
multiple toggles in quick succession, but that's going to be a separate
issue, as—to achieve that—it needs to be rewritten more significantly.
---------
Co-authored-by: Sodbileg Gansukh <sodbileg.gansukh@gmail.com>
ref https://ghost.slack.com/archives/C02G9E68C/p1732783603483239
- Need to create a patch release, however this test is suddenly failing.
- Fails at const fileChooserPromise = page.waitForEvent('filechooser');
- reason is not clear, however, cannot reproduce.
no issue
- `MockedApi.browseComments` only worked on top-level comments, it couldn't find replies when passed `filter:'id:123'` such is used when liking and editing replies
- fixed missing get handler for fetching single comment via Admin API (used after showing a hidden comment)
- added `flattenComments` and `findCommentById` helper functions to facilitate easier finding of a comment or reply within the nested structure
- added tests for liking and hiding replies
no issue
- expanded e2e test behaviour to route Admin requests through our MockedApi instance so we have the same test experience for normal and admin comments requests
- extracted page route method bodies to enable request methods to be spied on
- updated admin moderation tests to properly use admin requests
ref PLG-270
- Updated the getCommentByID service to filter out hidden and deleted
replies.
- Ensured all replies are loaded before applying the filter.
- Simplified logic to handle non-paginated routes by directly removing
unwanted replies.
- Wired up new Admin Endpoint that shows hidden replies but not deleted
replies.
- Updated comments-ui client
- Added unit tests for mocking apiClient event listeners.
- added eventlistener playwright tests to ensure it fires on UI clicks.
no issue
- repeated use of the same init data made tests longer than they needed to be, especially as the number of tests grows
- added `initializeTest()` function to remove unnecessary duplication
ref PLG-270
- Updated the getCommentByID service to filter out hidden and deleted
replies.
- Ensured all replies are loaded before applying the filter.
- Simplified logic to handle non-paginated routes by directly removing
unwanted replies.
- Wired up new Admin Endpoint that shows hidden replies but not deleted
replies.
- Updated comments-ui client.
ref https://linear.app/ghost/issue/ONC-613/
A little while back we changed to requiring a key when interacting with
member endpoints that are not authenticated. One request code path in
Portal was missed, causing some requests to fail. This should patch that
hole.
closes#21439
On Windows 10/Chrome (but maybe nowhere else?), attempting to drag a
file into any of the drop targets in the admin panel resulted in
flickering behavior, and generally dropping didn't actually trigger the
upload.
I thought originally it was a problem with the size of the drop target,
but it actually appears to be a rerender bug. In brief, handleDragging
and handleStopDragging were firing repeatedly, and each fire triggered a
rerender, that added or removed a div from the file upload widget.
I suspect some browser-specific difference in how drag events fire is to
blame.
This PR moves the logic to change the classes applied to the div, rather
than changing whether the div is present.
I have manually tested with Windows 10 in the users import, theme
import, and content import widgets. Styles are preserved (although I
think they could be improved, as the grey outline is really faint) and
uploading now works consistently, instead of mostly triggering display
of the raw file most of the time.
closes https://linear.app/ghost/issue/PLG-266
- the reply form is a child of the parent comment component but we have different comment components for published vs unpublished with the bug coming from the latter missing the logic to display the form
- added missing form display and added a regression test
closes https://linear.app/ghost/issue/PLG-265
- wrapped the async part of `dispatchAction` in a Promise so code that calls it can await the action completion
- this was a regression introduced a long time ago when we switched to Typescript and React hooks
- added a `setDelay()` method to our `MockedApi` class to make it easier to test interstitial loading states
ref PLG-227
- Updated logic that allows Admin Users on comments to interact with
some endpoints from a specific admin-only route.
- It pulls 2 admin specific routes:
- 1. an admin specific 'browse' route that includes hidden comments that
would otherwise be hidden from regular users and members.
- 2. A specific replies route, that would also include hidden comments
- This was needed in order to get accurate pagination.
- Additionally, it wires up the routes via `message-handler` that deal
with the potential cors issues.
- Includes style updates
---------
Co-authored-by: Sanne de Vries <sannedv@protonmail.com>
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
ref DES-982
- we're hiding font-related theme settings from official themes to make room for the new custom font settings
- this adds author name as an additional check on top of the existing ones (theme name and corresponding setting keys)
ref https://linear.app/ghost/issue/PLG-235
- Any comments older than yesterday are now shown with the date instead of relative time
- Comments from the current year are now shown with just the month and day
---------
Co-authored-by: Kevin Ansfield <kevin@ghost.org>
refs
[AP-606](https://linear.app/ghost/issue/AP-606/suggested-accounts-not-rendering-due-to-404)
Some of the suggested accounts in `admin-x-activitypub` were not
rendering due to the requests for the data returning a 404. This was due
to incorrect account handles being used. This commit fixes the issue by
ensuring the correct handles are being used. This commit also adds a new
hook to handle the fetching of suggested accounts that also limits and
randomizes the accounts returned.
ref https://linear.app/ghost/issue/PLG-230
When clicking "Reply" on a reply we now show an "In reply to" reference on the form and when saved show that reference in the rendered view, making it easier to follow discussions within comment replies.
- updated calls to `openCommentForm` action when opening a reply to add the in-reply-to data to the `openForm` instance
- updated Form comment to use the `openForm` instance data when rendering the in-reply-to reference
- updated Comment component to render the in-reply-to reference from the API-provided data
- includes click handler to scroll to the referenced comment
- added `getCommentInReplyToSnippet` helper function so strip a comment back to plaintext for display in the reply-to reference on the comment form (snippets on other comments are generated server-side)
---------
Co-authored-by: Sanne de Vries <sannedv@protonmail.com>
closes https://linear.app/ghost/issue/PLG-260
ref https://github.com/TryGhost/Ghost/pull/21621
- in a recent refactor, a `comment` prop started being passed through to `<Form>` inside of `<ReplyForm>` which had an unexpected side-effect of changing the avatar image to the comment's member instead of the logged-in member
- removed the prop passthrough and updated test to catch future regressios
ref https://linear.app/ghost/issue/PLG-230
closes https://linear.app/ghost/issue/PLG-256
Adding an in-reply-to reference link/snippet to reply forms was proving difficult with the previous setup due the amount of data that needed to be passed up and down a deeply nested component tree. This refactor lays the groundwork for making that easier and aims to make form autoclose behaviour more centralised by keeping the open form state in app context and the opening/closing of forms in actions so there's less need for messy local state and to drill functions down the component tree.
- replaces `openFormCount` context state with an `openCommentForms` array
- keeping detailed open form references in the application state means the display of forms is centrally managed rather than managed via local state inside components
- it simplifies some of the problems faced with the `<PublishedComment>` component that previously managed form display. That component is re-used for both the top-level comment as well as replies even though replying on a reply puts the top-level comment into reply mode meaning we had a mess of local state and passed-through functions to work around the component having varying behaviour depending on nesting level
- `openFormCount` is still available on the application state via `useMemo` on the provider meaning the implementation of `openCommentForms` is hidden from app code that just needs to know if forms are open
- removes `<AutocloseForm>` as the autoclose behaviour is now controlled via the `openCommentForm` action
- updated `<Form>` so it manages the "has unsaved changes" properties on `openFormComments` ready for use by `openCommentForm`'s autoclosing behaviour
close
https://linear.app/ghost/issue/AP-528/remove-unnecessary-separator-after-last-list-items
- Previously, in some components, we relied on CSS and all elements in
the list being the same type of an HTML element to show the separator.
Now, we've extracted the separator into its own component and place
after all items during mapping except the last one.
no issue
- running tests locally, especially in UI mode, would often result in an avatar saturation test failing
- the cause was calculating saturation for an element that still had it's opacity animating in
- added a test util function that waits for an element in a frame to reach full opacity
- used function in test to ensure we have a stable element before calculating the color saturation
ref https://linear.app/ghost/issue/AP-585
If preferredUsername is not a string, and we attempt to render it, we
will crash the entire React application!