From b1195a9aa01c6c6a9486a0f32d7f5c5e0c717a1d Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Thu, 19 Sep 2024 13:45:37 +0100 Subject: [PATCH 01/28] First set of proposed UI tweaks. --- public/assets/styles/reset.scss | 2 +- public/assets/styles/utility/display.scss | 7 + public/assets/styles/variables/_text.scss | 2 +- public/components/Header.tsx | 2 +- public/components/NotificationIndicator.tsx | 2 +- public/components/common/PoweredByFider.tsx | 2 +- public/components/layout/Stack.tsx | 2 +- .../components/AdminBasePage.tsx | 2 +- public/pages/Home/Home.page.scss | 19 +- public/pages/Home/Home.page.tsx | 6 +- public/pages/Home/components/TagsFilter.tsx | 4 +- public/pages/MySettings/MySettings.page.tsx | 2 +- public/pages/ShowPost/ShowPost.page.scss | 23 ++- public/pages/ShowPost/ShowPost.page.tsx | 173 +++++++++--------- .../ShowPost/components/DiscussionPanel.tsx | 2 +- .../pages/ShowPost/components/ShowComment.tsx | 4 +- views/base.html | 3 +- 17 files changed, 143 insertions(+), 114 deletions(-) diff --git a/public/assets/styles/reset.scss b/public/assets/styles/reset.scss index 45670f2e7..9d3b9cb2e 100644 --- a/public/assets/styles/reset.scss +++ b/public/assets/styles/reset.scss @@ -16,7 +16,7 @@ body { overflow-x: hidden; min-width: 320px; color: get("colors.gray.900"); - background-color: get("colors.white"); + background-color: get("colors.gray.100"); font-size: get("font.size.base"); font-family: $font-base; } diff --git a/public/assets/styles/utility/display.scss b/public/assets/styles/utility/display.scss index 814c5db7e..23f3cd134 100644 --- a/public/assets/styles/utility/display.scss +++ b/public/assets/styles/utility/display.scss @@ -63,6 +63,13 @@ } } +.box { + border-radius: get("border.radius.large"); + background-color: get("colors.white"); + border: 1px solid get("colors.gray.200"); + padding: spacing(4); +} + .flex { display: flex; } diff --git a/public/assets/styles/variables/_text.scss b/public/assets/styles/variables/_text.scss index f24cf6bd9..8d8ca00ef 100644 --- a/public/assets/styles/variables/_text.scss +++ b/public/assets/styles/variables/_text.scss @@ -1,4 +1,4 @@ -$font-base: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, +$font-base: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; $font-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; diff --git a/public/components/Header.tsx b/public/components/Header.tsx index b4c754677..495d01507 100644 --- a/public/components/Header.tsx +++ b/public/components/Header.tsx @@ -16,7 +16,7 @@ export const Header = () => { const hideModal = () => setIsSignInModalOpen(false) return ( -
+
diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 9a547ee44..9813db0e5 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -21,7 +21,7 @@ export const NotificationIndicator = () => { }, [fider.session.isAuthenticated]) return ( - + {unreadNotifications > 0 &&
} diff --git a/public/components/common/PoweredByFider.tsx b/public/components/common/PoweredByFider.tsx index ad51078f7..791b93598 100644 --- a/public/components/common/PoweredByFider.tsx +++ b/public/components/common/PoweredByFider.tsx @@ -21,7 +21,7 @@ export const PoweredByFider = (props: PoweredByFiderProps) => { return ( ) diff --git a/public/components/layout/Stack.tsx b/public/components/layout/Stack.tsx index dd70f4825..be356c4ca 100644 --- a/public/components/layout/Stack.tsx +++ b/public/components/layout/Stack.tsx @@ -12,7 +12,7 @@ interface StackProps { } const Stack = (props: StackProps, dir: "x" | "y") => { - const spacing = props.spacing === undefined ? 1 : props.spacing + const spacing = props.spacing === undefined ? 2 : props.spacing const className = classSet({ [`${props.className}`]: props.className, flex: true, diff --git a/public/pages/Administration/components/AdminBasePage.tsx b/public/pages/Administration/components/AdminBasePage.tsx index 10ad7fc55..9fb13bfd4 100644 --- a/public/pages/Administration/components/AdminBasePage.tsx +++ b/public/pages/Administration/components/AdminBasePage.tsx @@ -17,7 +17,7 @@ export const AdminPageContainer = (props: AdminPageContainerProps) => { return ( <>
-
+
diff --git a/public/pages/Home/Home.page.scss b/public/pages/Home/Home.page.scss index 46a301ca2..9fb06910a 100644 --- a/public/pages/Home/Home.page.scss +++ b/public/pages/Home/Home.page.scss @@ -14,13 +14,22 @@ .p-home { &__welcome-col { - background-color: get("colors.gray.100"); - padding: spacing(2); - border-radius: get("border.radius.medium"); + > :first-child { + background-color: get("colors.white"); + border-radius: get("border.radius.large"); + border: 1px solid get("colors.gray.200"); + + @include media("lg") { + } + } + } + + &__posts-col { + background-color: get("colors.white"); + border-radius: get("border.radius.large"); + border: 1px solid get("colors.gray.200"); @include media("lg") { - padding: 0; - background-color: transparent; } } diff --git a/public/pages/Home/Home.page.tsx b/public/pages/Home/Home.page.tsx index 834d45017..a0b1c4f7c 100644 --- a/public/pages/Home/Home.page.tsx +++ b/public/pages/Home/Home.page.tsx @@ -77,13 +77,13 @@ What can we do better? This is the place for you to vote, discuss and share idea
- + - +
-
+
{isLonely() ? ( ) : title ? ( diff --git a/public/pages/Home/components/TagsFilter.tsx b/public/pages/Home/components/TagsFilter.tsx index cee7dbb60..902f0e600 100644 --- a/public/pages/Home/components/TagsFilter.tsx +++ b/public/pages/Home/components/TagsFilter.tsx @@ -32,7 +32,9 @@ export const TagsFilter = (props: TagsFilterProps) => { return ( - with + + with + {label}
}> {props.tags.map((t) => ( diff --git a/public/pages/MySettings/MySettings.page.tsx b/public/pages/MySettings/MySettings.page.tsx index 248cc1127..ea9b959e8 100644 --- a/public/pages/MySettings/MySettings.page.tsx +++ b/public/pages/MySettings/MySettings.page.tsx @@ -112,7 +112,7 @@ export default class MySettingsPage extends React.Component
-
+
Confirm your new email diff --git a/public/pages/ShowPost/ShowPost.page.scss b/public/pages/ShowPost/ShowPost.page.scss index c2efacbf9..1a4870c1d 100644 --- a/public/pages/ShowPost/ShowPost.page.scss +++ b/public/pages/ShowPost/ShowPost.page.scss @@ -9,23 +9,30 @@ .p-show-post { display: grid; gap: spacing(4); - grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-columns: 1fr 3fr; grid-template-rows: auto; grid-template-areas: - "Header Header Header Action" - "Discussion Discussion Discussion Action"; + "Action Main" + "Action Main"; + + &__main-col { + grid-area: Main; + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + } &__header-col { - grid-area: Header; } &__action-col { + > :first-child { + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + } grid-area: Action; } - - &__discussion_col { - grid-area: Discussion; - } } } } diff --git a/public/pages/ShowPost/ShowPost.page.tsx b/public/pages/ShowPost/ShowPost.page.tsx index 8690b378d..a83fd6004 100644 --- a/public/pages/ShowPost/ShowPost.page.tsx +++ b/public/pages/ShowPost/ShowPost.page.tsx @@ -145,102 +145,105 @@ export default class ShowPostPage extends React.Component
- -
- - - +
+
+
+ + + + +
+ {this.state.editMode ? ( +
+ +
+ ) : ( +

{this.props.post.title}

+ )} -
+ + + Posted by · + + +
+ + + + Description + {this.state.editMode ? (
- + @@ -73,16 +70,11 @@ const GeneralSettingsPage = () => { placeholder="Enter your suggestion here..." onChange={setInvitation} > -

- This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback. - Leave it empty for a default message. -

+

Placeholder text in the suggestion's box. It should invite your visitors into sharing their feedback.

- -

- We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels. -

+ +

JPG, GIF or PNG smaller than 100KB, minimum size 200x200 pixels.

{!Fider.isSingleHostMode() && ( @@ -104,8 +96,7 @@ const GeneralSettingsPage = () => { ] ) : (

- Custom domains allow you to access your app via your own domain name (for example, feedback.yourcompany.com - ). + Use custom domains to access Fider via your own domain name feedback.yourcompany.com

)}
From ca8d930a93764363b4513029e197f03a3fc05b18 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 20 Sep 2024 12:51:39 +0100 Subject: [PATCH 06/28] My settings UI tweaks --- public/pages/MySettings/MySettings.page.tsx | 2 +- public/pages/MySettings/components/NotificationSettings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/pages/MySettings/MySettings.page.tsx b/public/pages/MySettings/MySettings.page.tsx index ea9b959e8..248cc1127 100644 --- a/public/pages/MySettings/MySettings.page.tsx +++ b/public/pages/MySettings/MySettings.page.tsx @@ -112,7 +112,7 @@ export default class MySettingsPage extends React.Component
-
+
Confirm your new email diff --git a/public/pages/MySettings/components/NotificationSettings.tsx b/public/pages/MySettings/components/NotificationSettings.tsx index 254bf456c..8585e8351 100644 --- a/public/pages/MySettings/components/NotificationSettings.tsx +++ b/public/pages/MySettings/components/NotificationSettings.tsx @@ -94,7 +94,7 @@ export const NotificationSettings = (props: NotificationSettingsProps) => {

- +
New Post From 44c5d71eaf75e132c9f0e52ba5a1f31d8f77d8ce Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 20 Sep 2024 15:40:50 +0100 Subject: [PATCH 07/28] More webhooks tweaks --- public/assets/styles/utility/text.scss | 13 +++++++++++- public/components/Header.tsx | 2 +- public/components/common/form/Form.scss | 4 ++-- .../components/webhook/WebhookForm.tsx | 6 +++--- .../components/webhook/WebhookListItem.tsx | 20 +++++++++++++++--- .../pages/ManageWebhooks.page.tsx | 21 ++++++------------- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/public/assets/styles/utility/text.scss b/public/assets/styles/utility/text.scss index 803ff8c24..0f54445f7 100644 --- a/public/assets/styles/utility/text.scss +++ b/public/assets/styles/utility/text.scss @@ -20,11 +20,16 @@ pre:last-child { font-weight: get("font.weight.semibold"); } -.text-title { +.text-header { font-size: get("font.size.xl"); font-weight: get("font.weight.medium"); } +.text-title { + font-size: get("font.size.lg"); + font-weight: get("font.weight.medium"); +} + .text-body { font-size: get("font.size.base"); } @@ -49,6 +54,12 @@ pre:last-child { color: get("colors.blue.600"); } +.nowrap { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .text-link:hover { color: get("colors.blue.800"); text-decoration: underline; diff --git a/public/components/Header.tsx b/public/components/Header.tsx index ca4174d18..65a240f37 100644 --- a/public/components/Header.tsx +++ b/public/components/Header.tsx @@ -23,7 +23,7 @@ export const Header = () => { -

{fider.session.tenant.name}

+

{fider.session.tenant.name}

{fider.session.isAuthenticated && ( diff --git a/public/components/common/form/Form.scss b/public/components/common/form/Form.scss index 5d56ca459..757ff3e03 100644 --- a/public/components/common/form/Form.scss +++ b/public/components/common/form/Form.scss @@ -11,10 +11,10 @@ } &:last-child { - margin-bottom: 0; + // margin-bottom: 0; .flex-x > & { - margin-bottom: spacing(2); + // margin-bottom: spacing(2); } } } diff --git a/public/pages/Administration/components/webhook/WebhookForm.tsx b/public/pages/Administration/components/webhook/WebhookForm.tsx index 02cf50ac5..ca9d93089 100644 --- a/public/pages/Administration/components/webhook/WebhookForm.tsx +++ b/public/pages/Administration/components/webhook/WebhookForm.tsx @@ -152,7 +152,7 @@ export const WebhookForm = (props: WebhookFormProps) => { This webhook has failed )} -

{title}

+

{title}

}> - + {Object.entries(httpHeaders).map(([header, value]) => ( ))} diff --git a/public/pages/Administration/components/webhook/WebhookListItem.tsx b/public/pages/Administration/components/webhook/WebhookListItem.tsx index 51d3b6776..2381fb123 100644 --- a/public/pages/Administration/components/webhook/WebhookListItem.tsx +++ b/public/pages/Administration/components/webhook/WebhookListItem.tsx @@ -1,7 +1,7 @@ import "./WebhookListItem.scss" import React, { useState } from "react" -import { Webhook, WebhookStatus, WebhookTriggerResult } from "@fider/models" +import { Webhook, WebhookStatus, WebhookTriggerResult, WebhookType } from "@fider/models" import { Button, Icon } from "@fider/components" import { actions, notify } from "@fider/services" @@ -63,6 +63,19 @@ export const WebhookListItem = (props: WebhookListItemProps) => { } } + const getWebhookType = (type: WebhookType) => { + switch (type) { + case WebhookType.CHANGE_STATUS: + return "Change Status" + case WebhookType.NEW_COMMENT: + return "New Comment" + case WebhookType.DELETE_POST: + return "Delete Post" + case WebhookType.NEW_POST: + return "New Post" + } + } + const testWebhook = async () => { const result = await actions.testWebhook(props.webhook.id) setTriggerResult(result.data) @@ -100,8 +113,9 @@ export const WebhookListItem = (props: WebhookListItemProps) => { -

- #{props.webhook.id} {props.webhook.name} +

+ #{props.webhook.id} + {getWebhookType(props.webhook.type)} - {props.webhook.name}

{triggerResult?.success === false && ( diff --git a/public/pages/Administration/pages/ManageWebhooks.page.tsx b/public/pages/Administration/pages/ManageWebhooks.page.tsx index f40f8c7e7..19cd6793f 100644 --- a/public/pages/Administration/pages/ManageWebhooks.page.tsx +++ b/public/pages/Administration/pages/ManageWebhooks.page.tsx @@ -30,10 +30,9 @@ interface WebhooksListProps { const WebhooksList = (props: WebhooksListProps) => { return (
-

{props.title}

-

These webhooks are triggered every time {props.description}.

+

Existing Webhooks

- {props.list.length === 0 ?

There aren’t any "{props.title.toLowerCase()}" webhook yet.

: props.list} + {props.list.length === 0 ?

There aren’t any webhooks yet.

: props.list}
) @@ -98,8 +97,8 @@ const ManageWebhooksPage = (props: ManageWebhooksPageProps) => { sortWebhooks() } - const getWebhookList = (filter: (webhook: Webhook) => boolean) => { - return allWebhooks.filter(filter).map((w) => { + const getWebhookItems = () => { + return allWebhooks.map((w) => { return ( { return render() } - const newPostList = getWebhookList((w) => w.type === WebhookType.NEW_POST) - const newCommentList = getWebhookList((w) => w.type === WebhookType.NEW_COMMENT) - const changeStatusList = getWebhookList((w) => w.type === WebhookType.CHANGE_STATUS) - const deletePostList = getWebhookList((w) => w.type === WebhookType.DELETE_POST) - return render(

@@ -140,13 +134,10 @@ const ManageWebhooksPage = (props: ManageWebhooksPageProps) => { .

- - - - +
From b226aaf05be4b1814d58c45007cf62cf373a5679 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 20 Sep 2024 17:32:09 +0100 Subject: [PATCH 08/28] No duplicate emails on the "show votes" --- public/pages/Administration/pages/ManageMembers.page.tsx | 2 +- public/pages/Administration/pages/ManageWebhooks.page.tsx | 2 +- public/pages/ShowPost/components/VotesModal.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index c058e4617..a9178314d 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -161,7 +161,7 @@ export default class ManageMembersPage extends AdminBasePage
-

+

{!this.state.query && ( <> Showing {this.state.visibleUsers.length} of {this.state.users.length} registered users. diff --git a/public/pages/Administration/pages/ManageWebhooks.page.tsx b/public/pages/Administration/pages/ManageWebhooks.page.tsx index 19cd6793f..932096515 100644 --- a/public/pages/Administration/pages/ManageWebhooks.page.tsx +++ b/public/pages/Administration/pages/ManageWebhooks.page.tsx @@ -30,7 +30,7 @@ interface WebhooksListProps { const WebhooksList = (props: WebhooksListProps) => { return (

-

Existing Webhooks

+

My Webhooks

{props.list.length === 0 ?

There aren’t any webhooks yet.

: props.list}
diff --git a/public/pages/ShowPost/components/VotesModal.tsx b/public/pages/ShowPost/components/VotesModal.tsx index 770a8c7f7..708baa1f9 100644 --- a/public/pages/ShowPost/components/VotesModal.tsx +++ b/public/pages/ShowPost/components/VotesModal.tsx @@ -70,7 +70,7 @@ export const VotesModal: React.FC = (props) => { - + {x.user.email} From 594c6dca8c01b5f7bd34370ed99536d659955a7a Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 20 Sep 2024 17:41:39 +0100 Subject: [PATCH 09/28] Fixed lint issue --- public/pages/Administration/pages/ManageWebhooks.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/pages/Administration/pages/ManageWebhooks.page.tsx b/public/pages/Administration/pages/ManageWebhooks.page.tsx index 932096515..0a739ed4a 100644 --- a/public/pages/Administration/pages/ManageWebhooks.page.tsx +++ b/public/pages/Administration/pages/ManageWebhooks.page.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react" import { Button } from "@fider/components" -import { Webhook, WebhookData, WebhookStatus, WebhookType } from "@fider/models" +import { Webhook, WebhookData, WebhookStatus } from "@fider/models" import { actions, Failure } from "@fider/services" import { AdminPageContainer } from "../components/AdminBasePage" import { WebhookForm } from "../components/webhook/WebhookForm" From 8f71a8733d93ea08651c83919ec08ee74b0ad257 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Wed, 25 Sep 2024 15:50:21 +0100 Subject: [PATCH 10/28] WIP notifications modal. --- app/cmd/routes.go | 11 +-- app/handlers/notification.go | 13 +++- app/models/entity/notification.go | 21 ++++-- .../sqlstore/postgres/notification.go | 16 +++-- public/components/NotificationIndicator.tsx | 68 +++++++++++++++++-- public/components/common/Dropdown.scss | 5 ++ public/components/common/Dropdown.tsx | 14 +++- public/models/notification.ts | 2 + .../pages/Home/components/PostsContainer.tsx | 1 + public/services/actions/notification.ts | 5 ++ 10 files changed, 131 insertions(+), 25 deletions(-) diff --git a/app/cmd/routes.go b/app/cmd/routes.go index 06548073e..e761492b6 100644 --- a/app/cmd/routes.go +++ b/app/cmd/routes.go @@ -71,7 +71,7 @@ func routes(r *web.Engine) *web.Engine { } } - //Starting from this step, a Tenant is required + // Starting from this step, a Tenant is required r.Use(middlewares.RequireTenant()) r.Get("/sitemap.xml", handlers.Sitemap()) @@ -96,7 +96,7 @@ func routes(r *web.Engine) *web.Engine { r.Get("/oauth/:provider/token", handlers.OAuthToken()) r.Get("/oauth/:provider/echo", handlers.OAuthEcho()) - //If tenant is pending, block it from using any other route + // If tenant is pending, block it from using any other route r.Use(middlewares.BlockPendingTenants()) r.Get("/signin", handlers.SignInPage()) @@ -106,7 +106,7 @@ func routes(r *web.Engine) *web.Engine { r.Post("/_api/signin/complete", handlers.CompleteSignInProfile()) r.Post("/_api/signin", handlers.SignInByEmail()) - //Block if it's private tenant with unauthenticated user + // Block if it's private tenant with unauthenticated user r.Use(middlewares.CheckTenantPrivacy()) r.Get("/", handlers.Index()) @@ -115,7 +115,7 @@ func routes(r *web.Engine) *web.Engine { ui := r.Group() { - //From this step, a User is required + // From this step, a User is required ui.Use(middlewares.IsAuthenticated()) ui.Get("/settings", handlers.UserSettings()) @@ -129,6 +129,7 @@ func routes(r *web.Engine) *web.Engine { ui.Post("/_api/user/change-email", handlers.ChangeUserEmail()) ui.Post("/_api/notifications/read-all", handlers.ReadAllNotifications()) ui.Get("/_api/notifications/unread/total", handlers.TotalUnreadNotifications()) + ui.Get("/_api/notifications/unread", handlers.GetAllNotifications()) // From this step, only Collaborators and Administrators are allowed ui.Use(middlewares.IsAuthorized(enum.RoleCollaborator, enum.RoleAdministrator)) @@ -146,7 +147,7 @@ func routes(r *web.Engine) *web.Engine { ui.Get("/admin/authentication", handlers.ManageAuthentication()) ui.Get("/_api/admin/oauth/:provider", handlers.GetOAuthConfig()) - //From this step, only Administrators are allowed + // From this step, only Administrators are allowed ui.Use(middlewares.IsAuthorized(enum.RoleAdministrator)) ui.Get("/admin/export", handlers.Page("Export · Site Settings", "", "Administration/pages/Export.page")) diff --git a/app/handlers/notification.go b/app/handlers/notification.go index f39221785..e00af53ed 100644 --- a/app/handlers/notification.go +++ b/app/handlers/notification.go @@ -9,6 +9,18 @@ import ( "github.com/getfider/fider/app/pkg/web" ) +// GetAllNotifications will get all the notifications for the new modal +func GetAllNotifications() web.HandlerFunc { + return func(c *web.Context) error { + q := &query.GetActiveNotifications{} + if err := bus.Dispatch(c, q); err != nil { + return c.Failure(err) + } + + return c.Ok(q.Result) + } +} + // TotalUnreadNotifications returns the total number of unread notifications func TotalUnreadNotifications() web.HandlerFunc { return func(c *web.Context) error { @@ -65,7 +77,6 @@ func ReadNotification() web.HandlerFunc { // ReadAllNotifications marks all unread notifications as read func ReadAllNotifications() web.HandlerFunc { return func(c *web.Context) error { - if err := bus.Dispatch(c, &cmd.MarkAllNotificationsAsRead{}); err != nil { return c.Failure(err) } diff --git a/app/models/entity/notification.go b/app/models/entity/notification.go index 385876920..28dc81275 100644 --- a/app/models/entity/notification.go +++ b/app/models/entity/notification.go @@ -1,12 +1,21 @@ package entity -import "time" +import ( + "time" + + "github.com/getfider/fider/app/models/enum" +) // Notification is the system generated notification entity type Notification struct { - ID int `json:"id" db:"id"` - Title string `json:"title" db:"title"` - Link string `json:"link" db:"link"` - Read bool `json:"read" db:"read"` - CreatedAt time.Time `json:"createdAt" db:"created_at"` + ID int `json:"id" db:"id"` + Title string `json:"title" db:"title"` + Link string `json:"link" db:"link"` + Read bool `json:"read" db:"read"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + AuthorName string `json:"authorName" db:"name"` + AuthorID int `json:"-" db:"author_id"` + AvatarBlobKey string `json:"-" db:"avatar_bkey"` + AvatarType enum.AvatarType `json:"-" db:"avatar_type"` + AvatarURL string `json:"avatarURL,omitempty"` } diff --git a/app/services/sqlstore/postgres/notification.go b/app/services/sqlstore/postgres/notification.go index 2e7d0fc50..5832e9edc 100644 --- a/app/services/sqlstore/postgres/notification.go +++ b/app/services/sqlstore/postgres/notification.go @@ -102,16 +102,22 @@ func getNotificationByID(ctx context.Context, q *query.GetNotificationByID) erro func getActiveNotifications(ctx context.Context, q *query.GetActiveNotifications) error { return using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error { - q.Result = []*entity.Notification{} err := trx.Select(&q.Result, ` - SELECT id, title, link, read, created_at - FROM notifications - WHERE tenant_id = $1 AND user_id = $2 - AND (read = false OR updated_at > CURRENT_DATE - INTERVAL '30 days') + SELECT n.id, n.title, n.link, n.read, n.created_at, n.author_id, u.avatar_type, u.avatar_bkey, u.name + FROM notifications n + LEFT JOIN users u ON u.id = n.author_id + WHERE n.tenant_id = $1 AND n.user_id = $2 + AND (n.read = false OR n.updated_at > CURRENT_DATE - INTERVAL '30 days') `, tenant.ID, user.ID) if err != nil { return errors.Wrap(err, "failed to get active notifications") } + + // Iterate over notifications and build avatar URL + for i := range q.Result { + q.Result[i].AvatarURL = buildAvatarURL(ctx, q.Result[i].AvatarType, int(q.Result[i].ID), q.Result[i].AuthorName, q.Result[i].AvatarBlobKey) + } + return nil }) } diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 9813db0e5..63d1d0a88 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -3,12 +3,42 @@ import "./NotificationIndicator.scss" import React, { useEffect, useState } from "react" import IconBell from "@fider/assets/images/heroicons-bell.svg" import { useFider } from "@fider/hooks" -import { actions } from "@fider/services" -import { Icon } from "./common" +import { actions, Fider } from "@fider/services" +import { Avatar, Icon, Markdown, Moment } from "./common" +import { Dropdown } from "./common/Dropdown" +import { Notification } from "@fider/models" +import { HStack, VStack } from "./layout" + +export const NotificationItem = ({ notification }: { notification: Notification }) => { + return ( + + +
+ + + + +
+
+ ) +} + +const NotificationIcon = ({ unreadNotifications }: { unreadNotifications: number }) => { + return ( + <> + + + {unreadNotifications > 0 &&
} + + + ) +} export const NotificationIndicator = () => { const fider = useFider() const [unreadNotifications, setUnreadNotifications] = useState(0) + const [showingNotifications, setShowingNotifications] = useState(false) + const [notifications, setNotifications] = useState() useEffect(() => { if (fider.session.isAuthenticated) { @@ -20,10 +50,36 @@ export const NotificationIndicator = () => { } }, [fider.session.isAuthenticated]) + useEffect(() => { + if (showingNotifications) { + actions.getAllNotifications().then((result) => { + if (result) { + setNotifications(result.data) + } + }) + } + }, [showingNotifications]) + return ( - - - {unreadNotifications > 0 &&
} - + setShowingNotifications(!showingNotifications)} + renderHandle={} + > +
+ {showingNotifications && notifications !== undefined && notifications?.length > 0 && ( + <> +

No new notifications

+

Previous notifications

+ + {notifications.map((n) => ( + + ))} + + + )} +
+
) } diff --git a/public/components/common/Dropdown.scss b/public/components/common/Dropdown.scss index 265bf97ca..005b84568 100644 --- a/public/components/common/Dropdown.scss +++ b/public/components/common/Dropdown.scss @@ -29,6 +29,11 @@ &--left { right: 0; } + + &--wide { + max-width: sizing(120); + } + } &__listitem { diff --git a/public/components/common/Dropdown.tsx b/public/components/common/Dropdown.tsx index 8da23d576..61e36c197 100644 --- a/public/components/common/Dropdown.tsx +++ b/public/components/common/Dropdown.tsx @@ -42,7 +42,9 @@ const Divider = () => { interface DropdownProps { renderHandle: JSX.Element position?: "left" | "right" + onToggled?: (isOpen: boolean) => void children: React.ReactNode + wide?: boolean } interface DropdownContextFuncs { @@ -57,12 +59,19 @@ export const Dropdown = (props: DropdownProps) => { const [isOpen, setIsOpen] = useState(false) const position = props.position || "right" + const changeToggleState = (newState: boolean) => { + setIsOpen(newState) + if (props.onToggled) { + props.onToggled(newState) + } + } + const toggleIsOpen = () => { - setIsOpen(!isOpen) + changeToggleState(!isOpen) } const close = () => { - setIsOpen(false) + changeToggleState(false) } const handleClick = (e: MouseEvent) => { @@ -82,6 +91,7 @@ export const Dropdown = (props: DropdownProps) => { }, []) const listClassName = classSet({ + "c-dropdown__list--wide": props.wide, "c-dropdown__list shadow-lg": true, [`c-dropdown__list--${position}`]: position === "left", }) diff --git a/public/models/notification.ts b/public/models/notification.ts index b85940827..a2cece932 100644 --- a/public/models/notification.ts +++ b/public/models/notification.ts @@ -4,4 +4,6 @@ export interface Notification { link: string read: boolean createdAt: string + authorName: string + avatarURL: string } diff --git a/public/pages/Home/components/PostsContainer.tsx b/public/pages/Home/components/PostsContainer.tsx index 9478ec749..70958f636 100644 --- a/public/pages/Home/components/PostsContainer.tsx +++ b/public/pages/Home/components/PostsContainer.tsx @@ -113,6 +113,7 @@ export class PostsContainer extends React.Component > => { return http.get<{ total: number }>("/_api/notifications/unread/total").then((result) => { @@ -10,6 +11,10 @@ export const getTotalUnreadNotifications = async (): Promise> => }) } +export const getAllNotifications = async (): Promise> => { + return http.get("/_api/notifications/unread") +} + export const markAllAsRead = async (): Promise => { return await http.post("/_api/notifications/read-all") } From 761cb11eee55277e24013927e0d971935a32271b Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Sun, 29 Sep 2024 16:27:43 +0100 Subject: [PATCH 11/28] Notifications dropdown --- .../sqlstore/postgres/notification.go | 2 +- public/assets/styles/utility/display.scss | 10 +++- public/components/NotificationIndicator.scss | 5 ++ public/components/NotificationIndicator.tsx | 57 ++++++++++++++----- public/components/common/Dropdown.scss | 10 +++- public/components/common/Dropdown.tsx | 3 + 6 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/services/sqlstore/postgres/notification.go b/app/services/sqlstore/postgres/notification.go index 5832e9edc..473a9fce2 100644 --- a/app/services/sqlstore/postgres/notification.go +++ b/app/services/sqlstore/postgres/notification.go @@ -115,7 +115,7 @@ func getActiveNotifications(ctx context.Context, q *query.GetActiveNotifications // Iterate over notifications and build avatar URL for i := range q.Result { - q.Result[i].AvatarURL = buildAvatarURL(ctx, q.Result[i].AvatarType, int(q.Result[i].ID), q.Result[i].AuthorName, q.Result[i].AvatarBlobKey) + q.Result[i].AvatarURL = buildAvatarURL(ctx, q.Result[i].AvatarType, int(q.Result[i].AuthorID), q.Result[i].AuthorName, q.Result[i].AvatarBlobKey) } return nil diff --git a/public/assets/styles/utility/display.scss b/public/assets/styles/utility/display.scss index 23f3cd134..38ea83e9e 100644 --- a/public/assets/styles/utility/display.scss +++ b/public/assets/styles/utility/display.scss @@ -149,7 +149,7 @@ border: 0 solid get("colors.gray.100"); border-top-width: 1px; } - .flex-y.flex--divide-#{$i} > *:last-child { + .flex-y.flex--divide-#{$i}:not(.no-lastchild-paddingzero) > *:last-child { padding-bottom: 0; } } @@ -203,3 +203,11 @@ cursor: pointer; pointer-events: inherit; } + + +.hover { + &:hover { + background-color: get("colors.gray.100") + } +} + diff --git a/public/components/NotificationIndicator.scss b/public/components/NotificationIndicator.scss index d36e2da63..12eecac8e 100644 --- a/public/components/NotificationIndicator.scss +++ b/public/components/NotificationIndicator.scss @@ -13,3 +13,8 @@ border-radius: 100%; } } + +.c-notifications-container { + max-height: 80vh; + overflow-y: auto; +} diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 63d1d0a88..f971d88b6 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -10,8 +10,13 @@ import { Notification } from "@fider/models" import { HStack, VStack } from "./layout" export const NotificationItem = ({ notification }: { notification: Notification }) => { + const openNotification = () => { + console.log(notification.link) + window.location.href = `/notifications/${notification.id}` + } + return ( - +
@@ -38,7 +43,8 @@ export const NotificationIndicator = () => { const fider = useFider() const [unreadNotifications, setUnreadNotifications] = useState(0) const [showingNotifications, setShowingNotifications] = useState(false) - const [notifications, setNotifications] = useState() + const [recent, setRecent] = useState() + const [unread, setUnread] = useState() useEffect(() => { if (fider.session.isAuthenticated) { @@ -54,7 +60,16 @@ export const NotificationIndicator = () => { if (showingNotifications) { actions.getAllNotifications().then((result) => { if (result) { - setNotifications(result.data) + const [unread, recent] = (result.data || []).reduce( + (result, item) => { + result[item.read ? 1 : 0].push(item) + return result + }, + [[] as Notification[], [] as Notification[]] + ) + setRecent(recent) + setUnread(unread) + setUnreadNotifications(unread.length) } }) } @@ -64,19 +79,35 @@ export const NotificationIndicator = () => { setShowingNotifications(!showingNotifications)} + fullsceenSm={true} + onToggled={(isOpen: boolean) => setShowingNotifications(isOpen)} renderHandle={} > -
- {showingNotifications && notifications !== undefined && notifications?.length > 0 && ( +
+ {showingNotifications && (unread !== undefined || recent !== undefined) && ( <> -

No new notifications

-

Previous notifications

- - {notifications.map((n) => ( - - ))} - + {unread !== undefined && unread?.length > 0 ? ( + <> +

Unread notifications

+ + {unread.map((n) => ( + + ))} + + + ) : ( +

No new notifications

+ )} + {recent !== undefined && recent?.length > 0 && ( + <> +

Previous notifications

+ + {recent.map((n) => ( + + ))} + + + )} )}
diff --git a/public/components/common/Dropdown.scss b/public/components/common/Dropdown.scss index 005b84568..38d94f00e 100644 --- a/public/components/common/Dropdown.scss +++ b/public/components/common/Dropdown.scss @@ -31,7 +31,15 @@ } &--wide { - max-width: sizing(120); + max-width: sizing(180); + } + + &--fullscreen-small { + @include media("sm") { + position: fixed; + left: 0; + width: 100vw; + } } } diff --git a/public/components/common/Dropdown.tsx b/public/components/common/Dropdown.tsx index 61e36c197..3493307b9 100644 --- a/public/components/common/Dropdown.tsx +++ b/public/components/common/Dropdown.tsx @@ -45,6 +45,7 @@ interface DropdownProps { onToggled?: (isOpen: boolean) => void children: React.ReactNode wide?: boolean + fullsceenSm?: boolean } interface DropdownContextFuncs { @@ -62,6 +63,7 @@ export const Dropdown = (props: DropdownProps) => { const changeToggleState = (newState: boolean) => { setIsOpen(newState) if (props.onToggled) { + console.log("onToggled", newState) props.onToggled(newState) } } @@ -93,6 +95,7 @@ export const Dropdown = (props: DropdownProps) => { const listClassName = classSet({ "c-dropdown__list--wide": props.wide, "c-dropdown__list shadow-lg": true, + "c-dropdown__list--fullscreen-small": props.fullsceenSm, [`c-dropdown__list--${position}`]: position === "left", }) From 4aecc0eab2c606ebe3c12dddc284dc9ab15570bc Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Sun, 29 Sep 2024 16:28:11 +0100 Subject: [PATCH 12/28] Username component shouldn't show email unless explicitly requested --- public/components/common/UserName.tsx | 3 ++- public/pages/Administration/pages/ManageMembers.page.tsx | 2 +- public/pages/ShowPost/components/VotesModal.tsx | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/components/common/UserName.tsx b/public/components/common/UserName.tsx index b7a7eb7a7..0f06751a7 100644 --- a/public/components/common/UserName.tsx +++ b/public/components/common/UserName.tsx @@ -11,6 +11,7 @@ interface UserNameProps { role?: UserRole email?: string } + showEmail?: boolean } export const UserName = (props: UserNameProps) => { @@ -23,7 +24,7 @@ export const UserName = (props: UserNameProps) => { return (
{props.user.name || "Anonymous"} - <>{props.user.email && ({props.user.email})} + <>{props.showEmail && props.user.email && ({props.user.email})} {isStaff && (
diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index a9178314d..19045bae9 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -38,7 +38,7 @@ const UserListItem = (props: UserListItemProps) => { - + {admin} {collaborator} {blocked} diff --git a/public/pages/ShowPost/components/VotesModal.tsx b/public/pages/ShowPost/components/VotesModal.tsx index 708baa1f9..770a8c7f7 100644 --- a/public/pages/ShowPost/components/VotesModal.tsx +++ b/public/pages/ShowPost/components/VotesModal.tsx @@ -70,7 +70,7 @@ export const VotesModal: React.FC = (props) => { - + {x.user.email} From 1af2ff425a31fc1e930512445f3d51dfb176fb87 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Sun, 29 Sep 2024 19:09:49 +0100 Subject: [PATCH 13/28] Formatting. --- public/pages/Administration/pages/ManageMembers.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index 19045bae9..4ed17c0a4 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -38,7 +38,7 @@ const UserListItem = (props: UserListItemProps) => { - + {admin} {collaborator} {blocked} From 1003796967de7debb31fc5acaa40320f08b8e512 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Mon, 30 Sep 2024 12:33:52 +0100 Subject: [PATCH 14/28] Missing route --- app/cmd/routes.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/cmd/routes.go b/app/cmd/routes.go index 87da777f7..8790da472 100644 --- a/app/cmd/routes.go +++ b/app/cmd/routes.go @@ -73,7 +73,7 @@ func routes(r *web.Engine) *web.Engine { r.Get("/oauth/:provider", handlers.SignInByOAuth()) r.Get("/oauth/:provider/callback", handlers.OAuthCallback()) - //Starting from this step, a Tenant is required + // Starting from this step, a Tenant is required r.Use(middlewares.RequireTenant()) r.Get("/sitemap.xml", handlers.Sitemap()) @@ -98,7 +98,7 @@ func routes(r *web.Engine) *web.Engine { r.Get("/oauth/:provider/token", handlers.OAuthToken()) r.Get("/oauth/:provider/echo", handlers.OAuthEcho()) - //If tenant is pending, block it from using any other route + // If tenant is pending, block it from using any other route r.Use(middlewares.BlockPendingTenants()) r.Get("/signin", handlers.SignInPage()) @@ -108,7 +108,7 @@ func routes(r *web.Engine) *web.Engine { r.Post("/_api/signin/complete", handlers.CompleteSignInProfile()) r.Post("/_api/signin", handlers.SignInByEmail()) - //Block if it's private tenant with unauthenticated user + // Block if it's private tenant with unauthenticated user r.Use(middlewares.CheckTenantPrivacy()) r.Get("/", handlers.Index()) @@ -117,12 +117,13 @@ func routes(r *web.Engine) *web.Engine { ui := r.Group() { - //From this step, a User is required + // From this step, a User is required ui.Use(middlewares.IsAuthenticated()) ui.Get("/settings", handlers.UserSettings()) ui.Get("/notifications", handlers.Notifications()) ui.Get("/notifications/:id", handlers.ReadNotification()) + ui.Get("/_api/notifications/unread", handlers.GetAllNotifications()) ui.Get("/change-email/verify", handlers.VerifyChangeEmailKey()) ui.Delete("/_api/user", handlers.DeleteUser()) @@ -148,7 +149,7 @@ func routes(r *web.Engine) *web.Engine { ui.Get("/admin/authentication", handlers.ManageAuthentication()) ui.Get("/_api/admin/oauth/:provider", handlers.GetOAuthConfig()) - //From this step, only Administrators are allowed + // From this step, only Administrators are allowed ui.Use(middlewares.IsAuthorized(enum.RoleAdministrator)) ui.Get("/admin/export", handlers.Page("Export · Site Settings", "", "Administration/pages/Export.page")) From 11701661fff37f719ee1f29585c943e798923834 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Tue, 1 Oct 2024 12:01:55 +0100 Subject: [PATCH 15/28] Margin bottom fixes --- public/components/common/form/Form.scss | 2 +- public/pages/Home/components/PostsContainer.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/public/components/common/form/Form.scss b/public/components/common/form/Form.scss index 757ff3e03..a3d12f5cb 100644 --- a/public/components/common/form/Form.scss +++ b/public/components/common/form/Form.scss @@ -11,7 +11,7 @@ } &:last-child { - // margin-bottom: 0; + margin-bottom: 0; .flex-x > & { // margin-bottom: spacing(2); diff --git a/public/pages/Home/components/PostsContainer.tsx b/public/pages/Home/components/PostsContainer.tsx index 70958f636..9478ec749 100644 --- a/public/pages/Home/components/PostsContainer.tsx +++ b/public/pages/Home/components/PostsContainer.tsx @@ -113,7 +113,6 @@ export class PostsContainer extends React.Component Date: Tue, 1 Oct 2024 15:43:07 +0100 Subject: [PATCH 16/28] Some minor changes to the styles --- public/assets/styles/utility/text.scss | 5 +++++ public/components/NotificationIndicator.tsx | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/public/assets/styles/utility/text.scss b/public/assets/styles/utility/text.scss index 0f54445f7..9cc2fc946 100644 --- a/public/assets/styles/utility/text.scss +++ b/public/assets/styles/utility/text.scss @@ -30,6 +30,11 @@ pre:last-child { font-weight: get("font.weight.medium"); } +.text-subtitle { + font-size: get("font.size.base"); + font-weight: get("font.weight.medium"); +} + .text-body { font-size: get("font.size.base"); } diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index f971d88b6..bd087ea95 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -16,7 +16,7 @@ export const NotificationItem = ({ notification }: { notification: Notification } return ( - +
@@ -88,7 +88,7 @@ export const NotificationIndicator = () => { <> {unread !== undefined && unread?.length > 0 ? ( <> -

Unread notifications

+

Unread notifications

{unread.map((n) => ( @@ -100,7 +100,7 @@ export const NotificationIndicator = () => { )} {recent !== undefined && recent?.length > 0 && ( <> -

Previous notifications

+

Previous notifications

{recent.map((n) => ( From c42951880a437352f5016950bae252be352d26f5 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Tue, 1 Oct 2024 19:30:53 +0100 Subject: [PATCH 17/28] Localised notifications modal --- public/components/NotificationIndicator.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index bd087ea95..7c2324bc7 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -9,6 +9,8 @@ import { Dropdown } from "./common/Dropdown" import { Notification } from "@fider/models" import { HStack, VStack } from "./layout" +import { Trans } from "@lingui/macro" + export const NotificationItem = ({ notification }: { notification: Notification }) => { const openNotification = () => { console.log(notification.link) @@ -88,7 +90,9 @@ export const NotificationIndicator = () => { <> {unread !== undefined && unread?.length > 0 ? ( <> -

Unread notifications

+

+ Unread notifications +

{unread.map((n) => ( @@ -96,11 +100,15 @@ export const NotificationIndicator = () => { ) : ( -

No new notifications

+

+ No new notifications +

)} {recent !== undefined && recent?.length > 0 && ( <> -

Previous notifications

+

+ Previous notifications +

{recent.map((n) => ( From e7e5145d2a715512967927c711b8f246abbfa51b Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Tue, 1 Oct 2024 19:31:04 +0100 Subject: [PATCH 18/28] Locale files updated --- locale/de/client.json | 7 +++++++ locale/el/client.json | 7 +++++++ locale/en/client.json | 3 +++ locale/es-ES/client.json | 7 +++++++ locale/fr/client.json | 7 +++++++ locale/nl/client.json | 7 +++++++ locale/pl/client.json | 7 +++++++ locale/pt-BR/client.json | 7 +++++++ locale/ru/client.json | 7 +++++++ locale/sk/client.json | 7 +++++++ locale/sv-SE/client.json | 7 +++++++ locale/tr/client.json | 7 +++++++ 12 files changed, 80 insertions(+) diff --git a/locale/de/client.json b/locale/de/client.json index f8e875e75..d7e268fcc 100644 --- a/locale/de/client.json +++ b/locale/de/client.json @@ -3,6 +3,7 @@ "action.change": "ändern", "action.close": "Schließen", "action.confirm": "Bestätigen", + "action.copylink": "", "action.delete": "Löschen", "action.edit": "Bearbeiten", "action.markallasread": "Alle als gelesen markieren", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Wenn Sie Ihr Konto löschen, werden wir all Ihre persönlichen Daten für immer löschen. Der von Ihnen veröffentlichte Inhalt bleibt erhalten, wird aber anonymisiert.<1>Dieser Prozess ist irreversibel. <2>Sind Sie sicher? ", "modal.deletecomment.header": "Kommentar löschen", "modal.deletecomment.text": "Dieser Prozess ist unumkehrbar. <0>Bist du dir sicher?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Keine Benutzer gefunden, die <0>{0} entsprechen.", "modal.showvotes.query.placeholder": "Suche nach Benutzern nach Namen...", "modal.signin.header": "Melde dich an, um eine neue Idee zu posten", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Wir haben Ihnen eine Bestätigungs-E-Mail mit einem Link zur Aktivierung Ihrer Website geschickt.", "page.pendingactivation.text2": "Bitte überprüfe deinen Posteingang, um ihn zu aktivieren.", "page.pendingactivation.title": "Dein Account ist nicht aktiviert", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Kommentar hinzufügen", "showpost.discussionpanel.emptymessage": "Niemand hat bisher kommentiert.", "showpost.label.author": "Gepostet von <0/> · <1/>", diff --git a/locale/el/client.json b/locale/el/client.json index 371d9fb02..a9984349a 100644 --- a/locale/el/client.json +++ b/locale/el/client.json @@ -3,6 +3,7 @@ "action.change": "αλλαγή", "action.close": "Κλείσιμο", "action.confirm": "Επιβεβαίωση", + "action.copylink": "", "action.delete": "Διαγραφή", "action.edit": "Επεξεργασία", "action.markallasread": "Σήμανση όλων ως αναγνωσμένων", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Όταν επιλέξετε να διαγράψετε τον λογαριασμό σας, θα διαγράψουμε για πάντα όλες τις προσωπικές σας πληροφορίες. Το περιεχόμενο που δημοσιεύσατε θα παραμείνει, αλλά θα είναι ανώνυμο.<1>Αυτή η διαδικασία είναι μη αναστρέψιμη. <2>Είστε σίγουρος;", "modal.deletecomment.header": "Διαγραφή Σχολίου", "modal.deletecomment.text": "Αυτή η διαδικασία είναι μη αναστρέψιμη. <0>Είστε σίγουρος;", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Δεν βρέθηκαν χρήστες που να ταιριάζουν <0>{0}.", "modal.showvotes.query.placeholder": "Αναζήτηση χρηστών με όνομα...", "modal.signin.header": "Συνδεθείτε για να συμμετάσχετε και να ψηφίσετε", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Σας στείλαμε ένα email επιβεβαίωσης με ένα σύνδεσμο για να ενεργοποιήσετε τον ιστότοπό σας.", "page.pendingactivation.text2": "Παρακαλώ ελέγξτε τα εισερχόμενά σας για να το ενεργοποιήσετε.", "page.pendingactivation.title": "Ο λογαριασμός σας εκκρεμεί ενεργοποίηση", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Αφήστε ένα σχόλιο", "showpost.discussionpanel.emptymessage": "Κανείς δεν έχει σχολιάσει ακόμα.", "showpost.label.author": "Δημοσιεύτηκε από <0/> · <1/>", diff --git a/locale/en/client.json b/locale/en/client.json index 21112eff3..4fd1b1ec6 100644 --- a/locale/en/client.json +++ b/locale/en/client.json @@ -82,6 +82,9 @@ "modal.deleteaccount.text": "<0>When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.<1>This process is irreversible. <2>Are you sure?", "modal.deletecomment.header": "Delete Comment", "modal.deletecomment.text": "This process is irreversible. <0>Are you sure?", + "modal.notifications.nonew": "No new notifications", + "modal.notifications.previous": "Previous notifications", + "modal.notifications.unread": "Unread notifications", "modal.showvotes.message.zeromatches": "No users found matching <0>{0}.", "modal.showvotes.query.placeholder": "Search for users by name...", "modal.signin.header": "Sign in to participate and vote", diff --git a/locale/es-ES/client.json b/locale/es-ES/client.json index 9fa7d186a..a3d595c88 100644 --- a/locale/es-ES/client.json +++ b/locale/es-ES/client.json @@ -3,6 +3,7 @@ "action.change": "cambiar", "action.close": "Cerrar", "action.confirm": "Confirmar", + "action.copylink": "", "action.delete": "Eliminar", "action.edit": "Editar", "action.markallasread": "Marcar Todo como Leído", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Cuando decides eliminar tu cuenta, borraremos toda tu información personal para siempre. El contenido que has publicado permanecerá, pero será anónimo.<1>Este proceso es irreversible. <2>¿Estás seguro?", "modal.deletecomment.header": "Eliminar Comentario", "modal.deletecomment.text": "Este proceso es irreversible. <0>¿Estás seguro?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "No se encontraron usuarios que coincidan con <0>{0}.", "modal.showvotes.query.placeholder": "Buscar usuarios por nombre...", "modal.signin.header": "Inicia sesión para publicar y votar", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Te hemos enviado un correo electrónico de confirmación con un enlace para activar tu sitio.", "page.pendingactivation.text2": "Por favor, revisa tu bandeja de entrada para activarla.", "page.pendingactivation.title": "Tu cuenta está pendiente de activación", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Publica un comentario", "showpost.discussionpanel.emptymessage": "Nadie ha comentado todavía.", "showpost.label.author": "Publicado por <0/> · <1/>", diff --git a/locale/fr/client.json b/locale/fr/client.json index 58293a999..af64d6359 100644 --- a/locale/fr/client.json +++ b/locale/fr/client.json @@ -3,6 +3,7 @@ "action.change": "changer", "action.close": "Fermer", "action.confirm": "Confirmer", + "action.copylink": "", "action.delete": "Supprimer", "action.edit": "Modifier", "action.markallasread": "Tout marquer comme lu", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Lorsque vous choisissez de supprimer votre compte, nous effacerons définitivement toutes vos informations personnelles. Le contenu que vous avez publié restera, mais il sera anonyme.<1>Ce processus est irréversible. <2>Êtes-vous sûr ?", "modal.deletecomment.header": "Supprimer le commentaire", "modal.deletecomment.text": "Ce processus est irréversible. <0>Êtes-vous sûr ?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Aucun utilisateur correspondant à <0>{0}.", "modal.showvotes.query.placeholder": "Rechercher des utilisateurs par nom...", "modal.signin.header": "Connectez-vous pour poster et voter", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Nous vous avons envoyé un e-mail de confirmation avec un lien pour activer votre site.", "page.pendingactivation.text2": "Veuillez vérifier votre boîte de réception pour l'activer.", "page.pendingactivation.title": "Votre compte n'est pas activé", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Rédiger un commentaire", "showpost.discussionpanel.emptymessage": "Personne n'a encore commenté.", "showpost.label.author": "Posté par <0/> · <1/>", diff --git a/locale/nl/client.json b/locale/nl/client.json index 1f1233c91..e881681b1 100644 --- a/locale/nl/client.json +++ b/locale/nl/client.json @@ -3,6 +3,7 @@ "action.change": "aanpassen", "action.close": "Sluiten", "action.confirm": "Bevestigen", + "action.copylink": "", "action.delete": "Verwijderen", "action.edit": "Bewerken", "action.markallasread": "Markeer alles als gelezen", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Als je ervoor kiest om je account te verwijderen, verwijderen we al je persoonlijke gegevens voor altijd. De inhoud die je hebt geplaatst blijft bestaan, maar zal geanonimiseerd worden.<1>Dit proces is onomkeerbaar. <2>Weet je het zeker?", "modal.deletecomment.header": "Reactie verwijderen", "modal.deletecomment.text": "Dit proces is onomkeerbaar. <0>Weet je het zeker?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Geen gebruikers gevonden voor <0>{0}.", "modal.showvotes.query.placeholder": "Zoek gebruikers op naam...", "modal.signin.header": "Log in om een bericht achter te laten en om te stemmen", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "We hebben je een bevestigingsmail gestuurd met een link om jouw site te activeren.", "page.pendingactivation.text2": "Controleer je inbox om het te activeren.", "page.pendingactivation.title": "Je account is nog niet geactiveerd", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Laat een reactie achter", "showpost.discussionpanel.emptymessage": "Nog niemand heeft gereageerd.", "showpost.label.author": "Geplaatst door <0/> · <1/>", diff --git a/locale/pl/client.json b/locale/pl/client.json index ee8409f03..5c5bc1c90 100644 --- a/locale/pl/client.json +++ b/locale/pl/client.json @@ -3,6 +3,7 @@ "action.change": "zmień", "action.close": "Zamknij", "action.confirm": "Potwierdź", + "action.copylink": "", "action.delete": "Usuń", "action.edit": "Edytuj", "action.markallasread": "Oznacz wszystkie jako przeczytane", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Jeśli zdecydujesz na usunięcie swojego konta, na zawsze usuniemy wszystkie Twoje dane osobowe. Opublikowana zawartość pozostanie na stronie, ale zostanie anonimowa.<1>Ten proces jest nieodwracalny. <2>Czy jesteś pewien?", "modal.deletecomment.header": "Usuń komentarz", "modal.deletecomment.text": "Ten proces jest nieodwracalny. <0>Czy jesteś pewien?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nie znaleziono użytkowników pasujących do <0>{0}.", "modal.showvotes.query.placeholder": "Wyszukaj użytkowników według nazwy...", "modal.signin.header": "Zaloguj się aby pisać i głosować", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Wysłaliśmy do Ciebie maila z linkiem do aktywowania Twojej strony.", "page.pendingactivation.text2": "Sprawdź swoją skrzynkę odbiorczą, aby ją aktywować.", "page.pendingactivation.title": "Twoje konto oczekuje na aktywację", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Skomentuj", "showpost.discussionpanel.emptymessage": "Wygląda na to, że nikt jeszcze nie skomentował.", "showpost.label.author": "Wysłane przez <0/> · <1/>", diff --git a/locale/pt-BR/client.json b/locale/pt-BR/client.json index 96e0c68d5..a7439d8cf 100644 --- a/locale/pt-BR/client.json +++ b/locale/pt-BR/client.json @@ -3,6 +3,7 @@ "action.change": "alterar", "action.close": "Fechar", "action.confirm": "Confirmar", + "action.copylink": "", "action.delete": "Deletar", "action.edit": "Editar", "action.markallasread": "Marcar todas como lidas", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Quando você optar por excluir sua conta, todas as suas informações pessoais serão removidas para sempre. O conteúdo que você publicou permanecerá, mas será anonimizado.<1>Esse processo é irreversível. <2>Você tem certeza?", "modal.deletecomment.header": "Excluir comentário", "modal.deletecomment.text": "Este processo é irreversível. <0>Tem certeza?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nenhum usuário encontrado para <0>{0}.", "modal.showvotes.query.placeholder": "Procurar usuários por nome...", "modal.signin.header": "Faça login para participar e votar", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Enviamos a você um e-mail de confirmação com um link para ativar o seu site.", "page.pendingactivation.text2": "Verifique sua caixa de entrada para ativá-la.", "page.pendingactivation.title": "Sua conta está com ativação pendente", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Deixe um comentário", "showpost.discussionpanel.emptymessage": "Ninguém comentou ainda.", "showpost.label.author": "Publicado por <0/> · <1/>", diff --git a/locale/ru/client.json b/locale/ru/client.json index 7cafb1ada..a1cf12c62 100644 --- a/locale/ru/client.json +++ b/locale/ru/client.json @@ -3,6 +3,7 @@ "action.change": "изменить", "action.close": "Закрыть", "action.confirm": "Подтвердить", + "action.copylink": "", "action.delete": "Удалить", "action.edit": "Изменить", "action.markallasread": "Отметить всё как прочитанное", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Если нужно, мы удалим всю информацию о вашем аккаунте навсегда. Всё, что вы публиковали, останется, но будет анонимизировано.<1>Это действие необратимо. <2>Вы уверены?", "modal.deletecomment.header": "Удалить комментарий", "modal.deletecomment.text": "Это действие необратимо. <0>Вы уверены?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Не удалось найти пользователей с <0>{0}.", "modal.showvotes.query.placeholder": "Найдите пользователей по их имени...", "modal.signin.header": "Войдите, чтобы создавать посты и голосовать", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Мы отправили вам письмо со ссылкой для активации этого сайта.", "page.pendingactivation.text2": "Проверьте свою почту, чтобы продолжить.", "page.pendingactivation.title": "Ваш аккаунт ожидает подтверждения", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Оставить комментарий", "showpost.discussionpanel.emptymessage": "Комментариев нет.", "showpost.label.author": "Создал <0/> · <1/>", diff --git a/locale/sk/client.json b/locale/sk/client.json index a034368de..d60077174 100644 --- a/locale/sk/client.json +++ b/locale/sk/client.json @@ -3,6 +3,7 @@ "action.change": "zmeniť", "action.close": "Zavrieť", "action.confirm": "Potvrdiť", + "action.copylink": "", "action.delete": "Vymazať", "action.edit": "Upraviť", "action.markallasread": "Označiť všetko ako prečítané", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Keď sa rozhodnete odstrániť svoj účet, všetky vaše osobné informácie navždy vymažeme. Obsah, ktorý ste zverejnili, zostane, ale bude anonymizovaný. <1> Tento proces je nevratný.<2>Ste si istí?", "modal.deletecomment.header": "Odstrániť komentár", "modal.deletecomment.text": "Tento proces je nevratný. <0>Ste si istí?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nenašli sa žiadni používatelia <0>{0}.", "modal.showvotes.query.placeholder": "Vyhľadajte používateľov podľa mena...", "modal.signin.header": "Prihláste sa, aby ste mohli pridávať príspevky a hlasovať", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Poslali sme vám potvrdzovací email s odkazom na aktiváciu vašich stránok.", "page.pendingactivation.text2": "Aktivujte prosím svoju doručenú poštu.", "page.pendingactivation.title": "Váš účet čaká na aktiváciu", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Zanechať komentár", "showpost.discussionpanel.emptymessage": "Zatiaľ sa nikto nevyjadril.", "showpost.label.author": "Pridané <0/> · <1/>", diff --git a/locale/sv-SE/client.json b/locale/sv-SE/client.json index 2096a2fea..56ee466a3 100644 --- a/locale/sv-SE/client.json +++ b/locale/sv-SE/client.json @@ -3,6 +3,7 @@ "action.change": "ändra", "action.close": "Stäng", "action.confirm": "Bekräfta", + "action.copylink": "", "action.delete": "Radera", "action.edit": "Ändra", "action.markallasread": "Markera alla som lästa", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>När du väljer att radera ditt konto kommer vi att radera all din personliga information för evigt. Innehållet du har publicerat kommer att finnas kvar, men det kommer att vara anonymiserat.<1>Denna process är oåterkallelig. <2>Är du säker?", "modal.deletecomment.header": "Radera kommentar", "modal.deletecomment.text": "Denna process är oåterkallelig. <0>Är du säker?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Inga användare hittades som matchar <0>{0}.", "modal.showvotes.query.placeholder": "Sök efter användare med namn...", "modal.signin.header": "Logga in för att skriva inlägg och rösta", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Vi har skickat ett bekräftelsemail med en länk för att aktivera din webbplats.", "page.pendingactivation.text2": "Kontrollera din inkorg för att aktivera den.", "page.pendingactivation.title": "Ditt konto väntar på aktivering", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Skriv en kommentar", "showpost.discussionpanel.emptymessage": "Ingen har kommenterat ännu.", "showpost.label.author": "Skriven av <0/> · <1/>", diff --git a/locale/tr/client.json b/locale/tr/client.json index 00529164e..3d0083f41 100644 --- a/locale/tr/client.json +++ b/locale/tr/client.json @@ -3,6 +3,7 @@ "action.change": "değiştir", "action.close": "Kapat", "action.confirm": "Onayla", + "action.copylink": "", "action.delete": "Sil", "action.edit": "Düzenle", "action.markallasread": "Tümünü Okundu olarak işaretle", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Hesabınızı kaldırdığınız zaman size ait bütün kişisel bilgileri kalıcı olarak sileceğiz. Yayınladığınız öneriler sitede anonim olarak kalmaya devam edecek.<1>Bu geri alınamaz bir işlemdir. <2>Devam etmek istiyor musunuz?", "modal.deletecomment.header": "Yorumu Sil", "modal.deletecomment.text": "Bu geri alınamaz bir işlemdir. <0>Emin misiniz?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Eşleşen kullanıcı bulunamadı <0>{0}.", "modal.showvotes.query.placeholder": "Kullanıcıları ismiyle arayın...", "modal.signin.header": "Öneride bulunmak ve oy vermek için giriş yapın", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Size, sayfanız için aktivasyon bağlantısı barındıran bir onay e-postası gönderdik.", "page.pendingactivation.text2": "Aktivasyon için lütfen gelen kutunuzu kontrol edin.", "page.pendingactivation.title": "Hesabınız aktivasyon beklemektedir", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Yorum yazın", "showpost.discussionpanel.emptymessage": "Henüz hiç kimse yorum yapmadı.", "showpost.label.author": "<0/> · <1/> tarafından gönderildi", From 4b8a7b1e2dbaae59a2e62d57ba8b12b7495f1ac0 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Mon, 7 Oct 2024 13:03:45 +0100 Subject: [PATCH 19/28] No notifications improvements. --- public/components/NotificationIndicator.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 7c2324bc7..9d5686362 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -1,4 +1,5 @@ import "./NotificationIndicator.scss" +import NoDataIllustration from "@fider/assets/images/undraw-empty.svg" import React, { useEffect, useState } from "react" import IconBell from "@fider/assets/images/heroicons-bell.svg" @@ -100,9 +101,14 @@ export const NotificationIndicator = () => { ) : ( -

- No new notifications -

+
+

+ No new notifications +

+ {recent?.length === 0 && ( + + )} +
)} {recent !== undefined && recent?.length > 0 && ( <> From 395a0a27fdc51bf5c9701c486aae4e2f89dc3e9c Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Mon, 7 Oct 2024 13:04:43 +0100 Subject: [PATCH 20/28] Console.logs removed --- public/components/NotificationIndicator.tsx | 1 - public/components/common/Dropdown.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 9d5686362..c15cf96a1 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -14,7 +14,6 @@ import { Trans } from "@lingui/macro" export const NotificationItem = ({ notification }: { notification: Notification }) => { const openNotification = () => { - console.log(notification.link) window.location.href = `/notifications/${notification.id}` } diff --git a/public/components/common/Dropdown.tsx b/public/components/common/Dropdown.tsx index 3493307b9..1f9e5b5ac 100644 --- a/public/components/common/Dropdown.tsx +++ b/public/components/common/Dropdown.tsx @@ -63,7 +63,6 @@ export const Dropdown = (props: DropdownProps) => { const changeToggleState = (newState: boolean) => { setIsOpen(newState) if (props.onToggled) { - console.log("onToggled", newState) props.onToggled(newState) } } From eedd58e106ec8a10d286e93c3a45506e1567ea03 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Mon, 7 Oct 2024 13:18:27 +0100 Subject: [PATCH 21/28] Formatting --- public/components/NotificationIndicator.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index c15cf96a1..c8eb84a86 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -100,14 +100,12 @@ export const NotificationIndicator = () => {
) : ( -
-

- No new notifications -

- {recent?.length === 0 && ( - - )} -
+
+

+ No new notifications +

+ {recent?.length === 0 && } +
)} {recent !== undefined && recent?.length > 0 && ( <> From 941fdb48a25591ef407e1ab787cca7ad0528ae45 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Mon, 7 Oct 2024 19:42:00 +0100 Subject: [PATCH 22/28] More notification spacing tweaks --- public/assets/styles/utility/display.scss | 6 ++---- public/components/NotificationIndicator.scss | 3 +++ public/components/NotificationIndicator.tsx | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/public/assets/styles/utility/display.scss b/public/assets/styles/utility/display.scss index 38ea83e9e..9ef74a062 100644 --- a/public/assets/styles/utility/display.scss +++ b/public/assets/styles/utility/display.scss @@ -149,7 +149,7 @@ border: 0 solid get("colors.gray.100"); border-top-width: 1px; } - .flex-y.flex--divide-#{$i}:not(.no-lastchild-paddingzero) > *:last-child { + .flex-y.flex--divide-#{$i} > *:last-child { padding-bottom: 0; } } @@ -204,10 +204,8 @@ pointer-events: inherit; } - .hover { &:hover { - background-color: get("colors.gray.100") + background-color: get("colors.gray.100"); } } - diff --git a/public/components/NotificationIndicator.scss b/public/components/NotificationIndicator.scss index 12eecac8e..40d9434f1 100644 --- a/public/components/NotificationIndicator.scss +++ b/public/components/NotificationIndicator.scss @@ -17,4 +17,7 @@ .c-notifications-container { max-height: 80vh; overflow-y: auto; + @include media("lg") { + min-width: 400px; + } } diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index c8eb84a86..af4574637 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -18,7 +18,7 @@ export const NotificationItem = ({ notification }: { notification: Notification } return ( - +
@@ -93,7 +93,7 @@ export const NotificationIndicator = () => {

Unread notifications

- + {unread.map((n) => ( ))} @@ -112,7 +112,7 @@ export const NotificationIndicator = () => {

Previous notifications

- + {recent.map((n) => ( ))} From c28b7802da0b4a6094ab1a4d90f3ec0774598f09 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Tue, 8 Oct 2024 08:58:03 +0100 Subject: [PATCH 23/28] More styling, plus "mark all as read" --- public/components/NotificationIndicator.tsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index af4574637..92a6638c6 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -77,6 +77,14 @@ export const NotificationIndicator = () => { } }, [showingNotifications]) + const markAllAsRead = async (e: React.MouseEvent) => { + e.preventDefault() + const response = await actions.markAllAsRead() + if (response.ok) { + location.reload() + } + } + return ( { <> {unread !== undefined && unread?.length > 0 ? ( <> -

+

Unread notifications + {unread.length > 1 && ( + + Mark All as Read + + )}

- + {unread.map((n) => ( ))} @@ -109,10 +122,10 @@ export const NotificationIndicator = () => { )} {recent !== undefined && recent?.length > 0 && ( <> -

+

Previous notifications

- + {recent.map((n) => ( ))} From 24019dded97db07c649c407a2df09e73fcd237fb Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Wed, 9 Oct 2024 10:17:55 +0100 Subject: [PATCH 24/28] Borders in the notifications modal --- public/assets/styles/utility/display.scss | 4 ++++ public/components/NotificationIndicator.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/assets/styles/utility/display.scss b/public/assets/styles/utility/display.scss index 9ef74a062..30ca95ec8 100644 --- a/public/assets/styles/utility/display.scss +++ b/public/assets/styles/utility/display.scss @@ -183,6 +183,10 @@ visibility: hidden; } +.bt { + border-top: 1px solid; +} + .overflow-scroll { overflow: scroll; } diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 92a6638c6..e2084809b 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -122,7 +122,7 @@ export const NotificationIndicator = () => { )} {recent !== undefined && recent?.length > 0 && ( <> -

+

Previous notifications

From c88d58d14d1f3a829f0424df84ef34dd13b790a5 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Thu, 10 Oct 2024 08:46:02 +0100 Subject: [PATCH 25/28] Show posts mobile view. --- public/pages/ShowPost/ShowPost.page.scss | 28 ++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/public/pages/ShowPost/ShowPost.page.scss b/public/pages/ShowPost/ShowPost.page.scss index 1a4870c1d..a23a0f93c 100644 --- a/public/pages/ShowPost/ShowPost.page.scss +++ b/public/pages/ShowPost/ShowPost.page.scss @@ -5,6 +5,23 @@ flex-grow: 1; } + .p-show-post { + &__main-col { + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + margin-bottom: spacing(4); + } + + &__action-col { + > :first-child { + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + } + } + } + @include media("lg") { .p-show-post { display: grid; @@ -17,20 +34,9 @@ &__main-col { grid-area: Main; - background-color: get("colors.white"); - padding: spacing(4); - border-radius: get("border.radius.large"); - } - - &__header-col { } &__action-col { - > :first-child { - background-color: get("colors.white"); - padding: spacing(4); - border-radius: get("border.radius.large"); - } grid-area: Action; } } From 4477936be443a322f70c2a2fd68731ba44809f8f Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Thu, 10 Oct 2024 08:49:20 +0100 Subject: [PATCH 26/28] Small tweaks to the powered by link --- public/components/common/PoweredByFider.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/components/common/PoweredByFider.scss b/public/components/common/PoweredByFider.scss index 8b5bc3582..a2693d84e 100644 --- a/public/components/common/PoweredByFider.scss +++ b/public/components/common/PoweredByFider.scss @@ -4,8 +4,8 @@ text-align: center; a { - color: get("colors.gray.700"); - font-size: 11px; + color: get("colors.blue.700"); + font-size: 12px; } a:hover { color: get("colors.gray.900"); From 064e252ab46594ff549e0a6e75407008b61024d4 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Thu, 10 Oct 2024 11:31:10 +0100 Subject: [PATCH 27/28] Changed how google fonts are included. --- app/pkg/web/testdata/basic.html | 4 +++- app/pkg/web/testdata/canonical.html | 4 +++- app/pkg/web/testdata/chunk.html | 4 +++- app/pkg/web/testdata/home.html | 4 +++- app/pkg/web/testdata/home_ssr.html | 4 +++- app/pkg/web/testdata/oauth.html | 4 +++- app/pkg/web/testdata/tenant.html | 4 +++- app/pkg/web/testdata/user.html | 4 +++- views/base.html | 4 +++- 9 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/pkg/web/testdata/basic.html b/app/pkg/web/testdata/basic.html index d42c68ffc..d5fa504ff 100755 --- a/app/pkg/web/testdata/basic.html +++ b/app/pkg/web/testdata/basic.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/canonical.html b/app/pkg/web/testdata/canonical.html index 54d1e8623..81b1e2040 100755 --- a/app/pkg/web/testdata/canonical.html +++ b/app/pkg/web/testdata/canonical.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/chunk.html b/app/pkg/web/testdata/chunk.html index ebda0cc9d..ab125af24 100644 --- a/app/pkg/web/testdata/chunk.html +++ b/app/pkg/web/testdata/chunk.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/home.html b/app/pkg/web/testdata/home.html index 02b6d84ee..3fe3afec8 100755 --- a/app/pkg/web/testdata/home.html +++ b/app/pkg/web/testdata/home.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/home_ssr.html b/app/pkg/web/testdata/home_ssr.html index 9fff8aae3..52729866a 100755 --- a/app/pkg/web/testdata/home_ssr.html +++ b/app/pkg/web/testdata/home_ssr.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/oauth.html b/app/pkg/web/testdata/oauth.html index 5a1cc2c8d..fab7303d8 100755 --- a/app/pkg/web/testdata/oauth.html +++ b/app/pkg/web/testdata/oauth.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/tenant.html b/app/pkg/web/testdata/tenant.html index f2f245be2..8503fd045 100755 --- a/app/pkg/web/testdata/tenant.html +++ b/app/pkg/web/testdata/tenant.html @@ -6,7 +6,9 @@ - + + + diff --git a/app/pkg/web/testdata/user.html b/app/pkg/web/testdata/user.html index d8246793a..b98c6fa06 100755 --- a/app/pkg/web/testdata/user.html +++ b/app/pkg/web/testdata/user.html @@ -6,7 +6,9 @@ - + + + diff --git a/views/base.html b/views/base.html index 435b579d9..c70b52e4f 100644 --- a/views/base.html +++ b/views/base.html @@ -6,7 +6,9 @@ - + + + {{ if .private.canonicalURL }} {{ end }} From 91bdc053bc93aa942091cdd11c2c8e3d44411ccc Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Thu, 10 Oct 2024 11:36:58 +0100 Subject: [PATCH 28/28] Order notifications by date desc --- app/services/sqlstore/postgres/notification.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/sqlstore/postgres/notification.go b/app/services/sqlstore/postgres/notification.go index 473a9fce2..f5f724b10 100644 --- a/app/services/sqlstore/postgres/notification.go +++ b/app/services/sqlstore/postgres/notification.go @@ -108,6 +108,7 @@ func getActiveNotifications(ctx context.Context, q *query.GetActiveNotifications LEFT JOIN users u ON u.id = n.author_id WHERE n.tenant_id = $1 AND n.user_id = $2 AND (n.read = false OR n.updated_at > CURRENT_DATE - INTERVAL '30 days') + ORDER BY n.updated_at DESC `, tenant.ID, user.ID) if err != nil { return errors.Wrap(err, "failed to get active notifications")