mirror of
https://github.com/Lumither/nocturne.git
synced 2026-10-17 10:26:21 +00:00
feat(global) several major updates:
- delete page `tag`, `archive` - add page `friends` - implement page `about` *partially*
This commit is contained in:
18 files changed
+319
-109
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
use std::{env, fs};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
use axum::extract::{Query, State};
|
use axum::extract::{Query, State};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
@@ -9,7 +9,7 @@ use futures::{stream, StreamExt};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use sqlx::{PgPool, query};
|
use sqlx::{query, PgPool};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ pub async fn refresh(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let post_dir = Path::new(&data_repo_dir).join("posts");
|
||||||
|
|
||||||
if is_force_refresh {
|
if is_force_refresh {
|
||||||
if let Err(e) = query("DROP TABLE IF EXISTS hash, meta, post, tag;")
|
if let Err(e) = query("DROP TABLE IF EXISTS hash, meta, post, tag;")
|
||||||
@@ -60,9 +61,9 @@ pub async fn refresh(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate post idx
|
// generate post idx
|
||||||
let md_path = search_md(Path::new(&data_repo_dir));
|
let post_path = search_md(&post_dir);
|
||||||
|
|
||||||
let post_list_with_hash: Vec<(Map<_, _>, Vec<_>)> = md_path
|
let post_list_with_hash: Vec<(Map<_, _>, Vec<_>)> = post_path
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|post_path| match post::from_path(&post_path) {
|
.filter_map(|post_path| match post::from_path(&post_path) {
|
||||||
Ok(post) => match fs::read(&post_path) {
|
Ok(post) => match fs::read(&post_path) {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function Layout({
|
||||||
|
children
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={ 'flex p-7' }>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MarkdownRenderer from '@/app/public/MarkdownRenderer';
|
||||||
|
import { fetchText } from '@/app/fetch';
|
||||||
|
|
||||||
|
const Me = async () => {
|
||||||
|
return (
|
||||||
|
<div className={ 'p-5' }>
|
||||||
|
<MarkdownRenderer>
|
||||||
|
{ await fetchText('https://raw.githubusercontent.com/lumither/blog-posts/master/about/me.md') }
|
||||||
|
</MarkdownRenderer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Me;
|
||||||
@@ -1,13 +1,58 @@
|
|||||||
|
import { Card } from '@nextui-org/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ConstructionPlaceHolder from '@/components/ConstructionPlaceHolder';
|
import { CardBody } from '@nextui-org/card';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
function About() {
|
const About = () => {
|
||||||
return (
|
return (
|
||||||
<div className={ `h-dvh` }>
|
<div className={ `flex flex-col w-full justify-center align-middle h-dvh` }>
|
||||||
<ConstructionPlaceHolder />
|
<div className={ 'md:relative md:h-[130px] mb-4 md:mb-0' }>
|
||||||
|
<div className={ 'md:relative md:left-[20%] flex flex-col w-fit' }>
|
||||||
|
<p className={ 'text-pretty text-3xl' }>{ '讷,远道而来的' }<span
|
||||||
|
className={ 'break-keep underline decoration-sky-400 dark:decoration-sky-700 decoration-4 underline-offset-0' }>旅人</span>
|
||||||
|
</p>
|
||||||
|
<p className={ 'text-pretty md:text-2xl mt-1 md:ml-4' }>{ '愿意坐下来听个故事吗...' }</p>
|
||||||
|
<p className={ 'hidden md:block text-lg md:ml-8' }>{ '一个关于一位' }<span
|
||||||
|
className={ 'text-gray-700 dark:text-gray-400 text-sm transition-colors' }>{ '█' }</span>{ '追寻' }<span
|
||||||
|
className={ 'text-gray-700 dark:text-gray-400 text-sm transition-colors' }>{ '█' }</span>{ ',探索' }<span
|
||||||
|
className={ 'text-gray-700 dark:text-gray-400 text-sm transition-colors' }>{ '█' }</span>{ '的故事' }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ `flex justify-center w-full h-[60%] md:h-[40%]` }>
|
||||||
|
<div
|
||||||
|
className={ `flex flex-col md:flex-row w-full md:w-[85%] lg:w-[90%] xl:w-[85%] p-4 gap-x-7 gap-y-5` }>
|
||||||
|
<Card
|
||||||
|
isHoverable
|
||||||
|
className={ 'w-full h-[45%] md:h-full' }
|
||||||
|
as={ Link }
|
||||||
|
href={ '/about/me' }
|
||||||
|
isPressable
|
||||||
|
>
|
||||||
|
<CardBody>
|
||||||
|
<div className={ 'h-full flex flex-col justify-center' }>
|
||||||
|
<p className={ 'text-center text-3xl h-fit' }>关于我</p>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
isHoverable
|
||||||
|
className={ 'w-full h-[45%] md:h-full' }
|
||||||
|
as={ Link }
|
||||||
|
href={ '/about/website' }
|
||||||
|
isPressable
|
||||||
|
>
|
||||||
|
<CardBody>
|
||||||
|
<div className={ 'h-full flex flex-col justify-center' }>
|
||||||
|
<p className={ 'text-center text-3xl h-fit' }>关于这个网站</p>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className={ 'text-center' }>*目前还没想到如何设计这一页,先摸鱼会(笑)</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default About;
|
export default About;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MarkdownRenderer from '@/app/public/MarkdownRenderer';
|
||||||
|
import { fetchText } from '@/app/fetch';
|
||||||
|
|
||||||
|
const Website = async () => {
|
||||||
|
return (
|
||||||
|
<div className={ 'p-5' }>
|
||||||
|
<MarkdownRenderer>
|
||||||
|
{ await fetchText('https://raw.githubusercontent.com/lumither/blog-posts/master/about/website.md') }
|
||||||
|
</MarkdownRenderer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Website;
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import ConstructionPlaceHolder from '@/components/ConstructionPlaceHolder';
|
|
||||||
|
|
||||||
const Archive = () => {
|
|
||||||
return (
|
|
||||||
<div className={ `h-dvh` }>
|
|
||||||
<ConstructionPlaceHolder />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Archive;
|
|
||||||
@@ -6,9 +6,10 @@ function Layout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
// <div className={ 'flex flex-auto p-7 pl-2 md:pl-7 items-stretch justify-center' }>
|
|
||||||
<div className={ 'flex flex-auto p-7 pl-2 lg:pl-7 w-full justify-center' }>
|
<div className={ 'flex flex-auto p-7 pl-2 lg:pl-7 w-full justify-center' }>
|
||||||
|
<main className={ 'w-full' }>
|
||||||
{ children }
|
{ children }
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { Button } from '@nextui-org/react';
|
||||||
|
import { IoArrowBackOutline } from 'react-icons/io5';
|
||||||
|
|
||||||
|
const ButtonGoBack = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
startContent={ <IoArrowBackOutline /> }
|
||||||
|
variant={ 'light' }
|
||||||
|
onClick={ () => router.back() }
|
||||||
|
>
|
||||||
|
{ 'Back' }
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ButtonGoBack;
|
||||||
@@ -1,16 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Markdown from 'react-markdown';
|
|
||||||
import { Card, CardBody } from '@nextui-org/card';
|
import { Card, CardBody } from '@nextui-org/card';
|
||||||
import remarkGfm from 'remark-gfm';
|
|
||||||
import remarkToc from 'remark-toc';
|
|
||||||
import remarkFrontmatter from 'remark-frontmatter';
|
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
||||||
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
||||||
import rehypeRaw from 'rehype-raw';
|
|
||||||
import rehypeSanitize from 'rehype-sanitize';
|
|
||||||
import Headers from '@/app/blog/post/[id]/Headers';
|
import Headers from '@/app/blog/post/[id]/Headers';
|
||||||
import Footer from '@/app/blog/post/[id]/Footer';
|
import Footer from '@/app/blog/post/[id]/Footer';
|
||||||
import { fetchNocturneApi } from '@/app/blog/api';
|
import { fetchNocturneApi } from '@/app/blog/api';
|
||||||
|
import MarkdownRenderer from '@/app/public/MarkdownRenderer';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string
|
id: string
|
||||||
@@ -31,55 +24,15 @@ async function PostCard(props: Props) {
|
|||||||
|
|
||||||
{/* card body */ }
|
{/* card body */ }
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Markdown
|
<div className={ 'p-5' }>
|
||||||
// className={ `p-5 max-w-full text-justify text-pretty prose prose-neutral prose-sm dark:prose-invert md:prose-md lg:prose-lg` }
|
<MarkdownRenderer>
|
||||||
className={ `p-5 max-w-full text-justify text-pretty prose prose-sm prose-neutral dark:prose-invert md:prose-md lg:prose-lg
|
{ ret['content'] }
|
||||||
prose-code:overflow-x-scroll
|
</MarkdownRenderer>
|
||||||
` }
|
</div>
|
||||||
remarkPlugins={ [ remarkGfm, remarkToc, remarkFrontmatter ] }
|
|
||||||
rehypePlugins={ [ rehypeRaw, rehypeSanitize ] }
|
|
||||||
components={ {
|
|
||||||
pre(props) {
|
|
||||||
const { node, className, children, ...rest } = props;
|
|
||||||
if ((children as any)['type'] === 'code') {
|
|
||||||
const match = /language-(\w+)/.exec((children as any)['props']['className'] || '');
|
|
||||||
let lang = match ? match[1] : 'text';
|
|
||||||
return (
|
|
||||||
<pre className={ `not-prose` }>
|
|
||||||
<SyntaxHighlighter
|
|
||||||
// @ts-ignore
|
|
||||||
style={ oneDark }
|
|
||||||
language={ lang }
|
|
||||||
showLineNumbers
|
|
||||||
// wrapLongLines
|
|
||||||
// wrapLines
|
|
||||||
classNames={ className }
|
|
||||||
PreTag="div"
|
|
||||||
{ ...rest }
|
|
||||||
>
|
|
||||||
{
|
|
||||||
String((children as any)['props']['children']).replace(/\n$/, '')
|
|
||||||
}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<pre className={ `not-prose` }>
|
|
||||||
<code className={ className } { ...props }>
|
|
||||||
{ children }
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} }
|
|
||||||
>{ ret['content'] }</Markdown>
|
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|
||||||
|
|
||||||
{/* card footer */ }
|
{/* card footer */ }
|
||||||
|
|
||||||
<Footer post={ ret } />
|
<Footer post={ ret } />
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PostCard from '@/app/blog/post/[id]/PostCard';
|
import PostCard from '@/app/blog/post/[id]/PostCard';
|
||||||
import { MotionDiv } from '@/app/public/MotionDiv';
|
import { MotionDiv } from '@/app/public/MotionDiv';
|
||||||
|
import ButtonGoBack from '@/app/blog/post/[id]/ButtonGoBack';
|
||||||
|
|
||||||
function BlogReader({ params }: { params: { id: string } }) {
|
function BlogReader({ params }: { params: { id: string } }) {
|
||||||
|
|
||||||
@@ -14,6 +15,9 @@ function BlogReader({ params }: { params: { id: string } }) {
|
|||||||
<div className={ `max-w-full` }>
|
<div className={ `max-w-full` }>
|
||||||
<PostCard id={ params.id } />
|
<PostCard id={ params.id } />
|
||||||
</div>
|
</div>
|
||||||
|
<div className={ 'mt-3' }>
|
||||||
|
<ButtonGoBack />
|
||||||
|
</div>
|
||||||
</MotionDiv>
|
</MotionDiv>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export async function fetchText(url: string, ttl: number = 600) {
|
||||||
|
const res = await fetch(url, {
|
||||||
|
next: {
|
||||||
|
revalidate: ttl
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return await res.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchJson(url: string, ttl: number = 600) {
|
||||||
|
const res = await fetch(url, {
|
||||||
|
next: {
|
||||||
|
revalidate: ttl
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function Layout({
|
||||||
|
children
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={ 'p-7' }>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { fetchJson } from '@/app/fetch';
|
||||||
|
import { Card, CardBody } from '@nextui-org/react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default async function Friends() {
|
||||||
|
|
||||||
|
let list = await fetchJson('https://raw.githubusercontent.com/Lumither/friends/master/friends.json');
|
||||||
|
|
||||||
|
const listLength = list.length;
|
||||||
|
const listMaxIdx = listLength - 1;
|
||||||
|
const listIsOdd = listLength % 2 !== 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ `min-h-dvh pb-10` }>
|
||||||
|
<div className={ 'p-7 pt-[10%] md:pt-[20%]' }>
|
||||||
|
<div className={ 'flex flex-col md:flex-row gap-x-3 justify-center' }>
|
||||||
|
<p className={ 'text-3xl text-center text-balance' }>海内存知己</p>
|
||||||
|
<p className={ 'text-3xl text-center text-balance' }>天涯若比邻</p>
|
||||||
|
</div>
|
||||||
|
<p className={ 'text-center text-balance text-zinc-500 dark:text-zinc-400' }>{ 'Though far apart, kin at heart' }</p>
|
||||||
|
</div>
|
||||||
|
<div className={ 'flex w-full h-full justify-center pt-3' }>
|
||||||
|
<ul className={ 'grid grid-cols-2 gap-x-6 gap-y-3 md:max-w-[90%] xl:max-w-[85%] w-full' }>
|
||||||
|
{
|
||||||
|
list.map((friend: any, key: number) => (
|
||||||
|
<li
|
||||||
|
key={ key }
|
||||||
|
className={ (key === listMaxIdx && listIsOdd) ? 'col-span-2 flex justify-center' : 'col-span-2 md:col-span-1' }
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
isHoverable
|
||||||
|
isPressable
|
||||||
|
shadow={ 'none' }
|
||||||
|
as={ Link }
|
||||||
|
href={ friend['url'] }
|
||||||
|
className={ 'dark:bg-[#282830]' }
|
||||||
|
>
|
||||||
|
<CardBody className={ 'pb-0' }>
|
||||||
|
<div className={ 'flex flex-row' }>
|
||||||
|
<div className={ 'flex p-2' }>
|
||||||
|
<div
|
||||||
|
className={ 'h-[80px] w-[80px] relative rounded-2xl' }>
|
||||||
|
<Image
|
||||||
|
alt="avatar"
|
||||||
|
className="object-cover rounded-2xl z-10"
|
||||||
|
fill
|
||||||
|
unoptimized
|
||||||
|
src={ friend['avatar'] }
|
||||||
|
/>
|
||||||
|
<Image
|
||||||
|
alt="avatar"
|
||||||
|
className="relative object-cover rounded-2xl scale-110 blur-3xl"
|
||||||
|
fill
|
||||||
|
unoptimized
|
||||||
|
src={ friend['avatar'] }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ 'p-2 flex-col max-w-full' }>
|
||||||
|
<p className={ 'text-xl' }>{ friend['title'] }</p>
|
||||||
|
{ (friend['name'] === undefined || friend['name'].isNull) ??
|
||||||
|
<p className={ 'text-zinc-600 dark:text-zinc-400' }>{ `@ ${ friend['name'] }` }</p> }
|
||||||
|
{ (friend['desc'] === undefined || friend['desc'].isNull) ??
|
||||||
|
<p className={ 'text-sm text-pretty text-zinc-600 dark:text-zinc-300 mt-1' }>{ friend['desc'] }</p> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
<div className={ 'h-1 bg-blue-800 dark:bg-blue-300' } />
|
||||||
|
</Card>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className={ 'text-center' }>想要成为好伙伴嘛,向<span
|
||||||
|
className={ 'text-blue-800 dark:text-blue-500' }><Link
|
||||||
|
href={ 'https://github.com/Lumither/friends/' }>这里</Link></span>发起PR吧
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,10 +3,8 @@ import React from 'react';
|
|||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<main>
|
|
||||||
<div className={ `h-dvh` }>
|
<div className={ `h-dvh` }>
|
||||||
<ConstructionPlaceHolder />
|
<ConstructionPlaceHolder />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import remarkToc from 'remark-toc';
|
||||||
|
import remarkFrontmatter from 'remark-frontmatter';
|
||||||
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import rehypeSanitize from 'rehype-sanitize';
|
||||||
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
|
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
||||||
|
|
||||||
|
const MarkdownRenderer = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div className={ 'w-full' }>
|
||||||
|
<Markdown
|
||||||
|
className={ `max-w-full text-justify text-pretty prose prose-sm prose-neutral dark:prose-invert
|
||||||
|
md:prose-md lg:prose-lg prose-code:overflow-x-scroll`
|
||||||
|
}
|
||||||
|
remarkPlugins={ [ remarkGfm, remarkToc, remarkFrontmatter ] }
|
||||||
|
rehypePlugins={ [ rehypeRaw, rehypeSanitize ] }
|
||||||
|
components={ {
|
||||||
|
pre(props) {
|
||||||
|
const { node, className, children, ...rest } = props;
|
||||||
|
if ((children as any)['type'] === 'code') {
|
||||||
|
const match = /language-(\w+)/.exec((children as any)['props']['className'] || '');
|
||||||
|
let lang = match ? match[1] : 'text';
|
||||||
|
return (
|
||||||
|
<pre className={ `not-prose` }>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
// @ts-ignore
|
||||||
|
style={ oneDark }
|
||||||
|
language={ lang }
|
||||||
|
showLineNumbers
|
||||||
|
// wrapLongLines
|
||||||
|
// wrapLines
|
||||||
|
classNames={ className }
|
||||||
|
PreTag="div"
|
||||||
|
{ ...rest }
|
||||||
|
>
|
||||||
|
{
|
||||||
|
String((children as any)['props']['children']).replace(/\n$/, '')
|
||||||
|
}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<pre className={ `not-prose` }>
|
||||||
|
<code className={ className } { ...props }>
|
||||||
|
{ children }
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
{
|
||||||
|
children as any
|
||||||
|
}
|
||||||
|
</Markdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default MarkdownRenderer;
|
||||||
Whitespace-only changes.
@@ -1,12 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import ConstructionPlaceHolder from '@/components/ConstructionPlaceHolder';
|
|
||||||
|
|
||||||
const Tags = () => {
|
|
||||||
return (
|
|
||||||
<div className={ `h-dvh` }>
|
|
||||||
<ConstructionPlaceHolder />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tags;
|
|
||||||
@@ -3,16 +3,7 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button } from '@nextui-org/react';
|
import { Button } from '@nextui-org/react';
|
||||||
import NextImage from 'next/image';
|
import NextImage from 'next/image';
|
||||||
import {
|
import { IoHome, IoInformationCircle, IoLink, IoLogoGithub, IoMail, IoPencil, IoSearch } from 'react-icons/io5';
|
||||||
IoFileTrayFull,
|
|
||||||
IoHome,
|
|
||||||
IoInformationCircle,
|
|
||||||
IoLogoGithub,
|
|
||||||
IoMail,
|
|
||||||
IoPencil,
|
|
||||||
IoPricetags,
|
|
||||||
IoSearch
|
|
||||||
} from 'react-icons/io5';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import ThemeSwitcher from '@/components/ThemeSwitcher';
|
import ThemeSwitcher from '@/components/ThemeSwitcher';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
@@ -34,14 +25,9 @@ const entries: { display_name: string; href: string; icon: React.ReactNode }[] =
|
|||||||
href: '/blog'
|
href: '/blog'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <IoPricetags size={ `20px` }></IoPricetags>,
|
icon: <IoLink size={ `20px` }></IoLink>,
|
||||||
display_name: 'Tags',
|
display_name: 'Friends',
|
||||||
href: '/tags'
|
href: '/friends'
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <IoFileTrayFull size={ `20px` }></IoFileTrayFull>,
|
|
||||||
display_name: 'Archive',
|
|
||||||
href: '/archive'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <IoSearch size={ `20px` }></IoSearch>,
|
icon: <IoSearch size={ `20px` }></IoSearch>,
|
||||||
@@ -116,7 +102,7 @@ function Navbar() {
|
|||||||
<div className={ `hidden lg:block` }>
|
<div className={ `hidden lg:block` }>
|
||||||
<div className={ `flex justify-center items-center my-7` }>
|
<div className={ `flex justify-center items-center my-7` }>
|
||||||
<NextImage
|
<NextImage
|
||||||
src={ 'https://oss.lumither.com/blog/pictures/compr/1717153492846703409_avatar.webp' }
|
src={ 'https://oss.lumither.com/blog/pictures/avatar.webp' }
|
||||||
alt={ 'avatar' }
|
alt={ 'avatar' }
|
||||||
width={ 200 }
|
width={ 200 }
|
||||||
height={ 200 }
|
height={ 200 }
|
||||||
|
|||||||
Reference in new issue
Block a user