Skip to content

Commit a226ea6

Browse files
authored
feat(blog-list): add BlogList BlogBackground BlogBackButton components as lynx-website (#74)
1 parent 27bc35f commit a226ea6

15 files changed

Lines changed: 1511 additions & 10 deletions

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@
5353
"./blog-avatar": {
5454
"types": "./dist/blog-avatar/index.d.ts",
5555
"import": "./dist/blog-avatar/index.js"
56+
},
57+
"./blog-back-button": {
58+
"types": "./dist/blog-back-button/index.d.ts",
59+
"import": "./dist/blog-back-button/index.js"
60+
},
61+
"./blog-list": {
62+
"types": "./dist/blog-list/index.d.ts",
63+
"import": "./dist/blog-list/index.js"
64+
},
65+
"./blog-background": {
66+
"types": "./dist/blog-background/index.d.ts",
67+
"import": "./dist/blog-background/index.js"
5668
}
5769
},
5870
"repository": {

rslib.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export default defineConfig({
2626
'nav-icon': './src/nav-icon/index.tsx',
2727
benchmark: './src/benchmark/index.tsx',
2828
'blog-avatar': './src/blog-avatar/index.tsx',
29+
'blog-back-button': './src/blog-back-button/index.tsx',
30+
'blog-list': './src/blog-list/index.tsx',
31+
'blog-background': './src/blog-background/index.tsx',
2932
'tool-stack': './src/tool-stack/index.tsx',
3033
hero: './src/hero/index.tsx',
3134
'section-style': './src/section-style/index.tsx',
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.blogBackButton {
2+
margin-bottom: 1rem;
3+
color: var(--rp-c-text-2);
4+
transition: color 0.2s ease-out;
5+
6+
.link {
7+
font-size: 14px;
8+
text-decoration: none;
9+
}
10+
11+
&::before {
12+
content: '';
13+
margin-right: 0.5rem;
14+
}
15+
16+
&:hover,
17+
&:focus-visible {
18+
color: var(--rp-c-brand);
19+
}
20+
}

src/blog-back-button/index.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { ALink, type LinkComp } from '../shared';
2+
import styles from './index.module.scss';
3+
4+
export type BlogBackButtonProps = {
5+
pathname: string;
6+
lang: string;
7+
blogPrefix?: string;
8+
className?: string;
9+
LinkComp?: LinkComp;
10+
};
11+
12+
const getClassName = (...classNames: Array<string | undefined>) => {
13+
return classNames.filter(Boolean).join(' ');
14+
};
15+
16+
const getBlogPrefix = (lang: string, blogPrefix = '/blog') => {
17+
if (lang === 'en') {
18+
return blogPrefix;
19+
}
20+
21+
const localizedPrefix = `/${lang}`;
22+
23+
if (
24+
blogPrefix === localizedPrefix ||
25+
blogPrefix.startsWith(`${localizedPrefix}/`)
26+
) {
27+
return blogPrefix;
28+
}
29+
30+
return `${localizedPrefix}${blogPrefix}`;
31+
};
32+
33+
const getLabel = (lang?: string) => {
34+
return lang === 'zh' ? '返回博客' : 'Back to blog';
35+
};
36+
37+
const trimTrailingSlashes = (value: string) => {
38+
let end = value.length;
39+
40+
while (end > 1 && value.charCodeAt(end - 1) === 47) {
41+
end -= 1;
42+
}
43+
44+
return value.slice(0, end) || '/';
45+
};
46+
47+
export function BlogBackButton({
48+
pathname,
49+
lang,
50+
blogPrefix,
51+
className,
52+
LinkComp,
53+
}: BlogBackButtonProps) {
54+
const resolvedBlogPrefix = getBlogPrefix(lang, blogPrefix);
55+
const normalizedPathname = trimTrailingSlashes(pathname);
56+
const blogIndexPath = `${resolvedBlogPrefix}/`;
57+
const isBlogSubpage = normalizedPathname.startsWith(`${resolvedBlogPrefix}/`);
58+
59+
if (!isBlogSubpage) {
60+
return null;
61+
}
62+
63+
const Link = LinkComp ?? ALink;
64+
65+
return (
66+
<div className={getClassName(styles.blogBackButton, className)}>
67+
<Link href={blogIndexPath} className={styles.link}>
68+
{getLabel(lang)}
69+
</Link>
70+
</div>
71+
);
72+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
:global {
2+
html:not(.dark) {
3+
--rs-blog-list-frame-bg:
4+
linear-gradient(180deg, rgba(15, 23, 42, 0.02), transparent 72%),
5+
linear-gradient(90deg, rgba(15, 23, 42, 0.025) 1px, transparent 1px),
6+
linear-gradient(rgba(15, 23, 42, 0.025) 1px, transparent 1px);
7+
}
8+
9+
html.dark {
10+
--rs-blog-list-frame-bg:
11+
linear-gradient(180deg, rgba(148, 163, 184, 0.04), transparent 72%),
12+
linear-gradient(90deg, rgba(148, 163, 184, 0.05) 1px, transparent 1px),
13+
linear-gradient(rgba(148, 163, 184, 0.05) 1px, transparent 1px);
14+
}
15+
}
16+
17+
.blogBackground {
18+
position: absolute;
19+
inset: 0;
20+
pointer-events: none;
21+
z-index: -1;
22+
}
23+
24+
.blogFrame {
25+
position: absolute;
26+
inset: 0;
27+
background: var(--rs-blog-list-frame-bg);
28+
background-size: 1200px;
29+
opacity: 0.45;
30+
}
31+
32+
:global(.dark) .blogFrame {
33+
opacity: 0.35;
34+
}

src/blog-background/index.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { MeteorsBackground } from '../blog-list/MeteorsBackground';
2+
import styles from './index.module.scss';
3+
4+
export type BlogBackgroundProps = {
5+
showBackground?: boolean;
6+
backgroundGridSize?: number;
7+
backgroundMeteorCount?: number;
8+
};
9+
10+
export function BlogBackground({
11+
showBackground = true,
12+
backgroundGridSize = 120,
13+
backgroundMeteorCount = 3,
14+
}: BlogBackgroundProps) {
15+
if (!showBackground) {
16+
return null;
17+
}
18+
19+
return (
20+
<div className={styles.blogBackground}>
21+
<div className={styles.blogFrame} />
22+
<MeteorsBackground
23+
gridSize={backgroundGridSize}
24+
meteorCount={backgroundMeteorCount}
25+
/>
26+
</div>
27+
);
28+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.frame {
2+
position: absolute;
3+
inset: 0;
4+
pointer-events: none;
5+
}
6+
7+
.canvas {
8+
width: 100%;
9+
height: 100%;
10+
pointer-events: none;
11+
}

0 commit comments

Comments
 (0)