This commit is contained in:
Sergey Yarkov 2022-08-28 14:27:47 +03:00
parent f072df8345
commit 01bb18b774
15 changed files with 71 additions and 18 deletions

View File

@ -1,5 +1,5 @@
{
"printWidth": 150,
"printWidth": 120,
"semi": true,
"singleQuote": false,
"tabWidth": 2,

View File

@ -15,7 +15,7 @@
"start": "astro dev",
"build": "astro build",
"preview": "astro preview --host",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md,mdx}\"",
"format": "prettier --write ./src/\"**/*.{js,jsx,ts,tsx,json,md,mdx,astro}\"",
"lint": "eslint '**/*.{js,mjs,ts,tsx}'"
},
"devDependencies": {

View File

@ -14,13 +14,19 @@ export const ArticleItem: Component<ArticleItemProps> = (props) => {
const hrefLangPrefix = props.data.lang && props.data.lang !== DEFAULT_LANGUAGE ? "/en" : "";
return (
<article class="article-item">
<a href={`${hrefLangPrefix}/blog/${new Date(props.data.published_at).toLocaleDateString("en-CA")}/${props.data.slug}/`}>
<a
href={`${hrefLangPrefix}/blog/${new Date(props.data.published_at).toLocaleDateString("en-CA")}/${
props.data.slug
}/`}
>
<div class="flex">
<h3>{props.data.title}</h3>
{isNonDefaultLanguage && <sup>{props.data.lang.toLocaleUpperCase()}</sup>}
</div>
<p>
<time datetime={props.data.published_at.toString()}>{createDateFormatter(props.lang).format(new Date(props.data.published_at))}</time>
<time datetime={props.data.published_at.toString()}>
{createDateFormatter(props.lang).format(new Date(props.data.published_at))}
</time>
</p>
</a>
</article>

View File

@ -21,7 +21,9 @@ const { title, coverImage, tags, author, published_at } = data;
{
tags.map((tag) => (
<li>
<TranslatedLink rel="tag" to={`/articles/?tags=${tag.toLocaleLowerCase()}`}>{`${tag}${tags.at(-1) === tag ? "" : ","}`}</TranslatedLink>
<TranslatedLink rel="tag" to={`/articles/?tags=${tag.toLocaleLowerCase()}`}>{`${tag}${
tags.at(-1) === tag ? "" : ","
}`}</TranslatedLink>
</li>
))
}
@ -31,7 +33,9 @@ const { title, coverImage, tags, author, published_at } = data;
<h1 itemprop="headline">{title}</h1>
</div>
<div class="published">
<time itemprop="datePublished" datetime={published_at}>{createDateFormatter(lang).format(new Date(published_at))}</time>
<time itemprop="datePublished" datetime={published_at}
>{createDateFormatter(lang).format(new Date(published_at))}
</time>
<span itemprop="author">{author}</span>
</div>
{

View File

@ -84,7 +84,10 @@ const ArticlesList: Component<ArticlesListProps> = (props) => {
return (
<div class="articles-list__wrapper">
<h2>{year}</h2>
<For each={sortArtcilesByDate(articles()[year])} children={(article) => <ArticleItem lang={props.lang} data={article} />} />
<For
each={sortArtcilesByDate(articles()[year])}
children={(article) => <ArticleItem lang={props.lang} data={article} />}
/>
</div>
);
}}

View File

@ -30,8 +30,20 @@ const { title = SITE_METADATA.title, description, canonicalUrl } = Astro.props a
<meta name="description" content={description || t("site.description")} />
<meta name="theme-color" content={SITE_METADATA.themeColor} />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png" media="(prefers-color-scheme: light)" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-light-16x16.png" media="(prefers-color-scheme: light)" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-light-32x32.png"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon-light-16x16.png"
media="(prefers-color-scheme: light)"
/>
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-dark-32x32.png" media="(prefers-color-scheme: dark)" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-dark-16x16.png" media="(prefers-color-scheme: dark)" />
<link rel="manifest" href="/site.webmanifest" />

View File

@ -19,7 +19,14 @@ const t = useTranslation(Astro);
</div>
</div>
<input name="subject" placeholder={t("input.subjectField")} type="text" autocomplete="off" required />
<textarea name="message" placeholder={t("input.messageField")} id="message" autocomplete="off" cols={30} rows={10} required></textarea>
<textarea
name="message"
placeholder={t("input.messageField")}
id="message"
autocomplete="off"
cols={30}
rows={10}
required></textarea>
<div class="footer">
<Button type="submit">{t("btn.submit")}</Button>
</div>

View File

@ -24,7 +24,10 @@ const { pathname } = Astro.url;
{
nav.map((link) => (
<li>
<TranslatedLink class={pathname.includes(removeSlashes(link.url)) && pathname.split("/").length < 5 && "active"} to={link.url}>
<TranslatedLink
class={pathname.includes(removeSlashes(link.url)) && pathname.split("/").length < 5 && "active"}
to={link.url}
>
<UIString key={link.key} />
</TranslatedLink>
</li>

View File

@ -13,7 +13,8 @@ export default {
"pageTitle.projects": "Projects",
"pageTitle.contacts": "Contacts",
/* Page descriptions */
"pageDescription.articles": "Technical articles, tutorials and various reference materials related to IT topics can be found here.",
"pageDescription.articles":
"Technical articles, tutorials and various reference materials related to IT topics can be found here.",
"pageDescription.projects": "A few of my main projects that have been developed and published in open access.",
"pageDescription.contacts": "Use the feedback form or write to me on social networks.",
/* Navigation */

View File

@ -13,7 +13,8 @@ export default {
"pageTitle.projects": "Проекты",
"pageTitle.contacts": "Контакты",
/* Page descriptions */
"pageDescription.articles": "Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь.",
"pageDescription.articles":
"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь.",
"pageDescription.projects": "Несколько моих основных проектов которые были разработаны и выложены в открытый доступ.",
"pageDescription.contacts": "Воспользуйтесь формой обратной связи или напишите мне в социальные сети.",
/* Navigation */

View File

@ -16,7 +16,11 @@ const { title, description, lang = "ru", noIndex = false, canonicalUrl } = Astro
---
<html lang={lang}>
<BaseHead title={title ? `${title} | ${SITE_METADATA.title}` : SITE_METADATA.title} description={description} canonicalUrl={canonicalUrl}>
<BaseHead
title={title ? `${title} | ${SITE_METADATA.title}` : SITE_METADATA.title}
description={description}
canonicalUrl={canonicalUrl}
>
{noIndex && <meta name="robots" content="noindex" />}
</BaseHead>
<BaseLayout>

View File

@ -49,7 +49,9 @@ const { pathname } = Astro.url;
{alternateLangs
.filter((lang) => lang !== siteLang)
.map((lang) => (
<a href={DEFAULT_LANGUAGE === lang ? `/${pathname.split("/").slice(2).join("/")}` : `/${lang}${pathname}`}>{languages[lang]}</a>
<a href={DEFAULT_LANGUAGE === lang ? `/${pathname.split("/").slice(2).join("/")}` : `/${lang}${pathname}`}>
{languages[lang]}
</a>
))
.reduce((prev, curr) => [prev, ", ", curr])}
</div>

View File

@ -15,7 +15,12 @@ const articles = transformArticles(data);
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
---
<PageLayout lang={lang} title={t("pageTitle.articles")} description={t("pageDescription.articles")} canonicalUrl={canonicalUrl.href}>
<PageLayout
lang={lang}
title={t("pageTitle.articles")}
description={t("pageDescription.articles")}
canonicalUrl={canonicalUrl.href}
>
<PageHeading heading={t("pageTitle.articles")} description={t("pageDescription.articles")} />
<section>
<ArticlesList

5
src/types/main.d.ts vendored
View File

@ -5,7 +5,10 @@ export {};
declare global {
interface Window {
theme?: ThemeModeType | undefined;
addEventListener<K extends keyof CustomEventMap>(type: K, listener: (this: Window, ev: CustomEventMap[K]) => void): void;
addEventListener<K extends keyof CustomEventMap>(
type: K,
listener: (this: Window, ev: CustomEventMap[K]) => void
): void;
}
interface CustomEventMap {

View File

@ -7,5 +7,7 @@ export function isEmail(email: string): boolean {
}
export function isURL(url: string): boolean {
return new RegExp(/(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\\/~+#-]*[\w@?^=%&\\/~+#-])/).test(url);
return new RegExp(/(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\\/~+#-]*[\w@?^=%&\\/~+#-])/).test(
url
);
}