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 # build output
node_modules
.svelte-kit
/package
src/routes/**/
src/routes/*.md
static/
build build
.vercel_build_output/ static
.netlify/ .svelte-kit
.env.local .netlify
.env.**.local .vercel
myblog/urara/2022-06-12-appwrite.md
# 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 *.config.js
urara.js urara.js

1
.npmrc
View file

@ -1 +1,2 @@
engine-strict=true 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, "editor.formatOnSave": true,
"files.eol": "\n", "files.eol": "\n",
"typescript.tsdk": "node_modules\\typescript\\lib", "typescript.tsdk": "node_modules/typescript/lib",
"css.lint.unknownAtRules": "ignore", "css.lint.unknownAtRules": "ignore",
"svelte.plugin.css.diagnostics.enable": false, "svelte.plugin.css.diagnostics.enable": false,
"[html]": { "[html]": {

View file

@ -20,11 +20,11 @@ My Tech Blog, base on [Urara](https://github.com/importantimport/urara)
## TODO ## TODO
- [ ] Note Page - [ ] Note Page
- [ ] Archie Page - [ ] Archvie Page
- [ ] Refactoring the atom feed format - [ ] Refactoring the atom feed format
- [ ] NeoDB component - [ ] 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 #!/bin/bash
echo "————————1. Build locally————————" echo "————————1. Build locally————————"
netlify build netlify build
echo "————————2.Deploy test————————" echo "————————2.Deploy————————————————"
netlify deploy
echo "————————3.Deploy————————"
netlify deploy --prod netlify deploy --prod

View file

@ -13,6 +13,7 @@ import { parse, join } from 'path'
import { visit } from 'unist-util-visit' import { visit } from 'unist-util-visit'
import { toString } from 'mdast-util-to-string' import { toString } from 'mdast-util-to-string'
import Slugger from 'github-slugger' import Slugger from 'github-slugger'
import remarkFFF from 'remark-fff'
import remarkFootnotes from 'remark-footnotes' import remarkFootnotes from 'remark-footnotes'
// highlighter // highlighter
@ -24,12 +25,12 @@ type VALUE = { [key in string | number]: VALUE } | Array<VALUE> | string | boole
const remarkUraraFm = const remarkUraraFm =
() => () =>
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => { (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) const { dir, name } = parse(filepath)
if (!data.fm) data.fm = {} if (!data.fm) data.fm = {}
// Generate slug & path // Generate slug & path
data.fm.slug = filepath 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 // Generate ToC
if (data.fm.toc !== false) { if (data.fm.toc !== false) {
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []] 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) 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 // Better type definitions needed
@ -72,9 +59,7 @@ const remarkUraraSpoiler = () => (tree: Node<Data>) =>
return node return node
}) })
const defineConfig = (config: MdsvexOptions) => config export default {
export default defineConfig({
extensions: ['.svelte.md', '.md'], extensions: ['.svelte.md', '.md'],
smartypants: { smartypants: {
dashes: 'oldschool' 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: [ rehypePlugins: [
rehypeSlug, rehypeSlug as any,
[rehypeAutolinkHeadings, { behavior: 'wrap' }], [rehypeAutolinkHeadings, { behavior: 'wrap' }],
[ [
rehypeExternalLinks, rehypeExternalLinks,
@ -116,4 +116,4 @@ export default defineConfig({
} }
] ]
] ]
}) } as MdsvexOptions

View file

@ -1,8 +1,7 @@
[build] [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" publish = "build"
[build.environment] [build.environment]
NPM_FLAGS = "--version" NPM_FLAGS = "--version"
AWS_LAMBDA_JS_RUNTIME = "nodejs16.x" AWS_LAMBDA_JS_RUNTIME = "nodejs16.x"
@ -26,13 +25,17 @@ node_bundler = "esbuild"
[[headers]] [[headers]]
for = "/*" for = "/*"
[headers.values] [headers.values]
Access-Control-Allow-Origin = "https://seviche.cc" Access-Control-Allow-Origin = "sevic.me"
X-Frame-Options = "DENY" X-Frame-Options = "SAMEORIGIN"
X-Content-Type-Options = "nosniff" X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block" 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" 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]] [[redirects]]
from = "/.well-known/host-meta" from = "/.well-known/host-meta"

View file

@ -12,16 +12,12 @@
"tsc:watch": "tsc -w -p tsconfig.node.json", "tsc:watch": "tsc -w -p tsconfig.node.json",
"urara:build": "node urara.js build", "urara:build": "node urara.js build",
"urara:watch": "node urara.js watch", "urara:watch": "node urara.js watch",
"kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite dev", "kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=11474 vite dev",
"kit:build": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite build", "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:parallel": "npm-run-all -p -r tsc:watch urara:watch \"kit:dev {@} \" --",
"dev": "npm-run-all -s tsc \"dev:parallel {@} \" --", "dev": "npm-run-all -s tsc \"dev:parallel {@} \" --",
"build": "npm-run-all -s tsc urara:build kit:build clean", "build": "npm-run-all -s tsc urara:build kit:build clean",
"preview": "vite preview", "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": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", "lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
@ -29,58 +25,66 @@
"zhlint": "zhlint urara/*/*.md --fix && zhlint urara/*.md --fix" "zhlint": "zhlint urara/*/*.md --fix && zhlint urara/*.md --fix"
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/heroicons-outline": "^1.1.2", "@iconify-json/heroicons-outline": "^1.1.6",
"@iconify-json/heroicons-solid": "^1.1.2", "@iconify-json/heroicons-solid": "^1.1.7",
"@iconify-json/ic": "^1.1.9", "@iconify-json/ic": "^1.1.13",
"@iconify-json/simple-icons": "1.1.21", "@iconify-json/icon-park-twotone": "1.1.9",
"@iconify-json/material-symbols": "1.1.14", "@iconify-json/material-symbols": "1.1.41",
"@iconify-json/mdi": "^1.1.30", "@iconify-json/mdi": "^1.1.52",
"@iconify-json/uil": "^1.1.2", "@iconify-json/simple-icons": "1.1.52",
"@sveltejs/adapter-auto": "1.0.0-next.64", "@iconify-json/uil": "^1.1.4",
"@sveltejs/adapter-node": "1.0.0-next.86", "@sveltejs/adapter-netlify": "^2.0.7",
"@sveltejs/adapter-static": "1.0.0-next.39", "@sveltejs/adapter-static": "^2.0.2",
"@sveltejs/kit": "1.0.0-next.405", "@sveltejs/adapter-vercel": "2.4.3",
"@tailwindcss/typography": "^0.5.4", "@sveltejs/kit": "^1.19.0",
"@types/node": "^18.7.8", "@tailwindcss/typography": "^0.5.9",
"@types/node": "^20.2.5",
"@types/unist": "^2.0.6", "@types/unist": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^5.33.1", "@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.33.1", "@typescript-eslint/parser": "^5.59.7",
"autoprefixer": "^10.4.8", "@unocss/extractor-svelte": "^0.51.13",
"chalk": "^5.0.1", "@vite-pwa/sveltekit": "^0.1.3",
"chalk": "^5.2.0",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cssnano": "^5.1.13", "daisyui": "^2.51.6",
"daisyui": "^2.24.0", "eslint": "^8.41.0",
"eslint": "^8.22.0", "eslint-config-prettier": "^8.8.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0", "eslint-plugin-svelte3": "^4.0.0",
"fenceparser": "^2.2.0", "fenceparser": "^2.2.0",
"fff-flavored-frontmatter": "~0.2.2", "fff-flavored-frontmatter": "~0.5.3",
"github-slugger": "^1.4.0", "github-slugger": "^2.0.0",
"mdast-util-to-string": "^3.1.0", "mdast-util-to-string": "^3.2.0",
"mdsvex": "^0.10.6", "mdsvex": "^0.10.6",
"netlify-cli": "^16.3.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"postcss": "^8.4.16", "postcss": "^8.4.23",
"prettier": "^2.7.1", "postcss-lightningcss": "^0.7.0",
"prettier-plugin-svelte": "^2.7.0", "prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.0",
"rehype-autolink-headings": "^6.1.1", "rehype-autolink-headings": "^6.1.1",
"rehype-external-links": "^2.0.0", "rehype-external-links": "^2.1.0",
"rehype-slug": "^5.0.1", "rehype-slug": "^5.1.0",
"remark": "^14.0.2", "remark": "^14.0.3",
"remark-fff": "~0.5.3",
"remark-footnotes": "~2.0.0", "remark-footnotes": "~2.0.0",
"shiki-twoslash": "^3.1.0", "rollup": "^3.23.0",
"svelte": "^3.49.0", "shiki-twoslash": "^3.1.2",
"svelte": "^3.59.1",
"svelte-bricks": "^0.1.7", "svelte-bricks": "^0.1.7",
"svelte-check": "^2.8.1", "svelte-check": "^3.4.3",
"svelte-preprocess": "^4.10.7", "svelte-preprocess": "^5.0.4",
"svelte-typeahead": "^4.2.4", "svelte-typeahead": "^4.4.1",
"tailwindcss": "^3.1.8", "sveltekit-embed": "^0.0.12",
"tslib": "^2.4.0", "tailwindcss": "^3.3.2",
"typescript": "^4.7.4", "tslib": "^2.5.2",
"unist-util-visit": "^4.1.0", "typescript": "^5.0.4",
"unocss": "^0.45.8", "unist-util-visit": "^4.1.2",
"vite": "^3.0.9", "unocss": "^0.51.13",
"vite-plugin-pwa": "^0.12.3", "vite": "^4.3.9",
"workbox-window": "^6.5.4" "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" /> /// <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>> { interface ImportMetaEnv extends Readonly<Record<string, string>> {
readonly URARA_SITE_PROTOCOL?: 'http://' | 'https://'
readonly URARA_SITE_DOMAIN?: string readonly URARA_SITE_DOMAIN?: string
} }
@ -14,8 +15,8 @@ interface ImportMeta {
declare global { declare global {
namespace Urara { namespace Urara {
namespace Post { namespace Post {
type Frontmatter = Omit<FFFBase, 'created' | 'updated' | 'image' | 'audio' | 'video' | 'flags'> & type Frontmatter = Omit<FFFBase, 'flags'> &
Pick<FFFExtra, 'in_reply_to'> & { Pick<FFFMention, 'in_reply_to'> & {
/** /**
* post type. * post type.
* @remarks auto-generated * @remarks auto-generated
@ -50,6 +51,10 @@ declare global {
* @remarks auto-generated or set manually * @remarks auto-generated or set manually
*/ */
updated: string updated: string
/**
* the published date of the post.
*/
published?: string
/** /**
* the featured image for article, or image for "photo" / "multi-photo" posts. * the featured image for article, or image for "photo" / "multi-photo" posts.
* @remarks currently only supports string * @remarks currently only supports string

View file

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

View file

@ -56,7 +56,12 @@ html {
/* .urara-prose a */ /* .urara-prose a */
.urara-prose :is(p, li) > 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 */ /* .urara-prose misc */
@ -188,9 +193,9 @@ pre.twoslash data-lsp:hover::before {
.urara-prose blockquote:before { .urara-prose blockquote:before {
vertical-align: -0.4em; 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 { .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 export let post: Urara.Post
</script> </script>
<a <button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Translate">
<a
href={`https://translate.google.com/translate?sl=auto&tl=${ href={`https://translate.google.com/translate?sl=auto&tl=${
navigator.languages ? navigator.languages[0] : navigator.language navigator.languages ? navigator.languages[0] : navigator.language
}&u=${site.protocol + site.domain + post.path}`} }&u=${site.protocol + site.domain + post.path}`}
class="btn btn-lg btn-circle btn-ghost bg-base-100 shadow-lg hover:shadow-xl"> class="btn btn-circle btn-ghost">
<span class="i-heroicons-outline-translate" /> <span class="i-heroicons-outline-translate" />
</a> </a>
</button>

View file

@ -3,10 +3,12 @@
export let post: Urara.Post export let post: Urara.Post
</script> </script>
<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( href={`https://www.addtoany.com/share#url=${site.protocol + site.domain + post.path}&title=${encodeURI(
post.title ?? post.path.slice(1) post.title ?? post.path.slice(1)
)}`} )}`}
class="btn btn-lg btn-circle btn-ghost bg-base-100 shadow-lg hover:shadow-xl"> class="btn btn-circle btn-ghost">
<span class="i-heroicons-outline-share" /> <span class="i-heroicons-outline-share" />
</a> </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> </script>
<div class="flex flex-col gap-8"> <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"> <div class="flex">
<p class="flex-1 m-auto italic opacity-50"> <p class="flex-1 m-auto italic opacity-50">
<!-- {`Sort by=${config?.sortBy ?? 'Created'}&sort-dir=${sortDirUp ? 'up' : 'down'}`} --> <!-- {`Sort by=${config?.sortBy ?? 'Created'}&sort-dir=${sortDirUp ? 'up' : 'down'}`} -->
@ -172,34 +202,4 @@
{:else} {:else}
<button id="webmention-loading" class="btn btn-lg btn-block flex btn-ghost loading" /> <button id="webmention-loading" class="btn btn-lg btn-block flex btn-ghost loading" />
{/if} {/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> </div>

View file

@ -24,7 +24,7 @@
.then( .then(
({ links }) => links.find((link: { rel: string }) => link.rel === 'http://ostatus.org/schema/1.0/subscribe').template ({ 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)) .catch(error => console.error(error))
$: if (input) $: if (input)
input.length < 5 ? (status = '') : input.includes('@') && input.includes('.') ? (status = 'success') : (status = 'warning') input.length < 5 ? (status = '') : input.includes('@') && input.includes('.') ? (status = 'success') : (status = 'warning')

View file

@ -3,8 +3,8 @@
</script> </script>
<script lang="ts"> <script lang="ts">
export let user = undefined export let user = ''
export let repo = undefined export let repo = ''
let info: { let info: {
html_url: string html_url: string
description: string description: string
@ -20,7 +20,7 @@
}) })
</script> </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"> <div class="p-6">
{#key info} {#key info}
{#if info} {#if info}

View file

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

View file

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

View file

@ -19,7 +19,7 @@
<div class="card-body p-4"> <div class="card-body p-4">
<div class="flex flex-col md:flex-row items-start gap-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"> <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>
<div class="card-title flex-1 flex-col items-start gap-4"> <div class="card-title flex-1 flex-col items-start gap-4">
<div> <div>

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { browser, dev } from '$app/env' import { browser, dev } from '$app/environment'
import { fly } from 'svelte/transition' import { fly } from 'svelte/transition'
import { site } from '$lib/config/site' import { site } from '$lib/config/site'
import { theme } from '$lib/config/general' import { theme } from '$lib/config/general'
@ -41,7 +41,8 @@
if (browser) if (browser)
currentTheme = 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> </script>
<svelte:head> <svelte:head>
@ -54,34 +55,32 @@
id="header" id="header"
class:-translate-y-32={!pin && scrollY > 0} 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 > 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'}"> 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 in:fly={{ x: -50, duration: 300, delay: 300 }} out:fly={{ x: -50, duration: 300 }} class="navbar">
<div class="navbar-start"> <div class="navbar-start">
{#if headerConfig.nav} {#if headerConfig.nav}
<Nav {path} {title} {pin} {scrollY} nav={headerConfig.nav} /> <Nav {path} {title} {pin} {scrollY} nav={headerConfig.nav} />
{/if} {/if}
<a href="/" sveltekit:prefetch class="btn btn-ghost normal-case text-lg">{site.title}</a> <a href="/" class="btn btn-ghost normal-case text-lg">{site.title}</a>
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<!-- {#if headerConfig.search} --> {#if headerConfig.search}
<!-- The button to open modal --> <button aria-label="search" on:click={() => (search = !search)} tabindex="0" class="btn btn-square btn-ghost">
<!-- <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">
<span class="i-heroicons-outline-search" /> <span class="i-heroicons-outline-search" />
</button> --> </button>
<!-- {/if} --> {/if}
<div id="change-theme" class="dropdown dropdown-end"> <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"> <div tabindex="0" class="btn btn-square btn-ghost">
<span class="i-heroicons-outline-color-swatch" /> <span class="i-heroicons-outline-color-swatch" />
</div> </div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
<ul <ul
tabindex="0" 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="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}> class:hidden={!pin}>
{#each theme as { name, text }} {#each theme as { name, text }}
<button <button
@ -92,7 +91,7 @@
}} }}
class:border-2={currentTheme === name} class:border-2={currentTheme === name}
class:border-primary={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"> 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"> <p class="flex-1 text-left text-base-content group-hover:text-primary-content transition-color">
{text ?? name} {text ?? name}
</p> </p>
@ -108,6 +107,14 @@
</div> </div>
</div> </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> </header>
<button <button

View file

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

View file

@ -1,102 +1,21 @@
<script lang="ts"> <script lang="ts">
import { onMount, createEventDispatcher } from 'svelte'
import { site } from '$lib/config/site' import { site } from '$lib/config/site'
import { header as headerConfig } from '$lib/config/general' 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> </script>
<form> <form
<input type="checkbox" id="search-modal" class="modal-toggle " /> action={headerConfig?.search?.provider === 'duckduckgo' ? '//duckduckgo.com/' : '//google.com/search'}
<label for="search-modal" class="modal cursor-pointer w-full items-start pt-16 "> method="get"
<label class="modal-box w-11/12 max-w-4xl " for=""> class="flex-1">
<div class="form-control"> <input
<span type="text"
class="i-heroicons-outline-search text-base-content pointer-events-none absolute z-10 my-2 ml-3 stroke-current opacity-60 w-5" /> name="q"
</div> class="input input-ghost input-bordered xl:bg-base-100 xl:text-base-content transition-all w-full h-12" />
<Typeahead placeholder="Search is not avaible …" limit={8} label="Search" inputAfterSelect="clear"> <input
<div class="py-1 text-sm" /> type="hidden"
</Typeahead> name={headerConfig?.search?.provider === 'duckduckgo' ? 'sites' : 'sitesearch'}
<div class="pointer-events-none absolute right-14 top-8 gap-1 opacity-50 hidden lg:flex"> value={site.protocol + site.domain} />
<kbd class="kbd kbd-sm">ESC</kbd> <button type="submit" class="btn btn-square btn-ghost ml-2">
</div> <span class="i-heroicons-outline-search" />
</label> </button>
</label>
</form> </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"> <script lang="ts">
export let post: Urara.Post 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> </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} {#if Object.keys(actions).length}
{#each Object.values(actions) as action} {#each Object.values(actions) as action}
<svelte:component this={action.default} {post} /> <svelte:component this={action} {post} />
{/each} {/each}
{/if} {/if}
</div> </div>

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { browser } from '$app/env' import { browser } from '$app/environment'
import { post as postConfig } from '$lib/config/post' import { post as postConfig } from '$lib/config/post'
import { posts as storedPosts } from '$lib/stores/posts' import { posts as storedPosts } from '$lib/stores/posts'
import { title as storedTitle } from '$lib/stores/title' import { title as storedTitle } from '$lib/stores/title'
@ -35,11 +35,10 @@
itemprop="blogPost" itemprop="blogPost"
class:md:mb-8={!preview} class:md:mb-8={!preview}
class:lg:mb-16={!preview} class:lg:mb-16={!preview}
class:h-entry={preview}
class:group={preview} class:group={preview}
class:image-full={preview && post.type === 'article' && post.image} class:image-full={preview && post.type === 'article' && post.image}
class:before:!rounded-none={preview && 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} {#if !preview && postConfig.bridgy}
<div id="bridgy" class="hidden"> <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} {#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"> <div class="flex flex-col gap-2">
{#if post.image && !preview} {#if post.image && !preview}
<figure <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 <Image
class={`${post.type === 'article' ? 'u-featured rounded-box shadow-xl' : 'u-photo'}`} class={`${post.type === 'article' ? 'u-featured' : 'u-photo'}`}
src={post.image} src={post.image}
alt={post.image} alt={post.image}
{loading} {loading}
@ -91,7 +91,7 @@
<a itemprop="url" class="u-url p-name" href={post.path}>{post.title ?? post.path.slice(1)}</a> <a itemprop="url" class="u-url p-name" href={post.path}>{post.title ?? post.path.slice(1)}</a>
</h2> </h2>
{:else} {: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} {/if}
{#if post.summary} {#if post.summary}

View file

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

View file

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { fly } from 'svelte/transition' import { fly } from 'svelte/transition'
import { browser } from '$app/env' import { browser } from '$app/environment'
import Card from '$lib/components/post_card.svelte' import Card from '$lib/components/post_card.svelte'
import Head from '$lib/components/head.svelte' import Head from '$lib/components/head.svelte'
import Toc from '$lib/components/post_toc.svelte' import Toc from '$lib/components/post_toc.svelte'
@ -22,7 +22,7 @@
<div <div
in:fly={{ x: 25, duration: 300, delay: 500 }} in:fly={{ x: 25, duration: 300, delay: 500 }}
out:fly={{ x: 25, duration: 300 }} 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} {#if browser}
<Action {post} /> <Action {post} />
{/if} {/if}
@ -30,7 +30,7 @@
<div <div
in:fly={{ x: -25, duration: 300, delay: 500 }} in:fly={{ x: -25, duration: 300, delay: 500 }}
out:fly={{ x: -25, duration: 300 }} 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} {#if browser && post.toc}
<div class="h-full hidden xl:block"> <div class="h-full hidden xl:block">
<Toc toc={post.toc} /> <Toc toc={post.toc} />

View file

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

View file

@ -6,25 +6,12 @@
<div class="flex flex-wrap gap-2 rounded-box outline outline-neutral/10 p-4 {className}"> <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> <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 <a
href={in_reply_to} href={in_reply_to}
rel="noopener external" rel="noopener noreferrer external"
target="_blank" 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"> 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" /> <span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
{in_reply_to} {in_reply_to}
</a> </a>
{/if}
</div> </div>

View file

@ -18,15 +18,15 @@
{site.author.name} {site.author.name}
</a> </a>
<span class:hidden={preview} class="opacity-50">/</span> <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 <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} datetime={jsonPublished}
itemprop="datePublished"> itemprop="datePublished">
{stringPublished} {stringPublished}
</time> </time>
<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} datetime={jsonUpdated}
itemprop="dateModified"> itemprop="dateModified">
{stringUpdated} {stringUpdated}

View file

@ -4,7 +4,6 @@
<script lang="ts"> <script lang="ts">
import { onMount, onDestroy } from 'svelte' import { onMount, onDestroy } from 'svelte'
import Tree from '$lib/components/post_toc_tree.svelte'
export let toc: Urara.Post.Toc[] export let toc: Urara.Post.Toc[]
let intersecting: string[] = [] let intersecting: string[] = []
@ -34,7 +33,7 @@
// @ts-ignore: Cannot find name 'headingsObserver' // @ts-ignore: Cannot find name 'headingsObserver'
if (typeof headingsObserver !== 'undefined') headingsObserver.disconnect() if (typeof headingsObserver !== 'undefined') headingsObserver.disconnect()
// @ts-ignore: Cannot find name 'articleObserver' // @ts-ignore: Cannot find name 'articleObserver'
if (typeof headingsObserver !== 'undefined') articleObserver.disconnect() if (typeof articleObserver !== 'undefined') articleObserver.disconnect()
}) })
$: if (intersecting.length > 0) bordered = intersecting $: if (intersecting.length > 0) bordered = intersecting
@ -53,16 +52,29 @@
aria-label="TableOfContent" aria-label="TableOfContent"
dir="rtl" dir="rtl"
class="max-h-[calc(100vh-12rem)] overflow-y-hidden hover:overflow-y-auto"> class="max-h-[calc(100vh-12rem)] overflow-y-hidden hover:overflow-y-auto">
<Tree <ul dir="ltr" id="toc-list-root">
toc={toc.reduce( {#each toc as { depth, title, slug }}
(acc, heading) => { <li id={`toc-item-${slug}`} class="flex flex-col">
let parent = acc <!-- svelte-ignore a11y-click-events-have-key-events -->
// @ts-ignore Type 'Toc | undefined' is not assignable to type 'Toc.' ts(2322) <span
while (parent.depth + 1 < heading.depth) parent = parent.children.at(-1) dir="ltr"
parent.children = [...(parent.children ?? []), { ...heading, children: [] }] on:click={() =>
return acc // @ts-ignore Object is possibly 'null'. ts(2531)
}, document.getElementById(slug).scrollIntoView({ behavior: 'smooth' })}
{ depth: toc[0].depth - 1, children: [] } 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> </nav>
</aside> </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"> <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 let className: string | undefined = undefined
export { className as class } export { className as class }
export let src: string export let src: string
export let alt: string = src export let alt: string = src
export let loading: 'eager' | 'lazy' = 'lazy' export let loading: 'eager' | 'lazy' = 'lazy'
export let decoding: 'async' | 'sync' | 'auto' = 'async' export let decoding: 'async' | 'sync' | 'auto' = 'async'
let source: Image[] | undefined = sources[`/src/static${src}`]
</script> </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: '野生栗子🌰', title: '野生栗子🌰',
link: 'https://blog.chestnut.monster/' link: 'https://blog.chestnut.monster/'
}, },
{
id: 'summerblue',
rel: 'friend',
name: '夏诤',
title: 'SummberBlue',
link: 'https://summerblue.space/',
descr: '早睡早起身体好'
},
{ {
id: 'loikin', id: 'loikin',
rel: 'friend', rel: 'friend',
name: 'Loikin', name: 'Loikin',
title: '此生未命名', title: '浣心',
link: 'https://blog.loikein.one/', link: 'https://blog.loikein.one/',
descr: '用爱和理性对抗荒谬', descr: '用爱和理性对抗荒谬',
avatar: '/assets/loikin.png' avatar: '/assets/loikin.png'
@ -74,8 +66,42 @@ export const friends: Friend[] = [
rel: 'friend', rel: 'friend',
name: '鲨', name: '鲨',
title: '一只脆脆鲨', title: '一只脆脆鲨',
link: 'http://blog.sharktale.xyz/', link: 'https://woods.sharktale.xyz/',
descr: '遇见一只脆脆鲨', descr: '遇见一只脆脆鲨',
avatar: 'https://s2.loli.net/2022/03/30/xwOzn9G8TIqFPvR.jpg' 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' import type { ThemeConfig, HeadConfig, HeaderConfig, FooterConfig, DateConfig, FeedConfig } from '$lib/types/general'
export const theme: ThemeConfig = [ 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', name: 'lofi',
text: 'Lo-Fi' text: 'Light'
},
{
name: 'pastel',
text: 'Pastel'
},
{
name: 'fantasy',
text: 'Fantasy'
},
{
name: 'wirefream',
text: 'Wireframe'
},
{
name: 'black',
text: 'Black'
},
{
name: 'luxury',
text: 'Luxury'
}, },
{ {
name: 'dracula', name: 'dracula',
text: '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', name: 'coffee',
text: 'Coffee' text: 'Coffee'
}, },
{ {
name: 'winter', name: 'cupcake',
text: 'Winter' 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'
} }
] ]
@ -160,12 +100,20 @@ export const header: HeaderConfig = {
{ {
text: 'About', text: 'About',
link: '/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' 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 = { 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', locales: 'en-US',
options: { options: {
year: 'numeric', year: 'numeric',

View file

@ -5,14 +5,14 @@ export const post: PostConfig = {
post: ['mastodon'] post: ['mastodon']
}, },
comment: { comment: {
use: ['Webmention', 'Giscus'], use: ['Remark42','Webmention', 'Giscus'],
style: 'boxed', style: 'boxed',
webmention: { webmention: {
username: 'seviche.cc', username: 'sevic.me',
sortBy: 'created', sortBy: 'created',
sortDir: 'down', sortDir: 'down',
form: true, form: true,
commentParade: true commentParade: false
}, },
giscus: { giscus: {
// src: 'https://giscus.kwaa.dev/client.js', // src: 'https://giscus.kwaa.dev/client.js',
@ -22,16 +22,10 @@ export const post: PostConfig = {
categoryID: 'DIC_kwDOHSra4c4CO9ua', categoryID: 'DIC_kwDOHSra4c4CO9ua',
theme: 'light', theme: 'light',
lang: 'en' 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', // img: 'https://usc1.contabostorage.com/cc0b816231a841b1b0232d5ef0c6deb1:image/2022/06/d4d2489936e4f647c25df6982c6ef924.png',
// link: 'https://haibian.seviche.cc' // 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', id: 'fokify',
name: 'Fokify ', name: 'Fokify ',

View file

@ -1,36 +1,32 @@
import type { SiteConfig } from '$lib/types/site' import type { SiteConfig } from '$lib/types/site'
export const site: SiteConfig = { export const site: SiteConfig = {
protocol: 'https://', protocol: import.meta.env.URARA_SITE_PROTOCOL ?? import.meta.env.DEV ? 'http://' : 'https://',
domain: 'seviche.cc', domain: 'sevic.me',
title: 'Seviche.cc', title: 'sevic.me',
subtitle: 'Tech / Code / Random Life', subtitle: 'Random Frontend-Developer',
lang: 'zh', lang: 'zh',
description: 'Tech / Code / Random Life', description: 'Random Frontend-Developer',
author: { author: {
name: '酸橘汁腌鱼', name: 'Sevi.C',
avatar: '/assets/avatar.jpg', avatar: '/assets/avatar.png',
status: '🖤', status: '🖤',
bio: ' Code / Tech <br> Living a Random Life ', bio: 'Full-stack wizard.',
metadata: [ metadata: [
{ {
text: '',
icon: 'i-mdi-github', icon: 'i-mdi-github',
link: 'https://github.com/sevichecc' link: 'https://github.com/sevichecc'
}, },
{ {
text: '',
icon: 'i-simple-icons-matrix', icon: 'i-simple-icons-matrix',
link: 'https://matrix.to/#/@seviche:kongwoo.icu' link: 'https://matrix.to/#/@seviche:kongwoo.icu'
}, },
{ {
text: '',
icon: 'i-heroicons-solid-key', icon: 'i-heroicons-solid-key',
link: 'https://keys.openpgp.org/vks/v1/by-fingerprint/76DF9F9CC0C3619AA12CB914AFF18B986818D8AD', link: '/assets/DDDDDDDD.asc',
rel: 'pgpkey' rel: 'pgpkey'
}, },
{ {
text: '',
icon: 'i-ic-twotone-rss-feed', icon: 'i-ic-twotone-rss-feed',
link: '/atom.xml', link: '/atom.xml',
rel: 'rss' 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' 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 = { export type PostConfig = {
bridgy?: { bridgy?: {
[kind: string]: ('fed' | 'mastodon' | 'flickr' | 'github' | 'twitter')[] [kind: string]: ('fed' | 'mastodon' | 'flickr' | 'github' | 'twitter')[]
@ -22,8 +15,7 @@ export type CommentConfig = {
giscus?: GiscusConfig giscus?: GiscusConfig
/** Utterances config, more at https://utteranc.es */ /** Utterances config, more at https://utteranc.es */
utterances?: UtterancesConfig utterances?: UtterancesConfig
/** Waline config, more at https://waline.js.org/en/reference/component.html#texrenderer */ remark42?: Remark42Config
waline?: WalineConfig
} }
export type WebmentionConfig = { export type WebmentionConfig = {
@ -81,39 +73,35 @@ export type UtterancesConfig = {
theme?: string theme?: string
} }
export type DisqusConfig = { export type Remark42Config = {
shortname: string /** hostname of Remark42 server, same as REMARK_URL in backend config, e.g. "https://demo.remark42.com" */
lang?: string host: string
} /** the SITE that you passed to Remark42 instance on start of backend. (default: remark) */
site_id?: string
// Refhttps://waline.js.org/reference/component.html /** url to the page with comments*/
export type WalineConfig = { url?: string
/** Waline server address url */ /** an array of widgets that should be rendered on a page (default: ['embed'] )*/
serverURL: string components?: ['embed' | 'last-comments' | 'counter']
/** Article path id*/ /** maximum number of comments that is rendered on mobile version (default: 15 )*/
path?: string max_shown_comments?: number
/** Display language. */ /** maximum number of comments in the last comments widget (default: 15 )*/
lang?: string max_last_comments?: number
/** Emoji settings, for details see https://waline.js.org/en/guide/client/emoji.html */ /** changes UI theme, (default: light )*/
emoji?: (string | WalineEmojiInfo)[] | false theme?: 'light' | 'dark'
/** Darkmode support */ /** title for current comments page (default: document.title)*/
dark?: string | boolean page_title?: string
/** Reviewer attributes. Optional values: 'nick', 'mail', 'link' */ /**
meta?: string[] * interface localization,
/** Set required fields*/ * 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)
requiredMeta?: string[] * default: en
/** login mode status */ */
login?: string locale?: 'en' | 'be' | 'bp' | 'bg' | 'zh' | 'fi' | 'fr' | 'de' | 'ja' | 'ko' | 'pl' | 'ru' | 'es' | 'tr' | 'ua' | 'it' | 'vi'
/** Comment word s limit. */ /** enables email subscription (default: true) */
wordLimit?: number | [number, number] show_email_subscription?: boolean
/**number of comments per page. */ /** enables RSS subscription, (default: true) */
pageSize?: number show_rss_subscription?: boolean
/** Custom image upload method. */ /** minimized UI with basic info only, (default: false) */
imageUploader?: WalineImageUploader | false simple_view?: boolean
/** Code highlighting, use hanabi by default */ /** hides footer with signature and links to Remark42,(default: false) */
highlighter?: WalineHighlighter | false no_footer?: boolean
/** Customize \TeX rendering */
texRender?: WalineTexRenderer | false
/** Whether show copyright and version in footer. */
copyright?: boolean
} }

View file

@ -1,8 +1,6 @@
import type { FFFAuthor } from 'fff-flavored-frontmatter' import type { FFFAuthor } from 'fff-flavored-frontmatter'
export type SiteConfig = { export type SiteConfig = {
/** @deprecated - use `description` instead */
descr?: string
/** site protocol. for example: `https://` */ /** site protocol. for example: `https://` */
protocol: string protocol: string
/** site domain. for example: `example.com` */ /** 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 { onMount } from 'svelte'
import { fly } from 'svelte/transition' import { fly } from 'svelte/transition'
import { page } from '$app/stores' 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 { posts as storedPosts, tags as storedTags } from '$lib/stores/posts'
import { title as storedTitle } from '$lib/stores/title' import { title as storedTitle } from '$lib/stores/title'
import Head from '$lib/components/head.svelte' import Head from '$lib/components/head.svelte'
import Footer from '$lib/components/footer.svelte' import Footer from '$lib/components/footer.svelte'
import Post from '$lib/components/post_card.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 Profile from '$lib/components/index_profile.svelte'
import RemoteFollow from '$lib/components/extra/follow.svelte'
let allPosts: Urara.Post[] let allPosts: Urara.Post[]
let allTags: string[] let allTags: string[]
@ -19,9 +18,7 @@
storedTitle.set('') storedTitle.set('')
$: storedPosts.subscribe( $: storedPosts.subscribe(storedPosts => (allPosts = storedPosts.filter(post => !post.flags?.includes('unlisted'))))
storedPosts => (allPosts = (storedPosts as Urara.Post[]).filter(post => !post.flags?.includes('unlisted')))
)
$: storedTags.subscribe(storedTags => (allTags = storedTags as string[])) $: storedTags.subscribe(storedTags => (allTags = storedTags as string[]))
@ -30,7 +27,7 @@
$: if (tags) { $: if (tags) {
posts = !tags ? allPosts : allPosts.filter(post => tags.every(tag => post.tags?.includes(tag))) posts = !tags ? allPosts : allPosts.filter(post => tags.every(tag => post.tags?.includes(tag)))
if (browser && window.location.pathname === '/') if (browser && window.location.pathname === '/')
window.history.replaceState({}, '', tags.length > 0 ? `?tags=${tags.toString()}` : `/`) goto(tags.length > 0 ? `?tags=${tags.toString()}` : `/`, { replaceState: true })
} }
onMount(() => { onMount(() => {
@ -125,5 +122,3 @@
{/key} {/key}
</div> </div>
</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,21 +1,20 @@
import type { RequestHandler } from '@sveltejs/kit' import type { RequestHandler } from './$types'
import { site } from '$lib/config/site' import { site } from '$lib/config/site'
import { feed } from '$lib/config/general' import { feed } from '$lib/config/general'
import { favicon } from '$lib/config/icon' import { favicon } from '$lib/config/icon'
import { genPosts, genTags } from '$lib/utils/posts' import { genPosts, genTags } from '$lib/utils/posts'
const render = async ( const render = (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })): string =>
posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true }) `<?xml version='1.0' encoding='utf-8'?>
): Promise<string> => `<?xml version='1.0' encoding='utf-8'?>
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<id>${site.protocol + site.domain}/</id> <id>${site.protocol + site.domain}/</id>
<title><![CDATA[${site.title}]]></title>${site.subtitle ? `\n <subtitle><![CDATA[${site.subtitle}]]></subtitle>` : ''}${ <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}" />
<link href="${site.protocol + site.domain}/atom.xml" rel="self" type="application/atom+xml" />${ <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> <updated>${new Date().toJSON()}</updated>
<author> <author>
<name><![CDATA[${site.author.name}]]></name> <name><![CDATA[${site.author.name}]]></name>
@ -39,11 +38,13 @@ const render = async (
</entry>` </entry>`
) )
.join('')} .join('')}
</feed>` </feed>`.trim()
export const GET: RequestHandler = async () => ({ export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () =>
new Response(render(), {
headers: { headers: {
'Content-Type': 'application/atom+xml; charset=utf-8' 'content-type': 'application/atom+xml; charset=utf-8'
}, }
body: await render() })
})

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 { site } from '$lib/config/site'
import { feed } from '$lib/config/general' import { feed } from '$lib/config/general'
import { favicon, any } from '$lib/config/icon' import { favicon, any } from '$lib/config/icon'
import { genPosts } from '$lib/utils/posts' 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', version: 'https://jsonfeed.org/version/1.1',
title: site.title, title: site.title,
home_page_url: site.protocol + site.domain, 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 () => ({ export const prerender = true
export const trailingSlash = 'never'
export const GET: RequestHandler = async () =>
json(render(), {
headers: { headers: {
'Content-Type': 'application/feed+json; charset=utf-8' 'content-type': 'application/feed+json; charset=utf-8'
}, }
body: JSON.stringify(await render(), null, 2) })
})

View file

@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
// @ts-nocheck // @ts-nocheck
import Masonry from 'svelte-bricks' import type { Friend } from '$lib/config/friends'
import { friends as allFriends } from '$lib/config/friends' import { friends as allFriends } from '$lib/config/friends'
import { title as storedTitle } from '$lib/stores/title' import { title as storedTitle } from '$lib/stores/title'
import Head from '$lib/components/head.svelte' import Head from '$lib/components/head.svelte'
import Masonry from 'svelte-bricks'
import FriendComponent from '$lib/components/extra/friend.svelte' import FriendComponent from '$lib/components/extra/friend.svelte'
const rnd = Math.random() const rnd = Math.random()
@ -16,7 +17,7 @@
storedTitle.set('') storedTitle.set('')
</script> </script>
<Head /> <Head page={{ title: 'Friends', path: '/friends' }} />
<Masonry <Masonry
{items} {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 // sveltekit config type
import type { Config } from '@sveltejs/kit' import type { Config } from '@sveltejs/kit'
// svelte preprocess // svelte adapter
import preprocess from 'svelte-preprocess' import adapterVercel from '@sveltejs/adapter-vercel'
import adapterAuto from '@sveltejs/adapter-auto' import adapterNetlify from '@sveltejs/adapter-netlify'
import adapterNode from '@sveltejs/adapter-node'
import adapterStatic from '@sveltejs/adapter-static' import adapterStatic from '@sveltejs/adapter-static'
// svelte preprocessor
import { mdsvex } from 'mdsvex' import { mdsvex } from 'mdsvex'
import mdsvexConfig from './mdsvex.config.js' import mdsvexConfig from './mdsvex.config.js'
import { vitePreprocess } from '@sveltejs/kit/vite'
const defineConfig = (config: Config) => config export default {
export default defineConfig({
extensions: ['.svelte', ...(mdsvexConfig.extensions as string[])], extensions: ['.svelte', ...(mdsvexConfig.extensions as string[])],
preprocess: [mdsvex(mdsvexConfig), preprocess()], preprocess: [mdsvex(mdsvexConfig), vitePreprocess()],
kit: { kit: {
adapter: Object.keys(process.env).some(key => ['VERCEL', 'CF_PAGES', 'NETLIFY'].includes(key)) adapter: Object.keys(process.env).some(key => key === 'VERCEL')
? adapterAuto() ? adapterVercel()
: process.env.ADAPTER === 'node' : Object.keys(process.env).some(key => key === 'NETLIFY')
? adapterNode({ out: 'build' }) ? adapterNetlify()
: adapterStatic({ : adapterStatic({
pages: 'build', pages: 'build',
assets: 'build', assets: 'build',
fallback: undefined fallback: undefined
}), }),
csp: { mode: 'auto' }, prerender: {
prerender: { default: true } 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 { theme } from './src/lib/config/general'
import type { TailwindConfig } from 'tailwindcss/tailwind-config' // @ts-ignore Could not find a declaration file for module '@tailwindcss/typography'.
// @ts-ignore TS2305: Module 'tailwindcss/plugin' has no exported member 'TailwindPluginWithoutOptions'.
import type { TailwindPluginWithoutOptions } from 'tailwindcss/plugin'
// tailwind plugins
import typography from '@tailwindcss/typography' import typography from '@tailwindcss/typography'
// @ts-ignore Could not find a declaration file for module 'daisyui'.
import daisyui from 'daisyui' import daisyui from 'daisyui'
interface Config extends TailwindConfig { export default {
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({
content: ['./src/**/*.{html,md,js,svelte,ts}'], content: ['./src/**/*.{html,md,js,svelte,ts}'],
theme: { theme: { extend: {} },
extend: {} plugins: [typography, daisyui],
}, daisyui: { themes: theme.map(({ name }) => name) }
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'
]
}
})

View file

@ -9,7 +9,7 @@ import chokidar from 'chokidar'
import chalk from 'chalk' import chalk from 'chalk'
const config = { const config = {
extensions: ['svelte', 'md', 'js', 'ts'], extensions: ['md'],
catch: ['ENOENT', 'EEXIST'] catch: ['ENOENT', 'EEXIST']
} }
@ -102,7 +102,7 @@ const clean = () => {
switch (process.argv[2]) { switch (process.argv[2]) {
case 'watch': case 'watch':
{ {
let watcher = chokidar.watch('urara', { const watcher = chokidar.watch('urara', {
ignored: (file: string) => path.basename(file).startsWith('.') ignored: (file: string) => path.basename(file).startsWith('.')
}) })
watcher 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) 来解决,它可以列出最近用过的网页,按站点分类,查找起来很方便 其实搭建之后我没有用过(一次都没有),平时的书签管理主要靠搜索,各个浏览器之间的书签互相导入后,直接在搜索栏搜,如果是常用的网址,我用 Chorme 扩展 [eesel](https://chrome.google.com/webstore/detail/eesel-productivity-at-wor/jffaiidojfhflballoapgofphkadiono) 来解决,它可以列出最近用过的网页,按站点分类,查找起来很方便

View file

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