Compare commits
1 Commits
master
...
app-router
Author | SHA1 | Date | |
---|---|---|---|
0ed07ae377 |
@ -1,15 +0,0 @@
|
|||||||
import { JSX } from "react";
|
|
||||||
|
|
||||||
export type ChildrenType = JSX.Element| Array<ChildrenType>;
|
|
||||||
|
|
||||||
function Container(props: { children?: ChildrenType, ignore?: boolean }) {
|
|
||||||
if (props.ignore)
|
|
||||||
return <>{props.children}</>;
|
|
||||||
return (
|
|
||||||
<div className='container'>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Container;
|
|
@ -1,20 +0,0 @@
|
|||||||
import Title from './title';
|
|
||||||
import Container, { ChildrenType } from './container';
|
|
||||||
|
|
||||||
type LayoutProps = {
|
|
||||||
children?: ChildrenType,
|
|
||||||
removeContainer?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
function Layout(props: LayoutProps) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Title />
|
|
||||||
<Container ignore={props.removeContainer}>
|
|
||||||
{props.children}
|
|
||||||
</Container>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Layout;
|
|
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@ -2,4 +2,4 @@
|
|||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
@ -3,14 +3,19 @@ import NextBundleAnalyzer from '@next/bundle-analyzer';
|
|||||||
|
|
||||||
let config: NextConfig = {
|
let config: NextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
i18n: {
|
turbopack: {
|
||||||
locales: ['en-US'],
|
rules: {
|
||||||
defaultLocale: 'en-US'
|
'*.txt': {
|
||||||
|
as: '*.js',
|
||||||
|
loaders: ['raw-loader'],
|
||||||
|
},
|
||||||
|
'*.md': {
|
||||||
|
as: '*.js',
|
||||||
|
loaders: ['raw-loader'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolveExtensions: ['.txt', '.md', '.tsx', '.ts', '.js']
|
||||||
},
|
},
|
||||||
// not sure why this breaks prod build in the latest version
|
|
||||||
// aah it's so frustrating to deal with an warning log that
|
|
||||||
// shows up regardless of the config but its presence halts
|
|
||||||
// the entire thing.
|
|
||||||
webpack: (config, _options) => {
|
webpack: (config, _options) => {
|
||||||
config.module.rules.push(
|
config.module.rules.push(
|
||||||
{
|
{
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "node ./scripts/generate-metadata.js",
|
"prebuild": "node ./scripts/generate-metadata.js",
|
||||||
"dev": "next dev",
|
"dev": "next dev --turbopack",
|
||||||
"build": "next build",
|
"build": "next build --turbopack",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"highlight.js": "^11.10.0",
|
"highlight.js": "^11.10.0",
|
||||||
"next": "^15.0.4",
|
"next": "^15.3.1",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
|
"raw-loader": "^4.0.2",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import type { AppProps } from 'next/app'
|
|
||||||
import 'normalize.css';
|
|
||||||
import '../styles/global.css';
|
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps) {
|
|
||||||
return <Component {...pageProps} />
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Html, Head, Main, NextScript } from "next/document";
|
|
||||||
|
|
||||||
export default function Document() {
|
|
||||||
return (
|
|
||||||
<Html lang="en">
|
|
||||||
<Head />
|
|
||||||
<body>
|
|
||||||
<Main />
|
|
||||||
<NextScript />
|
|
||||||
</body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,22 +1,20 @@
|
|||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
import ReadmeMd from '../README.md';
|
import ReadmeMd from '../../../README.md';
|
||||||
import License from '../LICENSE.txt';
|
import License from '../../../LICENSE.txt';
|
||||||
import Layout from '../components/layout';
|
|
||||||
|
|
||||||
function AboutPage() {
|
function AboutPage() {
|
||||||
return (
|
return (
|
||||||
<Layout >
|
<>
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<p>Paul's Personal Website.</p>
|
<p>Paul's Personal Website.</p>
|
||||||
<p> You can find me on the following:
|
<p> You can find me on the following platforms:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>X/Twitter: <a href='https://x.com/paulw_xyz'>paulw_xyz</a></li>
|
<li>X/Twitter: <a href='https://x.com/paulw_xyz'>paulw_xyz</a></li>
|
||||||
<li>GitHub: <a href='https://github.com/paulwxyz'>paulwxyz</a></li>
|
<li>GitHub: <a href='https://github.com/paulwxyz'>paulwxyz</a></li>
|
||||||
<li>BlueSky (unused): <a href='https://bsky.app/profile/@paulw.xyz'>@paulw.xyz</a></li>
|
{/* <li>BlueSky (unused): <a href='https://bsky.app/profile/@paulw.xyz'>@paulw.xyz</a></li> */}
|
||||||
<li><a href='https://git.paulw.xyz/xyz'>git.paulw.xyz</a></li>
|
<li><a href='https://git.paulw.xyz/xyz'>git.paulw.xyz</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
The original motivation was to just play with Next.js as it pretty much did the things I wanted web pages to do. But it came at the cost of needless complexity. As I use the JavaScript/ECMAScript/Whatever-you-want-to-call-it-script more and more, I am convinced that it is not a platform worth pursuing because the more complex it gets, the less control I have over what it does and this platform and its users seems to be okay with that sort of loss. I have been instead pivoting toward things that impressed and got me interested in working with computers.</p>
|
The original motivation was to just play with Next.js as it pretty much did the things I wanted web pages to do. But it came at the cost of needless complexity. As I use the JavaScript/ECMAScript/Whatever-you-want-to-call-it-script more and more, I am convinced that it is not a platform worth pursuing because the more complex it gets, the less control I have over what it does and this platform and its users seems to be okay with that sort of loss. I have been instead pivoting toward things that impressed and got me interested in working with computers.</p>
|
||||||
<p>Most services/products are keen on going against the <a href='https://stephango.com/file-over-app'>file over app</a> philosophy which entails prioritizing data over software and anticipate and embrace the eventual death of software. People instead want subscription services that barely support open formats and sometimes do not support exporting data to commonly used formats. The goal here is to avoid storing artifacts under locations that are easily not accessible, not under my control, and does not lock me out of using it with other software. The only reason I have not completely abandoned this is thanks to my decision to rely on Markdown files alone. Had it been reliant on any cloud software, I would have started over.</p>
|
<p>Most services/products are keen on going against the <a href='https://stephango.com/file-over-app'>file over app</a> philosophy which entails prioritizing data over software and anticipate and embrace the eventual death of software. People instead want subscription services that barely support open formats and sometimes do not support exporting data to commonly used formats. The goal here is to avoid storing artifacts under locations that are easily not accessible, not under my control, and does not lock me out of using it with other software. The only reason I have not completely abandoned this is thanks to my decision to rely on Markdown files alone. Had it been reliant on any cloud software, I would have started over.</p>
|
||||||
@ -31,14 +29,14 @@ function AboutPage() {
|
|||||||
<section className='block'>
|
<section className='block'>
|
||||||
<h2>README</h2>
|
<h2>README</h2>
|
||||||
<ReactMarkdown>
|
<ReactMarkdown>
|
||||||
{ReadmeMd.replace(/^#{1,5} /g, (s: string) => { return `#${s}` })}
|
{ReadmeMd.replace(/^#{6}\s+(.*)\s+$/gm, (s: string, a) => `**${a}**\n`).replace(/^#{1,5} /gm, (s: string) => { return `##${s}` })}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</section>
|
</section>
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<h2>LICENSE</h2>
|
<h2>LICENSE</h2>
|
||||||
<pre className='license'>{License}</pre>
|
<pre className='license'>{License}</pre>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
9
src/app/components/container.tsx
Normal file
9
src/app/components/container.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default function Container(props: { children?: React.ReactNode, ignore?: boolean }) {
|
||||||
|
if (props.ignore)
|
||||||
|
return <>{props.children}</>;
|
||||||
|
return (
|
||||||
|
<div className='container'>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Pages from '../public/external.json';
|
import Pages from '../../../public/external.json';
|
||||||
|
|
||||||
function QuickLinks() {
|
function QuickLinks() {
|
||||||
return (
|
return (
|
@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import NotesInfo from '../public/notes.json';
|
import NotesInfo from '../../../public/notes.json';
|
||||||
|
|
||||||
function RecentNotes() {
|
function RecentNotes() {
|
||||||
const notes = Object.entries(NotesInfo)
|
const notes = Object.entries(NotesInfo)
|
@ -1,7 +1,7 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { toRelativeDate } from "../lib/date";
|
import { toRelativeDate } from "../lib/date";
|
||||||
import style from '../styles/recent-posts.module.css';
|
import style from './recent-posts.module.css';
|
||||||
import PostsInfo from '../public/posts.json';
|
import PostsInfo from '../../../public/posts.json';
|
||||||
|
|
||||||
function PostBlock({ slug, otime, title }: { slug: string, otime: string, title: string }) {
|
function PostBlock({ slug, otime, title }: { slug: string, otime: string, title: string }) {
|
||||||
return (
|
return (
|
@ -1,10 +1,10 @@
|
|||||||
|
'use client'
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { usePathname } from 'next/navigation';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import style from '../styles/title.module.css';
|
import style from './title.module.css';
|
||||||
import SiteMap from '../public/sitemap.json';
|
import SiteMap from '../../../public/sitemap.json';
|
||||||
import Head from 'next/head';
|
|
||||||
import { Sites } from '../lib/site';
|
import { Sites } from '../lib/site';
|
||||||
|
|
||||||
function createPathElements(ancestors: Array<{ name: string, path: string }>) {
|
function createPathElements(ancestors: Array<{ name: string, path: string }>) {
|
||||||
@ -20,10 +20,8 @@ function createPathElements(ancestors: Array<{ name: string, path: string }>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function Title() {
|
export default function Title() {
|
||||||
|
const pagePath = usePathname();
|
||||||
const router = useRouter();
|
|
||||||
const pagePath = router.asPath;
|
|
||||||
const splitPath: Array<{ name: string, path: string }> = [];
|
const splitPath: Array<{ name: string, path: string }> = [];
|
||||||
|
|
||||||
// TODO(Paul): clean this up
|
// TODO(Paul): clean this up
|
||||||
@ -32,7 +30,7 @@ function Title() {
|
|||||||
if (pagePath !== '/') {
|
if (pagePath !== '/') {
|
||||||
const subPaths = pagePath.split('?')[0].split('#')[0].split('/');
|
const subPaths = pagePath.split('?')[0].split('#')[0].split('/');
|
||||||
for (const p of subPaths.slice(1, subPaths.length)) {
|
for (const p of subPaths.slice(1, subPaths.length)) {
|
||||||
if (!p)
|
if (!p || !currRoot[p])
|
||||||
continue;
|
continue;
|
||||||
splitPath.push({ name: currRoot[p].title, path: p });
|
splitPath.push({ name: currRoot[p].title, path: p });
|
||||||
|
|
||||||
@ -50,9 +48,9 @@ function Title() {
|
|||||||
const pathElements = splitPath && createPathElements(splitPath) || <></>;
|
const pathElements = splitPath && createPathElements(splitPath) || <></>;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<head>
|
||||||
<title>{title && `${title} | PaulW.XYZ` || 'PaulW.XYZ'}</title>
|
<title>{title && `${title} | PaulW.XYZ` || 'PaulW.XYZ'}</title>
|
||||||
</Head>
|
</head>
|
||||||
<div className={style.container}>
|
<div className={style.container}>
|
||||||
<h1 className={style.title}>
|
<h1 className={style.title}>
|
||||||
{title || 'PaulW.XYZ'}
|
{title || 'PaulW.XYZ'}
|
||||||
@ -67,6 +65,4 @@ function Title() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Title;
|
|
23
src/app/layout.tsx
Normal file
23
src/app/layout.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type {Metadata} from 'next'
|
||||||
|
import 'normalize.css'
|
||||||
|
import './global.css'
|
||||||
|
import Container from './components/container'
|
||||||
|
import Title from './components/title'
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'PaulW.XYZ',
|
||||||
|
description: `Paul's Website`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({children,}: Readonly<{children: React.ReactNode}>) {
|
||||||
|
return (
|
||||||
|
<html lang='en'>
|
||||||
|
<body>
|
||||||
|
<Title />
|
||||||
|
<Container>
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
@ -1,22 +1,21 @@
|
|||||||
import Head from 'next/head';
|
'use client'
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import style from '../styles/title.module.css';
|
import style from './components/title.module.css';
|
||||||
|
|
||||||
function NotFoundPage() {
|
function NotFoundPage() {
|
||||||
// clean this page up
|
// clean this page up
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<head>
|
||||||
<title>404: Not Found | PaulW.XYZ</title>
|
<title>404: Not Found | PaulW.XYZ</title>
|
||||||
</Head>
|
</head>
|
||||||
<div className={style.container}>
|
<div className={style.container}>
|
||||||
<h1 className={style.title}>
|
<h1 className={style.title}>
|
||||||
Page Not Found
|
Page Not Found
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${style.nav} h1`}>
|
<div className={`${style.nav} h1`}><Link href='/'>PaulW.XYZ</Link> / ... ??? / 404: Not Found</div>
|
||||||
<Link href='/'>PaulW.XYZ</Link> / ... ??? / 404: Not Found </div>
|
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
<section className='block text center'>
|
<section className='block text center'>
|
||||||
<h1>Error 404</h1>
|
<h1>Error 404</h1>
|
@ -11,12 +11,11 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings';
|
|||||||
import rehypeHighlight from 'rehype-highlight';
|
import rehypeHighlight from 'rehype-highlight';
|
||||||
import rehypeHighlightCodeLines, { type HighlightLinesOptions } from 'rehype-highlight-code-lines';
|
import rehypeHighlightCodeLines, { type HighlightLinesOptions } from 'rehype-highlight-code-lines';
|
||||||
|
|
||||||
import Layout from '../../components/layout';
|
|
||||||
import readMarkdown from '../../lib/read-markdown';
|
import readMarkdown from '../../lib/read-markdown';
|
||||||
import { toLocaleString } from '../../lib/date';
|
import { toLocaleString } from '../../lib/date';
|
||||||
import NotesInfo from '../../public/notes.json';
|
import NotesInfo from '../../../../public/notes.json';
|
||||||
|
|
||||||
import style from '../../styles/note.module.css';
|
import style from './note.module.css';
|
||||||
import 'highlight.js/styles/monokai-sublime.css';
|
import 'highlight.js/styles/monokai-sublime.css';
|
||||||
import 'katex/dist/katex.min.css';
|
import 'katex/dist/katex.min.css';
|
||||||
|
|
||||||
@ -47,46 +46,21 @@ function Markdown({ content }: any) {
|
|||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
}
|
}
|
||||||
|
|
||||||
function Note({ note }: { note: Note }) {
|
export default async function Note({params}: {params: { note: string}}) {
|
||||||
|
const note = params.note
|
||||||
|
const n = await getNotes(note)
|
||||||
return (<>
|
return (<>
|
||||||
<Layout >
|
|
||||||
<span className={style['last-updated']}>
|
<span className={style['last-updated']}>
|
||||||
Last updated: {toLocaleString(note.mtime)}
|
Last updated: {toLocaleString(n.mtime)}
|
||||||
</span>
|
</span>
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<Markdown content={note.content} />
|
<Markdown content={n.content} />
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params }: { params: { note: string } }) {
|
async function getNotes(name: string) {
|
||||||
const note: string = params.note;
|
|
||||||
const notesInfo: Notes = NotesInfo;
|
const notesInfo: Notes = NotesInfo;
|
||||||
const noteInfo: Note = notesInfo[note];
|
return {...notesInfo[name], content: await readMarkdown('notes', name, true)}
|
||||||
|
}
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
note: {
|
|
||||||
...noteInfo,
|
|
||||||
content: await readMarkdown('notes', note, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
return {
|
|
||||||
paths: Object.keys(NotesInfo).map((note: string) => {
|
|
||||||
return {
|
|
||||||
params: {
|
|
||||||
note
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
fallback: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Note;
|
|
@ -1,9 +1,7 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import Layout from '../../components/layout';
|
import { toRelativeDate } from '../lib/date';
|
||||||
import { toRelativeDate } from '../../lib/date';
|
import NotesInfo from '../../../public/notes.json';
|
||||||
|
|
||||||
import NotesInfo from '../../public/notes.json';
|
|
||||||
|
|
||||||
function NoteEntry({ note }: { note: { title: string, mtime: string, slug: string } }) {
|
function NoteEntry({ note }: { note: { title: string, mtime: string, slug: string } }) {
|
||||||
return (
|
return (
|
||||||
@ -36,7 +34,7 @@ function NotesPage() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<>
|
||||||
{
|
{
|
||||||
!notes || notes.length === 0
|
!notes || notes.length === 0
|
||||||
&& <>No notes found</>
|
&& <>No notes found</>
|
||||||
@ -50,7 +48,7 @@ function NotesPage() {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
}
|
}
|
||||||
</Layout>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Layout from '../components/layout';
|
import QuickLinks from './components/quick-links';
|
||||||
import QuickLinks from '../components/quick-links';
|
import RecentNotes from './components/recent-notes';
|
||||||
import RecentNotes from '../components/recent-notes';
|
import RecentPosts from './components/recent-posts';
|
||||||
import RecentPosts from '../components/recent-posts';
|
import RootInfo from '../../public/home.json';
|
||||||
import RootInfo from '../public/home.json';
|
|
||||||
|
|
||||||
function Nav() {
|
function Nav() {
|
||||||
const nav = Object.entries(RootInfo);
|
const nav = Object.entries(RootInfo);
|
||||||
@ -22,12 +21,12 @@ function Nav() {
|
|||||||
|
|
||||||
function HomePage() {
|
function HomePage() {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<>
|
||||||
<QuickLinks />
|
<QuickLinks />
|
||||||
<RecentPosts />
|
<RecentPosts />
|
||||||
<RecentNotes />
|
<RecentNotes />
|
||||||
<Nav />
|
<Nav />
|
||||||
</Layout>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
import Layout from '../../components/layout';
|
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import style from '../../styles/post.module.css';
|
import style from '../../styles/post.module.css';
|
||||||
import PostsInfo from '../../public/posts.json';
|
import PostsInfo from '../../../../public/posts.json';
|
||||||
import readMarkdown from '../../lib/read-markdown';
|
import readMarkdown from '../../lib/read-markdown';
|
||||||
import DateTool, { toLocaleString } from '../../lib/date';
|
import DateTool, { toLocaleString } from '../../lib/date';
|
||||||
|
|
||||||
@ -11,11 +10,6 @@ interface IPost {
|
|||||||
otime?: string;
|
otime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPosts {
|
|
||||||
[slug: string]: IPost
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function TimeBlock({ mtime, otime }: { mtime: string, otime: string }) {
|
function TimeBlock({ mtime, otime }: { mtime: string, otime: string }) {
|
||||||
const ampm = (h: number) => { if (h >= 12) return 'p.m.'; return 'a.m.'; };
|
const ampm = (h: number) => { if (h >= 12) return 'p.m.'; return 'a.m.'; };
|
||||||
|
|
||||||
@ -50,12 +44,12 @@ function TimeBlock({ mtime, otime }: { mtime: string, otime: string }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// post: IPost & { content: string, cover?: string, otime: string, mtime?: string }
|
||||||
function Post({ post }: { post: IPost & { content: string, cover?: string, otime: string, mtime?: string } }) {
|
export default async function Post({ params }: { params: {post: string} }) {
|
||||||
|
const post = await getPost(params.post);
|
||||||
if (!post)
|
if (!post)
|
||||||
return <></>;
|
return <></>;
|
||||||
return (<>
|
return (<>
|
||||||
<Layout removeContainer={true} >
|
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
{ post.otime !== post.mtime &&
|
{ post.otime !== post.mtime &&
|
||||||
<span className={style.time}>
|
<span className={style.time}>
|
||||||
@ -80,37 +74,12 @@ function Post({ post }: { post: IPost & { content: string, cover?: string, otime
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<div className={style.spacer}></div>
|
<div className={style.spacer}></div>
|
||||||
</Layout>
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params }: any) {
|
export async function getPost(n: string) {
|
||||||
const postsInfo: IPosts = PostsInfo;
|
const postsInfo: Record<string, (IPost & { cover?: string, otime: string, mtime?: string })> = PostsInfo;
|
||||||
const post: IPost = postsInfo[params.post];
|
return {...postsInfo[n], content: await readMarkdown('posts', n, true)};
|
||||||
return {
|
}
|
||||||
props: {
|
|
||||||
post: {
|
|
||||||
...post,
|
|
||||||
content: await readMarkdown('posts', params.post, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
return {
|
|
||||||
paths: Object.keys(PostsInfo).map((post: string) => {
|
|
||||||
return {
|
|
||||||
params: {
|
|
||||||
post
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
fallback: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default Post;
|
|
@ -1,13 +1,11 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Layout from '../../components/layout';
|
import date from '../lib/date';
|
||||||
import date from '../../lib/date';
|
import PostsInfo from '../../../public/posts.json';
|
||||||
import PostsInfo from '../../public/posts.json';
|
|
||||||
|
|
||||||
function PostsPage() {
|
function PostsPage() {
|
||||||
return (
|
return (<>
|
||||||
<Layout>
|
|
||||||
{Object.keys(PostsInfo).length && <Posts /> || <NoPosts />}
|
{Object.keys(PostsInfo).length && <Posts /> || <NoPosts />}
|
||||||
</Layout>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Layout from '../components/layout';
|
|
||||||
import { Sites } from '../lib/site';
|
import { Sites } from '../lib/site';
|
||||||
import SiteMap from '../public/sitemap.json';
|
import SiteMap from '../../../public/sitemap.json';
|
||||||
|
|
||||||
function Desc(props: any) {
|
function Desc(props: any) {
|
||||||
return (
|
return (
|
||||||
@ -33,9 +32,9 @@ function traverseMap(head?: Sites, cwd = '', depth = 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SiteMapPage() {
|
function SiteMapPage() {
|
||||||
return <Layout>
|
return <>
|
||||||
{traverseMap(SiteMap.pages)}
|
{traverseMap(SiteMap.pages)}
|
||||||
</Layout>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SiteMapPage;
|
export default SiteMapPage;
|
@ -1,55 +0,0 @@
|
|||||||
.avatarContainer {
|
|
||||||
padding: 0.5rem;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatarContainer img {
|
|
||||||
border-radius: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardLabel {
|
|
||||||
display: block;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardLabel:after {
|
|
||||||
content: ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardValue {
|
|
||||||
background-color: #303436;
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: 0.25rem 1rem;
|
|
||||||
margin: 0.25rem 0;
|
|
||||||
border: none;
|
|
||||||
display: block;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media screen and (min-width: 800px) {
|
|
||||||
.card {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardTable {
|
|
||||||
flex: 1 1;
|
|
||||||
padding: 0.5rem;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardRow {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardLabel {
|
|
||||||
flex: .2 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardValue {
|
|
||||||
flex: 1 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
.desc {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.listItem {
|
|
||||||
padding: 0.25rem;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.listItem::before {
|
|
||||||
content: '■';
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.listItemDesc {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0.25rem;
|
|
||||||
margin-left: 2.5rem;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block .block {
|
|
||||||
margin: 0;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
border-radius: 0;
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: none;
|
|
||||||
border-top: 1px dashed var(--main-border-color);
|
|
||||||
border-left: 1px dashed var(--main-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.block .block:first-of-type {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block .block:last-of-type {
|
|
||||||
border-bottom-left-radius: 1rem;
|
|
||||||
border-bottom: 1px dashed var(--main-border-color);
|
|
||||||
}
|
|
@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2023",
|
"target": "es2023",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@ -18,13 +14,22 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"incremental": true
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
"lib/slug.js"
|
"lib/slug.js",
|
||||||
|
".next/types/**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user