This commit is contained in:
2246
package-lock.json
generated
2246
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -9,20 +9,20 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^4.3.13",
|
"@astrojs/mdx": "^5.0.2",
|
||||||
"@astrojs/react": "^4.4.2",
|
"@astrojs/react": "^5.0.1",
|
||||||
"@astrojs/rss": "^4.0.14",
|
"@astrojs/rss": "^4.0.17",
|
||||||
"@astrojs/sitemap": "^3.6.0",
|
"@astrojs/sitemap": "^3.7.1",
|
||||||
"@astrojs/svelte": "^7.2.4",
|
"@astrojs/svelte": "^8.0.3",
|
||||||
"@js-temporal/polyfill": "^0.5.1",
|
"@js-temporal/polyfill": "^0.5.1",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.2.2",
|
||||||
"astro": "^5.16.6",
|
"astro": "^6.0.8",
|
||||||
"rehype-autolink-headings": "^7.1.0",
|
"rehype-autolink-headings": "^7.1.0",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
"remark-toc": "^9.0.0",
|
"remark-toc": "^9.0.0",
|
||||||
"shiki": "^3.20.0",
|
"shiki": "^4.0.2",
|
||||||
"svelte": "^5.46.1",
|
"svelte": "^5.46.1",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.2.2",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,160 +1,192 @@
|
|||||||
---
|
---
|
||||||
import type { JSX } from "astro/jsx-runtime"
|
import type { JSX } from "astro/jsx-runtime";
|
||||||
|
|
||||||
type LambdaToken = ['lambda', string, Token[], Token[]]
|
type LambdaToken = ["lambda", string, Token[], Token[]];
|
||||||
type Token =
|
type Token =
|
||||||
| ['comment', string]
|
| ["comment", string]
|
||||||
| LambdaToken
|
| LambdaToken
|
||||||
| ['operator', string]
|
| ["operator", string]
|
||||||
| ['name', string]
|
| ["name", string]
|
||||||
| ['whitespace', string]
|
| ["whitespace", string]
|
||||||
| ['placeholder', string]
|
| ["placeholder", string]
|
||||||
| ['macro', string]
|
| ["macro", string]
|
||||||
| ['keyword', string]
|
| ["keyword", string]
|
||||||
| ['string', string]
|
| ["string", string]
|
||||||
| ['number', string]
|
| ["number", string];
|
||||||
|
|
||||||
function matchParen(expr: string, greedy = false): string {
|
function matchParen(expr: string, greedy = false): string {
|
||||||
for (var i = 0, lvl = 0;
|
for (var i = 0, lvl = 0; 0 <= lvl && i < expr.length; i++) {
|
||||||
0 <= lvl && i < expr.length;
|
if (expr[i] == "(" || expr[i] == "\\") lvl++;
|
||||||
i++) {
|
else if (expr[i] == ")" || expr[i] == ".") lvl--;
|
||||||
if (expr[i] == '(' || expr[i] == '\\') lvl++
|
else if (greedy && expr[i] == "\n" && lvl == 0) break;
|
||||||
else if (expr[i] == ')' || expr[i] == '.') lvl--
|
|
||||||
else if (greedy && expr[i] == '\n' && lvl == 0) break
|
|
||||||
}
|
}
|
||||||
return expr.slice(0, i)
|
return expr.slice(0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseLambda(expr: string): LambdaToken {
|
function parseLambda(expr: string): LambdaToken {
|
||||||
expr = expr.slice(1) // Get rid of \
|
expr = expr.slice(1); // Get rid of \
|
||||||
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr)
|
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr);
|
||||||
if (!nameMatch) throw new Error(`Missing name in "${expr}"`)
|
if (!nameMatch) throw new Error(`Missing name in "${expr}"`);
|
||||||
const name = nameMatch[0].trim()
|
const name = nameMatch[0].trim();
|
||||||
const afterName = nameMatch[0].length
|
const afterName = nameMatch[0].length;
|
||||||
let type: Token[] = []
|
let type: Token[] = [];
|
||||||
let afterType = afterName
|
let afterType = afterName;
|
||||||
if (expr[afterName] == ':') {
|
if (expr[afterName] == ":") {
|
||||||
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1)
|
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1);
|
||||||
type = tokenizeExp(typeStr)
|
type = tokenizeExp(typeStr);
|
||||||
afterType += typeStr.length + 1
|
afterType += typeStr.length + 1;
|
||||||
}
|
}
|
||||||
if (expr[afterType] != '.') throw new Error(`Missing dot in "${expr.slice(afterType)}"`)
|
if (expr[afterType] != ".")
|
||||||
const body = tokenizeExp(expr.slice(afterType + 1))
|
throw new Error(`Missing dot in "${expr.slice(afterType)}"`);
|
||||||
return ['lambda', name, type, body]
|
const body = tokenizeExp(expr.slice(afterType + 1));
|
||||||
|
return ["lambda", name, type, body];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Problem
|
// Problem
|
||||||
// \f:\a:a.a.\a:a.a
|
// \f:\a:a.a.\a:a.a
|
||||||
|
|
||||||
function tokenizeExp(expr: string): Token[] {
|
function tokenizeExp(expr: string): Token[] {
|
||||||
if (expr == '') return []
|
if (expr == "") return [];
|
||||||
const ws = /^(\s|\n)+/.exec(expr)
|
const ws = /^(\s|\n)+/.exec(expr);
|
||||||
if (ws) return [['whitespace', ws[0]], ...tokenizeExp(expr.slice(ws[0].length))]
|
if (ws)
|
||||||
const keyword = /^(export|import|default|replacing)\s/.exec(expr)
|
return [["whitespace", ws[0]], ...tokenizeExp(expr.slice(ws[0].length))];
|
||||||
if (keyword) return [['keyword', keyword[0]], ...tokenizeExp(expr.slice(keyword[0].length))]
|
const keyword = /^(export|import|default|replacing)\s/.exec(expr);
|
||||||
const macro = /^:=|^=\-?([\d\_a-fA-F]+(\.[\d\_a-fA-F]+)?(p\-?[\d_]+)?)?=>/.exec(expr)
|
if (keyword)
|
||||||
|
return [
|
||||||
|
["keyword", keyword[0]],
|
||||||
|
...tokenizeExp(expr.slice(keyword[0].length)),
|
||||||
|
];
|
||||||
|
const macro =
|
||||||
|
/^:=|^=\-?([\d\_a-fA-F]+(\.[\d\_a-fA-F]+)?(p\-?[\d_]+)?)?=>/.exec(expr);
|
||||||
// const macro = /^[:<]=(([\d_]+(\.[\d_]+)?)?=>?)?/.exec(expr)
|
// const macro = /^[:<]=(([\d_]+(\.[\d_]+)?)?=>?)?/.exec(expr)
|
||||||
if (macro) return [['macro', macro[0]], ...tokenizeExp(expr.slice(macro[0].length))]
|
if (macro)
|
||||||
const number = /^\d\S*/.exec(expr)
|
return [["macro", macro[0]], ...tokenizeExp(expr.slice(macro[0].length))];
|
||||||
if (number) return [['number', number[0]], ...tokenizeExp(expr.slice(number[0].length))]
|
const number = /^\d\S*/.exec(expr);
|
||||||
const name = /^[A-Za-z0-9_]+/.exec(expr)
|
if (number)
|
||||||
if (name) return [['name', name[0]], ...tokenizeExp(expr.slice(name[0].length))]
|
return [
|
||||||
|
["number", number[0]],
|
||||||
|
...tokenizeExp(expr.slice(number[0].length)),
|
||||||
|
];
|
||||||
|
const name = /^[A-Za-z0-9_]+/.exec(expr);
|
||||||
|
if (name)
|
||||||
|
return [["name", name[0]], ...tokenizeExp(expr.slice(name[0].length))];
|
||||||
if (expr.startsWith("--[")) {
|
if (expr.startsWith("--[")) {
|
||||||
let end = expr.indexOf("]--") + "]--".length;
|
let end = expr.indexOf("]--") + "]--".length;
|
||||||
return [
|
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
|
||||||
['comment', expr.slice(0, end)],
|
|
||||||
...tokenizeExp(expr.slice(end))
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
if (expr.startsWith("--")) {
|
if (expr.startsWith("--")) {
|
||||||
let end = expr.indexOf("\n");
|
let end = expr.indexOf("\n");
|
||||||
return [
|
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
|
||||||
["comment", expr.slice(0, end)],
|
|
||||||
...tokenizeExp(expr.slice(end))
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
if (expr.startsWith('\\')) {
|
if (expr.startsWith("\\")) {
|
||||||
const lambda = matchParen(expr)
|
const lambda = matchParen(expr);
|
||||||
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))]
|
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))];
|
||||||
}
|
}
|
||||||
if (expr.startsWith('"')) {
|
if (expr.startsWith('"')) {
|
||||||
let i = '"'.length;
|
let i = '"'.length;
|
||||||
for (; i <= expr.length; i++) {
|
for (; i <= expr.length; i++) {
|
||||||
if (expr[i] == '\\') i++;
|
if (expr[i] == "\\") i++;
|
||||||
if (expr[i] == '"') break;
|
if (expr[i] == '"') break;
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
["string", expr.slice(0, i+1)],
|
["string", expr.slice(0, i + 1)],
|
||||||
...tokenizeExp(expr.slice(i+1))
|
...tokenizeExp(expr.slice(i + 1)),
|
||||||
]
|
];
|
||||||
}
|
}
|
||||||
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr)
|
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr);
|
||||||
if (ph) return [['placeholder', ph[0]], ...tokenizeExp(expr.slice(ph[0].length))]
|
if (ph)
|
||||||
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(expr)
|
return [["placeholder", ph[0]], ...tokenizeExp(expr.slice(ph[0].length))];
|
||||||
if (opChars) return [['operator', opChars[0]], ...tokenizeExp(expr.slice(opChars[0].length))]
|
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(expr);
|
||||||
throw new Error(`Logic error: none of the regices in a complete cover matched "${expr}"`)
|
if (opChars)
|
||||||
|
return [
|
||||||
|
["operator", opChars[0]],
|
||||||
|
...tokenizeExp(expr.slice(opChars[0].length)),
|
||||||
|
];
|
||||||
|
throw new Error(
|
||||||
|
`Logic error: none of the regices in a complete cover matched "${expr}"`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function nameStyle(level: number | undefined): JSX.CSSProperties {
|
function nameStyle(level: number | undefined): JSX.CSSProperties {
|
||||||
return {
|
return {
|
||||||
color: level === undefined
|
color:
|
||||||
? "hsl(30, 50%, 70%)"
|
level === undefined
|
||||||
: `hsl(
|
? "hsl(30, 50%, 70%)"
|
||||||
|
: `hsl(
|
||||||
calc(170 - ${level} * 5),
|
calc(170 - ${level} * 5),
|
||||||
calc(50% + ${level} * 10%),
|
calc(50% + ${level} * 10%),
|
||||||
calc(70% - ${level} * 5%)
|
calc(70% - ${level} * 5%)
|
||||||
)`,
|
)`,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
text?: string,
|
text?: string;
|
||||||
tokens?: Token[],
|
tokens?: Token[];
|
||||||
vlvlv?: Map<string, number>
|
vlvlv?: Map<string, number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { text, tokens, vlvlv = new Map() }: Props = Astro.props;
|
let { text, tokens, vlvlv = new Map() }: Props = Astro.props;
|
||||||
|
|
||||||
const nextLvl = vlvlv.size + 1
|
const nextLvl = vlvlv.size + 1;
|
||||||
|
|
||||||
const outTokens = tokens ? tokens : tokenizeExp(text!.trim());
|
const outTokens = tokens ? tokens : tokenizeExp(text!.trim());
|
||||||
---
|
---
|
||||||
|
|
||||||
<code style={{
|
<code
|
||||||
whiteSpace: "pre-wrap",
|
style={{
|
||||||
padding: "unset",
|
display: vlvlv.size == 0 ? "inline-block" : "inline",
|
||||||
background: "unset",
|
padding: "unset",
|
||||||
borderRadius: "unset",
|
background: "unset",
|
||||||
border: "unset",
|
borderRadius: "unset",
|
||||||
fontFamily: '"Droid Sans Mono", monospace',
|
border: "unset",
|
||||||
fontSize: "small",
|
whiteSpace: "pre-line",
|
||||||
}}>
|
fontFamily: '"Droid Sans Mono", monospace',
|
||||||
{outTokens.map(([name, value, ...extras], i) => { switch (name) {
|
fontSize: "small",
|
||||||
case 'comment': return <span style={{ color: "#8f8" }}>{value}</span>
|
}}
|
||||||
case 'name': return <span style={nameStyle(vlvlv.get(value))}>{value}</span>
|
>{
|
||||||
case 'operator': return <span style={{ color: "white" }}>{value}</span>
|
outTokens.map(([name, value, ...extras], i) => {
|
||||||
case 'whitespace': return <span>{value}</span>
|
switch (name) {
|
||||||
case 'placeholder': return <span style={{ color: "#bb5" }}>{value}</span>
|
case "comment":
|
||||||
case 'macro': return <span style={{ color: "#f55" }}>{value}</span>
|
return <span style={{ color: "#8f8" }}>{value}</span>;
|
||||||
case 'keyword': return <span style={{ color: "#39f" }}>{value}</span>
|
case "name":
|
||||||
case 'string': return <span style={{ color: "#f8b" }}>{value}</span>
|
return <span style={nameStyle(vlvlv.get(value))}>{value}</span>;
|
||||||
case 'number': return <span style={{ color: "#afa" }}>{value}</span>
|
case "operator":
|
||||||
case 'lambda':
|
return <span style={{ color: "white" }}>{value}</span>;
|
||||||
const sub_vlvlv = new Map(vlvlv)
|
case "whitespace":
|
||||||
sub_vlvlv.set(value, nextLvl)
|
return <span>{value}</span>;
|
||||||
return <span data-name={value}>
|
case "placeholder":
|
||||||
<span style={{ color: "#999" }}>\</span>
|
return <span style={{ color: "#bb5" }}>{value}</span>;
|
||||||
<span style={nameStyle(vlvlv.get(value))}>{value}</span>
|
case "macro":
|
||||||
{extras[0]!.length? <>
|
return <span style={{ color: "#f55" }}>{value}</span>;
|
||||||
<span style={{ color: "#999" }}>:</span>
|
case "keyword":
|
||||||
<span>
|
return <span style={{ color: "#39f" }}>{value}</span>;
|
||||||
<Astro.self vlvlv={sub_vlvlv} tokens={extras[0]!} />
|
case "string":
|
||||||
</span>
|
return <span style={{ color: "#f8b" }}>{value}</span>;
|
||||||
</> :null}
|
case "number":
|
||||||
<span style={{ color: "#999" }}>.</span>
|
return <span style={{ color: "#afa" }}>{value}</span>;
|
||||||
<span>
|
case "lambda":
|
||||||
<Astro.self vlvlv={sub_vlvlv} tokens={extras[1]!} />
|
const sub_vlvlv = new Map(vlvlv);
|
||||||
</span>
|
sub_vlvlv.set(value, nextLvl);
|
||||||
</span>
|
return (
|
||||||
}})}
|
<span data-name={value}>
|
||||||
</code>
|
<span>\</span>
|
||||||
|
<span style={nameStyle(vlvlv.get(value))}>{value}</span>
|
||||||
|
{extras[0]!.length ? (
|
||||||
|
<>
|
||||||
|
<span style={{ color: "#999" }}>:</span>
|
||||||
|
<span>
|
||||||
|
<Astro.self vlvlv={sub_vlvlv} tokens={extras[0]!} />
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<span style={{ color: "#999" }}>.</span>
|
||||||
|
<span>
|
||||||
|
<Astro.self vlvlv={sub_vlvlv} tokens={extras[1]!} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}</code
|
||||||
|
>
|
||||||
|
|||||||
@@ -7,52 +7,81 @@
|
|||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
border-color: default;
|
border-color: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.astro-code {
|
.astro-code {
|
||||||
margin: 1ch 0;
|
margin: 1ch 0;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
pre, code {
|
|
||||||
|
pre,
|
||||||
|
code {
|
||||||
background-color: var(--color-side-bg);
|
background-color: var(--color-side-bg);
|
||||||
padding-left: 1ch;
|
padding-left: 1ch;
|
||||||
padding-right: 1ch;
|
padding-right: 1ch;
|
||||||
}
|
}
|
||||||
pre > code {
|
|
||||||
|
pre>code {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-content {
|
.post-content {
|
||||||
a {
|
a {
|
||||||
color: var(--color-link);
|
color: var(--color-link);
|
||||||
|
|
||||||
&:visited {
|
&:visited {
|
||||||
color: var(--color-link-visited);
|
color: var(--color-link-visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre,
|
||||||
padding-block: .5ch;
|
code {
|
||||||
margin-block: .5ch;
|
display: inline-block;
|
||||||
|
/* padding-block: .5ch;
|
||||||
|
margin-block: .5ch; */
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,h2,h3,h4,h5,h6 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
& i {
|
& i {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
&:hover i { visibility: initial; }
|
|
||||||
|
&:hover i {
|
||||||
|
visibility: initial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h1 { font-size: x-large; }
|
|
||||||
h2 { margin-left: 30px; }
|
h1 {
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: #fff7;
|
color: #fff7;
|
||||||
margin-bottom: 0;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& i.gg-link {
|
& i.gg-link {
|
||||||
@@ -62,16 +91,39 @@
|
|||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#table-of-contents { display: none }
|
ul {
|
||||||
#table-of-contents + ul {
|
list-style: ' - ' outside;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-left: 2ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
list-style: decimal outside;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-left: 2ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#table-of-contents {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
#table-of-contents+ul {
|
||||||
float: right;
|
float: right;
|
||||||
background-color: var(--color-side-bg);
|
background-color: var(--color-side-bg);
|
||||||
padding: 5px 12px;
|
padding: 5px 12px;
|
||||||
width: 20ch;
|
width: 20ch;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
list-style-type: decimal;
|
list-style-type: decimal;
|
||||||
list-style-position: inside;
|
list-style-position: inside;
|
||||||
@@ -79,6 +131,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--breakpoint-xs: 25rem;
|
--breakpoint-xs: 25rem;
|
||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
@@ -97,17 +150,20 @@
|
|||||||
background-color: var(--color-emph-bg);
|
background-color: var(--color-emph-bg);
|
||||||
border-color: var(--color-emph-bg);
|
border-color: var(--color-emph-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-meta {
|
.post-meta {
|
||||||
color: var(--color-faint-fg);
|
color: var(--color-faint-fg);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-left: 0.3em;
|
margin-left: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: var(---color-emph-fg);
|
color: var(---color-emph-fg);
|
||||||
letter-spacing: 3px;
|
letter-spacing: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gutter {
|
.gutter {
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user