Updated the site
Some checks failed
Upload via SSH / build (push) Failing after 1m27s

This commit is contained in:
Bethlenfalvi, Lorinc (ext)
2026-03-23 17:25:03 +01:00
parent 8bafec4821
commit b986001041
4 changed files with 1212 additions and 1388 deletions

2246
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,20 +9,20 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^4.3.13",
"@astrojs/react": "^4.4.2",
"@astrojs/rss": "^4.0.14",
"@astrojs/sitemap": "^3.6.0",
"@astrojs/svelte": "^7.2.4",
"@astrojs/mdx": "^5.0.2",
"@astrojs/react": "^5.0.1",
"@astrojs/rss": "^4.0.17",
"@astrojs/sitemap": "^3.7.1",
"@astrojs/svelte": "^8.0.3",
"@js-temporal/polyfill": "^0.5.1",
"@tailwindcss/vite": "^4.1.18",
"astro": "^5.16.6",
"@tailwindcss/vite": "^4.2.2",
"astro": "^6.0.8",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"remark-toc": "^9.0.0",
"shiki": "^3.20.0",
"shiki": "^4.0.2",
"svelte": "^5.46.1",
"tailwindcss": "^4.1.18",
"tailwindcss": "^4.2.2",
"typescript": "^5.9.3"
}
}

View File

@@ -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 =
| ['comment', string]
| ["comment", string]
| LambdaToken
| ['operator', string]
| ['name', string]
| ['whitespace', string]
| ['placeholder', string]
| ['macro', string]
| ['keyword', string]
| ['string', string]
| ['number', string]
| ["operator", string]
| ["name", string]
| ["whitespace", string]
| ["placeholder", string]
| ["macro", string]
| ["keyword", string]
| ["string", string]
| ["number", string];
function matchParen(expr: string, greedy = false): string {
for (var i = 0, lvl = 0;
0 <= lvl && i < expr.length;
i++) {
if (expr[i] == '(' || expr[i] == '\\') lvl++
else if (expr[i] == ')' || expr[i] == '.') lvl--
else if (greedy && expr[i] == '\n' && lvl == 0) break
for (var i = 0, lvl = 0; 0 <= lvl && i < expr.length; i++) {
if (expr[i] == "(" || expr[i] == "\\") lvl++;
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 {
expr = expr.slice(1) // Get rid of \
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr)
if (!nameMatch) throw new Error(`Missing name in "${expr}"`)
const name = nameMatch[0].trim()
const afterName = nameMatch[0].length
let type: Token[] = []
let afterType = afterName
if (expr[afterName] == ':') {
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1)
type = tokenizeExp(typeStr)
afterType += typeStr.length + 1
expr = expr.slice(1); // Get rid of \
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr);
if (!nameMatch) throw new Error(`Missing name in "${expr}"`);
const name = nameMatch[0].trim();
const afterName = nameMatch[0].length;
let type: Token[] = [];
let afterType = afterName;
if (expr[afterName] == ":") {
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1);
type = tokenizeExp(typeStr);
afterType += typeStr.length + 1;
}
if (expr[afterType] != '.') throw new Error(`Missing dot in "${expr.slice(afterType)}"`)
const body = tokenizeExp(expr.slice(afterType + 1))
return ['lambda', name, type, body]
if (expr[afterType] != ".")
throw new Error(`Missing dot in "${expr.slice(afterType)}"`);
const body = tokenizeExp(expr.slice(afterType + 1));
return ["lambda", name, type, body];
}
// Problem
// \f:\a:a.a.\a:a.a
function tokenizeExp(expr: string): Token[] {
if (expr == '') return []
const ws = /^(\s|\n)+/.exec(expr)
if (ws) return [['whitespace', ws[0]], ...tokenizeExp(expr.slice(ws[0].length))]
const keyword = /^(export|import|default|replacing)\s/.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)
function tokenizeExp(expr: string): Token[] {
if (expr == "") return [];
const ws = /^(\s|\n)+/.exec(expr);
if (ws)
return [["whitespace", ws[0]], ...tokenizeExp(expr.slice(ws[0].length))];
const keyword = /^(export|import|default|replacing)\s/.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)
if (macro) return [['macro', macro[0]], ...tokenizeExp(expr.slice(macro[0].length))]
const number = /^\d\S*/.exec(expr)
if (number) 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 (macro)
return [["macro", macro[0]], ...tokenizeExp(expr.slice(macro[0].length))];
const number = /^\d\S*/.exec(expr);
if (number)
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("--[")) {
let end = expr.indexOf("]--") + "]--".length;
return [
['comment', expr.slice(0, end)],
...tokenizeExp(expr.slice(end))
]
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
}
if (expr.startsWith("--")) {
let end = expr.indexOf("\n");
return [
["comment", expr.slice(0, end)],
...tokenizeExp(expr.slice(end))
]
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
}
if (expr.startsWith('\\')) {
const lambda = matchParen(expr)
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))]
if (expr.startsWith("\\")) {
const lambda = matchParen(expr);
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))];
}
if (expr.startsWith('"')) {
let i = '"'.length;
for (; i <= expr.length; i++) {
if (expr[i] == '\\') i++;
if (expr[i] == "\\") i++;
if (expr[i] == '"') break;
}
return [
["string", expr.slice(0, i+1)],
...tokenizeExp(expr.slice(i+1))
]
["string", expr.slice(0, i + 1)],
...tokenizeExp(expr.slice(i + 1)),
];
}
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr)
if (ph) return [['placeholder', ph[0]], ...tokenizeExp(expr.slice(ph[0].length))]
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(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}"`)
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr);
if (ph)
return [["placeholder", ph[0]], ...tokenizeExp(expr.slice(ph[0].length))];
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(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 {
return {
color: level === undefined
? "hsl(30, 50%, 70%)"
: `hsl(
color:
level === undefined
? "hsl(30, 50%, 70%)"
: `hsl(
calc(170 - ${level} * 5),
calc(50% + ${level} * 10%),
calc(70% - ${level} * 5%)
)`,
}
};
}
interface Props {
text?: string,
tokens?: Token[],
vlvlv?: Map<string, number>
text?: string;
tokens?: Token[];
vlvlv?: Map<string, number>;
}
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());
---
<code style={{
whiteSpace: "pre-wrap",
padding: "unset",
background: "unset",
borderRadius: "unset",
border: "unset",
fontFamily: '"Droid Sans Mono", monospace',
fontSize: "small",
}}>
{outTokens.map(([name, value, ...extras], i) => { switch (name) {
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>
case 'whitespace': return <span>{value}</span>
case 'placeholder': return <span style={{ color: "#bb5" }}>{value}</span>
case 'macro': return <span style={{ color: "#f55" }}>{value}</span>
case 'keyword': return <span style={{ color: "#39f" }}>{value}</span>
case 'string': return <span style={{ color: "#f8b" }}>{value}</span>
case 'number': return <span style={{ color: "#afa" }}>{value}</span>
case 'lambda':
const sub_vlvlv = new Map(vlvlv)
sub_vlvlv.set(value, nextLvl)
return <span data-name={value}>
<span style={{ color: "#999" }}>\</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>
<code
style={{
display: vlvlv.size == 0 ? "inline-block" : "inline",
padding: "unset",
background: "unset",
borderRadius: "unset",
border: "unset",
whiteSpace: "pre-line",
fontFamily: '"Droid Sans Mono", monospace',
fontSize: "small",
}}
>{
outTokens.map(([name, value, ...extras], i) => {
switch (name) {
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>;
case "whitespace":
return <span>{value}</span>;
case "placeholder":
return <span style={{ color: "#bb5" }}>{value}</span>;
case "macro":
return <span style={{ color: "#f55" }}>{value}</span>;
case "keyword":
return <span style={{ color: "#39f" }}>{value}</span>;
case "string":
return <span style={{ color: "#f8b" }}>{value}</span>;
case "number":
return <span style={{ color: "#afa" }}>{value}</span>;
case "lambda":
const sub_vlvlv = new Map(vlvlv);
sub_vlvlv.set(value, nextLvl);
return (
<span data-name={value}>
<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
>

View File

@@ -7,52 +7,81 @@
font-family: 'Montserrat', sans-serif;
font-weight: 300;
}
* {
border-color: default;
}
.astro-code {
margin: 1ch 0;
white-space: pre-wrap;
}
pre, code {
pre,
code {
background-color: var(--color-side-bg);
padding-left: 1ch;
padding-right: 1ch;
}
pre > code {
pre>code {
padding: 0;
}
p {
margin-bottom: 15px;
}
.post-content {
a {
color: var(--color-link);
&:visited {
color: var(--color-link-visited);
}
}
pre {
padding-block: .5ch;
margin-block: .5ch;
pre,
code {
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-bottom: 10px;
font-weight: 500;
& i {
visibility: hidden;
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 {
color: #fff7;
margin-bottom: 0;
margin-bottom: 10px;
}
& i.gg-link {
@@ -62,16 +91,39 @@
margin-bottom: 7px;
}
#table-of-contents { display: none }
#table-of-contents + ul {
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;
background-color: var(--color-side-bg);
padding: 5px 12px;
width: 20ch;
margin: 10px;
ul {
padding-left: 10px;
}
li {
list-style-type: decimal;
list-style-position: inside;
@@ -79,6 +131,7 @@
}
}
}
@theme {
--breakpoint-xs: 25rem;
--tw-border-style: solid;
@@ -97,17 +150,20 @@
background-color: var(--color-emph-bg);
border-color: var(--color-emph-bg);
}
.post-meta {
color: var(--color-faint-fg);
font-style: italic;
font-weight: 500;
margin-left: 0.3em;
}
.summary {
font-style: italic;
color: var(---color-emph-fg);
letter-spacing: 3px;
}
.gutter {
scrollbar-gutter: stable;
}