Fix typography feature, scroll top button fix, slugify fix (#93)
* Fix typography feature, scroll top button fix, slugify fix * build fix, some lint * refactoring, lint
This commit is contained in:
parent
b040d5e0c9
commit
47d14b0a5d
16
package-lock.json
generated
16
package-lock.json
generated
|
@ -17,7 +17,8 @@
|
||||||
"formidable": "2.1.1",
|
"formidable": "2.1.1",
|
||||||
"i18next": "22.4.15",
|
"i18next": "22.4.15",
|
||||||
"mailgun.js": "8.2.1",
|
"mailgun.js": "8.2.1",
|
||||||
"node-fetch": "3.3.1"
|
"node-fetch": "3.3.1",
|
||||||
|
"typograf": "7.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.21.8",
|
"@babel/core": "7.21.8",
|
||||||
|
@ -19579,6 +19580,14 @@
|
||||||
"node": ">=12.20"
|
"node": ">=12.20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typograf": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/typograf/-/typograf-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-R7Kbb7JKuT96hWHTWQbZrGUchCk98rM2IQ38mi0ye2LoEJRn4o3lSZ8DZxK4ufrszUlrXIvnidIZ0AKA7UHvgg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ua-parser-js": {
|
"node_modules/ua-parser-js": {
|
||||||
"version": "0.7.33",
|
"version": "0.7.33",
|
||||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||||
|
@ -35067,6 +35076,11 @@
|
||||||
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"typograf": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/typograf/-/typograf-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-R7Kbb7JKuT96hWHTWQbZrGUchCk98rM2IQ38mi0ye2LoEJRn4o3lSZ8DZxK4ufrszUlrXIvnidIZ0AKA7UHvgg=="
|
||||||
|
},
|
||||||
"ua-parser-js": {
|
"ua-parser-js": {
|
||||||
"version": "0.7.33",
|
"version": "0.7.33",
|
||||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
"formidable": "2.1.1",
|
"formidable": "2.1.1",
|
||||||
"i18next": "22.4.15",
|
"i18next": "22.4.15",
|
||||||
"mailgun.js": "8.2.1",
|
"mailgun.js": "8.2.1",
|
||||||
"node-fetch": "3.3.1"
|
"node-fetch": "3.3.1",
|
||||||
|
"typograf": "7.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.21.8",
|
"@babel/core": "7.21.8",
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
"...subscribing": "...subscribing",
|
"...subscribing": "...subscribing",
|
||||||
"About myself": "About myself",
|
"About myself": "About myself",
|
||||||
"About the project": "About the project",
|
"About the project": "About the project",
|
||||||
|
"Add another image": "Add another image",
|
||||||
"Add comment": "Comment",
|
"Add comment": "Comment",
|
||||||
"Add image": "Add image",
|
"Add image": "Add image",
|
||||||
"Add another image": "Add another image",
|
|
||||||
"Address on Discourse": "Address on Discourse",
|
"Address on Discourse": "Address on Discourse",
|
||||||
"All": "All",
|
"All": "All",
|
||||||
"All authors": "All authors",
|
"All authors": "All authors",
|
||||||
|
@ -46,9 +46,6 @@
|
||||||
"Create Chat": "Create Chat",
|
"Create Chat": "Create Chat",
|
||||||
"Create Group": "Create a group",
|
"Create Group": "Create a group",
|
||||||
"Create account": "Create an account",
|
"Create account": "Create an account",
|
||||||
"Password should be at least 8 characters": "Password should be at least 8 characters",
|
|
||||||
"Password should contain at least one number": "Password should contain at least one number",
|
|
||||||
"Password should contain at least one special character: !@#$%^&*": "Password should contain at least one special character: !@#$%^&*",
|
|
||||||
"Create post": "Create post",
|
"Create post": "Create post",
|
||||||
"Date of Birth": "Date of Birth",
|
"Date of Birth": "Date of Birth",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
|
@ -77,6 +74,7 @@
|
||||||
"Feed settings": "Feed settings",
|
"Feed settings": "Feed settings",
|
||||||
"Feedback": "Feedback",
|
"Feedback": "Feedback",
|
||||||
"Fill email": "Fill email",
|
"Fill email": "Fill email",
|
||||||
|
"Fix typography": "Fix typography",
|
||||||
"Follow": "Follow",
|
"Follow": "Follow",
|
||||||
"Follow the topic": "Follow the topic",
|
"Follow the topic": "Follow the topic",
|
||||||
"Followers": "Followers",
|
"Followers": "Followers",
|
||||||
|
@ -146,6 +144,9 @@
|
||||||
"Partners": "Partners",
|
"Partners": "Partners",
|
||||||
"Password": "Password",
|
"Password": "Password",
|
||||||
"Password again": "Password again",
|
"Password again": "Password again",
|
||||||
|
"Password should be at least 8 characters": "Password should be at least 8 characters",
|
||||||
|
"Password should contain at least one number": "Password should contain at least one number",
|
||||||
|
"Password should contain at least one special character: !@#$%^&*": "Password should contain at least one special character: !@#$%^&*",
|
||||||
"Passwords are not equal": "Passwords are not equal",
|
"Passwords are not equal": "Passwords are not equal",
|
||||||
"Paste Embed code": "Paste Embed code",
|
"Paste Embed code": "Paste Embed code",
|
||||||
"Personal": "Personal",
|
"Personal": "Personal",
|
||||||
|
@ -163,6 +164,7 @@
|
||||||
"Profile": "Profile",
|
"Profile": "Profile",
|
||||||
"Profile settings": "Profile settings",
|
"Profile settings": "Profile settings",
|
||||||
"Publications": "Publications",
|
"Publications": "Publications",
|
||||||
|
"Publish Settings": "Publish Settings",
|
||||||
"Quit": "Quit",
|
"Quit": "Quit",
|
||||||
"Quotes": "Quotes",
|
"Quotes": "Quotes",
|
||||||
"Reason uknown": "Reason unknown",
|
"Reason uknown": "Reason unknown",
|
||||||
|
@ -224,6 +226,7 @@
|
||||||
"Try to find another way": "Try to find another way",
|
"Try to find another way": "Try to find another way",
|
||||||
"Unfollow": "Unfollow",
|
"Unfollow": "Unfollow",
|
||||||
"Unfollow the topic": "Unfollow the topic",
|
"Unfollow the topic": "Unfollow the topic",
|
||||||
|
"Unnamed draft": "Unnamed draft",
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Userpic": "Userpic",
|
"Userpic": "Userpic",
|
||||||
|
@ -279,7 +282,5 @@
|
||||||
"topics": "topics",
|
"topics": "topics",
|
||||||
"user already exist": "user already exists",
|
"user already exist": "user already exists",
|
||||||
"view": "view",
|
"view": "view",
|
||||||
"zine": "zine",
|
"zine": "zine"
|
||||||
"Unnamed draft": "Unnamed draft",
|
|
||||||
"Publish Settings": "Publish Settings"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
"A short introduction to keep the reader interested": "Небольшое вступление, чтобы заинтересовать читателя",
|
"A short introduction to keep the reader interested": "Небольшое вступление, чтобы заинтересовать читателя",
|
||||||
"About myself": "О себе",
|
"About myself": "О себе",
|
||||||
"About the project": "О проекте",
|
"About the project": "О проекте",
|
||||||
|
"Add another image": "Добавить другое изображение",
|
||||||
"Add comment": "Комментировать",
|
"Add comment": "Комментировать",
|
||||||
"Add image": "Добавить изображение",
|
"Add image": "Добавить изображение",
|
||||||
"Add another image": "Добавить другое изображение",
|
|
||||||
"Add to bookmarks": "Добавить в закладки",
|
"Add to bookmarks": "Добавить в закладки",
|
||||||
"Address on Discourse": "Адрес на Дискурсе",
|
"Address on Discourse": "Адрес на Дискурсе",
|
||||||
"All": "Все",
|
"All": "Все",
|
||||||
|
@ -48,9 +48,6 @@
|
||||||
"Create Chat": "Создать чат",
|
"Create Chat": "Создать чат",
|
||||||
"Create Group": "Создать группу",
|
"Create Group": "Создать группу",
|
||||||
"Create account": "Создать аккаунт",
|
"Create account": "Создать аккаунт",
|
||||||
"Password should be at least 8 characters": "Пароль должен быть не менее 8 символов",
|
|
||||||
"Password should contain at least one number": "Пароль должен содержать хотя бы одну цифру",
|
|
||||||
"Password should contain at least one special character: !@#$%^&*": "Пароль должен содержать хотя бы один специальный символ: !@#$%^&*",
|
|
||||||
"Create post": "Создать публикацию",
|
"Create post": "Создать публикацию",
|
||||||
"Date of Birth": "Дата рождения",
|
"Date of Birth": "Дата рождения",
|
||||||
"Delete": "Удалить",
|
"Delete": "Удалить",
|
||||||
|
@ -80,6 +77,7 @@
|
||||||
"Feed settings": "Настройки ленты",
|
"Feed settings": "Настройки ленты",
|
||||||
"Feedback": "Обратная связь",
|
"Feedback": "Обратная связь",
|
||||||
"Fill email": "Введите почту",
|
"Fill email": "Введите почту",
|
||||||
|
"Fix typography": "Исправить типографику",
|
||||||
"Follow": "Подписаться",
|
"Follow": "Подписаться",
|
||||||
"Follow the topic": "Подписаться на тему",
|
"Follow the topic": "Подписаться на тему",
|
||||||
"Followers": "Подписчики",
|
"Followers": "Подписчики",
|
||||||
|
@ -153,6 +151,9 @@
|
||||||
"Partners": "Партнёры",
|
"Partners": "Партнёры",
|
||||||
"Password": "Пароль",
|
"Password": "Пароль",
|
||||||
"Password again": "Пароль ещё раз",
|
"Password again": "Пароль ещё раз",
|
||||||
|
"Password should be at least 8 characters": "Пароль должен быть не менее 8 символов",
|
||||||
|
"Password should contain at least one number": "Пароль должен содержать хотя бы одну цифру",
|
||||||
|
"Password should contain at least one special character: !@#$%^&*": "Пароль должен содержать хотя бы один специальный символ: !@#$%^&*",
|
||||||
"Passwords are not equal": "Пароли не совпадают",
|
"Passwords are not equal": "Пароли не совпадают",
|
||||||
"Paste Embed code": "Вставьте embed код",
|
"Paste Embed code": "Вставьте embed код",
|
||||||
"Personal": "Личные",
|
"Personal": "Личные",
|
||||||
|
@ -174,6 +175,7 @@
|
||||||
"Publication settings": "Настройки публикации",
|
"Publication settings": "Настройки публикации",
|
||||||
"Publications": "Публикации",
|
"Publications": "Публикации",
|
||||||
"Publish": "Опубликовать",
|
"Publish": "Опубликовать",
|
||||||
|
"Publish Settings": "Настройки публикации",
|
||||||
"Quit": "Выйти",
|
"Quit": "Выйти",
|
||||||
"Quotes": "Цитаты",
|
"Quotes": "Цитаты",
|
||||||
"Reason uknown": "Причина неизвестна",
|
"Reason uknown": "Причина неизвестна",
|
||||||
|
@ -237,6 +239,7 @@
|
||||||
"Try to find another way": "Попробуйте найти по-другому",
|
"Try to find another way": "Попробуйте найти по-другому",
|
||||||
"Unfollow": "Отписаться",
|
"Unfollow": "Отписаться",
|
||||||
"Unfollow the topic": "Отписаться от темы",
|
"Unfollow the topic": "Отписаться от темы",
|
||||||
|
"Unnamed draft": "Unnamed draft",
|
||||||
"Upload": "Загрузить",
|
"Upload": "Загрузить",
|
||||||
"Username": "Имя пользователя",
|
"Username": "Имя пользователя",
|
||||||
"Userpic": "Аватар",
|
"Userpic": "Аватар",
|
||||||
|
@ -300,7 +303,5 @@
|
||||||
"topics": "темы",
|
"topics": "темы",
|
||||||
"user already exist": "пользователь уже существует",
|
"user already exist": "пользователь уже существует",
|
||||||
"view": "просмотр",
|
"view": "просмотр",
|
||||||
"zine": "журнал",
|
"zine": "журнал"
|
||||||
"Publish Settings": "Настройки публикации",
|
|
||||||
"Unnamed draft": "Unnamed draft"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,12 +187,14 @@ export const Editor = (props: EditorProps) => {
|
||||||
]
|
]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const html = useEditorHTML(() => editor())
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
actions: { countWords }
|
actions: { countWords, setEditor }
|
||||||
} = useEditorContext()
|
} = useEditorContext()
|
||||||
|
|
||||||
|
setEditor(editor)
|
||||||
|
|
||||||
|
const html = useEditorHTML(() => editor())
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
props.onChange(html())
|
props.onChange(html())
|
||||||
if (html()) {
|
if (html()) {
|
||||||
|
|
|
@ -59,6 +59,13 @@
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
color: rgb(255 255 255 / 35%);
|
||||||
|
font-weight: normal !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkWithIcon {
|
.linkWithIcon {
|
||||||
|
@ -73,16 +80,6 @@
|
||||||
margin-top: 3em;
|
margin-top: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgb(255 255 255 / 35%);
|
|
||||||
font-weight: normal !important;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: none;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hidden {
|
&.hidden {
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
|
||||||
import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler'
|
import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler'
|
||||||
import { getPagePath } from '@nanostores/router'
|
import { getPagePath } from '@nanostores/router'
|
||||||
import { router } from '../../../stores/router'
|
import { router } from '../../../stores/router'
|
||||||
|
import { useEditorHTML } from 'solid-tiptap'
|
||||||
|
import Typograf from 'typograf'
|
||||||
|
|
||||||
|
const typograf = new Typograf({ locale: ['ru', 'en-US'] })
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shoutId: number
|
shoutId: number
|
||||||
|
@ -18,6 +22,7 @@ export const Panel = (props: Props) => {
|
||||||
const {
|
const {
|
||||||
isEditorPanelVisible,
|
isEditorPanelVisible,
|
||||||
wordCounter,
|
wordCounter,
|
||||||
|
editorRef,
|
||||||
actions: { toggleEditorPanel, saveShout, publishShout }
|
actions: { toggleEditorPanel, saveShout, publishShout }
|
||||||
} = useEditorContext()
|
} = useEditorContext()
|
||||||
|
|
||||||
|
@ -47,6 +52,12 @@ export const Panel = (props: Props) => {
|
||||||
publishShout()
|
publishShout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFixTypographyLinkClick = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const html = useEditorHTML(() => editorRef.current())
|
||||||
|
editorRef.current().commands.setContent(typograf.execute(html()))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
ref={(el) => (containerRef.current = el)}
|
ref={(el) => (containerRef.current = el)}
|
||||||
|
@ -111,6 +122,11 @@ export const Panel = (props: Props) => {
|
||||||
{t('Publication settings')}
|
{t('Publication settings')}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a onClick={handleFixTypographyLinkClick} href="#">
|
||||||
|
{t('Fix typography')}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a>{t('Corrections history')}</a>
|
<a>{t('Corrections history')}</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.ProseMirror {
|
.ProseMirror {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
min-height: 300px;
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
@include font-size(1.6rem);
|
@include font-size(1.6rem);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
background: #000;
|
background: #000;
|
||||||
content: '';
|
content: '';
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -89,14 +89,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
|
@include font-size(1.2rem);
|
||||||
|
|
||||||
color: #9fa1a7;
|
color: #9fa1a7;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@include font-size(1.2rem);
|
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
content: '+';
|
content: '+';
|
||||||
font-size: 1.6em;
|
font-size: 1.6em;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
@ -107,7 +108,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.opened {
|
&.opened {
|
||||||
&:after {
|
&::after {
|
||||||
right: 0.9rem;
|
right: 0.9rem;
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,18 +44,18 @@ export const RegisterForm = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidPassword(password) {
|
function isValidPassword(passwordToCheck) {
|
||||||
const minLength = 8
|
const minLength = 8
|
||||||
const hasNumber = /\d/
|
const hasNumber = /\d/
|
||||||
const hasSpecial = /[!@#$%^&*]/
|
const hasSpecial = /[!#$%&*@^]/
|
||||||
|
|
||||||
if (password.length < minLength) {
|
if (passwordToCheck.length < minLength) {
|
||||||
return t('Password should be at least 8 characters')
|
return t('Password should be at least 8 characters')
|
||||||
}
|
}
|
||||||
if (!hasNumber.test(password)) {
|
if (!hasNumber.test(passwordToCheck)) {
|
||||||
return t('Password should contain at least one number')
|
return t('Password should contain at least one number')
|
||||||
}
|
}
|
||||||
if (!hasSpecial.test(password)) {
|
if (!hasSpecial.test(passwordToCheck)) {
|
||||||
return t('Password should contain at least one special character: !@#$%^&*')
|
return t('Password should contain at least one special character: !@#$%^&*')
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -20,7 +20,8 @@ type EditViewProps = {
|
||||||
shout: Shout
|
shout: Shout
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollTop = () => {
|
const handleScrollTopButtonClick = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
window.scrollTo({
|
window.scrollTo({
|
||||||
top: 0,
|
top: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
|
@ -124,7 +125,7 @@ export const EditView = (props: EditViewProps) => {
|
||||||
class={clsx(styles.scrollTopButton, {
|
class={clsx(styles.scrollTopButton, {
|
||||||
[styles.visible]: isScrolled()
|
[styles.visible]: isScrolled()
|
||||||
})}
|
})}
|
||||||
onClick={scrollTop}
|
onClick={handleScrollTopButtonClick}
|
||||||
>
|
>
|
||||||
<Icon name="up-button" class={styles.icon} />
|
<Icon name="up-button" class={styles.icon} />
|
||||||
<span class={styles.scrollTopButtonLabel}>{t('Scroll up')}</span>
|
<span class={styles.scrollTopButtonLabel}>{t('Scroll up')}</span>
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
border: none;
|
border: none;
|
||||||
resize: none;
|
resize: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: #858585;
|
color: #858585;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { useSnackbar } from './snackbar'
|
||||||
import { openPage } from '@nanostores/router'
|
import { openPage } from '@nanostores/router'
|
||||||
import { router, useRouter } from '../stores/router'
|
import { router, useRouter } from '../stores/router'
|
||||||
import { slugify } from '../utils/slugify'
|
import { slugify } from '../utils/slugify'
|
||||||
|
import { Editor } from '@tiptap/core'
|
||||||
|
|
||||||
type WordCounter = {
|
type WordCounter = {
|
||||||
characters: number
|
characters: number
|
||||||
|
@ -30,6 +31,7 @@ type EditorContextType = {
|
||||||
wordCounter: Accessor<WordCounter>
|
wordCounter: Accessor<WordCounter>
|
||||||
form: ShoutForm
|
form: ShoutForm
|
||||||
formErrors: Record<keyof ShoutForm, string>
|
formErrors: Record<keyof ShoutForm, string>
|
||||||
|
editorRef: { current: () => Editor }
|
||||||
actions: {
|
actions: {
|
||||||
saveShout: () => Promise<void>
|
saveShout: () => Promise<void>
|
||||||
publishShout: () => Promise<void>
|
publishShout: () => Promise<void>
|
||||||
|
@ -39,6 +41,7 @@ type EditorContextType = {
|
||||||
countWords: (value: WordCounter) => void
|
countWords: (value: WordCounter) => void
|
||||||
setForm: SetStoreFunction<ShoutForm>
|
setForm: SetStoreFunction<ShoutForm>
|
||||||
setFormErrors: SetStoreFunction<Record<keyof ShoutForm, string>>
|
setFormErrors: SetStoreFunction<Record<keyof ShoutForm, string>>
|
||||||
|
setEditor: (editor: () => Editor) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +70,8 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
const [isEditorPanelVisible, setIsEditorPanelVisible] = createSignal<boolean>(false)
|
const [isEditorPanelVisible, setIsEditorPanelVisible] = createSignal<boolean>(false)
|
||||||
|
|
||||||
|
const editorRef: { current: () => Editor } = { current: null }
|
||||||
|
|
||||||
const [form, setForm] = createStore<ShoutForm>(null)
|
const [form, setForm] = createStore<ShoutForm>(null)
|
||||||
const [formErrors, setFormErrors] = createStore<Record<keyof ShoutForm, string>>(null)
|
const [formErrors, setFormErrors] = createStore<Record<keyof ShoutForm, string>>(null)
|
||||||
|
|
||||||
|
@ -198,6 +203,10 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setEditor = (editor: () => Editor) => {
|
||||||
|
editorRef.current = editor
|
||||||
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
saveShout,
|
saveShout,
|
||||||
publishShout,
|
publishShout,
|
||||||
|
@ -206,10 +215,18 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
toggleEditorPanel,
|
toggleEditorPanel,
|
||||||
countWords,
|
countWords,
|
||||||
setForm,
|
setForm,
|
||||||
setFormErrors
|
setFormErrors,
|
||||||
|
setEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
const value: EditorContextType = { actions, form, formErrors, isEditorPanelVisible, wordCounter }
|
const value: EditorContextType = {
|
||||||
|
actions,
|
||||||
|
form,
|
||||||
|
formErrors,
|
||||||
|
editorRef,
|
||||||
|
isEditorPanelVisible,
|
||||||
|
wordCounter
|
||||||
|
}
|
||||||
|
|
||||||
return <EditorContext.Provider value={value}>{props.children}</EditorContext.Provider>
|
return <EditorContext.Provider value={value}>{props.children}</EditorContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,8 +211,8 @@ h5 {
|
||||||
padding-bottom: 0.2rem;
|
padding-bottom: 0.2rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
background: rgb(243, 244, 246);
|
background: rgb(243 244 246);
|
||||||
content: '';
|
content: '';
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
|
@ -2,6 +2,6 @@ import { translit } from './ru2en'
|
||||||
|
|
||||||
export const slugify = (text) => {
|
export const slugify = (text) => {
|
||||||
return translit(text.toLowerCase())
|
return translit(text.toLowerCase())
|
||||||
.replaceAll(/[^\da-z]/g, '')
|
|
||||||
.replaceAll(' ', '-')
|
.replaceAll(' ', '-')
|
||||||
|
.replaceAll(/[^\da-z]/g, '')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user