Rewrite it in Rust

This commit is contained in:
Maciej Jur 2024-04-13 15:26:52 +02:00
parent 7a36b62138
commit dc96e49b34
Signed by: kamov
GPG key ID: 191CBFF5F72ECAFD
174 changed files with 3977 additions and 8523 deletions

28
.gitignore vendored
View file

@ -1,17 +1,5 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
@ -24,15 +12,17 @@ pnpm-debug.log*
public/**/*.jpg
public/**/*.png
public/**/*.webp
src/**/*.jpg
src/**/*.png
src/**/*.webp
# obsidian
.obsidian/
.stfolder/
content/**/*.jpg
content/**/*.png
content/**/*.webp
# Kanji generator
tools/kklc/kklc.csv
tools/kklc/target/
public/static/kanji/
# Rust
target/
# JavaScript
js/**/node_modules/

View file

@ -1,4 +0,0 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
.vscode/launch.json vendored
View file

@ -1,11 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

View file

@ -1,3 +0,0 @@
Astro
prerender
KaTeX

View file

@ -1,6 +0,0 @@
{
"files.associations": {
// "*.mdx": "markdown"
},
"ltex.language": "en-US"
}

1449
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,26 @@
[package]
name = "ssg"
version = "0.1.0"
edition = "2021"
name = "treesitter"
version = "0.0.0"
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4"] }
napi-derive = "2.12.2"
aho-corasick = "1.1.3"
chrono = "0.4.35"
comrak = { version = "0.22.0", default-features = false, features = ["shortcodes"] }
glob = "0.3.1"
grass = { version = "0.13.2", default-features = false, features = ["random"] }
gray_matter = { version = "0.2.6", default-features = false, features = ["yaml"] }
hayagriva = "0.5.2"
hypertext = "0.5.0"
katex = "0.4.6"
once_cell = "1.19.0"
regex = "1.10.4"
serde = { version = "1.0.197", features = ["derive"] }
# Treesitter
tree-sitter = "0.20.10"
tree-sitter-highlight = "0.20.1"
# Languages
tree-sitter-astro = { git = "https://github.com/virchau13/tree-sitter-astro.git", rev = "e924787e12e8a03194f36a113290ac11d6dc10f3" }
tree-sitter-css = "0.20.0"
tree-sitter-haskell = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "1da347c88599faad7964e63facead5d163ac7dba" }
@ -30,10 +34,3 @@ tree-sitter-rust = "0.20.4"
tree-sitter-scheme = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "af0fd1fa452cb2562dc7b5c8a8c55551c39273b9" }
tree-sitter-toml = "0.20.0"
tree-sitter-typescript = "0.20.5"
[build-dependencies]
napi-build = "2.0.1"
[profile.release]
lto = true
strip = "symbols"

View file

@ -1,19 +1,8 @@
update:
pnpm update
pnpm update svelte@next
dev:
pnpm run astro dev
build:
pnpm run astro build
cargo run
deploy: build
rsync -Pavz ./dist/ kamoshi:/var/www/kamoshi.org --delete
rsync -Pavz ./dist/ kamoshi:/var/www/kamoshi.org --delete --mkpath
preview: build
pnpm run astro preview
treesitter:
cd ./tools/treesitter; \
pnpm run build
serve:
python -m http.server -d ./dist

View file

@ -1,40 +0,0 @@
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import mdx from '@astrojs/mdx';
import svelte from '@astrojs/svelte';
import pagefind from 'astro-pagefind';
import remarkDirective from 'remark-directive';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import remarkEmoji from 'remark-emoji';
import remarkBib from './src/utils/remark/bib';
import remarkRuby from './src/utils/remark/ruby';
import rehypeTreesitter from './src/utils/treesitter';
// https://astro.build/config
export default defineConfig({
site: 'https://kamoshi.org',
trailingSlash: 'always',
markdown: {
syntaxHighlight: false,
remarkPlugins: [
remarkDirective,
remarkMath,
[remarkEmoji, { accessible: true }],
[remarkRuby, { sep: ';' }],
remarkBib,
],
rehypePlugins: [
// https://katex.org/docs/options.html
[rehypeKatex, { output: 'mathml' }],
rehypeTreesitter,
],
},
integrations: [
mdx(),
svelte({ compilerOptions: { runes: true } }),
pagefind(),
sitemap()
]
});

View file

@ -1,9 +1,7 @@
---
layout: ../layouts/Wiki.astro
title: "About me"
date: 2021-09-10T19:34:01+02:00
---
import Timeline from "@components/Timeline.astro";
I studied Computer Science at a university and I have professional experience
as a TypeScript developer. I can use languages such as Rust, C#, TypeScript or
@ -21,23 +19,6 @@ ahead of me, I am determined to achieve fluency in Japanese language in the
future.
一番好きな同人サークルは
- Alstroemeria Records音楽
- Shibayan Records音楽
- Syrufit音楽
- 凋叶棕(音楽)
- azmaya同人誌
- へ蝶々(同人誌)
 Syrufitさんはもう活動を停止しました。
## Timeline
<Timeline />
## Q&A
**Q. Why did you create this website?**
@ -48,6 +29,13 @@ of me working on this. The CSS styles, for example, were all hand rolled by
myself. To simplify everything it's a static website served from Nginx, this
way I don't have to do nearly any maintenance work.
**Q. Can I take a look at the source code?**
Sure thing! The source code is available in
[a repository on GitHub](https://github.com/kamoshi/kamoshi.org),
and you're welcome to learn. I have just one request please, if you would like
to use this code for your own website do allow others to learn from it too!
**Q. What's your setup?**
I currently use Arch Linux with KDE Plasma desktop as my daily driver. For

View file

@ -1,3 +1,7 @@
---
title: "Test"
date: 2021-09-10T19:34:01+02:00
---
# Welcome to my website! :heart:
You have found this little floating rock in the middle of the Internet! Congrats 🎉

View file

Before

Width:  |  Height:  |  Size: 423 KiB

After

Width:  |  Height:  |  Size: 423 KiB

View file

@ -7,7 +7,7 @@ animate: true
# Dead simple Haskell
![Haskell logo](/static/content/slides/haskell-molecules/haskell.png)
![Haskell logo](haskell.png)
-----
@ -17,11 +17,11 @@ animate: true
### Atoms
![atoms](/static/content/slides/haskell-molecules/atoms.png)
![atoms](atoms.png)
---
![atoms](/static/content/slides/haskell-molecules/atoms.png)
![atoms](atoms.png)
```haskell
data H = H -- hydrogen
@ -33,11 +33,11 @@ data C = C -- carbon
### Molecules
![Atoms](/static/content/slides/haskell-molecules/molecules.png)
![Atoms](molecules.png)
---
![Atoms](/static/content/slides/haskell-molecules/molecules.png)
![Atoms](molecules.png)
```haskell
type H₂O = (H, O, H) -- water
@ -49,15 +49,15 @@ type CO₂ = (O, C, O) -- carbon dioxide
### Reactions
![Magic](/static/content/slides/haskell-molecules/magic.png)
![Magic](magic.png)
---
![More magic](/static/content/slides/haskell-molecules/more-magic.png)
![More magic](more-magic.png)
---
![More magic](/static/content/slides/haskell-molecules/more-magic.png)
![More magic](more-magic.png)
```haskell ignore
makeWater :: H -> H -> O -> H₂O
@ -98,11 +98,11 @@ burnOxygen c (o1, o2) = (o1, c, o2)
### `.` `$`
![Plumbing](/static/content/slides/haskell-molecules/plumbing.png)
![Plumbing](plumbing.png)
---
![Partial application](/static/content/slides/haskell-molecules/partial.png)
![Partial application](partial.png)
```haskell ignore
λ> :type makeOxygen
@ -119,7 +119,7 @@ makeOxygen O O :: O₂
---
![Combustion](/static/content/slides/haskell-molecules/combustion.png)
![Combustion](combustion.png)
```haskell ignore
λ> :type burnOxygen
@ -137,7 +137,7 @@ burnOxygen C O₂ :: CO₂
---
![Two functions](/static/content/slides/haskell-molecules/two-fs.png)
![Two functions](two-fs.png)
```haskell
f1 :: O -> O₂
@ -149,7 +149,7 @@ f2 = burnOxygen C
---
![Composition](/static/content/slides/haskell-molecules/composition.png)
![Composition](composition.png)
```haskell
@ -158,7 +158,7 @@ f3 = f2 . f1
---
![Composition2](/static/content/slides/haskell-molecules/composition2.png)
![Composition2](composition2.png)
```haskell
f3 :: O -> CO₂
@ -194,7 +194,7 @@ Diagnostics:
---
![Composition3](/static/content/slides/haskell-molecules/composition3.png)
![Composition3](composition3.png)
```haskell ignore
f3' o = f2 . f1 o
@ -202,7 +202,7 @@ f3' o = f2 . f1 o
---
![Funnel](/static/content/slides/haskell-molecules/funnel.png)
![Funnel](funnel.png)
```haskell ignore
f3' o = f2 . f1 $ o
@ -228,11 +228,11 @@ f $ x = f x
## Isotopes
![Heavy water](/static/content/slides/haskell-molecules/heavy-water.gif)
![Heavy water](heavy-water.gif)
---
![Isotopes](/static/content/slides/haskell-molecules/isotopes.png)
![Isotopes](isotopes.png)
---
@ -531,7 +531,7 @@ data List a = () | (a) | (a, a) | (a, a, a) | ...
### Traits
![Neon colors](/static/content/slides/haskell-molecules/neon.png)
![Neon colors](neon.png)
---
@ -663,11 +663,11 @@ mixNoble n1 n2 = toColor n1 <> "-" <> toColor n2
## Shrodinger's cat
![Cat in a box](/static/content/slides/haskell-molecules/cat.png)
![Cat in a box](cat.png)
---
![Cat in a box](/static/content/slides/haskell-molecules/cat.png)
![Cat in a box](cat.png)
```haskell
data Box a
@ -678,7 +678,7 @@ data Box a
---
![Map](/static/content/slides/haskell-molecules/map.png)
![Map](map.png)
```haskell
data Cat = Cat String deriving Show
@ -687,7 +687,7 @@ data Dog = Dog String deriving Show
---
![Map](/static/content/slides/haskell-molecules/map.png)
![Map](map.png)
```haskell
class Mappable box where
@ -720,11 +720,11 @@ instance Mappable [] where
map' f xs = [f x | x <- xs]
```
![Cat list](/static/content/slides/haskell-molecules/cat-list.png)
![Cat list](cat-list.png)
---
![Cat list](/static/content/slides/haskell-molecules/cat-list.png)
![Cat list](cat-list.png)
```haskell ignore
λ> a = Has $ Cat "cat"
@ -766,11 +766,11 @@ Has (Dog "a")
-----
![Cat merge](/static/content/slides/haskell-molecules/cat-merge.png)
![Cat merge](cat-merge.png)
---
![Cat merge](/static/content/slides/haskell-molecules/cat-merge.png)
![Cat merge](cat-merge.png)
```haskell
merge :: Cat -> Cat -> Dog
@ -789,7 +789,7 @@ catB = Cat "Nyaa"
Dog "Meow & Nyaa"
```
![Cat merge](/static/content/slides/haskell-molecules/merge.png)
![Cat merge](merge.png)
---
@ -799,7 +799,7 @@ boxB = Has $ Cat "Nyaa" :: Box Cat
empty = Empty :: Box Cat
```
![Cat merge](/static/content/slides/haskell-molecules/merge-box.png)
![Cat merge](merge-box.png)
---
@ -809,7 +809,7 @@ boxB = Has $ Cat "Nyaa" :: Box Cat
empty = Empty :: Box Cat
```
![Cat merge](/static/content/slides/haskell-molecules/merge-box.png)
![Cat merge](merge-box.png)
```haskell ignore
λ> merge boxA catB
@ -829,7 +829,7 @@ boxB = Has $ Cat "Nyaa" :: Box Cat
empty = Empty :: Box Cat
```
![Cat merge](/static/content/slides/haskell-molecules/merge-prim.png)
![Cat merge](merge-prim.png)
```haskell
merge' :: Box Cat -> Box Cat -> Box Dog
@ -847,7 +847,7 @@ merge' _ Empty = Empty
merge' (Has c1) (Has c2) = merge c1 c2
```
![Cat merge](/static/content/slides/haskell-molecules/merge-prim.png)
![Cat merge](merge-prim.png)
```haskell ignore
λ> merge' boxA boxB
@ -866,7 +866,7 @@ class Appliable box where
apply' :: box (a -> b) -> box a -> box b
```
![Wrap apply](/static/content/slides/haskell-molecules/wrap-apply.png)
![Wrap apply](wrap-apply.png)
---
@ -970,11 +970,11 @@ Has (Dog "Meow & Nyaa")
Empty
```
![Wrap apply](/static/content/slides/haskell-molecules/wrap-apply.png)
![Wrap apply](wrap-apply.png)
---
![Wrap apply](/static/content/slides/haskell-molecules/wrap-apply.png)
![Wrap apply](wrap-apply.png)
```haskell
merge4 :: Cat -> Cat -> Cat -> Cat -> Dog
@ -1008,11 +1008,11 @@ killOrSave cat@(Cat name) = case name of
_ -> Has cat
```
![Kill](/static/content/slides/haskell-molecules/kill.png)
![Kill](kill.png)
---
![Kill](/static/content/slides/haskell-molecules/kill.png)
![Kill](kill.png)
```haskell ignore
λ> wrap killOrSave `apply'` Has (Cat "Meow")
@ -1059,11 +1059,11 @@ instance Chainable [] where
chain xs f = [x' | x <- xs, x' <- f x]
```
![Save-kill](/static/content/slides/haskell-molecules/save-kill.png)
![Save-kill](save-kill.png)
---
![Save-kill](/static/content/slides/haskell-molecules/save-kill.png)
![Save-kill](save-kill.png)
```haskell
kill :: Cat -> Box Cat
@ -1075,7 +1075,7 @@ save = Has
---
![Save-kill](/static/content/slides/haskell-molecules/save-kill.png)
![Save-kill](save-kill.png)
```haskell ignore
λ> boxA `chain` save `chain` save `chain` save
@ -1134,15 +1134,15 @@ clone (Cat c) = [Cat $ c <> "L" , Cat $ c <> "R"]
[]
```
![Chain list](/static/content/slides/haskell-molecules/chain-list.png)
![Chain list](chain-list.png)
---
![Callbacks](/static/content/slides/haskell-molecules/callbacks.jpg)
![Callbacks](callbacks.jpg)
-----
![This was all dream](/static/content/slides/haskell-molecules/cave.png)
![This was all dream](cave.png)
---
@ -1152,7 +1152,7 @@ What's a `Mappable`?
It's a `Functor`
![It's a Functor](/static/content/slides/haskell-molecules/its-functor.png)
![It's a Functor](its-functor.png)
---
@ -1197,13 +1197,13 @@ It's a `Functor`
It's a `Functor`
![Tardis](/static/content/slides/haskell-molecules/tardis.jpg)
![Tardis](tardis.jpg)
---
It's a `Functor`
![Tardis inside](/static/content/slides/haskell-molecules/tardis-inside.jpg)
![Tardis inside](tardis-inside.jpg)
---
@ -1212,7 +1212,7 @@ main :: IO ()
main = print "Hello World!"
```
![Tardis inside](/static/content/slides/haskell-molecules/io.png)
![Tardis inside](io.png)
---
@ -1222,7 +1222,7 @@ What's a `Appliable`?
It's an Applicative
![It's an applicative](/static/content/slides/haskell-molecules/its-applicative.png)
![It's an applicative](its-applicative.png)
---
@ -1296,7 +1296,7 @@ What's a `Chainable`?
It's a monad
![It's a monad](/static/content/slides/haskell-molecules/its-monad.png)
![It's a monad](its-monad.png)
---
@ -1342,7 +1342,7 @@ It's a monad
---
![Just one more typeclass bro](/static/content/slides/haskell-molecules/pepe.png)
![Just one more typeclass bro](pepe.png)
-----

21
js/package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "js",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"reveal.js": "^5.0.5"
},
"devDependencies": {
"@types/leaflet": "^1.9.8",
"@types/leaflet.markercluster": "^1.5.4"
}
}

View file

@ -2,6 +2,8 @@ import L from 'leaflet';
import 'leaflet.markercluster'
// PHOTOS
interface Photo extends L.LatLngLiteral {
thumbnail: string;
photoUrl: string;
@ -90,5 +92,38 @@ if (L.MarkerClusterGroup) {
L.photo.cluster = function (options: any) {
return new L.Photo.Cluster!(options);
};
}
// MAP
const template = `
<div class="popup">
<a href="{photo}">
<img width="{width}" height="{height}" src="{photo}" alt="" />
<div class="meta">
<span class="date">{date}</span><span class="caption">{caption}</span>
</div>
</a>
</div>
`;
const map = L.map('map').setView([51.85, 16.57], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
const photoLayer = L.photo.cluster().on('click', function(evt) {
evt.layer.bindPopup(L.Util.template(template, evt.layer.photo)).openPopup();
});
async function loadData() {
const data = await fetch('/static/map/data.json');
if (!data.ok) return;
return await data.json()
}
// Add photos to the map
loadData().then(data => photoLayer.add(data).addTo(map));

59
js/pnpm-lock.yaml Normal file
View file

@ -0,0 +1,59 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
leaflet:
specifier: ^1.9.4
version: 1.9.4
leaflet.markercluster:
specifier: ^1.5.3
version: 1.5.3(leaflet@1.9.4)
reveal.js:
specifier: ^5.0.5
version: 5.0.5
devDependencies:
'@types/leaflet':
specifier: ^1.9.8
version: 1.9.8
'@types/leaflet.markercluster':
specifier: ^1.5.4
version: 1.5.4
packages:
/@types/geojson@7946.0.14:
resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==}
dev: true
/@types/leaflet.markercluster@1.5.4:
resolution: {integrity: sha512-tfMP8J62+wfsVLDLGh5Zh1JZxijCaBmVsMAX78MkLPwvPitmZZtSin5aWOVRhZrCS+pEOZwNzexbfWXlY+7yjg==}
dependencies:
'@types/leaflet': 1.9.8
dev: true
/@types/leaflet@1.9.8:
resolution: {integrity: sha512-EXdsL4EhoUtGm2GC2ZYtXn+Fzc6pluVgagvo2VC1RHWToLGlTRwVYoDpqS/7QXa01rmDyBjJk3Catpf60VMkwg==}
dependencies:
'@types/geojson': 7946.0.14
dev: true
/leaflet.markercluster@1.5.3(leaflet@1.9.4):
resolution: {integrity: sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==}
peerDependencies:
leaflet: ^1.3.1
dependencies:
leaflet: 1.9.4
dev: false
/leaflet@1.9.4:
resolution: {integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==}
dev: false
/reveal.js@5.0.5:
resolution: {integrity: sha512-MPWPV/cRlkZhh72dAGYv/bUCr9ulwM2/ucCqiL/KN4tvhb6VvN49iwOyWHE08wppj8lMQXi2xbS3kyKgfyTYqg==}
engines: {node: '>=18.0.0'}
dev: false

7
js/reveal.js Normal file
View file

@ -0,0 +1,7 @@
import Reveal from 'reveal.js';
Reveal.initialize({
hash: true,
slideNumber: true,
});

View file

@ -1,47 +0,0 @@
{
"name": "kamoshi.org",
"type": "module",
"private": true,
"version": "0.0.1",
"scripts": {
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.1.1",
"@astrojs/sitemap": "^3.1.1",
"@astrojs/svelte": "^5.2.0",
"@citation-js/plugin-bibtex": "^0.7.9",
"@js-temporal/polyfill": "^0.4.4",
"astro": "^4.4.14",
"astro-pagefind": "^1.4.0",
"chart.js": "^4.4.2",
"citation-js": "^0.7.9",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"mdast-util-to-string": "^4.0.0",
"purify-ts": "^2.0.3",
"rehype-katex": "^7.0.0",
"rehype-raw": "^7.0.0",
"rehype-stringify": "^10.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.1",
"remark-gfm": "^4.0.0",
"remark-math": "^6.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.0",
"reveal.js": "^5.0.5",
"svelte": "5.0.0-next.72",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@types/leaflet": "^1.9.8",
"@types/leaflet.markercluster": "^1.5.4",
"@types/reveal.js": "^5.0.1",
"@types/unist": "^3.0.2",
"pagefind": "^1.0.4",
"prettier": "^3.2.5",
"sass": "^1.71.1",
"sharp": "^0.33.2"
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
.marker-cluster-small {
background-color: rgba(181, 226, 140, 0.6);
}
.marker-cluster-small div {
background-color: rgba(110, 204, 57, 0.6);
}
.marker-cluster-medium {
background-color: rgba(241, 211, 87, 0.6);
}
.marker-cluster-medium div {
background-color: rgba(240, 194, 12, 0.6);
}
.marker-cluster-large {
background-color: rgba(253, 156, 115, 0.6);
}
.marker-cluster-large div {
background-color: rgba(241, 128, 23, 0.6);
}
/* IE 6-8 fallback colors */
.leaflet-oldie .marker-cluster-small {
background-color: rgb(181, 226, 140);
}
.leaflet-oldie .marker-cluster-small div {
background-color: rgb(110, 204, 57);
}
.leaflet-oldie .marker-cluster-medium {
background-color: rgb(241, 211, 87);
}
.leaflet-oldie .marker-cluster-medium div {
background-color: rgb(240, 194, 12);
}
.leaflet-oldie .marker-cluster-large {
background-color: rgb(253, 156, 115);
}
.leaflet-oldie .marker-cluster-large div {
background-color: rgb(241, 128, 23);
}
.marker-cluster {
background-clip: padding-box;
border-radius: 20px;
}
.marker-cluster div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
text-align: center;
border-radius: 15px;
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.marker-cluster span {
line-height: 30px;
}

View file

@ -0,0 +1,14 @@
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
}
.leaflet-cluster-spider-leg {
/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
}

View file

@ -0,0 +1,600 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
user-select: none;
-webkit-user-drag: none;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
box-sizing: border-box;
z-index: 800;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-list {
border: 0;
margin: 0;
padding: 0;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
margin-right: 0.277em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,27 +0,0 @@
.leaflet-marker-photo {
border: 2px solid #fff;
box-shadow: 3px 3px 10px #888;
div {
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
}
b {
position: absolute;
top: -7px;
right: -11px;
color: #555;
background-color: #fff;
border-radius: 8px;
height: 12px;
min-width: 12px;
line-height: 12px;
text-align: center;
padding: 3px;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
}

View file

@ -1,12 +0,0 @@
import 'leaflet';
declare module 'leaflet' {
class Photo extends L.FeatureGroup {
static Cluster?: { new(...args: any[]): any } & L.Class;
}
let photo: {
(photos: Photo[], options: any): Photo;
cluster?: (options?: any) => any;
};
}

View file

@ -1,9 +0,0 @@
## かもし
初めましての方は初めまして、ポーランド出身で日本語を勉強している人です。
間違いがあったらすみません。
こちらは個人的なウェブサイトで、「かもし」というのは個人サークル名といってもいいです。
日本語を練習するため日本語を使って色々なことを書きます。
英語も使います。趣味はプログラミングや日本語や日本の歌や同人など色々なことです。
質問があったらメールを送信してくれてください。

View file

@ -1,75 +0,0 @@
import type { Node, Parent } from 'unist';
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from 'remark-gfm';
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeStringify from "rehype-stringify";
import { visit } from "unist-util-visit";
interface CodeNode extends Node {
type: 'code';
lang?: string;
meta?: string;
value: string;
}
const ESCAPED_CHARS: {[key: string]: string} = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
const REGEX_HL_LINES = /\[([\s\d,|-]*)\]/;
function transformCode(node: CodeNode, index: number, parent: Parent) {
if (!node.meta || !REGEX_HL_LINES.test(node.meta)) return;
const langtag = node.lang ? ` class="${node.lang}" ` : ''
const numbers = node.meta.match(REGEX_HL_LINES)![1];
const escaped = node.value.replace(/[&<>"']/g, match => ESCAPED_CHARS[match] || '');
parent.children[index] = {
type: 'html',
value: `<pre><code data-line-numbers="${numbers}"${langtag}>${escaped}</code></pre>`,
} as any;
}
function codePassthrough() {
return (tree: Node, _: any) => {
visit(tree, 'code', transformCode);
}
}
const renderer = unified()
.use(remarkParse)
.use(remarkGfm)
.use(codePassthrough)
.use(remarkRehype, {allowDangerousHtml: true})
.use(rehypeRaw)
.use(rehypeStringify);
const SPLIT_H = /\n-----\n/;
const SPLIT_V = /\n---\n/;
function wrapSection(animate: boolean, id: number) {
return (content: string): string => {
return animate
? `<section data-auto-animate data-auto-animate-id="${id}">${content}</section>`
: `<section>${content}</section>`;
}
}
export function render(text: string, animate = false): string {
const wrapOuter = wrapSection(false, 0);
return text
.split(SPLIT_H)
.map(stacks => stacks.split(SPLIT_V).map(slide => String(renderer.processSync(slide))))
.map((stack, i) => (stack.length > 1)
? wrapOuter(stack.map(wrapSection(animate, i)).join(''))
: wrapOuter(stack[0]))
.join('');
}

View file

@ -1,46 +0,0 @@
[
{
"year": 2016,
"months": [
{
"month": "May",
"events": [
"Started learning Japanese language"
]
}
]
},
{
"year": 2018,
"months": [
{
"month": "September",
"events": [
"Started studying Computer Science"
]
}
]
},
{
"year": 2022,
"months": [
{
"month": "February",
"events": [
"Completed bachelor's degree in Computer Science at Wrocław University of Science and Technology"
]
}
]
},
{
"year": 2023,
"months": [
{
"month": "July",
"events": [
"Completed master's degree in Computer Science at Wrocław University of Science and Technology"
]
}
]
}
]

View file

@ -1,10 +0,0 @@
---
interface Props {
src: string;
size?: 'normal' | 'big';
}
const { src, size } = Astro.props;
---
<img class="md-icon" class:list={[size]} src={src} alt=""/>

View file

@ -1,3 +0,0 @@
<small class="marginnote">
<slot />
</small>

View file

@ -1,33 +0,0 @@
---
import timeline from '../assets/timeline.json';
---
<div class="sc-timeline">
{timeline.map((year: any) => (
<section class="sc-timeline__year">
<h3 class="sc-timeline__year-header sticky font-medium">{year.year}</h3>
<div class="sc-timeline__year-container">
{year.events && (
<section class="sc-timeline__year-events">
<ul class="sc-timeline__list">
{year.events.map((event: any) => (
<li class="sc-timeline__list-item">{event}</li>
))}
</ul>
</section>
)}
{year.months?.map((month: any) => (
<section class="sc-timeline__month">
<h4 class="sc-timeline__month-header font-medium">{month.month}</h4>
<ul class="sc-timeline__list">
{month.events.map((event: any) => (
<li class="sc-timeline__list-item">{event}</li>
))}
</ul>
</section>
))}
</div>
</section>
))}
</div>

View file

@ -1,54 +0,0 @@
---
interface Props {
headings: Array<{
depth: number;
slug: string;
text: string;
}>
}
type Heading = Props['headings'][number];
type Nested = Heading & { children?: Heading[] };
const { headings } = Astro.props;
function fold(headings: Heading[]) {
const toc = [] as Nested[];
const map = new Map<number, Nested>();
for (const h of headings) {
const heading = { ...h };
map.set(heading.depth, heading);
if (heading.depth === 2)
toc.push(heading)
else {
const backref = map.get(heading.depth - 1)!;
backref.children
? backref.children.push(heading)
: backref.children = [heading];
}
}
return toc;
}
---
<section class="p-toc">
<h2>Content</h2>
<nav>
<ul class="p-toc__primary">
{fold(headings).map(heading => (
<li class="p-toc__primary-item">
<a href={`#${heading.slug}`}>{heading.text}</a>
{heading.children && (
<ul class="p-toc__nested">
{heading.children?.map(child => (
<li class="p-toc__nested-item">
<a href={`#${child.slug}`}>{child.text}</a>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
</section>

View file

@ -1,15 +0,0 @@
---
const year = new Date().getFullYear();
const copy = `Copyright &copy; ${year} Maciej Jur`;
const mail = "maciej@kamoshi.org";
const href = `mailto:${mail}`;
---
<footer class="footer">
<div>
<div set:html={copy}></div>
<a href={href}>{mail}</a>
</div>
<a class="footer__cc-wrap" rel="license" href="http://creativecommons.org/licenses/by/4.0/">
<img class="footer__cc-stamp" alt="Creative Commons License" width="88" height="31" src="/static/svg/by.svg"/>
</a>
</footer>

View file

@ -1,19 +0,0 @@
---
import type { Maybe } from 'purify-ts';
interface Props {
title: Maybe<string>;
}
const { title } = Astro.props;
---
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content={Astro.generator} />
<title>{title.mapOrDefault(title => `${title} | kamoshi.org`, "kamoshi.org")}</title>
<link rel="sitemap" href="/sitemap-index.xml"/>
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" href="/favicon.ico" sizes="any">

View file

@ -1,73 +0,0 @@
---
import Logotype from "./Logotype.astro";
interface MenuItem {
name: string;
url: string;
}
/** Config for the menu displayed in site navbar. */
const menu: MenuItem[] = [
{
name: 'Posts',
url: '/posts/',
},
{
name: 'Slides',
url: '/slides/',
},
{
name: 'Wiki',
url: '/wiki/',
},
{
name: 'Map',
url: '/map/',
},
{
name: 'About',
url: '/about/',
},
{
name: 'Search',
url: '/search/'
}
];
---
<nav class="p-nav">
<input id="p-nav-toggle" type="checkbox" hidden>
<div class="p-nav__bar">
<a href="/" class="p-nav__logo">
<img class="p-nav__logo-icon" height="48px" width="51px" src="/static/svg/aya.svg" alt="">
<div class="p-nav__logo-text">
<div class="p-nav__logo-main">
<Logotype />
</div>
<div class="p-nav__logo-sub" id="p-nav-splash">
Doesn't require JavaScript!
</div>
</div>
</a>
<label class="p-nav__burger" for="p-nav-toggle" tabindex="0">
<span class="p-nav__burger-icon"></span>
</label>
</div>
<menu class="p-nav__menu">
{menu.map(item => (
<li class="p-nav__menu-item">
<a class="p-nav__menu-link" href={item.url}>
{item.name}
</a>
</li>
))}
</menu>
<script>
import { bindSubtitle } from "../../utils/splash";
bindSubtitle();
</script>
</nav>

View file

@ -1,6 +0,0 @@
---
import Text from '@assets/markdown/intro.md';
---
<section class="p-card intro-jp" lang="ja-JP">
<Text/>
</section>

View file

@ -1,13 +0,0 @@
---
import image from "@assets/home/IMG_20231029_111650.jpg";
import { Image } from "astro:assets";
const alt = "Autumn park with colorful trees and fallen leaves";
---
<section class="p-card home-card-image">
<h2 class="p-card__heading">Image of the Month</h2>
<a href={image.src} class="home-card-image__link">
<Image src={image} alt={alt} class="home-card-image__image" />
</a>
</section>

View file

@ -1,9 +0,0 @@
---
import Widget from './kanji.svelte';
---
<section class="p-card">
<h2 class="p-card__heading">Kanji of the Day</h2>
<div>
<Widget client:load/>
</div>
</section>

View file

@ -1,51 +0,0 @@
type Ruby = Array<[string, string]>;
export interface KKLCEntry {
id: number;
char: string;
keys: string[];
senses: string[];
onyomi: string[];
kunyomi: string[];
examples: Array<[string, Ruby]>;
}
async function chooseId(): Promise<number> {
const date = new Date().toLocaleDateString('en');
const data = new TextEncoder().encode(date);
const hash = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hash));
const hashValue = hashArray.reduce((acc, byte) => acc + byte, 0);
const min = 1;
const max = 2300;
return min + (hashValue % (max - min + 1));
}
function tryGetCache(id: number) {
const item = localStorage.getItem('kanji');
if (!item) return;
const cache = JSON.parse(item);
if (cache.id === id) {
return cache.data;
}
}
function insertCache(id: number, data: KKLCEntry) {
localStorage.setItem('kanji', JSON.stringify({ id, data }));
}
export async function getKanji(): Promise<KKLCEntry> {
const id = await chooseId();
const cache = tryGetCache(id);
if (cache) return cache;
const data = await fetch(`/static/kanji/${id}.json`).then(res => res.json());
insertCache(id, data);
return data;
}

View file

@ -1,49 +0,0 @@
<script lang="ts">
import { getKanji, type KKLCEntry } from './data.svelte.ts';
let state = $state<Promise<KKLCEntry>>(new Promise(() => {}));
$effect(() => void (state = getKanji()));
</script>
<div class="daily-kanji">
{#await state}
<div class="spinner-wrap">
<div class="spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
</div>
{:then state}
<div class="info">
<div class="info-char">
{state.char}
</div>
<div class="info-meta">
<div class="info-key">
{state.keys.join(', ')}
</div>
<div class="info-on">
{state.onyomi.join(', ')}
</div>
<div class="info-kun">
{state.kunyomi.join(', ')}
</div>
</div>
</div>
<table class="examples">
<tbody>
{#each state.examples as [meaning, example]}
<tr>
<td class="examples-ja">
<ruby>
{#each example as [expr, ruby]}{expr}<rt>{ruby||''}</rt>{/each}
</ruby>
</td>
<td class="examples-en">
{meaning}
</td>
</tr>
{/each}
</tbody>
</table>
{/await}
</div>

View file

@ -1,29 +0,0 @@
---
import { Temporal } from "@js-temporal/polyfill";
interface Props {
title: string;
date: Temporal.ZonedDateTime;
desc: string;
path: string;
}
const { title, date, desc, path } = Astro.props;
const short = date.toPlainDate().toString();
const human = date.toLocaleString("en", { month: '2-digit', day: "2-digit" });
---
<a class="page-item" href={path}>
<div class="page-item__header">
<h3>{title}</h3>
<time datetime={short}>
{human}
</time>
</div>
{desc && (
<div class="page-item__desc">
{desc}
</div>
)}
</a>

View file

@ -1,26 +0,0 @@
interface Pagefind {
search: (query: string) => Promise<PagefindResponse>;
}
interface PagefindResult {
id: string;
data: () => Promise<PagefindDocument>;
}
interface PagefindResponse {
results: PagefindResult[];
}
interface PagefindDocument {
url: string;
excerpt: string;
filters: {
author: string;
};
meta: {
title: string;
image: string;
};
content: string;
word_count: number;
}

View file

@ -1,97 +0,0 @@
<script lang="ts">
import type { ChangeEventHandler, UIEventHandler } from 'svelte/elements';
let client = $state<Pagefind>();
let query = $state<string>('');
let limit = $state<number>(10);
let result = $derived(client?.search(query));
const require = (path: string) => import(/* @vite-ignore */path);
function sync(): void {
query = new URLSearchParams(window.location.search).get('q') || '';
}
function onInput(): ChangeEventHandler<HTMLInputElement> {
let debounce: number | undefined;
return event => {
clearTimeout(debounce);
const value = event.currentTarget.value;
const url = new URL(window.location.href);
(value)
? url.searchParams.set('q', value)
: url.searchParams.delete('q');
debounce = setTimeout(() => window.history.pushState({}, '', url), 1000);
}
}
function onScroll(): UIEventHandler<Window> {
let throttle = Date.now();
return event => {
const now = Date.now();
if (throttle + 200 > now) return;
const { scrollHeight } = document.documentElement;
const { innerHeight, scrollY } = event.currentTarget;
const distance = scrollHeight - (innerHeight + scrollY);
if (distance < 100) {
limit += 5;
throttle = now;
}
}
}
$effect(() => {
sync();
require('/pagefind/pagefind.js').then(pf => client = pf);
});
</script>
<svelte:window
on:popstate={sync}
on:scroll={onScroll()}/>
{#snippet tile(data: PagefindDocument)}
<a class="c-search__result" href={data.url}>
<header class="c-search__header">
<h2 class="c-search__title">
{data.meta.title}
</h2>
</header>
<div class="c-search__excerpt">
{@html data.excerpt}
</div>
</a>
{/snippet}
<article class="c-search">
<h1>Search</h1>
<input class="c-search__input" placeholder="Start typing here!"
bind:value={query}
on:input={onInput()}
on:input={() => limit = 10}/>
{#if query && result}
{#await result}
Loading...
{:then {results}}
<section class="c-search__results">
<div>Showing results for "{query}" ({results.length})</div>
{#each results.slice(0, limit) as page (page.id)}
{#await page.data()}
Loading...
{:then page}
{@render tile(page)}
{/await}
{/each}
</section>
{/await}
{:else}
<div>No results to show yet...</div>
{/if}
</article>

View file

@ -1,43 +0,0 @@
---
import { Maybe } from 'purify-ts/Maybe';
import HeadingsList from './HeadingsList.astro';
import type { MarkdownHeading } from 'astro';
interface Props {
headings: MarkdownHeading[];
}
export type Nested = MarkdownHeading & { children?: MarkdownHeading[] };
function fold(headings: MarkdownHeading[]): Nested[] {
const toc = [] as Nested[];
const map = new Map<number, Nested>();
for (const h of headings) {
const heading = { ...h };
map.set(heading.depth, heading);
if (heading.depth === 2)
toc.push(heading)
else {
const backref = map.get(heading.depth - 1)!;
backref.children
? backref.children.push(heading)
: backref.children = [heading];
}
}
return toc;
}
const { headings } = Astro.props;
---
<h2 class="link-tree__heading">
<a class="link-tree__heading-text" href="#top">Content</a>
</h2>
<nav id="table-of-contents" class="link-tree__nav">
<HeadingsList
headings={Maybe.of(headings).map(fold)}
/>
</nav>

View file

@ -1,28 +0,0 @@
---
import { Maybe } from 'purify-ts';
import type { Nested } from './Headings.astro';
interface Props {
headings: Maybe<Nested[]>;
}
const { headings } = Astro.props;
---
{headings
.map(headings =>
<ul class="link-tree__nav-list">
{headings.map(heading =>
<li class="link-tree__nav-list-item">
<a class="link-tree__nav-list-text link" href={`#${heading.slug}`}>
{heading.text}
</a>
<Astro.self headings={Maybe.fromNullable(heading.children)}/>
</li>
)}
</ul>
)
.extract()
}

View file

@ -1,26 +0,0 @@
---
import PagesList from "./PagesList.astro";
import type { Maybe } from "purify-ts/Maybe";
import type { PagesProps } from "./PagesList.astro";
import { pathify } from "@utils/tree";
interface Props {
heading: string;
pages: Maybe<PagesProps>;
}
const { heading, pages } = Astro.props;
---
<h2 class="link-tree__heading">
{pages.chain(x => x.prefix)
.map(pathify)
.mapOrDefault(href =>
<a class="link-tree__heading-text" href={href}>{heading}</a>,
<span class="link-tree__heading-text">{heading}</span>
)}
</h2>
<nav class="link-tree__nav">
{pages.map(pages => <PagesList {...pages} />).extract()}
</nav>

Some files were not shown because too many files have changed in this diff Show more