✨ Tags & Categories
This commit is contained in:
		| @@ -24,7 +24,6 @@ | ||||
|     "react-dom": "^18.2.0", | ||||
|     "sass": "^1.70.0", | ||||
|     "tailwindcss": "^3.4.1", | ||||
|     "theme-change": "^2.5.0", | ||||
|     "tinacms": "^1.5.28", | ||||
|     "typescript": "^5.3.3" | ||||
|   }, | ||||
|   | ||||
| @@ -81,12 +81,7 @@ const items: MenuItem[] = [ | ||||
|   </div> | ||||
|   <div class="navbar-end"> | ||||
|     <label class="swap swap-rotate px-[16px]"> | ||||
|       <input | ||||
|         type="checkbox" | ||||
|         class="theme-controller" | ||||
|         value="dark" | ||||
|         data-toggle-theme="dark" | ||||
|       /> | ||||
|       <input type="checkbox" class="theme-controller" value="light" checked /> | ||||
|  | ||||
|       <svg | ||||
|         class="swap-on fill-current w-8 h-8" | ||||
| @@ -108,9 +103,3 @@ const items: MenuItem[] = [ | ||||
|     </label> | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
| <script> | ||||
|   import { themeChange } from "theme-change"; | ||||
|  | ||||
|   themeChange(); | ||||
| </script> | ||||
|   | ||||
							
								
								
									
										45
									
								
								src/components/PostList.astro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/components/PostList.astro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| --- | ||||
| interface Props { | ||||
|   posts: any[]; | ||||
| } | ||||
|  | ||||
| import { POST_TYPES } from "../scripts/consts"; | ||||
|  | ||||
| const { posts } = Astro.props; | ||||
| --- | ||||
|  | ||||
| <div class="grid justify-items-strench gap-6"> | ||||
|   { | ||||
|     posts?.map((item) => ( | ||||
|       <a href={`/posts/${item.slug}`}> | ||||
|         <div class="card sm:card-side hover:bg-base-200 transition-colors sm:max-w-none shadow-xl"> | ||||
|           {item.heroImg && ( | ||||
|             <figure class="mx-auto w-full object-cover p-6 max-sm:pb-0 sm:max-w-[12rem] sm:pe-0"> | ||||
|               <img | ||||
|                 loading="lazy" | ||||
|                 src={item.heroImg} | ||||
|                 class="border-base-content bg-base-300 rounded-btn border border-opacity-5" | ||||
|                 alt={item.title} | ||||
|               /> | ||||
|             </figure> | ||||
|           )} | ||||
|           <div class="card-body"> | ||||
|             <h2 class="text-xl">{item.title}</h2> | ||||
|             <div> | ||||
|               <span class="badge badge-accent">{POST_TYPES[item.type]}</span> | ||||
|               {item.categories?.map((category: string) => ( | ||||
|                 <span class="badge badge-primary">{category}</span> | ||||
|               ))} | ||||
|               {item.tags?.map((tag: string) => ( | ||||
|                 <span class="badge badge-secondary">{tag}</span> | ||||
|               ))} | ||||
|             </div> | ||||
|             <div class="text-xs opacity-60 line-clamp-3"> | ||||
|               {item.description} | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </a> | ||||
|     )) | ||||
|   } | ||||
| </div> | ||||
| @@ -15,17 +15,6 @@ const { title } = Astro.props; | ||||
|     <meta name="generator" content={Astro.generator} /> | ||||
|     <title>{title}</title> | ||||
|  | ||||
|     <script is:inline> | ||||
|       if (localStorage.getItem("theme") === null) { | ||||
|         document.documentElement.setAttribute("data-theme", "light"); | ||||
|       } else { | ||||
|         document.documentElement.setAttribute( | ||||
|           "data-theme", | ||||
|           localStorage.getItem("theme") | ||||
|         ); | ||||
|       } | ||||
|     </script> | ||||
|  | ||||
|     <ViewTransitions /> | ||||
|   </head> | ||||
|   <body> | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/pages/categories/[slug].astro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/pages/categories/[slug].astro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| --- | ||||
| import PageLayout from "../../layouts/PageLayout.astro"; | ||||
|  | ||||
| import { client } from "../../../tina/__generated__/client"; | ||||
| import PostList from "../../components/PostList.astro"; | ||||
|  | ||||
| export const prerender = false; | ||||
|  | ||||
| const { slug } = Astro.params; | ||||
|  | ||||
| const postsResponse = await client.queries.postConnection({ | ||||
|   filter: { categories: { in: [slug ?? "index"] } }, | ||||
| }); | ||||
| const posts = postsResponse.data.postConnection.edges | ||||
|   ?.sort((a, b) => | ||||
|     new Date(a?.node?.date ?? 0).getTime() <= | ||||
|     new Date(b?.node?.date ?? 0).getTime() | ||||
|       ? -1 | ||||
|       : 0 | ||||
|   ) | ||||
|   .map((event) => { | ||||
|     return { ...event?.node, slug: event?.node?._sys.filename }; | ||||
|   }); | ||||
| --- | ||||
|  | ||||
| <PageLayout> | ||||
|   <div class="max-w-[720px] mx-auto"> | ||||
|     <div class="pt-16 pb-6 px-6"> | ||||
|       <h1 class="text-4xl font-bold">分类检索</h1> | ||||
|       <p class="pt-3">以下是包含「{slug}」分类的记录……</p> | ||||
|     </div> | ||||
|  | ||||
|     <PostList posts={posts as any[]} /> | ||||
|   </div> | ||||
| </PageLayout> | ||||
| @@ -4,6 +4,8 @@ import PageLayout from "../../layouts/PageLayout.astro"; | ||||
| import { client } from "../../../tina/__generated__/client"; | ||||
| import { TinaMarkdown } from "tinacms/dist/rich-text"; | ||||
|  | ||||
| export const prerender = false; | ||||
|  | ||||
| const eventsResponse = await client.queries.eventConnection(); | ||||
| const events = eventsResponse.data.eventConnection.edges | ||||
|   ?.sort((a, b) => | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| --- | ||||
| import PageLayout from "../../layouts/PageLayout.astro"; | ||||
| 
 | ||||
| import client from "../../../tina/__generated__/client"; | ||||
| import { POST_TYPES } from "../../scripts/consts"; | ||||
| import { client } from "../../../tina/__generated__/client"; | ||||
| import { TinaMarkdown } from "tinacms/dist/rich-text"; | ||||
| 
 | ||||
| export const prerender = false; | ||||
| @@ -42,6 +43,34 @@ const { data } = await client.queries.post({ | ||||
|               <div>作者</div> | ||||
|               <div>{data.post.author?.name ?? "佚名"}</div> | ||||
|             </div> | ||||
|             <div> | ||||
|               <div>类型</div> | ||||
|               <div class="text-accent">{POST_TYPES[data.post.type as unknown as string]}</div> | ||||
|             </div> | ||||
|             <div> | ||||
|               <div>分类</div> | ||||
|               <div class="flex gap-1"> | ||||
|                 { | ||||
|                   data.post.categories?.map((category) => ( | ||||
|                     <a href={`/categories/${category}`} class="link link-primary"> | ||||
|                       {category} | ||||
|                     </a> | ||||
|                   )) | ||||
|                 } | ||||
|               </div> | ||||
|             </div> | ||||
|             <div> | ||||
|               <div>标签</div> | ||||
|               <div class="flex gap-1"> | ||||
|                 { | ||||
|                   data.post.tags?.map((tag) => ( | ||||
|                     <a href={`/tags/${tag}`} class="link link-secondary"> | ||||
|                       {tag} | ||||
|                     </a> | ||||
|                   )) | ||||
|                 } | ||||
|               </div> | ||||
|             </div> | ||||
|             <div> | ||||
|               <div>发布于</div> | ||||
|               <div>{new Date(data.post.date ?? 0).toLocaleString()}</div> | ||||
| @@ -2,6 +2,9 @@ | ||||
| import PageLayout from "../../layouts/PageLayout.astro"; | ||||
|  | ||||
| import { client } from "../../../tina/__generated__/client"; | ||||
| import PostList from "../../components/PostList.astro"; | ||||
|  | ||||
| export const prerender = false; | ||||
|  | ||||
| const postsResponse = await client.queries.postConnection(); | ||||
| const posts = postsResponse.data.postConnection.edges | ||||
| @@ -23,33 +26,5 @@ const posts = postsResponse.data.postConnection.edges | ||||
|       <p class="pt-3">记录生活,记录理想,记录记录……</p> | ||||
|     </div> | ||||
|  | ||||
|     <div class="card card-compact w-full shadow-xl"> | ||||
|       <div class="card-body"> | ||||
|         <div class="grid justify-items-strench gap-6"> | ||||
|           { | ||||
|             posts?.map((item) => ( | ||||
|               <a href={`/posts/${item.slug}`}> | ||||
|                 <div class="card sm:card-side hover:bg-base-200 transition-colors sm:max-w-none"> | ||||
|                   {item.heroImg && ( | ||||
|                     <figure class="mx-auto w-full object-cover p-6 max-sm:pb-0 sm:max-w-[12rem] sm:pe-0"> | ||||
|                       <img | ||||
|                         loading="lazy" | ||||
|                         src={item.heroImg} | ||||
|                         class="border-base-content bg-base-300 rounded-btn border border-opacity-5" | ||||
|                         alt={item.title} | ||||
|                       /> | ||||
|                     </figure> | ||||
|                   )} | ||||
|                   <div class="card-body"> | ||||
|                     <h2 class="card-title">{item.title}</h2> | ||||
|                     <p class="text-xs opacity-60">{item.description}</p> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </a> | ||||
|             )) | ||||
|           } | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|     <PostList posts={posts as any[]} /> | ||||
| </PageLayout> | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/pages/tags/[slug].astro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/pages/tags/[slug].astro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| --- | ||||
| import PageLayout from "../../layouts/PageLayout.astro"; | ||||
|  | ||||
| import { client } from "../../../tina/__generated__/client"; | ||||
| import PostList from "../../components/PostList.astro"; | ||||
|  | ||||
| export const prerender = false; | ||||
|  | ||||
| const { slug } = Astro.params; | ||||
|  | ||||
| const postsResponse = await client.queries.postConnection({ | ||||
|   filter: { tags: { in: [slug ?? "index"] } }, | ||||
| }); | ||||
| const posts = postsResponse.data.postConnection.edges | ||||
|   ?.sort((a, b) => | ||||
|     new Date(a?.node?.date ?? 0).getTime() <= | ||||
|     new Date(b?.node?.date ?? 0).getTime() | ||||
|       ? -1 | ||||
|       : 0 | ||||
|   ) | ||||
|   .map((event) => { | ||||
|     return { ...event?.node, slug: event?.node?._sys.filename }; | ||||
|   }); | ||||
| --- | ||||
|  | ||||
| <PageLayout> | ||||
|   <div class="max-w-[720px] mx-auto"> | ||||
|     <div class="pt-16 pb-6 px-6"> | ||||
|       <h1 class="text-4xl font-bold">标签检索</h1> | ||||
|       <p class="pt-3">以下是包含「{slug}」标签的记录……</p> | ||||
|     </div> | ||||
|  | ||||
|     <PostList posts={posts as any[]} /> | ||||
|   </div> | ||||
| </PageLayout> | ||||
							
								
								
									
										5
									
								
								src/scripts/consts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/scripts/consts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| export const POST_TYPES: { [id: string]: string } = { | ||||
|   article: "文章", | ||||
|   podcast: "播客", | ||||
|   announcements: "通告", | ||||
| }; | ||||
| @@ -43,6 +43,27 @@ const Post: Collection = { | ||||
|         timeFormat: "hh:mm A", | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       label: "Categories", | ||||
|       name: "categories", | ||||
|       type: "string", | ||||
|       list: true, | ||||
|     }, | ||||
|     { | ||||
|       label: "Tags", | ||||
|       name: "tags", | ||||
|       type: "string", | ||||
|       list: true, | ||||
|     }, | ||||
|     { | ||||
|       label: "Type", | ||||
|       name: "type", | ||||
|       type: "string", | ||||
|       // @ts-ignore | ||||
|       component: "select", | ||||
|       options: ["article", "podcast", "announcement"], | ||||
|       list: true, | ||||
|     }, | ||||
|     { | ||||
|       type: "rich-text", | ||||
|       label: "Body", | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -9574,11 +9574,6 @@ term-vector@^1.0.0: | ||||
|   resolved "https://registry.yarnpkg.com/term-vector/-/term-vector-1.0.0.tgz#3ad3cf93c5c2df3e3840e3090ee4ec5fe647910b" | ||||
|   integrity sha512-P7xDawxO9T1yjR2oiTfgw7BzvyrdsbakUT6PJsgaAeFmSV+6h3fnXtmZJf4ynef6HVamYgs7Wf5I75UBV15ddQ== | ||||
|  | ||||
| theme-change@^2.5.0: | ||||
|   version "2.5.0" | ||||
|   resolved "https://registry.yarnpkg.com/theme-change/-/theme-change-2.5.0.tgz#d3b064af9c4cd01ab16ce0a4ecb251c827a50e68" | ||||
|   integrity sha512-B/UdsgdHAGhSKHTAQnxg/etN0RaMDpehuJmZIjLMDVJ6DGIliRHGD6pODi1CXLQAN9GV0GSyB3G6yCuK05PkPQ== | ||||
|  | ||||
| thenify-all@^1.0.0: | ||||
|   version "1.6.0" | ||||
|   resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user