feat: html layout pages

This commit is contained in:
Sergey Yarkov 2022-07-15 23:56:29 +03:00
parent 97ccb7613f
commit 099f580a6f
15 changed files with 313 additions and 46 deletions

2
.gitignore vendored
View File

@ -10,6 +10,8 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
.idea
# environment variables # environment variables
.env .env

5
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

58
.idea/codeStyles/Project.xml generated Normal file
View File

@ -0,0 +1,58 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="HTML_ENFORCE_QUOTES" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/yarkov.tech.iml" filepath="$PROJECT_DIR$/.idea/yarkov.tech.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

12
.idea/yarkov.tech.iml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -7,7 +7,7 @@ Personal website created with Astro.
### Todo ### Todo
- [ ] HTML layout - [x] HTML layout
- [ ] Adaptive & Responsive layout - [ ] Adaptive & Responsive layout
- [ ] Dark/Light Theme - [ ] Dark/Light Theme
- [ ] Multilang web-site - [ ] Multilang web-site

View File

@ -1,6 +1,6 @@
import './ArticleItem.scss'; import './ArticleItem.scss';
import { Component } from 'solid-js'; import { Component } from 'solid-js';
import { IArticle } from '@root/interfaces'; import type { IArticle } from '@root/interfaces';
import { DateFormatter } from '@utils/date'; import { DateFormatter } from '@utils/date';
export type ArticleItemProps = { export type ArticleItemProps = {

View File

@ -24,15 +24,6 @@
} }
&-tags { &-tags {
margin-bottom: 45px; margin-bottom: 45px;
& nav ul {
display: flex;
flex-wrap: wrap;
column-gap: 5px;
row-gap: 10px;
list-style: none;
margin: 0;
padding: 0;
}
} }
&-list { &-list {
&__wrapper { &__wrapper {

View File

@ -1,9 +1,9 @@
import './ArticlesList.scss'; import "./ArticlesList.scss";
import { Component, createSignal, Show } from 'solid-js'; import { Component, createSignal, Show } from "solid-js";
import { PageHeading } from '@components/PageHeading'; import { PageHeading } from "@components/PageHeading";
import { IArticle } from '@root/interfaces'; import type { IArticle } from "@root/interfaces";
import * as utils from '@root/utils/articles'; import * as utils from "@root/utils/articles";
import { ArticleItem } from '../ArticleItem'; import { ArticleItem } from "../ArticleItem";
export type ArticlesListProps = { export type ArticlesListProps = {
data: IArticle[]; data: IArticle[];
@ -11,42 +11,39 @@ export type ArticlesListProps = {
}; };
export const ArticlesList: Component<ArticlesListProps> = ({ data, tags }) => { export const ArticlesList: Component<ArticlesListProps> = ({ data, tags }) => {
const [articles, setArticles] = createSignal( const [articles, setArticles] = createSignal(utils.filterArticlesByYear(data));
utils.filterArticlesByYear(data)
);
const [selectedTags, setSelectedTags] = createSignal<string[]>([]); const [selectedTags, setSelectedTags] = createSignal<string[]>([]);
const [filteredArticles, setFilteredArticles] = createSignal<IArticle[]>([]); const [filteredArticles, setFilteredArticles] = createSignal<IArticle[]>([]);
return ( return (
<section class='articles container'> <section class="articles container">
<PageHeading <PageHeading
heading='Статьи' heading="Статьи"
description='Технические статьи, туториалы и различные справочные материалы которые description="Технические статьи, туториалы и различные справочные материалы которые
связаны с IT тематикой находятся здесь.' связаны с IT тематикой находятся здесь."
/> />
<div class='articles-search'> <div class="articles-search">
<svg <svg
width='25' width="25"
height='24' height="24"
viewBox='0 0 25 24' viewBox="0 0 25 24"
xmlns='http://www.w3.org/2000/svg'> xmlns="http://www.w3.org/2000/svg">
<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'></path> <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"></path>
</svg> </svg>
<input type='text' placeholder='поиск по названию или описанию...' /> <input type="text" placeholder="поиск по названию или описанию..." />
<span>{data.length}</span> <span>{data.length}</span>
</div> </div>
<div class='articles-tags'> <div class="articles-tags">
<nav> <nav>
<ul> <ul class='list-links'>
{tags.map((tag) => ( {tags.map((tag) => (
<li <li
style={ style={
selectedTags().includes(tag) && selectedTags().includes(tag) &&
'border-color: var(--border-color-hover);' "border-color: var(--border-color-hover);"
} }
class='btn-link' class="btn-link"
onClick={() => { onClick={() => {
if (selectedTags().includes(tag)) { if (selectedTags().includes(tag)) {
setSelectedTags( setSelectedTags(
@ -73,13 +70,13 @@ export const ArticlesList: Component<ArticlesListProps> = ({ data, tags }) => {
</ul> </ul>
</nav> </nav>
</div> </div>
<div class='articles-list'> <div class="articles-list">
<Show when={filteredArticles().length === 0}> <Show when={filteredArticles().length === 0}>
{Object.keys(articles()) {Object.keys(articles())
.map(Number) .map(Number)
.sort((a, b) => b - a) .sort((a, b) => b - a)
.map((year) => ( .map((year) => (
<div class='articles-list__wrapper'> <div class="articles-list__wrapper">
<h2>{year}</h2> <h2>{year}</h2>
{utils.sortArtcilesByDate(articles()[year]).map((article) => ( {utils.sortArtcilesByDate(articles()[year]).map((article) => (
<ArticleItem data={article} /> <ArticleItem data={article} />

140
src/pages/[article].astro Normal file
View File

@ -0,0 +1,140 @@
---
import Page from "@root/layouts/Page.astro";
import { Markdown } from "astro/components";
export function getStaticPaths() {
return [
{ params: { article: 'article' } },
]
}
---
<Page title="Article">
<article class="article container">
<header>
<div class="meta">
<ul class="list-links">
<li><a class="btn-link" href="#">JavaScript</a></li>
<li><a class="btn-link" href="#">Docker</a></li>
<li><a class="btn-link" href="#">Node.js</a></li>
<li><a class="btn-link" href="#">AVR</a></li>
<li><a class="btn-link" href="#">GraphQL</a></li>
<li><a class="btn-link" href="#">Web-development</a></li>
</ul>
<div>
<time datetime='2022-01-01'>
19 ЯНВ, 2022
</time>
<span>Опубликовал&nbsp;<b>Sergey Yarkov</b></span>
</div>
</div>
<div class="heading">
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </h1>
</div>
<div>
<figure>
<img
src="https://img.freepik.com/premium-photo/beautiful-emerald-lake-yoho-national-park-british-columbia-canada_131985-177.jpg?w=1920"
alt="Article Image">
</figure>
</div>
</header>
<div class="article-content">
<Markdown>
## Introduction
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
Maecenas eget condimentum velit, sit amet feugiat lectus. Class aptent taciti sociosqu ad litora torquent per
conubia nostra, per inceptos himenaeos. Praesent auctor purus luctus enim egestas, ac scelerisque ante pulvinar.
Donec ut rhoncus ex. Suspendisse ac rhoncus nisl, eu tempor urna. Curabitur vel bibendum lorem. Morbi convallis
convallis diam sit amet lacinia. Aliquam in elementum
Curabitur tempor quis eros tempus lacinia. Nam bibendum pellentesque quam a convallis. Sed ut vulputate nisi.
Integer in felis sed leo vestibulum venenatis. Suspendisse quis arcu sem. Aenean feugiat ex eu vestibulum
vestibulum. Morbi a eleifend magna. Nam metus lacus, porttitor eu mauris a, blandit ultrices nibh. Mauris sit
amet magna non ligula vestibulum eleifend. Nulla varius volutpat turpis sed lacinia. Nam eget mi in purus
lobortis eleifend. Sed nec ante dictum sem condimentum ullamcorper quis venenatis nisi. Proin vitae facilisis
nisi, ac posuere leo.
### Another Heading
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
- `Nam metus lacus`: porttitor eu mauris a, blandit ultrices nibh.
- `Class aptent`: taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
- `Sed nec ante`: dictum sem condimentum ullamcorper quis venenatis nisi.
</Markdown>
</div>
<footer>
<h2>Comments</h2>
</footer>
</article>
<style lang="scss">
.article {
& header {
& .meta {
display: flex;
justify-content: space-between;
align-items: flex-start;
column-gap: 5px;
row-gap: 1.2rem;
& ul {
max-width: 350px;
}
& div {
display: flex;
flex-direction: column;
text-align: right;
}
}
& .heading {
margin-top: 2rem;
& h1 {
font-weight: 600;
font-size: 2.25rem;
}
& p {
font-size: 1.125rem;
line-height: var(--line-height-base);
}
}
& figure {
margin: 0;
& img {
border-radius: var(--border-radius-md);
display: block;
margin: 0 auto;
max-width: 100%;
}
}
}
& footer {
margin-top: 5rem;
}
}
@media screen and (max-width: 560px) {
.article header .meta {
flex-direction: column-reverse;
& ul {
max-width: 100%;
}
& div {
align-self: flex-end;
}
}
}
</style>
</Page>

View File

@ -22,6 +22,14 @@
--font-size-8xl: 6rem; --font-size-8xl: 6rem;
--font-size-9xl: 8rem; --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 */ /* Colors */
--color-white: #ffffff; --color-white: #ffffff;
--color-black: #010409; --color-black: #010409;
@ -150,6 +158,15 @@ body {
padding: 0 var(--content-padding); padding: 0 var(--content-padding);
} }
.list-links {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin: 0;
padding: 0;
list-style: none;
}
/* Buttons */ /* Buttons */
.btn-link { .btn-link {
cursor: pointer; cursor: pointer;
@ -174,10 +191,23 @@ body {
& p, & p,
em, em,
q { q {
line-height: 1.5; line-height: var(--line-height-base);
font-size: var(--font-size-lg); font-size: var(--font-size-lg);
} }
& ul {
padding-left: 1.5rem;
line-height: var(--line-height-base);
margin-bottom: 1.5rem;
margin-top: 0;
& li {
font-size: var(--font-size-lg);
line-height: var(--line-height-base);
margin-bottom: 0.5rem;
padding-left: 0.25rem;
}
}
q { q {
font-style: italic; font-style: italic;
quotes: "«" "»"; quotes: "«" "»";
@ -187,7 +217,8 @@ body {
h2, h2,
h3, h3,
h4 { h4 {
margin: 3rem 0 1rem 0; margin-top: 3rem;
margin-bottom: 1rem;
padding-bottom: 0.35rem; padding-bottom: 0.35rem;
} }
@ -199,14 +230,25 @@ body {
} }
& h2 { & h2 {
font-size: var(--font-size-3xl);
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
& h3 {
font-size: var(--font-size-2xl);
}
& a { & a {
font-weight: 600; font-weight: 600;
} }
} }
li::marker {
color: var(--color-blue-500);
font-size: 1.3rem;
line-height: var(--line-height-none);
}
a { a {
color: var(--color-blue-500); color: var(--color-blue-500);
font-weight: 500; font-weight: 500;

View File

@ -1,16 +1,16 @@
import { IArticle } from '@root/interfaces'; import type { IArticle } from '@root/interfaces';
import { MarkdownInstance } from 'astro'; import { MarkdownInstance } from 'astro';
export const transformArticles = ( export const transformArticles = (
articles: MarkdownInstance<IArticle>[] articles: MarkdownInstance<IArticle>[]
): IArticle[] => { ): IArticle[] => articles.map((article) => ({
return articles.map((article) => ({
title: article.frontmatter.title, title: article.frontmatter.title,
description: article.frontmatter.description, description: article.frontmatter.description,
author: article.frontmatter.author,
tags: article.frontmatter.tags, tags: article.frontmatter.tags,
published_at: article.frontmatter.published_at, published_at: article.frontmatter.published_at,
})); }))
}; ;
export const sortArtcilesByDate = (articles: IArticle[]): IArticle[] => { export const sortArtcilesByDate = (articles: IArticle[]): IArticle[] => {
return articles.sort( return articles.sort(

View File

@ -8,6 +8,7 @@
"types": ["vite/client"], "types": ["vite/client"],
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"jsx": "preserve",
"paths": { "paths": {
"@root/*": ["./src/*"], "@root/*": ["./src/*"],
"@styles/*": ["./src/styles/*"], "@styles/*": ["./src/styles/*"],