{count()}
-
-
);
diff --git a/src/components/Spinner/Spinner.scss b/src/components/Spinner/Spinner.scss
deleted file mode 100644
index f11e721..0000000
--- a/src/components/Spinner/Spinner.scss
+++ /dev/null
@@ -1,26 +0,0 @@
-.spinner {
- --spinner-size: 1em;
- display: inline-block;
- border-top: 1px solid var(--font-color);
- border-right: 1px solid var(--font-color);
- border-bottom-style: solid;
- border-left-style: solid;
- border-radius: 99999px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-bottom-color: transparent;
- border-left-color: transparent;
- animation: 0.45s linear 0s infinite normal none running spinner;
- width: var(--spinner-size);
- height: var(--spinner-size);
-}
-
-@keyframes spinner {
- from {
- transform: rotate(0deg);
- }
-
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/components/Spinner/Spinner.tsx b/src/components/Spinner/Spinner.tsx
deleted file mode 100644
index f91921a..0000000
--- a/src/components/Spinner/Spinner.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import type { Component, JSX } from "solid-js";
-
-import "./Spinner.scss";
-
-type SpinnerProps = JSX.HTMLAttributes
;
-
-const Spinner: Component = (props) => {
- return ;
-};
-
-export default Spinner;
diff --git a/src/components/Spinner/index.ts b/src/components/Spinner/index.ts
deleted file mode 100644
index 66d1096..0000000
--- a/src/components/Spinner/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./Spinner";
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
deleted file mode 100644
index f487bb2..0000000
--- a/src/hooks/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./useForm";
diff --git a/src/hooks/useForm.ts b/src/hooks/useForm.ts
deleted file mode 100644
index 0e3a936..0000000
--- a/src/hooks/useForm.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import type { Accessor } from "solid-js";
-
-import { createStore, SetStoreFunction } from "solid-js/store";
-
-type HTMLElementsType = HTMLInputElement | HTMLTextAreaElement;
-type CustomValidatorType = (element: HTMLElementsType) => string | false;
-type FieldConfigType = { element: HTMLElementsType; validators: Array };
-type FormSubmitFnType = (ref: HTMLFormElement, accessor: Accessor<(form: HTMLFormElement) => unknown>) => void;
-type ValidateFnType = (ref: HTMLElementsType, accessor: Accessor>) => void;
-type СheckValidFnType = (config: FieldConfigType, setErrors: SetStoreFunction>, errorClass: string) => void;
-
-const checkValid: СheckValidFnType = (fieldConfig, setErrors, errorClass) => {
- const { element, validators = [] } = fieldConfig;
-
- element.setCustomValidity("");
- element.checkValidity();
- let message = element.validationMessage;
-
- /* Run custom validators */
- if (Array.isArray(validators)) {
- if (!message) {
- for (const validator of validators) {
- if (typeof validator === "function") {
- const text = validator(element);
- if (text) {
- element.setCustomValidity(text);
- break;
- }
- }
- }
- message = element.validationMessage;
- }
- }
-
- /* Set errors if message exists and class to input element */
- if (message) {
- errorClass && element.classList.toggle(errorClass, true);
- setErrors({ [element.name]: message });
- }
-};
-
-export const useForm = ({ errorClass }) => {
- const [errors, setErrors] = createStore<{ [key: string]: string | undefined }>({});
- const fields = {};
-
- const validate: ValidateFnType = (ref, accessor) => {
- const validators = accessor();
- let config: FieldConfigType;
- fields[ref.name] = config = { element: ref, validators };
- ref.onblur = () => checkValid(config, setErrors, errorClass);
- ref.oninput = () => {
- if (!errors[ref.name]) return;
- setErrors({ [ref.name]: undefined });
- errorClass && ref.classList.toggle(errorClass, false);
- };
- };
-
- const formSubmit: FormSubmitFnType = (ref, accessor) => {
- const callback = accessor();
- ref.setAttribute("novalidate", "");
- ref.onsubmit = (e) => {
- e.preventDefault();
- let isError = false;
-
- /* Validate all fields of form */
- for (const key in fields) {
- const field = fields[key] as FieldConfigType;
- checkValid(field, setErrors, errorClass);
- if (!isError && field.element.validationMessage) {
- field.element.focus();
- isError = true;
- }
- }
-
- if (typeof callback === "function") !isError && callback(ref);
- };
- };
-
- return { validate, formSubmit, errors };
-};
diff --git a/src/i18n/en/ui.ts b/src/i18n/en/ui.ts
index f903dc7..e41afb3 100644
--- a/src/i18n/en/ui.ts
+++ b/src/i18n/en/ui.ts
@@ -34,8 +34,8 @@ export default {
"404.heading": "404",
"404.description": "The page you are trying to find does not exist.",
/* Buttons */
- "btn.send": "Submit",
- "btn.sending": "Submitting...",
+ "btn.submit": "Submit",
+ "btn.submiting": "Submitting...",
"btn.sourceCode": "Source",
"btn.demo": "Demo",
"btn.article": "Article",
diff --git a/src/i18n/ru/ui.ts b/src/i18n/ru/ui.ts
index d0bcd2e..cd47bde 100644
--- a/src/i18n/ru/ui.ts
+++ b/src/i18n/ru/ui.ts
@@ -34,8 +34,8 @@ export default {
"404.heading": "404",
"404.description": "Страницу которую вы пытаетесь найти не существует.",
/* Buttons */
- "btn.send": "Отправить",
- "btn.sending": "Отправка...",
+ "btn.submit": "Отправить",
+ "btn.submitting": "Отправка...",
"btn.sourceCode": "Исходник",
"btn.demo": "Демо",
"btn.article": "Статья",
diff --git a/src/i18n/utils.ts b/src/i18n/utils.ts
index 4482df5..a6afe62 100644
--- a/src/i18n/utils.ts
+++ b/src/i18n/utils.ts
@@ -19,33 +19,6 @@ export function formatArticlesByLangs(data: Record): MDXInstance[] {
- const data = import.meta.glob>("../../content/articles/**/*.mdx", { eager: true });
- const modules = formatArticlesByLangs(data);
- const siteLang = utils.getLanguageFromURL(Astro.url.pathname);
- const articles: MDXInstance[] = [];
-
- for (const key of Object.keys(modules)) {
- const langs = Object.keys(modules[key]);
- for (const articleLang of langs) {
- const isNonDefaultLanguage = !langs.includes(siteLang) && langs.length === 1;
- const article = modules[key];
-
- if (articleLang === siteLang) {
- articles.push(article[siteLang]);
- article[siteLang].frontmatter.lang = siteLang;
- }
-
- if (isNonDefaultLanguage) {
- articles.push(article[articleLang]);
- article[articleLang].frontmatter.lang = articleLang;
- }
- }
- }
-
- return articles;
-}
-
export function getLanguageKeys(): Array {
return Object.keys(languages);
}
diff --git a/src/services/ArticleService.ts b/src/services/ArticleService.ts
new file mode 100644
index 0000000..708a294
--- /dev/null
+++ b/src/services/ArticleService.ts
@@ -0,0 +1,34 @@
+import type { AstroGlobal, MDXInstance } from "astro";
+import { formatArticlesByLangs } from "@i18n/utils";
+import { getLanguageFromURL } from "@utils/url";
+
+class ArticleService {
+ public getTranslatedArticles(Astro: Readonly): MDXInstance[] {
+ const data = import.meta.glob>("../../content/articles/**/*.mdx", { eager: true });
+ const modules = formatArticlesByLangs(data);
+ const siteLang = getLanguageFromURL(Astro.url.pathname);
+ const articles: MDXInstance[] = [];
+
+ for (const key of Object.keys(modules)) {
+ const langs = Object.keys(modules[key]);
+ for (const articleLang of langs) {
+ const isNonDefaultLanguage = !langs.includes(siteLang) && langs.length === 1;
+ const article = modules[key];
+
+ if (articleLang === siteLang) {
+ articles.push(article[siteLang]);
+ article[siteLang].frontmatter.lang = siteLang;
+ }
+
+ if (isNonDefaultLanguage) {
+ articles.push(article[articleLang]);
+ article[articleLang].frontmatter.lang = articleLang;
+ }
+ }
+ }
+
+ return articles;
+ }
+}
+
+export default new ArticleService();
diff --git a/src/services/index.ts b/src/services/index.ts
new file mode 100644
index 0000000..1d9fc80
--- /dev/null
+++ b/src/services/index.ts
@@ -0,0 +1 @@
+export { default as ArticleService } from "./ArticleService";
diff --git a/src/styles/global.scss b/src/styles/global.scss
index 2fc2d7e..0e565a4 100644
--- a/src/styles/global.scss
+++ b/src/styles/global.scss
@@ -128,8 +128,3 @@ a {
color: var(--color-blue-400);
}
}
-
-button {
- background: none;
- border: none;
-}
diff --git a/src/templates/Articles.astro b/src/templates/Articles.astro
index 56ac1c6..e53d204 100644
--- a/src/templates/Articles.astro
+++ b/src/templates/Articles.astro
@@ -4,10 +4,11 @@ import PageHeading from "@components/PageHeading";
import ArticlesList from "@components/ArticlesList";
import { transformArticles, formatToArticleBlocks } from "@utils/articles";
import { getLanguageFromURL } from "@root/utils";
-import { useTranslation, getTranslatedArticles } from "@i18n/utils";
+import { useTranslation } from "@i18n/utils";
+import { ArticleService } from "@services/index";
const t = useTranslation(Astro);
-const data = getTranslatedArticles(Astro);
+const data = ArticleService.getTranslatedArticles(Astro);
const tags = new Set(data.map((article) => article.frontmatter.tags).flat());
const lang = getLanguageFromURL(Astro.url.pathname);
const articles = transformArticles(data);
diff --git a/src/templates/Contacts.astro b/src/templates/Contacts.astro
index 5689e4b..5811694 100644
--- a/src/templates/Contacts.astro
+++ b/src/templates/Contacts.astro
@@ -13,19 +13,7 @@ const lang = getLanguageFromURL(Astro.url.pathname);
diff --git a/src/templates/Home.astro b/src/templates/Home.astro
index 73b11c1..a093826 100644
--- a/src/templates/Home.astro
+++ b/src/templates/Home.astro
@@ -4,10 +4,11 @@ import PageLayout from "@layouts/default.astro";
import RecentArticles from "@components/RecentArticles";
import { Splash, SplashHeading, SplashLinks, Link } from "@components/Splash";
import { getLanguageFromURL } from "@root/utils";
-import { getTranslatedArticles, useTranslation } from "@i18n/utils";
+import { useTranslation } from "@i18n/utils";
+import { ArticleService } from "@services/index";
import UIString from "@components/UIString";
-const data = getTranslatedArticles(Astro);
+const data = ArticleService.getTranslatedArticles(Astro);
const t = useTranslation(Astro);
const lang = getLanguageFromURL(Astro.url.pathname);
const articles = utils.transformArticles(data);
diff --git a/tsconfig.json b/tsconfig.json
index 9127811..237b3e9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,7 +19,8 @@
"@stores/*": ["./src/stores/*"],
"@hooks/*": ["./src/hooks/*"],
"@i18n/*": ["./src/i18n/*"],
- "@images/*": ["./src/images/*"]
+ "@images/*": ["./src/images/*"],
+ "@services/*": ["./src/services/*"]
},
"outDir": "./dist",
"typeRoots": ["./node_modules/@types", "./src/types"]