Compare commits

...

192 commits

Author SHA1 Message Date
SevicheCC
5612fc5cea new post 2025-03-22 17:04:42 +08:00
SevicheCC
bb907ba1fc update url 2025-01-01 16:24:22 +08:00
SevicheCC
b15c3ae1cb post modify 2024-10-30 02:30:30 +08:00
SevicheCC
6a46db88b4 new post 2024-10-29 02:36:58 +08:00
SevicheCC
7860de0a9f new friend 2024-10-27 13:45:52 +08:00
SevicheCC
5e2805658b test fish 2024-10-21 19:12:52 +08:00
SevicheCC
cdcba10cd7 update about 2024-10-21 10:39:57 +08:00
SevicheCC
00eaaa1095 test fish 2024-10-15 21:00:00 +08:00
SevicheCC
4036684462 test fish 2024-10-15 12:05:21 +08:00
SevicheCC
18487c1c4c fix css 2024-10-15 11:59:36 +08:00
SevicheCC
74c08e6e3b fix url 2024-10-15 00:45:49 +08:00
SevicheCC
f294662f4c fix:empty file 2024-10-15 00:16:12 +08:00
SevicheCC
c5026b4751 new post 2024-10-14 23:53:58 +08:00
SevicheCC
1cf978f7f8 fix typo 2024-09-15 03:41:53 +08:00
SevicheCC
c141924464 fix typo 2024-09-15 00:03:54 +08:00
SevicheCC
f136f65090 new post 2024-09-14 23:03:53 +08:00
SevicheCC
6e96aede25 fix post title 2024-02-23 21:37:04 +08:00
SevicheCC
fd6bb3b7aa update post text 2024-02-23 21:19:02 +08:00
SevicheCC
1f04658852 new post 2024-02-23 21:13:12 +08:00
SevicheCC
e6dddea4ac new post * 2 2024-01-22 21:01:46 +08:00
SevicheCC
424a4dd8f9 new post 2023-10-27 21:11:03 +08:00
SevicheCC
a03602e4c2 new friend 2023-10-27 21:10:50 +08:00
SevicheCC
042610eaff fix typo and missing sentence 2023-09-10 22:11:28 +08:00
SevicheCC
87d3c8614f new post 2023-09-10 20:41:25 +08:00
SevicheCC
1ac63adbea chore(deps): update nelify cli 2023-09-10 20:39:47 +08:00
SevicheCC
264810b57c new post 2023-09-04 22:08:27 +08:00
SevicheCC
4caccfb44e fix typo 2023-09-01 23:34:18 +08:00
SevicheCC
869e284255 update project 2023-09-01 23:32:42 +08:00
SevicheCC
558c43f2ae add new post 2023-08-27 19:16:38 +08:00
SevicheCC
bc54ba32bb Update netlify-cli 2023-08-16 13:41:31 +08:00
SevicheCC
58ecbd0cd6 Update Friend's name 2023-08-16 13:41:17 +08:00
SevicheCC
fc61fa5d70 remove comment parade 2023-08-02 00:49:21 +08:00
SevicheCC
a4e55d514f update friends link 2023-05-29 10:30:38 +08:00
SevicheCC
3d1c5518d0 update friends link 2023-05-28 21:19:24 +08:00
SevicheCC
784006f2de update friends url 2023-05-28 21:04:05 +08:00
SevicheCC
f4aa175030 fix: pwa build error 2023-05-28 02:35:24 +08:00
SevicheCC
5c8d0009b5 fix: http font 2023-05-28 01:38:05 +08:00
SevicheCC
de598d5d8d add post detail about gpt 2023-05-19 21:56:11 +08:00
SevicheCC
e656f74da5 update deps & add links 2023-05-19 21:24:54 +08:00
SevicheCC
3615e90403 new post 2023-05-19 01:56:33 +08:00
SevicheCC
72de5eda03 fix giscus style 2023-05-10 14:31:42 +08:00
SevicheCC
02bad37340 update default theme 2023-05-09 16:28:45 +08:00
SevicheCC
986d25d583 compress avatar 2023-05-09 16:16:50 +08:00
SevicheCC
b18b150f68 update deps 2023-05-09 16:04:33 +08:00
SevicheCC
d927c0ef09 add whitespace 2023-05-09 02:06:17 +08:00
SevicheCC
62c47c701e update personal info 2023-05-09 01:58:33 +08:00
SevicheCC
34691d4b4c merge with upstream 3f449443be 2023-05-09 01:43:16 +08:00
SevicheCC
2cfc5b2783 new posts and remark42 2023-05-09 00:55:32 +08:00
sevichecc
5993aa2a6b post: 🔨 fix indent 2023-02-16 01:19:23 +08:00
sevichecc
a5998f5849 post: 🔨 fix referenct 2023-02-16 00:47:24 +08:00
sevichecc
bc4c959a29 post: 🔨remove emoji 2023-02-16 00:27:01 +08:00
sevichecc
cec524f59b post: new post about tools 2023-02-16 00:20:09 +08:00
sevichecc
03ee044482 chore: ♻️ expand build space 2023-02-04 11:57:44 +08:00
sevichecc
c9e8c38cfa post: 🔨 little tweaks 2023-02-04 11:56:49 +08:00
sevichecc
5d1b25c678 post: ♻️ refactor content 2023-02-04 00:05:09 +08:00
sevichecc
3b70f808ec post: 🧼 make some improvement 2023-02-03 23:49:21 +08:00
sevichecc
d995dd5cb6 post: 🔨 missing url 2023-02-03 23:47:17 +08:00
sevichecc
254ccca9b1 refactor: ♻️ remove deploy test 2023-02-03 23:40:54 +08:00
sevichecc
002f1d55f7 chore: ⬆️ merge with upsteam 8ce01f4b70 2023-02-03 23:39:47 +08:00
sevichecc
17a039a043 chore: ⬆️ merge with upsteam a8e5c55228 2023-02-03 23:37:25 +08:00
sevichecc
09ad19e627 fix: 🔨 losing image 2023-02-03 23:29:04 +08:00
sevichecc
55ed0bc3e3 chore: ⬆️ update devpendencies 2023-02-03 21:37:22 +08:00
sevichecc
f9276a11a9 post: 🔨 little tweaks 2023-02-03 21:36:47 +08:00
sevichecc
8c0baefb9c post: 🔖 monthly reading 2023-02-03 21:35:36 +08:00
sevichecc
6768187eb2 post:🔨 update release version 2023-02-01 15:33:00 +08:00
sevichecc
cfe746dfd6 post: ♻️ rewrite 2023-02-01 15:27:19 +08:00
sevichecc
1a32b7e9b8 refactor: ♻️ weaken the action buttons 2023-01-30 17:28:52 +08:00
sevichecc
3c28b61096 format code 2023-01-30 13:53:06 +08:00
sevichecc
9acbd6721b 🔨 decrese the card shadow and remove image shadow 2023-01-30 13:42:38 +08:00
sevichecc
9519c931a4 update deploy script 2023-01-30 00:39:24 +08:00
sevichecc
a72a21c688 new post 2023-01-30 00:01:05 +08:00
sevichecc
5e39cd0012 replace image source 2023-01-29 18:13:40 +08:00
sevichecc
ed65720a39 add footer since date 2023-01-29 18:13:00 +08:00
sevichecc
1481384339 merge with upsteam 89d8512758 2023-01-27 17:39:56 +08:00
sevichecc
83a5509ef0 merge with upsteam 055d890c79 (diff-02b812f3ec51006878cda37f92a36abc785ee5518b84340ce4a7ed41051c93f0) 2023-01-26 00:45:59 +08:00
sevichecc
6583df822e merge with upsteam 455fcd5941 2023-01-26 00:43:14 +08:00
sevichecc
ffd76f5d56 merge with upsteam 5731381edb 2023-01-26 00:39:09 +08:00
sevichecc
b604050d9f merge with upsteam 7f6cc6bc09 2023-01-26 00:30:36 +08:00
sevichecc
bae3b10a94 merge with upsteam 950fc38068 2023-01-26 00:22:34 +08:00
sevichecc
a8a6fd43d4 merge with upsteam 2ef763fc34 2023-01-26 00:15:28 +08:00
sevichecc
94a4949f21 merge with upsteam 35b3514bd8 2023-01-26 00:10:01 +08:00
sevichecc
af5e4e100a merge with upsteam 29b6cc4abd 2023-01-26 00:07:15 +08:00
sevichecc
fcc51c609f merge with upsteam 85d1b5d057 2023-01-26 00:05:50 +08:00
sevichecc
5ea4b9a171 merge with upsteam 16c08d841c 2023-01-26 00:03:16 +08:00
sevichecc
89671e6b1a merge with upsteam 93bfad5146 2023-01-25 23:55:50 +08:00
sevichecc
48bd5b970f merge with upsteam 07f4ac77bc 2023-01-25 23:49:28 +08:00
sevichecc
3301fed08c fix typo 2023-01-22 11:56:09 +08:00
sevichecc
7ebaa57d25 update README 2023-01-22 03:04:43 +08:00
sevichecc
c7a853aa8d new psot 2023-01-22 03:03:34 +08:00
sevichecc
27cbb38784 fix blockquote inline style 2023-01-13 18:29:16 +08:00
sevichecc
70b196ab55 fix wrong newline marker 2023-01-13 18:17:19 +08:00
sevichecc
32a20d18c6 expand node space size 2023-01-13 18:16:31 +08:00
sevichecc
2e39f0d002 test rollup override 2023-01-13 17:56:10 +08:00
sevichecc
761e1579c9 add new line 2023-01-13 17:44:07 +08:00
sevichecc
698cbf23ee fix wrong codeblock 2023-01-13 16:09:18 +08:00
sevichecc
129f94256b new post 2023-01-13 15:58:43 +08:00
sevichecc
12d4308382 Merge branch 'main' of https://github.com/Sevichecc/Urara-Blog 2023-01-13 15:56:11 +08:00
sevichecc
c7e4fa0743 new post 2023-01-13 15:55:34 +08:00
sevichecc
de9a6dc1d6 new post 2023-01-09 12:59:38 +08:00
125e2d8a3f change the key's path 2023-01-08 01:13:40 +08:00
934175040a fix typo 2023-01-07 22:12:11 +08:00
fba7b6caa8 update post detail 2023-01-06 19:20:18 +08:00
6150cb99b5 revert packeage version 2023-01-01 21:54:52 +08:00
f873231ff5 update dependency and update post 2023-01-01 21:28:57 +08:00
56a6b35969 new post 2023-01-01 21:15:22 +08:00
522903bf66 add tags 2022-12-31 16:13:41 +08:00
8a7ce1334f fix format 2022-12-30 17:06:29 +08:00
6df32981ed add newsletter post 2022-12-30 16:56:04 +08:00
a60fffe045 fix typo 2022-12-27 17:04:47 +08:00
06d2daa57e update project 2022-12-27 16:44:46 +08:00
sevichecc
7a20781835 replace the bookmark link 2022-12-26 17:08:33 +08:00
sevichecc
f37e97a659 update 2022-12-26 16:21:57 +08:00
sevichecc
a7f98f64ed typo 2022-12-23 15:06:50 +08:00
sevichecc
d1e6708372 update post 2022-12-22 17:24:29 +08:00
sevichecc
8207fc37c4 update post 2022-12-22 17:11:59 +08:00
sevichecc
9f19f3def6 revert u-photo 2022-12-22 00:20:41 +08:00
sevichecc
79d53a8305 compress images 2022-12-22 00:12:20 +08:00
sevichecc
7d2add5908 update dependecies 2022-12-22 00:12:05 +08:00
sevichecc
de5b2eb855 add webring 2022-12-22 00:11:53 +08:00
sevichecc
544d1329f1 update post 2022-12-21 01:49:06 +08:00
sevichecc
9a5a32b84d revert heti 2022-12-21 00:24:30 +08:00
sevichecc
85e59ea101 update snow and heti 2022-12-20 23:43:46 +08:00
sevichecc
565f9a4741 new friends 2022-12-20 14:07:15 +08:00
sevichecc
ceeaf79813 update post 2022-12-20 14:03:38 +08:00
sevichecc
33383a713a remove imagetool 2022-12-20 00:48:52 +08:00
sevichecc
9a8c21dd94 Update dependencies 2022-12-20 00:45:56 +08:00
sevichecc
0d8be4ed2c update post 2022-12-20 00:36:57 +08:00
sevichecc
f745b442aa update post 2022-12-20 00:31:40 +08:00
sevichecc
50b67ff7ab typo 2022-12-20 00:30:39 +08:00
sevichecc
6c79aad7f8 typo 2022-12-20 00:24:51 +08:00
sevichecc
2cda61b258 new post 2022-12-20 00:12:20 +08:00
sevichecc
e3504dc9ea revert imagetool 2022-12-18 16:16:30 +08:00
sevichecc
e35cc0358d update PGP keys 2022-12-17 11:51:19 +08:00
sevichecc
8aab7476b8 fix avatar 2022-12-16 00:55:16 +08:00
sevichecc
35cd280b4e merge witih upsteam c283797207 2022-12-15 23:23:21 +08:00
sevichecc
e573f44c64 merge with upsteam 6eed620c37 2022-12-15 23:04:28 +08:00
sevichecc
78d84c7007 revert footnote 2022-12-14 18:41:51 +08:00
sevichecc
1b132e0f79 update email 2022-12-14 18:15:15 +08:00
sevichecc
fbd08730aa update dependencies 2022-12-14 17:00:00 +08:00
sevichecc
d1f24cb315 fix date 2022-12-12 17:28:51 +08:00
sevichecc
f36fb27520 typo 2022-12-12 17:25:22 +08:00
sevichecc
fbe4a8c049 new post 2022-12-12 17:23:23 +08:00
sevichecc
a6518742fa change pgp url in profile 2022-12-12 15:39:59 +08:00
sevichecc
6f5cca9b49 move pgp path 2022-12-12 15:37:36 +08:00
sevichecc
c4e2987d09 fix pgp url 2022-12-12 14:21:30 +08:00
sevichecc
846c3dfb4e update key url 2022-12-12 14:10:37 +08:00
sevichecc
4e7e166741 update key 2022-12-12 14:06:54 +08:00
sevichecc
63e205dbee compress image 2022-12-10 11:14:03 +08:00
sevichecc
ef40691ae0 compress size of image 2022-12-10 02:56:08 +08:00
sevichecc
859055145c update to vite 4.0 & dependencies 2022-12-10 02:46:18 +08:00
sevichecc
5f82002927 fix trailingSlash 2022-12-10 02:40:13 +08:00
sevichecc
abf0af9d0a merge with upsteam 1ad522ad69 2022-12-08 20:34:21 +08:00
sevichecc
7933868ed4 minify cover image 2022-12-08 18:59:59 +08:00
sevichecc
145db1e3d7 new post 2022-12-08 18:25:41 +08:00
sevichecc
bc744a6fe1 revert post title 2022-11-21 14:30:09 +08:00
sevichecc
5456694bb0 replace acount of remove follow 2022-11-19 17:58:03 +08:00
sevichecc
02b3421515 revert card title 2022-11-19 17:38:25 +08:00
sevichecc
87431ce883 merge with upsteam e5438c818b 2022-11-19 17:06:15 +08:00
sevichecc
96f5eadb5f merge with upsteam 1d6a799ca1 2022-11-19 14:48:03 +08:00
sevichecc
254fc15d16 fix: header and head 2022-11-17 22:37:03 +08:00
sevichecc
bc5317aa93 update devpendencies 2022-11-17 21:45:51 +08:00
sevichecc
c25250957e update with 9f3df09 2022/11/16 2022-11-16 14:01:37 +08:00
sevichecc
2402a28938 feat:add pleroma redirect 2022-11-14 21:54:49 +08:00
sevichecc
3ead5f8092 change cover image 2022-11-01 15:31:40 +08:00
sevichecc
8f1a4209c4 fix path of cover image and upgrade dependance 2022-11-01 15:16:27 +08:00
sevichecc
776b6fa55a new post 2022-11-01 14:29:19 +08:00
sevichecc
034f4bf0ac new post 2022-10-16 17:06:46 +08:00
sevichecc
a6aaaa0a68 typo 2022-10-03 21:56:58 +08:00
sevichecc
dff72b3073 fix: resolve JavaScript heap out of memory problem 2022-10-03 21:42:57 +08:00
sevichecc
3b48ece929 revert: remove template in code block 2022-10-03 21:19:33 +08:00
sevichecc
bcf63c83a7 typo 2022-10-03 19:39:41 +08:00
sevichecc
322392cdae new post 2022-10-03 19:38:54 +08:00
sevichecc
e1e41f325b new post 2022-10-03 19:37:32 +08:00
sevichecc
74ec341e16 fix: remove redundant css class 2022-10-02 23:24:10 +08:00
sevichecc
c517418e54 fix: change theme overflow 2022-10-02 23:01:22 +08:00
sevichecc
d9c6d1ae97 new post 2022-10-02 14:30:03 +08:00
sevichecc
d290c3cf70 new post 2022-10-01 22:57:14 +08:00
sevichecc
19f13f8c79 new post 2022-10-01 22:43:30 +08:00
sevichecc
ad9db582c8 new post 2022-10-01 22:31:08 +08:00
sevichecc
6abe138aa9 fix: change friend's name 2022-09-30 22:59:18 +08:00
sevichecc
eafe2f8417 fix:修复标题问题 2022-09-30 22:32:31 +08:00
sevichecc
e1aa3951ea new friends 2022-09-25 14:13:59 +08:00
sevichecc
bd7d35d050 merge with upstream 4745cd 2022-09-10 11:18:21 +08:00
sevichecc
867cad5d7d merge with 894b532 2022-09-10 11:13:07 +08:00
sevichecc
e7a63a4d73 update post summary 2022-09-08 13:30:44 +08:00
sevichecc
0dfb834044 merge with 39b858a 2022-09-08 00:02:13 +08:00
sevichecc
cd9aef3b3f merge with 39b858a 2022-09-07 23:58:47 +08:00
sevichecc
300164443f migrate route 2022-09-07 23:29:18 +08:00
sevichecc
f74b530662 marge with upsteam 2022-09-05 13:41:04 +08:00
sevichecc
f352f70280 move friends 2022-09-03 14:23:36 +08:00
sevichecc
e57c287c48 regular format 2022-09-03 13:09:41 +08:00
sevichecc
29fd250ace new post and merge with upsteam 3a99081 2022-09-03 13:04:22 +08:00
217 changed files with 18345 additions and 5850 deletions

35
.gitignore vendored
View file

@ -1,15 +1,26 @@
.DS_Store
node_modules
.svelte-kit
/package
src/routes/**/
src/routes/*.md
static/
# build output
build
.vercel_build_output/
.netlify/
.env.local
.env.**.local
myblog/urara/2022-06-12-appwrite.md
static
.svelte-kit
.netlify
.vercel
# dependencies
node_modules
# env
*.local
# logs
pnpm-debug.log*
# macOS-specific files
.DS_Store
# temp file
src/routes/**/+page.svelte.md
src/routes/**/+page.md
src/static
*.config.js
urara.js

1
.npmrc
View file

@ -1 +1,2 @@
engine-strict=true
strict-peer-dependencies=false

2
.nvmrc
View file

@ -1 +1 @@
v18.4.0
v19.4.0

View file

@ -1,7 +1,7 @@
{
"editor.formatOnSave": true,
"files.eol": "\n",
"typescript.tsdk": "node_modules\\typescript\\lib",
"typescript.tsdk": "node_modules/typescript/lib",
"css.lint.unknownAtRules": "ignore",
"svelte.plugin.css.diagnostics.enable": false,
"[html]": {

View file

@ -20,11 +20,11 @@ My Tech Blog, base on [Urara](https://github.com/importantimport/urara)
## TODO
- [ ] Note Page
- [ ] Archie Page
- [ ] Archvie Page
- [ ] Refactoring the atom feed format
- [ ] NeoDB component
- [ ] ...
### License:
### License
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)
© 2024 Sevi.C All Rights Reserved.

View file

@ -1,7 +1,5 @@
#!/bin/bash
echo "————————1. Build locally————————"
netlify build
echo "————————2.Deploy test————————"
netlify deploy
echo "————————3.Deploy————————"
echo "————————2.Deploy————————————————"
netlify deploy --prod

View file

@ -13,6 +13,7 @@ import { parse, join } from 'path'
import { visit } from 'unist-util-visit'
import { toString } from 'mdast-util-to-string'
import Slugger from 'github-slugger'
import remarkFFF from 'remark-fff'
import remarkFootnotes from 'remark-footnotes'
// highlighter
@ -24,12 +25,12 @@ type VALUE = { [key in string | number]: VALUE } | Array<VALUE> | string | boole
const remarkUraraFm =
() =>
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => {
const filepath = (filename as string).split('/src/routes')[1]
const filepath = filename ? filename.split('/src/routes')[1] : 'unknown'
const { dir, name } = parse(filepath)
if (!data.fm) data.fm = {}
// Generate slug & path
data.fm.slug = filepath
data.fm.path = join(dir, `/${name}`.replace('/index', '').replace('.svelte', ''))
data.fm.path = join(dir, `/${name}`.replace('/+page', '').replace('.svelte', ''))
// Generate ToC
if (data.fm.toc !== false) {
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []]
@ -40,23 +41,9 @@ const remarkUraraFm =
slug: slugs.slug(toString(node), false)
})
})
data.fm.toc = toc
if (toc.length > 0) data.fm.toc = toc
else data.fm.toc = false
}
// Auto-read created & updated
if (!data.fm.created || !data.fm.updated) {
const { ctime, mtime } = statSync(new URL(`./urara${filepath}`, import.meta.url))
if (!data.fm.created) data.fm.created = ctime
if (!data.fm.updated) data.fm.updated = mtime
}
// Remark FFF Experimental (Hugo -> MDsveX)
Object.entries({
image: 'images',
tags: 'category',
bookmark_of: 'bookmarkOf',
like_of: 'likeOf',
repost_of: 'repostOf',
in_reply_to: 'inReplyTo'
}).forEach(([output, input]: string[]) => (data.fm = { ...data.fm, [output]: data.fm![input] }))
}
// Better type definitions needed
@ -72,9 +59,7 @@ const remarkUraraSpoiler = () => (tree: Node<Data>) =>
return node
})
const defineConfig = (config: MdsvexOptions) => config
export default defineConfig({
export default {
extensions: ['.svelte.md', '.md'],
smartypants: {
dashes: 'oldschool'
@ -104,9 +89,24 @@ export default defineConfig({
)}\` }`
}
},
remarkPlugins: [remarkUraraFm, remarkUraraSpoiler, [remarkFootnotes, { inlineNotes: true }]],
remarkPlugins: [
[
remarkFFF as any,
{
presets: ['hugo'],
target: 'mdsvex',
autofill: {
provider: 'fs',
path: (path: string) => path.replace('/src/routes/', '/urara/')
}
}
],
remarkUraraFm,
remarkUraraSpoiler,
[remarkFootnotes, { inlineNotes: true }]
],
rehypePlugins: [
rehypeSlug,
rehypeSlug as any,
[rehypeAutolinkHeadings, { behavior: 'wrap' }],
[
rehypeExternalLinks,
@ -116,4 +116,4 @@ export default defineConfig({
}
]
]
})
} as MdsvexOptions

View file

@ -1,8 +1,7 @@
[build]
command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm build"
command = "corepack prepare pnpm@8.5.1 --activate && pnpm i && npx pnpm build"
publish = "build"
[build.environment]
NPM_FLAGS = "--version"
AWS_LAMBDA_JS_RUNTIME = "nodejs16.x"
@ -26,13 +25,17 @@ node_bundler = "esbuild"
[[headers]]
for = "/*"
[headers.values]
Access-Control-Allow-Origin = "https://seviche.cc"
X-Frame-Options = "DENY"
Access-Control-Allow-Origin = "sevic.me"
X-Frame-Options = "SAMEORIGIN"
X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block"
Content-Security-Policy = "style-src 'self' 'unsafe-inline' https://cdn.commento.io/css/commento.css http://fonts.cdnfonts.com/css/lato ; script-src 'self' 'unsafe-inline' https://*.seviche.cc https://giscus.app https://hexoverc.vercel.app/umami.js https://cdn.splitbee.io/sb.js https://cdn.commento.io/js/commento.js"
Content-Security-Policy = "script-src 'self' 'unsafe-inline' https://*.seviche.cc https://giscus.app https://hexoverc.vercel.app/umami.js https://cdn.splitbee.io/sb.js https://plausiable.seviche.cc/js/script.js"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "usb=()"
[[redirects]]
from = "/.well-known/webfinger"
to = "https://kongwoo.icu/.well-known/webfinger?resource=acct:blog@kongwoo.icu"
status = 302
force = true
[[redirects]]
from = "/.well-known/host-meta"

View file

@ -12,16 +12,12 @@
"tsc:watch": "tsc -w -p tsconfig.node.json",
"urara:build": "node urara.js build",
"urara:watch": "node urara.js watch",
"kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite dev",
"kit:build": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite build",
"kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=11474 vite dev",
"kit:build": "cross-env NODE_OPTIONS=--max_old_space_size=11474 vite build",
"dev:parallel": "npm-run-all -p -r tsc:watch urara:watch \"kit:dev {@} \" --",
"dev": "npm-run-all -s tsc \"dev:parallel {@} \" --",
"build": "npm-run-all -s tsc urara:build kit:build clean",
"preview": "vite preview",
"dev:urara": "node urara.js watch",
"dev:kit": "export NODE_OPTIONS=--max_old_space_size=8192 && MODE=development svelte-kit dev",
"build:urara": "node urara.ts build",
"build:kit": "export NODE_OPTIONS=--max_old_space_size=8192 && svelte-kit build",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
@ -29,58 +25,66 @@
"zhlint": "zhlint urara/*/*.md --fix && zhlint urara/*.md --fix"
},
"devDependencies": {
"@iconify-json/heroicons-outline": "^1.1.2",
"@iconify-json/heroicons-solid": "^1.1.2",
"@iconify-json/ic": "^1.1.9",
"@iconify-json/simple-icons": "1.1.21",
"@iconify-json/material-symbols": "1.1.14",
"@iconify-json/mdi": "^1.1.30",
"@iconify-json/uil": "^1.1.2",
"@sveltejs/adapter-auto": "1.0.0-next.64",
"@sveltejs/adapter-node": "1.0.0-next.86",
"@sveltejs/adapter-static": "1.0.0-next.39",
"@sveltejs/kit": "1.0.0-next.405",
"@tailwindcss/typography": "^0.5.4",
"@types/node": "^18.7.8",
"@iconify-json/heroicons-outline": "^1.1.6",
"@iconify-json/heroicons-solid": "^1.1.7",
"@iconify-json/ic": "^1.1.13",
"@iconify-json/icon-park-twotone": "1.1.9",
"@iconify-json/material-symbols": "1.1.41",
"@iconify-json/mdi": "^1.1.52",
"@iconify-json/simple-icons": "1.1.52",
"@iconify-json/uil": "^1.1.4",
"@sveltejs/adapter-netlify": "^2.0.7",
"@sveltejs/adapter-static": "^2.0.2",
"@sveltejs/adapter-vercel": "2.4.3",
"@sveltejs/kit": "^1.19.0",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "^20.2.5",
"@types/unist": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"autoprefixer": "^10.4.8",
"chalk": "^5.0.1",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"@unocss/extractor-svelte": "^0.51.13",
"@vite-pwa/sveltekit": "^0.1.3",
"chalk": "^5.2.0",
"chokidar": "^3.5.3",
"cross-env": "^7.0.3",
"cssnano": "^5.1.13",
"daisyui": "^2.24.0",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"daisyui": "^2.51.6",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-svelte3": "^4.0.0",
"fenceparser": "^2.2.0",
"fff-flavored-frontmatter": "~0.2.2",
"github-slugger": "^1.4.0",
"mdast-util-to-string": "^3.1.0",
"fff-flavored-frontmatter": "~0.5.3",
"github-slugger": "^2.0.0",
"mdast-util-to-string": "^3.2.0",
"mdsvex": "^0.10.6",
"netlify-cli": "^16.3.1",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.16",
"prettier": "^2.7.1",
"prettier-plugin-svelte": "^2.7.0",
"postcss": "^8.4.23",
"postcss-lightningcss": "^0.7.0",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-external-links": "^2.0.0",
"rehype-slug": "^5.0.1",
"remark": "^14.0.2",
"rehype-external-links": "^2.1.0",
"rehype-slug": "^5.1.0",
"remark": "^14.0.3",
"remark-fff": "~0.5.3",
"remark-footnotes": "~2.0.0",
"shiki-twoslash": "^3.1.0",
"svelte": "^3.49.0",
"rollup": "^3.23.0",
"shiki-twoslash": "^3.1.2",
"svelte": "^3.59.1",
"svelte-bricks": "^0.1.7",
"svelte-check": "^2.8.1",
"svelte-preprocess": "^4.10.7",
"svelte-typeahead": "^4.2.4",
"tailwindcss": "^3.1.8",
"tslib": "^2.4.0",
"typescript": "^4.7.4",
"unist-util-visit": "^4.1.0",
"unocss": "^0.45.8",
"vite": "^3.0.9",
"vite-plugin-pwa": "^0.12.3",
"workbox-window": "^6.5.4"
"svelte-check": "^3.4.3",
"svelte-preprocess": "^5.0.4",
"svelte-typeahead": "^4.4.1",
"sveltekit-embed": "^0.0.12",
"tailwindcss": "^3.3.2",
"tslib": "^2.5.2",
"typescript": "^5.0.4",
"unist-util-visit": "^4.1.2",
"unocss": "^0.51.13",
"vite": "^4.3.9",
"vite-imagetools": "^4.0.19",
"vite-plugin-pwa": "^0.14.7",
"workbox-build": "^6.6.0",
"workbox-window": "^6.6.0"
}
}

File diff suppressed because it is too large Load diff

11
src/app.d.ts vendored
View file

@ -1,8 +1,9 @@
/// <reference types="@sveltejs/kit" />
import { FFFBase, FFFExtra } from 'fff-flavored-frontmatter'
import type { FFFBase, FFFMention } from 'fff-flavored-frontmatter'
interface ImportMetaEnv extends Readonly<Record<string, string>> {
readonly URARA_SITE_PROTOCOL?: 'http://' | 'https://'
readonly URARA_SITE_DOMAIN?: string
}
@ -14,8 +15,8 @@ interface ImportMeta {
declare global {
namespace Urara {
namespace Post {
type Frontmatter = Omit<FFFBase, 'created' | 'updated' | 'image' | 'audio' | 'video' | 'flags'> &
Pick<FFFExtra, 'in_reply_to'> & {
type Frontmatter = Omit<FFFBase, 'flags'> &
Pick<FFFMention, 'in_reply_to'> & {
/**
* post type.
* @remarks auto-generated
@ -50,6 +51,10 @@ declare global {
* @remarks auto-generated or set manually
*/
updated: string
/**
* the published date of the post.
*/
published?: string
/**
* the featured image for article, or image for "photo" / "multi-photo" posts.
* @remarks currently only supports string

View file

@ -13,5 +13,6 @@
<body itemscope itemtype="https://schema.org/WebPage">
%sveltekit.body%
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View file

@ -56,7 +56,12 @@ html {
/* .urara-prose a */
.urara-prose :is(p, li) > a {
@apply bg-[length:100%_0.2em] hover:bg-[length:100%_100%] bg-[position:0_88%] bg-gradient-to-t from-secondary/50 to-secondary/40 bg-no-repeat transition-all ease-in-out !no-underline;
@apply underline
font-normal
hover:decoration-red-700/50
hover:text-red-700
decoration-2
underline-offset-4 decoration-gray-700/30;
}
/* .urara-prose misc */
@ -188,9 +193,9 @@ pre.twoslash data-lsp:hover::before {
.urara-prose blockquote:before {
vertical-align: -0.4em;
@apply mr-2 text-5xl leading-3 italic font-serif opacity-25;
@apply mr-2 text-5xl mt-4 leading-3 italic font-serif opacity-25 float-left;
}
.urara-prose blockquote p {
@apply inline opacity-80 before:content-[''] after:content-[''];
@apply opacity-80 before:content-[''] after:content-[''];
}

7
src/hooks.server.ts Normal file
View file

@ -0,0 +1,7 @@
import type { Handle } from '@sveltejs/kit'
import { site } from '$lib/config/site'
export const handle: Handle = async ({ event, resolve }) =>
await resolve(event, {
transformPageChunk: ({ html }) => html.replace('<html lang="en">', `<html lang="${site.lang ?? 'en'}">`)
})

View file

@ -0,0 +1,5 @@
<button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Jump to comments">
<a href="#post-comment" class="btn btn-circle btn-ghost hover:bg-red-10">
<span class="i-heroicons-outline-chat-alt-2" />
</a>
</button>

View file

@ -1,3 +0,0 @@
<a href="#post-comment" class="btn btn-lg btn-circle btn-ghost bg-base-100 shadow-lg hover:shadow-xl">
<span class="i-heroicons-outline-chat-alt-2" />
</a>

View file

@ -3,10 +3,12 @@
export let post: Urara.Post
</script>
<a
href={`https://translate.google.com/translate?sl=auto&tl=${
navigator.languages ? navigator.languages[0] : navigator.language
}&u=${site.protocol + site.domain + post.path}`}
class="btn btn-lg btn-circle btn-ghost bg-base-100 shadow-lg hover:shadow-xl">
<span class="i-heroicons-outline-translate" />
</a>
<button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Translate">
<a
href={`https://translate.google.com/translate?sl=auto&tl=${
navigator.languages ? navigator.languages[0] : navigator.language
}&u=${site.protocol + site.domain + post.path}`}
class="btn btn-circle btn-ghost">
<span class="i-heroicons-outline-translate" />
</a>
</button>

View file

@ -3,10 +3,12 @@
export let post: Urara.Post
</script>
<a
href={`https://www.addtoany.com/share#url=${site.protocol + site.domain + post.path}&title=${encodeURI(
post.title ?? post.path.slice(1)
)}`}
class="btn btn-lg btn-circle btn-ghost bg-base-100 shadow-lg hover:shadow-xl">
<span class="i-heroicons-outline-share" />
</a>
<button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Share">
<a
href={`https://www.addtoany.com/share#url=${site.protocol + site.domain + post.path}&title=${encodeURI(
post.title ?? post.path.slice(1)
)}`}
class="btn btn-circle btn-ghost">
<span class="i-heroicons-outline-share" />
</a>
</button>

View file

@ -0,0 +1,63 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte'
import type { Remark42Config } from '$lib/types/post'
export let post: Urara.Post
export let config: Remark42Config
let remark42Instance: any
onMount(() => {
const [c, s] = [document.createElement('script'), document.createElement('script')]
c.id = 'remark42_config'
c.type = 'application/javascript'
c.innerHTML = `
var remark_config = {
host: '${config.host}',
site_id: '${config.site_id || 'remark'}',
url: '${post.path}',
components: [${config.components || "'embed'"}],
max_shown_comments: ${config.max_shown_comments || 15},
max_last_comments: ${config.max_last_comments || 15},
theme: '${config.theme || 'light'}',
page_title: '${config.page_title || post.title}',
locale: '${config.locale || 'en'}',
show_email_subscription: ${config.show_email_subscription || true},
show_rss_subscription: ${config.show_rss_subscription || true},
simple_view: ${config.simple_view || false},
no_footer: ${config.no_footer || false},
}`
s.id = 'remark42_script'
s.type = 'application/javascript'
s.innerHTML = `!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src='${config.host}/web/'+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);`
document.head.appendChild(c)
document.head.appendChild(s)
const opt = {
...config,
url: post.path
}
const checkRemark42 = () => {
if ((window as any).REMARK42) {
remark42Instance = (window as any).REMARK42.createInstance({
node: document.getElementById('remark42') as HTMLElement,
...opt
})
} else {
setTimeout(checkRemark42, 100)
}
}
checkRemark42()
})
onDestroy(() => {
if (remark42Instance && typeof remark42Instance.destroy === 'function') {
remark42Instance.destroy()
}
})
</script>
<div id="remark42" />

View file

@ -1,117 +0,0 @@
<!-- <script lang="ts">
import { onMount } from 'svelte'
import { site } from '$lib/config/site'
import type { WalineConfig } from '$lib/types/post'
export let post: Urara.Post
export let config: WalineConfig
onMount(() => {
const waline = document.createElement('script')
const [c, s] = [document.createElement('script'), document.createElement('script')]
c.id = 'disqus_config'
c.type = 'application/javascript'
console.log(waline)
Object.entries({
src: 'https://unpkg.com/@waline/client@v2/dist/waline.js',
serverURL: config.serverURL,
path: config.path ?? post.path ?? window.location.pathname,
lang: config.lang ?? 'en',
emoji: config.emoji ?? ['//unpkg.com/@waline/emojis@1.0.1/weibo'],
dark: config.dark ?? false,
meta: config.meta ?? ['nick', 'mail', 'link'],
requiredMeta: config.requiredMeta ?? [],
login: config.login ?? 'enable',
wordLimit: config.wordLimit ?? 0,
pageSize: config.pageSize ?? 10,
imageUploader: config.imageUploader,
highlighter: config.highlighter,
texRender: config.texRender,
copyright: config.copyright ?? true,
crossorigin: 'anonymous',
async: ''
}).forEach(([key, value]) => waline.setAttribute(key, value))
setTimeout(() => {
const observer = new MutationObserver(() => {
document.getElementById('giscus-loading').remove()
observer.disconnect()
})
observer.observe(document.getElementById('giscus'), {
childList: true
})
document.getElementById('giscus-container').appendChild(waline)
}, 1000)
})
</script>
<link rel="stylesheet" href="https://unpkg.com/@waline/client@v2/dist/waline.css" />
<div id="waline" class="waline-container" />
<style>
.waline-container {
background-color: var(--card-background);
border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l1);
padding: 2%;
}
.waline-container .vcount {
color: var(--card-text-color-main);
}
.v[data-class='v'] .vcard {
flex: 1;
width: 0;
padding-bottom: 0.5em;
border-bottom: 0; /*删掉回复下面的线*/
}
.v[data-class='v'] .vcard .vquote {
border-left: 1px solid rgba(237, 237, 237, 0.5);
}
@media (max-width: 580px) {
.v[data-class='v'] .vheader .vheader-item:not(:last-child) {
border-bottom: 1px solid rgba(237, 237, 237, 0.8); /*输入框分割线*/
}
}
/*日间模式*/
:root {
--waline-theme-color: #34495e; /*主题色,提交按钮*/
--waline-active-color: #246bb1; /*鼠标移到提交按钮上的颜色*/
/* 徽章 */
--waline-badge-color: #34495e; /*博主徽章色*/
--waline-avatar-radius: 5px;
--waline-avatar-size: 6rem;
--waline-dark-grey: #34495e; /*ID颜色*/
--waline-text-color: #34495e; /*字体颜色*/
--waline-font-size: 1.7rem; /*字体大小颜色*/
}
/*夜间模式*/
:root[data-scheme='dark'] {
--waline-theme-color: #acc6e0;
--waline-white: #34495e; /*按键字体颜色*/
--waline-active-color: #8ab1d8;
--waline-light-grey: #666;
--waline-dark-grey: #acc6e0; /*ID颜色*/
--waline-badge-color: #acc6e0;
/* 布局颜色 */
--waline-text-color: rgba(255, 255, 255, 0.7);
--waline-bgcolor: #515151;
--waline-bgcolor-light: #66696b; /*行内代码块颜色*/
--waline-border-color: #9b9c9c;
--waline-disable-bgcolor: #444;
--waline-disable-color: #272727;
/* 特殊颜色 */
--waline-bq-color: #9b9c9c; /*quote*/
/* 其他颜色 */
--waline-info-bgcolor: #acc6e0;
--waline-info-color: #9b9c9c;
}
.v[data-class='v'] .vcontent .vemoji {
width: 2.2em; /*表情包大小修改*/
margin: 0.25em;
}
.v[data-class='v'] .vheader {
border-bottom: 1px solid rgba(237, 237, 237, 0.8); /*输入框分割线*/
}
.v[data-class='v'] .vpanel {
border-radius: 8px; /*输入框圆角*/
}
</style> -->

View file

@ -74,6 +74,36 @@
</script>
<div class="flex flex-col gap-8">
{#if config?.form === true}
<form id="webmention-form" method="post" action="https://webmention.io/{config.username}/webmention">
<input type="hidden" name="target" value={site.protocol + site.domain + post.path} />
<div class="label gap-4">
<span class="label-text">send webmentions here:</span>
<!-- {#if config?.commentParade === true}
<span class="label-text-alt text-right">
or <a
class="hover:!text-primary"
href="https://quill.p3k.io/?dontask=1&me=https://commentpara.de/&reply={encodeURI(
site.protocol + site.domain + post.path
)}">
comment anonymously
</a>
</span>
{/if} -->
</div>
<div class="flex gap-2">
<div class="flex-1">
<input
class="input input-bordered focus:input-primary w-full"
type="text"
id="reply-url"
name="source"
placeholder="https://example.com/my-post" />
</div>
<button class="btn btn-primary flex-none mt-auto" type="submit" id="webmention-submit">Send</button>
</div>
</form>
{/if}
<div class="flex">
<p class="flex-1 m-auto italic opacity-50">
<!-- {`Sort by=${config?.sortBy ?? 'Created'}&sort-dir=${sortDirUp ? 'up' : 'down'}`} -->
@ -172,34 +202,4 @@
{:else}
<button id="webmention-loading" class="btn btn-lg btn-block flex btn-ghost loading" />
{/if}
{#if config?.form === true}
<form id="webmention-form" method="post" action="https://webmention.io/{config.username}/webmention">
<input type="hidden" name="target" value={site.protocol + site.domain + post.path} />
<div class="label gap-4">
<span class="label-text">send webmentions here:</span>
{#if config?.commentParade === true}
<span class="label-text-alt text-right">
or <a
class="hover:!text-primary"
href="https://quill.p3k.io/?dontask=1&me=https://commentpara.de/&reply={encodeURI(
site.protocol + site.domain + post.path
)}">
comment anonymously
</a>
</span>
{/if}
</div>
<div class="flex gap-2">
<div class="flex-1">
<input
class="input input-bordered focus:input-primary w-full"
type="text"
id="reply-url"
name="source"
placeholder="https://example.com/my-post" />
</div>
<button class="btn btn-primary flex-none mt-auto" type="submit" id="webmention-submit">Send</button>
</div>
</form>
{/if}
</div>

View file

@ -24,7 +24,7 @@
.then(
({ links }) => links.find((link: { rel: string }) => link.rel === 'http://ostatus.org/schema/1.0/subscribe').template
)
.then(template => (window.location.href = template.replace('{uri}', `sevichecc@kongwoo.icu`)))
.then(template => (window.location.href = template.replace('{uri}', `blog@seviche.cc`)))
.catch(error => console.error(error))
$: if (input)
input.length < 5 ? (status = '') : input.includes('@') && input.includes('.') ? (status = 'success') : (status = 'warning')

View file

@ -3,8 +3,8 @@
</script>
<script lang="ts">
export let user = undefined
export let repo = undefined
export let user = ''
export let repo = ''
let info: {
html_url: string
description: string
@ -20,7 +20,7 @@
})
</script>
<div class="card bg-base-100 !bg-base-200 my-4 ">
<div class="card bg-base-100 !bg-base-200 my-4">
<div class="p-6">
{#key info}
{#if info}

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { dev } from '$app/env'
import { dev } from '$app/environment'
let className = undefined
export { className as class }
export let src = undefined

View file

@ -19,10 +19,10 @@
<div class="rounded-full border-2 border-white shadow-xl w-16 h-16">
<img
class="hover:rotate-[360deg] transition-transform duration-1000 ease-in-out m-0"
src={avatar ?? site.author.avatar}
alt={name ?? site.author.name}
loading="lazy"
decoding="async" />
decoding="async"
src={avatar ?? site.author.avatar} />
</div>
</div>
{#if subname}

View file

@ -19,7 +19,7 @@
<div class="card-body p-4">
<div class="flex flex-col md:flex-row items-start gap-4">
<div class="mb-auto aspect-video w-full max-w-full shrink-0 md:max-w-xs">
<img class="rounded-md " src={project.img} alt={project.description} />
<img class="rounded-md" src={project.img} alt={project.description} />
</div>
<div class="card-title flex-1 flex-col items-start gap-4">
<div>

View file

@ -1,22 +1,26 @@
<script lang="ts">
export let id = undefined
export let list = undefined
export let playlist = undefined
export let start = undefined
export let autoplay = false
export let disablekb = false
export let controls = true
export let id: string
export let list: boolean | undefined = undefined
export let playlist: string | undefined = undefined
export let start: string | undefined = undefined
export let autoplay: boolean = false
export let disablekb: boolean = false
export let controls: boolean = true
export let fs = true
export let loop = false
const src = `https://www.youtube.com/embed/${id}?${list ? `listType=playlist&list=${list}&` : ''}${
playlist ? `playlist=${playlist}&` : ''
}${start ? `start=${start}` : ''}${autoplay ? 'autoplay=1&' : ''}${disablekb ? 'disablekb=1&' : ''}${
controls ? '' : 'controls=0&'
}${fs ? '' : 'fs=0&'}${loop ? 'loop=1' : ''}`
const src = `https://www.youtube.com/embed/${id}?${new URLSearchParams({
...(list ? { listType: 'playlist', list: 'true' } : {}),
...(playlist ? { playlist } : {}),
...(start ? { start } : {}),
autoplay: autoplay ? '1' : '0',
disablekb: disablekb ? '1' : '0',
controls: controls ? '1' : '0',
fs: fs ? '1' : '0',
loop: loop ? '1' : '0'
}).toString()}`
</script>
<div class="relative pb-[56.25%] mb-2">
<div class="relative pb-[56.25%] mb-4">
<iframe
{src}
class="absolute w-full h-full"

View file

@ -16,7 +16,7 @@
<p>
{#if footerConfig.nav}
{#each footerConfig.nav as { text, link }, i}
<a href={link} rel="noopener external" target="_blank">{text}</a>
<a href={link} rel="noopener noreferrer external" target="_blank">{text}</a>
{#if i + 1 < footerConfig.nav.length}
<span class="mr-1">·</span>
{/if}
@ -30,7 +30,7 @@
<br />
Powered by
<a
rel="noopener external"
rel="noopener noreferrer external"
target="_blank"
class="tooltip tooltip-secondary hover:text-secondary"
data-tip="🌸 [δ] - Based on MDsveX & SvelteKit 🌸"

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { dev } from '$app/env'
import { dev } from '$app/environment'
import { head } from '$lib/config/general'
import { site } from '$lib/config/site'
import OpenGraph from '$lib/components/head_opengraph.svelte'

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { browser, dev } from '$app/env'
import { browser, dev } from '$app/environment'
import { fly } from 'svelte/transition'
import { site } from '$lib/config/site'
import { theme } from '$lib/config/general'
@ -41,7 +41,8 @@
if (browser)
currentTheme =
localStorage.getItem('theme') ?? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'night' : 'lemonade')
localStorage.getItem('theme') ??
(window.matchMedia('(prefers-color-scheme: dark)').matches ? theme?.[1].name : theme[0].name ?? theme[0].name)
</script>
<svelte:head>
@ -54,60 +55,66 @@
id="header"
class:-translate-y-32={!pin && scrollY > 0}
class="fixed z-50 w-screen transition-all duration-500 ease-in-out border-b-2 border-transparent max-h-[4.125rem] {scrollY >
32 && 'backdrop-blur border-base-content/10 bg-base-100/30 md:bg-base-200/30'}">
<div in:fly={{ x: -50, duration: 300, delay: 300 }} out:fly={{ x: -50, duration: 300 }} class="navbar">
<div class="navbar-start">
{#if headerConfig.nav}
<Nav {path} {title} {pin} {scrollY} nav={headerConfig.nav} />
{/if}
<a href="/" sveltekit:prefetch class="btn btn-ghost normal-case text-lg">{site.title}</a>
</div>
<div class="navbar-end">
<!-- {#if headerConfig.search} -->
<!-- The button to open modal -->
<!-- <label for="search-modal" class="btn btn-square btn-ghost ml-2"><span class="i-heroicons-outline-search" /></label> -->
<!-- <button
on:click={() => {
search = !search
}}
type="submit"
class="btn btn-square btn-ghost ml-2">
32 && 'backdrop-blur !border-base-content/10 bg-base-100/30 md:bg-base-200/30'}">
{#if !search}
<div in:fly={{ x: -50, duration: 300, delay: 300 }} out:fly={{ x: -50, duration: 300 }} class="navbar">
<div class="navbar-start">
{#if headerConfig.nav}
<Nav {path} {title} {pin} {scrollY} nav={headerConfig.nav} />
{/if}
<a href="/" class="btn btn-ghost normal-case text-lg">{site.title}</a>
</div>
<div class="navbar-end">
{#if headerConfig.search}
<button aria-label="search" on:click={() => (search = !search)} tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-search" />
</button> -->
<!-- {/if} -->
<div id="change-theme" class="dropdown dropdown-end">
<div tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-color-swatch" />
</button>
{/if}
<div id="change-theme" class="dropdown dropdown-end">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
<div tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-color-swatch" />
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
<ul
tabindex="0"
class="flex flex-nowrap shadow-2xl menu dropdown-content bg-base-100 text-base-content rounded-box w-52 p-2 gap-2 overflow-y-auto max-h-[21.5rem]"
class:hidden={!pin}>
{#each theme as { name, text }}
<button
data-theme={name}
on:click={() => {
currentTheme = name
localStorage.setItem('theme', name)
}}
class:border-2={currentTheme === name}
class:border-primary={currentTheme === name}
class="btn btn-ghost w-full hover:bg-primary group rounded-lg flex bg-base-100 p-2 transition-all">
<p class="flex-1 text-left text-base-content group-hover:text-primary-content transition-color">
{text ?? name}
</p>
<div class="flex-none m-auto flex gap-1">
<div class="bg-primary w-2 h-4 rounded" />
<div class="bg-secondary w-2 h-4 rounded" />
<div class="bg-accent w-2 h-4 rounded" />
<div class="bg-neutral w-2 h-4 rounded" />
</div>
</button>
{/each}
</ul>
</div>
<ul
tabindex="0"
class="flex shadow-2xl menu dropdown-content bg-base-100 text-base-content rounded-box w-52 p-2 gap-2 overflow-y-auto max-h-[21.5rem]"
class:hidden={!pin}>
{#each theme as { name, text }}
<button
data-theme={name}
on:click={() => {
currentTheme = name
localStorage.setItem('theme', name)
}}
class:border-2={currentTheme === name}
class:border-primary={currentTheme === name}
class="btn btn-ghost hover:bg-primary group rounded-lg flex bg-base-100 p-2 transition-all">
<p class="flex-1 text-left text-base-content group-hover:text-primary-content transition-color">
{text ?? name}
</p>
<div class="flex-none m-auto flex gap-1">
<div class="bg-primary w-2 h-4 rounded" />
<div class="bg-secondary w-2 h-4 rounded" />
<div class="bg-accent w-2 h-4 rounded" />
<div class="bg-neutral w-2 h-4 rounded" />
</div>
</button>
{/each}
</ul>
</div>
</div>
</div>
{:else}
<div in:fly={{ x: 50, duration: 300, delay: 300 }} out:fly={{ x: 50, duration: 300 }} class="navbar">
<Search />
<button on:click={() => (search = !search)} tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-x" />
</button>
</div>
{/if}
</header>
<button

View file

@ -6,6 +6,8 @@
export let pin: boolean
</script>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
<div class="dropdown lg:hidden">
<label for="navbar-dropdown" tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-menu-alt-1" />
@ -14,11 +16,12 @@
id="navbar-dropdown"
tabindex="0"
class:hidden={!pin}
class="menu menu-compact dropdown-content bg-base-100 text-base-content shadow-lg rounded-box max-w-52 p-2">
class="menu menu-compact dropdown-content bg-base-100 text-base-content shadow-lg rounded-box min-w-max max-w-52 p-2
">
{#each nav as { text, link, children }}
{#if link && !children}
<li>
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
<a class:font-bold={link === path} href={link}>{text}</a>
</li>
{:else if children}
<li tabindex="0">
@ -29,7 +32,7 @@
<ul class="bg-base-100 text-base-content shadow-lg p-2">
{#each children as { text, link }}
<li>
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
<a class:font-bold={link === path} href={link}>{text}</a>
</li>
{/each}
</ul>
@ -49,18 +52,19 @@
{#each nav as { text, link, children }}
{#if link && !children}
<li>
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
<a class="!rounded-btn" class:font-bold={link === path} href={link}>{text}</a>
</li>
{:else if children}
<li tabindex="0">
<span class:font-bold={children.some(({ link }) => link === path)} class="gap-1">
<li>
<span class:font-bold={children.some(({ link }) => link === path)} class="!rounded-btn gap-1">
{text}
<span class="i-heroicons-solid-chevron-down -mr-1" />
</span>
<ul class="bg-base-100 text-base-content shadow-lg p-2">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<ul tabindex="0" class="menu rounded-box bg-base-100 text-base-content shadow-lg p-2">
{#each children as { text, link }}
<li>
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
<a class:font-bold={link === path} href={link}>{text}</a>
</li>
{/each}
</ul>

View file

@ -1,102 +1,21 @@
<script lang="ts">
import { onMount, createEventDispatcher } from 'svelte'
import { site } from '$lib/config/site'
import { header as headerConfig } from '$lib/config/general'
import Typeahead from 'svelte-typeahead'
import { page } from '$app/stores'
// ref : https://github.com/saadeghi/daisyui/blob/master/src/docs/src/components/Search.svelte
</script>
<form>
<input type="checkbox" id="search-modal" class="modal-toggle " />
<label for="search-modal" class="modal cursor-pointer w-full items-start pt-16 ">
<label class="modal-box w-11/12 max-w-4xl " for="">
<div class="form-control">
<span
class="i-heroicons-outline-search text-base-content pointer-events-none absolute z-10 my-2 ml-3 stroke-current opacity-60 w-5" />
</div>
<Typeahead placeholder="Search is not avaible …" limit={8} label="Search" inputAfterSelect="clear">
<div class="py-1 text-sm" />
</Typeahead>
<div class="pointer-events-none absolute right-14 top-8 gap-1 opacity-50 hidden lg:flex">
<kbd class="kbd kbd-sm">ESC</kbd>
</div>
</label>
</label>
<form
action={headerConfig?.search?.provider === 'duckduckgo' ? '//duckduckgo.com/' : '//google.com/search'}
method="get"
class="flex-1">
<input
type="text"
name="q"
class="input input-ghost input-bordered xl:bg-base-100 xl:text-base-content transition-all w-full h-12" />
<input
type="hidden"
name={headerConfig?.search?.provider === 'duckduckgo' ? 'sites' : 'sitesearch'}
value={site.protocol + site.domain} />
<button type="submit" class="btn btn-square btn-ghost ml-2">
<span class="i-heroicons-outline-search" />
</button>
</form>
<!-- <script lang="ts">
import { onMount, createEventDispatcher } from "svelte"
import { page } from "$app/stores"
import { goto } from "$app/navigation"
import Typeahead from "svelte-typeahead"
import { pages } from "@src/lib/data.js"
const dispatch = createEventDispatcher()
let searchIndex = []
pages.forEach((group) => {
group.items.forEach((item) => {
searchIndex.push(item)
})
})
let seachboxEl
function handleKeydown(e) {
if ((e.keyCode === 75 && e.metaKey) || (e.keyCode === 75 && e.ctrlKey)) {
e.preventDefault()
seachboxEl.querySelector("input[type=search]").focus()
dispatch("focus")
}
}
function onSelect({ detail }) {
goto(searchIndex[detail.originalIndex].href)
dispatch("search", detail)
}
</script>
<svelte:window on:keydown={handleKeydown} />
-->
<style global>
.searchbox [data-svelte-typeahead] {
background: none;
width: 100%;
max-width: 100%;
}
[data-svelte-search] label {
display: none;
}
[data-svelte-search] input {
background-color: transparent;
color: inherit;
border-radius: 0.5em;
padding-left: 2em;
}
[data-svelte-search] input::placeholder {
color: inherit;
}
[data-svelte-search] input:focus {
outline-color: hsla(var(--bc) / 0.2);
background-color: hsl(var(--b1));
color: hsla(var(--bc));
}
[data-svelte-typeahead] .svelte-typeahead-list {
transform: translateY(0.5em);
background: hsl(var(--b1));
border-radius: var(--rounded-btn);
overflow: hidden;
}
[data-svelte-typeahead] .svelte-typeahead-list .selected,
[data-svelte-typeahead] .svelte-typeahead-list .selected:hover {
background: hsl(var(--n));
color: hsl(var(--nc));
}
[data-svelte-typeahead] .svelte-typeahead-list li {
color: hsl(var(--bc));
}
[data-svelte-typeahead] .svelte-typeahead-list li:hover {
background: hsl(var(--b2));
color: hsl(var(--bc));
}
[data-svelte-typeahead] .svelte-typeahead-list li:not(:last-of-type) {
border-bottom-color: hsla(var(--bc) / 0.1);
}
</style>

File diff suppressed because one or more lines are too long

View file

@ -1,12 +1,12 @@
<script lang="ts">
export let post: Urara.Post
const actions = import.meta.glob<{ default: unknown }>('/src/lib/components/actions/*.svelte', { eager: true })
const actions = import.meta.glob<any>('/src/lib/components/actions/*.svelte', { eager: true, import: 'default' })
</script>
<div class="sticky top-24 hidden xl:flex flex-col gap-4 w-fit h-[calc(100vh-12rem)] ml-auto mr-8 my-8 justify-center">
<div class="sticky top-24 hidden xl:flex flex-col gap-4 w-fit max-h-[calc(100vh-12rem)] ml-auto mr-6 my-8 justify-center">
{#if Object.keys(actions).length}
{#each Object.values(actions) as action}
<svelte:component this={action.default} {post} />
<svelte:component this={action} {post} />
{/each}
{/if}
</div>

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { browser } from '$app/env'
import { browser } from '$app/environment'
import { post as postConfig } from '$lib/config/post'
import { posts as storedPosts } from '$lib/stores/posts'
import { title as storedTitle } from '$lib/stores/title'
@ -35,11 +35,10 @@
itemprop="blogPost"
class:md:mb-8={!preview}
class:lg:mb-16={!preview}
class:h-entry={preview}
class:group={preview}
class:image-full={preview && post.type === 'article' && post.image}
class:before:!rounded-none={preview && post.image}
class="card bg-base-100 rounded-none md:rounded-box md:shadow-xl z-10">
class="h-entry card bg-base-100 rounded-none md:rounded-box md:shadow-lg md:shadow-grey-10 overflow-hidden z-10">
{#if !preview && postConfig.bridgy}
<div id="bridgy" class="hidden">
{#each post.flags?.some( flag => flag.startsWith('bridgy') ) ? post.flags.flatMap( flag => (flag.startsWith('bridgy') ? flag.slice(7) : []) ) : [...(postConfig.bridgy.post ?? []), ...(postConfig.bridgy[post.type] ?? [])] as target}
@ -73,9 +72,10 @@
<div class="flex flex-col gap-2">
{#if post.image && !preview}
<figure
class={`md:order-last mb-4 ${post.type === 'article' ? 'flex-col gap-2 -mx-4 -mt-8 md:mt-0' : 'flex-col -mx-8'}`}>
class={`md:order-last rounded-lg mb-4 ${post.type === 'article' ? 'flex-col gap-2 -mt-8 md:mt-0' : 'flex-col -mx-8'}'
}`}>
<Image
class={`${post.type === 'article' ? 'u-featured rounded-box shadow-xl' : 'u-photo'}`}
class={`${post.type === 'article' ? 'u-featured' : 'u-photo'}`}
src={post.image}
alt={post.image}
{loading}
@ -91,7 +91,7 @@
<a itemprop="url" class="u-url p-name" href={post.path}>{post.title ?? post.path.slice(1)}</a>
</h2>
{:else}
<h1 itemprop="name headline" class="card-title text-3xl mb-8 p-name">{post.title ?? post.path.slice(1)}</h1>
<h1 itemprop="name headline" class="card-title text-2xl mb-8 p-name">{post.title ?? post.path.slice(1)}</h1>
{/if}
{/if}
{#if post.summary}

View file

@ -3,7 +3,7 @@
import { toSnake } from '$lib/utils/case'
export let post: Urara.Post
export let config: CommentConfig
const comments = import.meta.glob<{ default: unknown }>('/src/lib/components/comments/*.svelte', { eager: true })
const comments = import.meta.glob<any>('/src/lib/components/comments/*.svelte', { eager: true, import: 'default' })
let currentComment: string | undefined = undefined
let currentConfig: unknown | undefined = undefined
currentComment = localStorage.getItem('comment') ?? toSnake(config.use[0])
@ -14,8 +14,9 @@
{#if config?.use.length > 0}
<div id="post-comment" class="card card-body">
{#if config.use.length > 1}
<div class="tabs w-full mb-8" class:tabs-boxed={config?.['style'] === 'boxed'}>
<div class="tabs w-full" class:tabs-boxed={config?.['style'] === 'boxed'}>
{#each config.use as name}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
on:click={() => {
currentComment = toSnake(name)
@ -33,7 +34,7 @@
{#if currentComment}
{#key currentComment}
<svelte:component
this={comments[`/src/lib/components/comments/${currentComment}.svelte`].default}
this={comments[`/src/lib/components/comments/${currentComment}.svelte`]}
{post}
config={currentConfig} />
{/key}

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { fly } from 'svelte/transition'
import { browser } from '$app/env'
import { browser } from '$app/environment'
import Card from '$lib/components/post_card.svelte'
import Head from '$lib/components/head.svelte'
import Toc from '$lib/components/post_toc.svelte'
@ -22,7 +22,7 @@
<div
in:fly={{ x: 25, duration: 300, delay: 500 }}
out:fly={{ x: 25, duration: 300 }}
class="flex-1 w-full max-w-screen-md order-first ease-out transform mx-auto xl:mr-0">
class="flex-1 w-full order-first ease-out transform mx-auto xl:mr-0 xl:ml-0">
{#if browser}
<Action {post} />
{/if}
@ -30,7 +30,7 @@
<div
in:fly={{ x: -25, duration: 300, delay: 500 }}
out:fly={{ x: -25, duration: 300 }}
class="flex-1 w-full max-w-screen-md xl:order-last ease-out transform mx-auto xl:mr-0">
class="flex-1 w-full xl:order-last ease-out transform mx-auto xl:ml-0 xl:mr-0">
{#if browser && post.toc}
<div class="h-full hidden xl:block">
<Toc toc={post.toc} />

View file

@ -7,10 +7,9 @@
<nav class="flex flex-col md:flex-row flex-warp justify-evenly">
{#if prev}
<div
href={prev.path}
class:image-full={prev['image']}
class:md:rounded-r-box={next && !next['image']}
class="flex-1 card group rounded-none before:!rounded-none">
class="flex-1 card group rounded-none before:!rounded-none overflow-hidden">
{#if prev['image']}
<figure class="!block">
<Image
@ -34,10 +33,9 @@
{/if}
{#if next}
<div
href={next.path}
class:image-full={next['image']}
class:md:rounded-l-box={prev && !prev['image']}
class="flex-1 card group rounded-none before:!rounded-none">
class="flex-1 card group rounded-none before:!rounded-none overflow-hidden">
{#if next['image']}
<figure class="!block">
<Image

View file

@ -6,25 +6,12 @@
<div class="flex flex-wrap gap-2 rounded-box outline outline-neutral/10 p-4 {className}">
<span class="flex-none font-bold uppercase opacity-30">Reply to:&nbsp;</span>
{#if Array.isArray(in_reply_to)}
{#each in_reply_to as reply}
<a
href={reply}
rel="noopener external"
target="_blank"
class="flex-none flex rounded-badge bg-base-200 hover:bg-base-300 transition-all gap-2 px-4 u-in-reply-to">
<span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
{reply}
</a>
{/each}
{:else}
<a
href={in_reply_to}
rel="noopener external"
target="_blank"
class="ml-auto flex-none flex rounded-badge bg-base-200 hover:bg-base-300 transition-all gap-2 px-4 u-in-reply-to">
<span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
{in_reply_to}
</a>
{/if}
<a
href={in_reply_to}
rel="noopener noreferrer external"
target="_blank"
class="ml-auto flex-none flex rounded-badge bg-base-200 hover:bg-base-300 transition-all gap-2 px-4 u-in-reply-to">
<span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
{in_reply_to}
</a>
</div>

View file

@ -18,15 +18,15 @@
{site.author.name}
</a>
<span class:hidden={preview} class="opacity-50">/</span>
<a href={post.path} class="swap hover:swap-active u-url u-uid">
<a href={post.path} class="u-url u-uid swap group/time">
<time
class="swap-off font-semibold opacity-75 duration-500 ease-in-out mr-auto dt-published"
class="group-hover/time:opacity-0 font-semibold opacity-75 duration-500 ease-in-out mr-auto dt-published"
datetime={jsonPublished}
itemprop="datePublished">
{stringPublished}
</time>
<time
class="swap-on font-semibold text-primary duration-500 ease-in-out mr-auto dt-updated"
class="opacity-0 group-hover/time:opacity-100 font-semibold text-primary duration-500 ease-in-out mr-auto dt-updated"
datetime={jsonUpdated}
itemprop="dateModified">
{stringUpdated}

View file

@ -4,7 +4,6 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte'
import Tree from '$lib/components/post_toc_tree.svelte'
export let toc: Urara.Post.Toc[]
let intersecting: string[] = []
@ -34,7 +33,7 @@
// @ts-ignore: Cannot find name 'headingsObserver'
if (typeof headingsObserver !== 'undefined') headingsObserver.disconnect()
// @ts-ignore: Cannot find name 'articleObserver'
if (typeof headingsObserver !== 'undefined') articleObserver.disconnect()
if (typeof articleObserver !== 'undefined') articleObserver.disconnect()
})
$: if (intersecting.length > 0) bordered = intersecting
@ -53,16 +52,29 @@
aria-label="TableOfContent"
dir="rtl"
class="max-h-[calc(100vh-12rem)] overflow-y-hidden hover:overflow-y-auto">
<Tree
toc={toc.reduce(
(acc, heading) => {
let parent = acc
// @ts-ignore Type 'Toc | undefined' is not assignable to type 'Toc.' ts(2322)
while (parent.depth + 1 < heading.depth) parent = parent.children.at(-1)
parent.children = [...(parent.children ?? []), { ...heading, children: [] }]
return acc
},
{ depth: toc[0].depth - 1, children: [] }
)} />
<ul dir="ltr" id="toc-list-root">
{#each toc as { depth, title, slug }}
<li id={`toc-item-${slug}`} class="flex flex-col">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
dir="ltr"
on:click={() =>
// @ts-ignore Object is possibly 'null'. ts(2531)
document.getElementById(slug).scrollIntoView({ behavior: 'smooth' })}
id={`toc-link-${slug}`}
class="cursor-pointer border-l-4 border-transparent transition-all hover:border-primary hover:bg-base-content hover:bg-opacity-10 active:bg-primary active:text-primary-content active:font-bold pr-4 {depth <=
2
? 'py-3'
: 'py-2'}"
class:pl-4={depth <= 2}
class:pl-8={depth === 3}
class:pl-12={depth === 4}
class:pl-16={depth === 5}
class:pl-20={depth === 6}>
{title}
</span>
</li>
{/each}
</ul>
</nav>
</aside>

View file

@ -1,33 +0,0 @@
<script lang="ts">
export let toc: Urara.Post.Toc
const { title, slug, depth, children } = toc
</script>
{#if title}
<span
dir="ltr"
on:click={() =>
// @ts-ignore Object is possibly 'null'. ts(2531)
document.getElementById(slug).scrollIntoView({ behavior: 'smooth' })}
id={`toc-link-${slug}`}
class="cursor-pointer border-l-4 border-transparent transition-all hover:border-primary hover:bg-base-content hover:bg-opacity-10 active:bg-primary active:text-primary-content active:font-bold pr-4 {depth <=
2
? 'py-3'
: 'py-2'}"
class:pl-4={depth <= 2}
class:pl-8={depth === 3}
class:pl-12={depth === 4}
class:pl-16={depth === 5}
class:pl-20={depth === 6}>
{title}
</span>
{/if}
{#if children}
<ul dir="ltr" id={`toc-list-${slug ?? 'root'}`}>
{#each children as child}
<li id={`toc-item-${child.slug}`} class="flex flex-col">
<svelte:self toc={child} />
</li>
{/each}
</ul>
{/if}

View file

@ -1,10 +1,37 @@
<script lang="ts">
/* @see {@link https://github.com/sveltejs/kit/issues/241#issuecomment-1363621896} */
type Image = {
src: string
w: number
h: number
}
const sources = import.meta.glob<Image[]>(['/src/static/**/*.{jpg,jpeg,png,webp,avif}', '!/src/static/assets'], {
query: {
format: 'avif',
quality: '80',
width: '736',
source: ''
},
import: 'default',
eager: true
})
let className: string | undefined = undefined
export { className as class }
export let src: string
export let alt: string = src
export let loading: 'eager' | 'lazy' = 'lazy'
export let decoding: 'async' | 'sync' | 'auto' = 'async'
let source: Image[] | undefined = sources[`/src/static${src}`]
</script>
<img {src} {alt} class={className ?? 'rounded-lg my-2'} {loading} {decoding} />
{#if source}
<picture>
<source srcset={source.map(({ src, w }) => `${src} ${w}w`).join(', ')} type="image/avif" />
<img {src} {alt} class={className ?? 'rounded-lg my-2'} {loading} {decoding} />
</picture>
{:else}
<img {src} {alt} class={className ?? 'rounded-lg my-2'} {loading} {decoding} />
{/if}

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { fly } from 'svelte/transition'
export let path: string = ''
</script>
{#key path}
<div
class="bg-base-100 md:bg-base-200 min-h-screen pt-16 md:pb-8 lg:pb-16"
in:fly={{ y: 100, duration: 300, delay: 300 }}
out:fly={{ y: -100, duration: 300 }}>
<slot />
</div>
{/key}

View file

@ -52,19 +52,11 @@ export const friends: Friend[] = [
title: '野生栗子🌰',
link: 'https://blog.chestnut.monster/'
},
{
id: 'summerblue',
rel: 'friend',
name: '夏诤',
title: 'SummberBlue',
link: 'https://summerblue.space/',
descr: '早睡早起身体好'
},
{
id: 'loikin',
rel: 'friend',
name: 'Loikin',
title: '此生未命名',
title: '浣心',
link: 'https://blog.loikein.one/',
descr: '用爱和理性对抗荒谬',
avatar: '/assets/loikin.png'
@ -74,8 +66,42 @@ export const friends: Friend[] = [
rel: 'friend',
name: '鲨',
title: '一只脆脆鲨',
link: 'http://blog.sharktale.xyz/',
link: 'https://woods.sharktale.xyz/',
descr: '遇见一只脆脆鲨',
avatar: 'https://s2.loli.net/2022/03/30/xwOzn9G8TIqFPvR.jpg'
},
{
id: 'kwaa',
rel: 'friend',
name: '藍 +85CD',
title: './kwaa.dev',
link: 'https://kwaa.dev',
descr: '[DATA EXPUNGED]',
avatar: 'https://kwaa.dev/assets/any@512.webp'
},
{
id: 'debula',
rel: 'friend',
title: '秘密花园',
name: '本宝宝',
link: 'https://blog.debula.ml',
descr: '月亮一直跟着我走,它迷路了吗?',
avatar: 'https://blog.debula.ml/usr/uploads/violet.jpg'
},
{
id: 'zhuzi',
rel: 'friend',
title: 'Bambooom',
name: '竹子',
link: 'https://zhuzi.dev',
descr: 'Blah Blah Booooom'
},
{
id: 'litomore',
rel: 'friend',
title: "LitoMore's Mind",
name: 'LitoMore',
link: 'https://litomore.me',
avatar: 'https://litomore.me/favicon.svg'
}
]

View file

@ -1,121 +1,61 @@
import type { ThemeConfig, HeadConfig, HeaderConfig, FooterConfig, DateConfig, FeedConfig } from '$lib/types/general'
export const theme: ThemeConfig = [
{
name: 'lemonade',
text: 'Light'
},
{
name: 'night',
text: 'Dark'
},
{
name: 'cupcake',
text: 'Cupcake'
},
{
name: 'bumblebee',
text: 'Bumblebee'
},
{
name: 'emerald',
text: 'Emerald'
},
{
name: 'corporate',
text: 'Corporate'
},
{
name: 'valentine',
text: 'Valentine'
},
{
name: 'synthwave',
text: 'Synthwave'
},
{
name: 'retro',
text: 'Retro'
},
{
name: 'cyberpunk',
text: 'Cyberpunk'
},
{
name: 'halloween',
text: 'Halloween'
},
{
name: 'garden',
text: 'Garden'
},
{
name: 'forest',
text: 'Forest'
},
{
name: 'aqua',
text: 'Aqua'
},
{
name: 'lofi',
text: 'Lo-Fi'
},
{
name: 'pastel',
text: 'Pastel'
},
{
name: 'fantasy',
text: 'Fantasy'
},
{
name: 'wirefream',
text: 'Wireframe'
},
{
name: 'black',
text: 'Black'
},
{
name: 'luxury',
text: 'Luxury'
text: 'Light'
},
{
name: 'dracula',
text: 'Dracula'
},
{
name: 'cmyk',
text: 'CMYK'
},
{
name: 'autumn',
text: 'Autumn'
},
{
name: 'business',
text: 'Business'
},
{
name: 'acid',
text: 'Acid'
},
// {
// name: 'lemonade',
// text: 'Lemonade'
// },
// {
// name: 'night',
// text: '🌃 Night'
// },
{
name: 'coffee',
text: 'Coffee'
},
{
name: 'winter',
text: 'Winter'
name: 'cupcake',
text: 'Cupcake'
},
{
name: 'valentine',
text: 'Valentine'
},
{
name: 'aqua',
text: 'Aqua'
},
{
name: 'synthwave',
text: 'Synthwave'
},
{
name: 'night',
text: 'Night'
},
// {
// name: 'lofi',
// text: 'Lo-Fi'
// },
{
name: 'garden',
text: 'Garden'
},
{
name: 'lemonade',
text: 'Lemonade'
},
{
name: 'cmyk',
text: 'CMYK'
},
{
name: 'retro',
text: 'Retro'
},
{
name: 'black',
text: 'Black'
}
]
@ -131,7 +71,7 @@ export const head: HeadConfig = {
// Umami Analytics
'<script data-cfasync="false" defer data-do-not-track="true" data-website-id="2403ea30-74ff-4ffa-8264-556b9f3b2897" src="https://hexoverc.vercel.app/umami.js"></script>',
// splitbee
'<script async data-cfasync="false" src="https://cdn.splitbee.io/sb.js"></script>',
'<script async data-cfasync="false" src="https://cdn.splitbee.io/sb.js"></script>',
// Block Baiduspider
'<meta name="baiduspider" content="noindex,noarchive">',
// Microsub
@ -160,12 +100,20 @@ export const header: HeaderConfig = {
{
text: 'About',
link: '/about'
},
{
text: 'etc',
children: [
{
text: 'Bookmarks',
link: 'https://airtable.com/shrpftxf6JgRomP2X'
},
{
text: 'Daily Notes',
link: 'https://x.seviche.cc'
}
]
}
// ,
// {
// text: 'Notes',
// link: '/notes'
// }
]
}
@ -180,30 +128,11 @@ export const footer: FooterConfig = {
link: '/privacy'
}
],
html: '<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>'
html: '@Sevi.C All Rights Reserved.',
since: '2021'
}
export const date: DateConfig = {
// toPublishedString: {
// locales: 'en-US',
// options: {
// year: 'numeric',
// weekday: 'short',
// month: 'short',
// day: 'numeric',
// timeZone: 'Asia/Shanghai'
// }
// },
// toUpdatedString: {
// locales: 'en-US',
// options: {
// year: 'numeric',
// weekday: 'short',
// month: 'short',
// day: 'numeric',
// timeZone: 'Asia/Shanghai'
// }
// },
locales: 'en-US',
options: {
year: 'numeric',

View file

@ -5,14 +5,14 @@ export const post: PostConfig = {
post: ['mastodon']
},
comment: {
use: ['Webmention', 'Giscus'],
use: ['Remark42','Webmention', 'Giscus'],
style: 'boxed',
webmention: {
username: 'seviche.cc',
username: 'sevic.me',
sortBy: 'created',
sortDir: 'down',
form: true,
commentParade: true
commentParade: false
},
giscus: {
// src: 'https://giscus.kwaa.dev/client.js',
@ -22,16 +22,10 @@ export const post: PostConfig = {
categoryID: 'DIC_kwDOHSra4c4CO9ua',
theme: 'light',
lang: 'en'
},
remark42: {
host: 'https://remark42.seviche.cc',
no_footer: true
}
// waline: {
// serverURL: 'https://waline-seviche.vercel.app/',
// lang: 'en',
// emoji: [
// 'https://cdn.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs',
// 'https://cdn.jsdelivr.net/gh/norevi/blob-emoji-for-waline@2.0/blobs-gif',
// 'ttps://cdn.jsdelivr.net/gh/norevi/blob-emoji-for-waline@2.0/blobs-png'
// ],
// requiredMeta: ['nick', 'mail']
// }
}
}

View file

@ -19,6 +19,53 @@ export const projects: Project[] = [
// img: 'https://usc1.contabostorage.com/cc0b816231a841b1b0232d5ef0c6deb1:image/2022/06/d4d2489936e4f647c25df6982c6ef924.png',
// link: 'https://haibian.seviche.cc'
// },
{
id: 'Raycast-NeoDB',
name: 'Raycast - NeoDB',
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
description: 'Search NeoDB items and view item details',
feature: 'React',
img: 'https://github.com/raycast/extensions/raw/f7cf284a8c14e38aee758adb00120de827a144fb/extensions/neodb//metadata/neodb-1.png',
link: 'https://www.raycast.com/SevicheCC/neodb'
},
{
id: 'Raycast-Mastodon',
name: 'Raycast - Mastodon',
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
description: 'Publish status from Raycast to Mastodon, and view your bookmarked status',
feature: 'React',
img: 'https://github.com/raycast/extensions/raw/1824339d4b3b404efb53e4fb09ac79d190437773/extensions/mastodon//media/command.png',
link: 'https://www.raycast.com/SevicheCC/mastodon'
},
{
id: 'Raycast-miniflux',
name: 'Raycast - Miniflux',
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
description: 'Search RSS entries from Raycast, and more features',
feature: 'React',
img: 'https://github.com/raycast/extensions/raw/3fdad375dd06b7f390b629235c6a10c37d05fc79/extensions/miniflux//media/commands.png',
link: 'https://www.raycast.com/SevicheCC/miniflux'
},
{
id: 'Raycast-Akkoma',
name: 'Raycast - Akkoma',
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
description: 'Publish status from Raycast to Akkoma or Pleroma, and view your bookmarked status',
feature: 'React',
img: 'https://github.com/raycast/extensions/raw/42e765bc6bf970054fd69abfdc6ab3dd2ea4942d/extensions/akkoma//media/command.png',
link: 'https://www.raycast.com/SevicheCC/akkoma'
},
{
id: 'miniflux-injector',
name: 'Miniflux-injector',
tags: ['Svelte', 'Browser Extension', 'Miniflux', 'RSS'],
description:
"Browser extension for the self-hosted miniflux bookmark service. Fork from <a href='https://github.com/Fivefold/linkding-injector' target='_blank'>linkding-injector</a>",
feature: 'Svelte',
img: 'https://usc1.contabostorage.com/cc0b816231a841b1b0232d5ef0c6deb1:image/2022/12/7ae29e6a539895491fbb88a28c95aed7.png',
link: 'https://github.com/Sevichecc/miniflux-injector'
},
{
id: 'fokify',
name: 'Fokify ',

View file

@ -1,36 +1,32 @@
import type { SiteConfig } from '$lib/types/site'
export const site: SiteConfig = {
protocol: 'https://',
domain: 'seviche.cc',
title: 'Seviche.cc',
subtitle: 'Tech / Code / Random Life',
protocol: import.meta.env.URARA_SITE_PROTOCOL ?? import.meta.env.DEV ? 'http://' : 'https://',
domain: 'sevic.me',
title: 'sevic.me',
subtitle: 'Random Frontend-Developer',
lang: 'zh',
description: 'Tech / Code / Random Life',
description: 'Random Frontend-Developer',
author: {
name: '酸橘汁腌鱼',
avatar: '/assets/avatar.jpg',
name: 'Sevi.C',
avatar: '/assets/avatar.png',
status: '🖤',
bio: ' Code / Tech <br> Living a Random Life ',
bio: 'Full-stack wizard.',
metadata: [
{
text: '',
icon: 'i-mdi-github',
link: 'https://github.com/sevichecc'
},
{
text: '',
icon: 'i-simple-icons-matrix',
link: 'https://matrix.to/#/@seviche:kongwoo.icu'
},
{
text: '',
icon: 'i-heroicons-solid-key',
link: 'https://keys.openpgp.org/vks/v1/by-fingerprint/76DF9F9CC0C3619AA12CB914AFF18B986818D8AD',
link: '/assets/DDDDDDDD.asc',
rel: 'pgpkey'
},
{
text: '',
icon: 'i-ic-twotone-rss-feed',
link: '/atom.xml',
rel: 'rss'
@ -44,6 +40,6 @@ export const site: SiteConfig = {
// }
]
},
keywords: ['Tech', 'Code', 'Random Life'],
keywords: ['Tech', 'Code', 'Seviche CC', 'Frondend Developer', 'Programming'],
themeColor: '#3D4451'
}

View file

@ -1,10 +1,3 @@
import type { WalineEmojiInfo } from '@waline/client'
type WalineImageUploader = (image: File) => Promise<string>
type WalineHighlighter = (code: string, lang: string) => string
type WalineTexRenderer = (blockMode: boolean, tex: string) => string
export type PostConfig = {
bridgy?: {
[kind: string]: ('fed' | 'mastodon' | 'flickr' | 'github' | 'twitter')[]
@ -22,8 +15,7 @@ export type CommentConfig = {
giscus?: GiscusConfig
/** Utterances config, more at https://utteranc.es */
utterances?: UtterancesConfig
/** Waline config, more at https://waline.js.org/en/reference/component.html#texrenderer */
waline?: WalineConfig
remark42?: Remark42Config
}
export type WebmentionConfig = {
@ -81,39 +73,35 @@ export type UtterancesConfig = {
theme?: string
}
export type DisqusConfig = {
shortname: string
lang?: string
}
// Refhttps://waline.js.org/reference/component.html
export type WalineConfig = {
/** Waline server address url */
serverURL: string
/** Article path id*/
path?: string
/** Display language. */
lang?: string
/** Emoji settings, for details see https://waline.js.org/en/guide/client/emoji.html */
emoji?: (string | WalineEmojiInfo)[] | false
/** Darkmode support */
dark?: string | boolean
/** Reviewer attributes. Optional values: 'nick', 'mail', 'link' */
meta?: string[]
/** Set required fields*/
requiredMeta?: string[]
/** login mode status */
login?: string
/** Comment word s limit. */
wordLimit?: number | [number, number]
/**number of comments per page. */
pageSize?: number
/** Custom image upload method. */
imageUploader?: WalineImageUploader | false
/** Code highlighting, use hanabi by default */
highlighter?: WalineHighlighter | false
/** Customize \TeX rendering */
texRender?: WalineTexRenderer | false
/** Whether show copyright and version in footer. */
copyright?: boolean
export type Remark42Config = {
/** hostname of Remark42 server, same as REMARK_URL in backend config, e.g. "https://demo.remark42.com" */
host: string
/** the SITE that you passed to Remark42 instance on start of backend. (default: remark) */
site_id?: string
/** url to the page with comments*/
url?: string
/** an array of widgets that should be rendered on a page (default: ['embed'] )*/
components?: ['embed' | 'last-comments' | 'counter']
/** maximum number of comments that is rendered on mobile version (default: 15 )*/
max_shown_comments?: number
/** maximum number of comments in the last comments widget (default: 15 )*/
max_last_comments?: number
/** changes UI theme, (default: light )*/
theme?: 'light' | 'dark'
/** title for current comments page (default: document.title)*/
page_title?: string
/**
* interface localization,
* English (en), Belarusian (be), Brazilian Portuguese (bp), Bulgarian (bg), Chinese (zh), Finnish (fi), French (fr), German (de), Japanese (ja), Korean (ko), Polish (pl), Russian (ru), Spanish (es), Turkish (tr), Ukrainian (ua), Italian (it) and Vietnamese (vi)
* default: en
*/
locale?: 'en' | 'be' | 'bp' | 'bg' | 'zh' | 'fi' | 'fr' | 'de' | 'ja' | 'ko' | 'pl' | 'ru' | 'es' | 'tr' | 'ua' | 'it' | 'vi'
/** enables email subscription (default: true) */
show_email_subscription?: boolean
/** enables RSS subscription, (default: true) */
show_rss_subscription?: boolean
/** minimized UI with basic info only, (default: false) */
simple_view?: boolean
/** hides footer with signature and links to Remark42,(default: false) */
no_footer?: boolean
}

View file

@ -1,8 +1,6 @@
import type { FFFAuthor } from 'fff-flavored-frontmatter'
export type SiteConfig = {
/** @deprecated - use `description` instead */
descr?: string
/** site protocol. for example: `https://` */
protocol: string
/** site domain. for example: `example.com` */

40
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,40 @@
<script lang="ts">
import type { LayoutData } from './$types'
import { onMount } from 'svelte'
import { browser, dev } from '$app/environment'
import { genTags } from '$lib/utils/posts'
import { posts, tags } from '$lib/stores/posts'
import { registerSW } from 'virtual:pwa-register'
import Head from '$lib/components/head_static.svelte'
import Header from '$lib/components/header.svelte'
import Transition from '$lib/components/transition.svelte'
import 'uno.css'
import '../app.pcss'
export let data: LayoutData
let { res, path } = data
$: if (data) path = data.path
posts.set(res)
tags.set(genTags(res))
onMount(
() =>
!dev &&
browser &&
registerSW({
immediate: true,
onRegistered: r => r && setInterval(async () => await r.update(), 198964),
onRegisterError: error => console.error(error)
})
)
</script>
<Head />
<Header {path} />
<Transition {path}>
<slot />
</Transition>

7
src/routes/+layout.ts Normal file
View file

@ -0,0 +1,7 @@
import type { LayoutLoad } from './$types'
export const prerender = true
export const trailingSlash = 'always'
export const load: LayoutLoad = async ({ url, fetch }) => ({
path: url.pathname,
res: await fetch('/posts.json').then(res => res.json())
})

View file

@ -2,15 +2,14 @@
import { onMount } from 'svelte'
import { fly } from 'svelte/transition'
import { page } from '$app/stores'
import { browser } from '$app/env'
import { browser } from '$app/environment'
import { goto } from '$app/navigation'
import { posts as storedPosts, tags as storedTags } from '$lib/stores/posts'
import { title as storedTitle } from '$lib/stores/title'
import Head from '$lib/components/head.svelte'
import Footer from '$lib/components/footer.svelte'
import Post from '$lib/components/post_card.svelte'
// import Post from '$lib/components/index_post.svelte'
import Profile from '$lib/components/index_profile.svelte'
import RemoteFollow from '$lib/components/extra/follow.svelte'
let allPosts: Urara.Post[]
let allTags: string[]
@ -19,9 +18,7 @@
storedTitle.set('')
$: storedPosts.subscribe(
storedPosts => (allPosts = (storedPosts as Urara.Post[]).filter(post => !post.flags?.includes('unlisted')))
)
$: storedPosts.subscribe(storedPosts => (allPosts = storedPosts.filter(post => !post.flags?.includes('unlisted'))))
$: storedTags.subscribe(storedTags => (allTags = storedTags as string[]))
@ -30,7 +27,7 @@
$: if (tags) {
posts = !tags ? allPosts : allPosts.filter(post => tags.every(tag => post.tags?.includes(tag)))
if (browser && window.location.pathname === '/')
window.history.replaceState({}, '', tags.length > 0 ? `?tags=${tags.toString()}` : `/`)
goto(tags.length > 0 ? `?tags=${tags.toString()}` : `/`, { replaceState: true })
}
onMount(() => {
@ -125,5 +122,3 @@
{/key}
</div>
</div>
<RemoteFollow />

View file

@ -1,38 +0,0 @@
<script lang="ts" context="module">
import type { Load } from './__types'
export const load: Load = ({ url: { pathname }, error, status }) => ({ props: { pathname, error, status } })
</script>
<script lang="ts">
import Head from '$lib/components/head.svelte'
import Footer from '$lib/components/footer.svelte'
export let pathname: string
export let error: Error
export let status: string
console.error(status, error.message)
</script>
<Head page={{ title: status ?? '404', path: pathname ?? '/404' }} />
<div class="flex flex-col flex-nowrap justify-center xl:flex-row xl:flex-wrap">
<div class="flex-none w-full max-w-screen-md mx-auto xl:mx-0">
<article
itemscope
itemtype="https://schema.org/BlogPosting"
class="card bg-base-100 rounded-none md:rounded-box shadow-xl md:mb-8 z-10">
<main itemprop="articleBody" class="card-body prose urara-prose">
<h1 class="opacity-20 text-6xl md:text-[12rem] -mt-2 mb-0">
{status ?? '404'}
</h1>
<h2 class="-mt-12 md:-mt-24">{error.message ?? 'Not found'}</h2>
<div class="card-actions">
<a href="/" class="btn btn-neutral no-underline shadow-xl hover:shadow-2xl mt-8">
<span class="i-heroicons-outline-home -ml-1 mr-2" />
Back to Home
</a>
</div>
</main>
</article>
<Footer sticky={true} class="flex-1 md:flex-initial" />
</div>
</div>

View file

@ -1,49 +0,0 @@
<script lang="ts" context="module">
import type { Load } from './__types'
export const prerender = true
export const load: Load = async ({ url, fetch }) => ({
props: {
path: url.pathname,
res: await fetch('/posts.json').then(res => res.json())
}
})
</script>
<script lang="ts">
import { onMount } from 'svelte'
import { browser, dev } from '$app/env'
import { fly } from 'svelte/transition'
import { genTags } from '$lib/utils/posts'
import { posts, tags } from '$lib/stores/posts'
import { registerSW } from 'virtual:pwa-register'
import Head from '$lib/components/head_static.svelte'
import Header from '$lib/components/header.svelte'
import 'uno.css'
import '../app.css'
export let res: Urara.Post[]
export let path: string
posts.set(res)
tags.set(genTags(res))
onMount(
() =>
!dev &&
browser &&
registerSW({
onRegistered: r => r && setInterval(async () => await r.update(), 198964),
onRegisterError: error => console.error(error)
})
)
</script>
<Head />
<Header {path} />
{#key path}
<div
class="bg-base-100 md:bg-base-200 min-h-screen pt-16 md:pb-8 lg:pb-16"
in:fly={{ y: 100, duration: 300, delay: 300 }}
out:fly={{ y: -100, duration: 300 }}>
<slot />
</div>
{/key}

View file

@ -1,49 +1,50 @@
import type { RequestHandler } from '@sveltejs/kit'
import type { RequestHandler } from './$types'
import { site } from '$lib/config/site'
import { feed } from '$lib/config/general'
import { favicon } from '$lib/config/icon'
import { genPosts, genTags } from '$lib/utils/posts'
const render = async (
posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })
): Promise<string> => `<?xml version='1.0' encoding='utf-8'?>
const render = (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })): string =>
`<?xml version='1.0' encoding='utf-8'?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>${site.protocol + site.domain}/</id>
<title><![CDATA[${site.title}]]></title>${site.subtitle ? `\n <subtitle><![CDATA[${site.subtitle}]]></subtitle>` : ''}${
favicon ? `\n <icon>${favicon.src}</icon>` : ''
}
favicon ? `\n <icon>${favicon.src}</icon>` : ''
}
<link href="${site.protocol + site.domain}" />
<link href="${site.protocol + site.domain}/atom.xml" rel="self" type="application/atom+xml" />${
feed.hubs?.map(hub => `\n <link href="${hub}" rel="hub"/>`).join('') ?? ''
}
feed.hubs?.map(hub => `\n <link href="${hub}" rel="hub"/>`).join('') ?? ''
}
<updated>${new Date().toJSON()}</updated>
<author>
<name><![CDATA[${site.author.name}]]></name>
</author>${genTags(posts)
.map(tag => `\n <category term="${tag}" scheme="${site.protocol + site.domain}/?tags=${encodeURI(tag)}" />`)
.join('')}${posts
.map(
post => `\n <entry>
.map(
post => `\n <entry>
<title type="html"><![CDATA[${post.title}]]></title>
<link href="${site.protocol + site.domain + post.path}" />
<id>${site.protocol + site.domain + post.path}</id>
<published>${new Date(post.published ?? post.created).toJSON()}</published>
<updated>${new Date(post.updated ?? post.published ?? post.created).toJSON()}</updated>${
post.summary ? `\n <summary type="html"><![CDATA[${post.summary.toString()}]]></summary>` : ''
}
post.summary ? `\n <summary type="html"><![CDATA[${post.summary.toString()}]]></summary>` : ''
}
<content type="html">
<![CDATA[${post.html}]]>
</content>${post.tags
?.map(tag => `\n <category term="${tag}" scheme="${site.protocol + site.domain}/?tags=${encodeURI(tag)}" />`)
.join('')}
</entry>`
)
.join('')}
</feed>`
)
.join('')}
</feed>`.trim()
export const GET: RequestHandler = async () => ({
headers: {
'Content-Type': 'application/atom+xml; charset=utf-8'
},
body: await render()
})
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () =>
new Response(render(), {
headers: {
'content-type': 'application/atom+xml; charset=utf-8'
}
})

View file

@ -1,10 +1,11 @@
import type { RequestHandler } from '@sveltejs/kit'
import type { RequestHandler } from './$types'
import { json } from '@sveltejs/kit'
import { site } from '$lib/config/site'
import { feed } from '$lib/config/general'
import { favicon, any } from '$lib/config/icon'
import { genPosts } from '$lib/utils/posts'
const render = async (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })) => ({
const render = (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })) => ({
version: 'https://jsonfeed.org/version/1.1',
title: site.title,
home_page_url: site.protocol + site.domain,
@ -41,9 +42,11 @@ const render = async (posts = genPosts({ postHtml: true, postLimit: feed.limit,
}))
})
export const GET: RequestHandler = async () => ({
headers: {
'Content-Type': 'application/feed+json; charset=utf-8'
},
body: JSON.stringify(await render(), null, 2)
})
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () =>
json(render(), {
headers: {
'content-type': 'application/feed+json; charset=utf-8'
}
})

View file

@ -1,9 +1,10 @@
<script lang="ts">
// @ts-nocheck
import Masonry from 'svelte-bricks'
import type { Friend } from '$lib/config/friends'
import { friends as allFriends } from '$lib/config/friends'
import { title as storedTitle } from '$lib/stores/title'
import Head from '$lib/components/head.svelte'
import Masonry from 'svelte-bricks'
import FriendComponent from '$lib/components/extra/friend.svelte'
const rnd = Math.random()
@ -16,7 +17,7 @@
storedTitle.set('')
</script>
<Head />
<Head page={{ title: 'Friends', path: '/friends' }} />
<Masonry
{items}

View file

@ -1,32 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit'
import { site } from '$lib/config/site'
import { any, maskable } from '$lib/config/icon'
export const GET: RequestHandler = () => ({
headers: {
'Content-Type': 'application/manifest+json; charset=utf-8'
},
body: JSON.stringify(
{
name: site.title,
short_name: site.title,
lang: site.lang,
description: site.description,
id: site.protocol + site.domain + '/',
start_url: '/',
scope: '/',
display: 'standalone',
orientation: 'portrait',
background_color: site.themeColor,
theme_color: site.themeColor,
icons: [
...Object.values(any)
.filter(icon => icon.sizes !== '180x180')
.map(icon => ({ ...icon, purpose: 'any' })),
...Object.values(maskable).map(icon => ({ ...icon, purpose: 'maskable' }))
]
},
null,
2
)
})

View file

@ -0,0 +1,37 @@
import type { RequestHandler } from './$types'
import { site } from '$lib/config/site'
import { any, maskable } from '$lib/config/icon'
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = () =>
new Response(
JSON.stringify(
{
name: site.title,
short_name: site.title,
lang: site.lang,
description: site.description,
id: site.protocol + site.domain + '/',
start_url: '/',
scope: '/',
display: 'standalone',
orientation: 'portrait',
background_color: site.themeColor,
theme_color: site.themeColor,
icons: [
...Object.values(any)
.filter(icon => icon.sizes !== '180x180')
.map(icon => ({ ...icon, purpose: 'any' })),
...Object.values(maskable).map(icon => ({ ...icon, purpose: 'maskable' }))
]
},
null,
2
),
{
headers: {
'Content-Type': 'application/manifest+json; charset=utf-8'
}
}
)

View file

@ -1,9 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit'
import { genPosts } from '$lib/utils/posts'
export const GET: RequestHandler = async () => ({
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(genPosts(), null, 2)
})

View file

@ -0,0 +1,7 @@
import type { RequestHandler } from './$types'
import { json } from '@sveltejs/kit'
import { genPosts } from '$lib/utils/posts'
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () => json(genPosts())

View file

@ -1,27 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit'
import { site } from '$lib/config/site'
import { genPosts } from '$lib/utils/posts'
const render = async (): Promise<string> => `<?xml version='1.0' encoding='utf-8'?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>${site.protocol + site.domain}</loc>
</url>
${genPosts()
.map(
post => `
<url>
<loc>${site.protocol + site.domain + post.path}</loc>
<lastmod>${new Date(post.updated ?? post.published ?? post.created).toISOString()}</lastmod>
<priority>0.5</priority>
</url>`
)
.join('')}
</urlset>`
export const GET: RequestHandler = async () => ({
headers: {
'Content-Type': 'application/xml; charset=utf-8'
},
body: await render()
})

View file

@ -0,0 +1,36 @@
import type { RequestHandler } from './$types'
import { site } from '$lib/config/site'
import { genPosts } from '$lib/utils/posts'
const render = (): string =>
`<?xml version='1.0' encoding='utf-8'?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="https://www.w3.org/1999/xhtml"
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1">
<url>
<loc>${site.protocol + site.domain}</loc>
</url>
${genPosts()
.map(
post => `
<url>
<loc>${site.protocol + site.domain + post.path}</loc>
<lastmod>${new Date(post.updated ?? post.published ?? post.created).toISOString()}</lastmod>
<priority>0.5</priority>
</url>`
)
.join('')}
</urlset>`.trim()
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () =>
new Response(render(), {
headers: {
'content-type': 'application/xml; charset=utf-8'
}
})

View file

@ -1,9 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit'
import { genPosts, genTags } from '$lib/utils/posts'
export const GET: RequestHandler = async () => ({
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(genTags(genPosts()), null, 2)
})

View file

@ -0,0 +1,7 @@
import type { RequestHandler } from './$types'
import { json } from '@sveltejs/kit'
import { genPosts, genTags } from '$lib/utils/posts'
export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () => json(genTags(genPosts()))

View file

@ -1,29 +1,35 @@
// sveltekit config type
import type { Config } from '@sveltejs/kit'
// svelte preprocess
import preprocess from 'svelte-preprocess'
import adapterAuto from '@sveltejs/adapter-auto'
import adapterNode from '@sveltejs/adapter-node'
// svelte adapter
import adapterVercel from '@sveltejs/adapter-vercel'
import adapterNetlify from '@sveltejs/adapter-netlify'
import adapterStatic from '@sveltejs/adapter-static'
// svelte preprocessor
import { mdsvex } from 'mdsvex'
import mdsvexConfig from './mdsvex.config.js'
import { vitePreprocess } from '@sveltejs/kit/vite'
const defineConfig = (config: Config) => config
export default defineConfig({
export default {
extensions: ['.svelte', ...(mdsvexConfig.extensions as string[])],
preprocess: [mdsvex(mdsvexConfig), preprocess()],
preprocess: [mdsvex(mdsvexConfig), vitePreprocess()],
kit: {
adapter: Object.keys(process.env).some(key => ['VERCEL', 'CF_PAGES', 'NETLIFY'].includes(key))
? adapterAuto()
: process.env.ADAPTER === 'node'
? adapterNode({ out: 'build' })
adapter: Object.keys(process.env).some(key => key === 'VERCEL')
? adapterVercel()
: Object.keys(process.env).some(key => key === 'NETLIFY')
? adapterNetlify()
: adapterStatic({
pages: 'build',
assets: 'build',
fallback: undefined
}),
csp: { mode: 'auto' },
prerender: { default: true }
prerender: {
handleMissingId: 'warn'
},
csp: {
mode: 'auto',
directives: {
'style-src': ['self', 'unsafe-inline', 'https://giscus.app']
}
}
}
})
} as Config

View file

@ -1,63 +1,12 @@
// tailwind config type
import type { TailwindConfig } from 'tailwindcss/tailwind-config'
// @ts-ignore TS2305: Module 'tailwindcss/plugin' has no exported member 'TailwindPluginWithoutOptions'.
import type { TailwindPluginWithoutOptions } from 'tailwindcss/plugin'
// tailwind plugins
import { theme } from './src/lib/config/general'
// @ts-ignore Could not find a declaration file for module '@tailwindcss/typography'.
import typography from '@tailwindcss/typography'
// @ts-ignore Could not find a declaration file for module 'daisyui'.
import daisyui from 'daisyui'
interface Config extends TailwindConfig {
daisyui?: {
styled?: boolean
themes?: boolean | string[]
base?: boolean
utils?: boolean
logs?: boolean
rtl?: boolean
darkTheme?: string
prefix?: string
}
}
const defineConfig = (config: Config) => config
export default defineConfig({
export default {
content: ['./src/**/*.{html,md,js,svelte,ts}'],
theme: {
extend: {}
},
plugins: [typography as TailwindPluginWithoutOptions, daisyui as TailwindPluginWithoutOptions],
daisyui: {
themes: [
'light',
'dark',
'cupcake',
'bumblebee',
'emerald',
'corporate',
'synthwave',
'retro',
'cyberpunk',
'valentine',
'halloween',
'garden',
'forest',
'aqua',
'lofi',
'pastel',
'fantasy',
'wireframe',
'black',
'luxury',
'dracula',
'cmyk',
'autumn',
'business',
'acid',
'lemonade',
'night',
'coffee',
'winter'
]
}
})
theme: { extend: {} },
plugins: [typography, daisyui],
daisyui: { themes: theme.map(({ name }) => name) }
}

View file

@ -9,7 +9,7 @@ import chokidar from 'chokidar'
import chalk from 'chalk'
const config = {
extensions: ['svelte', 'md', 'js', 'ts'],
extensions: ['md'],
catch: ['ENOENT', 'EEXIST']
}
@ -102,7 +102,7 @@ const clean = () => {
switch (process.argv[2]) {
case 'watch':
{
let watcher = chokidar.watch('urara', {
const watcher = chokidar.watch('urara', {
ignored: (file: string) => path.basename(file).startsWith('.')
})
watcher

View file

@ -0,0 +1,27 @@
{
"aliases": [
"https://kongwoo.icu/users/blog"
],
"links": [
{
"href": "https://kongwoo.icu/users/blog",
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html"
},
{
"href": "https://kongwoo.icu/users/blog",
"rel": "self",
"type": "application/activity+json"
},
{
"href": "https://kongwoo.icu/users/blog",
"rel": "self",
"type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "https://kongwoo.icu/ostatus_subscribe?acct={uri}"
}
],
"subject": "acct:blog@kongwoo.icu"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View file

@ -12,7 +12,7 @@ lastmod: 2022-04-16T12:54:20.049Z
## 书签这回事
上回说到用 [自建网页书签 Flare](https://seviche.cc/blog/flare/) ,今天不小心把 SSH 链接弄坏了也就是连不上了因为搭载的服务不多所以把整个服务器都重装了Flare 网页书签也炸了。
上回说到用 [自建网页书签 Flare](https://sevic.me/blog/flare/) ,今天不小心把 SSH 链接弄坏了也就是连不上了因为搭载的服务不多所以把整个服务器都重装了Flare 网页书签也炸了。
其实搭建之后我没有用过(一次都没有),平时的书签管理主要靠搜索,各个浏览器之间的书签互相导入后,直接在搜索栏搜,如果是常用的网址,我用 Chorme 扩展 [eesel](https://chrome.google.com/webstore/detail/eesel-productivity-at-wor/jffaiidojfhflballoapgofphkadiono) 来解决,它可以列出最近用过的网页,按站点分类,查找起来很方便

View file

@ -2,16 +2,9 @@
title: Miniflux · 保存文章到 Pocket 以及 RSS
summary: 将 Miniflux 上的文章到保存到 Pocket/Instapaper,以及 RSS 相关文章和资源
created: 2022-03-10T16:24:38.663Z
preview: ''
draft: ''
tags:
- RSS
- Miniflux
changelogs:
- tag: '202203011'
summary:
- 添加了`instapaper`的连接方式
- 添加了Pocket按钮嵌入方式
lastmod: 2022-04-07T07:38:52.406Z
---

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

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