diff --git a/src/components/Author/Userpic/Userpic.tsx b/src/components/Author/Userpic/Userpic.tsx
index fbec00c9..11e3bc4c 100644
--- a/src/components/Author/Userpic/Userpic.tsx
+++ b/src/components/Author/Userpic/Userpic.tsx
@@ -22,7 +22,7 @@ export const Userpic = (props: Props) => {
const letters = () => {
if (!props.name) return
const names = props.name ? props.name.split(' ') : []
- return `${names[0][0 ?? names[0][0]]}.${names.length > 1 ? `${names[1][0]}.` : ''}`
+ return `${names[0][0] ? names[0][0] : ''}.${names.length > 1 ? `${names[1][0]}.` : ''}`
}
const avatarSize = createMemo(() => {
diff --git a/src/components/Editor/BubbleMenu/BlockquoteBubbleMenu.tsx b/src/components/Editor/BubbleMenu/BlockquoteBubbleMenu.tsx
index 4d1b4f2e..6247c74e 100644
--- a/src/components/Editor/BubbleMenu/BlockquoteBubbleMenu.tsx
+++ b/src/components/Editor/BubbleMenu/BlockquoteBubbleMenu.tsx
@@ -22,7 +22,7 @@ export const BlockquoteBubbleMenu = (props: Props) => {
type="button"
class={styles.bubbleMenuButton}
onClick={() => {
- props.editor.chain().focus().setBlockQuoteFloat('left').run()
+ props.editor?.chain().focus().setBlockQuoteFloat('left').run()
}}
>
@@ -35,7 +35,7 @@ export const BlockquoteBubbleMenu = (props: Props) => {
ref={triggerRef}
type="button"
class={styles.bubbleMenuButton}
- onClick={() => props.editor.chain().focus().setBlockQuoteFloat(null).run()}
+ onClick={() => props.editor?.chain().focus().setBlockQuoteFloat(null).run()}
>
@@ -47,7 +47,7 @@ export const BlockquoteBubbleMenu = (props: Props) => {
ref={triggerRef}
type="button"
class={styles.bubbleMenuButton}
- onClick={() => props.editor.chain().focus().setBlockQuoteFloat('right').run()}
+ onClick={() => props.editor?.chain().focus().setBlockQuoteFloat('right').run()}
>
diff --git a/src/components/Editor/BubbleMenu/FigureBubbleMenu.tsx b/src/components/Editor/BubbleMenu/FigureBubbleMenu.tsx
index 27ce2f28..706c9048 100644
--- a/src/components/Editor/BubbleMenu/FigureBubbleMenu.tsx
+++ b/src/components/Editor/BubbleMenu/FigureBubbleMenu.tsx
@@ -33,7 +33,7 @@ export const FigureBubbleMenu = (props: Props) => {
ref={triggerRef}
type="button"
class={styles.bubbleMenuButton}
- onClick={() => props.editor.chain().focus().setFigureFloat('left').run()}
+ onClick={() => props.editor?.chain().focus().setFigureFloat('left').run()}
>
@@ -45,7 +45,7 @@ export const FigureBubbleMenu = (props: Props) => {
ref={triggerRef}
type="button"
class={styles.bubbleMenuButton}
- onClick={() => props.editor.chain().focus().setFigureFloat(null).run()}
+ onClick={() => props.editor?.chain().focus().setFigureFloat(null).run()}
>
@@ -57,7 +57,7 @@ export const FigureBubbleMenu = (props: Props) => {
ref={triggerRef}
type="button"
class={styles.bubbleMenuButton}
- onClick={() => props.editor.chain().focus().setFigureFloat('right').run()}
+ onClick={() => props.editor?.chain().focus().setFigureFloat('right').run()}
>
@@ -67,7 +67,7 @@ export const FigureBubbleMenu = (props: Props) => {
diff --git a/src/components/Editor/BubbleMenu/IncutBubbleMenu.tsx b/src/components/Editor/BubbleMenu/IncutBubbleMenu.tsx
index 01517729..4a80a680 100644
--- a/src/components/Editor/BubbleMenu/IncutBubbleMenu.tsx
+++ b/src/components/Editor/BubbleMenu/IncutBubbleMenu.tsx
@@ -19,7 +19,7 @@ export const IncutBubbleMenu = (props: Props) => {
const { t } = useLocalize()
const [substratBubbleOpen, setSubstratBubbleOpen] = createSignal(false)
const handleChangeBg = (bg: string | null) => {
- props.editor.chain().focus().setArticleBg(bg).run()
+ props.editor?.chain().focus().setArticleBg(bg).run()
setSubstratBubbleOpen(false)
}
return (
@@ -27,14 +27,14 @@ export const IncutBubbleMenu = (props: Props) => {
@@ -42,7 +42,7 @@ export const IncutBubbleMenu = (props: Props) => {
diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
index 633fa63e..7d72ab0a 100644
--- a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
+++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
@@ -91,9 +91,9 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
const handleAddFootnote = (footnote: string) => {
if (footNote()) {
- props.editor.chain().focus().updateFootnote({ value: footnote }).run()
+ props.editor?.chain().focus().updateFootnote({ value: footnote }).run()
} else {
- props.editor.chain().focus().setFootnote({ value: footnote }).run()
+ props.editor?.chain().focus().setFootnote({ value: footnote }).run()
}
setFootNote()
setLinkEditorOpen(false)
@@ -108,16 +108,16 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
const handleSetPunchline = () => {
if (isPunchLine()) {
- props.editor.chain().focus().toggleBlockquote('punchline').run()
+ props.editor?.chain().focus().toggleBlockquote('punchline').run()
}
- props.editor.chain().focus().toggleBlockquote('quote').run()
+ props.editor?.chain().focus().toggleBlockquote('quote').run()
toggleTextSizePopup()
}
const handleSetQuote = () => {
if (isQuote()) {
- props.editor.chain().focus().toggleBlockquote('quote').run()
+ props.editor?.chain().focus().toggleBlockquote('quote').run()
}
- props.editor.chain().focus().toggleBlockquote('punchline').run()
+ props.editor?.chain().focus().toggleBlockquote('punchline').run()
toggleTextSizePopup()
}
@@ -130,13 +130,13 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
})
const handleOpenLinkForm = () => {
- props.editor.chain().focus().addTextWrap({ class: 'highlight-fake-selection' }).run()
+ props.editor?.chain().focus().addTextWrap({ class: 'highlight-fake-selection' }).run()
setLinkEditorOpen(true)
}
const handleCloseLinkForm = () => {
setLinkEditorOpen(false)
- props.editor.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run()
+ props.editor?.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run()
}
return (
@@ -188,7 +188,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isH1()
})}
onClick={() => {
- props.editor.chain().focus().toggleHeading({ level: 2 }).run()
+ props.editor?.chain().focus().toggleHeading({ level: 2 }).run()
toggleTextSizePopup()
}}
>
@@ -205,7 +205,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isH2()
})}
onClick={() => {
- props.editor.chain().focus().toggleHeading({ level: 3 }).run()
+ props.editor?.chain().focus().toggleHeading({ level: 3 }).run()
toggleTextSizePopup()
}}
>
@@ -222,7 +222,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isH3()
})}
onClick={() => {
- props.editor.chain().focus().toggleHeading({ level: 4 }).run()
+ props.editor?.chain().focus().toggleHeading({ level: 4 }).run()
toggleTextSizePopup()
}}
>
@@ -273,7 +273,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isIncut()
})}
onClick={() => {
- props.editor.chain().focus().toggleArticle().run()
+ props.editor?.chain().focus().toggleArticle().run()
toggleTextSizePopup()
}}
>
@@ -296,7 +296,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
class={clsx(styles.bubbleMenuButton, {
[styles.bubbleMenuButtonActive]: isBold()
})}
- onClick={() => props.editor.chain().focus().toggleBold().run()}
+ onClick={() => props.editor?.chain().focus().toggleBold().run()}
>
@@ -310,7 +310,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
class={clsx(styles.bubbleMenuButton, {
[styles.bubbleMenuButtonActive]: isItalic()
})}
- onClick={() => props.editor.chain().focus().toggleItalic().run()}
+ onClick={() => props.editor?.chain().focus().toggleItalic().run()}
>
@@ -326,7 +326,9 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
class={clsx(styles.bubbleMenuButton, {
[styles.bubbleMenuButtonActive]: isHighlight()
})}
- onClick={() => props.editor.chain().focus().toggleHighlight({ color: '#f6e3a1' }).run()}
+ onClick={() =>
+ props.editor?.chain().focus().toggleHighlight({ color: '#f6e3a1' }).run()
+ }
>
@@ -389,7 +391,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isBulletList()
})}
onClick={() => {
- props.editor.chain().focus().toggleBulletList().run()
+ props.editor?.chain().focus().toggleBulletList().run()
toggleListPopup()
}}
>
@@ -406,7 +408,7 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
[styles.bubbleMenuButtonActive]: isOrderedList()
})}
onClick={() => {
- props.editor.chain().focus().toggleOrderedList().run()
+ props.editor?.chain().focus().toggleOrderedList().run()
toggleListPopup()
}}
>
diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx
index 28e953f6..e4a401d7 100644
--- a/src/components/Feed/ArticleCard/ArticleCard.tsx
+++ b/src/components/Feed/ArticleCard/ArticleCard.tsx
@@ -7,6 +7,7 @@ import { Popover } from '~/components/_shared/Popover'
import { useLocalize } from '~/context/localize'
import { useSession } from '~/context/session'
import type { Author, Maybe, Shout, Topic } from '~/graphql/schema/core.gen'
+import { sentenceSeparator } from '~/intl/chars'
import { capitalize } from '~/utils/capitalize'
import { descFromBody } from '~/utils/meta'
import { CoverImage } from '../../Article/CoverImage'
diff --git a/src/components/SearchModal/SearchModal.module.scss b/src/components/SearchModal/SearchModal.module.scss
index a35c919c..ddfc00eb 100644
--- a/src/components/SearchModal/SearchModal.module.scss
+++ b/src/components/SearchModal/SearchModal.module.scss
@@ -1,6 +1,4 @@
@mixin search-filter-control {
- @include font-size(1.4rem);
-
height: 4rem;
padding: 0 2rem;
background: rgb(64 64 64 / 50%);
@@ -9,6 +7,8 @@
font-weight: 500;
white-space: nowrap;
+ @include font-size(1.4rem);
+
&:hover {
background: #404040;
}
@@ -23,8 +23,6 @@
}
.searchInput {
- @include font-size(4.8rem);
-
width: 100%;
padding: 0 0 0.5rem;
background: none;
@@ -34,6 +32,8 @@
font-weight: bold;
outline: none;
+ @include font-size(4.8rem);
+
&::placeholder {
color: rgb(255 255 255 / 32%);
}
@@ -60,10 +60,10 @@
}
.searchDescription {
- @include font-size(1.6rem);
-
margin-bottom: 44px;
color: rgb(255 255 255 / 64%);
+
+ @include font-size(1.6rem);
}
.topicsList {
diff --git a/src/components/Topic/TopicBadge/TopicBadge.module.scss b/src/components/Topic/TopicBadge/TopicBadge.module.scss
index f4c205bc..06280c1c 100644
--- a/src/components/Topic/TopicBadge/TopicBadge.module.scss
+++ b/src/components/Topic/TopicBadge/TopicBadge.module.scss
@@ -72,7 +72,7 @@
line-height: 1.4;
margin: 0.8rem 0;
- -webkit-line-clamp: 2;
+ line-clamp: 2;
}
}
@@ -165,4 +165,4 @@
word-break: keep-all;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/components/TopicsNav/TopicsNav.tsx b/src/components/TopicsNav/TopicsNav.tsx
index 5357e22f..b0818bb4 100644
--- a/src/components/TopicsNav/TopicsNav.tsx
+++ b/src/components/TopicsNav/TopicsNav.tsx
@@ -5,16 +5,15 @@ import { Icon } from '~/components/_shared/Icon'
import { useLocalize } from '~/context/localize'
import { useTopics } from '~/context/topics'
import type { Topic } from '~/graphql/schema/core.gen'
+import { ruChars } from '~/intl/chars'
import { getRandomItemsFromArray } from '~/utils/random'
import styles from './TopicsNav.module.scss'
-const russianChars = /[ЁА-яё]/
-
export const RandomTopics = () => {
const { sortedTopics } = useTopics()
const { lang, t } = useLocalize()
const tag = (topic: Topic) =>
- russianChars.test(topic.title || '') && lang() !== 'ru' ? topic.slug : topic.title
+ ruChars.test(topic.title || '') && lang() !== 'ru' ? topic.slug : topic.title
const [randomTopics, setRandomTopics] = createSignal([])
createEffect(
on(sortedTopics, (ttt: Topic[]) => {
diff --git a/src/components/Views/AllTopics/AllTopics.tsx b/src/components/Views/AllTopics/AllTopics.tsx
index 126e359b..d1e9421e 100644
--- a/src/components/Views/AllTopics/AllTopics.tsx
+++ b/src/components/Views/AllTopics/AllTopics.tsx
@@ -6,6 +6,7 @@ import { SearchField } from '~/components/_shared/SearchField'
import { useLocalize } from '~/context/localize'
import { useTopics } from '~/context/topics'
import type { Topic } from '~/graphql/schema/core.gen'
+import { enChars, ruChars } from '~/intl/chars'
import { dummyFilter } from '~/intl/dummyFilter'
import { scrollHandler } from '~/utils/scroll'
import { TopicBadge } from '../../Topic/TopicBadge'
@@ -21,9 +22,6 @@ export const ABC = {
en: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ#'
}
-const russianChars = /[^ËА-яё]/
-const latinChars = /[^A-z]/
-
export const AllTopics = (props: Props) => {
const { t, lang } = useLocalize()
const alphabet = createMemo(() => ABC[lang()])
@@ -38,8 +36,8 @@ export const AllTopics = (props: Props) => {
return topics().reduce(
(acc, topic) => {
let letter = lang() === 'en' ? topic.slug[0].toUpperCase() : (topic?.title?.[0] || '').toUpperCase()
- if (russianChars.test(letter) && lang() === 'ru') letter = '#'
- if (latinChars.test(letter) && lang() === 'en') letter = '#'
+ if (enChars.test(letter) && lang() === 'ru') letter = '#'
+ if (ruChars.test(letter) && lang() === 'en') letter = '#'
if (!acc[letter]) acc[letter] = []
acc[letter].push(topic)
return acc
diff --git a/src/components/Views/Profile/ProfileSettings.tsx b/src/components/Views/Profile/ProfileSettings.tsx
index fb7b962e..94c7eddf 100644
--- a/src/components/Views/Profile/ProfileSettings.tsx
+++ b/src/components/Views/Profile/ProfileSettings.tsx
@@ -340,8 +340,16 @@ export const ProfileSettings = () => {
/>
{t('About')}
- updateFormField('about', value)}
placeholder={t('About')}
/>
diff --git a/src/components/_shared/DropArea/DropArea.tsx b/src/components/_shared/DropArea/DropArea.tsx
index 0c1159cd..a49005cb 100644
--- a/src/components/_shared/DropArea/DropArea.tsx
+++ b/src/components/_shared/DropArea/DropArea.tsx
@@ -37,9 +37,8 @@ export const DropArea = (props: Props) => {
const runUpload = async (files: UploadFile[]) => {
try {
setLoading(true)
- const handler = props.fileType === 'image' ? handleImageUpload : handleFileUpload
const tkn = session()?.access_token as string
- // Since handler returns a promise, we need to await the results
+ const handler = props.fileType === 'image' ? handleImageUpload : handleFileUpload
tkn &&
Promise.all(files.map((file) => handler(file, tkn)))
.then(props.onUpload)
diff --git a/src/context/following.tsx b/src/context/following.tsx
index f4eb4853..4ae3e25c 100644
--- a/src/context/following.tsx
+++ b/src/context/following.tsx
@@ -172,7 +172,7 @@ export const FollowingProvider = (props: { children: JSX.Element }) => {
}
break
}
- // case 'AUTHOR':
+ // case 'AUTHOR': {
default: {
if (value) {
if (!updatedFollows.authors?.some((author) => author.slug === slug)) {
diff --git a/src/intl/chars.ts b/src/intl/chars.ts
new file mode 100644
index 00000000..37e85f66
--- /dev/null
+++ b/src/intl/chars.ts
@@ -0,0 +1,6 @@
+export const allChars = /[^\dA-zА-я]/
+export const slugChars = /[^\da-z]/g
+export const enChars = /[^A-z]/
+export const ruChars = /[^ËА-яё]/
+export const sentenceSeparator = /{!|\?|:|;}\s/
+export const cyrillicRegex = /[\u0400-\u04FF]/ // Range for Cyrillic characters
diff --git a/src/intl/translate.ts b/src/intl/translate.ts
index 59c6d875..6440b64e 100644
--- a/src/intl/translate.ts
+++ b/src/intl/translate.ts
@@ -1,12 +1,8 @@
import { Author } from '~/graphql/schema/core.gen'
import { capitalize } from '~/utils/capitalize'
+import { allChars, cyrillicRegex, enChars, ruChars } from './chars'
import { translit } from './translit'
-const cyrillicRegex = /[\u0400-\u04FF]/ // Range for Cyrillic characters
-const allChars = /[^\dA-zА-я]/
-const rusChars = /[^ËА-яё]/
-const enChars = /[^A-z]/
-
export const isCyrillic = (s: string): boolean => {
return cyrillicRegex.test(s)
}
@@ -32,7 +28,7 @@ export const authorLetterReduce = (acc: { [x: string]: Author[] }, author: Autho
letter = found[0].toUpperCase()
}
}
- if (rusChars.test(letter) && lng === 'ru') letter = '@'
+ if (ruChars.test(letter) && lng === 'ru') letter = '@'
if (enChars.test(letter) && lng === 'en') letter = '@'
if (!acc[letter]) acc[letter] = []
diff --git a/src/intl/translit.ts b/src/intl/translit.ts
index 0cbfc5ac..7e3ad936 100644
--- a/src/intl/translit.ts
+++ b/src/intl/translit.ts
@@ -1,4 +1,5 @@
import translitConfig from './abc-translit.json'
+import { ruChars, slugChars } from './chars'
const ru2en: { [key: string]: string } = translitConfig
const rusChars = /[ЁА-яё]/
@@ -7,7 +8,7 @@ export const translit = (str: string) => {
return ''
}
- const isCyrillic = rusChars.test(str)
+ const isCyrillic = ruChars.test(str)
if (!isCyrillic) {
return str
@@ -17,7 +18,5 @@ export const translit = (str: string) => {
}
export const slugify = (text: string) => {
- return translit(text.toLowerCase())
- .replaceAll(' ', '-')
- .replaceAll(/[^\da-z]/g, '')
+ return translit(text.toLowerCase()).replaceAll(' ', '-').replaceAll(slugChars, '')
}
diff --git a/src/routes/feed/my/[...mode]/[...order].tsx b/src/routes/feed/my/[...mode]/[...order].tsx
index bc7ea929..52daa16f 100644
--- a/src/routes/feed/my/[...mode]/[...order].tsx
+++ b/src/routes/feed/my/[...mode]/[...order].tsx
@@ -54,7 +54,7 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
const order = createMemo(() => {
return (
- (paramOrderPattern.test(props.params.order)
+ (paramPattern.test(props.params.order)
? props.params.order === 'hot'
? 'last_comment'
: props.params.order
diff --git a/tests/1-page-sections.spec.ts b/tests/1-page-sections.spec.ts
index 8454dab4..a16f3854 100644
--- a/tests/1-page-sections.spec.ts
+++ b/tests/1-page-sections.spec.ts
@@ -5,7 +5,7 @@ import { type Page, expect, test } from '@playwright/test'
/* Global starting test config */
let page: Page
-const discoursPattern = /Дискурс/
+
function httpsGet(url: string): Promise {
return new Promise((resolve, reject) => {
https
@@ -50,7 +50,8 @@ test.beforeAll(async ({ browser }) => {
page = await browser.newPage()
test.setTimeout(150000)
await page.goto(baseURL)
- await expect(page).toHaveTitle(discoursPattern)
+ // biome-ignore lint/performance/useTopLevelRegex:
+ await expect(page).toHaveTitle(/Дискурс/)
console.log('Localhost server started successfully!')
})
test.afterAll(async () => {
diff --git a/tests/2-auth-topic-actions.spec.ts b/tests/2-auth-topic-actions.spec.ts
index afa0f196..30196cf2 100644
--- a/tests/2-auth-topic-actions.spec.ts
+++ b/tests/2-auth-topic-actions.spec.ts
@@ -5,7 +5,6 @@ import { type Page, expect, test } from '@playwright/test'
/* Global starting test config */
let page: Page
-const discoursPattern = /Дискурс/
function httpsGet(url: string): Promise {
return new Promise((resolve, reject) => {
https
@@ -50,7 +49,8 @@ test.beforeAll(async ({ browser }) => {
page = await browser.newPage()
test.setTimeout(150000)
await page.goto(baseURL)
- await expect(page).toHaveTitle(discoursPattern)
+ // biome-ignore lint/performance/useTopLevelRegex:
+ await expect(page).toHaveTitle(/Дискурс/)
await page.getByRole('link', { name: 'Войти' }).click()
console.log('Localhost server started successfully!')
await page.close()
diff --git a/tests/3-auth-drafts-actions.spec.ts b/tests/3-auth-drafts-actions.spec.ts
index ee88e6d0..c9b592bc 100644
--- a/tests/3-auth-drafts-actions.spec.ts
+++ b/tests/3-auth-drafts-actions.spec.ts
@@ -6,8 +6,6 @@ import { type Page, expect, test } from '@playwright/test'
let page: Page
-const discoursPattern = /Дискурс/
-
function httpsGet(url: string): Promise {
return new Promise((resolve, reject) => {
https
@@ -52,7 +50,8 @@ test.beforeAll(async ({ browser }) => {
page = await browser.newPage()
test.setTimeout(150000)
await page.goto(baseURL)
- await expect(page).toHaveTitle(discoursPattern)
+ // biome-ignore lint/performance/useTopLevelRegex:
+ await expect(page).toHaveTitle(/Дискурс/)
console.log('Localhost server started successfully!')
await page.close()
})
diff --git a/tests/4-auth-author-actions.spec.ts b/tests/4-auth-author-actions.spec.ts
index 50d79726..d47516e0 100644
--- a/tests/4-auth-author-actions.spec.ts
+++ b/tests/4-auth-author-actions.spec.ts
@@ -8,8 +8,6 @@ let page: Page
/* Global starting test config */
-const discoursPattern = /Дискурс/
-
function httpsGet(url: string): Promise {
return new Promise((resolve, reject) => {
https
@@ -56,7 +54,8 @@ test.beforeAll(async ({ browser }) => {
page = await context.newPage()
test.setTimeout(150000)
await page.goto(baseURL)
- await expect(page).toHaveTitle(discoursPattern)
+ // biome-ignore lint/performance/useTopLevelRegex:
+ await expect(page).toHaveTitle(/Дискурс/)
await page.getByRole('link', { name: 'Войти' }).click()
console.log('Localhost server started successfully!')
await page.close()