From 47d14b0a5dc5149dfc91eae9cee9caf21f2c080d Mon Sep 17 00:00:00 2001
From: Igor Lobanov
Date: Fri, 12 May 2023 15:03:46 +0200
Subject: [PATCH] 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
---
package-lock.json | 16 +++++++++++++-
package.json | 3 ++-
public/locales/en/translation.json | 15 ++++++-------
public/locales/ru/translation.json | 15 ++++++-------
src/components/Editor/Editor.tsx | 8 ++++---
src/components/Editor/Panel/Panel.module.scss | 17 +++++++--------
src/components/Editor/Panel/Panel.tsx | 16 ++++++++++++++
src/components/Editor/Prosemirror.scss | 1 +
.../TopicSelect/TopicSelect.module.scss | 2 +-
.../Feed/Sidebar/Sidebar.module.scss | 7 ++++---
src/components/Nav/AuthModal/RegisterForm.tsx | 10 ++++-----
src/components/Views/Edit.module.scss | 2 +-
src/components/Views/Edit.tsx | 5 +++--
.../GrowingTextarea.module.scss | 1 +
src/context/editor.tsx | 21 +++++++++++++++++--
src/pages/profile/Settings.module.scss | 4 ++--
src/utils/slugify.ts | 2 +-
17 files changed, 99 insertions(+), 46 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 5b13cedc..40731789 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,7 +17,8 @@
"formidable": "2.1.1",
"i18next": "22.4.15",
"mailgun.js": "8.2.1",
- "node-fetch": "3.3.1"
+ "node-fetch": "3.3.1",
+ "typograf": "7.1.0"
},
"devDependencies": {
"@babel/core": "7.21.8",
@@ -19579,6 +19580,14 @@
"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": {
"version": "0.7.33",
"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==",
"dev": true
},
+ "typograf": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/typograf/-/typograf-7.1.0.tgz",
+ "integrity": "sha512-R7Kbb7JKuT96hWHTWQbZrGUchCk98rM2IQ38mi0ye2LoEJRn4o3lSZ8DZxK4ufrszUlrXIvnidIZ0AKA7UHvgg=="
+ },
"ua-parser-js": {
"version": "0.7.33",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
diff --git a/package.json b/package.json
index 9899c4a0..f5d88894 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,8 @@
"formidable": "2.1.1",
"i18next": "22.4.15",
"mailgun.js": "8.2.1",
- "node-fetch": "3.3.1"
+ "node-fetch": "3.3.1",
+ "typograf": "7.1.0"
},
"devDependencies": {
"@babel/core": "7.21.8",
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index 6ccff815..004e6fc2 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -2,9 +2,9 @@
"...subscribing": "...subscribing",
"About myself": "About myself",
"About the project": "About the project",
+ "Add another image": "Add another image",
"Add comment": "Comment",
"Add image": "Add image",
- "Add another image": "Add another image",
"Address on Discourse": "Address on Discourse",
"All": "All",
"All authors": "All authors",
@@ -46,9 +46,6 @@
"Create Chat": "Create Chat",
"Create Group": "Create a group",
"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",
"Date of Birth": "Date of Birth",
"Delete": "Delete",
@@ -77,6 +74,7 @@
"Feed settings": "Feed settings",
"Feedback": "Feedback",
"Fill email": "Fill email",
+ "Fix typography": "Fix typography",
"Follow": "Follow",
"Follow the topic": "Follow the topic",
"Followers": "Followers",
@@ -146,6 +144,9 @@
"Partners": "Partners",
"Password": "Password",
"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",
"Paste Embed code": "Paste Embed code",
"Personal": "Personal",
@@ -163,6 +164,7 @@
"Profile": "Profile",
"Profile settings": "Profile settings",
"Publications": "Publications",
+ "Publish Settings": "Publish Settings",
"Quit": "Quit",
"Quotes": "Quotes",
"Reason uknown": "Reason unknown",
@@ -224,6 +226,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",
@@ -279,7 +282,5 @@
"topics": "topics",
"user already exist": "user already exists",
"view": "view",
- "zine": "zine",
- "Unnamed draft": "Unnamed draft",
- "Publish Settings": "Publish Settings"
+ "zine": "zine"
}
diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json
index 6d2cb90b..6c13535c 100644
--- a/public/locales/ru/translation.json
+++ b/public/locales/ru/translation.json
@@ -3,9 +3,9 @@
"A short introduction to keep the reader interested": "Небольшое вступление, чтобы заинтересовать читателя",
"About myself": "О себе",
"About the project": "О проекте",
+ "Add another image": "Добавить другое изображение",
"Add comment": "Комментировать",
"Add image": "Добавить изображение",
- "Add another image": "Добавить другое изображение",
"Add to bookmarks": "Добавить в закладки",
"Address on Discourse": "Адрес на Дискурсе",
"All": "Все",
@@ -48,9 +48,6 @@
"Create Chat": "Создать чат",
"Create Group": "Создать группу",
"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": "Создать публикацию",
"Date of Birth": "Дата рождения",
"Delete": "Удалить",
@@ -80,6 +77,7 @@
"Feed settings": "Настройки ленты",
"Feedback": "Обратная связь",
"Fill email": "Введите почту",
+ "Fix typography": "Исправить типографику",
"Follow": "Подписаться",
"Follow the topic": "Подписаться на тему",
"Followers": "Подписчики",
@@ -153,6 +151,9 @@
"Partners": "Партнёры",
"Password": "Пароль",
"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": "Пароли не совпадают",
"Paste Embed code": "Вставьте embed код",
"Personal": "Личные",
@@ -174,6 +175,7 @@
"Publication settings": "Настройки публикации",
"Publications": "Публикации",
"Publish": "Опубликовать",
+ "Publish Settings": "Настройки публикации",
"Quit": "Выйти",
"Quotes": "Цитаты",
"Reason uknown": "Причина неизвестна",
@@ -237,6 +239,7 @@
"Try to find another way": "Попробуйте найти по-другому",
"Unfollow": "Отписаться",
"Unfollow the topic": "Отписаться от темы",
+ "Unnamed draft": "Unnamed draft",
"Upload": "Загрузить",
"Username": "Имя пользователя",
"Userpic": "Аватар",
@@ -300,7 +303,5 @@
"topics": "темы",
"user already exist": "пользователь уже существует",
"view": "просмотр",
- "zine": "журнал",
- "Publish Settings": "Настройки публикации",
- "Unnamed draft": "Unnamed draft"
+ "zine": "журнал"
}
diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx
index 49f5e375..98630a27 100644
--- a/src/components/Editor/Editor.tsx
+++ b/src/components/Editor/Editor.tsx
@@ -187,12 +187,14 @@ export const Editor = (props: EditorProps) => {
]
}))
- const html = useEditorHTML(() => editor())
-
const {
- actions: { countWords }
+ actions: { countWords, setEditor }
} = useEditorContext()
+ setEditor(editor)
+
+ const html = useEditorHTML(() => editor())
+
createEffect(() => {
props.onChange(html())
if (html()) {
diff --git a/src/components/Editor/Panel/Panel.module.scss b/src/components/Editor/Panel/Panel.module.scss
index eb589799..43f137ae 100644
--- a/src/components/Editor/Panel/Panel.module.scss
+++ b/src/components/Editor/Panel/Panel.module.scss
@@ -59,6 +59,13 @@
a {
text-decoration: none;
border-bottom: none;
+ color: rgb(255 255 255 / 35%);
+ font-weight: normal !important;
+
+ &:hover {
+ background: none;
+ color: #fff;
+ }
}
.linkWithIcon {
@@ -73,16 +80,6 @@
margin-top: 3em;
}
- a {
- color: rgb(255 255 255 / 35%);
- font-weight: normal !important;
-
- &:hover {
- background: none;
- color: #fff;
- }
- }
-
&.hidden {
transform: translateX(100%);
}
diff --git a/src/components/Editor/Panel/Panel.tsx b/src/components/Editor/Panel/Panel.tsx
index 83e72514..d67f81c8 100644
--- a/src/components/Editor/Panel/Panel.tsx
+++ b/src/components/Editor/Panel/Panel.tsx
@@ -8,6 +8,10 @@ import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler'
import { getPagePath } from '@nanostores/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 = {
shoutId: number
@@ -18,6 +22,7 @@ export const Panel = (props: Props) => {
const {
isEditorPanelVisible,
wordCounter,
+ editorRef,
actions: { toggleEditorPanel, saveShout, publishShout }
} = useEditorContext()
@@ -47,6 +52,12 @@ export const Panel = (props: Props) => {
publishShout()
}
+ const handleFixTypographyLinkClick = (e) => {
+ e.preventDefault()
+ const html = useEditorHTML(() => editorRef.current())
+ editorRef.current().commands.setContent(typograf.execute(html()))
+ }
+
return (
+
+
+ {t('Fix typography')}
+
+
{t('Corrections history')}
diff --git a/src/components/Editor/Prosemirror.scss b/src/components/Editor/Prosemirror.scss
index 7538473a..64cb38b5 100644
--- a/src/components/Editor/Prosemirror.scss
+++ b/src/components/Editor/Prosemirror.scss
@@ -1,5 +1,6 @@
.ProseMirror {
outline: none;
+ min-height: 300px;
blockquote {
@include font-size(1.6rem);
diff --git a/src/components/Editor/TopicSelect/TopicSelect.module.scss b/src/components/Editor/TopicSelect/TopicSelect.module.scss
index a2a15c1b..e09737ae 100644
--- a/src/components/Editor/TopicSelect/TopicSelect.module.scss
+++ b/src/components/Editor/TopicSelect/TopicSelect.module.scss
@@ -9,7 +9,7 @@
color: #ccc;
}
- &:before {
+ &::before {
background: #000;
content: '';
height: 100%;
diff --git a/src/components/Feed/Sidebar/Sidebar.module.scss b/src/components/Feed/Sidebar/Sidebar.module.scss
index fd66ff3e..8a0db25c 100644
--- a/src/components/Feed/Sidebar/Sidebar.module.scss
+++ b/src/components/Feed/Sidebar/Sidebar.module.scss
@@ -89,14 +89,15 @@
}
h4 {
+ @include font-size(1.2rem);
+
color: #9fa1a7;
cursor: pointer;
- @include font-size(1.2rem);
letter-spacing: 0.05em;
text-transform: uppercase;
position: relative;
- &:after {
+ &::after {
content: '+';
font-size: 1.6em;
line-height: 1;
@@ -107,7 +108,7 @@
}
&.opened {
- &:after {
+ &::after {
right: 0.9rem;
transform: rotate(45deg);
}
diff --git a/src/components/Nav/AuthModal/RegisterForm.tsx b/src/components/Nav/AuthModal/RegisterForm.tsx
index 618befea..98702bfe 100644
--- a/src/components/Nav/AuthModal/RegisterForm.tsx
+++ b/src/components/Nav/AuthModal/RegisterForm.tsx
@@ -44,18 +44,18 @@ export const RegisterForm = () => {
}
}
- function isValidPassword(password) {
+ function isValidPassword(passwordToCheck) {
const minLength = 8
const hasNumber = /\d/
- const hasSpecial = /[!@#$%^&*]/
+ const hasSpecial = /[!#$%&*@^]/
- if (password.length < minLength) {
+ if (passwordToCheck.length < minLength) {
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')
}
- if (!hasSpecial.test(password)) {
+ if (!hasSpecial.test(passwordToCheck)) {
return t('Password should contain at least one special character: !@#$%^&*')
}
return null
diff --git a/src/components/Views/Edit.module.scss b/src/components/Views/Edit.module.scss
index 6644d763..4f639ded 100644
--- a/src/components/Views/Edit.module.scss
+++ b/src/components/Views/Edit.module.scss
@@ -92,7 +92,7 @@
}
}
-//Grow input
+// Grow input
.editSettings,
.edit {
diff --git a/src/components/Views/Edit.tsx b/src/components/Views/Edit.tsx
index e982fd7d..131be0d0 100644
--- a/src/components/Views/Edit.tsx
+++ b/src/components/Views/Edit.tsx
@@ -20,7 +20,8 @@ type EditViewProps = {
shout: Shout
}
-const scrollTop = () => {
+const handleScrollTopButtonClick = (e) => {
+ e.preventDefault()
window.scrollTo({
top: 0,
behavior: 'smooth'
@@ -124,7 +125,7 @@ export const EditView = (props: EditViewProps) => {
class={clsx(styles.scrollTopButton, {
[styles.visible]: isScrolled()
})}
- onClick={scrollTop}
+ onClick={handleScrollTopButtonClick}
>
{t('Scroll up')}
diff --git a/src/components/_shared/GrowingTextarea/GrowingTextarea.module.scss b/src/components/_shared/GrowingTextarea/GrowingTextarea.module.scss
index e257b625..e9f60955 100644
--- a/src/components/_shared/GrowingTextarea/GrowingTextarea.module.scss
+++ b/src/components/_shared/GrowingTextarea/GrowingTextarea.module.scss
@@ -17,6 +17,7 @@
border: none;
resize: none;
overflow: hidden;
+
&::placeholder {
color: #858585;
}
diff --git a/src/context/editor.tsx b/src/context/editor.tsx
index d47877ad..92d8354d 100644
--- a/src/context/editor.tsx
+++ b/src/context/editor.tsx
@@ -8,6 +8,7 @@ import { useSnackbar } from './snackbar'
import { openPage } from '@nanostores/router'
import { router, useRouter } from '../stores/router'
import { slugify } from '../utils/slugify'
+import { Editor } from '@tiptap/core'
type WordCounter = {
characters: number
@@ -30,6 +31,7 @@ type EditorContextType = {
wordCounter: Accessor
form: ShoutForm
formErrors: Record
+ editorRef: { current: () => Editor }
actions: {
saveShout: () => Promise
publishShout: () => Promise
@@ -39,6 +41,7 @@ type EditorContextType = {
countWords: (value: WordCounter) => void
setForm: SetStoreFunction
setFormErrors: SetStoreFunction>
+ setEditor: (editor: () => Editor) => void
}
}
@@ -67,6 +70,8 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
const [isEditorPanelVisible, setIsEditorPanelVisible] = createSignal(false)
+ const editorRef: { current: () => Editor } = { current: null }
+
const [form, setForm] = createStore(null)
const [formErrors, setFormErrors] = createStore>(null)
@@ -198,6 +203,10 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
}
}
+ const setEditor = (editor: () => Editor) => {
+ editorRef.current = editor
+ }
+
const actions = {
saveShout,
publishShout,
@@ -206,10 +215,18 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
toggleEditorPanel,
countWords,
setForm,
- setFormErrors
+ setFormErrors,
+ setEditor
}
- const value: EditorContextType = { actions, form, formErrors, isEditorPanelVisible, wordCounter }
+ const value: EditorContextType = {
+ actions,
+ form,
+ formErrors,
+ editorRef,
+ isEditorPanelVisible,
+ wordCounter
+ }
return {props.children}
}
diff --git a/src/pages/profile/Settings.module.scss b/src/pages/profile/Settings.module.scss
index 3c3302bb..f180b7f2 100644
--- a/src/pages/profile/Settings.module.scss
+++ b/src/pages/profile/Settings.module.scss
@@ -211,8 +211,8 @@ h5 {
padding-bottom: 0.2rem;
position: relative;
- &:before {
- background: rgb(243, 244, 246);
+ &::before {
+ background: rgb(243 244 246);
content: '';
height: 100%;
left: 0;
diff --git a/src/utils/slugify.ts b/src/utils/slugify.ts
index 5edb0c94..f823249f 100644
--- a/src/utils/slugify.ts
+++ b/src/utils/slugify.ts
@@ -2,6 +2,6 @@ import { translit } from './ru2en'
export const slugify = (text) => {
return translit(text.toLowerCase())
- .replaceAll(/[^\da-z]/g, '')
.replaceAll(' ', '-')
+ .replaceAll(/[^\da-z]/g, '')
}