feat!: add file to src
This commit is contained in:
parent
aa011faa54
commit
90eaaa8ae4
24 changed files with 471 additions and 0 deletions
24
src/components/ScrollToTop.vue
Normal file
24
src/components/ScrollToTop.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts" setup>
|
||||
import { useWindowScroll } from '@vueuse/core'
|
||||
|
||||
const { y: scroll } = useWindowScroll()
|
||||
|
||||
function toTop() {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
aria-label="Scroll to top"
|
||||
fixed right-5 sm:right-30 bottom-30 w-12 h-12 text-lg hover:op100 rounded-full flex="~ items-center justify-center"
|
||||
bg-hex-8883 transition duration-300 z-100 print:hidden
|
||||
:class="scroll > 300 ? 'op75' : 'op0 pointer-events-none'"
|
||||
@click="toTop()"
|
||||
>
|
||||
<i i-ri-arrow-up-line />
|
||||
</button>
|
||||
</template>
|
7
src/content/blog/note/post-1.md
Normal file
7
src/content/blog/note/post-1.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Note Name
|
||||
duration: 5min
|
||||
date: 2022-12-01
|
||||
---
|
||||
|
||||
Writing...
|
7
src/content/blog/note/post-2.md
Normal file
7
src/content/blog/note/post-2.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Note Name
|
||||
duration: 5min
|
||||
date: 2018-01-01
|
||||
---
|
||||
|
||||
Writing...
|
7
src/content/blog/note/post-3.md
Normal file
7
src/content/blog/note/post-3.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Note Name
|
||||
duration: 5min
|
||||
date: 2022-02-01
|
||||
---
|
||||
|
||||
Writing...
|
7
src/content/blog/note/post-4.md
Normal file
7
src/content/blog/note/post-4.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Note Name
|
||||
duration: 5min
|
||||
date: 2024-03-01
|
||||
---
|
||||
|
||||
Writing...
|
7
src/content/blog/post-1.md
Normal file
7
src/content/blog/post-1.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: Your blog description, which is long text, can be an introduction to the post or a paragraph of the post.
|
||||
date: 2024-05-01
|
||||
---
|
||||
|
||||
Writing...
|
8
src/content/blog/post-2.md
Normal file
8
src/content/blog/post-2.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: If you set the lang field to include zh, it will display an identifier.
|
||||
date: 2024-04-01
|
||||
lang: zh
|
||||
---
|
||||
|
||||
Writing...
|
8
src/content/blog/post-3.md
Normal file
8
src/content/blog/post-3.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: A tag field is provided, which can be used to display custom information.
|
||||
date: 2024-03-01
|
||||
tag: Tag Text
|
||||
---
|
||||
|
||||
Writing...
|
6
src/content/blog/post-4.md
Normal file
6
src/content/blog/post-4.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: If you need to link to an external address, you can set the redirect field.
|
||||
date: 2024-02-01
|
||||
redirect: '/'
|
||||
---
|
6
src/content/blog/post-5.md
Normal file
6
src/content/blog/post-5.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: If you want to tell the visitor that there is a video, you can set the video field to true.
|
||||
date: 2024-02-01
|
||||
video: true
|
||||
---
|
5
src/content/blog/post-6.md
Normal file
5
src/content/blog/post-6.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: Vitesse theme groups posts by year and displays them sorted by date.
|
||||
date: 2023-08-01
|
||||
---
|
6
src/content/blog/post-7.md
Normal file
6
src/content/blog/post-7.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: You can set a duration to tell the viewer how long it will take to watch it。
|
||||
duration: 20min
|
||||
date: 2023-05-01
|
||||
---
|
5
src/content/blog/post-8.md
Normal file
5
src/content/blog/post-8.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Blog Name
|
||||
description: The date and title fields are required.
|
||||
date: 2022-11-01
|
||||
---
|
6
src/content/pages/page-1.md
Normal file
6
src/content/pages/page-1.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Sponsor
|
||||
description: How to sponsor for me.
|
||||
---
|
||||
|
||||
Writing...
|
6
src/content/pages/page-2.md
Normal file
6
src/content/pages/page-2.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Sponsor
|
||||
description: How to sponsor for me.
|
||||
---
|
||||
|
||||
Writing...
|
49
src/pages/blog/[...path].astro
Normal file
49
src/pages/blog/[...path].astro
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
import BaseLayout from '@/layouts/BaseLayout.astro'
|
||||
import ListPosts from '@/components/ListPosts.vue'
|
||||
import { getPosts } from '@/utils/posts'
|
||||
import siteConfig from '@/site-config'
|
||||
import { uniqBy } from 'lodash-es'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const blogEntries = await getPosts()
|
||||
return uniqBy(
|
||||
blogEntries.map((entry) => {
|
||||
return {
|
||||
params: {
|
||||
path: entry.slug.includes('/')
|
||||
? entry.slug.split('/').shift()
|
||||
: undefined,
|
||||
},
|
||||
}
|
||||
}),
|
||||
'params.path',
|
||||
)
|
||||
}
|
||||
|
||||
const { path } = Astro.params
|
||||
|
||||
const posts = await getPosts(path)
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="Blog"
|
||||
description="List of all the blog posts."
|
||||
pageNav={true}
|
||||
pageOperate={true}
|
||||
>
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:gap-4 flex-wrap mb-8">
|
||||
{
|
||||
siteConfig.page.navLinks.map((nav) => (
|
||||
<a
|
||||
aria-label={nav.text}
|
||||
class={`nav-link text-3xl font-bold ${Astro.url.pathname === nav.href ? 'opacity-80' : 'opacity-30 hover:opacity-50'}`}
|
||||
href={nav.href}
|
||||
>
|
||||
{nav.text}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<ListPosts list={posts} />
|
||||
</BaseLayout>
|
61
src/pages/posts/[...slug].astro
Normal file
61
src/pages/posts/[...slug].astro
Normal file
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import BaseLayout from '@/layouts/BaseLayout.astro'
|
||||
import { type CollectionPosts } from '@/types'
|
||||
import { getPosts } from '@/utils/posts'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getPosts()
|
||||
return posts.map((post) => {
|
||||
return {
|
||||
params: { slug: post.slug },
|
||||
props: {
|
||||
post,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type Props = { post: CollectionPosts }
|
||||
|
||||
const { post } = Astro.props
|
||||
const { title, image, description, date, duration, tag } = post.data
|
||||
|
||||
const { Content } = await post.render()
|
||||
|
||||
function getDate(date: string) {
|
||||
return new Date(date).toISOString()
|
||||
}
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={title}
|
||||
description={description}
|
||||
pageType="article"
|
||||
pageOperate={true}
|
||||
>
|
||||
<article class="mb-16 max-w-none prose">
|
||||
<h1 class="text-title">
|
||||
{title}
|
||||
</h1>
|
||||
<p op-50>
|
||||
{date && <time datetime={getDate(date)}>{date.split(',')}</time>}
|
||||
{duration && <span>· {duration}</span>}
|
||||
{tag && <span>· {tag}</span>}
|
||||
</p>
|
||||
{
|
||||
image && (
|
||||
<p>
|
||||
<img
|
||||
width="100%"
|
||||
height="auto"
|
||||
src={image.src}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
alt={image.alt || ''}
|
||||
/>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
<Content />
|
||||
</article>
|
||||
</BaseLayout>
|
88
src/pages/projects/data.ts
Normal file
88
src/pages/projects/data.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import type { ProjectData } from '@/types'
|
||||
|
||||
export const projectData: ProjectData = [
|
||||
{
|
||||
title: 'Projects Group',
|
||||
projects: [
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Projects Group',
|
||||
projects: [
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Project Name',
|
||||
projects: [],
|
||||
},
|
||||
{
|
||||
title: 'Projects Group',
|
||||
projects: [
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Projects Group',
|
||||
projects: [
|
||||
{
|
||||
text: 'Project Name',
|
||||
description: 'Your project description information is a long piece of text.',
|
||||
icon: 'i-carbon-campsite',
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
31
src/pages/projects/index.astro
Normal file
31
src/pages/projects/index.astro
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
import { projectData } from './data'
|
||||
import BaseLayout from '@/layouts/BaseLayout.astro'
|
||||
import ListProjects from '@/components/ListProjects.vue'
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="Projects"
|
||||
description="List of projects that I am proud of"
|
||||
pageOperate={true}
|
||||
>
|
||||
<h1 class="mb-10 text-title">Projects</h1>
|
||||
<div mb-16 sm:mb-24>
|
||||
{
|
||||
projectData.length > 0 && (
|
||||
<div>
|
||||
{projectData.map((i) => (
|
||||
<div mb-10>
|
||||
<h2 class="select-none relative h20 pointer-events-none">
|
||||
<span class="text-3.2em color-transparent font-bold text-stroke-1.5 text-stroke-hex-aaa op35 dark:op20 absolute top-0">
|
||||
{i.title}
|
||||
</span>
|
||||
</h2>
|
||||
<ListProjects list={i.projects} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</BaseLayout>
|
15
src/pages/robots.txt.ts
Normal file
15
src/pages/robots.txt.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
interface Context {
|
||||
site: string
|
||||
}
|
||||
|
||||
export function GET(context: Context) {
|
||||
const robots = `
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: ${new URL('sitemap-index.xml', context.site).href}`.trim()
|
||||
|
||||
return new Response(robots, {
|
||||
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
||||
})
|
||||
}
|
26
src/pages/rss.xml.ts
Normal file
26
src/pages/rss.xml.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import rss from '@astrojs/rss'
|
||||
import siteConfig from '@/site-config'
|
||||
import { getPosts } from '@/utils/posts'
|
||||
|
||||
interface Context {
|
||||
site: string
|
||||
}
|
||||
|
||||
export async function GET(context: Context) {
|
||||
const posts = await getPosts()
|
||||
|
||||
return rss({
|
||||
title: siteConfig.title,
|
||||
description: siteConfig.description,
|
||||
site: context.site,
|
||||
items: posts!.map((item) => {
|
||||
return {
|
||||
...item.data,
|
||||
link: `${context.site}/posts/${item.slug}/`,
|
||||
pubDate: new Date(item.data.date),
|
||||
content: item.body,
|
||||
author: `${siteConfig.author} <${siteConfig.email}>`,
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
24
src/styles/dot.css
Normal file
24
src/styles/dot.css
Normal file
|
@ -0,0 +1,24 @@
|
|||
html.dark {
|
||||
--dot-bg-color: #0d1117;
|
||||
--dot-color: #2f353c;
|
||||
--dot-mask-color: #000000;
|
||||
}
|
||||
|
||||
html:not(.dark) {
|
||||
--dot-bg-color: #ffffff;
|
||||
--dot-color: #a5aeb850;
|
||||
--dot-mask-color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-dot::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
linear-gradient(90deg, var(--dot-bg-color) 22px, transparent 1%) 50%,
|
||||
linear-gradient(var(--dot-bg-color) 22px, transparent 1%) 50%,
|
||||
var(--dot-color);
|
||||
background-position: center center;
|
||||
background-size: 24px 24px;
|
||||
mask-image: linear-gradient(0deg, transparent 5%, var(--dot-mask-color));
|
||||
}
|
59
src/styles/global.css
Normal file
59
src/styles/global.css
Normal file
|
@ -0,0 +1,59 @@
|
|||
html.dark .astro-code,
|
||||
html.dark .astro-code span {
|
||||
color: var(--shiki-dark) !important;
|
||||
background-color: #161b22 !important;
|
||||
font-style: var(--shiki-dark-font-style) !important;
|
||||
font-weight: var(--shiki-dark-font-weight) !important;
|
||||
text-decoration: var(--shiki-dark-text-decoration) !important;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html:not(.dark) {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
#nprogress {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#nprogress .bar {
|
||||
background: #888;
|
||||
opacity: 0.75;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
img {
|
||||
--at-apply: rd-1.5;
|
||||
}
|
||||
|
||||
.prose-link i {
|
||||
--at-apply: text-sm mr-1;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
--at-apply: prose-link;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
--at-apply: text-9 mb-4;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
--at-apply: mt-16 mb-4 text-6;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
--at-apply: mt-10 mb-4 text-5;
|
||||
}
|
||||
|
||||
article {
|
||||
--at-apply: sm: min-h-38 min-h-28;
|
||||
}
|
3
src/utils/link.ts
Normal file
3
src/utils/link.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export function getLinkTarget(link: string) {
|
||||
return link.includes('http') ? '_blank' : '_self'
|
||||
}
|
Loading…
Reference in a new issue