feat!: add file to src

This commit is contained in:
kaivanwong 2024-05-11 17:20:49 +08:00
parent aa011faa54
commit 90eaaa8ae4
24 changed files with 471 additions and 0 deletions

View 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>

View file

@ -0,0 +1,7 @@
---
title: Note Name
duration: 5min
date: 2022-12-01
---
Writing...

View file

@ -0,0 +1,7 @@
---
title: Note Name
duration: 5min
date: 2018-01-01
---
Writing...

View file

@ -0,0 +1,7 @@
---
title: Note Name
duration: 5min
date: 2022-02-01
---
Writing...

View file

@ -0,0 +1,7 @@
---
title: Note Name
duration: 5min
date: 2024-03-01
---
Writing...

View 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...

View 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...

View 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...

View 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: '/'
---

View 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
---

View 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
---

View 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
---

View file

@ -0,0 +1,5 @@
---
title: Blog Name
description: The date and title fields are required.
date: 2022-11-01
---

View file

@ -0,0 +1,6 @@
---
title: Sponsor
description: How to sponsor for me.
---
Writing...

View file

@ -0,0 +1,6 @@
---
title: Sponsor
description: How to sponsor for me.
---
Writing...

View 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>

View 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>

View 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: '/',
},
],
},
]

View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
export function getLinkTarget(link: string) {
return link.includes('http') ? '_blank' : '_self'
}