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:
Igor Lobanov 2023-05-12 15:03:46 +02:00 committed by GitHub
parent b040d5e0c9
commit 47d14b0a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 99 additions and 46 deletions

16
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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"
}

View File

@ -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": "журнал"
}

View File

@ -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()) {

View File

@ -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%);
}

View File

@ -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 (
<aside
ref={(el) => (containerRef.current = el)}
@ -111,6 +122,11 @@ export const Panel = (props: Props) => {
{t('Publication settings')}
</a>
</p>
<p>
<a onClick={handleFixTypographyLinkClick} href="#">
{t('Fix typography')}
</a>
</p>
<p>
<a>{t('Corrections history')}</a>
</p>

View File

@ -1,5 +1,6 @@
.ProseMirror {
outline: none;
min-height: 300px;
blockquote {
@include font-size(1.6rem);

View File

@ -9,7 +9,7 @@
color: #ccc;
}
&:before {
&::before {
background: #000;
content: '';
height: 100%;

View File

@ -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);
}

View File

@ -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

View File

@ -92,7 +92,7 @@
}
}
//Grow input
// Grow input
.editSettings,
.edit {

View File

@ -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}
>
<Icon name="up-button" class={styles.icon} />
<span class={styles.scrollTopButtonLabel}>{t('Scroll up')}</span>

View File

@ -17,6 +17,7 @@
border: none;
resize: none;
overflow: hidden;
&::placeholder {
color: #858585;
}

View File

@ -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<WordCounter>
form: ShoutForm
formErrors: Record<keyof ShoutForm, string>
editorRef: { current: () => Editor }
actions: {
saveShout: () => Promise<void>
publishShout: () => Promise<void>
@ -39,6 +41,7 @@ type EditorContextType = {
countWords: (value: WordCounter) => void
setForm: SetStoreFunction<ShoutForm>
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 editorRef: { current: () => Editor } = { current: null }
const [form, setForm] = createStore<ShoutForm>(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 = {
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 <EditorContext.Provider value={value}>{props.children}</EditorContext.Provider>
}

View File

@ -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;

View File

@ -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, '')
}