Merge branch 'feature/dark-light-theme' into develop

This commit is contained in:
Sergey Yarkov 2022-07-28 00:10:11 +03:00
commit c43f1b8484
44 changed files with 398 additions and 1175 deletions

View File

@ -9,9 +9,9 @@ Personal website created with Astro.
- [x] HTML layout
- [x] Adaptive & Responsive layout
- [ ] Dark/Light Theme
- [x] Search articles by title or description
- [x] Dark/Light Theme
- [ ] Multilang web-site
- [ ] Search articles by title or description
- [ ] Form handling via Netlify Forms
- [ ] SEO optimized

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
/**
* This script is used to determine the theme of the site.
* The theme value is taken from localstorage, otherwise from the operating system.
* It is very important to include this script before loading the CSS
* and body markup to prevent FOUC (Flash of unstyled content).
*/
const getTheme = () => {
const local = localStorage.getItem('theme');
if (local && (local === 'dark' || local === 'light')) return local;
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
return isDark ? 'dark' : 'light';
};
window.theme = getTheme();
document.documentElement.setAttribute('data-theme', window.theme);
/* Sync with OS theme */
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
window.theme = isDark ? 'dark' : 'light';
localStorage.setItem('theme', window.theme);
document.documentElement.setAttribute('data-theme', window.theme);
});

View File

@ -7,7 +7,7 @@
align-items: center;
column-gap: 10px;
color: var(--font-color);
padding: 8px 15px;
padding: 8px 0;
& h3 {
font-size: var(--font-size-md);
font-weight: normal;
@ -22,12 +22,6 @@
white-space: nowrap;
margin-bottom: 0;
}
&:hover {
text-decoration: none;
}
}
&:hover {
background-color: var(--background-color-hover);
}
}

View File

@ -1,8 +1,6 @@
import type { ArticleType } from '@root/types';
import './ArticleItem.scss';
import { Component } from 'solid-js';
import { DateFormatter } from '@utils/date';
import './ArticleItem.scss';
export type ArticleItemProps = {
data: ArticleType;

View File

@ -1,6 +1,4 @@
---
import type { ArticleType } from '@root/types';
import { DateFormatter } from '@root/utils';
import './ArticlePost.scss';

View File

@ -27,7 +27,7 @@
& h1 {
font-weight: 600;
font-size: 2.25rem;
font-size: 2.125rem;
}
& p {

View File

@ -1,5 +1,4 @@
import type { Component } from 'solid-js';
import type { ArticleBlockType } from '@root/types';
import { createSignal, createEffect, For } from 'solid-js';
import { search, selectedTags } from '@stores/searchStore';

View File

@ -19,4 +19,6 @@ const { title = SITE_METADATA.title, description } = Astro.props as Props;
{title}
</title>
<meta name='title' content={title} />
<meta name="description" content={description || SITE_METADATA.description} />
<meta name='description' content={description || SITE_METADATA.description} />
<script is:inline src='assets/js/detect-theme.js' />
<slot></slot>

View File

@ -11,14 +11,14 @@ const {
<div class='contacts-list'>
<a href={'mailto:' + email}
>Email
<Icon name='arrow-up-right' width='15' height='15' />
<Icon name='arrow-up-right' width='15' height='15' data-filter='none' />
</a>
<a href={githubUrl} target='_blank'
>Github
<Icon name='arrow-up-right' width='15' height='15' />
<Icon name='arrow-up-right' width='15' height='15' data-filter='none' />
</a>
<a href={telegramUrl} target='_blank'
>Telegram
<Icon name='arrow-up-right' width='15' height='15' />
<Icon name='arrow-up-right' width='15' height='15' data-filter='none' />
</a>
</div>

View File

@ -8,4 +8,8 @@
display: flex;
column-gap: 5px;
}
& svg {
filter: none;
}
}

View File

@ -1,34 +1,34 @@
.footer {
& .container {
margin-top: 5rem;
padding: 25px 0 10px 0;
font-weight: 500;
border-top: 1px solid var(--border-color);
display: flex;
flex-direction: column;
align-items: center;
row-gap: 15px;
user-select: none;
}
&__links {
display: flex;
align-items: center;
column-gap: 25px;
list-style: none;
margin: 0;
padding: 0;
& li {
display: flex;
align-items: center;
column-gap: 7px;
& a {
color: var(--font-color);
font-size: var(--font-size-sm);
}
}
}
&__copy {
text-align: center;
font-size: var(--font-size-xs);
}
& .container {
margin-top: 5rem;
padding: 25px 0 10px 0;
font-weight: 500;
border-top: 1px solid var(--border-color);
display: flex;
flex-direction: column;
align-items: center;
row-gap: 15px;
user-select: none;
}
&__links {
display: flex;
align-items: center;
column-gap: 25px;
list-style: none;
margin: 0;
padding: 0;
& li {
display: flex;
align-items: center;
column-gap: 7px;
& a {
color: var(--font-color);
font-size: var(--font-size-sm);
}
}
}
&__copy {
text-align: center;
font-size: var(--font-size-xs);
}
}

View File

@ -38,8 +38,8 @@ const { pathname } = Astro.canonicalURL;
<Icon name='telegram' width='18' height='18' />
</a>
</div>
<ThemeSwitcher />
<ThemeSwitcher client:visible />
</nav>
<NavToggle client:media='(max-width: 768px)' />
<NavToggle client:visible />
</div>
</header>

View File

@ -6,7 +6,7 @@
padding-top: 15px;
padding-bottom: 15px;
user-select: none;
z-index: 9999;
& .container {
display: flex;
align-items: center;
@ -63,61 +63,11 @@
}
}
}
&__button {
cursor: pointer;
width: 30px;
height: 21px;
position: relative;
transform: rotate(0deg);
background: none;
border: none;
&:hover {
border: none;
opacity: var(--opacity-hover);
}
& span {
pointer-events: none;
display: block;
position: absolute;
height: 3px;
width: 100%;
background: var(--color-black);
border-radius: 7px;
opacity: 1;
left: 0;
}
& span:nth-child(1) {
top: 2px;
transform-origin: left center;
}
& span:nth-child(2) {
top: 9px;
transform-origin: left center;
}
& span:nth-child(3) {
top: 16px;
transform-origin: left center;
}
&[aria-pressed='true'] {
& span:nth-child(1) {
transform: rotate(45deg);
top: -1px;
left: 5px;
}
& span:nth-child(2) {
display: none;
}
& span:nth-child(3) {
transform: rotate(-45deg);
top: 20px;
left: 5px;
}
}
}
}
@media screen and (max-width: 768px) {
.header {
padding: 10px 0;
&__nav {
display: none;
}
@ -125,7 +75,8 @@
body[data-is-mobile-open='true'] {
& .header {
background-color: var(--color-white);
padding: 15px 0;
background-color: var(--background-header-color);
position: fixed;
right: 0;
left: 0;
@ -159,7 +110,7 @@
justify-content: center;
}
}
&__button {
& .nav-toggle {
position: absolute;
right: var(--content-padding);
}

View File

@ -1,5 +1,15 @@
.nav-toggle {
cursor: pointer;
border: none;
padding: 0;
&:hover {
border: none;
opacity: var(--opacity-hover);
}
}
@media screen and (min-width: 769px) {
#nav-toggle {
.nav-toggle {
display: none;
}
}

View File

@ -3,6 +3,18 @@ import type { Component } from 'solid-js';
import { createSignal, createEffect } from 'solid-js';
import './NavToggle.scss';
const MenuIcon: Component = () => (
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="24px" height="24px">
<path d="M 0 7.5 L 0 12.5 L 50 12.5 L 50 7.5 Z M 0 22.5 L 0 27.5 L 50 27.5 L 50 22.5 Z M 0 37.5 L 0 42.5 L 50 42.5 L 50 37.5 Z" />
</svg>
);
const CloseIcon: Component = () => (
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="24px" height="24px">
<path d="M 9.15625 6.3125 L 6.3125 9.15625 L 22.15625 25 L 6.21875 40.96875 L 9.03125 43.78125 L 25 27.84375 L 40.9375 43.78125 L 43.78125 40.9375 L 27.84375 25 L 43.6875 9.15625 L 40.84375 6.3125 L 25 22.15625 Z" />
</svg>
);
const NavToggle: Component = () => {
const [isNavShown, setIsNavShown] = createSignal<boolean>(false);
@ -20,10 +32,8 @@ const NavToggle: Component = () => {
});
return (
<button id="nav-toggle" class="header__button" onClick={toggleNav} type="button" aria-pressed={isNavShown() ? 'true' : 'false'} aria-label="Menu">
<span />
<span />
<span />
<button class="nav-toggle" onClick={toggleNav} type="button" aria-pressed={isNavShown()} aria-label="Menu">
{isNavShown() ? <CloseIcon /> : <MenuIcon />}
</button>
);
};

View File

@ -1,6 +1,4 @@
---
import type { ProjectType } from '@root/types';
import './ProjectItem.scss';
import { Icon } from 'astro-icon';

View File

@ -1,6 +1,4 @@
---
import type { ArticleType } from '@root/types';
import './RecentArticles.scss';
import { ArticleItem } from '@components/ArticleItem';
import { sortArtcilesByDate } from '@utils/articles';

View File

@ -9,15 +9,19 @@
position: absolute;
left: 8px;
fill: var(--font-color-grayer);
filter: none;
}
& input {
padding-left: 40px;
color: var(--font-color-grayer);
color: var(--font-color-gray);
background-color: var(--background-color-hover);
}
& span {
font-size: var(--font-size-lg);
font-weight: 500;
color: var(--font-color-grayer);
color: var(--font-color-gray);
min-width: 20px;
text-align: center;
}
}

View File

@ -54,7 +54,7 @@ const SearchInput: Component<SearchInputProps> = (props) => {
return (
<div class="search-input">
<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg">
<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg" data-filter="none">
<path d="M10.6026 3.60001C11.8798 3.59993 13.1316 3.94283 14.2172 4.5901C15.3028 5.23736 16.179 6.16331 16.7472 7.26368C17.3154 8.36405 17.5531 9.59517 17.4334 10.8184C17.3137 12.0417 16.8415 13.2085 16.0699 14.1876L21.2427 19.164C21.4085 19.3248 21.5053 19.5399 21.5135 19.7662C21.5218 19.9926 21.4411 20.2137 21.2874 20.3853C21.1337 20.5569 20.9184 20.6665 20.6845 20.6921C20.4505 20.7178 20.2151 20.6576 20.0253 20.5236L19.9205 20.436L14.7476 15.4596C13.8802 16.0922 12.8687 16.5172 11.7968 16.6994C10.7248 16.8815 9.62324 16.8157 8.58298 16.5074C7.54272 16.199 6.59366 15.6569 5.81422 14.9259C5.03478 14.1949 4.44733 13.296 4.10042 12.3034C3.7535 11.3108 3.65708 10.2531 3.81911 9.21757C3.98114 8.18204 4.39698 7.19847 5.03226 6.34812C5.66755 5.49778 6.50404 4.80506 7.47263 4.32721C8.44122 3.84936 9.51411 3.60009 10.6026 3.60001V3.60001ZM10.6026 5.40001C9.27934 5.40001 8.01025 5.90572 7.07454 6.80589C6.13884 7.70607 5.61316 8.92697 5.61316 10.2C5.61316 11.473 6.13884 12.6939 7.07454 13.5941C8.01025 14.4943 9.27934 15 10.6026 15C11.9259 15 13.195 14.4943 14.1307 13.5941C15.0664 12.6939 15.5921 11.473 15.5921 10.2C15.5921 8.92697 15.0664 7.70607 14.1307 6.80589C13.195 5.90572 11.9259 5.40001 10.6026 5.40001Z" />
</svg>
<input onInput={onSearch} value={search()} type="text" placeholder={props.placeholder || 'Search article by title or description...'} />

View File

@ -1,6 +1,4 @@
---
import type { SkillsType } from '@root/types';
import { Icon } from 'astro-icon';
import './SkillsBlock.scss';

View File

@ -86,12 +86,7 @@ const TagsList: Component<TagsListProps> = (props) => {
<For
each={props.data}
children={(tag) => (
<li
onClick={onSelect}
style={isTagSelected(tag) && 'border-color: var(--border-color-hover);'}
class="btn-link"
data-tag={tag.toLocaleLowerCase()}
>
<li onClick={onSelect} class="btn-link" data-tag={tag.toLocaleLowerCase()} data-active={isTagSelected(tag)}>
{tag}
</li>
)}

View File

@ -1,8 +0,0 @@
---
import './ThemeSwitcher.scss';
import { Icon } from 'astro-icon'
---
<button class='theme-switcher'>
<Icon name='moon' width='21' height='21' />
</button>

View File

@ -6,8 +6,13 @@
cursor: pointer;
padding: 0;
margin: 0;
opacity: 0;
&:hover {
opacity: var(--opacity-hover);
border: none;
}
&.ready {
opacity: 1;
transition: all 0.1s linear 0s;
}
}

View File

@ -0,0 +1,64 @@
import type { Component, JSX } from 'solid-js';
import { SITE_SETTINGS } from '@root/config';
import { createSignal, onMount, Switch, Match } from 'solid-js';
import './ThemeSwitcher.scss';
const MoonIcon: Component = () => (
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.4998 10.3311C9.39883 9.22975 8.64906 7.82674 8.34521 6.29939C8.04136 4.77203 8.19707 3.18889 8.79266 1.75C7.09451 2.08429 5.53468 2.91752 4.31266 4.14313C0.895781 7.56 0.895781 13.1005 4.31266 16.5174C7.73041 19.9351 13.27 19.9342 16.6878 16.5174C17.9131 15.2955 18.7462 13.736 19.0809 12.0382C17.642 12.6337 16.0589 12.7894 14.5316 12.4855C13.0042 12.1817 11.6012 11.432 10.4998 10.3311Z"
fill="#010409"
/>
</svg>
);
const SunIcon: Component = () => (
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.12062 10.5C6.12062 12.9159 8.08587 14.8811 10.5017 14.8811C12.9176 14.8811 14.8829 12.9159 14.8829 10.5C14.8829 8.08413 12.9176 6.11888 10.5017 6.11888C8.08587 6.11888 6.12062 8.08413 6.12062 10.5ZM9.625 16.625H11.375V19.25H9.625V16.625ZM9.625 1.75H11.375V4.375H9.625V1.75ZM1.75 9.625H4.375V11.375H1.75V9.625ZM16.625 9.625H19.25V11.375H16.625V9.625ZM4.93238 17.3057L3.69513 16.0685L5.551 14.2126L6.78825 15.4499L4.93238 17.3057ZM14.2118 5.551L16.0685 3.69425L17.3057 4.9315L15.449 6.78825L14.2118 5.551ZM5.551 6.78912L3.69513 4.93238L4.93325 3.69513L6.78825 5.55187L5.551 6.78912ZM17.3057 16.0685L16.0685 17.3057L14.2118 15.449L15.449 14.2118L17.3057 16.0685Z"
fill="black"
/>
</svg>
);
const ThemeSwitcher: Component = () => {
const [theme, setTheme] = createSignal<ThemeModeType>(SITE_SETTINGS.defaultTheme);
const [isReady, setIsReady] = createSignal<boolean>(false);
const toggleTheme: JSX.EventHandler<HTMLButtonElement, MouseEvent> = () => {
if (!window.theme) return;
const newTheme = theme() === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
onMount(() => {
setIsReady(true);
if (window.theme) {
setTheme(window.theme);
/* Update theme state on changing OS the,e */
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
const theme = isDark ? 'dark' : 'light';
setTheme(theme);
});
}
});
return (
<button onClick={toggleTheme} class={isReady() ? 'theme-switcher ready' : 'theme-switcher'} aria-label={theme()}>
<Switch
children={
<>
<Match when={theme() === 'light'} children={<MoonIcon />} />
<Match when={theme() === 'dark'} children={<SunIcon />} />
</>
}
/>
</button>
);
};
export default ThemeSwitcher;

View File

@ -1 +1 @@
export { default } from './ThemeSwitcher.astro';
export { default } from './ThemeSwitcher';

View File

@ -1,3 +1,7 @@
export const SITE_SETTINGS: SiteConfigType = {
defaultTheme: 'dark',
};
export const SITE_METADATA = {
title: 'Sergey Yarkov',
name: 'yarkov.tech',

View File

@ -1,6 +1,6 @@
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_378_210)">
<path d="M13.1464 11.4548C13.1464 12.2108 13.3615 12.5123 13.924 12.5123C15.1777 12.5123 15.976 10.9148 15.976 8.258C15.976 4.1972 13.0168 2.2532 9.32232 2.2532C5.52162 2.2532 2.06472 4.802 2.06472 9.6188C2.06472 14.2196 5.08872 16.7252 9.73272 16.7252C11.3095 16.7252 12.3679 16.5524 13.987 16.0124L14.3344 17.4587C12.736 17.978 11.0278 18.1283 9.71112 18.1283C3.61992 18.1283 0.357422 14.7803 0.357422 9.6179C0.357422 4.4123 4.13832 0.8699 9.34392 0.8699C14.7655 0.8699 17.6374 4.1099 17.6374 8.0843C17.6374 11.4539 16.5799 14.0243 13.2535 14.0243C11.7406 14.0243 10.7479 13.4195 10.6183 12.0794C10.2295 13.5698 9.19272 14.0243 7.78782 14.0243C5.90862 14.0243 4.33182 12.5762 4.33182 9.6611C4.33182 6.7235 5.71512 4.9091 8.19912 4.9091C9.51672 4.9091 10.3375 5.4275 10.7029 6.2483L11.3302 5.1035H13.1446V11.4548H13.1464V11.4548ZM10.4905 8.6036C10.4905 7.4165 9.60402 6.9188 8.86962 6.9188C8.07042 6.9188 7.18572 7.5659 7.18572 9.4676C7.18572 10.9796 7.85532 11.822 8.86962 11.822C9.58242 11.822 10.4905 11.3684 10.4905 10.1156V8.6036Z" fill="#010409"/>
<path d="M13.1464 11.4548C13.1464 12.2108 13.3615 12.5123 13.924 12.5123C15.1777 12.5123 15.976 10.9148 15.976 8.258C15.976 4.1972 13.0168 2.2532 9.32232 2.2532C5.52162 2.2532 2.06472 4.802 2.06472 9.6188C2.06472 14.2196 5.08872 16.7252 9.73272 16.7252C11.3095 16.7252 12.3679 16.5524 13.987 16.0124L14.3344 17.4587C12.736 17.978 11.0278 18.1283 9.71112 18.1283C3.61992 18.1283 0.357422 14.7803 0.357422 9.6179C0.357422 4.4123 4.13832 0.8699 9.34392 0.8699C14.7655 0.8699 17.6374 4.1099 17.6374 8.0843C17.6374 11.4539 16.5799 14.0243 13.2535 14.0243C11.7406 14.0243 10.7479 13.4195 10.6183 12.0794C10.2295 13.5698 9.19272 14.0243 7.78782 14.0243C5.90862 14.0243 4.33182 12.5762 4.33182 9.6611C4.33182 6.7235 5.71512 4.9091 8.19912 4.9091C9.51672 4.9091 10.3375 5.4275 10.7029 6.2483L11.3302 5.1035H13.1446V11.4548H13.1464V11.4548ZM10.4905 8.6036C10.4905 7.4165 9.60402 6.9188 8.86962 6.9188C8.07042 6.9188 7.18572 7.5659 7.18572 9.4676C7.18572 10.9796 7.85532 11.822 8.86962 11.822C9.58242 11.822 10.4905 11.3684 10.4905 10.1156V8.6036Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_378_210">

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,11 +1,9 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_355_422)">
<path d="M8.03531 0.576701C10.5562 -0.0697833 13.3423 0.306935 15.5655 1.67904C18.3655 3.3535 20.1934 6.52092 20.2399 9.78139C20.3423 13.0744 18.6259 16.3395 15.8678 18.1302C12.798 20.1953 8.55156 20.2744 5.41664 18.3116C2.22132 16.4046 0.356169 12.5581 0.835309 8.86506C1.22125 4.96272 4.23531 1.52092 8.03531 0.576779V0.576701Z" fill="#010101"/>
<path d="M7.64851 2.1721C12.4113 0.26507 18.2532 3.78601 18.7462 8.89304C19.5137 13.4884 15.6997 18.1581 11.0438 18.293C6.61593 18.7349 2.33687 14.9813 2.21133 10.5349C1.88109 6.93491 4.2532 3.3628 7.64851 2.1721Z" fill="white"/>
<path d="M8.12824 9.50703C10.2632 7.76281 12.3515 5.95812 14.5329 4.26508C13.3887 6.02328 12.212 7.75812 11.0678 9.51625C10.0864 9.52093 9.10504 9.52094 8.12824 9.50695V9.50703ZM9.93293 10.4791C10.9189 10.4791 11.9004 10.4791 12.8818 10.493C10.7329 12.2279 8.65387 14.0465 6.46777 15.7349C7.61199 13.9767 8.78871 12.2373 9.93293 10.4791Z" fill="#010101"/>
<g clip-path="url(#clip0_753_2)">
<path d="M10.4463 0.0116577C9.6101 0.0140479 8.77739 0.119851 7.96715 0.326658C4.06715 1.29582 0.972981 4.82832 0.575481 8.83499C0.0838144 12.625 1.99965 16.5725 5.27881 18.53C8.49631 20.545 12.8563 20.4633 16.0071 18.3442C18.838 16.5058 20.6005 13.1542 20.4955 9.77332C20.4471 6.42666 18.5705 3.17666 15.6955 1.45666C14.1288 0.490824 12.2863 0.00499105 10.4471 0.012491L10.4463 0.0116577ZM10.3938 1.42499C14.5146 1.41916 18.5513 4.60249 18.9621 8.86166C19.7496 13.5783 15.8346 18.3725 11.0555 18.5117C6.51048 18.965 2.11881 15.1117 1.98881 10.5475C1.65048 6.85249 4.08631 3.18499 7.57048 1.96416C8.46874 1.60663 9.42702 1.42392 10.3938 1.42582V1.42499ZM14.6363 4.11166C12.3971 5.84916 10.253 7.70166 8.06215 9.49249C9.06465 9.50666 10.0721 9.50582 11.0796 9.50082C12.2546 7.69666 13.463 5.91749 14.6363 4.11166ZM9.91548 10.49C8.74048 12.295 7.53215 14.0808 6.35715 15.885C8.60131 14.1517 10.7363 12.285 12.9421 10.505C11.9333 10.4928 10.9244 10.4878 9.91548 10.49V10.49Z" fill="#010101"/>
</g>
<defs>
<clipPath id="clip0_355_422">
<clipPath id="clip0_753_2">
<rect width="20" height="20" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,13 +1,11 @@
---
import type { Props as BaseHeadProps } from '@root/components/BaseHead.astro';
import type { ArticleType } from '@root/types';
import '@styles/global.scss';
import BaseHead from '@root/components/BaseHead.astro';
import BaseHead from '@components/BaseHead.astro';
import BaseLayout from '@components/BaseLayout';
import { DateFormatter } from '@root/utils';
import ArticleContent from '@root/components/ArticleContent';
import ArticlePost from '@root/components/ArticlePost';
import ArticleContent from '@components/ArticleContent';
import ArticlePost from '@components/ArticlePost';
import '@styles/global.scss';
export interface Props extends BaseHeadProps {
lang?: string | undefined;
@ -19,7 +17,10 @@ const { lang = 'ru', content } = Astro.props as Props;
<html lang={lang}>
<head>
<BaseHead title={content.title} />
<BaseHead title={content.title}>
<link rel='stylesheet' href='assets/css/prism-one-dark.min.css' media='(prefers-color-scheme: dark)' />
<link rel='stylesheet' href='assets/css/prism-one-light.min.css' media='(prefers-color-scheme: light)' />
</BaseHead>
</head>
<BaseLayout>

View File

@ -1,11 +1,11 @@
---
import type { Props as BaseHeadProps } from '@root/components/BaseHead.astro';
import type { Props as BaseHeadProps } from '@components/BaseHead.astro';
import '@styles/global.scss';
import BaseHead from '@root/components/BaseHead.astro';
import BaseLayout from '@components/BaseLayout';
import { SITE_METADATA } from '@root/config';
import PageHeading from '@root/components/PageHeading';
import BaseHead from '@components/BaseHead.astro';
import BaseLayout from '@components/BaseLayout';
import PageHeading from '@components/PageHeading';
import '@styles/global.scss';
export interface Props extends BaseHeadProps {
lang?: string | undefined;

View File

@ -1,5 +1,4 @@
---
import '@root/styles/prism-one-light.css';
import ArticleLayout from '@root/layouts/article.astro';
import { Markdown } from 'astro/components';

View File

@ -1,6 +1,4 @@
---
import type { ArticleType } from '@root/types';
import PageLayout from '@layouts/default.astro';
import ArticlesList from '@components/ArticlesList';
import { transformArticles, formatToArticleBlocks } from '@utils/articles';

View File

@ -1,6 +1,5 @@
---
import PageLayout from '@layouts/default.astro';
import PageHeading from '@components/PageHeading';
import ContactForm from '@components/ContactForm';
import ContactsList from '@components/ContactsList';
---

View File

@ -1,6 +1,4 @@
---
import type { ArticleType } from '@root/types';
import * as utils from '@utils/index';
import PageLayout from '@layouts/default.astro';
import RecentArticles from '@components/RecentArticles';

View File

@ -1,120 +1,10 @@
:root {
/* Fonts */
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-family-base: 'Rubik', var(--font-fallback);
--font-color: var(--color-black);
--font-color-gray: var(--color-gray-500);
--font-color-grayer: var(--color-gray-700);
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
--font-size-6xl: 3.75rem;
--font-size-7xl: 4.5rem;
--font-size-8xl: 6rem;
--font-size-9xl: 8rem;
/* Line heights */
--line-height-normal: 'normal';
--line-height-none: 1;
--line-height-shorter: 1.25;
--line-height-short: 1.375;
--line-height-base: 1.5;
--line-height-tall: 1.625;
/* Colors */
--color-white: #ffffff;
--color-black: #010409;
--color-blue-50: #cae8ff;
--color-blue-100: #a5d6ff;
--color-blue-200: #79c0ff;
--color-blue-300: #58a6ff;
--color-blue-400: #388bfd;
--color-blue-500: #1f6feb;
--color-blue-600: #1158c7;
--color-blue-700: #0d419d;
--color-blue-800: #0c2d6b;
--color-blue-900: #051d4d;
--color-gray-50: #f0f6fc;
--color-gray-100: #c9d1d9;
--color-gray-200: #b1bac4;
--color-gray-300: #8b949e;
--color-gray-400: #6e7681;
--color-gray-500: #484f58;
--color-gray-600: #30363d;
--color-gray-700: #21262d;
--color-gray-800: #161b22;
--color-gray-900: #0d1117;
--color-orange-50: #ffdfb6;
--color-orange-100: #ffc680;
--color-orange-200: #ffa657;
--color-orange-300: #f0883e;
--color-orange-400: #db6d28;
--color-orange-500: #bd561d;
--color-orange-600: #9b4215;
--color-orange-700: #762d0a;
--color-orange-800: #5a1e02;
--color-orange-900: #3d1300;
--color-yellow-50: #f8e3a1;
--color-yellow-100: #f2cc60;
--color-yellow-200: #e3b341;
--color-yellow-300: #d29922;
--color-yellow-400: #bb8009;
--color-yellow-500: #9e6a03;
--color-yellow-600: #845306;
--color-yellow-700: #693e00;
--color-yellow-800: #4b2900;
--color-yellow-900: #341a00;
--background-color-hover: var(--color-gray-50);
/* Border */
--border-color: var(--color-gray-100);
--border-color-hover: var(--color-gray-400);
--border-radius-md: 3px;
--border-radius-lg: 5px;
/* Sizes */
--content-width: 760px;
--content-padding: 24px;
/* Elements */
--background-body-color: var(--color-white);
--background-header-color: var(--color-white);
--background-scrollbar-track-color: #eff1f5;
--background-scrollbar-thumb-color: var(--color-gray-100);
--background-inline-code: rgba(0, 0, 0, 0.05);
--opacity-hover: 0.7;
}
@import './theme.scss';
::selection {
background: var(--color-yellow-100);
color: var(--color-black);
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: var(--background-scrollbar-track-color);
}
::-webkit-scrollbar-thumb {
background: var(--background-scrollbar-thumb-color);
}
html,
body {
box-sizing: border-box;
@ -138,13 +28,14 @@ html {
font-weight: normal;
font-kerning: normal;
font-family: var(--font-family-base);
background: var(--background-body-color);
}
body {
margin: 0;
padding: 0;
color: var(--font-color);
background-color: var(--background-body-color);
background: var(--background-body-color);
}
.container {
@ -168,6 +59,7 @@ body {
align-items: center;
column-gap: 5px;
padding: 3px 10px;
background-color: var(--background-btn-link);
border-radius: var(--border-radius-md);
border: 1px solid var(--border-color);
text-decoration: none;
@ -181,6 +73,10 @@ body {
color: inherit;
border-color: var(--border-color-hover);
}
&[data-active='true'] {
background-color: var(--background-btn-link-active);
border-color: var(--border-color-hover);
}
}
li::marker {
@ -215,23 +111,27 @@ textarea {
-webkit-appearance: none;
font-family: var(--font-family-base);
padding: 8px 15px;
border: 1px solid var(--border-color);
border: none;
border-radius: var(--border-radius-md);
background-color: var(--background-inputs-color);
font-size: var(--font-size-sm);
width: 100%;
outline-color: var(--color-blue-500);
resize: vertical;
border: 1px solid var(--border-color);
outline-color: var(--color-blue-500);
}
button {
cursor: pointer;
font-family: var(--font-family-base);
font-weight: 500;
font-size: var(--font-size-sm);
padding: 4px 15px;
font-size: var(--font-size-md);
color: var(--font-color);
padding: 4px 16px;
border: 1px solid var(--border-color);
border-radius: var(--border-radius-md);
background: none;
font-size: var(--font-size-sm);
&:hover {
border: 1px solid var(--border-color-hover);
}
@ -264,12 +164,12 @@ pre {
}
a {
color: var(--color-blue-500);
color: var(--color-blue-400);
font-weight: 500;
text-decoration: none;
&:hover {
text-decoration: underline;
color: var(--color-blue-500);
color: var(--color-blue-400);
}
}

View File

@ -1,440 +0,0 @@
/**
* One Dark theme for prism.js
* Based on Atom's One Dark theme: https://github.com/atom/atom/tree/master/packages/one-dark-syntax
*/
/**
* One Dark colours (accurate as of commit 8ae45ca on 6 Sep 2018)
* From colors.less
* --mono-1: hsl(220, 14%, 71%);
* --mono-2: hsl(220, 9%, 55%);
* --mono-3: hsl(220, 10%, 40%);
* --hue-1: hsl(187, 47%, 55%);
* --hue-2: hsl(207, 82%, 66%);
* --hue-3: hsl(286, 60%, 67%);
* --hue-4: hsl(95, 38%, 62%);
* --hue-5: hsl(355, 65%, 65%);
* --hue-5-2: hsl(5, 48%, 51%);
* --hue-6: hsl(29, 54%, 61%);
* --hue-6-2: hsl(39, 67%, 69%);
* --syntax-fg: hsl(220, 14%, 71%);
* --syntax-bg: hsl(220, 13%, 18%);
* --syntax-gutter: hsl(220, 14%, 45%);
* --syntax-guide: hsla(220, 14%, 71%, 0.15);
* --syntax-accent: hsl(220, 100%, 66%);
* From syntax-variables.less
* --syntax-selection-color: hsl(220, 13%, 28%);
* --syntax-gutter-background-color-selected: hsl(220, 13%, 26%);
* --syntax-cursor-line: hsla(220, 100%, 80%, 0.04);
*/
code[class*="language-"],
pre[class*="language-"] {
background: hsl(220, 13%, 18%);
color: hsl(220, 14%, 71%);
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: "Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Selection */
code[class*="language-"]::-moz-selection,
code[class*="language-"] *::-moz-selection,
pre[class*="language-"] *::-moz-selection {
background: hsl(220, 13%, 28%);
color: inherit;
text-shadow: none;
}
code[class*="language-"]::selection,
code[class*="language-"] *::selection,
pre[class*="language-"] *::selection {
background: hsl(220, 13%, 28%);
color: inherit;
text-shadow: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
border-radius: 0.3em;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.2em 0.3em;
border-radius: 0.3em;
white-space: normal;
}
/* Print */
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
.token.comment,
.token.prolog,
.token.cdata {
color: hsl(220, 10%, 40%);
}
.token.doctype,
.token.punctuation,
.token.entity {
color: hsl(220, 14%, 71%);
}
.token.attr-name,
.token.class-name,
.token.boolean,
.token.constant,
.token.number,
.token.atrule {
color: hsl(29, 54%, 61%);
}
.token.keyword {
color: hsl(286, 60%, 67%);
}
.token.property,
.token.tag,
.token.symbol,
.token.deleted,
.token.important {
color: hsl(355, 65%, 65%);
}
.token.selector,
.token.string,
.token.char,
.token.builtin,
.token.inserted,
.token.regex,
.token.attr-value,
.token.attr-value > .token.punctuation {
color: hsl(95, 38%, 62%);
}
.token.variable,
.token.operator,
.token.function {
color: hsl(207, 82%, 66%);
}
.token.url {
color: hsl(187, 47%, 55%);
}
/* HTML overrides */
.token.attr-value > .token.punctuation.attr-equals,
.token.special-attr > .token.attr-value > .token.value.css {
color: hsl(220, 14%, 71%);
}
/* CSS overrides */
.language-css .token.selector {
color: hsl(355, 65%, 65%);
}
.language-css .token.property {
color: hsl(220, 14%, 71%);
}
.language-css .token.function,
.language-css .token.url > .token.function {
color: hsl(187, 47%, 55%);
}
.language-css .token.url > .token.string.url {
color: hsl(95, 38%, 62%);
}
.language-css .token.important,
.language-css .token.atrule .token.rule {
color: hsl(286, 60%, 67%);
}
/* JS overrides */
.language-javascript .token.operator {
color: hsl(286, 60%, 67%);
}
.language-javascript .token.template-string > .token.interpolation > .token.interpolation-punctuation.punctuation {
color: hsl(5, 48%, 51%);
}
/* JSON overrides */
.language-json .token.operator {
color: hsl(220, 14%, 71%);
}
.language-json .token.null.keyword {
color: hsl(29, 54%, 61%);
}
/* MD overrides */
.language-markdown .token.url,
.language-markdown .token.url > .token.operator,
.language-markdown .token.url-reference.url > .token.string {
color: hsl(220, 14%, 71%);
}
.language-markdown .token.url > .token.content {
color: hsl(207, 82%, 66%);
}
.language-markdown .token.url > .token.url,
.language-markdown .token.url-reference.url {
color: hsl(187, 47%, 55%);
}
.language-markdown .token.blockquote.punctuation,
.language-markdown .token.hr.punctuation {
color: hsl(220, 10%, 40%);
font-style: italic;
}
.language-markdown .token.code-snippet {
color: hsl(95, 38%, 62%);
}
.language-markdown .token.bold .token.content {
color: hsl(29, 54%, 61%);
}
.language-markdown .token.italic .token.content {
color: hsl(286, 60%, 67%);
}
.language-markdown .token.strike .token.content,
.language-markdown .token.strike .token.punctuation,
.language-markdown .token.list.punctuation,
.language-markdown .token.title.important > .token.punctuation {
color: hsl(355, 65%, 65%);
}
/* General */
.token.bold {
font-weight: bold;
}
.token.comment,
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.namespace {
opacity: 0.8;
}
/* Plugin overrides */
/* Selectors should have higher specificity than those in the plugins' default stylesheets */
/* Show Invisibles plugin overrides */
.token.token.tab:not(:empty):before,
.token.token.cr:before,
.token.token.lf:before,
.token.token.space:before {
color: hsla(220, 14%, 71%, 0.15);
text-shadow: none;
}
/* Toolbar plugin overrides */
/* Space out all buttons and move them away from the right edge of the code block */
div.code-toolbar > .toolbar.toolbar > .toolbar-item {
margin-right: 0.4em;
}
/* Styling the buttons */
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span {
background: hsl(220, 13%, 26%);
color: hsl(220, 9%, 55%);
padding: 0.1em 0.4em;
border-radius: 0.3em;
}
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus {
background: hsl(220, 13%, 28%);
color: hsl(220, 14%, 71%);
}
/* Line Highlight plugin overrides */
/* The highlighted line itself */
.line-highlight.line-highlight {
background: hsla(220, 100%, 80%, 0.04);
}
/* Default line numbers in Line Highlight plugin */
.line-highlight.line-highlight:before,
.line-highlight.line-highlight[data-end]:after {
background: hsl(220, 13%, 26%);
color: hsl(220, 14%, 71%);
padding: 0.1em 0.6em;
border-radius: 0.3em;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); /* same as Toolbar plugin default */
}
/* Hovering over a linkable line number (in the gutter area) */
/* Requires Line Numbers plugin as well */
pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before {
background-color: hsla(220, 100%, 80%, 0.04);
}
/* Line Numbers and Command Line plugins overrides */
/* Line separating gutter from coding area */
.line-numbers.line-numbers .line-numbers-rows,
.command-line .command-line-prompt {
border-right-color: hsla(220, 14%, 71%, 0.15);
}
/* Stuff in the gutter */
.line-numbers .line-numbers-rows > span:before,
.command-line .command-line-prompt > span:before {
color: hsl(220, 14%, 45%);
}
/* Match Braces plugin overrides */
/* Note: Outline colour is inherited from the braces */
.rainbow-braces .token.token.punctuation.brace-level-1,
.rainbow-braces .token.token.punctuation.brace-level-5,
.rainbow-braces .token.token.punctuation.brace-level-9 {
color: hsl(355, 65%, 65%);
}
.rainbow-braces .token.token.punctuation.brace-level-2,
.rainbow-braces .token.token.punctuation.brace-level-6,
.rainbow-braces .token.token.punctuation.brace-level-10 {
color: hsl(95, 38%, 62%);
}
.rainbow-braces .token.token.punctuation.brace-level-3,
.rainbow-braces .token.token.punctuation.brace-level-7,
.rainbow-braces .token.token.punctuation.brace-level-11 {
color: hsl(207, 82%, 66%);
}
.rainbow-braces .token.token.punctuation.brace-level-4,
.rainbow-braces .token.token.punctuation.brace-level-8,
.rainbow-braces .token.token.punctuation.brace-level-12 {
color: hsl(286, 60%, 67%);
}
/* Diff Highlight plugin overrides */
/* Taken from https://github.com/atom/github/blob/master/styles/variables.less */
pre.diff-highlight > code .token.token.deleted:not(.prefix),
pre > code.diff-highlight .token.token.deleted:not(.prefix) {
background-color: hsla(353, 100%, 66%, 0.15);
}
pre.diff-highlight > code .token.token.deleted:not(.prefix)::-moz-selection,
pre.diff-highlight > code .token.token.deleted:not(.prefix) *::-moz-selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix)::-moz-selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix) *::-moz-selection {
background-color: hsla(353, 95%, 66%, 0.25);
}
pre.diff-highlight > code .token.token.deleted:not(.prefix)::selection,
pre.diff-highlight > code .token.token.deleted:not(.prefix) *::selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix)::selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix) *::selection {
background-color: hsla(353, 95%, 66%, 0.25);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix),
pre > code.diff-highlight .token.token.inserted:not(.prefix) {
background-color: hsla(137, 100%, 55%, 0.15);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix)::-moz-selection,
pre.diff-highlight > code .token.token.inserted:not(.prefix) *::-moz-selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix)::-moz-selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix) *::-moz-selection {
background-color: hsla(135, 73%, 55%, 0.25);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix)::selection,
pre.diff-highlight > code .token.token.inserted:not(.prefix) *::selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix)::selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix) *::selection {
background-color: hsla(135, 73%, 55%, 0.25);
}
/* Previewers plugin overrides */
/* Based on https://github.com/atom-community/atom-ide-datatip/blob/master/styles/atom-ide-datatips.less and https://github.com/atom/atom/blob/master/packages/one-dark-ui */
/* Border around popup */
.prism-previewer.prism-previewer:before,
.prism-previewer-gradient.prism-previewer-gradient div {
border-color: hsl(224, 13%, 17%);
}
/* Angle and time should remain as circles and are hence not included */
.prism-previewer-color.prism-previewer-color:before,
.prism-previewer-gradient.prism-previewer-gradient div,
.prism-previewer-easing.prism-previewer-easing:before {
border-radius: 0.3em;
}
/* Triangles pointing to the code */
.prism-previewer.prism-previewer:after {
border-top-color: hsl(224, 13%, 17%);
}
.prism-previewer-flipped.prism-previewer-flipped.after {
border-bottom-color: hsl(224, 13%, 17%);
}
/* Background colour within the popup */
.prism-previewer-angle.prism-previewer-angle:before,
.prism-previewer-time.prism-previewer-time:before,
.prism-previewer-easing.prism-previewer-easing {
background: hsl(219, 13%, 22%);
}
/* For angle, this is the positive area (eg. 90deg will display one quadrant in this colour) */
/* For time, this is the alternate colour */
.prism-previewer-angle.prism-previewer-angle circle,
.prism-previewer-time.prism-previewer-time circle {
stroke: hsl(220, 14%, 71%);
stroke-opacity: 1;
}
/* Stroke colours of the handle, direction point, and vector itself */
.prism-previewer-easing.prism-previewer-easing circle,
.prism-previewer-easing.prism-previewer-easing path,
.prism-previewer-easing.prism-previewer-easing line {
stroke: hsl(220, 14%, 71%);
}
/* Fill colour of the handle */
.prism-previewer-easing.prism-previewer-easing circle {
fill: transparent;
}

View File

@ -1,428 +0,0 @@
/**
* One Light theme for prism.js
* Based on Atom's One Light theme: https://github.com/atom/atom/tree/master/packages/one-light-syntax
*/
/**
* One Light colours (accurate as of commit eb064bf on 19 Feb 2021)
* From colors.less
* --mono-1: hsl(230, 8%, 24%);
* --mono-2: hsl(230, 6%, 44%);
* --mono-3: hsl(230, 4%, 64%)
* --hue-1: hsl(198, 99%, 37%);
* --hue-2: hsl(221, 87%, 60%);
* --hue-3: hsl(301, 63%, 40%);
* --hue-4: hsl(119, 34%, 47%);
* --hue-5: hsl(5, 74%, 59%);
* --hue-5-2: hsl(344, 84%, 43%);
* --hue-6: hsl(35, 99%, 36%);
* --hue-6-2: hsl(35, 99%, 40%);
* --syntax-fg: hsl(230, 8%, 24%);
* --syntax-bg: hsl(230, 1%, 98%);
* --syntax-gutter: hsl(230, 1%, 62%);
* --syntax-guide: hsla(230, 8%, 24%, 0.2);
* --syntax-accent: hsl(230, 100%, 66%);
* From syntax-variables.less
* --syntax-selection-color: hsl(230, 1%, 90%);
* --syntax-gutter-background-color-selected: hsl(230, 1%, 90%);
* --syntax-cursor-line: hsla(230, 8%, 24%, 0.05);
*/
code[class*="language-"],
pre[class*="language-"] {
background: hsl(230, 1%, 98%);
color: hsl(230, 8%, 24%);
font-family: "Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Selection */
code[class*="language-"]::-moz-selection,
code[class*="language-"] *::-moz-selection,
pre[class*="language-"] *::-moz-selection {
background: hsl(230, 1%, 90%);
color: inherit;
}
code[class*="language-"]::selection,
code[class*="language-"] *::selection,
pre[class*="language-"] *::selection {
background: hsl(230, 1%, 90%);
color: inherit;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
border-radius: 0.3em;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.2em 0.3em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.cdata {
color: hsl(230, 4%, 64%);
}
.token.doctype,
.token.punctuation,
.token.entity {
color: hsl(230, 8%, 24%);
}
.token.attr-name,
.token.class-name,
.token.boolean,
.token.constant,
.token.number,
.token.atrule {
color: hsl(35, 99%, 36%);
}
.token.keyword {
color: hsl(301, 63%, 40%);
}
.token.property,
.token.tag,
.token.symbol,
.token.deleted,
.token.important {
color: hsl(5, 74%, 59%);
}
.token.selector,
.token.string,
.token.char,
.token.builtin,
.token.inserted,
.token.regex,
.token.attr-value,
.token.attr-value > .token.punctuation {
color: hsl(119, 34%, 47%);
}
.token.variable,
.token.operator,
.token.function {
color: hsl(221, 87%, 60%);
}
.token.url {
color: hsl(198, 99%, 37%);
}
/* HTML overrides */
.token.attr-value > .token.punctuation.attr-equals,
.token.special-attr > .token.attr-value > .token.value.css {
color: hsl(230, 8%, 24%);
}
/* CSS overrides */
.language-css .token.selector {
color: hsl(5, 74%, 59%);
}
.language-css .token.property {
color: hsl(230, 8%, 24%);
}
.language-css .token.function,
.language-css .token.url > .token.function {
color: hsl(198, 99%, 37%);
}
.language-css .token.url > .token.string.url {
color: hsl(119, 34%, 47%);
}
.language-css .token.important,
.language-css .token.atrule .token.rule {
color: hsl(301, 63%, 40%);
}
/* JS overrides */
.language-javascript .token.operator {
color: hsl(301, 63%, 40%);
}
.language-javascript .token.template-string > .token.interpolation > .token.interpolation-punctuation.punctuation {
color: hsl(344, 84%, 43%);
}
/* JSON overrides */
.language-json .token.operator {
color: hsl(230, 8%, 24%);
}
.language-json .token.null.keyword {
color: hsl(35, 99%, 36%);
}
/* MD overrides */
.language-markdown .token.url,
.language-markdown .token.url > .token.operator,
.language-markdown .token.url-reference.url > .token.string {
color: hsl(230, 8%, 24%);
}
.language-markdown .token.url > .token.content {
color: hsl(221, 87%, 60%);
}
.language-markdown .token.url > .token.url,
.language-markdown .token.url-reference.url {
color: hsl(198, 99%, 37%);
}
.language-markdown .token.blockquote.punctuation,
.language-markdown .token.hr.punctuation {
color: hsl(230, 4%, 64%);
font-style: italic;
}
.language-markdown .token.code-snippet {
color: hsl(119, 34%, 47%);
}
.language-markdown .token.bold .token.content {
color: hsl(35, 99%, 36%);
}
.language-markdown .token.italic .token.content {
color: hsl(301, 63%, 40%);
}
.language-markdown .token.strike .token.content,
.language-markdown .token.strike .token.punctuation,
.language-markdown .token.list.punctuation,
.language-markdown .token.title.important > .token.punctuation {
color: hsl(5, 74%, 59%);
}
/* General */
.token.bold {
font-weight: bold;
}
.token.comment,
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.namespace {
opacity: 0.8;
}
/* Plugin overrides */
/* Selectors should have higher specificity than those in the plugins' default stylesheets */
/* Show Invisibles plugin overrides */
.token.token.tab:not(:empty):before,
.token.token.cr:before,
.token.token.lf:before,
.token.token.space:before {
color: hsla(230, 8%, 24%, 0.2);
}
/* Toolbar plugin overrides */
/* Space out all buttons and move them away from the right edge of the code block */
div.code-toolbar > .toolbar.toolbar > .toolbar-item {
margin-right: 0.4em;
}
/* Styling the buttons */
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span {
background: hsl(230, 1%, 90%);
color: hsl(230, 6%, 44%);
padding: 0.1em 0.4em;
border-radius: 0.3em;
}
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus {
background: hsl(230, 1%, 78%); /* custom: darken(--syntax-bg, 20%) */
color: hsl(230, 8%, 24%);
}
/* Line Highlight plugin overrides */
/* The highlighted line itself */
.line-highlight.line-highlight {
background: hsla(230, 8%, 24%, 0.05);
}
/* Default line numbers in Line Highlight plugin */
.line-highlight.line-highlight:before,
.line-highlight.line-highlight[data-end]:after {
background: hsl(230, 1%, 90%);
color: hsl(230, 8%, 24%);
padding: 0.1em 0.6em;
border-radius: 0.3em;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); /* same as Toolbar plugin default */
}
/* Hovering over a linkable line number (in the gutter area) */
/* Requires Line Numbers plugin as well */
pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before {
background-color: hsla(230, 8%, 24%, 0.05);
}
/* Line Numbers and Command Line plugins overrides */
/* Line separating gutter from coding area */
.line-numbers.line-numbers .line-numbers-rows,
.command-line .command-line-prompt {
border-right-color: hsla(230, 8%, 24%, 0.2);
}
/* Stuff in the gutter */
.line-numbers .line-numbers-rows > span:before,
.command-line .command-line-prompt > span:before {
color: hsl(230, 1%, 62%);
}
/* Match Braces plugin overrides */
/* Note: Outline colour is inherited from the braces */
.rainbow-braces .token.token.punctuation.brace-level-1,
.rainbow-braces .token.token.punctuation.brace-level-5,
.rainbow-braces .token.token.punctuation.brace-level-9 {
color: hsl(5, 74%, 59%);
}
.rainbow-braces .token.token.punctuation.brace-level-2,
.rainbow-braces .token.token.punctuation.brace-level-6,
.rainbow-braces .token.token.punctuation.brace-level-10 {
color: hsl(119, 34%, 47%);
}
.rainbow-braces .token.token.punctuation.brace-level-3,
.rainbow-braces .token.token.punctuation.brace-level-7,
.rainbow-braces .token.token.punctuation.brace-level-11 {
color: hsl(221, 87%, 60%);
}
.rainbow-braces .token.token.punctuation.brace-level-4,
.rainbow-braces .token.token.punctuation.brace-level-8,
.rainbow-braces .token.token.punctuation.brace-level-12 {
color: hsl(301, 63%, 40%);
}
/* Diff Highlight plugin overrides */
/* Taken from https://github.com/atom/github/blob/master/styles/variables.less */
pre.diff-highlight > code .token.token.deleted:not(.prefix),
pre > code.diff-highlight .token.token.deleted:not(.prefix) {
background-color: hsla(353, 100%, 66%, 0.15);
}
pre.diff-highlight > code .token.token.deleted:not(.prefix)::-moz-selection,
pre.diff-highlight > code .token.token.deleted:not(.prefix) *::-moz-selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix)::-moz-selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix) *::-moz-selection {
background-color: hsla(353, 95%, 66%, 0.25);
}
pre.diff-highlight > code .token.token.deleted:not(.prefix)::selection,
pre.diff-highlight > code .token.token.deleted:not(.prefix) *::selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix)::selection,
pre > code.diff-highlight .token.token.deleted:not(.prefix) *::selection {
background-color: hsla(353, 95%, 66%, 0.25);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix),
pre > code.diff-highlight .token.token.inserted:not(.prefix) {
background-color: hsla(137, 100%, 55%, 0.15);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix)::-moz-selection,
pre.diff-highlight > code .token.token.inserted:not(.prefix) *::-moz-selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix)::-moz-selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix) *::-moz-selection {
background-color: hsla(135, 73%, 55%, 0.25);
}
pre.diff-highlight > code .token.token.inserted:not(.prefix)::selection,
pre.diff-highlight > code .token.token.inserted:not(.prefix) *::selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix)::selection,
pre > code.diff-highlight .token.token.inserted:not(.prefix) *::selection {
background-color: hsla(135, 73%, 55%, 0.25);
}
/* Previewers plugin overrides */
/* Based on https://github.com/atom-community/atom-ide-datatip/blob/master/styles/atom-ide-datatips.less and https://github.com/atom/atom/blob/master/packages/one-light-ui */
/* Border around popup */
.prism-previewer.prism-previewer:before,
.prism-previewer-gradient.prism-previewer-gradient div {
border-color: hsl(0, 0, 95%);
}
/* Angle and time should remain as circles and are hence not included */
.prism-previewer-color.prism-previewer-color:before,
.prism-previewer-gradient.prism-previewer-gradient div,
.prism-previewer-easing.prism-previewer-easing:before {
border-radius: 0.3em;
}
/* Triangles pointing to the code */
.prism-previewer.prism-previewer:after {
border-top-color: hsl(0, 0, 95%);
}
.prism-previewer-flipped.prism-previewer-flipped.after {
border-bottom-color: hsl(0, 0, 95%);
}
/* Background colour within the popup */
.prism-previewer-angle.prism-previewer-angle:before,
.prism-previewer-time.prism-previewer-time:before,
.prism-previewer-easing.prism-previewer-easing {
background: hsl(0, 0%, 100%);
}
/* For angle, this is the positive area (eg. 90deg will display one quadrant in this colour) */
/* For time, this is the alternate colour */
.prism-previewer-angle.prism-previewer-angle circle,
.prism-previewer-time.prism-previewer-time circle {
stroke: hsl(230, 8%, 24%);
stroke-opacity: 1;
}
/* Stroke colours of the handle, direction point, and vector itself */
.prism-previewer-easing.prism-previewer-easing circle,
.prism-previewer-easing.prism-previewer-easing path,
.prism-previewer-easing.prism-previewer-easing line {
stroke: hsl(230, 8%, 24%);
}
/* Fill colour of the handle */
.prism-previewer-easing.prism-previewer-easing circle {
fill: transparent;
}

140
src/styles/theme.scss Normal file
View File

@ -0,0 +1,140 @@
:root,
:root[data-theme='light'] {
color-scheme: light;
/* Fonts */
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-family-base: 'Rubik', var(--font-fallback);
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
--font-size-6xl: 3.75rem;
--font-size-7xl: 4.5rem;
--font-size-8xl: 6rem;
--font-size-9xl: 8rem;
/* Line heights */
--line-height-normal: 'normal';
--line-height-none: 1;
--line-height-shorter: 1.25;
--line-height-short: 1.375;
--line-height-base: 1.5;
--line-height-tall: 1.625;
/* Colors */
--color-white: #ffffff;
--color-black: #010409;
--color-blue-50: #cae8ff;
--color-blue-100: #a5d6ff;
--color-blue-200: #79c0ff;
--color-blue-300: #58a6ff;
--color-blue-400: #388bfd;
--color-blue-500: #1f6feb;
--color-blue-600: #1158c7;
--color-blue-700: #0d419d;
--color-blue-800: #0c2d6b;
--color-blue-900: #051d4d;
--color-gray-50: #f0f6fc;
--color-gray-100: #c9d1d9;
--color-gray-200: #b1bac4;
--color-gray-300: #8b949e;
--color-gray-400: #6e7681;
--color-gray-500: #484f58;
--color-gray-600: #30363d;
--color-gray-700: #21262d;
--color-gray-800: #161b22;
--color-gray-900: #0d1117;
--color-orange-50: #ffdfb6;
--color-orange-100: #ffc680;
--color-orange-200: #ffa657;
--color-orange-300: #f0883e;
--color-orange-400: #db6d28;
--color-orange-500: #bd561d;
--color-orange-600: #9b4215;
--color-orange-700: #762d0a;
--color-orange-800: #5a1e02;
--color-orange-900: #3d1300;
--color-yellow-50: #f8e3a1;
--color-yellow-100: #f2cc60;
--color-yellow-200: #e3b341;
--color-yellow-300: #d29922;
--color-yellow-400: #bb8009;
--color-yellow-500: #9e6a03;
--color-yellow-600: #845306;
--color-yellow-700: #693e00;
--color-yellow-800: #4b2900;
--color-yellow-900: #341a00;
/* Border */
--border-radius-md: 3px;
--border-radius-lg: 5px;
/* Sizes */
--content-width: 760px;
--content-padding: 24px;
--opacity-hover: 0.7;
/* Fonts */
--font-color: var(--color-black);
--font-color-gray: var(--color-gray-500);
--font-color-grayer: var(--color-gray-700);
/* Border */
--border-color: var(--color-gray-100);
--border-color-hover: var(--color-gray-400);
/* Elements */
--background-body-color: var(--color-white);
--background-header-color: var(--color-white);
--background-inline-code: rgba(0, 0, 0, 0.05);
--background-color-hover: var(--color-gray-50);
--background-btn-link: var(--color-white);
--background-btn-link-active: var(--color-white);
--background-inputs-color: var(--color-white);
/* Icons */
--icon-primary: var(--color-white);
--icon-secondary: var(--color-gray-700);
}
:root[data-theme='dark'] {
color-scheme: dark;
/* Fonts */
--font-color: var(--color-white);
--font-color-gray: var(--color-gray-100);
--font-color-grayer: var(--color-gray-200);
/* Border */
--border-color: var(--color-gray-700);
--border-color-hover: var(--color-gray-600);
/* Elements */
--background-body-color: var(--color-gray-900);
--background-header-color: var(--color-gray-900);
--background-inline-code: var(--color-gray-800);
--background-color-hover: var(--color-gray-800);
--background-btn-link: var(--color-gray-800);
--background-btn-link-active: var(--color-gray-700);
--background-inputs-color: var(--color-gray-800);
/* Icons */
--icon-primary: var(--color-white);
--icon-secondary: var(--color-gray-100);
--icon-filter: invert(100%);
& .header svg,
& .site-content svg:not([data-filter='none']) {
filter: var(--icon-filter);
}
}

View File

@ -1,25 +0,0 @@
export type ArticleType = {
title: string;
author: string;
tags: Array<string>;
published_at: string;
};
export type ProjectType = {
icon: string;
name: string;
year: string;
description: string;
sourceUrl?: string | undefined;
articleUrl?: string | undefined;
demoUrl?: string | undefined;
};
export type SkillsType = {
title: string;
list: Array<{ icon?: string | undefined; name: string }>;
};
export type ArticleBlockType = {
[year: number]: ArticleType[];
};

35
src/types/main.d.ts vendored Normal file
View File

@ -0,0 +1,35 @@
export {};
declare global {
interface Window {
theme?: ThemeModeType | undefined;
}
type ArticleType = {
title: string;
author: string;
tags: Array<string>;
published_at: string;
};
type ProjectType = {
icon: string;
name: string;
year: string;
description: string;
sourceUrl?: string | undefined;
articleUrl?: string | undefined;
demoUrl?: string | undefined;
};
type SkillsType = {
title: string;
list: Array<{ icon?: string | undefined; name: string }>;
};
type ArticleBlockType = {
[year: number]: ArticleType[];
};
type ThemeModeType = 'light' | 'dark';
}

View File

@ -1,5 +1,3 @@
import type { ArticleType, ArticleBlockType } from '@root/types';
import { MarkdownInstance } from 'astro';
export const transformArticles = (articles: MarkdownInstance<ArticleType>[]): ArticleType[] =>

View File

@ -17,7 +17,8 @@
"@utils/*": ["./src/utils/*"],
"@stores/*": ["./src/stores/*"]
},
"outDir": "./dist"
"outDir": "./dist",
"typeRoots": ["./node_modules/@types", "./src/types"]
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts"]
}