This commit is contained in:
Untone 2023-10-16 21:00:22 +03:00
commit 12e5743d24
23 changed files with 191 additions and 103 deletions

View File

@ -28,6 +28,8 @@
"All posts": "All posts", "All posts": "All posts",
"All topics": "All topics", "All topics": "All topics",
"Almost done! Check your email.": "Almost done! Just checking your email.", "Almost done! Check your email.": "Almost done! Just checking your email.",
"Are you sure you want to delete this comment?": "Are you sure you want to delete this comment?",
"Are you sure you want to delete this draft?": "Are you sure you want to delete this draft?",
"Are you sure you want to to proceed the action?": "Are you sure you want to to proceed the action?", "Are you sure you want to to proceed the action?": "Are you sure you want to to proceed the action?",
"Art": "Art", "Art": "Art",
"Artist": "Artist", "Artist": "Artist",
@ -100,6 +102,7 @@
"Discussion rules": "Discussion rules", "Discussion rules": "Discussion rules",
"Discussions": "Discussions", "Discussions": "Discussions",
"Dogma": "Dogma", "Dogma": "Dogma",
"Draft successfully deleted": "Draft successfully deleted",
"Drafts": "Drafts", "Drafts": "Drafts",
"Drag the image to this area": "Drag the image to this area", "Drag the image to this area": "Drag the image to this area",
"Each image must be no larger than 5 MB.": "Each image must be no larger than 5 MB.", "Each image must be no larger than 5 MB.": "Each image must be no larger than 5 MB.",
@ -193,6 +196,7 @@
"Manifesto": "Manifesto", "Manifesto": "Manifesto",
"Many files, choose only one": "Many files, choose only one", "Many files, choose only one": "Many files, choose only one",
"Material card": "Material card", "Material card": "Material card",
"Message": "Message",
"More": "More", "More": "More",
"Most commented": "Commented", "Most commented": "Commented",
"Most read": "Readable", "Most read": "Readable",
@ -206,12 +210,19 @@
"New only": "New only", "New only": "New only",
"New password": "New password", "New password": "New password",
"New stories every day and even more!": "New stories and more are waiting for you every day!", "New stories every day and even more!": "New stories and more are waiting for you every day!",
"NewCommentNotificationText": "{commentsCount, plural, one {New comment} other {{commentsCount} comments}} to your publication {shoutTitle} from {lastCommenterName}{restUsersCount, plural, =0 {} one { one more user} other { and more {restUsersCount} users}}",
"NewReplyNotificationText": "{commentsCount, plural, one {New reply} other {{commentsCount} replays} other {{commentsCount} новых ответов}} to your publication {shoutTitle} от {lastCommenterName}{restUsersCount, plural, =0 {} one { and one more user} other { and more {restUsersCount} users}}", "NotificationNewCommentText1": "{commentsCount, plural, one {New comment} other {{commentsCount} comments}} to your publication",
"NotificationNewCommentText2": "from",
"NotificationNewCommentText3": "{restUsersCount, plural, =0 {} one { one more user} other { and more {restUsersCount} users}}",
"NotificationNewReplyText1": "{commentsCount, plural, one {New reply} other {{commentsCount} replays}} to your publication",
"NotificationNewReplyText2": "from",
"NotificationNewReplyText3": "{restUsersCount, plural, =0 {} one { and one more user} other { and more {restUsersCount} users}}",
"Newsletter": "Newsletter", "Newsletter": "Newsletter",
"Night mode": "Night mode", "Night mode": "Night mode",
"No notifications, yet": "No notifications, yet", "No notifications yet": "No notifications yet",
"No such account, please try to register": "No such account found, please try to register", "Write good articles, comment\nand it won't be so empty here": "Write good articles, comment\nand it won't be so empty here",
"Nothing here yet": "There's nothing here yet", "Nothing here yet": "There's nothing here yet",
"Nothing is here": "There is nothing here", "Nothing is here": "There is nothing here",
"Notifications": "Notifications", "Notifications": "Notifications",
@ -353,7 +364,6 @@
"Where": "From", "Where": "From",
"Words": "Слов", "Words": "Слов",
"Work with us": "Cooperate with Discourse", "Work with us": "Cooperate with Discourse",
"Message": "Message",
"Write a comment...": "Write a comment...", "Write a comment...": "Write a comment...",
"Write a short introduction": "Write a short introduction", "Write a short introduction": "Write a short introduction",
"Write about the topic": "Write about the topic", "Write about the topic": "Write about the topic",

View File

@ -31,6 +31,8 @@
"All posts": "Все публикации", "All posts": "Все публикации",
"All topics": "Все темы", "All topics": "Все темы",
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.", "Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
"Are you sure you want to delete this comment?": "Уверены, что хотите удалить этот комментарий?",
"Are you sure you want to delete this draft?": "Уверены, что хотите удалить этот черновик?",
"Are you sure you want to to proceed the action?": "Вы уверены, что хотите продолжить?", "Are you sure you want to to proceed the action?": "Вы уверены, что хотите продолжить?",
"Art": "Искусство", "Art": "Искусство",
"Artist": "Исполнитель", "Artist": "Исполнитель",
@ -104,6 +106,7 @@
"Discussion rules": "Правила сообществ самиздата в соцсетях", "Discussion rules": "Правила сообществ самиздата в соцсетях",
"Discussions": "Дискуссии", "Discussions": "Дискуссии",
"Dogma": "Догма", "Dogma": "Догма",
"Draft successfully deleted": "Черновик успешно удален",
"Drafts": "Черновики", "Drafts": "Черновики",
"Drag the image to this area": "Перетащите изображение в эту область", "Drag the image to this area": "Перетащите изображение в эту область",
"Each image must be no larger than 5 MB.": "Каждое изображение должно быть размером не больше 5 мб.", "Each image must be no larger than 5 MB.": "Каждое изображение должно быть размером не больше 5 мб.",
@ -217,11 +220,19 @@
"New only": "Только новые", "New only": "Только новые",
"New password": "Новый пароль", "New password": "Новый пароль",
"New stories every day and even more!": "Каждый день вас ждут новые истории и ещё много всего интересного!", "New stories every day and even more!": "Каждый день вас ждут новые истории и ещё много всего интересного!",
"NewCommentNotificationText": "{commentsCount, plural, one {Новый комментарий} few {{commentsCount} новых комментария} other {{commentsCount} новых комментариев}} к вашей публикации {shoutTitle} от {lastCommenterName}{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
"NewReplyNotificationText": "{commentsCount, plural, one {Новый ответ} few {{commentsCount} новых ответа} other {{commentsCount} новых ответов}} к вашему комментарию к публикации {shoutTitle} от {lastCommenterName}{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}", "NotificationNewCommentText1": "{commentsCount, plural, one {Новый комментарий} few {{commentsCount} новых комментария} other {{commentsCount} новых комментариев}} к вашей публикации",
"NotificationNewCommentText2": "от",
"NotificationNewCommentText3": "{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
"NotificationNewReplyText1": "{commentsCount, plural, one {Новый ответ} few {{commentsCount} новых ответа} other {{commentsCount} новых ответов}} к вашему комментарию к публикации",
"NotificationNewReplyText2": "от",
"NotificationNewReplyText3": "{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
"Newsletter": "Рассылка", "Newsletter": "Рассылка",
"Night mode": "Ночная тема", "Night mode": "Ночная тема",
"No notifications, yet": "Тут пока пусто", "No notifications yet": "Уведомлений пока нет",
"Write good articles, comment\nand it won't be so empty here": "Пишите хорошие статьи, комментируйте,\nи здесь станет не так пусто",
"No such account, please try to register": "Такой адрес не найден, попробуйте зарегистрироваться", "No such account, please try to register": "Такой адрес не найден, попробуйте зарегистрироваться",
"Nothing here yet": "Здесь пока ничего нет", "Nothing here yet": "Здесь пока ничего нет",
"Nothing is here": "Здесь ничего нет", "Nothing is here": "Здесь ничего нет",

View File

@ -62,7 +62,12 @@ export const Comment = (props: Props) => {
const remove = async () => { const remove = async () => {
if (comment()?.id) { if (comment()?.id) {
try { try {
const isConfirmed = await showConfirm() const isConfirmed = await showConfirm({
confirmBody: t('Are you sure you want to delete this comment?'),
confirmButtonLabel: t('Delete'),
confirmButtonVariant: 'danger',
declineButtonVariant: 'primary'
})
if (isConfirmed) { if (isConfirmed) {
await deleteReaction(comment().id) await deleteReaction(comment().id)
@ -136,7 +141,7 @@ export const Comment = (props: Props) => {
})} })}
/> />
<small> <small>
<a href={`#comment-${comment()?.id}`}>{comment()?.shout.title || ''}</a> <a href={`#comment_${comment()?.id}`}>{comment()?.shout.title || ''}</a>
</small> </small>
</div> </div>
} }
@ -174,7 +179,7 @@ export const Comment = (props: Props) => {
<CommentRatingControl comment={comment()} /> <CommentRatingControl comment={comment()} />
</div> </div>
</Show> </Show>
<div class={styles.commentBody} id={'comment-' + (comment().id || '')}> <div class={styles.commentBody}>
<Show when={editMode()} fallback={<MD body={body()} />}> <Show when={editMode()} fallback={<MD body={body()} />}>
<Suspense fallback={<p>{t('Loading')}</p>}> <Suspense fallback={<p>{t('Loading')}</p>}>
<SimplifiedEditor <SimplifiedEditor

View File

@ -1,4 +1,4 @@
import { Show, createMemo, createSignal, onMount, For, createEffect } from 'solid-js' import { Show, createMemo, createSignal, onMount, For } from 'solid-js'
import { Comment } from './Comment' import { Comment } from './Comment'
import styles from './Article.module.scss' import styles from './Article.module.scss'
import { clsx } from 'clsx' import { clsx } from 'clsx'
@ -181,7 +181,7 @@ export const CommentsTree = (props: Props) => {
<SimplifiedEditor <SimplifiedEditor
quoteEnabled={true} quoteEnabled={true}
imageEnabled={true} imageEnabled={true}
autoFocus={true} autoFocus={false}
submitByCtrlEnter={true} submitByCtrlEnter={true}
placeholder={t('Write a comment...')} placeholder={t('Write a comment...')}
onSubmit={(value) => handleSubmitComment(value)} onSubmit={(value) => handleSubmitComment(value)}

View File

@ -28,11 +28,24 @@ import styles from './Article.module.scss'
import { CardTopic } from '../Feed/CardTopic' import { CardTopic } from '../Feed/CardTopic'
import { createPopper } from '@popperjs/core' import { createPopper } from '@popperjs/core'
interface Props { type Props = {
article: Shout article: Shout
scrollToComments?: boolean scrollToComments?: boolean
} }
export type ArticlePageSearchParams = {
scrollTo: 'comments'
commentId: string
}
const scrollTo = (el: HTMLElement) => {
window.scrollTo({
top: el.offsetTop - 96,
left: 0,
behavior: 'smooth'
})
}
export const FullArticle = (props: Props) => { export const FullArticle = (props: Props) => {
const { t } = useLocalize() const { t } = useLocalize()
const { const {
@ -78,15 +91,12 @@ export const FullArticle = (props: Props) => {
}) })
const commentsRef: { current: HTMLDivElement } = { current: null } const commentsRef: { current: HTMLDivElement } = { current: null }
const scrollToComments = () => { const scrollToComments = () => {
window.scrollTo({ scrollTo(commentsRef.current)
top: commentsRef.current.offsetTop - 96,
left: 0,
behavior: 'smooth'
})
} }
const { searchParams, changeSearchParam } = useRouter() const { searchParams, changeSearchParam } = useRouter<ArticlePageSearchParams>()
createEffect(() => { createEffect(() => {
if (props.scrollToComments) { if (props.scrollToComments) {
@ -105,9 +115,12 @@ export const FullArticle = (props: Props) => {
createEffect(() => { createEffect(() => {
if (searchParams().commentId && isReactionsLoaded()) { if (searchParams().commentId && isReactionsLoaded()) {
const commentElement = document.querySelector(`[id='comment_${searchParams().commentId}']`) const commentElement = document.querySelector<HTMLElement>(
`[id='comment_${searchParams().commentId}']`
)
changeSearchParam({ commentId: null })
if (commentElement) { if (commentElement) {
commentElement.scrollIntoView({ behavior: 'smooth' }) scrollTo(commentElement)
} }
} }
}) })

View File

@ -35,11 +35,16 @@ export const Draft = (props: Props) => {
const handleDeleteLinkClick = async (e) => { const handleDeleteLinkClick = async (e) => {
e.preventDefault() e.preventDefault()
const isConfirmed = await showConfirm() const isConfirmed = await showConfirm({
confirmBody: t('Are you sure you want to delete this draft?'),
confirmButtonLabel: t('Delete'),
confirmButtonVariant: 'danger',
declineButtonVariant: 'primary'
})
if (isConfirmed) { if (isConfirmed) {
props.onDelete(props.shout) props.onDelete(props.shout)
await showSnackbar({ type: 'success', body: t('Success') }) await showSnackbar({ body: t('Draft successfully deleted') })
} }
} }

View File

@ -7,7 +7,6 @@ import formattedTime from '../../utils/formatDateTime'
import { Icon } from '../_shared/Icon' import { Icon } from '../_shared/Icon'
import { MessageActionsPopup } from './MessageActionsPopup' import { MessageActionsPopup } from './MessageActionsPopup'
import QuotedMessage from './QuotedMessage' import QuotedMessage from './QuotedMessage'
import MD from '../Article/MD'
type Props = { type Props = {
content: MessageType content: MessageType

View File

@ -1,48 +1,22 @@
.confirmModal { .confirmModal {
background: #fff;
min-height: 550px;
position: relative; position: relative;
@include media-breakpoint-up(md) { .confirmModalTitle {
min-height: 710px; @include font-size(2rem);
}
}
.confirmModalTitle {
font-size: 26px;
line-height: 32px;
font-weight: 700; font-weight: 700;
color: #141414; color: var(--default-color);
text-align: left; text-align: center;
} }
.confirmModalActions { .confirmModalActions {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-top: 16px; margin-top: 4rem;
} gap: 2rem;
.confirmModalButton { .confirmAction {
display: block; flex: 1;
width: 100%; }
margin-right: 12px;
font-weight: 700;
margin-top: 32px;
padding: 1.6rem !important;
border: 1px solid black;
&:hover {
background-color: rgb(0 0 0 / 8%);
}
}
.confirmModalButtonPrimary {
margin-right: 0;
background-color: black;
color: white;
border: none;
&:hover {
background-color: rgb(0 0 0 / 60%);
} }
} }

View File

@ -1,7 +1,7 @@
import { clsx } from 'clsx'
import { useConfirm } from '../../../context/confirm' import { useConfirm } from '../../../context/confirm'
import styles from './ConfirmModal.module.scss'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { Button } from '../../_shared/Button'
import styles from './ConfirmModal.module.scss'
export const ConfirmModal = () => { export const ConfirmModal = () => {
const { t } = useLocalize() const { t } = useLocalize()
@ -12,21 +12,26 @@ export const ConfirmModal = () => {
} = useConfirm() } = useConfirm()
return ( return (
<div> <div class={styles.confirmModal}>
<h4 class={styles.confirmModalTitle}> <h4 class={styles.confirmModalTitle}>
{confirmMessage().confirmBody ?? t('Are you sure you want to to proceed the action?')} {confirmMessage().confirmBody ?? t('Are you sure you want to to proceed the action?')}
</h4> </h4>
<div class={styles.confirmModalActions}> <div class={styles.confirmModalActions}>
<button class={styles.confirmModalButton} onClick={() => resolveConfirm(false)}> <Button
{confirmMessage().declineButtonLabel ?? t('Decline')} onClick={() => resolveConfirm(false)}
</button> value={confirmMessage().declineButtonLabel ?? t('Decline')}
<button size="L"
class={clsx(styles.confirmModalButton, styles.confirmModalButtonPrimary)} variant={confirmMessage().declineButtonVariant ?? 'secondary'}
class={styles.confirmAction}
/>
<Button
onClick={() => resolveConfirm(true)} onClick={() => resolveConfirm(true)}
> value={confirmMessage().confirmButtonLabel ?? t('Confirm')}
{confirmMessage().confirmButtonLabel ?? t('Confirm')} size="L"
</button> variant={confirmMessage().confirmButtonVariant ?? 'primary'}
class={styles.confirmAction}
/>
</div> </div>
</div> </div>
) )

View File

@ -67,7 +67,7 @@ export const Header = (props: Props) => {
let windowScrollTop = 0 let windowScrollTop = 0
createEffect(() => { createEffect(() => {
const mainContent = document.querySelector('.main-content') as HTMLDivElement const mainContent = document.querySelector<HTMLDivElement>('.main-content')
if (fixed() || modal() !== null) { if (fixed() || modal() !== null) {
windowScrollTop = window.scrollY windowScrollTop = window.scrollY

View File

@ -71,8 +71,8 @@
} }
.close { .close {
right: 3.6rem; right: 1.6rem;
top: 12px; top: 1.6rem;
} }
} }
} }

View File

@ -1,4 +1,4 @@
import { createEffect, createMemo, createSignal, on, Show } from 'solid-js' import { createEffect, createMemo, createSignal, Show } from 'solid-js'
import type { JSX } from 'solid-js' import type { JSX } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { hideModal, useModalStore } from '../../../stores/ui' import { hideModal, useModalStore } from '../../../stores/ui'
@ -8,7 +8,6 @@ import styles from './Modal.module.scss'
import { redirectPage } from '@nanostores/router' import { redirectPage } from '@nanostores/router'
import { router } from '../../../stores/router' import { router } from '../../../stores/router'
import { Icon } from '../../_shared/Icon' import { Icon } from '../../_shared/Icon'
import { resetSortedArticles } from '../../../stores/zine/articles'
interface Props { interface Props {
name: string name: string

View File

@ -0,0 +1,12 @@
.EmptyMessage {
// TODO: check markup
color: var(--black-500);
text-align: center;
font-size: 15px;
line-height: 24px;
white-space: pre-line;
}
.title {
font-weight: 500;
}

View File

@ -0,0 +1,14 @@
import { clsx } from 'clsx'
import styles from './EmptyMessage.module.scss'
import { useLocalize } from '../../../context/localize'
export const EmptyMessage = () => {
const { t } = useLocalize()
return (
<div class={clsx(styles.EmptyMessage)}>
<div class={styles.title}>{t('No notifications yet')}</div>
<div>{t("Write good articles, comment\nand it won't be so empty here")}</div>
</div>
)
}

View File

@ -0,0 +1 @@
export { EmptyMessage } from './EmptyMessage'

View File

@ -20,6 +20,13 @@
&:hover { &:hover {
background-color: var(--gray-100); background-color: var(--gray-100);
} }
a,
a:visited {
padding-bottom: 0 !important;
border-bottom: none !important;
font-weight: 700;
}
} }
.userpic { .userpic {

View File

@ -7,6 +7,7 @@ import { Icon } from '../_shared/Icon'
import { createEffect, For } from 'solid-js' import { createEffect, For } from 'solid-js'
import { useNotifications } from '../../context/notifications' import { useNotifications } from '../../context/notifications'
import { NotificationView } from './NotificationView' import { NotificationView } from './NotificationView'
import { EmptyMessage } from './EmptyMessage'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
@ -30,8 +31,22 @@ export const NotificationsPanel = (props: Props) => {
handler: () => handleHide() handler: () => handleHide()
}) })
let windowScrollTop = 0
createEffect(() => { createEffect(() => {
const mainContent = document.querySelector<HTMLDivElement>('.main-content')
if (props.isOpen) {
windowScrollTop = window.scrollY
mainContent.style.marginTop = `-${windowScrollTop}px`
}
document.body.classList.toggle('fixed', props.isOpen) document.body.classList.toggle('fixed', props.isOpen)
if (!props.isOpen) {
mainContent.style.marginTop = ''
window.scrollTo(0, windowScrollTop)
}
}) })
useEscKeyDownHandler(handleHide) useEscKeyDownHandler(handleHide)
@ -52,10 +67,7 @@ export const NotificationsPanel = (props: Props) => {
<Icon name="close" /> <Icon name="close" />
</div> </div>
<div class={styles.title}>{t('Notifications')}</div> <div class={styles.title}>{t('Notifications')}</div>
<For <For each={sortedNotifications()} fallback={<EmptyMessage />}>
each={sortedNotifications()}
fallback={<div class={styles.emptyMessageContainer}>{t('No notifications, yet')}</div>}
>
{(notification) => ( {(notification) => (
<NotificationView <NotificationView
notification={notification} notification={notification}

View File

@ -16,7 +16,6 @@ import { apiClient } from '../../../utils/apiClient'
import { Comment } from '../../Article/Comment' import { Comment } from '../../Article/Comment'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { AuthorRatingControl } from '../../Author/AuthorRatingControl' import { AuthorRatingControl } from '../../Author/AuthorRatingControl'
import { hideModal } from '../../../stores/ui'
import { getPagePath } from '@nanostores/router' import { getPagePath } from '@nanostores/router'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'
import { Loading } from '../../_shared/Loading' import { Loading } from '../../_shared/Loading'

View File

@ -31,6 +31,17 @@
} }
} }
&.danger {
border: 3px solid var(--danger-color);
background: var(--background-color);
color: var(--danger-color);
&:hover {
background: var(--danger-color);
color: #fff;
}
}
&.inline { &.inline {
font-weight: 700; font-weight: 700;
font-size: 16px; font-size: 16px;

View File

@ -2,10 +2,11 @@ import type { JSX } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import styles from './Button.module.scss' import styles from './Button.module.scss'
export type ButtonVariant = 'primary' | 'secondary' | 'bordered' | 'inline' | 'light' | 'outline' | 'danger'
type Props = { type Props = {
value: string | JSX.Element value: string | JSX.Element
size?: 'S' | 'M' | 'L' size?: 'S' | 'M' | 'L'
variant?: 'primary' | 'secondary' | 'bordered' | 'inline' | 'light' | 'outline' variant?: ButtonVariant
type?: 'submit' | 'button' type?: 'submit' | 'button'
loading?: boolean loading?: boolean
disabled?: boolean disabled?: boolean

View File

@ -2,11 +2,14 @@ import { createContext, createSignal, useContext } from 'solid-js'
import type { Accessor, JSX } from 'solid-js' import type { Accessor, JSX } from 'solid-js'
import { hideModal, showModal } from '../stores/ui' import { hideModal, showModal } from '../stores/ui'
import { ButtonVariant } from '../components/_shared/Button/Button'
type ConfirmMessage = { type ConfirmMessage = {
confirmBody?: string | JSX.Element confirmBody?: string | JSX.Element
confirmButtonLabel?: string confirmButtonLabel?: string
confirmButtonVariant?: ButtonVariant
declineButtonLabel?: string declineButtonLabel?: string
declineButtonVariant?: ButtonVariant
} }
type ConfirmContextType = { type ConfirmContextType = {
@ -15,7 +18,9 @@ type ConfirmContextType = {
showConfirm: (message?: { showConfirm: (message?: {
confirmBody?: ConfirmMessage['confirmBody'] confirmBody?: ConfirmMessage['confirmBody']
confirmButtonLabel?: ConfirmMessage['confirmButtonLabel'] confirmButtonLabel?: ConfirmMessage['confirmButtonLabel']
confirmButtonVariant?: ConfirmMessage['confirmButtonVariant']
declineButtonLabel?: ConfirmMessage['declineButtonLabel'] declineButtonLabel?: ConfirmMessage['declineButtonLabel']
declineButtonVariant?: ConfirmMessage['declineButtonVariant']
}) => Promise<boolean> }) => Promise<boolean>
resolveConfirm: (value: boolean) => void resolveConfirm: (value: boolean) => void
} }
@ -36,13 +41,17 @@ export const ConfirmProvider = (props: { children: JSX.Element }) => {
message: { message: {
confirmBody?: ConfirmMessage['confirmBody'] confirmBody?: ConfirmMessage['confirmBody']
confirmButtonLabel?: ConfirmMessage['confirmButtonLabel'] confirmButtonLabel?: ConfirmMessage['confirmButtonLabel']
confirmButtonVariant?: ConfirmMessage['confirmButtonVariant']
declineButtonLabel?: ConfirmMessage['declineButtonLabel'] declineButtonLabel?: ConfirmMessage['declineButtonLabel']
declineButtonVariant?: ConfirmMessage['declineButtonVariant']
} = {} } = {}
): Promise<boolean> => { ): Promise<boolean> => {
const messageToShow = { const messageToShow = {
confirmBody: message.confirmBody, confirmBody: message.confirmBody,
confirmButtonLabel: message.confirmButtonLabel, confirmButtonLabel: message.confirmButtonLabel,
declineButtonLabel: message.declineButtonLabel confirmButtonVariant: message.confirmButtonVariant,
declineButtonLabel: message.declineButtonLabel,
declineButtonVariant: message.declineButtonVariant
} }
setConfirmMessage(messageToShow) setConfirmMessage(messageToShow)

View File

@ -24,6 +24,7 @@ type NotificationsContextType = {
sortedNotifications: Accessor<ServerNotification[]> sortedNotifications: Accessor<ServerNotification[]>
actions: { actions: {
showNotificationsPanel: () => void showNotificationsPanel: () => void
hideNotificationsPanel: () => void
markNotificationAsRead: (notification: ServerNotification) => Promise<void> markNotificationAsRead: (notification: ServerNotification) => Promise<void>
setMessageHandler: (MessageHandler) => void setMessageHandler: (MessageHandler) => void
} }
@ -129,7 +130,16 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
setIsNotificationsPanelOpen(true) setIsNotificationsPanelOpen(true)
} }
const actions = { showNotificationsPanel, markNotificationAsRead, setMessageHandler } const hideNotificationsPanel = () => {
setIsNotificationsPanelOpen(false)
}
const actions = {
setMessageHandler,
showNotificationsPanel,
hideNotificationsPanel,
markNotificationAsRead
}
const value: NotificationsContextType = { const value: NotificationsContextType = {
notificationEntities, notificationEntities,

View File

@ -11,18 +11,9 @@ import { setPageLoadManagerPromise } from '../utils/pageLoadManager'
export const ArticlePage = (props: PageProps) => { export const ArticlePage = (props: PageProps) => {
const shouts = props.article ? [props.article] : [] const shouts = props.article ? [props.article] : []
const { page } = useRouter()
const slug = createMemo(() => { const slug = createMemo(() => page().params['slug'] as string)
const { page: getPage } = useRouter()
const page = getPage()
if (page.route !== 'article') {
throw new Error('ts guard')
}
return page.params.slug
})
const { articleEntities } = useArticlesStore({ const { articleEntities } = useArticlesStore({
shouts shouts