mirror of
https://github.com/Lumither/nocturne.git
synced 2026-10-17 10:26:21 +00:00
feat(blog) add footer for post reading part
This commit is contained in:
11 files changed
+178
-23
No files matched your search
@@ -230,7 +230,7 @@ $$
|
|||||||
_insert_columns TEXT := 'post_id';
|
_insert_columns TEXT := 'post_id';
|
||||||
_insert_values TEXT := quote_literal(_post_id);
|
_insert_values TEXT := quote_literal(_post_id);
|
||||||
_update_set TEXT := '';
|
_update_set TEXT := '';
|
||||||
_blacklist TEXT[] := ARRAY['id', 'tags'];
|
_blacklist TEXT[] := ARRAY['tags'];
|
||||||
BEGIN
|
BEGIN
|
||||||
SELECT EXISTS(SELECT 1 FROM meta WHERE post_id = _post_id) INTO _exists;
|
SELECT EXISTS(SELECT 1 FROM meta WHERE post_id = _post_id) INTO _exists;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function Layout({
|
|||||||
}) {
|
}) {
|
||||||
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 md:pl-7 items-stretch justify-center' }>
|
||||||
<div className={ 'flex flex-auto p-7 pl-2 md:pl-7 w-full justify-center' }>
|
<div className={ 'flex flex-auto p-7 pl-2 lg:pl-7 w-full justify-center' }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MinifyPostCard from '@/app/blog/post/[id]/MinifyPostCard';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { FaCreativeCommons } from 'react-icons/fa6';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
post: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const Footer = (props: Props) => {
|
||||||
|
const { post } = props;
|
||||||
|
|
||||||
|
const header_img = post['header_img'];
|
||||||
|
const adjacent_posts = post['adj'];
|
||||||
|
const prev_post = adjacent_posts['prev'];
|
||||||
|
const next_post = adjacent_posts['next'];
|
||||||
|
const link = post['meta']['link'] ?? `https://lumither.com/blog/post/${ post['meta']['id'] }`;
|
||||||
|
const author = post['meta']['author'] ?? 'Tao';
|
||||||
|
const author_link = post['meta']['author_link'] ?? '/about';
|
||||||
|
const post_date = new Date(post['first_update']);
|
||||||
|
const update_date = new Date(post['last_update']);
|
||||||
|
const cc = post['meta']['cc'] ?? 'by-nc-sa';
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ `w-full` }>
|
||||||
|
|
||||||
|
<div className={ 'flex transition bg-zinc-300/80 dark:bg-gray-600/25' }>
|
||||||
|
<div className={ `p-8 w-full` }>
|
||||||
|
<div className={ 'flex flex-col space-y-4 relative' }>
|
||||||
|
<div className={ 'z-[2]' }>
|
||||||
|
<p className={ 'text-xl font-bold' }>{ post['meta']['title'] }</p>
|
||||||
|
<Link href={ link }>
|
||||||
|
<p className={ 'text-sm underline decoration-indigo-500 dark:decoration-sky-500' }>{ link }</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className={ 'z-[2] flex flex-row flex-wrap gap-x-7 gap-y-2' }>
|
||||||
|
<div>
|
||||||
|
<p className={ 'text-lg font-bold' }>Author</p>
|
||||||
|
<Link href={ author_link }>
|
||||||
|
<p className={ 'underline decoration-indigo-500 dark:decoration-sky-500' }>{ author }</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className={ 'text-lg font-bold' }>Posted on</p>
|
||||||
|
<p>{ post_date.toLocaleString('default', {
|
||||||
|
month: `long`,
|
||||||
|
day: `numeric`,
|
||||||
|
year: `numeric`
|
||||||
|
}) }</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className={ 'text-lg font-bold' }>Updated on</p>
|
||||||
|
<p>{ update_date.toLocaleString('default', {
|
||||||
|
month: `long`,
|
||||||
|
day: `numeric`,
|
||||||
|
year: `numeric`
|
||||||
|
}) }</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className={ 'text-lg font-bold' }>Published under</p>
|
||||||
|
<Link href={ `https://creativecommons.org/licenses/${ cc }/4.0/` }>
|
||||||
|
<p className={ 'underline decoration-indigo-500 dark:decoration-sky-500' }>{ `CC ${ cc.toUpperCase() } 4.0` }</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<FaCreativeCommons size={ '80px' }
|
||||||
|
className={ 'absolute inset-y-0 right-0 opacity-50 brightness-75 z-0' } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={ `flex justify-center` }>
|
||||||
|
<div className={ `w-full shadow-2xl ` }>
|
||||||
|
<div className={ `flex flex-col md:flex-row w-full` }>
|
||||||
|
{
|
||||||
|
next_post &&
|
||||||
|
<MinifyPostCard post={ next_post } desc={ 'prev' }></MinifyPostCard>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
prev_post &&
|
||||||
|
<MinifyPostCard post={ prev_post } desc={ 'next' }></MinifyPostCard>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Footer;
|
||||||
@@ -10,15 +10,15 @@ type Props = {
|
|||||||
|
|
||||||
const Headers = (props: Props) => {
|
const Headers = (props: Props) => {
|
||||||
let post = props.post;
|
let post = props.post;
|
||||||
let title = (post as any)['title'];
|
let title = post['title'];
|
||||||
let sub_title = (post as any)['sub_title'];
|
let sub_title = post['sub_title'];
|
||||||
// let summary = (post as any)['summary'];
|
// let summary = (post as any)['summary'];
|
||||||
let category = (post as any)['category'];
|
let category = post['category'];
|
||||||
let tags = (post as any)['tags'];
|
let tags = post['tags'];
|
||||||
let last_update = new Date((post as any)['last_update']);
|
// let last_update = new Date((post as any)['last_update']);
|
||||||
let first_update = new Date((post as any)['first_update']);
|
let first_update = new Date(post['first_update']);
|
||||||
let post_id = (post as any)['post_id'];
|
// let post_id = (post as any)['post_id'];
|
||||||
let header_img = (post as any)['header_img'];
|
let header_img = post['header_img'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -39,7 +39,7 @@ const Headers = (props: Props) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
className={ header_img !== '' ?
|
className={ header_img !== '' ?
|
||||||
'mx-8 -mt-16 backdrop-blur bg-zinc-300/80 dark:bg-gray-600/25 rounded-2xl z-30'
|
'mx-8 -mt-16 backdrop-blur transition bg-zinc-300/80 dark:bg-gray-600/25 rounded-2xl z-30'
|
||||||
: 'mx-6 mt-6'
|
: 'mx-6 mt-6'
|
||||||
}>
|
}>
|
||||||
<div className={ `p-4` }>
|
<div className={ `p-4` }>
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardFooter, CardHeader } from '@nextui-org/card';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
post: any
|
||||||
|
desc: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const MinifyPostCard = (props: Props) => {
|
||||||
|
const { post, desc } = props;
|
||||||
|
const img_url = post['header_img'] as string;
|
||||||
|
return (
|
||||||
|
<div className={ 'w-full transition hover:brightness-75' }>
|
||||||
|
<Card isFooterBlurred
|
||||||
|
className="w-full h-[300px] shadow-none border-0 rounded-none overflow-hidden"
|
||||||
|
as={ Link }
|
||||||
|
isPressable
|
||||||
|
href={ `/blog/post/${ post['id'] }` }
|
||||||
|
>
|
||||||
|
<CardHeader className="absolute z-10 top-1 flex-col items-start">
|
||||||
|
<p className={ `text-tiny uppercase font-bold ${ img_url ? 'text-white/60' : 'text-black/60 dark:text-white/60' }` }>{ desc }</p>
|
||||||
|
</CardHeader>
|
||||||
|
{ img_url &&
|
||||||
|
<div>
|
||||||
|
<Image
|
||||||
|
className={ 'object-cover object-center ' }
|
||||||
|
src={ img_url }
|
||||||
|
alt={ post.title }
|
||||||
|
fill
|
||||||
|
/>
|
||||||
|
<CardFooter
|
||||||
|
className="absolute transition-colors bg-zinc-300/80 dark:bg-gray-600/25 dark:backdrop-brightness-75 bottom-0 justify-between rounded-none">
|
||||||
|
<div>
|
||||||
|
<p className="text-2xl font-bold">{ post['title'] }</p>
|
||||||
|
<p className="">{ post['sub_title'] }</p>
|
||||||
|
</div>
|
||||||
|
</CardFooter>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{ !img_url &&
|
||||||
|
<div className={ 'h-full grid p-6 place-content-center' }>
|
||||||
|
<div className={ 'flex flex-row items-center text-center max-h-fit' }>
|
||||||
|
<p className={ 'text-3xl font-bold' }>{ post['title'] }</p>
|
||||||
|
<div className={ 'h-full w-1 mx-2 bg-zinc-500 dark:bg-zinc-400' }></div>
|
||||||
|
<p className={ 'text-xl' }>{ post['sub_title'] }</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default MinifyPostCard;
|
||||||
@@ -10,6 +10,7 @@ import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|||||||
import rehypeRaw from 'rehype-raw';
|
import rehypeRaw from 'rehype-raw';
|
||||||
import rehypeSanitize from 'rehype-sanitize';
|
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';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string
|
id: string
|
||||||
@@ -37,7 +38,7 @@ async function PostCard(props: Props) {
|
|||||||
<div>
|
<div>
|
||||||
<Card className={ `max-w-full relative` }>
|
<Card className={ `max-w-full relative` }>
|
||||||
|
|
||||||
{/* card headers*/ }
|
{/* card headers */ }
|
||||||
<Headers post={ post_data } />
|
<Headers post={ post_data } />
|
||||||
|
|
||||||
{/* card body */ }
|
{/* card body */ }
|
||||||
@@ -87,6 +88,12 @@ async function PostCard(props: Props) {
|
|||||||
} }
|
} }
|
||||||
>{ (post_data as any)['content'] }</Markdown>
|
>{ (post_data as any)['content'] }</Markdown>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|
||||||
|
|
||||||
|
{/* card footer */ }
|
||||||
|
|
||||||
|
<Footer post={ post_data } />
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<body className={ `dark:bg-[#282830] min-h-screen` }>
|
<body className={ `transition duration-300 dark:bg-[#282830] min-h-screen` }>
|
||||||
<NextThemesProvider attribute="class" defaultTheme="dark">
|
<NextThemesProvider attribute="class" defaultTheme="dark">
|
||||||
<div className={ `justify-center flex flex-row w-full max-w-full` }>
|
<div className={ `justify-center flex flex-row w-full max-w-full` }>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ function Navbar() {
|
|||||||
}, [ path ]);
|
}, [ path ]);
|
||||||
|
|
||||||
|
|
||||||
const minMobileWidth: number = 768;
|
const minMobileWidth: number = 1024;
|
||||||
const [ isMobile, setIsMobile ] = useState(false);
|
const [ isMobile, setIsMobile ] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateMobileWidth = () => {
|
const updateMobileWidth = () => {
|
||||||
@@ -111,9 +111,9 @@ function Navbar() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={ `flex flex-col min-w-[50px] md:min-w-[256px] mr-0 md:mr-2 ml-2 md:ml-8 min-h-dvh pt-8 sticky` }>
|
className={ `flex flex-col min-w-[50px] lg:min-w-[256px] mr-0 lg:mr-2 ml-2 lg:ml-8 min-h-dvh pt-8 sticky` }>
|
||||||
<div className={ `fixed min-h-screen h-full` }>
|
<div className={ `fixed min-h-screen h-full` }>
|
||||||
<div className={ `hidden md: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/compr/1717153492846703409_avatar.webp' }
|
||||||
@@ -132,7 +132,7 @@ function Navbar() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ul className={ `flex flex-col space-y-2 md:space-y-0 md:flex-row items-center my-4 md:space-x-2` }>
|
<ul className={ `flex flex-col space-y-2 lg:space-y-0 lg:flex-row items-center my-4 lg:space-x-2` }>
|
||||||
{
|
{
|
||||||
connections.map((conn, key) => (
|
connections.map((conn, key) => (
|
||||||
<li key={ key }>
|
<li key={ key }>
|
||||||
@@ -154,7 +154,7 @@ function Navbar() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={ `flex justify-center md:justify-start w-full mt-8 ml-0 md:-ml-3` }>
|
className={ `flex justify-center lg:justify-start w-full mt-8 ml-0 lg:-ml-3` }>
|
||||||
<ul className={ `flex flex-col space-y-2 w-full` }>
|
<ul className={ `flex flex-col space-y-2 w-full` }>
|
||||||
{
|
{
|
||||||
entries.map((meta, key) => (
|
entries.map((meta, key) => (
|
||||||
@@ -165,11 +165,11 @@ function Navbar() {
|
|||||||
color={ `default` }
|
color={ `default` }
|
||||||
fullWidth
|
fullWidth
|
||||||
isIconOnly={ isMobile }
|
isIconOnly={ isMobile }
|
||||||
className={ 'flex md:justify-start w-fit md:w-full' }
|
className={ 'flex lg:justify-start w-fit lg:w-full' }
|
||||||
aria-label={ `navbar: ${ meta.display_name }` }
|
aria-label={ `navbar: ${ meta.display_name }` }
|
||||||
href={ meta.href }>
|
href={ meta.href }>
|
||||||
{ meta.icon }
|
{ meta.icon }
|
||||||
<p className={ `font-bold hidden md:block` }>{ meta.display_name }</p>
|
<p className={ `font-bold hidden lg:block` }>{ meta.display_name }</p>
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
@@ -177,7 +177,7 @@ function Navbar() {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={ `mt-8 flex md:hidden justify-center w-full` }>
|
<div className={ `mt-8 flex lg:hidden justify-center w-full` }>
|
||||||
<p className={ `text-center sideways-lr font-bold text-2xl text-zinc-500 dark:text-zinc-400` }>
|
<p className={ `text-center sideways-lr font-bold text-2xl text-zinc-500 dark:text-zinc-400` }>
|
||||||
{ shownPath }
|
{ shownPath }
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function ThemeSwitcher() {
|
|||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
></Switch>
|
></Switch>
|
||||||
<p className={ `font-bold hidden md:block` }>{ `Toggle Theme` }</p>
|
<p className={ `font-bold hidden lg:block` }>{ `Toggle Theme` }</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.2",
|
"eslint-config-next": "14.2.2",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
const config = {
|
const config = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
},
|
autoprefixer: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
Reference in new issue
Block a user