init
This commit is contained in:
commit
2c1f2adcf8
28 changed files with 4155 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
.next/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# supMDX
|
||||||
|
A template to make blog-like site with MDX
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
- `supMDX.yml`
|
10
components/Footer.tsx
Normal file
10
components/Footer.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import config from '#config';
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
const {startYear: year0, siteAuthor} = config;
|
||||||
|
const year = new Date().getFullYear();
|
||||||
|
|
||||||
|
return <footer>{siteAuthor &&
|
||||||
|
<div>Copyright © {year>year0 ? `${year0}-${year}` : year} {siteAuthor} All rights reserved.</div>
|
||||||
|
}</footer>;
|
||||||
|
}
|
35
components/MDXRoot.tsx
Normal file
35
components/MDXRoot.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import Head from 'next/head';
|
||||||
|
import Nav from './Nav';
|
||||||
|
import MetaInfo from './MetaInfo';
|
||||||
|
import type {HeadingInfo} from '@sup39/rehype-mdx-export-headings';
|
||||||
|
|
||||||
|
export type MDXProps = {
|
||||||
|
children: JSX.Element
|
||||||
|
data: {
|
||||||
|
pathname: string,
|
||||||
|
},
|
||||||
|
meta: Partial<{
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
h1: string
|
||||||
|
[key: string]: any
|
||||||
|
}>
|
||||||
|
headings: HeadingInfo[]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function MDXRoot({children, data: {pathname}, meta={}, headings}: MDXProps) {
|
||||||
|
const {title, description} = meta;
|
||||||
|
const h1 = meta.h1 ?? title;
|
||||||
|
return <>
|
||||||
|
<Head>
|
||||||
|
<title>{title}</title>
|
||||||
|
{description && <meta name="description" content={description} />}
|
||||||
|
</Head>
|
||||||
|
<Nav pathname={pathname} headings={headings} />
|
||||||
|
<main>
|
||||||
|
{h1 ? <h1>{h1}</h1> : <></>}
|
||||||
|
<MetaInfo data={meta} />
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</>;
|
||||||
|
}
|
12
components/MetaInfo.tsx
Normal file
12
components/MetaInfo.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import config from '#config';
|
||||||
|
|
||||||
|
export default function MetaInfo({data}: {data: {[_: string]: any}}) {
|
||||||
|
const {metaFields: fields = []} = config;
|
||||||
|
return <div>{fields.map(({label, prop}) => {
|
||||||
|
const val = data[prop];
|
||||||
|
return val == null ? null : <div key={prop}>
|
||||||
|
<span>{label}</span>
|
||||||
|
<span>{val}</span>
|
||||||
|
</div>;
|
||||||
|
})}</div>;
|
||||||
|
}
|
53
components/Nav.tsx
Normal file
53
components/Nav.tsx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import {useState} from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import NavHeader from './NavHeader';
|
||||||
|
import type {HeadingInfo} from '@sup39/rehype-mdx-export-headings';
|
||||||
|
import config from '#config';
|
||||||
|
|
||||||
|
export type NavEntryInfo = {
|
||||||
|
name: string
|
||||||
|
link: string
|
||||||
|
children?: NavEntryInfo[]|null
|
||||||
|
};
|
||||||
|
|
||||||
|
export function NavEntry<Body, >({
|
||||||
|
entry: {name, link, children}, dir, here, children: childrenJSX,
|
||||||
|
}: {entry: NavEntryInfo, dir: string, here: string, children?: Body}) {
|
||||||
|
const [toggle, setToggle] = useState(false);
|
||||||
|
const href = dir+link;
|
||||||
|
const isHere = href.replace(/\/$/, '')===here; // remove trailing slash
|
||||||
|
const entryCls = 'nav-entry'+(isHere ? ' nav-here' : '');
|
||||||
|
return children?.length ? <div className={'nav-dir'+(toggle ? ' nav-fold-open' : '')}><>
|
||||||
|
<div className={entryCls}>
|
||||||
|
<Link href={href}>{name}</Link>
|
||||||
|
<svg viewBox="0 0 8 8" onClick={()=>setToggle(e=>!e)}><polyline points="6 3 4 5 2 3"></polyline></svg>
|
||||||
|
</div>
|
||||||
|
{isHere ? childrenJSX : <></>}
|
||||||
|
<div className='nav-dir-child'>{
|
||||||
|
children.map(entry => <NavEntry key={entry.link} entry={entry} dir={href} here={here}>{childrenJSX}</NavEntry>)
|
||||||
|
}</div>
|
||||||
|
</></div> : <div className={entryCls}>
|
||||||
|
<Link href={href}>{name}</Link>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Nav({children, headings, pathname}: {
|
||||||
|
children?: JSX.Element
|
||||||
|
headings: HeadingInfo[]
|
||||||
|
pathname: string
|
||||||
|
}) {
|
||||||
|
const [navFold, setNavFold] = useState(false);
|
||||||
|
|
||||||
|
const headingsJSX = <ul className=''>{headings.map(({label, id}) => <li key={id}>
|
||||||
|
<a href={'#'+id}>{label}</a>
|
||||||
|
</li>)}</ul>;
|
||||||
|
|
||||||
|
return <nav className={navFold ? 'open' : ''}>
|
||||||
|
<NavHeader onToggleFold={()=>setNavFold(e=>!e)} />
|
||||||
|
{children}
|
||||||
|
<div className='nav-root'>
|
||||||
|
{config.nav.map(entry => <NavEntry key={entry.link} entry={entry} dir={'/'} here={pathname} />)}
|
||||||
|
{headingsJSX}
|
||||||
|
</div>
|
||||||
|
</nav>;
|
||||||
|
}
|
10
components/NavHeader.tsx
Normal file
10
components/NavHeader.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function NavHeader({onToggleFold}: {onToggleFold?: ()=>void}) {
|
||||||
|
return <header>
|
||||||
|
<Link href="/" id="icon-link">
|
||||||
|
<div style={{fontSize: '1.5em'}}>supMDX</div>
|
||||||
|
</Link>
|
||||||
|
<div className="menu-toggle" onClick={onToggleFold} />
|
||||||
|
</header>;
|
||||||
|
}
|
12
components/mdx.tsx
Normal file
12
components/mdx.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/** <S $="span" _=".a.b.c" className="extra class-name">...</S> */
|
||||||
|
export function S<E extends React.ElementType='span'>({
|
||||||
|
$: TagName = 'span',
|
||||||
|
_: modifier = '',
|
||||||
|
className, children, ...props
|
||||||
|
}: {
|
||||||
|
$?: string,
|
||||||
|
_?: string,
|
||||||
|
} & React.ComponentProps<E>) {
|
||||||
|
const cls = [className, ...(modifier.match(/\.(\w+)/g) ?? [])].map(s => s.slice(1)).join(' ');
|
||||||
|
return <TagName className={cls} {...props}>{children}</TagName>;
|
||||||
|
}
|
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
30
next.config.mjs
Normal file
30
next.config.mjs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import mdx from '@next/mdx';
|
||||||
|
import remarkFrontmatter from 'remark-frontmatter';
|
||||||
|
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
||||||
|
import ExportHeadings from '@sup39/rehype-mdx-export-headings';
|
||||||
|
import ComponentWrapper from '@sup39/rehype-mdx-component-wrapper';
|
||||||
|
|
||||||
|
const withMDX = mdx({
|
||||||
|
extension: /\.mdx?$/,
|
||||||
|
options: {
|
||||||
|
remarkPlugins: [
|
||||||
|
remarkFrontmatter,
|
||||||
|
() => remarkMdxFrontmatter({name: 'meta'}),
|
||||||
|
],
|
||||||
|
rehypePlugins: [
|
||||||
|
() => ExportHeadings({tags: ['h2'], name: 'headings'}),
|
||||||
|
() => ComponentWrapper({props: ['headings', 'meta']}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export default withMDX({
|
||||||
|
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
|
||||||
|
trailingSlash: true,
|
||||||
|
webpack(config) {
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.ya?ml$/,
|
||||||
|
use: 'yaml-loader',
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
});
|
67
package.json
Normal file
67
package.json
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"name": "supMDX",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.md,.mdx ."
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"next/core-web-vitals",
|
||||||
|
"@sup39/typescript"
|
||||||
|
],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"*.ts",
|
||||||
|
"*.tsx"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-undef": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"*.mdx"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"plugin:mdx/recommended"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-trailing-spaces": "off",
|
||||||
|
"indent": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"eslintIgnore": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@mdx-js/loader": "^2.1.5",
|
||||||
|
"@mdx-js/react": "^2.1.5",
|
||||||
|
"@next/mdx": "^13.0.2",
|
||||||
|
"@sup39/rehype-mdx-component-wrapper": "^0.1.0",
|
||||||
|
"@sup39/rehype-mdx-export-headings": "^0.1.1",
|
||||||
|
"next": "^13.0.2",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"remark-frontmatter": "^4.0.1",
|
||||||
|
"remark-mdx-frontmatter": "^2.1.1",
|
||||||
|
"sass": "^1.56.0",
|
||||||
|
"yaml-loader": "^0.8.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@sup39/eslint-config-typescript": "^0.1.2",
|
||||||
|
"@types/node": "18.11.9",
|
||||||
|
"@types/react": "18.0.24",
|
||||||
|
"eslint": "^8.26.0",
|
||||||
|
"eslint-config-next": "^13.0.2",
|
||||||
|
"eslint-plugin-mdx": "^2.0.5",
|
||||||
|
"typescript": "4.8.4"
|
||||||
|
}
|
||||||
|
}
|
20
pages/_app.tsx
Normal file
20
pages/_app.tsx
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
import type {AppProps} from 'next/app';
|
||||||
|
import {MDXProvider} from '@mdx-js/react';
|
||||||
|
import {S} from '@/mdx';
|
||||||
|
import '../styles/index.sass';
|
||||||
|
|
||||||
|
// add anchor to all headings having id
|
||||||
|
const hx = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;
|
||||||
|
const extendedHx = Object.fromEntries(hx.map(H => [H,
|
||||||
|
({children, id, ...props}: React.ComponentProps<(typeof hx)[number]>) => <H id={id} {...props}>
|
||||||
|
{id && <a className="anchor" />}
|
||||||
|
{children}
|
||||||
|
</H>,
|
||||||
|
]));
|
||||||
|
|
||||||
|
export default function App({Component, pageProps, router: {pathname}}: AppProps) {
|
||||||
|
return <MDXProvider components={{S, ...extendedHx}}>
|
||||||
|
<Component data={{pathname}} {...pageProps} />
|
||||||
|
</MDXProvider>;
|
||||||
|
}
|
8
pages/index.mdx
Normal file
8
pages/index.mdx
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
title: supMDX
|
||||||
|
description: You can write any meta data you want
|
||||||
|
author: me
|
||||||
|
---
|
||||||
|
|
||||||
|
## h2
|
||||||
|
### h3
|
27
styles/a.sass
Normal file
27
styles/a.sass
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
a, .link
|
||||||
|
color: #72E5DB
|
||||||
|
text-decoration: none
|
||||||
|
cursor: pointer
|
||||||
|
a:hover, .link:hover
|
||||||
|
color: #72E5DB
|
||||||
|
text-decoration: underline
|
||||||
|
a:active, .link:active
|
||||||
|
color: #A0E5DF
|
||||||
|
text-decoration: underline
|
||||||
|
|
||||||
|
a.anchor
|
||||||
|
float: left
|
||||||
|
padding-right: 4px
|
||||||
|
margin-left: -24px
|
||||||
|
a.anchor:before
|
||||||
|
content: ""
|
||||||
|
background-image: url("https://cdn.sup39.dev/img/anchor.svg")
|
||||||
|
width: 16px
|
||||||
|
height: 16px
|
||||||
|
vertical-align: middle
|
||||||
|
margin: 0 0 4px 0
|
||||||
|
display: inline-block
|
||||||
|
visibility: hidden
|
23
styles/code.sass
Normal file
23
styles/code.sass
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
code
|
||||||
|
font-family: Menlo, Monaco, Consolas, "Courier New", "Hiragino Kaku Gothic ProN", monospace
|
||||||
|
padding: 2px 4px
|
||||||
|
margin: 0 1px 0 0
|
||||||
|
font-size: 90%
|
||||||
|
font-variant-numeric: slashed-zero
|
||||||
|
background-color: #4a4a4a
|
||||||
|
border-radius: 4px
|
||||||
|
white-space: nowrap
|
||||||
|
pre code
|
||||||
|
white-space: break-spaces
|
||||||
|
background: unset
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
pre
|
||||||
|
background: #333
|
||||||
|
color: #fff
|
||||||
|
border-radius: 4px
|
||||||
|
overflow-x: auto
|
||||||
|
padding: 0.6em
|
35
styles/heading.sass
Normal file
35
styles/heading.sass
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6
|
||||||
|
margin: 0
|
||||||
|
h1
|
||||||
|
font-size: 2.5em
|
||||||
|
font-weight: 600
|
||||||
|
line-height: 1.3
|
||||||
|
margin-bottom: 0.5em
|
||||||
|
h2
|
||||||
|
font-size: 1.8em
|
||||||
|
font-weight: 500
|
||||||
|
line-height: 1.3
|
||||||
|
padding-bottom: 0.1em
|
||||||
|
border-bottom: 1px solid var(--bd)
|
||||||
|
margin-top: 1.0em
|
||||||
|
margin-bottom: 0.25em
|
||||||
|
h3
|
||||||
|
font-size: 1.5em
|
||||||
|
font-weight: bold
|
||||||
|
line-height: 1.6
|
||||||
|
margin-top: 0.5em
|
||||||
|
h4
|
||||||
|
font-size: 1.2em
|
||||||
|
font-weight: 600
|
||||||
|
margin-top: 1em
|
||||||
|
h5
|
||||||
|
font-size: 1.1em
|
||||||
|
font-weight: 500
|
||||||
|
margin-top: 1em
|
||||||
|
h6
|
||||||
|
font-size: 1em
|
||||||
|
font-weight: 400
|
||||||
|
margin-top: 1em
|
11
styles/index.sass
Normal file
11
styles/index.sass
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
@import './vars.sass'
|
||||||
|
@import './nav.sass'
|
||||||
|
@import './menu-toggle.sass'
|
||||||
|
@import './heading.sass'
|
||||||
|
@import './span.sass'
|
||||||
|
@import './a.sass'
|
||||||
|
@import './code.sass'
|
||||||
|
@import './misc.sass'
|
||||||
|
|
||||||
|
@media only screen and (min-width: 768px)
|
||||||
|
@import './nav.pc.sass'
|
37
styles/menu-toggle.sass
Normal file
37
styles/menu-toggle.sass
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
.menu-toggle
|
||||||
|
width: 20px
|
||||||
|
height: 20px
|
||||||
|
display: block
|
||||||
|
cursor: pointer
|
||||||
|
.menu-toggle:before
|
||||||
|
top: 30%
|
||||||
|
.menu-toggle:after
|
||||||
|
top: 70%
|
||||||
|
|
||||||
|
.menu-toggle:before,
|
||||||
|
.menu-toggle:after
|
||||||
|
position: absolute
|
||||||
|
content: ""
|
||||||
|
width: 100%
|
||||||
|
height: 2px
|
||||||
|
transform: translate(0, -50%)
|
||||||
|
background: var(--fg)
|
||||||
|
transition: all .25s ease-out
|
||||||
|
|
||||||
|
.open
|
||||||
|
.menu-toggle:before
|
||||||
|
transform: translate(0, -50%) rotate(135deg)
|
||||||
|
.menu-toggle:after
|
||||||
|
transform: translate(0, -50%) rotate(-135deg)
|
||||||
|
.menu-toggle:before,
|
||||||
|
.menu-toggle:after
|
||||||
|
top: 50%
|
||||||
|
left: -10%
|
||||||
|
width: 120%
|
||||||
|
|
||||||
|
@media only screen and (min-width: 768px)
|
||||||
|
.menu-toggle
|
||||||
|
display: none
|
261
styles/misc.sass
Normal file
261
styles/misc.sass
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
html
|
||||||
|
font-size: 16px
|
||||||
|
body
|
||||||
|
color: var(--fg)
|
||||||
|
background: var(--bg)
|
||||||
|
line-height: 1.6
|
||||||
|
font-weight: 300
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, Verdana, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif
|
||||||
|
font-variant-numeric: tabular-nums
|
||||||
|
margin: 0
|
||||||
|
*
|
||||||
|
box-sizing: border-box
|
||||||
|
|
||||||
|
/**** font ****/
|
||||||
|
html:lang(zh-TW) body
|
||||||
|
font-family: "SF Pro TC","SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif
|
||||||
|
|
||||||
|
/**** image ****/
|
||||||
|
article img
|
||||||
|
max-width: 100%
|
||||||
|
height: auto
|
||||||
|
margin: 1em 0
|
||||||
|
|
||||||
|
#icon-link
|
||||||
|
text-decoration: none
|
||||||
|
> *
|
||||||
|
float: left
|
||||||
|
.icon
|
||||||
|
width: 72px
|
||||||
|
height: 72px
|
||||||
|
.icon-text
|
||||||
|
height: 72px
|
||||||
|
font-size: 27px
|
||||||
|
font-weight: 600
|
||||||
|
line-height: 1.2
|
||||||
|
padding-left: 16px
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
text-align: center
|
||||||
|
.pink
|
||||||
|
font-size: 24px
|
||||||
|
#icon-link:link
|
||||||
|
color: unset
|
||||||
|
|
||||||
|
/**** main ****/
|
||||||
|
main
|
||||||
|
padding: 24px
|
||||||
|
article
|
||||||
|
font-weight: 300
|
||||||
|
h3
|
||||||
|
+ table, + h4
|
||||||
|
margin-top: 0.5em
|
||||||
|
h4 + table
|
||||||
|
margin-top: 0.5em
|
||||||
|
table
|
||||||
|
margin-block-start: 1em
|
||||||
|
margin-block-end: 1em
|
||||||
|
table,
|
||||||
|
table th,
|
||||||
|
table td
|
||||||
|
border: solid 1px var(--bd)
|
||||||
|
border-collapse: collapse
|
||||||
|
padding: 4px
|
||||||
|
> ul
|
||||||
|
padding-inline-start: 2em
|
||||||
|
margin-block-start: 0.5em
|
||||||
|
margin-block-end: 1em
|
||||||
|
ul ul
|
||||||
|
padding-inline-start: 1.25em
|
||||||
|
> h2 + ul
|
||||||
|
padding-inline-start: 1.5em
|
||||||
|
|
||||||
|
footer
|
||||||
|
background: #18181e
|
||||||
|
background: #222
|
||||||
|
font-size: 0.75em
|
||||||
|
line-height: 1em
|
||||||
|
padding: 1.5em 2em
|
||||||
|
margin-top: 1em
|
||||||
|
|
||||||
|
p + *.compact
|
||||||
|
margin-block-start: -1em
|
||||||
|
*.compact
|
||||||
|
margin-block-start: 0em
|
||||||
|
|
||||||
|
/**** table ****/
|
||||||
|
.tac
|
||||||
|
text-align: center
|
||||||
|
.tar
|
||||||
|
text-align: right
|
||||||
|
table.tb-r tbody
|
||||||
|
text-align: right
|
||||||
|
|
||||||
|
/**** form ****/
|
||||||
|
form > div
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
> *
|
||||||
|
margin: 3px
|
||||||
|
|
||||||
|
/**** input ****/
|
||||||
|
input, textarea
|
||||||
|
color: var(--fg)
|
||||||
|
background: #222
|
||||||
|
border: var(--bd) solid 1px
|
||||||
|
font-size: 1em
|
||||||
|
input[invalid]
|
||||||
|
background: #600
|
||||||
|
input[type="number"]
|
||||||
|
text-align: right
|
||||||
|
|
||||||
|
/**** button ****/
|
||||||
|
button,
|
||||||
|
input[type="button"],
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="reset"]
|
||||||
|
color: var(--fg)
|
||||||
|
background: #2a8
|
||||||
|
border: #2a8 1px solid
|
||||||
|
border-radius: 4px
|
||||||
|
font-size: 14px
|
||||||
|
cursor: pointer
|
||||||
|
button:hover,
|
||||||
|
input[type="button"]:hover,
|
||||||
|
input[type="submit"]:hover,
|
||||||
|
input[type="reset"]:hover
|
||||||
|
border: #197 1px solid
|
||||||
|
background: #197
|
||||||
|
button:active,
|
||||||
|
input[type="button"]:active,
|
||||||
|
input[type="submit"]:active,
|
||||||
|
input[type="reset"]:active
|
||||||
|
border: #075 1px solid
|
||||||
|
background: #075
|
||||||
|
|
||||||
|
button:disabled
|
||||||
|
background: #444
|
||||||
|
border: #555 1px solid
|
||||||
|
cursor: not-allowed
|
||||||
|
button[variant="warning"]
|
||||||
|
background: #c87603
|
||||||
|
border: #c87603 1px solid
|
||||||
|
button[variant="warning"]:enabled:hover
|
||||||
|
background: #b60
|
||||||
|
border: #b60 1px solid
|
||||||
|
button[variant="warning"]:enabled:active
|
||||||
|
background: #a50
|
||||||
|
border: #b60 1px solid
|
||||||
|
button[variant="danger"]:enabled
|
||||||
|
background: #c32
|
||||||
|
border: #c32 1px solid
|
||||||
|
button[variant="danger"]:enabled:hover
|
||||||
|
background: #b21
|
||||||
|
border: #b21 1px solid
|
||||||
|
button[variant="danger"]:enabled:active
|
||||||
|
background: #a10
|
||||||
|
border: #b21 1px solid
|
||||||
|
button.sm
|
||||||
|
font-size: 12px
|
||||||
|
|
||||||
|
/**** div.bt ****/
|
||||||
|
div.bt-plus, div.bt-minus
|
||||||
|
position: relative
|
||||||
|
width: 1.2em
|
||||||
|
height: 1.2em
|
||||||
|
border: #2ee5b8 1px solid
|
||||||
|
border-radius: 4px
|
||||||
|
cursor: pointer
|
||||||
|
user-select: none
|
||||||
|
-webkit-user-select: none
|
||||||
|
-moz-user-select: none
|
||||||
|
-khtml-user-select: none
|
||||||
|
-ms-user-select: none
|
||||||
|
div.bt-plus:before,
|
||||||
|
div.bt-plus:after,
|
||||||
|
div.bt-minus:before
|
||||||
|
content: ""
|
||||||
|
position: absolute
|
||||||
|
top: 50%
|
||||||
|
left: 50%
|
||||||
|
transform: translate(-50%, -50%)
|
||||||
|
width: 50%
|
||||||
|
height: 1px
|
||||||
|
background: var(--fg)
|
||||||
|
div.bt-plus:after
|
||||||
|
width: 1px
|
||||||
|
height: 50%
|
||||||
|
|
||||||
|
/**** variant ****/
|
||||||
|
span.danger
|
||||||
|
color: #f66
|
||||||
|
button.danger
|
||||||
|
background: #a33
|
||||||
|
|
||||||
|
/**** details ****/
|
||||||
|
details
|
||||||
|
border: 1px solid
|
||||||
|
padding: 0.5em 1em
|
||||||
|
margin-block-start: 0.5em
|
||||||
|
margin-block-end: 0.5em
|
||||||
|
> summary
|
||||||
|
padding: 4px 0.5em
|
||||||
|
margin: -0.5em -1em -0.5em
|
||||||
|
details[open]
|
||||||
|
padding-bottom: 0
|
||||||
|
> summary
|
||||||
|
border-bottom: 1px solid
|
||||||
|
margin: -0.5em -1em 0
|
||||||
|
> ul, > ol
|
||||||
|
padding-inline-start: 1.5em
|
||||||
|
|
||||||
|
/**** misc ****/
|
||||||
|
video
|
||||||
|
max-width: 100%
|
||||||
|
.noselect
|
||||||
|
-webkit-touch-callout: none // iOS Safari
|
||||||
|
-webkit-user-select: none // Safari
|
||||||
|
-khtml-user-select: none // Konqueror HTML
|
||||||
|
-moz-user-select: none // Old versions of Firefox
|
||||||
|
-ms-user-select: none // Internet Explorer/Edge
|
||||||
|
user-select: none // Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox
|
||||||
|
|
||||||
|
/**** hide ****/
|
||||||
|
div.hide-ctn
|
||||||
|
position: relative
|
||||||
|
color: #fff
|
||||||
|
margin-block-start: -1em
|
||||||
|
margin-block-end: 2em
|
||||||
|
z-index:-1
|
||||||
|
*
|
||||||
|
position: absolute
|
||||||
|
font-size: 0.25em
|
||||||
|
color: #0000
|
||||||
|
|
||||||
|
/**** highlight ****/
|
||||||
|
table.code-lnum
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
width: 100%
|
||||||
|
border: none
|
||||||
|
td
|
||||||
|
border: none
|
||||||
|
td:first-child
|
||||||
|
padding-left: 0.5em
|
||||||
|
padding-right: 1em
|
||||||
|
text-align: right
|
||||||
|
td:last-child
|
||||||
|
width: 100%
|
||||||
|
white-space: pre
|
||||||
|
.hljs-comment
|
||||||
|
color: #7d6
|
||||||
|
.hljs-keyword
|
||||||
|
color: #ffa
|
||||||
|
font-weight: bold
|
||||||
|
.hljs-number, .hljs-string
|
||||||
|
color: #ffb7e7
|
32
styles/nav.pc.sass
Normal file
32
styles/nav.pc.sass
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
nav
|
||||||
|
width: var(--nav-width)
|
||||||
|
overflow: auto
|
||||||
|
position: fixed
|
||||||
|
left: 0
|
||||||
|
top: 0
|
||||||
|
bottom: 0
|
||||||
|
border-bottom: none
|
||||||
|
border-right: 1px solid var(--bd)
|
||||||
|
padding: 1em 1em
|
||||||
|
header
|
||||||
|
margin-bottom: 1em
|
||||||
|
.menu-toggle
|
||||||
|
display: none
|
||||||
|
.nav-root
|
||||||
|
height: auto
|
||||||
|
opacity: 1
|
||||||
|
visibility: visible
|
||||||
|
|
||||||
|
main, footer
|
||||||
|
margin-left: var(--nav-width)
|
||||||
|
main
|
||||||
|
padding: 24px 32px
|
||||||
|
|
||||||
|
*:hover > a.anchor:before
|
||||||
|
visibility: visible
|
||||||
|
|
||||||
|
.mobile-only
|
||||||
|
display: none
|
107
styles/nav.sass
Normal file
107
styles/nav.sass
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
$yellow: #ff9
|
||||||
|
$bd: var(--bd)
|
||||||
|
|
||||||
|
/** mobile */
|
||||||
|
nav
|
||||||
|
width: 100%
|
||||||
|
background: #28282e
|
||||||
|
border-bottom: 1px solid var(--bd)
|
||||||
|
border-right: none
|
||||||
|
padding: 1.25em 1.25em
|
||||||
|
|
||||||
|
header
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
.menu-toggle
|
||||||
|
position: absolute
|
||||||
|
top: 50%
|
||||||
|
right: 1em
|
||||||
|
transform: translate(-50%, -50%)
|
||||||
|
|
||||||
|
.nav-root
|
||||||
|
height: 0
|
||||||
|
// opacity: 0
|
||||||
|
visibility: hidden
|
||||||
|
|
||||||
|
*
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
|
||||||
|
a
|
||||||
|
display: block
|
||||||
|
color: #eee
|
||||||
|
|
||||||
|
.nav-dir-child
|
||||||
|
padding-left: 1em
|
||||||
|
|
||||||
|
.nav-here, .nav-here a,
|
||||||
|
.nav-here + ul, .nav-here + ul a
|
||||||
|
color: $yellow
|
||||||
|
ul
|
||||||
|
list-style-type: square
|
||||||
|
margin-block-start: 0
|
||||||
|
margin-block-end: 0
|
||||||
|
padding-inline-start: 24px
|
||||||
|
|
||||||
|
.nav-root
|
||||||
|
> div
|
||||||
|
border-top: 1px solid $bd
|
||||||
|
padding: 0.5em 0.5em
|
||||||
|
|
||||||
|
/** heading list */
|
||||||
|
> ul
|
||||||
|
border-top: 1px solid $bd
|
||||||
|
padding-top: 0.75em
|
||||||
|
// margin-bottom: 0.5em
|
||||||
|
|
||||||
|
|
||||||
|
/** here */
|
||||||
|
.nav-here
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
|
||||||
|
/** container of entry */
|
||||||
|
.nav-entry
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
> a
|
||||||
|
flex-grow: 1
|
||||||
|
|
||||||
|
> svg
|
||||||
|
stroke: #9ff
|
||||||
|
fill: none
|
||||||
|
stroke-width: 1
|
||||||
|
stroke-linecap: round
|
||||||
|
stroke-linejoin: round
|
||||||
|
width: 1.2em
|
||||||
|
height: 1.2em
|
||||||
|
cursor: pointer
|
||||||
|
border-radius: 50%
|
||||||
|
> svg:hover
|
||||||
|
background: #18181e
|
||||||
|
|
||||||
|
|
||||||
|
/** folder hide */
|
||||||
|
.nav-dir-child
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.nav-fold-open > .nav-dir-child
|
||||||
|
display: block
|
||||||
|
|
||||||
|
.nav-fold-open > .nav-entry > svg
|
||||||
|
rotate: 180deg
|
||||||
|
|
||||||
|
nav.open
|
||||||
|
header
|
||||||
|
margin-bottom: 1.25em
|
||||||
|
.nav-root
|
||||||
|
height: auto
|
||||||
|
opacity: 1
|
||||||
|
visibility: visible
|
||||||
|
// transition: opacity 0.4s ease-in-out
|
29
styles/span.sass
Normal file
29
styles/span.sass
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
.mint
|
||||||
|
color: var(--mint)
|
||||||
|
.pink
|
||||||
|
color: var(--pink)
|
||||||
|
.kw
|
||||||
|
color: #9ff
|
||||||
|
font-weight: bold
|
||||||
|
.mk
|
||||||
|
color: #ff99e5
|
||||||
|
font-weight: bold
|
||||||
|
.y
|
||||||
|
color: #ff7
|
||||||
|
font-weight: bold
|
||||||
|
.note
|
||||||
|
color: #777
|
||||||
|
.arg
|
||||||
|
color: #da8cff
|
||||||
|
font-weight: bold
|
||||||
|
.u
|
||||||
|
text-decoration: underline
|
||||||
|
font-weight: bold
|
||||||
|
.mono
|
||||||
|
font-family: monospace
|
||||||
|
span[title]
|
||||||
|
cursor: help
|
||||||
|
text-decoration: dotted underline
|
10
styles/vars.sass
Normal file
10
styles/vars.sass
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2022 sup39
|
||||||
|
|
||||||
|
:root
|
||||||
|
--bg: #222228
|
||||||
|
--fg: #eee
|
||||||
|
--bd: #777
|
||||||
|
--mint: #2ee5b8
|
||||||
|
--pink: #e58acf
|
||||||
|
--nav-width: 256px
|
16
supMDX-env.d.ts
vendored
Normal file
16
supMDX-env.d.ts
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
declare module '#config' {
|
||||||
|
import type {NavEntry} from '@/Nav';
|
||||||
|
type Config = {
|
||||||
|
startYear: number
|
||||||
|
siteAuthor?: string
|
||||||
|
metaFields?: {label: string, prop: string}[]
|
||||||
|
nav: NavEntry[]
|
||||||
|
};
|
||||||
|
const config: Config;
|
||||||
|
export default config;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.yaml' {
|
||||||
|
const data: any;
|
||||||
|
export default data;
|
||||||
|
}
|
7
supMDX.yml
Normal file
7
supMDX.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
startYear: 2022
|
||||||
|
siteAuthor: <Edit author name in supMDX.yml>
|
||||||
|
metaFields:
|
||||||
|
- {prop: author, label: 'Author: '}
|
||||||
|
- {prop: createdAt, label: 'Created at '}
|
||||||
|
- {prop: updatedAt, label: 'Updated at '}
|
||||||
|
nav: []
|
37
tsconfig.json
Normal file
37
tsconfig.json
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["components/*"],
|
||||||
|
"#/*": ["pages/*"],
|
||||||
|
"#config": ["supMDX.yml"],
|
||||||
|
"%/*": ["utils/*"]
|
||||||
|
},
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"incremental": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue