diff --git a/src/components/Article/Comment.module.scss b/src/components/Article/Comment.module.scss
index 7a48dec2..786fe41d 100644
--- a/src/components/Article/Comment.module.scss
+++ b/src/components/Article/Comment.module.scss
@@ -150,7 +150,6 @@
}
.commentAuthor,
-.commentDate,
.commentRating {
@include font-size(1.2rem);
}
@@ -161,11 +160,30 @@
margin-right: 12px;
}
-.commentDate {
- color: rgb(0 0 0 / 30%);
+.commentDates {
flex: 1;
- @include media-breakpoint-down(md) {
- margin-left: 1rem;
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+ justify-content: flex-start;
+ color: rgba(0, 0, 0, 0.3);
+ font-size: 1.2rem;
+ margin-bottom: 4px;
+ color: rgb(0 0 0 / 30%);
+ @include font-size(1.2rem);
+
+ .date {
+ .icon {
+ line-height: 1;
+ width: 1rem;
+ display: inline-block;
+ opacity: 0.6;
+ margin-right: 0.5rem;
+ vertical-align: middle;
+ }
+ @include media-breakpoint-down(md) {
+ margin-left: 1rem;
+ }
}
}
diff --git a/src/components/Article/Comment.tsx b/src/components/Article/Comment.tsx
index 2c0b7045..c108895e 100644
--- a/src/components/Article/Comment.tsx
+++ b/src/components/Article/Comment.tsx
@@ -1,21 +1,17 @@
import styles from './Comment.module.scss'
import { Icon } from '../_shared/Icon'
import { AuthorCard } from '../Author/Card'
-import { Show, createMemo, createSignal, For } from 'solid-js'
+import { Show, createMemo, createSignal, For, lazy, Suspense } from 'solid-js'
import { clsx } from 'clsx'
import type { Author, Reaction } from '../../graphql/types.gen'
import { t } from '../../utils/intl'
-import { createReaction, deleteReaction } from '../../stores/zine/reactions'
+import { createReaction, deleteReaction, updateReaction } from '../../stores/zine/reactions'
import MD from './MD'
import { formatDate } from '../../utils'
-import { SharePopup } from './SharePopup'
-import stylesHeader from '../Nav/Header.module.scss'
import Userpic from '../Author/Userpic'
import { useSession } from '../../context/session'
import { ReactionKind } from '../../graphql/types.gen'
-import CommentEditor from '../_shared/CommentEditor'
-import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
-import { getDescription } from '../../utils/meta'
+const CommentEditor = lazy(() => import('../_shared/CommentEditor'))
type Props = {
comment: Reaction
@@ -27,7 +23,7 @@ type Props = {
export const Comment = (props: Props) => {
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
const [loading, setLoading] = createSignal(false)
- const [submitted, setSubmitted] = createSignal(false)
+ const [editMode, setEditMode] = createSignal(false)
const { session } = useSession()
const canEdit = createMemo(() => props.comment.createdBy?.slug === session()?.user?.slug)
@@ -61,16 +57,33 @@ export const Comment = (props: Props) => {
}
)
setIsReplyVisible(false)
- setSubmitted(true)
setLoading(false)
} catch (error) {
console.error('[handleCreate reaction]:', error)
}
}
- const formattedDate = createMemo(() =>
- formatDate(new Date(comment()?.createdAt), { hour: 'numeric', minute: 'numeric' })
- )
+ const formattedDate = (date) =>
+ createMemo(() => formatDate(new Date(date), { hour: 'numeric', minute: 'numeric' }))
+
+ const toggleEditMode = () => {
+ setEditMode((oldEditMode) => !oldEditMode)
+ }
+
+ const handleUpdate = async (value) => {
+ setLoading(true)
+ try {
+ await updateReaction(props.comment.id, {
+ kind: ReactionKind.Comment,
+ body: value,
+ shout: props.comment.shout.id
+ })
+ setEditMode(false)
+ setLoading(false)
+ } catch (error) {
+ console.error('[handleCreate reaction]:', error)
+ }
+ }
return (
}>
+ handleCreate(value)} />
+
diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx
index 67eb9f77..5092b0b6 100644
--- a/src/components/Article/CommentsTree.tsx
+++ b/src/components/Article/CommentsTree.tsx
@@ -1,4 +1,4 @@
-import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
+import { Show, createMemo, createSignal, onMount, For } from 'solid-js'
import Comment from './Comment'
import { t } from '../../utils/intl'
import styles from '../../styles/Article.module.scss'
@@ -11,6 +11,7 @@ import { Author, ReactionKind } from '../../graphql/types.gen'
import { useSession } from '../../context/session'
import CommentEditor from '../_shared/CommentEditor'
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
+import Button from '../_shared/Button'
const ARTICLE_COMMENTS_PAGE_SIZE = 50
const MAX_COMMENT_LEVEL = 6
@@ -27,9 +28,11 @@ export const CommentsTree = (props: Props) => {
const [isCommentsLoading, setIsCommentsLoading] = createSignal(false)
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const { sortedReactions, loadReactionsBy } = useReactionsStore()
+
const reactions = createMemo(() =>
sortedReactions().sort(commentsOrder() === 'rating' ? byStat('rating') : byCreated)
)
+
const { session } = useSession()
const loadMore = async () => {
try {
@@ -85,26 +88,22 @@ export const CommentsTree = (props: Props) => {
@@ -128,7 +127,7 @@ export const CommentsTree = (props: Props) => {
handleSubmitComment(value)}
/>
diff --git a/src/components/_shared/Button/Button.module.scss b/src/components/_shared/Button/Button.module.scss
index f1e08220..50e510d7 100644
--- a/src/components/_shared/Button/Button.module.scss
+++ b/src/components/_shared/Button/Button.module.scss
@@ -31,6 +31,19 @@
}
}
+ &.inline {
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 21px;
+ color: #696969;
+
+ &.hover,
+ &.active {
+ text-decoration: underline;
+ color: #141414;
+ }
+ }
+
&:disabled,
&:disabled:hover {
cursor: default;
diff --git a/src/components/_shared/Button/Button.tsx b/src/components/_shared/Button/Button.tsx
index 109f3783..5a3fb3fa 100644
--- a/src/components/_shared/Button/Button.tsx
+++ b/src/components/_shared/Button/Button.tsx
@@ -5,7 +5,7 @@ import styles from './Button.module.scss'
type Props = {
value: string | JSX.Element
size?: 'S' | 'M' | 'L'
- variant?: 'primary' | 'secondary'
+ variant?: 'primary' | 'secondary' | 'inline'
type?: 'submit' | 'button'
loading?: boolean
disabled?: boolean
diff --git a/src/components/_shared/CommentEditor/CommentEditor.tsx b/src/components/_shared/CommentEditor/CommentEditor.tsx
index de857fc1..21175293 100644
--- a/src/components/_shared/CommentEditor/CommentEditor.tsx
+++ b/src/components/_shared/CommentEditor/CommentEditor.tsx
@@ -8,7 +8,7 @@ import { t } from '../../../utils/intl'
import { schema } from './schema'
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
-import { DOMSerializer } from 'prosemirror-model'
+import { DOMParser as ProseDOMParser, DOMSerializer } from 'prosemirror-model'
import { renderGrouped } from 'prosemirror-menu'
import { buildMenuItems } from './menu'
import { keymap } from 'prosemirror-keymap'
@@ -20,9 +20,10 @@ import { useSession } from '../../../context/session'
import { showModal } from '../../../stores/ui'
type Props = {
- initialValue: string
+ placeholder?: string
onSubmit: (value: string) => void
clear?: boolean
+ initialContent?: string
}
const htmlContainer = typeof document === 'undefined' ? null : document.createElement('div')
@@ -37,14 +38,19 @@ const CommentEditor = (props: Props) => {
const editorElRef: { current: HTMLDivElement } = { current: null }
const menuElRef: { current: HTMLDivElement } = { current: null }
const editorViewRef: { current: EditorView } = { current: null }
+
+ const domNew = new DOMParser().parseFromString(`${props.initialContent}
`, 'text/xml')
+ const doc = ProseDOMParser.fromSchema(schema).parse(domNew)
+
const initEditor = () => {
editorViewRef.current = new EditorView(editorElRef.current, {
state: EditorState.create({
schema,
+ doc: props.initialContent ? doc : null,
plugins: [
history(),
customKeymap(),
- placeholder(props.initialValue),
+ placeholder(props.placeholder),
keymap({ 'Mod-z': undo, 'Mod-y': redo }),
keymap(baseKeymap)
]
diff --git a/src/graphql/mutation/reaction-destroy.ts b/src/graphql/mutation/reaction-destroy.ts
index 8be2fa78..abc1bf05 100644
--- a/src/graphql/mutation/reaction-destroy.ts
+++ b/src/graphql/mutation/reaction-destroy.ts
@@ -1,8 +1,8 @@
import { gql } from '@urql/core'
export default gql`
- mutation DeleteReactionMutation($reaction: Int!) {
- deleteReaction(reaction: $reaction) {
+ mutation DeleteReactionMutation($id: Int!) {
+ deleteReaction(id: $id) {
error
reaction {
id
diff --git a/src/graphql/mutation/reaction-update.ts b/src/graphql/mutation/reaction-update.ts
index 325e96e8..c9650ae5 100644
--- a/src/graphql/mutation/reaction-update.ts
+++ b/src/graphql/mutation/reaction-update.ts
@@ -1,32 +1,13 @@
import { gql } from '@urql/core'
export default gql`
- mutation UpdateReactionMutation($reaction: ReactionInput!) {
- updateReaction(reaction: $reaction) {
+ mutation UpdateReactionMutation($id: Int!, $reaction: ReactionInput!) {
+ updateReaction(id: $id, reaction: $reaction) {
error
reaction {
- id
- createdBy {
- slug
- name
- userpic
- }
body
- kind
- range
- createdAt
updatedAt
- shout
- replyTo {
- id
- createdBy {
- slug
- userpic
- name
- }
- body
- kind
- }
+ replyTo
}
}
}
diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts
index 620d5f56..94cb09eb 100644
--- a/src/graphql/types.gen.ts
+++ b/src/graphql/types.gen.ts
@@ -537,11 +537,13 @@ export enum ReactionKind {
Disagree = 'DISAGREE',
Dislike = 'DISLIKE',
Disproof = 'DISPROOF',
+ Footnote = 'FOOTNOTE',
Like = 'LIKE',
Proof = 'PROOF',
Propose = 'PROPOSE',
Quote = 'QUOTE',
- Reject = 'REJECT'
+ Reject = 'REJECT',
+ Remark = 'REMARK'
}
export enum ReactionStatus {
@@ -656,12 +658,9 @@ export type Stat = {
}
export type Subscription = {
- collabUpdate?: Maybe
newMessage?: Maybe
-}
-
-export type SubscriptionCollabUpdateArgs = {
- collab: Scalars['Int']
+ newReaction?: Maybe
+ newShout?: Maybe
}
export type Token = {
diff --git a/src/locales/ru.json b/src/locales/ru.json
index cd78234d..b086056e 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -17,6 +17,7 @@
"By name": "По имени",
"By popularity": "По популярности",
"By rating": "По популярности",
+ "By time": "По времени",
"By relevance": "По релевантности",
"By shouts": "По публикациям",
"By signing up you agree with our": "Регистрируясь, вы соглашаетесь с",
@@ -223,6 +224,8 @@
"Add comment": "Комментировать",
"My subscriptions": "Подписки",
"Nothing here yet": "Здесь пока ничего нет",
+ "Edited": "Отредактирован",
+ "Nothing here yet": "Здесь пока ничего нет",
"Invite experts": "Пригласить экспертов",
"Subscribe to comments": "Подписаться на комментарии",
"Add to bookmarks": "Добавить в закладки",
diff --git a/src/stores/zine/reactions.ts b/src/stores/zine/reactions.ts
index 6f50d75c..be479ce3 100644
--- a/src/stores/zine/reactions.ts
+++ b/src/stores/zine/reactions.ts
@@ -1,6 +1,6 @@
import type { Reaction, ReactionInput } from '../../graphql/types.gen'
import { apiClient } from '../../utils/apiClient'
-import { createSignal } from 'solid-js'
+import { createEffect, createSignal } from 'solid-js'
// TODO: import { roomConnect } from '../../utils/p2p'
export const REACTIONS_AMOUNT_PER_PAGE = 100
@@ -34,15 +34,21 @@ export const createReaction = async (
setSortedReactions((prev) => [...prev, reaction])
}
-export const deleteReaction = async (reactionId: number) => {
- const reaction = await apiClient.destroyReaction(reactionId)
+export const deleteReaction = async (id: number) => {
+ const reaction = await apiClient.destroyReaction(id)
console.debug('[deleteReaction]:', reaction.reaction.id)
setSortedReactions(sortedReactions().filter((item) => item.id !== reaction.reaction.id))
}
-export const updateReaction = async (reaction: Reaction) => {
- const { reaction: r } = await apiClient.updateReaction({ reaction })
- return r
+export const updateReaction = async (id: number, input: ReactionInput) => {
+ const reaction = await apiClient.updateReaction(id, input)
+ const editedReactionIndex = sortedReactions().findIndex((r) => r.id === id)
+ const newSortedReactions = [...sortedReactions()]
+ newSortedReactions[editedReactionIndex] = {
+ ...newSortedReactions[editedReactionIndex],
+ ...reaction
+ }
+ setSortedReactions(newSortedReactions)
}
export const useReactionsStore = () => {
diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts
index 39c405fc..8d805bc4 100644
--- a/src/utils/apiClient.ts
+++ b/src/utils/apiClient.ts
@@ -237,14 +237,16 @@ export const apiClient = {
return response.data.createReaction.reaction
},
destroyReaction: async (id: number) => {
- const response = await privateGraphQLClient.mutation(reactionDestroy, { reaction: id }).toPromise()
+ const response = await privateGraphQLClient.mutation(reactionDestroy, { id: id }).toPromise()
console.debug('[destroyReaction]:', response)
return response.data.deleteReaction
},
- updateReaction: async (reaction) => {
- const response = await privateGraphQLClient.mutation(reactionUpdate, reaction).toPromise()
-
- return response.data.createReaction
+ updateReaction: async (id: number, input: ReactionInput) => {
+ const response = await privateGraphQLClient
+ .mutation(reactionUpdate, { id: id, reaction: input })
+ .toPromise()
+ console.debug('[updateReaction]:', response)
+ return response.data.updateReaction.reaction
},
getAuthorsBy: async (options: QueryLoadAuthorsByArgs) => {
const resp = await publicGraphQLClient.query(authorsLoadBy, options).toPromise()