Compare commits
No commits in common. "910f531207936bea816372198332ee26e36ba57a" and "5c9a871b2547febe4fad908e18550a86acf54668" have entirely different histories.
910f531207
...
5c9a871b25
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022-2024 Paul W.
|
Copyright (c) 2022-2023 Paul W.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
28
README.md
28
README.md
@ -1,20 +1,20 @@
|
|||||||
# PaulW.XYZ
|
# PaulW.XYZ
|
||||||
|
|
||||||
A [Next.js](https://nextjs.com) website that mainly involves generating content out of a bunch of markdown files contained in `notes/` and `posts/` which contain rough, unorganized yet useful information and thought-out articles respectively.
|
A [Next.js](https://nextjs.com) website that mainly involves generating content out of a bunch of markdown files contained in `notes/` and `posts/` which contain rough, unorganized yet useful information and thought-out articles respectively. It's still a work in progress as I have no clear direction I want to take this site toward. However, it is something that I will always keep in check; as I use this as a hub for whatever I work on, especially if it involves a lot of reading.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
## Third-Party Licenses
|
|
||||||
Any trademarks listed on this site are the property of their respective owners. This site neither endorses nor is affiliated with any of the owners. Any source code available on any of the pages is without warranty of any kind and the use of such is at your own risk.
|
Any trademarks listed on this site are the property of their respective owners. This site neither endorses nor is affiliated with any of the owners. Any source code available on any of the pages is without warranty of any kind and the use of such is at your own risk.
|
||||||
|
|
||||||
### Fonts
|
### Third-party
|
||||||
|
#### Fonts
|
||||||
|
|
||||||
[Hack](https://github.com/source-foundry/Hack)
|
- [Hack](https://github.com/source-foundry/Hack)
|
||||||
- © 2018 Source Foundry Authors
|
- © 2018 Source Foundry Authors
|
||||||
- MIT License
|
- MIT License
|
||||||
|
- [Cantarell](https://github.com/davelab6/cantarell)
|
||||||
[Cantarell](https://github.com/davelab6/cantarell)
|
- © 2009-2010, [Understanding Limited](mailto:dave@understandinglimited.com)
|
||||||
- © 2009-2010, [Understanding Limited](mailto:dave@understandinglimited.com)
|
- Open Font License, Version 1.1
|
||||||
- Open Font License, Version 1.1
|
- [EB Garamond](https://github.com/georgd/EB-Garamond)
|
||||||
|
- © 2010-2013 [Georg Duffner](http://www.georgduffner.at)
|
||||||
[EB Garamond](https://github.com/georgd/EB-Garamond)
|
- Open Font License, Version 1.1
|
||||||
- © 2010-2013 [Georg Duffner](http://www.georgduffner.at)
|
|
||||||
- Open Font License, Version 1.1
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
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,18 +1,25 @@
|
|||||||
import Title from './title';
|
import Title from './title';
|
||||||
import Container, { ChildrenType } from './container';
|
|
||||||
|
type ChildrenType = JSX.Element | Array<ChildrenType>;
|
||||||
|
|
||||||
type LayoutProps = {
|
type LayoutProps = {
|
||||||
children?: ChildrenType,
|
children?: ChildrenType,
|
||||||
removeContainer?: boolean,
|
removeContainer?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function Layout(props: LayoutProps) {
|
function Container(props: {children?: ChildrenType, ignore?: boolean}) {
|
||||||
|
if (props.ignore)
|
||||||
|
return <>{props.children}</>;
|
||||||
|
return <div className='container'>
|
||||||
|
{props.children}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Layout(props : LayoutProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title />
|
<Title />
|
||||||
<Container ignore={props.removeContainer}>
|
<Container ignore={props.removeContainer}>{props.children}</Container>
|
||||||
{props.children}
|
|
||||||
</Container>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
103
components/lists.tsx
Normal file
103
components/lists.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import style from '../styles/lists.module.css';
|
||||||
|
import React, { ReactElement } from 'react';
|
||||||
|
|
||||||
|
export interface listItem {
|
||||||
|
[x: string]: any;
|
||||||
|
children?: listItem[] | string[];
|
||||||
|
url?: string;
|
||||||
|
type?: string;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function toListItem(record: Record<string, any>): listItem | null {
|
||||||
|
if (!record.title)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let children: listItem[] | string[] = [];
|
||||||
|
if (Array.isArray(record.children) && record.children.length) {
|
||||||
|
|
||||||
|
let lchildren: listItem[] = [];
|
||||||
|
let schildren: string[] = [];
|
||||||
|
for (const child of record.children) {
|
||||||
|
if (typeof child === 'string') {
|
||||||
|
schildren.push(child);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const lChild = toListItem(child);
|
||||||
|
if (lChild)
|
||||||
|
lchildren.push(lChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lchildren.length) {
|
||||||
|
children = schildren;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
children = [...lchildren, ...schildren.map((s: string): listItem => {
|
||||||
|
return { title: s };
|
||||||
|
})];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(record, {
|
||||||
|
title: record.title,
|
||||||
|
url: record.url,
|
||||||
|
children: children.length ? children : undefined,
|
||||||
|
type: record.type?.length ? record.type : undefined,
|
||||||
|
description: record.description,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapChild(
|
||||||
|
obj: listItem | string,
|
||||||
|
level: number,
|
||||||
|
typeMap? : Record<string, (o: listItem) => JSX.Element>
|
||||||
|
) {
|
||||||
|
if (typeof obj === 'string') {
|
||||||
|
if (obj === '')
|
||||||
|
return <></>
|
||||||
|
return <span className={style.listItem}>{obj}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.title === '')
|
||||||
|
return <></>
|
||||||
|
|
||||||
|
const desc = obj.description
|
||||||
|
? <span className={style.listItemDesc}>{obj.description}</span>
|
||||||
|
: <></>;
|
||||||
|
|
||||||
|
if (obj.url)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={style.listItem}><a href={obj.url}>{obj.title}</a></span>
|
||||||
|
{desc}
|
||||||
|
</>);
|
||||||
|
|
||||||
|
if (!obj.children) {
|
||||||
|
let cb;
|
||||||
|
if (obj.type && typeMap) {
|
||||||
|
cb = typeMap[obj.type]
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb
|
||||||
|
? cb(obj)
|
||||||
|
: (<><span className={style.listItem}>{obj.title}</span>{desc}</>);
|
||||||
|
}
|
||||||
|
|
||||||
|
let title: ReactElement;
|
||||||
|
|
||||||
|
if (level >= 0 && level <= 4)
|
||||||
|
title = React.createElement(`h${level + 2}`, {}, obj.title);
|
||||||
|
else
|
||||||
|
title = React.createElement('strong', {}, obj.title);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={level < 4 && `block ${style.block}` || ''}>
|
||||||
|
{title}
|
||||||
|
{obj.description ? <p className={style.desc}>{obj.description}</p> : <></>}
|
||||||
|
<div>
|
||||||
|
{obj.children.map(l => mapChild(l, level + 1, typeMap))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
@ -4,17 +4,12 @@ import Pages from '../public/external.json';
|
|||||||
function QuickLinks() {
|
function QuickLinks() {
|
||||||
return (
|
return (
|
||||||
<div className='block'>
|
<div className='block'>
|
||||||
<h2>Quick Links</h2>
|
<div className='h2'>Quick Links</div>
|
||||||
{
|
{
|
||||||
Object.entries(Pages).map(([title, link], i) => {
|
Object.entries(Pages).map(([title, link], i) => {
|
||||||
const extern = link.match(/^http/) && `blue extern` || '';
|
const extern = link.match(/^http/) && `blue extern` || '';
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link key={i} href={link} className={`${extern} link button`}>{title}</Link>
|
||||||
key={i}
|
|
||||||
href={link}
|
|
||||||
className={`${extern} link button`}>
|
|
||||||
{title}
|
|
||||||
</Link>
|
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,38 +2,22 @@ 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);
|
||||||
.map(([slug, note]) => {
|
|
||||||
return {
|
|
||||||
slug,
|
|
||||||
title: note.title,
|
|
||||||
mtime: new Date(note.mtime)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sort(
|
|
||||||
(a, b) => {
|
|
||||||
return b.mtime.getTime() - a.mtime.getTime();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className='block'>
|
<div className='block'>
|
||||||
<h2>Recent Notes</h2>
|
<div className='h2'>Recent Notes</div>
|
||||||
<ul>
|
{notes?.slice(0, 10)
|
||||||
{notes?.slice(0, 5)
|
.map(([slug, note]: any) => {
|
||||||
.map(({slug, title, mtime}) => {
|
return <Link key={slug} href={`/notes/${slug}`} className={`button link`}>{note.title}</Link>
|
||||||
return (
|
|
||||||
<li key={mtime.getTime()} >
|
|
||||||
<Link href={`/notes/${slug}`}>{title}</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
notes.length > 5 &&
|
notes.length > 10 &&
|
||||||
<Link href='/notes'>More...</Link>
|
<div>
|
||||||
|
<Link href='/notes' className='h5'>More...</Link>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,46 +1,34 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { toRelativeDate } from "../lib/date";
|
import date from "../lib/date";
|
||||||
import style from '../styles/recent-posts.module.css';
|
import style from '../styles/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 }) {
|
|
||||||
return (
|
|
||||||
<div className={style.block}>
|
|
||||||
<span className={style.postDate}>
|
|
||||||
{toRelativeDate(new Date(otime))}
|
|
||||||
</span>
|
|
||||||
<div className={style.postTitle}>
|
|
||||||
<Link href={`/posts/${slug}`}>
|
|
||||||
{title}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function RecentPosts() {
|
function RecentPosts() {
|
||||||
const posts = Object.entries(PostsInfo).reverse();
|
const posts = Object.entries(PostsInfo);
|
||||||
if (!posts.length)
|
if (!posts.length)
|
||||||
return <></>;
|
return <></>;
|
||||||
return (
|
return (
|
||||||
<div className='block'>
|
<div className='block'>
|
||||||
<h2>Recent Posts</h2>
|
<div className='h2'>Recent Posts</div>
|
||||||
<div className={style.container}>
|
<div className={style.container}>
|
||||||
{posts?.slice(0, 10)
|
{posts?.slice(0, 10)
|
||||||
.map(([slug, post]: any, i: number) => {
|
.map(([slug, post]: any) => {
|
||||||
return (
|
return <div className={style.block} key={post.slug}>
|
||||||
<PostBlock
|
<span className={style.postDate}>
|
||||||
key={i}
|
{date.toRelativeDate(new Date(post.otime))}
|
||||||
slug={slug}
|
</span>
|
||||||
title={post.title}
|
<div className={style.postTitle}>
|
||||||
otime={post.otime} />
|
<Link href={`/posts/${slug}`}>
|
||||||
);
|
{post.title}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
posts.length > 10 &&
|
posts.length > 10 &&
|
||||||
<div className={style.more}>
|
<div className={style.more}>
|
||||||
<Link href='/posts' >More...</Link>
|
<Link href='/posts' className='h5'>More...</Link>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@ function createPathElements(ancestors: Array<{ name: string, path: string }>) {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function Title() {
|
function Title() {
|
||||||
|
|
||||||
@ -28,15 +28,13 @@ function Title() {
|
|||||||
let currRoot: SiteSubPages = SiteMap.subpages;
|
let currRoot: SiteSubPages = SiteMap.subpages;
|
||||||
let title: string | null = null;
|
let title: string | null = null;
|
||||||
if (pagePath !== '/') {
|
if (pagePath !== '/') {
|
||||||
const subPaths = pagePath.split('?')[0].split('#')[0].split('/');
|
const subPaths = pagePath.split('/');
|
||||||
for (const p of subPaths.slice(1, subPaths.length)) {
|
for (const p of subPaths.slice(1, subPaths.length)) {
|
||||||
splitPath.push({ name: currRoot[p].title, path: p });
|
splitPath.push({ name: currRoot[p].title, path: p });
|
||||||
|
|
||||||
if (currRoot === undefined
|
if (currRoot === undefined
|
||||||
|| currRoot[p] === undefined
|
|| currRoot[p] === undefined
|
||||||
|| currRoot[p].subpages === undefined)
|
|| currRoot[p].subpages !== undefined)
|
||||||
break;
|
currRoot = currRoot[p].subpages!;
|
||||||
currRoot = currRoot[p].subpages!;
|
|
||||||
}
|
}
|
||||||
if (splitPath !== undefined && splitPath.length > 0)
|
if (splitPath !== undefined && splitPath.length > 0)
|
||||||
title = splitPath.pop()!.name;
|
title = splitPath.pop()!.name;
|
||||||
@ -55,11 +53,9 @@ function Title() {
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${style.nav} h1`}>
|
<div className={`${style.nav} h1`}>
|
||||||
{
|
{title
|
||||||
title
|
? <><Link href='/'>PaulW.XYZ</Link> / {pathElements}{title}</>
|
||||||
? <><Link href='/'>PaulW.XYZ</Link> / {pathElements}{title}</>
|
: <>PaulW.XYZ /</>}
|
||||||
: <>PaulW.XYZ /</>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
69
lib/date.ts
69
lib/date.ts
@ -1,4 +1,3 @@
|
|||||||
// getMonth() method ranges from 0-11 so no reason to account for it
|
|
||||||
const months = [
|
const months = [
|
||||||
'January',
|
'January',
|
||||||
'February',
|
'February',
|
||||||
@ -14,50 +13,35 @@ const months = [
|
|||||||
'December'
|
'December'
|
||||||
];
|
];
|
||||||
|
|
||||||
function toHumanReadableDate(date: Date | string, disable?: { year?: boolean, month?: boolean, day?: boolean }) {
|
const ordSfx = ['','st','nd','rd','th'];
|
||||||
const oDate = (typeof date === 'string') ? new Date(date) : date;
|
|
||||||
|
function toHumanReadableDate(date: Date | string, disable?: {year?: boolean, month?: boolean, day?: boolean}) {
|
||||||
|
const oDate = (typeof date === 'string')? new Date(date): date;
|
||||||
|
|
||||||
const year = oDate.getFullYear();
|
const year = oDate.getFullYear();
|
||||||
const month = months[oDate.getMonth()];
|
const month = months[oDate.getMonth()];
|
||||||
const day = oDate.getDate();
|
const day = oDate.getDate();
|
||||||
|
|
||||||
let out = !disable?.day ? `${day}${getOrdinalDaySuffix(day)}` : '';
|
let sfx;
|
||||||
|
if (day >= 1 && day <= 3)
|
||||||
|
sfx = ordSfx[day];
|
||||||
|
else
|
||||||
|
sfx = ordSfx[4];
|
||||||
|
|
||||||
|
let out = !disable?.day ? `${day}${sfx}` : '';
|
||||||
out = !disable?.month ? `${out} ${month}` : out;
|
out = !disable?.month ? `${out} ${month}` : out;
|
||||||
out = !disable?.year ? `${out} ${year}` : out;
|
out = !disable?.year ? `${out} ${year}` : out;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toRelativeDate(date: Date | string): string {
|
||||||
export function getOrdinalDaySuffix(day: number) {
|
const oDate = (typeof date === 'string')? new Date(date): date;
|
||||||
switch (day) {
|
|
||||||
case 1:
|
|
||||||
case 21:
|
|
||||||
case 31:
|
|
||||||
return 'st';
|
|
||||||
case 2:
|
|
||||||
case 22:
|
|
||||||
return 'nd';
|
|
||||||
case 3:
|
|
||||||
case 23:
|
|
||||||
return 'rd';
|
|
||||||
default:
|
|
||||||
return 'th';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toRelativeDate(date: Date | string): string {
|
|
||||||
const oDate = (typeof date === 'string') ? new Date(date) : date;
|
|
||||||
|
|
||||||
|
|
||||||
if (!isValid(oDate)) {
|
|
||||||
return 'Invalid Date';
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const diff = now.getTime() - oDate.getTime();
|
const diff = now.getTime() - oDate.getTime();
|
||||||
|
|
||||||
let tdiff = Math.floor(diff / 1000);
|
let tdiff = Math.floor(diff/1000);
|
||||||
|
|
||||||
if (tdiff < 0) {
|
if (tdiff < 0) {
|
||||||
return toHumanReadableDate(oDate);
|
return toHumanReadableDate(oDate);
|
||||||
@ -67,14 +51,14 @@ export function toRelativeDate(date: Date | string): string {
|
|||||||
return `${tdiff} seconds ago`;
|
return `${tdiff} seconds ago`;
|
||||||
}
|
}
|
||||||
|
|
||||||
tdiff = Math.floor(tdiff / 60);
|
tdiff = Math.floor(tdiff/60);
|
||||||
if (tdiff < 60) {
|
if (tdiff < 60) {
|
||||||
return `${tdiff} minute${tdiff === 1 ? '' : 's'} ago`;
|
return `${tdiff} minute${tdiff === 1? '' : 's'} ago`;
|
||||||
}
|
}
|
||||||
|
|
||||||
tdiff = Math.floor(tdiff / 60);
|
tdiff = Math.floor(tdiff/60);
|
||||||
if (tdiff < 24) {
|
if (tdiff < 24) {
|
||||||
return `${tdiff} hour${tdiff === 1 ? '' : 's'} ago`;
|
return `${tdiff} hour${tdiff === 1? '' : 's'} ago`;
|
||||||
}
|
}
|
||||||
if (tdiff < 48) {
|
if (tdiff < 48) {
|
||||||
return `Yesterday`;
|
return `Yesterday`;
|
||||||
@ -82,24 +66,15 @@ export function toRelativeDate(date: Date | string): string {
|
|||||||
|
|
||||||
if (oDate.getFullYear() != now.getFullYear())
|
if (oDate.getFullYear() != now.getFullYear())
|
||||||
return toHumanReadableDate(oDate);
|
return toHumanReadableDate(oDate);
|
||||||
return toHumanReadableDate(oDate, { year: true });
|
return toHumanReadableDate(oDate, {year: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFullMonth(month: number) {
|
function isValid(date: any) {
|
||||||
if (month >= 1 && month <= 12)
|
return (new Date(date)).toString() === 'Invalid Date';
|
||||||
return months[month];
|
|
||||||
return 'Invalid Month';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValid(date: any) {
|
|
||||||
return (new Date(date)).toString() !== 'Invalid Date';
|
|
||||||
}
|
|
||||||
|
|
||||||
const DateTool = {
|
const DateTool = {
|
||||||
toRelativeDate,
|
toRelativeDate,
|
||||||
getFullMonth,
|
isValid
|
||||||
isValid,
|
|
||||||
getOrdinalDaySuffix,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DateTool;
|
export default DateTool;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const config = {
|
module.exports = {
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: ['en-US'],
|
locales: ['en-US'],
|
||||||
defaultLocale: 'en-US'
|
defaultLocale: 'en-US'
|
||||||
@ -32,15 +32,9 @@ const config = {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return config;
|
return config
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
domains: ['avatars.githubusercontent.com']
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.ANALYZE) {
|
|
||||||
const bundleAnalyzer = require('@next/bundle-analyzer')({
|
|
||||||
enabled: true
|
|
||||||
});
|
|
||||||
module.exports = bundleAnalyzer(config);
|
|
||||||
} else {
|
|
||||||
module.exports = config;
|
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
# Web Browsers
|
|
||||||
Extensions/Plugins I Use on All Supported Browsers:
|
|
||||||
- uBlock Origin
|
|
||||||
- Decentraleyes
|
|
||||||
- FastForward (RIP)
|
|
||||||
- CanvasBlocker
|
|
||||||
- ClearURLs
|
|
||||||
- Greasemonkey/Tampermonkey
|
|
||||||
- Indie Wiki Buddy
|
|
||||||
- SingleFile
|
|
||||||
|
|
||||||
Product/Service-specific Extensions:
|
|
||||||
- SteamDB
|
|
||||||
- Return YouTube Dislike
|
|
||||||
- SponsorBlock
|
|
||||||
|
|
||||||
## Chromium
|
|
||||||
- [Chromium Source Docs](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/README.md)
|
|
||||||
|
|
||||||
## Firefox
|
|
||||||
- [Firefox Source Docs](https://firefox-source-docs.mozilla.org/)
|
|
||||||
|
|
||||||
### Reducing UI element padding
|
|
||||||
- Go to the browser's [about\:config](#) page
|
|
||||||
- Set `browser.uidensity` equal to `1`
|
|
||||||
|
|
||||||
## Safari
|
|
||||||
- [Webkit Docs](https://docs.webkit.org/index.html)
|
|
68
notes/lua.md
68
notes/lua.md
@ -1,68 +0,0 @@
|
|||||||
# Lua Programming Language
|
|
||||||
|
|
||||||
## Lua 5.4 C API
|
|
||||||
|
|
||||||
|
|
||||||
## Lua 5.4 Bytecode
|
|
||||||
|
|
||||||
> [!note]
|
|
||||||
> These are **unstable** and may differ in different versions of the language.
|
|
||||||
> They are not part of the language specification but an implementation detail, which in this case is the reference implementation.
|
|
||||||
|
|
||||||
> [!note]
|
|
||||||
> The reference implementation used to have a stack based but now uses a register based VM similar to how modern real computer architectures.
|
|
||||||
|
|
||||||
The instructions are 32 bits wide; every instruction has an opcode that takes up 7 bits, which leaves out 25 bits for the addresses and values.
|
|
||||||
|
|
||||||
The instructions work with three register referred to as: A, B, C; each are of length 8 bits.
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th>31</th><th>...</th><th>24</th><th>23</th><th>...</th><th>16</th><th>15</th><th>14</th><th>...</th><th>7</th><th>6</th><th>...</th><th>0</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr>
|
|
||||||
<td>iABC</td>
|
|
||||||
<td colspan='3' style='text-align:center'>C (8 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>B (8 bits)</td>
|
|
||||||
<td style='text-align:center'>k (1 bit)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>A (8 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>OP (7 bits)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>iABx</td>
|
|
||||||
<td colspan='7' style='text-align:center'>B (17 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>A (8 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>OP (7 bits)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>iAsBx</td>
|
|
||||||
<td colspan='7' style='text-align:center'>signed B 17 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>A (8 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>OP (7 bits)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>iAx</td>
|
|
||||||
<td colspan='10' style='text-align:center'>Ax (25 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>OP (7 bits)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>sJ</td>
|
|
||||||
<td colspan='10' style='text-align:center'>signed jump address (25 bits)</td>
|
|
||||||
<td colspan='3' style='text-align:center'>OP (7 bits)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- arithmetic to calculate the lengths used from https://www.lua.org/source/5.4/lopcodes.h.html
|
|
||||||
A = 8
|
|
||||||
B = 8
|
|
||||||
C = 8
|
|
||||||
Bx = A + B + 1 -- 17
|
|
||||||
Ax = A + Bx -- 25
|
|
||||||
sJ = A + Bx -- 25
|
|
||||||
```
|
|
||||||
This page contains excerpts from Lua's source code which is the copyright of Lua.org, PUC-Rio and is licensed under the MIT License.
|
|
||||||
[lua.org/license.html](https://www.lua.org/license.html)
|
|
17
notes/nintendo-switch.md
Normal file
17
notes/nintendo-switch.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Nintendo Switch
|
||||||
|
|
||||||
|
<a href='https://www.nintendo.com/switch' class='link button extern blue'>Official Website</a>
|
||||||
|
<a href='https://developer.nintendo.com/' class='link button extern blue'>Developer Portal</a>
|
||||||
|
|
||||||
|
## Third-party Software
|
||||||
|
- [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere)
|
||||||
|
- custom firmware
|
||||||
|
|
||||||
|
## Third-party Resources
|
||||||
|
- [DekuDeals](https://www.dekudeals.com/)
|
||||||
|
- price tracker for games with support for all major US retailers
|
||||||
|
|
||||||
|
|
||||||
|
## High-level Emulators
|
||||||
|
- [yuzu](https://yuzu-emu.org/)
|
||||||
|
- [Ryujinx](https://ryujinx.org/)
|
40
notes/os.md
40
notes/os.md
@ -1,40 +0,0 @@
|
|||||||
# Operating Systems
|
|
||||||
## Windows
|
|
||||||
|
|
||||||
### Package Managers
|
|
||||||
|
|
||||||
- Chocolatey
|
|
||||||
- requires Administrator permissions
|
|
||||||
- Winget
|
|
||||||
- comes with Windows
|
|
||||||
- (it doesn't work half of the time for me)
|
|
||||||
|
|
||||||
### Mounting ISO, CUE images
|
|
||||||
|
|
||||||
Windows versions 8 and above natively support mounting ISOs. However CUE images are not supported.
|
|
||||||
WinCDEmu is a lightweight, open-source disc emulator that supports mounting CUE, NRG, IMG, ISO, etc. images.
|
|
||||||
- [WinCDEmu Website](https://wincdemu.sysprogs.org/)
|
|
||||||
- [Source (GitHub)](https://github.com/sysprogs/WinCDEmu)
|
|
||||||
- [Portable Version](https://wincdemu.sysprogs.org/portable/)
|
|
||||||
|
|
||||||
### Master Control Panel / God Mode
|
|
||||||
(Misnomer; you probably won't use this either)
|
|
||||||
|
|
||||||
Shows a list of all the available settings on Windows in a single view.
|
|
||||||
|
|
||||||
Open it by exceuting the following command or saving it as a shortcut: `explorer.exe shell:::{ED7BA470-8E54-465E-825C-99712043E01C}`
|
|
||||||
|
|
||||||
## MacOS
|
|
||||||
|
|
||||||
### Package Manager
|
|
||||||
|
|
||||||
- [HomeBrew](https://brew.sh)
|
|
||||||
- package manager everyone uses but it is noticeably slow
|
|
||||||
|
|
||||||
### Video Players
|
|
||||||
|
|
||||||
- IINA
|
|
||||||
- video player based on mpv with native macOS UI
|
|
||||||
- mpv
|
|
||||||
- mpv doesn't have a brew cask for Apple silicon; stolen-mpv exists but it is x86 only
|
|
||||||
- mpv brew formula is the cli tool which works pretty well but it is not as nice as packaged applications
|
|
@ -1,52 +0,0 @@
|
|||||||
# Programming Resources
|
|
||||||
|
|
||||||
A handy list of blog posts, articles, videos, and books that I would probably
|
|
||||||
refer to someone or within something.
|
|
||||||
|
|
||||||
- Untangling Lifetimes: The Arena Allocator
|
|
||||||
|
|
||||||
Making performant dynamic manual memory management in C feel almost like
|
|
||||||
garbage collection.
|
|
||||||
|
|
||||||
https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator
|
|
||||||
|
|
||||||
- Ryan Fleury's UI Series
|
|
||||||
|
|
||||||
Semi-paywalled
|
|
||||||
|
|
||||||
https://www.rfleury.com/p/ui-series-table-of-contents
|
|
||||||
|
|
||||||
- Immediate-Mode Graphical User Interfaces (2005)
|
|
||||||
|
|
||||||
https://caseymuratori.com/blog_0001
|
|
||||||
|
|
||||||
https://www.youtube.com/watch?v=Z1qyvQsjK5Y
|
|
||||||
|
|
||||||
- What Color is Your Function?
|
|
||||||
|
|
||||||
https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
|
|
||||||
|
|
||||||
- Real-time audio programming 101: time waits for nothing
|
|
||||||
|
|
||||||
http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing
|
|
||||||
|
|
||||||
- Triangulation
|
|
||||||
|
|
||||||
https://www.humus.name/index.php?ID=228
|
|
||||||
|
|
||||||
- Quantifying the Performance of Garbage Collection vs. Explicit Memory
|
|
||||||
Management
|
|
||||||
|
|
||||||
https://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf
|
|
||||||
|
|
||||||
- Typing is Hard
|
|
||||||
|
|
||||||
https://3fx.ch/typing-is-hard.html
|
|
||||||
|
|
||||||
- The Aggregate Magic Algorithms
|
|
||||||
|
|
||||||
http://aggregate.org/MAGIC/
|
|
||||||
|
|
||||||
- Memory Allocation Strategies
|
|
||||||
|
|
||||||
https://www.gingerbill.org/series/memory-allocation-strategies/
|
|
@ -1,21 +1,15 @@
|
|||||||
# Steam Deck
|
# Steam Deck
|
||||||
|
|
||||||
- [Official Website](https://www.steamdeck.com/)
|
<a href='https://www.steamdeck.com/' class='link button extern blue'>Official Website</a>
|
||||||
|
|
||||||
## Third-party Software
|
## Third-party Software
|
||||||
|
|
||||||
- [Decky Plugin Loader](https://decky.xyz/)
|
* [Decky Plugin Loader](https://decky.xyz/)
|
||||||
- Source: [GitHub / SteamDeckHomebrew](https://github.com/SteamDeckHomebrew)
|
* Installer: [decky\_installer.desktop](https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/decky_installer.desktop)
|
||||||
- Installer:
|
|
||||||
[decky_installer.desktop](https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/decky_installer.desktop)
|
|
||||||
|
|
||||||
## Console-like Youtube in Gaming Mode
|
## Access Console-like Youtube in Gaming Mode
|
||||||
|
|
||||||
- Using Chromium's undocumented command-line options, the user agent can be
|
* Using Chromium's undocumented command-line options, the user agent can be changed to PlayStation's, Xbox's or Tizen's (Samsung's TV OS) and the application can be launched in full screen by using the `--kiosk` flag. The following XDG Desktop Configuration, for example, can be used and added as a non-Steam game while in Desktop mode for access in gaming mode
|
||||||
changed to PlayStation's, Xbox's or Tizen's (Samsung's TV OS) and the
|
|
||||||
application can be launched in full screen by using the `--kiosk` flag. The
|
|
||||||
following XDG Desktop Configuration, for example, can be used and added as a
|
|
||||||
non-Steam game while in Desktop mode for access in gaming mode
|
|
||||||
|
|
||||||
```cfg
|
```cfg
|
||||||
#!/usr/bin/env xdg-open
|
#!/usr/bin/env xdg-open
|
||||||
@ -27,45 +21,34 @@ GenericName=Online Video Platform
|
|||||||
Comment=An online video-sharing, social media platform
|
Comment=An online video-sharing, social media platform
|
||||||
Exec=/usr/bin/flatpak run --branch=master --arch=x86_64 --file-forwarding org.chromium.Chrome @@ %F @@ --user-agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox Series X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36 Edge/20.02' --kiosk 'https://www.youtube.com/tv'
|
Exec=/usr/bin/flatpak run --branch=master --arch=x86_64 --file-forwarding org.chromium.Chrome @@ %F @@ --user-agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox Series X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36 Edge/20.02' --kiosk 'https://www.youtube.com/tv'
|
||||||
Terminal=false
|
Terminal=false
|
||||||
MimeType=text/plain; # $XDG_PATH contains the paths used to fetch icons, extensions for supported formats are optional Icon=com.youtube.tv
|
MimeType=text/plain;
|
||||||
|
# $XDG_PATH contains the paths used to fetch icons, extensions for supported formats are optional
|
||||||
|
Icon=com.youtube.tv
|
||||||
```
|
```
|
||||||
|
|
||||||
- Firefox can also be used however the supported command-line options are
|
* Firefox can also be used however the supported command-line options are limited
|
||||||
limited
|
* The URL is https://www.youtube.com/tv
|
||||||
- The URL for the TV user interface is https://www.youtube.com/tv
|
* Without the user agent change, the above URL is inaccessible
|
||||||
- Without the user agent change, the above URL is inaccessible and will redirect
|
* Adblockers like uBlock Origin, AdBlock Plus (both tested) do not remove ads unlike on the desktop site
|
||||||
you to the desktop version of the website
|
* Choosing the Xbox user agent is recommended as button prompts match the Steam Deck's `ABXY` button layout
|
||||||
- Adblockers like uBlock Origin, AdBlock Plus (both tested) do not remove ads
|
* The Electron framework can be used to build a wrapper for the URL. This is the preferable method as it supports exiting from within the application, while browsers only support manual termination from the Steam menu. E.g. (assuming you can build native linux binaries on a device)
|
||||||
even if they work with the desktop version
|
|
||||||
- Choosing an Xbox user agent is recommended as button prompts match the Steam
|
```javascript
|
||||||
Deck's `ABXY` button layout
|
const { app, BrowserWindow } = require('electron');
|
||||||
- The Electron framework can be used to build a wrapper for the URL
|
app.whenReady()
|
||||||
- This is the preferable method as it supports exiting from within the
|
.then(() => {
|
||||||
application, while browsers only support manual termination from the Steam
|
const win = new BrowserWindow({
|
||||||
menu.
|
|
||||||
- Sample code for the electron app (assuming you can build linux binaries
|
|
||||||
for the target platform):
|
|
||||||
```javascript
|
|
||||||
// sample code to get started
|
|
||||||
const { app, BrowserWindow } = require('electron');
|
|
||||||
app
|
|
||||||
.whenReady()
|
|
||||||
.then(() => {
|
|
||||||
const win = new BrowserWindow({
|
|
||||||
backgroundColor: '#2e2c29',
|
backgroundColor: '#2e2c29',
|
||||||
kiosk: true,
|
kiosk: true
|
||||||
});
|
});
|
||||||
win.maximize();
|
win.maximize();
|
||||||
win.loadURL('https://youtube.com/tv');
|
win.loadURL('https://youtube.com/tv');
|
||||||
win.webContents.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox Series X) '
|
const wc = win.webContents;
|
||||||
+ 'AppleWebKit/537.36 (KHTML, like Gecko) '
|
wc.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox Series X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36 Edge/20.02'
|
||||||
+ 'Chrome/48.0.2564.82 Safari/537.36 Edge/20.02';
|
})
|
||||||
})
|
.catch(()=>{}); // swallow errs
|
||||||
.catch(() => { });
|
```
|
||||||
```
|
|
||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
|
|
||||||
- When using a dock or a hub to connect to an external display, ensure the
|
* When using a dock or a hub to connect to an external display, ensure the display supports the refresh rate set on the device as some TVs and other displays only support refresh rates that are multiples of 30Hz
|
||||||
display supports the refresh rate set on the device; some TVs and some
|
|
||||||
monitors only support refresh rates that are multiples of 30Hz
|
|
||||||
|
@ -1,33 +1,27 @@
|
|||||||
# Steam Client
|
# Steam Client
|
||||||
|
|
||||||
- [Steam Store](https://store.steampowered.com)
|
<a href='https://store.steampowered.com' class='link button extern blue'>Steam Store</a>
|
||||||
- [SteamCMD](https://developer.valvesoftware.com/wiki/SteamCMD)
|
<a href='https://developer.valvesoftware.com/wiki/SteamCMD' class='link button extern blue'>SteamCMD</a>
|
||||||
|
|
||||||
## Accessing the Console
|
## Accessing the Console
|
||||||
|
- Use the following URIs on a browser or a file manager to open GUI client with the console:
|
||||||
- Use the following URIs on a browser or a file manager to open GUI client with
|
- `steam://nav/console`
|
||||||
the console:
|
- `steam://open/console`
|
||||||
- `steam://nav/console`
|
- will not work if the Steam client is running in the background
|
||||||
- `steam://open/console`
|
|
||||||
- will not work if the Steam client is running in the background
|
|
||||||
- The `-console` flag can be used with the client executable
|
- The `-console` flag can be used with the client executable
|
||||||
- Alternatively, SteamCMD, a command-line only version of the Steam client, can
|
- Alternatively, SteamCMD, a command-line only version of the Steam client, can be used
|
||||||
be used
|
- [Windows Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip)
|
||||||
- [Windows
|
- [Linux Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz)
|
||||||
Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip)
|
- [macOS Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd_osx.tar.gz)
|
||||||
- [Linux
|
|
||||||
Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz)
|
|
||||||
- [macOS
|
|
||||||
Binary](https://steamcdn-a.akamaihd.net/client/installer/steamcmd_osx.tar.gz)
|
|
||||||
|
|
||||||
## Downloading Older Depots
|
## Downloading Older Depots
|
||||||
|
|
||||||
Download a single depot (used to download older versions of applications/games):
|
Download a single depot (used to download older versions of applications/games):
|
||||||
|
```
|
||||||
|
download_depot <appid> <depotid> [<target manifestid>] [<delta manifestid>] [<depot flags filter>]
|
||||||
|
```
|
||||||
|
|
||||||
`download_depot <appid> <depotid> [<target manifestid>] [<delta manifestid>][<depot flags filter>]`
|
[SteamDB](https://steamdb.info/) can be used to find the required argument values.
|
||||||
|
|
||||||
[SteamDB](https://steamdb.info/) can be used to find the required argument
|
|
||||||
values.
|
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
@ -38,19 +32,18 @@ values.
|
|||||||
## Third-party Resources
|
## Third-party Resources
|
||||||
|
|
||||||
- [SteamDB](https://steamdb.info/)
|
- [SteamDB](https://steamdb.info/)
|
||||||
- tracks depot changes, price history, everything steam
|
- tracks depot changes, price history, everything steam
|
||||||
- [SteamGifts](https://steamgifts.com/)
|
- [SteamGifts](https://steamgifts.com/)
|
||||||
- giveaway Steam keys or take part in giveaways
|
- giveaway Steam keys or take part in giveaways
|
||||||
- [SteamTradeMatcher](https://steamtradematcher.com/)
|
- [SteamTradeMatcher](https://steamtradematcher.com/)
|
||||||
- one-to-one trading of items on Steam
|
- one-to-one trading of items on Steam
|
||||||
- [ArchiSteamFarm](https://asf.justarchi.net)
|
- [ArchiSteamFarm](https://asf.justarchi.net)
|
||||||
- useful bot written in C# to farm trading cards for owned games that can be
|
- useful bot written in C# to farm trading cards for owned games that can be sold
|
||||||
sold
|
|
||||||
- [IsThereAnyDeal](https://isthereanydeal.com)
|
- [IsThereAnyDeal](https://isthereanydeal.com)
|
||||||
- tracks game deals for steam, steam key stores and other platforms
|
- tracks game deals for steam, steam key stores and other platforms
|
||||||
- somewhat broken although it is being migrated and modernized, see [New
|
- somewhat broken although it is being migrated and modernized, see [New ITAD](https://new.isthereanydeal.com)
|
||||||
ITAD](https://new.isthereanydeal.com)
|
|
||||||
- [gg.deals](https://gg.deals)
|
- [gg.deals](https://gg.deals)
|
||||||
- newer than and similar to IsThereAnyDeal with modern UI
|
- newer than and similar to IsThereAnyDeal with modern UI
|
||||||
- [SteamGridDB](https://steamgriddb.com/)
|
- [SteamGridDB](https://steamgriddb.com/)
|
||||||
- custom video game assets for games available and not available on steam
|
- custom video game assets for games available and not available on steam
|
||||||
|
|
||||||
|
@ -15,13 +15,10 @@
|
|||||||
"react-markdown": "^9.0.0",
|
"react-markdown": "^9.0.0",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"remark-directive": "^3.0.0",
|
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remark-github-admonitions-to-directives": "^2.0.0",
|
|
||||||
"uri-js": "^4.4.1"
|
"uri-js": "^4.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next/bundle-analyzer": "^14.0.1",
|
|
||||||
"@svgr/webpack": "^6.5.1",
|
"@svgr/webpack": "^6.5.1",
|
||||||
"@types/node": "^18.17.17",
|
"@types/node": "^18.17.17",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
|
@ -8,16 +8,16 @@ function AboutPage() {
|
|||||||
return (
|
return (
|
||||||
<Layout >
|
<Layout >
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<p>Paul's Personal Website. I go by <a href='https://github.com/LambdaPaul'>@LambdaPaul</a> on GitHub and <a href='https://x.com/lambda_paul'>@lambda_paul</a> on X/Twitter.</p>
|
<p>This is a personal website written by <a href='https://github.com/LambdaPaul'>@LambdaPaul</a>.</p>
|
||||||
<p>Why did I create this?
|
<p>Why did I write this?
|
||||||
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>
|
I do not really know, at least the content I put here.
|
||||||
<p>Most services/products are keen on going against what Steph Ango calls <a href='https://stephango.com/file-over-app'>File over app</a>, a philosophy in which you prioritize 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>
|
I wanted a place on the web where I wanted to put everything I think is worth looking at some point in the future.
|
||||||
|
It seems wise to have things up here even though they may not be worthwhile, as many things ultimately are not.</p>
|
||||||
<p>Got any questions, concerns, or issues? Contact me via email: <code>lambdapaul [at] pm [dot] me</code>.</p>
|
<p>Got any questions, concerns, or issues? Contact me via email: <code>lambdapaul [at] pm [dot] me</code>.</p>
|
||||||
</section>
|
</section>
|
||||||
<hr />
|
<hr />
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<p>Source for this site is available on GitHub: <a href='https://github.com/LambdaPaul/www'>https://github.com/LambdaPaul/www</a></p>
|
<p>Source for this site is available at <a className='button link extern blue' href='https://github.com/LambdaPaul/www'>GitHub / LambdaPaul / www</a></p>
|
||||||
<p>Relevant information regarding the source is available on the repo and is also provided below.</p>
|
<p>Relevant information regarding the source is available on the repo and is also provided below.</p>
|
||||||
</section>
|
</section>
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
|
@ -9,8 +9,7 @@ import RootInfo from '../public/home.json';
|
|||||||
function Nav() {
|
function Nav() {
|
||||||
const nav = RootInfo;
|
const nav = RootInfo;
|
||||||
return (
|
return (
|
||||||
<div className='block'>
|
<div className='block' style={{ textAlign: 'center' }}>
|
||||||
<h2>Navigation</h2>
|
|
||||||
{
|
{
|
||||||
Object.entries(nav).map(([slug, info], i) => {
|
Object.entries(nav).map(([slug, info], i) => {
|
||||||
return <Link key={i} href={slug} className='button green'>{info.title}</Link>
|
return <Link key={i} href={slug} className='button green'>{info.title}</Link>
|
||||||
@ -23,10 +22,10 @@ function Nav() {
|
|||||||
function HomePage() {
|
function HomePage() {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<QuickLinks />
|
|
||||||
<RecentPosts />
|
|
||||||
<RecentNotes />
|
|
||||||
<Nav />
|
<Nav />
|
||||||
|
<QuickLinks />
|
||||||
|
<RecentNotes />
|
||||||
|
<RecentPosts />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
|
import Layout from '../../components/layout';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import SyntaxHighlighter from 'react-syntax-highlighter';
|
import SyntaxHighlighter from 'react-syntax-highlighter';
|
||||||
import { monokaiSublime as hlTheme } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
|
import { monokaiSublime as hlTheme } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import rehypeRaw from 'rehype-raw';
|
import rehypeRaw from 'rehype-raw';
|
||||||
import remarkDirective from 'remark-directive';
|
|
||||||
import remarkGithubAdmonitionsToDirectives from 'remark-github-admonitions-to-directives';
|
|
||||||
|
|
||||||
import Layout from '../../components/layout';
|
|
||||||
import readMarkdown from '../../lib/read-markdown';
|
import readMarkdown from '../../lib/read-markdown';
|
||||||
import NotesInfo from '../../public/notes.json';
|
import NotesInfo from '../../public/notes.json';
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ interface Notes {
|
|||||||
|
|
||||||
function Markdown({ content }: any) {
|
function Markdown({ content }: any) {
|
||||||
return <ReactMarkdown
|
return <ReactMarkdown
|
||||||
remarkPlugins={[remarkGithubAdmonitionsToDirectives, remarkDirective]}
|
remarkPlugins={[remarkGfm]}
|
||||||
rehypePlugins={[rehypeRaw]}
|
rehypePlugins={[rehypeRaw]}
|
||||||
components={{
|
components={{
|
||||||
code({ node, className, children, ...props }) {
|
code({ node, className, children, ...props }) {
|
||||||
|
@ -1,55 +1,37 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import Layout from '../../components/layout';
|
import Layout from '../../components/layout';
|
||||||
import { toRelativeDate } from '../../lib/date';
|
|
||||||
|
|
||||||
|
import date 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(props: { path: string, note: { title: string, mtime: string } }) {
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ flex: '1 0 50%' }}>
|
<td style={{ flex: '1 0 50%' }}>
|
||||||
<Link href={`/notes/${note.slug}`}>
|
<Link href={props.path}>
|
||||||
{note.title}
|
{props.note.title}
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td style={{ fontStyle: 'italic' }}>
|
<td style={{ fontStyle: 'italic' }}>
|
||||||
{note.mtime && toRelativeDate(note.mtime)}
|
{props.note.mtime && date.toRelativeDate(new Date(props.note.mtime))}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NotesPage() {
|
function NotesPage() {
|
||||||
const notes = Object.entries(NotesInfo)
|
const notes = Object.entries(NotesInfo);
|
||||||
.map(([slug, note]) => {
|
|
||||||
return {
|
|
||||||
slug,
|
|
||||||
title: note.title,
|
|
||||||
mtime: new Date(note.mtime)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sort(
|
|
||||||
(a, b) => {
|
|
||||||
return b.mtime.getTime() - a.mtime.getTime();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
{
|
{!notes || notes.length === 0 && <>No notes found</> || <table>
|
||||||
!notes || notes.length === 0
|
<tbody>
|
||||||
&& <>No notes found</>
|
{notes.map(([slug, note]: any, i: number) => {
|
||||||
|| <table>
|
return <NoteEntry path={`/notes/${slug}`} note={note} key={i} />
|
||||||
<tbody>
|
})}
|
||||||
{notes.map(
|
</tbody>
|
||||||
(note: any, i: number) => {
|
</table>}
|
||||||
return (<NoteEntry note={note} key={i} />);
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
}
|
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ 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 from '../../lib/date';
|
|
||||||
|
|
||||||
interface Post {
|
interface Post {
|
||||||
title: string;
|
title: string;
|
||||||
@ -15,43 +14,7 @@ interface Posts {
|
|||||||
[slug: string]: Post
|
[slug: string]: Post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Post({ post }: { post: Post & { content: string, cover?: string } }) {
|
||||||
function TimeBlock({ mtime, otime }: { mtime: string, otime: string }) {
|
|
||||||
const ampm = (h: number) => { if (h >= 12) return 'p.m.'; return 'a.m.'; };
|
|
||||||
|
|
||||||
const mdate = new Date(mtime);
|
|
||||||
const odate = new Date(otime);
|
|
||||||
|
|
||||||
const format = (date: Date) => {
|
|
||||||
const day = date.getDay();
|
|
||||||
const ord = <sup>{DateTool.getOrdinalDaySuffix(date.getDay())}</sup>;
|
|
||||||
const month = DateTool.getFullMonth(date.getMonth());
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const hours = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
|
|
||||||
const minPrefix = date.getMinutes() < 10 ? '0' : '';
|
|
||||||
const minutes = date.getMinutes();
|
|
||||||
const twelveSfx = ampm(date.getHours());
|
|
||||||
return <>{day}{ord} {month} {year} at {hours}:{minPrefix}{minutes} {twelveSfx}</>
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ textAlign: 'right', fontSize: '16px', fontFamily: 'Cantarell', fontStyle: 'italic' }}>
|
|
||||||
{
|
|
||||||
mtime ?
|
|
||||||
<div className='mtime' data-text={mdate.toISOString()}>
|
|
||||||
Last updated: {format(mdate)}
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<></>
|
|
||||||
}
|
|
||||||
<div className='otime'>
|
|
||||||
{format(odate)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Post({ post }: { post: Post & { content: string, cover?: string, otime: string, mtime?: string } }) {
|
|
||||||
return (<>
|
return (<>
|
||||||
<Layout removeContainer={true} >
|
<Layout removeContainer={true} >
|
||||||
{<div className={style.imageBlock}
|
{<div className={style.imageBlock}
|
||||||
@ -59,16 +22,14 @@ function Post({ post }: { post: Post & { content: string, cover?: string, otime:
|
|||||||
backgroundImage:
|
backgroundImage:
|
||||||
post.cover ?
|
post.cover ?
|
||||||
`url(/assets/images/${post.cover})` :
|
`url(/assets/images/${post.cover})` :
|
||||||
'linear-gradient(to bottom right, rgb(5, 51, 11), rgb(5, 45, 13) 15%, rgb(5, 39,15) 40%, rgb(0, 30, 16) 80%)'
|
'linear-gradient(to bottom right, #565a0f, #08432c 15%, rgb(5, 39, 10) 40%, rgb(0, 22, 46) 80%)'
|
||||||
}}></div>}
|
}}></div>}
|
||||||
<div className={`${style.spacer} ${post.cover ? style.background : ''}`}></div>
|
<div className={style.spacer}></div>
|
||||||
<section className={`${style.block} block`}>
|
<section className={`${style.block} block`}>
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
<TimeBlock mtime={post.mtime} otime={post.otime} />
|
|
||||||
<ReactMarkdown>{post.content}</ReactMarkdown>
|
<ReactMarkdown>{post.content}</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<div className={style.spacer}></div>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
@ -30,7 +30,7 @@ function Posts() {
|
|||||||
return <tr key={i} style={{ alignItems: 'center' }}>
|
return <tr key={i} style={{ alignItems: 'center' }}>
|
||||||
<td style={{ display: 'inline-block', textAlign: 'right', fontSize: '0.9rem' }}>
|
<td style={{ display: 'inline-block', textAlign: 'right', fontSize: '0.9rem' }}>
|
||||||
<div style={{ fontStyle: 'italics', fontSize: '.8rem' }}>{
|
<div style={{ fontStyle: 'italics', fontSize: '.8rem' }}>{
|
||||||
post.mtime && (post.mtime != post.otime) && `Updated ${date.toRelativeDate(new Date(post.mtime))}`
|
post.mtime && `Updated ${date.toRelativeDate(new Date(post.mtime))}`
|
||||||
}</div>
|
}</div>
|
||||||
<div>{date.toRelativeDate(new Date(post.otime))}</div>
|
<div>{date.toRelativeDate(new Date(post.otime))}</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -8,14 +8,12 @@ function traverseMap(head: Site, cwd = '', depth = 0) {
|
|||||||
return [];
|
return [];
|
||||||
let elements = [];
|
let elements = [];
|
||||||
for (const [slug, info] of Object.entries(head.subpages)) {
|
for (const [slug, info] of Object.entries(head.subpages)) {
|
||||||
if (slug === 'sitemap')
|
|
||||||
continue;
|
|
||||||
const path = `${cwd}/${slug}`;
|
const path = `${cwd}/${slug}`;
|
||||||
const children = (<><dl style={{marginLeft: '3rem'}}> {traverseMap(info, path, depth + 1)}</dl></>);
|
const children = (<><ul> {traverseMap(info, path, depth + 1)}</ul></>);
|
||||||
elements.push(<>
|
elements.push(<>
|
||||||
<dt>{info.title}</dt>
|
<li>
|
||||||
<dd><Link href={path}>paulw.xyz{path}</Link></dd>
|
<Link className='button' href={path}>{info.title}</Link> {children}
|
||||||
{children}
|
</li>
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
return elements;
|
return elements;
|
||||||
@ -25,7 +23,7 @@ function SiteMapPage() {
|
|||||||
|
|
||||||
|
|
||||||
return <Layout>
|
return <Layout>
|
||||||
<dl>{traverseMap(SiteMap)}</dl>
|
<ul>{traverseMap(SiteMap)}</ul>
|
||||||
</Layout>;
|
</Layout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
{"mos-6502":{"title":"MOS 6502 Microprocessor","mtime":"2023-10-29T18:05:52.439Z"},"zilog-z80":{"title":"Zilog Z80 Microprocessor","mtime":"2023-10-29T18:07:08.579Z"},"steam":{"title":"Steam Client","mtime":"2024-02-13T22:34:17.609Z"},"steam-deck":{"title":"Steam Deck","mtime":"2024-02-13T22:53:51.919Z"},"programming-resources":{"title":"Programming Resources","mtime":"2024-04-20T19:59:46.944Z"},"os":{"title":"Operating Systems","mtime":"2024-05-10T16:07:32.581Z"},"lua":{"title":"Lua Programming Language","mtime":"2024-09-13T08:45:18.515Z"},"browsers":{"title":"Web Browsers","mtime":"2024-09-13T08:47:57.942Z"}}
|
{"mos-6502":{"title":"MOS 6502 Microprocessor","mtime":"2023-10-29T18:05:52.440Z"},"nintendo-switch":{"title":"Nintendo Switch","mtime":"2023-10-29T18:06:23.793Z"},"steam-deck":{"title":"Steam Deck","mtime":"2023-10-29T18:06:45.197Z"},"steam":{"title":"Steam Client","mtime":"2023-10-29T18:06:53.897Z"},"zilog-z80":{"title":"Zilog Z80 Microprocessor","mtime":"2023-10-29T18:07:08.580Z"}}
|
@ -1 +1 @@
|
|||||||
{"title":"PaulW.XYZ","subpages":{"posts":{"title":"Posts","subpages":{}},"notes":{"title":"Notes","subpages":{"mos-6502":{"title":"MOS 6502 Microprocessor","mtime":"2023-10-29T18:05:52.439Z"},"zilog-z80":{"title":"Zilog Z80 Microprocessor","mtime":"2023-10-29T18:07:08.579Z"},"steam":{"title":"Steam Client","mtime":"2024-02-13T22:34:17.609Z"},"steam-deck":{"title":"Steam Deck","mtime":"2024-02-13T22:53:51.919Z"},"programming-resources":{"title":"Programming Resources","mtime":"2024-04-20T19:59:46.944Z"},"os":{"title":"Operating Systems","mtime":"2024-05-10T16:07:32.581Z"},"lua":{"title":"Lua Programming Language","mtime":"2024-09-13T08:45:18.515Z"},"browsers":{"title":"Web Browsers","mtime":"2024-09-13T08:47:57.942Z"}}},"about":{"title":"About"},"sitemap":{"title":"Site Map"}}}
|
{"title":"PaulW.XYZ","subpages":{"posts":{"title":"Posts","subpages":{}},"notes":{"title":"Notes","subpages":{"mos-6502":{"title":"MOS 6502 Microprocessor","mtime":"2023-10-29T18:05:52.440Z"},"nintendo-switch":{"title":"Nintendo Switch","mtime":"2023-10-29T18:06:23.793Z"},"steam-deck":{"title":"Steam Deck","mtime":"2023-10-29T18:06:45.197Z"},"steam":{"title":"Steam Client","mtime":"2023-10-29T18:06:53.897Z"},"zilog-z80":{"title":"Zilog Z80 Microprocessor","mtime":"2023-10-29T18:07:08.580Z"}}},"about":{"title":"About"},"sitemap":{"title":"Site Map"}}}
|
@ -2,12 +2,12 @@ const fs = require('fs/promises');
|
|||||||
const { createReadStream } = require('fs');
|
const { createReadStream } = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const readline = require('readline/promises');
|
const readline = require('readline/promises');
|
||||||
// const { info } = require('console');
|
const { info } = require('console');
|
||||||
|
|
||||||
async function readFirstLines(filePath, lineCount = 1) {
|
async function readFirstLines(filePath, lineCount = 1) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const stream = createReadStream(filePath, { encoding: 'utf-8' });
|
const stream = createReadStream(filePath, 'utf-8');
|
||||||
const rl = readline.createInterface({ input: stream });
|
const rl = readline.createInterface({ input: stream });
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
const lines = [];
|
const lines = [];
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
src: url('/assets/fonts/Cantarell/Cantarell-Regular.otf') format('opentype');
|
src: url('/assets/fonts/Cantarell/Cantarell-Regular.otf') format('opentype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -25,7 +24,6 @@
|
|||||||
src: url('/assets/fonts/Cantarell/Cantarell-Thin.otf') format('opentype');
|
src: url('/assets/fonts/Cantarell/Cantarell-Thin.otf') format('opentype');
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -33,7 +31,6 @@
|
|||||||
src: url('/assets/fonts/Cantarell/Cantarell-Light.otf') format('opentype');
|
src: url('/assets/fonts/Cantarell/Cantarell-Light.otf') format('opentype');
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -41,7 +38,6 @@
|
|||||||
src: url('/assets/fonts/Cantarell/Cantarell-Bold.otf') format('opentype');
|
src: url('/assets/fonts/Cantarell/Cantarell-Bold.otf') format('opentype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -49,7 +45,6 @@
|
|||||||
src: url('/assets/fonts/Cantarell/Cantarell-ExtraBold.otf') format('opentype');
|
src: url('/assets/fonts/Cantarell/Cantarell-ExtraBold.otf') format('opentype');
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -57,7 +52,6 @@
|
|||||||
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-Regular.ttf') format('truetype');
|
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-Regular.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -65,7 +59,6 @@
|
|||||||
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-Bold.ttf') format('truetype');
|
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-Bold.ttf') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -73,39 +66,34 @@
|
|||||||
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-ExtraBold.ttf') format('truetype');
|
src: url('/assets/fonts/EB_Garamond/static/EBGaramond-ExtraBold.ttf') format('truetype');
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('/assets/fonts/Hack/hack-regular-subset.woff2') format('woff2'), url('/assets/fonts/Hack/hack-regular-subset.woff') format('woff');
|
src: url('/assets/fonts/Hack/hack-regular-subset.woff2?sha=3114f1256') format('woff2'), url('/assets/fonts/Hack/hack-regular-subset.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: normal;
|
font-weight: 400;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('/assets/fonts/Hack/hack-bold-subset.woff2') format('woff2'), url('/assets/fonts/Hack/hack-bold-subset.woff') format('woff');
|
src: url('/assets/fonts/Hack/hack-bold-subset.woff2?sha=3114f1256') format('woff2'), url('/assets/fonts/Hack/hack-bold-subset.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: bold;
|
font-weight: 700;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('/assets/fonts/Hack/hack-italic-subset.woff2') format('woff2'), url('/assets/fonts/Hack/hack-italic-webfont.woff') format('woff');
|
src: url('/assets/fonts/Hack/hack-italic-subset.woff2?sha=3114f1256') format('woff2'), url('/assets/fonts/Hack/hack-italic-webfont.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: normal;
|
font-weight: 400;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('/assets/fonts/Hack/hack-bolditalic-subset.woff2') format('woff2'), url('/assets/fonts/Hack/hack-bolditalic-subset.woff') format('woff');
|
src: url('/assets/fonts/Hack/hack-bolditalic-subset.woff2?sha=3114f1256') format('woff2'), url('/assets/fonts/Hack/hack-bolditalic-subset.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: bold;
|
font-weight: 700;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@ -296,9 +284,9 @@ li {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 818px) {
|
@media screen and (min-width: 1018px) {
|
||||||
.container {
|
.container {
|
||||||
max-width: 818px;
|
max-width: 1018px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,14 @@
|
|||||||
|
|
||||||
.block {
|
.block {
|
||||||
font-family: 'EB Garamond', 'Garamond', 'Times New Roman', Times, serif;
|
font-family: 'EB Garamond', 'Garamond', 'Times New Roman', Times, serif;
|
||||||
background-color: rgba(13, 17, 23, 0.97);
|
background-color: rgba(13, 17, 23, 0.99);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
font-size: 1.4rem;
|
font-size: 1.25rem;
|
||||||
line-height: 2.5rem;
|
line-height: 2rem;
|
||||||
padding: 2rem 1rem;
|
padding: 2rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
height: 6.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.background.spacer {
|
|
||||||
height: 25rem;
|
height: 25rem;
|
||||||
}
|
}
|
@ -30,16 +30,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.postTitle {
|
.postTitle {
|
||||||
|
font-family: 'EB Garamond', 'Garamond', 'Times New Roman', Times, serif;
|
||||||
flex: 1 1 60%;
|
flex: 1 1 60%;
|
||||||
padding: .25rem 0.75rem;
|
padding: .25rem 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postTitle a {
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px dotted transparent;
|
||||||
|
transition: border-width 100ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postTitle a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px dotted var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.postTitle a:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px dotted var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
.postDate {
|
.postDate {
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 1rem;
|
font-size: 0.9rem;
|
||||||
padding: .25rem 0.50rem;
|
padding: .25rem 0.50rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user