mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 10:29:21 +03:00
format
This commit is contained in:
parent
fbe085d9b8
commit
5908df1500
@ -4,7 +4,7 @@ import { toString } from "hast-util-to-string";
|
|||||||
import { escape } from "html-escaper";
|
import { escape } from "html-escaper";
|
||||||
import solid from "@astrojs/solid-js";
|
import solid from "@astrojs/solid-js";
|
||||||
import image from "@astrojs/image";
|
import image from "@astrojs/image";
|
||||||
import compress from "astro-compress";
|
// import compress from "astro-compress";
|
||||||
import mdx from "@astrojs/mdx";
|
import mdx from "@astrojs/mdx";
|
||||||
|
|
||||||
const createAnchorLabel = (heading) => {
|
const createAnchorLabel = (heading) => {
|
||||||
@ -16,15 +16,7 @@ const createAnchorLabel = (heading) => {
|
|||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: "https://yarkov.tech",
|
site: "https://yarkov.tech",
|
||||||
integrations: [
|
integrations: [solid(), image(), mdx()],
|
||||||
solid(),
|
|
||||||
compress({
|
|
||||||
img: false,
|
|
||||||
html: false,
|
|
||||||
}),
|
|
||||||
image(),
|
|
||||||
mdx(),
|
|
||||||
],
|
|
||||||
markdown: {
|
markdown: {
|
||||||
syntaxHighlight: "prism",
|
syntaxHighlight: "prism",
|
||||||
remarkPlugins: ["remark-gfm", "remark-smartypants"],
|
remarkPlugins: ["remark-gfm", "remark-smartypants"],
|
||||||
|
|||||||
2395
package-lock.json
generated
2395
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -19,11 +19,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/image": "^0.3.2",
|
"@astrojs/image": "^0.3.2",
|
||||||
"@astrojs/mdx": "^0.7.0",
|
"@astrojs/mdx": "^0.8.0",
|
||||||
"@astrojs/solid-js": "^0.4.1",
|
"@astrojs/solid-js": "^0.4.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
"@types/mdx": "^2.0.2",
|
||||||
"@typescript-eslint/parser": "^5.32.0",
|
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||||
"astro": "^1.0.0-rc.7",
|
"@typescript-eslint/parser": "^5.33.0",
|
||||||
|
"astro": "^1.0.0-rc.8",
|
||||||
"astro-compress": "^0.0.15",
|
"astro-compress": "^0.0.15",
|
||||||
"astro-icon": "^0.7.3",
|
"astro-icon": "^0.7.3",
|
||||||
"eslint": "^8.21.0",
|
"eslint": "^8.21.0",
|
||||||
@ -32,7 +33,7 @@
|
|||||||
"hastscript": "^7.0.2",
|
"hastscript": "^7.0.2",
|
||||||
"html-escaper": "^3.0.3",
|
"html-escaper": "^3.0.3",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prettier-plugin-astro": "^0.3.0",
|
"prettier-plugin-astro": "^0.4.1",
|
||||||
"rehype-autolink-headings": "^6.1.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-slug": "^5.0.1",
|
"rehype-slug": "^5.0.1",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
|
|||||||
@ -6,17 +6,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
window.theme = (() => {
|
window.theme = (() => {
|
||||||
const local = localStorage.getItem('theme');
|
const local = localStorage.getItem("theme");
|
||||||
if (local && (local === 'dark' || local === 'light')) return local;
|
if (local && (local === "dark" || local === "light")) return local;
|
||||||
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
return isDark ? 'dark' : 'light';
|
return isDark ? "dark" : "light";
|
||||||
})();
|
})();
|
||||||
|
|
||||||
document.documentElement.setAttribute('data-theme', window.theme);
|
document.documentElement.setAttribute("data-theme", window.theme);
|
||||||
|
|
||||||
/* Sync with OS theme */
|
/* Sync with OS theme */
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches: isDark }) => {
|
||||||
window.theme = isDark ? 'dark' : 'light';
|
window.theme = isDark ? "dark" : "light";
|
||||||
localStorage.setItem('theme', window.theme);
|
localStorage.setItem("theme", window.theme);
|
||||||
document.documentElement.setAttribute('data-theme', window.theme);
|
document.documentElement.setAttribute("data-theme", window.theme);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,30 +7,30 @@
|
|||||||
if (window.theme) {
|
if (window.theme) {
|
||||||
/* the {theme} in the path will be dynamically changed */
|
/* the {theme} in the path will be dynamically changed */
|
||||||
const PATH = `/assets/css/code-highlight-{theme}.min.css`;
|
const PATH = `/assets/css/code-highlight-{theme}.min.css`;
|
||||||
const $head = document.getElementsByTagName('head')[0];
|
const $head = document.getElementsByTagName("head")[0];
|
||||||
const getPath = (theme) => PATH.replace(`{theme}`, theme);
|
const getPath = (theme) => PATH.replace(`{theme}`, theme);
|
||||||
const createLink = (theme, media) => {
|
const createLink = (theme, media) => {
|
||||||
const $link = document.createElement('link');
|
const $link = document.createElement("link");
|
||||||
$link.rel = 'stylesheet';
|
$link.rel = "stylesheet";
|
||||||
$link.type = 'text/css';
|
$link.type = "text/css";
|
||||||
$link.href = getPath(theme);
|
$link.href = getPath(theme);
|
||||||
$link.media = media;
|
$link.media = media;
|
||||||
return $link;
|
return $link;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* init links to load them first */
|
/* init links to load them first */
|
||||||
const $light = createLink('light', 'none');
|
const $light = createLink("light", "none");
|
||||||
const $dark = createLink('dark', 'none');
|
const $dark = createLink("dark", "none");
|
||||||
|
|
||||||
const toggleMedia = (theme) => {
|
const toggleMedia = (theme) => {
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case 'light':
|
case "light":
|
||||||
$light.media = 'all';
|
$light.media = "all";
|
||||||
$dark.media = 'none';
|
$dark.media = "none";
|
||||||
break;
|
break;
|
||||||
case 'dark':
|
case "dark":
|
||||||
$light.media = 'none';
|
$light.media = "none";
|
||||||
$dark.media = 'all';
|
$dark.media = "all";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -41,8 +41,8 @@ if (window.theme) {
|
|||||||
$head.appendChild($light);
|
$head.appendChild($light);
|
||||||
$head.appendChild($dark);
|
$head.appendChild($dark);
|
||||||
|
|
||||||
window.addEventListener('onthemetoggled', ({ detail: newTheme }) => toggleMedia(newTheme));
|
window.addEventListener("onthemetoggled", ({ detail: newTheme }) => toggleMedia(newTheme));
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches: isDark }) => {
|
||||||
return isDark ? toggleMedia('dark') : toggleMedia('light');
|
return isDark ? toggleMedia("dark") : toggleMedia("light");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ArticleContent.astro';
|
export { default } from "./ArticleContent.astro";
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
}
|
}
|
||||||
& p {
|
& p {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
font-family: monospace;
|
font-family: var(--font-family-monospace);
|
||||||
color: var(--font-color-gray);
|
color: var(--font-color-gray);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export * from './ArticleItem';
|
export * from "./ArticleItem";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ArticlePost.astro';
|
export { default } from "./ArticlePost.astro";
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { Component } from 'solid-js';
|
import { Component } from "solid-js";
|
||||||
|
|
||||||
import { createSignal, createEffect, For } from 'solid-js';
|
import { createSignal, createEffect, For } from "solid-js";
|
||||||
import { search, selectedTags } from '@stores/searchStore';
|
import { search, selectedTags } from "@stores/searchStore";
|
||||||
import { findArticlesBySearch, findArticlesByTags, sortArtcilesByDate } from '@utils/articles';
|
import { findArticlesBySearch, findArticlesByTags, sortArtcilesByDate } from "@utils/articles";
|
||||||
import { ArticleItem } from '@components/ArticleItem';
|
import { ArticleItem } from "@components/ArticleItem";
|
||||||
import SearchInput from '@components/SearchInput';
|
import SearchInput from "@components/SearchInput";
|
||||||
import TagsList from '@components/TagsList';
|
import TagsList from "@components/TagsList";
|
||||||
import './ArticlesList.scss';
|
import "./ArticlesList.scss";
|
||||||
|
|
||||||
type ArticlesListProps = {
|
type ArticlesListProps = {
|
||||||
data: {
|
data: {
|
||||||
@ -69,7 +69,7 @@ const ArticlesList: Component<ArticlesListProps> = (props) => {
|
|||||||
<div class="articles-list">
|
<div class="articles-list">
|
||||||
{isEmpty() ? (
|
{isEmpty() ? (
|
||||||
<div class="articles-list__empty">
|
<div class="articles-list__empty">
|
||||||
<p>{props.emptyPlaceholder || 'No articles found...'}</p>
|
<p>{props.emptyPlaceholder || "No articles found..."}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<For
|
<For
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ArticlesList';
|
export { default } from "./ArticlesList";
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE_METADATA } from '@root/config';
|
import { SITE_METADATA } from "@root/config";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title?: string | undefined;
|
title?: string | undefined;
|
||||||
@ -11,7 +11,8 @@ const { title = SITE_METADATA.title, description } = Astro.props as Props;
|
|||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono&display=swap" rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
@ -21,5 +22,7 @@ const { title = SITE_METADATA.title, description } = Astro.props as Props;
|
|||||||
<meta name="title" content={title} />
|
<meta name="title" content={title} />
|
||||||
<meta name="description" content={description || SITE_METADATA.description} />
|
<meta name="description" content={description || SITE_METADATA.description} />
|
||||||
<meta name="theme-color" content={SITE_METADATA.themeColor} />
|
<meta name="theme-color" content={SITE_METADATA.themeColor} />
|
||||||
<script is:inline src="/assets/js/detect-theme.js" />
|
<script is:inline src="/assets/js/detect-theme.js">
|
||||||
|
|
||||||
|
</script>
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './BaseLayout.astro';
|
export { default } from "./BaseLayout.astro";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './Button';
|
export { default } from "./Button";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ContactForm';
|
export { default } from "./ContactForm";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ContactsList.astro';
|
export { default } from "./ContactsList.astro";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './Counter';
|
export { default } from "./Counter";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './Footer.astro';
|
export { default } from "./Footer.astro";
|
||||||
|
|||||||
@ -1,42 +1,42 @@
|
|||||||
---
|
---
|
||||||
import './Header.scss';
|
import { Icon } from "astro-icon";
|
||||||
import { SITE_METADATA } from '@root/config';
|
import { SITE_METADATA } from "@root/config";
|
||||||
import ThemeSwitcher from '@components/ThemeSwticher';
|
import ThemeSwitcher from "@components/ThemeSwticher";
|
||||||
import { Icon } from 'astro-icon';
|
import { removeSlashes } from "@utils/string";
|
||||||
import { removeSlashes } from '@utils/string'
|
import NavToggle from "./NavToggle";
|
||||||
import NavToggle from './NavToggle';
|
import "./Header.scss";
|
||||||
|
|
||||||
const { name, nav, contacts } = SITE_METADATA;
|
const { name, nav, contacts } = SITE_METADATA;
|
||||||
const { pathname } = Astro.canonicalURL;
|
const { pathname } = Astro.url;
|
||||||
---
|
---
|
||||||
|
|
||||||
<header class='header'>
|
<header class="header">
|
||||||
<div class='container'>
|
<div class="container">
|
||||||
<div class='header__logo'>
|
<div class="header__logo">
|
||||||
<a href='/'>{name}</a>
|
<a href="/">{name}</a>
|
||||||
</div>
|
</div>
|
||||||
<nav class='header__nav'>
|
<nav class="header__nav">
|
||||||
<ul class='header__nav-links'>
|
<ul class="header__nav-links">
|
||||||
{nav.map((link) => (
|
{nav.map((link) => (
|
||||||
<li>
|
<li>
|
||||||
<a class={removeSlashes(pathname)===removeSlashes(link.url) && 'active' } href={link.url}>
|
<a class={removeSlashes(pathname) === removeSlashes(link.url) && "active"} href={link.url}>
|
||||||
{link.name}
|
{link.name}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<div class='header__nav-contacts'>
|
<div class="header__nav-contacts">
|
||||||
<a href={'mailto:' + contacts.email}>
|
<a href={"mailto:" + contacts.email}>
|
||||||
Почта
|
Почта
|
||||||
<Icon name='email' width='18' height='18' />
|
<Icon name="email" width="18" height="18" />
|
||||||
</a>
|
</a>
|
||||||
<a href={contacts.githubUrl}>
|
<a href={contacts.githubUrl}>
|
||||||
Github
|
Github
|
||||||
<Icon name='github_filled' width='18' height='18' />
|
<Icon name="github_filled" width="18" height="18" />
|
||||||
</a>
|
</a>
|
||||||
<a href={contacts.telegramUrl}>
|
<a href={contacts.telegramUrl}>
|
||||||
Телеграм
|
Телеграм
|
||||||
<Icon name='telegram' width='18' height='18' />
|
<Icon name="telegram" width="18" height="18" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<ThemeSwitcher client:visible />
|
<ThemeSwitcher client:visible />
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { Component } from 'solid-js';
|
import type { Component } from "solid-js";
|
||||||
|
|
||||||
import { createSignal, createEffect } from 'solid-js';
|
import { createSignal, createEffect } from "solid-js";
|
||||||
import './NavToggle.scss';
|
import "./NavToggle.scss";
|
||||||
|
|
||||||
const MenuIcon: Component = () => (
|
const MenuIcon: Component = () => (
|
||||||
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="24px" height="24px">
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="24px" height="24px">
|
||||||
@ -24,11 +24,11 @@ const NavToggle: Component = () => {
|
|||||||
const body = document.body;
|
const body = document.body;
|
||||||
|
|
||||||
if (isNavShown()) {
|
if (isNavShown()) {
|
||||||
body.setAttribute('data-is-mobile-open', 'true');
|
body.setAttribute("data-is-mobile-open", "true");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.removeAttribute('data-is-mobile-open');
|
body.removeAttribute("data-is-mobile-open");
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './NavToggle';
|
export { default } from "./NavToggle";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './Header.astro';
|
export { default } from "./Header.astro";
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import './PageHeading.scss';
|
import "./PageHeading.scss";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
heading: string;
|
heading: string;
|
||||||
@ -9,8 +9,8 @@ export interface Props {
|
|||||||
const { heading, description } = Astro.props as Props;
|
const { heading, description } = Astro.props as Props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class='page-heading'>
|
<div class="page-heading">
|
||||||
<h1 style={!description && 'margin-bottom: 2.5rem;'}>
|
<h1 style={!description && "margin-bottom: 2.5rem;"}>
|
||||||
{heading}
|
{heading}
|
||||||
</h1>
|
</h1>
|
||||||
{description && <p>{description}</p>}
|
{description && <p>{description}</p>}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './PageHeading.astro';
|
export { default } from "./PageHeading.astro";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ProjectItem.astro';
|
export { default } from "./ProjectItem.astro";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ProjectsList.astro';
|
export { default } from "./ProjectsList.astro";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import './RecentArticles.scss';
|
import "./RecentArticles.scss";
|
||||||
import { ArticleItem } from '@components/ArticleItem';
|
import { ArticleItem } from "@components/ArticleItem";
|
||||||
import { sortArtcilesByDate } from '@utils/articles';
|
import { sortArtcilesByDate } from "@utils/articles";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
articles: ArticleType[];
|
articles: ArticleType[];
|
||||||
@ -13,13 +13,13 @@ const { articles, length = 5 } = Astro.props as Props;
|
|||||||
const recent = sortArtcilesByDate(articles);
|
const recent = sortArtcilesByDate(articles);
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class='recent'>
|
<section class="recent">
|
||||||
<div class='recent-heading'>
|
<div class="recent-heading">
|
||||||
<h2>недавние публикации</h2>
|
<h2>недавние публикации</h2>
|
||||||
<a href='/articles'>смотреть все</a>
|
<a href="/articles">смотреть все</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='recent-list'>
|
<div class="recent-list">
|
||||||
{recent.length !== 0 ? (
|
{recent.length !== 0 ? (
|
||||||
recent.slice(0, length).map((article) => <ArticleItem data={article} />)
|
recent.slice(0, length).map((article) => <ArticleItem data={article} />)
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './RecentArticles.astro';
|
export { default } from "./RecentArticles.astro";
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { Component, JSX } from 'solid-js';
|
import type { Component, JSX } from "solid-js";
|
||||||
|
|
||||||
import { createEffect } from 'solid-js';
|
import { createEffect } from "solid-js";
|
||||||
import { search, setSearch } from '@stores/searchStore';
|
import { search, setSearch } from "@stores/searchStore";
|
||||||
import * as utils from '@utils/history';
|
import * as utils from "@utils/history";
|
||||||
import './SearchInput.scss';
|
import "./SearchInput.scss";
|
||||||
|
|
||||||
type SearchInputProps = {
|
type SearchInputProps = {
|
||||||
count: number;
|
count: number;
|
||||||
@ -15,10 +15,10 @@ const SearchInput: Component<SearchInputProps> = (props) => {
|
|||||||
* Reset state and delete `search` param from url
|
* Reset state and delete `search` param from url
|
||||||
*/
|
*/
|
||||||
const resetSearch = () => {
|
const resetSearch = () => {
|
||||||
const url = utils.deleteParamFromUrl('search');
|
const url = utils.deleteParamFromUrl("search");
|
||||||
|
|
||||||
setSearch('');
|
setSearch("");
|
||||||
history.replaceState(null, '', url);
|
history.replaceState(null, "", url);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,9 +32,9 @@ const SearchInput: Component<SearchInputProps> = (props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = utils.setParamToUrl('search', value.trim());
|
const url = utils.setParamToUrl("search", value.trim());
|
||||||
|
|
||||||
history.replaceState(null, '', `${location.pathname}?${url}`);
|
history.replaceState(null, "", `${location.pathname}?${url}`);
|
||||||
setSearch(value);
|
setSearch(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ const SearchInput: Component<SearchInputProps> = (props) => {
|
|||||||
* Set the signal state by reading the `search` parameter from the URL.
|
* Set the signal state by reading the `search` parameter from the URL.
|
||||||
*/
|
*/
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const param = new URLSearchParams(location.search).get('search');
|
const param = new URLSearchParams(location.search).get("search");
|
||||||
|
|
||||||
if (!param) {
|
if (!param) {
|
||||||
resetSearch();
|
resetSearch();
|
||||||
@ -63,7 +63,7 @@ const SearchInput: Component<SearchInputProps> = (props) => {
|
|||||||
value={search()}
|
value={search()}
|
||||||
type="text"
|
type="text"
|
||||||
role="search"
|
role="search"
|
||||||
placeholder={props.placeholder || 'Search article by title or description...'}
|
placeholder={props.placeholder || "Search article by title or description..."}
|
||||||
autocapitalize="off"
|
autocapitalize="off"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './SearchInput';
|
export { default } from "./SearchInput";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './SkillsBlock.astro';
|
export { default } from "./SkillsBlock.astro";
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './SkillsList.astro';
|
export { default } from "./SkillsList.astro";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import './Splash.scss';
|
import "./Splash.scss";
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class='splash'>
|
<section class="splash">
|
||||||
<slot></slot>
|
<slot />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import './SplashHeading.scss';
|
import "./SplashHeading.scss";
|
||||||
---
|
---
|
||||||
|
|
||||||
<header class='splash-heading'>
|
<header class="splash-heading">
|
||||||
<slot></slot>
|
<slot />
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import './SplashLinks.scss';
|
import "./SplashLinks.scss";
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav class='splash-links'>
|
<nav class="splash-links">
|
||||||
<slot></slot>
|
<slot />
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export { default as Splash } from './Splash.astro';
|
export { default as Splash } from "./Splash.astro";
|
||||||
export { default as SplashHeading } from './SplashHeading.astro';
|
export { default as SplashHeading } from "./SplashHeading.astro";
|
||||||
export { default as SplashLinks } from './SplashLinks.astro';
|
export { default as SplashLinks } from "./SplashLinks.astro";
|
||||||
export { default as Link } from './Link.astro';
|
export { default as Link } from "./Link.astro";
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { Component, JSX } from 'solid-js';
|
import type { Component, JSX } from "solid-js";
|
||||||
|
|
||||||
import { For, createEffect } from 'solid-js';
|
import { For, createEffect } from "solid-js";
|
||||||
import { selectedTags, setSelectedTags } from '@stores/searchStore';
|
import { selectedTags, setSelectedTags } from "@stores/searchStore";
|
||||||
import * as utils from '@utils/history';
|
import * as utils from "@utils/history";
|
||||||
|
|
||||||
type TagsListProps = {
|
type TagsListProps = {
|
||||||
data: string[];
|
data: string[];
|
||||||
@ -15,14 +15,14 @@ const TagsList: Component<TagsListProps> = (props) => {
|
|||||||
* Reset signal state and `tags` property in history state
|
* Reset signal state and `tags` property in history state
|
||||||
*/
|
*/
|
||||||
const resetSelected = () => {
|
const resetSelected = () => {
|
||||||
const url = utils.deleteParamFromUrl('tags');
|
const url = utils.deleteParamFromUrl("tags");
|
||||||
|
|
||||||
setSelectedTags([]);
|
setSelectedTags([]);
|
||||||
history.replaceState(null, '', url);
|
history.replaceState(null, "", url);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect: JSX.EventHandler<HTMLLIElement, PointerEvent> = (e) => {
|
const onSelect: JSX.EventHandler<HTMLLIElement, PointerEvent> = (e) => {
|
||||||
const tag = e.target.getAttribute('data-tag');
|
const tag = e.target.getAttribute("data-tag");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete tag from selected tags if already selected
|
* Delete tag from selected tags if already selected
|
||||||
@ -30,7 +30,7 @@ const TagsList: Component<TagsListProps> = (props) => {
|
|||||||
*/
|
*/
|
||||||
if (isTagSelected(tag)) {
|
if (isTagSelected(tag)) {
|
||||||
const updated = selectedTags().filter((selectedTag) => selectedTag !== tag);
|
const updated = selectedTags().filter((selectedTag) => selectedTag !== tag);
|
||||||
const url = utils.setParamToUrl('tags', updated.join(','));
|
const url = utils.setParamToUrl("tags", updated.join(","));
|
||||||
|
|
||||||
if (updated.length === 0) {
|
if (updated.length === 0) {
|
||||||
resetSelected();
|
resetSelected();
|
||||||
@ -38,7 +38,7 @@ const TagsList: Component<TagsListProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSelectedTags(updated);
|
setSelectedTags(updated);
|
||||||
history.replaceState(null, '', `${location.pathname}?${url}`);
|
history.replaceState(null, "", `${location.pathname}?${url}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,14 +46,14 @@ const TagsList: Component<TagsListProps> = (props) => {
|
|||||||
* Add selected tag to state and update url
|
* Add selected tag to state and update url
|
||||||
*/
|
*/
|
||||||
const updated = [...selectedTags(), tag];
|
const updated = [...selectedTags(), tag];
|
||||||
const url = utils.setParamToUrl('tags', updated.join(','));
|
const url = utils.setParamToUrl("tags", updated.join(","));
|
||||||
|
|
||||||
setSelectedTags(updated);
|
setSelectedTags(updated);
|
||||||
history.replaceState(null, '', `${location.pathname}?${url}`);
|
history.replaceState(null, "", `${location.pathname}?${url}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
let param: string | string[] = new URLSearchParams(location.search).get('tags');
|
let param: string | string[] = new URLSearchParams(location.search).get("tags");
|
||||||
|
|
||||||
if (!param) {
|
if (!param) {
|
||||||
resetSelected();
|
resetSelected();
|
||||||
@ -61,7 +61,7 @@ const TagsList: Component<TagsListProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* to array */
|
/* to array */
|
||||||
param = param.split(',');
|
param = param.split(",");
|
||||||
|
|
||||||
if (param.length === 0) {
|
if (param.length === 0) {
|
||||||
resetSelected();
|
resetSelected();
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './TagsList';
|
export { default } from "./TagsList";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { Component, JSX } from 'solid-js';
|
import type { Component, JSX } from "solid-js";
|
||||||
|
|
||||||
import { createSignal, onMount, Switch, Match } from 'solid-js';
|
import { createSignal, onMount, Switch, Match } from "solid-js";
|
||||||
import './ThemeSwitcher.scss';
|
import "./ThemeSwitcher.scss";
|
||||||
|
|
||||||
const MoonIcon: Component = () => (
|
const MoonIcon: Component = () => (
|
||||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -22,19 +22,19 @@ const SunIcon: Component = () => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const ThemeSwitcher: Component = () => {
|
const ThemeSwitcher: Component = () => {
|
||||||
const [theme, setTheme] = createSignal<ThemeModeType>('light');
|
const [theme, setTheme] = createSignal<ThemeModeType>("light");
|
||||||
const [isReady, setIsReady] = createSignal<boolean>(false);
|
const [isReady, setIsReady] = createSignal<boolean>(false);
|
||||||
|
|
||||||
const toggleTheme: JSX.EventHandler<HTMLButtonElement, MouseEvent> = () => {
|
const toggleTheme: JSX.EventHandler<HTMLButtonElement, MouseEvent> = () => {
|
||||||
if (!window.theme) return;
|
if (!window.theme) return;
|
||||||
|
|
||||||
const newTheme = theme() === 'light' ? 'dark' : 'light';
|
const newTheme = theme() === "light" ? "dark" : "light";
|
||||||
const toggleEvent = new CustomEvent('onthemetoggled', { detail: newTheme });
|
const toggleEvent = new CustomEvent("onthemetoggled", { detail: newTheme });
|
||||||
|
|
||||||
setTheme(newTheme);
|
setTheme(newTheme);
|
||||||
window.dispatchEvent(toggleEvent);
|
window.dispatchEvent(toggleEvent);
|
||||||
localStorage.setItem('theme', newTheme);
|
localStorage.setItem("theme", newTheme);
|
||||||
document.documentElement.setAttribute('data-theme', newTheme);
|
document.documentElement.setAttribute("data-theme", newTheme);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -42,20 +42,20 @@ const ThemeSwitcher: Component = () => {
|
|||||||
if (window.theme) {
|
if (window.theme) {
|
||||||
setTheme(window.theme);
|
setTheme(window.theme);
|
||||||
/* Update theme state on changing OS theme */
|
/* Update theme state on changing OS theme */
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches: isDark }) => {
|
||||||
const theme = isDark ? 'dark' : 'light';
|
const theme = isDark ? "dark" : "light";
|
||||||
setTheme(theme);
|
setTheme(theme);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button onClick={toggleTheme} class={isReady() ? 'theme-switcher ready' : 'theme-switcher'} aria-label={theme()}>
|
<button onClick={toggleTheme} class={isReady() ? "theme-switcher ready" : "theme-switcher"} aria-label={theme()}>
|
||||||
<Switch
|
<Switch
|
||||||
children={
|
children={
|
||||||
<>
|
<>
|
||||||
<Match when={theme() === 'light'} children={<MoonIcon />} />
|
<Match when={theme() === "light"} children={<MoonIcon />} />
|
||||||
<Match when={theme() === 'dark'} children={<SunIcon />} />
|
<Match when={theme() === "dark"} children={<SunIcon />} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { default } from './ThemeSwitcher';
|
export { default } from "./ThemeSwitcher";
|
||||||
|
|||||||
158
src/config.ts
158
src/config.ts
@ -1,132 +1,132 @@
|
|||||||
export const SITE_METADATA: SiteMetadataType = {
|
export const SITE_METADATA: SiteMetadataType = {
|
||||||
title: 'Sergey Yarkov',
|
title: "Sergey Yarkov",
|
||||||
name: 'yarkov.tech',
|
name: "yarkov.tech",
|
||||||
author: 'Sergey Yarkov',
|
author: "Sergey Yarkov",
|
||||||
description:
|
description:
|
||||||
'Здесь я публикую статьи и туториалы на различные IT темы, а также рассказываю о своих проектах которые я сделал за последние несколько лет.',
|
"Здесь я публикую статьи и туториалы на различные IT темы, а также рассказываю о своих проектах которые я сделал за последние несколько лет.",
|
||||||
themeColor: '#1e2327',
|
themeColor: "#1e2327",
|
||||||
contacts: {
|
contacts: {
|
||||||
email: 'serzh.yarkov@gmail.com',
|
email: "serzh.yarkov@gmail.com",
|
||||||
githubUrl: 'https://github.com/sergeyyarkov',
|
githubUrl: "https://github.com/sergeyyarkov",
|
||||||
telegramUrl: 'https://t.me/sergeyyarkov',
|
telegramUrl: "https://t.me/sergeyyarkov",
|
||||||
},
|
},
|
||||||
nav: [
|
nav: [
|
||||||
{ name: 'Статьи', url: '/articles' },
|
{ name: "Статьи", url: "/articles" },
|
||||||
{ name: 'Проекты', url: '/projects' },
|
{ name: "Проекты", url: "/projects" },
|
||||||
{ name: 'Обо мне', url: '/about' },
|
{ name: "Обо мне", url: "/about" },
|
||||||
{ name: 'Контакты', url: '/contacts' },
|
{ name: "Контакты", url: "/contacts" },
|
||||||
],
|
],
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
icon: 'book',
|
icon: "book",
|
||||||
name: 'yarkov.tech',
|
name: "yarkov.tech",
|
||||||
year: '2022',
|
year: "2022",
|
||||||
description: 'Мой персональный веб-сайт где находятся информация обо мне и список различных статей, туториалов...',
|
description: "Мой персональный веб-сайт где находятся информация обо мне и список различных статей, туториалов...",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/yarkov.tech',
|
sourceUrl: "https://github.com/sergeyyarkov/yarkov.tech",
|
||||||
demoUrl: 'https://yarkov.tech',
|
demoUrl: "https://yarkov.tech",
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'triangle_filled',
|
icon: "triangle_filled",
|
||||||
name: 'devthread',
|
name: "devthread",
|
||||||
year: '2021',
|
year: "2021",
|
||||||
description: 'Статический веб-сайт для публикации различных статей, разработанный при помощи Gatsby.js и NetlifyCMS',
|
description: "Статический веб-сайт для публикации различных статей, разработанный при помощи Gatsby.js и NetlifyCMS",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/devthread.ru',
|
sourceUrl: "https://github.com/sergeyyarkov/devthread.ru",
|
||||||
demoUrl: 'https://devthread.netlify.app',
|
demoUrl: "https://devthread.netlify.app",
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'round-school',
|
icon: "round-school",
|
||||||
name: 'educt',
|
name: "educt",
|
||||||
year: '2022',
|
year: "2022",
|
||||||
description: 'Система управления обучением (LMS) для публикации ваших курсов, лекций, уроков',
|
description: "Система управления обучением (LMS) для публикации ваших курсов, лекций, уроков",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/educt',
|
sourceUrl: "https://github.com/sergeyyarkov/educt",
|
||||||
demoUrl: 'https://client-educt-lms.netlify.app',
|
demoUrl: "https://client-educt-lms.netlify.app",
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'round-shop-two',
|
icon: "round-shop-two",
|
||||||
name: 'digital-store',
|
name: "digital-store",
|
||||||
year: '2019',
|
year: "2019",
|
||||||
description: 'Настраиваемый интернет-магазин с панелью управления для продажи цифровых товаров',
|
description: "Настраиваемый интернет-магазин с панелью управления для продажи цифровых товаров",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/digital-store/tree/digital-store-docker',
|
sourceUrl: "https://github.com/sergeyyarkov/digital-store/tree/digital-store-docker",
|
||||||
demoUrl: 'https://digital-store.herokuapp.com',
|
demoUrl: "https://digital-store.herokuapp.com",
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'chat',
|
icon: "chat",
|
||||||
name: 'react-chat-app',
|
name: "react-chat-app",
|
||||||
year: '2021',
|
year: "2021",
|
||||||
description: 'Клиент-серверное веб приложение чата разработанное при помощи Node.js и Socket.io',
|
description: "Клиент-серверное веб приложение чата разработанное при помощи Node.js и Socket.io",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/react-chat-app',
|
sourceUrl: "https://github.com/sergeyyarkov/react-chat-app",
|
||||||
demoUrl: undefined,
|
demoUrl: undefined,
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'nodejs',
|
icon: "nodejs",
|
||||||
name: 'node-docker-example',
|
name: "node-docker-example",
|
||||||
year: '2022',
|
year: "2022",
|
||||||
description: 'Пример использования Docker для развертывания Node.js приложения',
|
description: "Пример использования Docker для развертывания Node.js приложения",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/node-docker-example',
|
sourceUrl: "https://github.com/sergeyyarkov/node-docker-example",
|
||||||
demoUrl: 'https://website-simple-blog.herokuapp.com',
|
demoUrl: "https://website-simple-blog.herokuapp.com",
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'chip',
|
icon: "chip",
|
||||||
name: 'memory-led-game',
|
name: "memory-led-game",
|
||||||
year: '2022',
|
year: "2022",
|
||||||
description: 'Аналог популярной игры “Саймон говорит” на AVR микроконтроллере',
|
description: "Аналог популярной игры “Саймон говорит” на AVR микроконтроллере",
|
||||||
sourceUrl: 'https://github.com/sergeyyarkov/attiny24a_memory-led-game',
|
sourceUrl: "https://github.com/sergeyyarkov/attiny24a_memory-led-game",
|
||||||
demoUrl: undefined,
|
demoUrl: undefined,
|
||||||
articleUrl: undefined,
|
articleUrl: undefined,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
skills: [
|
skills: [
|
||||||
{
|
{
|
||||||
title: 'Программирование',
|
title: "Программирование",
|
||||||
list: [
|
list: [
|
||||||
{ icon: 'nodejs', name: 'Javascript/Typescript' },
|
{ icon: "nodejs", name: "Javascript/Typescript" },
|
||||||
{ icon: 'language-c', name: 'C Language' },
|
{ icon: "language-c", name: "C Language" },
|
||||||
{ icon: 'mysql', name: 'SQL' },
|
{ icon: "mysql", name: "SQL" },
|
||||||
{ icon: 'graphql', name: 'GraphQL' },
|
{ icon: "graphql", name: "GraphQL" },
|
||||||
{ icon: 'avr', name: 'AVR instruction set' },
|
{ icon: "avr", name: "AVR instruction set" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Фреймворки',
|
title: "Фреймворки",
|
||||||
list: [
|
list: [
|
||||||
{ icon: 'adonisjs', name: 'Adonis.js' },
|
{ icon: "adonisjs", name: "Adonis.js" },
|
||||||
{ icon: 'expressjs', name: 'Express.js' },
|
{ icon: "expressjs", name: "Express.js" },
|
||||||
{ icon: 'socket-io', name: 'Socket.io' },
|
{ icon: "socket-io", name: "Socket.io" },
|
||||||
{ icon: 'astro_filled', name: 'Astro' },
|
{ icon: "astro_filled", name: "Astro" },
|
||||||
{ icon: 'reactjs', name: 'React.js' },
|
{ icon: "reactjs", name: "React.js" },
|
||||||
{ icon: 'gatsbyjs', name: 'Gatsby.js' },
|
{ icon: "gatsbyjs", name: "Gatsby.js" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Инструменты',
|
title: "Инструменты",
|
||||||
list: [
|
list: [
|
||||||
{ icon: 'nodejs', name: 'Node.js' },
|
{ icon: "nodejs", name: "Node.js" },
|
||||||
{ icon: 'docker', name: 'Docker' },
|
{ icon: "docker", name: "Docker" },
|
||||||
{ icon: 'git-branch', name: 'Git/gitflow' },
|
{ icon: "git-branch", name: "Git/gitflow" },
|
||||||
{ icon: 'sass', name: 'SASS' },
|
{ icon: "sass", name: "SASS" },
|
||||||
{ icon: 'webpack', name: 'Webpack' },
|
{ icon: "webpack", name: "Webpack" },
|
||||||
{ icon: 'vite', name: 'Vite.js' },
|
{ icon: "vite", name: "Vite.js" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Базы данных',
|
title: "Базы данных",
|
||||||
list: [
|
list: [
|
||||||
{ icon: 'postgresql', name: 'PostgreSQL' },
|
{ icon: "postgresql", name: "PostgreSQL" },
|
||||||
{ icon: 'mongodb', name: 'MongoDB' },
|
{ icon: "mongodb", name: "MongoDB" },
|
||||||
{ icon: 'redis', name: 'Redis' },
|
{ icon: "redis", name: "Redis" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Языки',
|
title: "Языки",
|
||||||
list: [
|
list: [
|
||||||
{ icon: undefined, name: 'Русский (родной)' },
|
{ icon: undefined, name: "Русский (родной)" },
|
||||||
{ icon: undefined, name: 'Английский (B1)' },
|
{ icon: undefined, name: "Английский (B1)" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import NotFound from '@templates/NotFound.astro';
|
import NotFound from "@templates/NotFound.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<NotFound />
|
<NotFound />
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import About from '@templates/About.astro';
|
import About from "@templates/About.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<About />
|
<About />
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Articles from '@templates/Articles.astro';
|
import Articles from "@templates/Articles.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Articles />
|
<Articles />
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Contacts from '@templates/Contacts.astro';
|
import Contacts from "@templates/Contacts.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Contacts />
|
<Contacts />
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Home from '@templates/Home.astro';
|
import Home from "@templates/Home.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Home />
|
<Home />
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Projects from '@templates/Projects.astro';
|
import Projects from "@templates/Projects.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Projects />
|
<Projects />
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export * from './searchStore';
|
export * from "./searchStore";
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createSignal } from 'solid-js';
|
import { createSignal } from "solid-js";
|
||||||
|
|
||||||
export const [search, setSearch] = createSignal<string>('');
|
export const [search, setSearch] = createSignal<string>("");
|
||||||
export const [selectedTags, setSelectedTags] = createSignal<string[]>([]);
|
export const [selectedTags, setSelectedTags] = createSignal<string[]>([]);
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
/* Fonts */
|
/* Fonts */
|
||||||
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||||
--font-family-base: "Rubik", var(--font-fallback);
|
--font-family-base: "Rubik", var(--font-fallback);
|
||||||
|
--font-family-monospace: "IBM Plex Mono", Menlo, monospace;
|
||||||
--font-size-xs: 0.75rem;
|
--font-size-xs: 0.75rem;
|
||||||
--font-size-sm: 0.875rem;
|
--font-size-sm: 0.875rem;
|
||||||
--font-size-md: 1rem;
|
--font-size-md: 1rem;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
import * as utils from '@utils/index';
|
import * as utils from "@utils/index";
|
||||||
import PageLayout from '@layouts/default.astro';
|
import PageLayout from "@layouts/default.astro";
|
||||||
import RecentArticles from '@components/RecentArticles';
|
import RecentArticles from "@components/RecentArticles";
|
||||||
import { Splash, SplashHeading, SplashLinks, Link } from '@components/Splash';
|
import { Splash, SplashHeading, SplashLinks, Link } from "@components/Splash";
|
||||||
|
|
||||||
const data = await Astro.glob<ArticleType>('../../content/articles/**/*.mdx');
|
const data = await Astro.glob<ArticleType>("../../content/articles/**/*.mdx");
|
||||||
const articles = utils.transformArticles(data);
|
const articles = utils.transformArticles(data);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { MarkdownInstance } from 'astro';
|
import { MarkdownInstance } from "astro";
|
||||||
|
|
||||||
export const transformArticles = (articles: MarkdownInstance<ArticleType>[]): ArticleType[] =>
|
export const transformArticles = (articles: MarkdownInstance<ArticleType>[]): ArticleType[] =>
|
||||||
articles.map((article) => ({
|
articles.map((article) => ({
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export const DateFormatter = new Intl.DateTimeFormat(undefined, {
|
export const DateFormatter = new Intl.DateTimeFormat(undefined, {
|
||||||
timeZone: 'UTC',
|
timeZone: "UTC",
|
||||||
month: 'short',
|
month: "short",
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
day: 'numeric',
|
day: "numeric",
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,14 +2,14 @@ export const extendHistoryState = (state: object, url?: URL | string | undefined
|
|||||||
const { history } = window;
|
const { history } = window;
|
||||||
const updated = Object.assign({}, history.state, state);
|
const updated = Object.assign({}, history.state, state);
|
||||||
|
|
||||||
history.replaceState(updated, '', url);
|
history.replaceState(updated, "", url);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteParamFromUrl = (param: string): string => {
|
export const deleteParamFromUrl = (param: string): string => {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
params.delete(param);
|
params.delete(param);
|
||||||
|
|
||||||
const url = !params.toString() ? window.location.pathname : '?' + params.toString();
|
const url = !params.toString() ? window.location.pathname : "?" + params.toString();
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export * from './articles';
|
export * from "./articles";
|
||||||
export * from './date';
|
export * from "./date";
|
||||||
export * from './history';
|
export * from "./history";
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"types": ["vite/client", "@astrojs/image/client", "mdx"],
|
"types": ["vite/client", "@astrojs/image/client", "@types/mdx"],
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user