Compare commits

..

3 commits

11 changed files with 186 additions and 81 deletions

View file

@ -1,8 +1,11 @@
--- ---
import ArticleMenu from './ArticleMenu.astro';
import { AstroComponentFactory } from 'astro/dist/runtime/server'; import { AstroComponentFactory } from 'astro/dist/runtime/server';
export interface Props { export interface Props {
PostContent: AstroComponentFactory; PostContent: AstroComponentFactory;
slug: string;
title: string; title: string;
description: string; description: string;
readingTime: number; readingTime: number;
@ -12,8 +15,9 @@ export interface Props {
} }
const { const {
PostContent, title, description, PostContent, slug,
readingTime, date, image, title, description,
readingTime, date,
preview = false, preview = false,
} = Astro.props; } = Astro.props;
@ -32,13 +36,28 @@ const locale = 'ru';
{readingTime.toFixed(1)} min read {readingTime.toFixed(1)} min read
</span> </span>
</address> </address>
{
!preview ?
<ArticleMenu slug={slug} title={title} /> :
""
}
</header> </header>
{ {
!preview ? !preview ?
<article> <article>
<PostContent /> <PostContent />
</article> : </article> :
<div> <div class="description">
{description} {description}
</div> </div>
} }
<style lang="less">
address {
margin-top: 0.25rem;
}
.description {
margin-top: 0.25rem;
}
</style>

View file

@ -1,7 +1,6 @@
--- ---
import Article from './Article.astro'; import Article from './Article.astro';
import SimpleMenu from '../layouts/SimpleMenu.astro'; import ArticleMenu from './ArticleMenu.astro';
import MenuItem from './MenuItem.astro';
import postRenderer from '../post-renderer.mjs'; import postRenderer from '../post-renderer.mjs';
import { postType } from '../post-renderer.mjs'; import { postType } from '../post-renderer.mjs';
@ -15,7 +14,6 @@ const {
PostContent, title, description, PostContent, title, description,
readingTime, date, image, readingTime, date, image,
} = await postRenderer(post); } = await postRenderer(post);
const link = `/blog/${post.slug}`;
--- ---
<div class="card card-elevated" id={post.slug}> <div class="card card-elevated" id={post.slug}>
@ -28,41 +26,7 @@ const link = `/blog/${post.slug}`;
image={image} image={image}
preview={true} preview={true}
/> />
<SimpleMenu jcc="end"> <ArticleMenu slug={post.slug} title={title} isCard />
<MenuItem
name={/*Comments*/""}
link={`/blog/comments#${post.slug}`}
icon="&#xf075;"
atLeft={false}
/>
<MenuItem
name={/*Copy Link*/""}
link="javascript:void(0)"
icon="&#xf0c5;"
atLeft={false}>
<span slot="js-dataset"
data-btn="copylink"
data-url={link}>
</span>
</MenuItem>
<MenuItem
name={/*Share*/""}
link="javascript:void(0)"
icon="&#xf1e0;"
atLeft={false}>
<span slot="js-dataset"
data-btn="share"
data-title={title}
data-url={link}>
</span>
</MenuItem>
<MenuItem
name="Read"
link={link}
icon="&#xf105;"
atLeft={false}
/>
</SimpleMenu>
</div> </div>
<style> <style>

View file

@ -0,0 +1,78 @@
---
import SimpleMenu from '../layouts/SimpleMenu.astro';
import MenuItem from './MenuItem.astro';
export interface Props {
slug: string;
title: string;
isCard?: boolean;
}
const { slug, title, isCard = false } = Astro.props;
const link = `/blog/${slug}`;
---
<SimpleMenu jc={isCard ? "end" : "start"} largeGap={!isCard}>
<MenuItem
name="Comments"
link={`${link}#comments`}
icon="&#xf075;"
iconAfter={isCard}
hideLabel={isCard}
/>
<MenuItem
name="Copy link"
link="javascript:void(0)"
icon="&#xf0c5;"
classes={["btn-copy"]}
dataset={{"data-url": link}}
iconAfter={isCard}
hideLabel={isCard}
/>
<MenuItem
name="Share"
link="javascript:void(0)"
icon="&#xf1e0;"
classes={["btn-share"]}
dataset={{"data-url": link, "data-title": title}}
iconAfter={isCard}
hideLabel={isCard}
/>
{
isCard ?
<MenuItem
name="Read"
link={link}
icon="&#xf105;"
iconAfter={true}
/> :
""
}
</SimpleMenu>
<script>
const handlerCopy = (ev: Event) => {
const elem = ev.currentTarget as HTMLAnchorElement
navigator.clipboard.writeText(
location.origin + elem.dataset.url
)
}
const handlerShare = (ev: Event) => {
const elem = ev.currentTarget as HTMLAnchorElement
navigator.share({
title: elem.dataset.title,
url: elem.dataset.url,
})
}
const btnsCopy = document.querySelectorAll('.btn-copy')
for (let btn of btnsCopy) {
btn.addEventListener('click', handlerCopy)
}
const btnsShare = document.querySelectorAll('.btn-share')
for (let btn of btnsShare) {
btn.addEventListener('click', handlerShare)
}
</script>

View file

@ -1,5 +1,4 @@
--- ---
import SimpleMenu from '../layouts/SimpleMenu.astro';
import Icon from './Icon.astro'; import Icon from './Icon.astro';
export interface Props { export interface Props {

View file

@ -6,51 +6,89 @@ export interface Props {
link: string; link: string;
icon: string; icon: string;
tblank?: boolean; tblank?: boolean;
atLeft?: boolean; iconAfter?: boolean;
hideLabel?: boolean;
classes?: Array<string>; classes?: Array<string>;
datajs?: string; dataset?: Object;
} }
const { const {
name, link, icon, name, link, icon,
tblank = false, tblank = false,
atLeft = true, iconAfter = false,
hideLabel = false,
classes = [], classes = [],
datajs = "", dataset = {},
} = Astro.props; } = Astro.props;
--- ---
<li> <li class:list={{"icon-after": iconAfter, "hide-label": hideLabel}}>
<slot name="js-dataset"></slot> <a href={link} target={tblank ? "_blank" : "_self"} class:list={classes} {...dataset}>
<a href={link} target={tblank ? "_blank" : "_self"} class:list={classes} data-js={datajs}>
<span class="icon-wrapper"> <span class="icon-wrapper">
<Icon code={icon} /> <Icon code={icon} />
</span> </span>
{name} <span class="name">{name}</span>
</a> </a>
</li> </li>
<style lang="less" define:vars={{fxd: atLeft ? "row" : "row-reverse"}}> <style lang="less">
a { @icon-size: 1.5rem;
display: flex;
flex-direction: var(--fxd);
align-items: center;
font-size: 1.15rem; li {
a {
display: flex;
flex-direction: row;
align-items: center;
column-gap: 0.125rem;
font-size: 1.15rem;
}
&:hover {
.icon-wrapper {
color: var(--fg);
}
}
}
li.icon-after {
a {
flex-direction: row-reverse;
}
}
li.hide-label {
a {
flex-direction: column;
align-items: center;
}
.name {
display: none;
}
position: relative;
&:hover {
.name {
display: block;
width: max-content;
padding: 0.2rem;
position: absolute;
bottom: @icon-size + 0.25rem;
z-index: 10;
font-size: 0.9rem;
color: #eee;
background: rgba(0, 0, 0, .7);
border-radius: 0.2rem;
}
}
} }
.icon-wrapper { .icon-wrapper {
margin-right: 0.2rem; width: @icon-size;
width: 1.5rem; font-size: @icon-size;
font-size: 1.5rem;
color: var(--fg-sec); color: var(--fg-sec);
} }
li:hover {
.icon-wrapper {
color: var(--fg);
}
}
</style> </style>

View file

@ -6,19 +6,18 @@ import MenuItem from "../components/MenuItem.astro";
export interface Props { export interface Props {
title: string; title: string;
description: string; description: string;
article?: boolean; mainpage?: boolean;
} }
const { title, description, article = false } = Astro.props; const { title, description, mainpage = false } = Astro.props;
--- ---
<Layout title={"Blog | " + title} description={description}> <Layout title={"Blog | " + title} description={description}>
<slot name="metadata" slot="metadata" /> <slot name="metadata" slot="metadata" />
<NavMenu> <NavMenu>
{ {
!article ? mainpage ?
<MenuItem name="Home" icon="&#xf104;" link="/" /> <MenuItem name="Home" icon="&#xf104;" link="/" /> :
<MenuItem name="Articles" icon="&#xf1ea;" link="/blog" /> :
<MenuItem name="Articles" icon="&#xf104;" link="/blog" /> <MenuItem name="Articles" icon="&#xf104;" link="/blog" />
} }
<MenuItem name="Shorts" icon="&#xf0e7;" link="/blog/shorts" /> <MenuItem name="Shorts" icon="&#xf0e7;" link="/blog/shorts" />

View file

@ -52,7 +52,6 @@ const { title, description } = Astro.props;
margin: auto; margin: auto;
padding: @main-padding; padding: @main-padding;
max-width: @max-width; max-width: @max-width;
width: 100%;
} }
article { article {

View file

@ -59,6 +59,7 @@ const { id } = Astro.props;
border-radius: var(--bdrs); border-radius: var(--bdrs);
background: var(--bg); background: var(--bg);
box-shadow: 0 0 1rem #161616;
} }
.controls { .controls {

View file

@ -1,16 +1,17 @@
--- ---
export interface Props { export interface Props {
jcc: "start" | "center" | "end" | "space-around" | "space-between"; jc: "start" | "center" | "end" | "space-around" | "space-between";
largeGap?: boolean;
} }
const { jcc } = Astro.props; const { jc, largeGap = false } = Astro.props;
--- ---
<ul> <ul style={{columnGap: largeGap ? "0.5rem" : "0.125rem"}}>
<slot /> <slot />
</ul> </ul>
<style lang="less" define:vars={{jcc: jcc}}> <style lang="less" define:vars={{jc: jc}}>
ul { ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
@ -18,6 +19,6 @@ const { jcc } = Astro.props;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: var(--jcc); justify-content: var(--jc);
} }
</style> </style>

View file

@ -3,7 +3,9 @@ import BlogLayout from "../../layouts/BlogLayout.astro";
import Article from "../../components/Article.astro"; import Article from "../../components/Article.astro";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import postRenderer from "../../post-renderer.mjs"; import postRenderer from "../../post-renderer.mjs";
import { postType } from "../../post-renderer.mjs";
export async function getStaticPaths() { export async function getStaticPaths() {
const posts = await getCollection("blog"); const posts = await getCollection("blog");
@ -15,14 +17,14 @@ export async function getStaticPaths() {
})); }));
} }
const { post } = Astro.props; const post: postType = Astro.props.post;
const { const {
PostContent, title, description, PostContent, title, description,
readingTime, date, image, readingTime, date, image,
} = await postRenderer(post); } = await postRenderer(post);
--- ---
<BlogLayout title={title} description={description} article={true}> <BlogLayout title={title} description={description}>
<Fragment slot="metadata"> <Fragment slot="metadata">
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
@ -37,6 +39,7 @@ const {
</Fragment> </Fragment>
<Article <Article
PostContent={PostContent} PostContent={PostContent}
slug={post.slug}
title={title} title={title}
description={description} description={description}
readingTime={readingTime} readingTime={readingTime}
@ -48,6 +51,10 @@ const {
<style lang="less" is:global> <style lang="less" is:global>
@import "/src/styles/max_width.less"; @import "/src/styles/max_width.less";
main {
width: 100%;
}
article { article {
margin: 0; margin: 0;

View file

@ -28,7 +28,7 @@ const description =
"The simpliest things!"; "The simpliest things!";
--- ---
<BlogLayout title="Homepage" description={description}> <BlogLayout title="Homepage" description={description} mainpage>
<Fragment slot="metadata"> <Fragment slot="metadata">
<meta name="robots" content="noindex, follow" /> <meta name="robots" content="noindex, follow" />
</Fragment> </Fragment>