Refactoring: article menu
This commit is contained in:
parent
d148f1e0f3
commit
f6cc226e03
7 changed files with 175 additions and 73 deletions
|
@ -1,8 +1,11 @@
|
|||
---
|
||||
import ArticleMenu from './ArticleMenu.astro';
|
||||
|
||||
import { AstroComponentFactory } from 'astro/dist/runtime/server';
|
||||
|
||||
export interface Props {
|
||||
PostContent: AstroComponentFactory;
|
||||
slug: string;
|
||||
title: string;
|
||||
description: string;
|
||||
readingTime: number;
|
||||
|
@ -12,8 +15,9 @@ export interface Props {
|
|||
}
|
||||
|
||||
const {
|
||||
PostContent, title, description,
|
||||
readingTime, date, image,
|
||||
PostContent, slug,
|
||||
title, description,
|
||||
readingTime, date,
|
||||
preview = false,
|
||||
} = Astro.props;
|
||||
|
||||
|
@ -32,13 +36,28 @@ const locale = 'ru';
|
|||
{readingTime.toFixed(1)} min read
|
||||
</span>
|
||||
</address>
|
||||
{
|
||||
!preview ?
|
||||
<ArticleMenu slug={slug} title={title} /> :
|
||||
""
|
||||
}
|
||||
</header>
|
||||
{
|
||||
!preview ?
|
||||
<article>
|
||||
<PostContent />
|
||||
</article> :
|
||||
<div>
|
||||
<div class="description">
|
||||
{description}
|
||||
</div>
|
||||
}
|
||||
|
||||
<style lang="less">
|
||||
address {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
import Article from './Article.astro';
|
||||
import SimpleMenu from '../layouts/SimpleMenu.astro';
|
||||
import MenuItem from './MenuItem.astro';
|
||||
import ArticleMenu from './ArticleMenu.astro';
|
||||
|
||||
import postRenderer from '../post-renderer.mjs';
|
||||
import { postType } from '../post-renderer.mjs';
|
||||
|
@ -15,7 +14,6 @@ const {
|
|||
PostContent, title, description,
|
||||
readingTime, date, image,
|
||||
} = await postRenderer(post);
|
||||
const link = `/blog/${post.slug}`;
|
||||
---
|
||||
|
||||
<div class="card card-elevated" id={post.slug}>
|
||||
|
@ -28,41 +26,7 @@ const link = `/blog/${post.slug}`;
|
|||
image={image}
|
||||
preview={true}
|
||||
/>
|
||||
<SimpleMenu jcc="end">
|
||||
<MenuItem
|
||||
name={/*Comments*/""}
|
||||
link={`/blog/comments#${post.slug}`}
|
||||
icon=""
|
||||
atLeft={false}
|
||||
/>
|
||||
<MenuItem
|
||||
name={/*Copy Link*/""}
|
||||
link="javascript:void(0)"
|
||||
icon=""
|
||||
atLeft={false}>
|
||||
<span slot="js-dataset"
|
||||
data-btn="copylink"
|
||||
data-url={link}>
|
||||
</span>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
name={/*Share*/""}
|
||||
link="javascript:void(0)"
|
||||
icon=""
|
||||
atLeft={false}>
|
||||
<span slot="js-dataset"
|
||||
data-btn="share"
|
||||
data-title={title}
|
||||
data-url={link}>
|
||||
</span>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
name="Read"
|
||||
link={link}
|
||||
icon=""
|
||||
atLeft={false}
|
||||
/>
|
||||
</SimpleMenu>
|
||||
<ArticleMenu slug={post.slug} title={title} isCard />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
78
src/components/ArticleMenu.astro
Normal file
78
src/components/ArticleMenu.astro
Normal 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=""
|
||||
iconAfter={isCard}
|
||||
hideLabel={isCard}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Copy link"
|
||||
link="javascript:void(0)"
|
||||
icon=""
|
||||
classes={["btn-copy"]}
|
||||
dataset={{"data-url": link}}
|
||||
iconAfter={isCard}
|
||||
hideLabel={isCard}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Share"
|
||||
link="javascript:void(0)"
|
||||
icon=""
|
||||
classes={["btn-share"]}
|
||||
dataset={{"data-url": link, "data-title": title}}
|
||||
iconAfter={isCard}
|
||||
hideLabel={isCard}
|
||||
/>
|
||||
{
|
||||
isCard ?
|
||||
<MenuItem
|
||||
name="Read"
|
||||
link={link}
|
||||
icon=""
|
||||
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>
|
|
@ -1,5 +1,4 @@
|
|||
---
|
||||
import SimpleMenu from '../layouts/SimpleMenu.astro';
|
||||
import Icon from './Icon.astro';
|
||||
|
||||
export interface Props {
|
||||
|
|
|
@ -6,51 +6,89 @@ export interface Props {
|
|||
link: string;
|
||||
icon: string;
|
||||
tblank?: boolean;
|
||||
atLeft?: boolean;
|
||||
iconAfter?: boolean;
|
||||
hideLabel?: boolean;
|
||||
classes?: Array<string>;
|
||||
datajs?: string;
|
||||
dataset?: Object;
|
||||
}
|
||||
|
||||
const {
|
||||
name, link, icon,
|
||||
tblank = false,
|
||||
atLeft = true,
|
||||
iconAfter = false,
|
||||
hideLabel = false,
|
||||
classes = [],
|
||||
datajs = "",
|
||||
dataset = {},
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<li>
|
||||
<slot name="js-dataset"></slot>
|
||||
<a href={link} target={tblank ? "_blank" : "_self"} class:list={classes} data-js={datajs}>
|
||||
<li class:list={{"icon-after": iconAfter, "hide-label": hideLabel}}>
|
||||
<a href={link} target={tblank ? "_blank" : "_self"} class:list={classes} {...dataset}>
|
||||
<span class="icon-wrapper">
|
||||
<Icon code={icon} />
|
||||
</span>
|
||||
{name}
|
||||
<span class="name">{name}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<style lang="less" define:vars={{fxd: atLeft ? "row" : "row-reverse"}}>
|
||||
a {
|
||||
display: flex;
|
||||
flex-direction: var(--fxd);
|
||||
align-items: center;
|
||||
<style lang="less">
|
||||
@icon-size: 1.5rem;
|
||||
|
||||
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 {
|
||||
margin-right: 0.2rem;
|
||||
width: 1.5rem;
|
||||
|
||||
font-size: 1.5rem;
|
||||
width: @icon-size;
|
||||
font-size: @icon-size;
|
||||
color: var(--fg-sec);
|
||||
}
|
||||
|
||||
li:hover {
|
||||
.icon-wrapper {
|
||||
color: var(--fg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
---
|
||||
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 />
|
||||
</ul>
|
||||
|
||||
<style lang="less" define:vars={{jcc: jcc}}>
|
||||
<style lang="less" define:vars={{jc: jc}}>
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
|
@ -18,6 +19,6 @@ const { jcc } = Astro.props;
|
|||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: var(--jcc);
|
||||
justify-content: var(--jc);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,7 +3,9 @@ import BlogLayout from "../../layouts/BlogLayout.astro";
|
|||
import Article from "../../components/Article.astro";
|
||||
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
import postRenderer from "../../post-renderer.mjs";
|
||||
import { postType } from "../../post-renderer.mjs";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("blog");
|
||||
|
@ -15,7 +17,7 @@ export async function getStaticPaths() {
|
|||
}));
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const post: postType = Astro.props.post;
|
||||
const {
|
||||
PostContent, title, description,
|
||||
readingTime, date, image,
|
||||
|
@ -37,6 +39,7 @@ const {
|
|||
</Fragment>
|
||||
<Article
|
||||
PostContent={PostContent}
|
||||
slug={post.slug}
|
||||
title={title}
|
||||
description={description}
|
||||
readingTime={readingTime}
|
||||
|
|
Loading…
Add table
Reference in a new issue