Compare commits
191 commits
5612fc5cea
...
55648926cc
Author | SHA1 | Date | |
---|---|---|---|
|
55648926cc | ||
|
14eca348d5 | ||
|
ec77b7991c | ||
|
f89931db5e | ||
|
351defae29 | ||
|
7f991888c8 | ||
|
88c2451f1c | ||
|
44161293b1 | ||
|
6857d0db43 | ||
|
709a0ecced | ||
|
d2a4de22ec | ||
|
163636db1c | ||
|
fc3dc11a6c | ||
|
d26faa908c | ||
|
605955c529 | ||
|
688f43a179 | ||
|
cfbd3e80dc | ||
|
73ba867450 | ||
|
8184b22820 | ||
|
b111507444 | ||
|
c1f5625dfc | ||
|
75c75e6eb0 | ||
|
c625f93890 | ||
|
9246a9e62a | ||
|
caa4ee96ee | ||
|
bd40930dd1 | ||
|
5f0f13791f | ||
|
81b2dfe5eb | ||
|
044ee42fbd | ||
|
de1c154c5a | ||
|
bf1cf00372 | ||
|
e4c443f5de | ||
|
6b9f76c2f4 | ||
|
d608d52f96 | ||
|
b99e3bbce4 | ||
|
51001b4c9a | ||
|
bcbcc19cc4 | ||
|
c172e458dd | ||
|
d3d15f2319 | ||
|
893b52a54c | ||
|
c6ee95ed14 | ||
|
1a4d315dc8 | ||
|
f012cd49df | ||
|
3a101d930d | ||
|
d368b27ccb | ||
|
b55b7e743e | ||
|
f61de8a4ef | ||
|
3eee6f2e08 | ||
|
9a4524334b | ||
|
e6121d7ce6 | ||
|
5fa39eff5f | ||
|
dfe8c3c86b | ||
|
3b0f1e0054 | ||
|
bc1a63a3c6 | ||
|
ba77428863 | ||
|
6887d2d2f4 | ||
|
67fc487ebd | ||
|
76c25dca25 | ||
|
8e03d5a6f9 | ||
|
43fa4b6f1d | ||
|
5839788ec5 | ||
|
7caf081bf0 | ||
|
ce5cb61e4a | ||
|
89e26218da | ||
|
f88ed05c3a | ||
|
ea843494dd | ||
|
3b91c65936 | ||
|
40468ba170 | ||
|
34a9bb8bc7 | ||
|
09304b5ff2 | ||
|
fd852e8662 | ||
|
01ef65192c | ||
|
2dc0ae6a29 | ||
|
c62a1d3d9c | ||
|
c86396d231 | ||
|
8f026e2f82 | ||
|
97a7368f78 | ||
|
8f785854a2 | ||
|
2495dc7278 | ||
|
3bb83c69db | ||
|
6b0931e36f | ||
|
cccd540138 | ||
|
fd675ffba6 | ||
|
e1192c07c9 | ||
|
fcdd5e5b8b | ||
|
4a4437fa89 | ||
|
54ef29e9df | ||
|
3117fea376 | ||
|
f9900cf2ce | ||
|
6b9ddc6515 | ||
|
d9bab31169 | ||
|
7ca12e188f | ||
|
65742201d7 | ||
|
3dcc661557 | ||
|
412977735d | ||
|
fea2bb0eb7 | ||
|
46c00bd873 | ||
|
7db3e8e84c | ||
a820252f19 | |||
896ca068b7 | |||
ebcc44815d | |||
39101d900b | |||
93f88e280e | |||
60e4c8e2a9 | |||
656c3846b9 | |||
1fc6d7059c | |||
d794908974 | |||
0aab4b206c | |||
6c025d206a | |||
|
f6d906fbc5 | ||
|
a1229cc818 | ||
|
66f7be3031 | ||
|
dc2dde8179 | ||
|
f2a72ff665 | ||
|
a4b09a51b5 | ||
|
5ac936411d | ||
|
a552789045 | ||
|
8063db4288 | ||
|
66e70995ff | ||
|
78f03b17af | ||
|
8bb2dfba88 | ||
|
fb398f01e5 | ||
|
5fbfeb2a14 | ||
|
3da4beb5ac | ||
|
4a76821732 | ||
|
c2ee7651c8 | ||
|
51d0ccfc4d | ||
|
c5c84b6614 | ||
|
4dfc70fbfd | ||
|
51e83043c2 | ||
|
acdd20d4a8 | ||
|
a72c359538 | ||
|
f97821910f | ||
|
33eb87f572 | ||
|
33938da75c | ||
|
fac88146a3 | ||
|
b75c60446b | ||
|
f97af151ff | ||
|
26db89bc7e | ||
|
c0b4685c7d | ||
|
469f5cfa3c | ||
|
1dfadf2ca1 | ||
|
46eb1dcdde | ||
|
8182065dcb | ||
|
2e8a8d00f4 | ||
|
b79470639f | ||
|
50ca3f23fe | ||
|
28b408bcd4 | ||
|
3791f92a60 | ||
|
2a58c54703 | ||
|
f0b5baec3a | ||
|
ba8072ed97 | ||
|
20200c540f | ||
|
08949974ff | ||
|
16f0222a17 | ||
|
bc42a8069c | ||
|
da8707e219 | ||
|
9f3dd18a29 | ||
|
61d8b528bd | ||
|
aef66c2278 | ||
|
a7afea3b62 | ||
|
f41426b657 | ||
|
0e650c5e72 | ||
|
5ed354da07 | ||
|
2db40dc64a | ||
|
aa73a982d7 | ||
|
0cfe982419 | ||
|
b758269bcb | ||
|
e21f200413 | ||
|
d990868296 | ||
|
ba9f0cb316 | ||
|
2318fbb0a4 | ||
|
939dd01dcb | ||
|
a6014f2701 | ||
|
0a2e7d6c4d | ||
|
d5e0938a4f | ||
|
68da2b2c4d | ||
|
e3d3106970 | ||
|
1514bc87c0 | ||
|
ee25a10322 | ||
|
eb8bffb49b | ||
|
2f0f551806 | ||
|
2aa93f55f8 | ||
|
a83280d7c7 | ||
|
1c13a53032 | ||
|
65cf431855 | ||
|
381f3b952b | ||
|
64ad865a62 | ||
|
c14ed1c151 | ||
|
21021e8fe1 | ||
|
f7bd62db4d |
35
.gitignore
vendored
|
@ -1,15 +1,26 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
.svelte-kit
|
||||
/package
|
||||
src/routes/**/
|
||||
src/routes/*.md
|
||||
static/
|
||||
# build output
|
||||
build
|
||||
.vercel_build_output/
|
||||
.netlify/
|
||||
.env.local
|
||||
.env.**.local
|
||||
myblog/urara/2022-06-12-appwrite.md
|
||||
static
|
||||
.svelte-kit
|
||||
.netlify
|
||||
.vercel
|
||||
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# env
|
||||
*.local
|
||||
|
||||
# logs
|
||||
pnpm-debug.log*
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# temp file
|
||||
src/routes/**/+page.svelte.md
|
||||
src/routes/**/+page.md
|
||||
src/static
|
||||
*.config.js
|
||||
urara.js
|
1
.npmrc
|
@ -1 +1,2 @@
|
|||
engine-strict=true
|
||||
strict-peer-dependencies=false
|
||||
|
|
2
.nvmrc
|
@ -1 +1 @@
|
|||
v18.4.0
|
||||
v19.4.0
|
2
.vscode/settings.json
vendored
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"files.eol": "\n",
|
||||
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"css.lint.unknownAtRules": "ignore",
|
||||
"svelte.plugin.css.diagnostics.enable": false,
|
||||
"[html]": {
|
||||
|
|
|
@ -20,7 +20,7 @@ My Tech Blog, base on [Urara](https://github.com/importantimport/urara)
|
|||
## TODO
|
||||
|
||||
- [ ] Note Page
|
||||
- [ ] Archie Page
|
||||
- [ ] Archvie Page
|
||||
- [ ] Refactoring the atom feed format
|
||||
- [ ] NeoDB component
|
||||
- [ ] ...
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#!/bin/bash
|
||||
echo "————————1. Build locally————————"
|
||||
netlify build
|
||||
echo "————————2.Deploy test————————"
|
||||
netlify deploy
|
||||
echo "————————3.Deploy————————"
|
||||
echo "————————2.Deploy————————————————"
|
||||
netlify deploy --prod
|
|
@ -13,6 +13,7 @@ import { parse, join } from 'path'
|
|||
import { visit } from 'unist-util-visit'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import Slugger from 'github-slugger'
|
||||
import remarkFFF from 'remark-fff'
|
||||
import remarkFootnotes from 'remark-footnotes'
|
||||
|
||||
// highlighter
|
||||
|
@ -24,12 +25,12 @@ type VALUE = { [key in string | number]: VALUE } | Array<VALUE> | string | boole
|
|||
const remarkUraraFm =
|
||||
() =>
|
||||
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => {
|
||||
const filepath = (filename as string).split('/src/routes')[1]
|
||||
const filepath = filename ? filename.split('/src/routes')[1] : 'unknown'
|
||||
const { dir, name } = parse(filepath)
|
||||
if (!data.fm) data.fm = {}
|
||||
// Generate slug & path
|
||||
data.fm.slug = filepath
|
||||
data.fm.path = join(dir, `/${name}`.replace('/index', '').replace('.svelte', ''))
|
||||
data.fm.path = join(dir, `/${name}`.replace('/+page', '').replace('.svelte', ''))
|
||||
// Generate ToC
|
||||
if (data.fm.toc !== false) {
|
||||
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []]
|
||||
|
@ -40,23 +41,9 @@ const remarkUraraFm =
|
|||
slug: slugs.slug(toString(node), false)
|
||||
})
|
||||
})
|
||||
data.fm.toc = toc
|
||||
if (toc.length > 0) data.fm.toc = toc
|
||||
else data.fm.toc = false
|
||||
}
|
||||
// Auto-read created & updated
|
||||
if (!data.fm.created || !data.fm.updated) {
|
||||
const { ctime, mtime } = statSync(new URL(`./urara${filepath}`, import.meta.url))
|
||||
if (!data.fm.created) data.fm.created = ctime
|
||||
if (!data.fm.updated) data.fm.updated = mtime
|
||||
}
|
||||
// Remark FFF Experimental (Hugo -> MDsveX)
|
||||
Object.entries({
|
||||
image: 'images',
|
||||
tags: 'category',
|
||||
bookmark_of: 'bookmarkOf',
|
||||
like_of: 'likeOf',
|
||||
repost_of: 'repostOf',
|
||||
in_reply_to: 'inReplyTo'
|
||||
}).forEach(([output, input]: string[]) => (data.fm = { ...data.fm, [output]: data.fm![input] }))
|
||||
}
|
||||
|
||||
// Better type definitions needed
|
||||
|
@ -72,9 +59,7 @@ const remarkUraraSpoiler = () => (tree: Node<Data>) =>
|
|||
return node
|
||||
})
|
||||
|
||||
const defineConfig = (config: MdsvexOptions) => config
|
||||
|
||||
export default defineConfig({
|
||||
export default {
|
||||
extensions: ['.svelte.md', '.md'],
|
||||
smartypants: {
|
||||
dashes: 'oldschool'
|
||||
|
@ -104,9 +89,24 @@ export default defineConfig({
|
|||
)}\` }`
|
||||
}
|
||||
},
|
||||
remarkPlugins: [remarkUraraFm, remarkUraraSpoiler, [remarkFootnotes, { inlineNotes: true }]],
|
||||
remarkPlugins: [
|
||||
[
|
||||
remarkFFF as any,
|
||||
{
|
||||
presets: ['hugo'],
|
||||
target: 'mdsvex',
|
||||
autofill: {
|
||||
provider: 'fs',
|
||||
path: (path: string) => path.replace('/src/routes/', '/urara/')
|
||||
}
|
||||
}
|
||||
],
|
||||
remarkUraraFm,
|
||||
remarkUraraSpoiler,
|
||||
[remarkFootnotes, { inlineNotes: true }]
|
||||
],
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
rehypeSlug as any,
|
||||
[rehypeAutolinkHeadings, { behavior: 'wrap' }],
|
||||
[
|
||||
rehypeExternalLinks,
|
||||
|
@ -116,4 +116,4 @@ export default defineConfig({
|
|||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
} as MdsvexOptions
|
||||
|
|
15
netlify.toml
|
@ -1,8 +1,7 @@
|
|||
[build]
|
||||
command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm build"
|
||||
command = "corepack prepare pnpm@8.5.1 --activate && pnpm i && npx pnpm build"
|
||||
publish = "build"
|
||||
|
||||
|
||||
[build.environment]
|
||||
NPM_FLAGS = "--version"
|
||||
AWS_LAMBDA_JS_RUNTIME = "nodejs16.x"
|
||||
|
@ -26,13 +25,17 @@ node_bundler = "esbuild"
|
|||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
Access-Control-Allow-Origin = "https://seviche.cc"
|
||||
X-Frame-Options = "DENY"
|
||||
Access-Control-Allow-Origin = "sevic.me"
|
||||
X-Frame-Options = "SAMEORIGIN"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
X-XSS-Protection = "1; mode=block"
|
||||
Content-Security-Policy = "style-src 'self' 'unsafe-inline' https://cdn.commento.io/css/commento.css http://fonts.cdnfonts.com/css/lato ; script-src 'self' 'unsafe-inline' https://*.seviche.cc https://giscus.app https://hexoverc.vercel.app/umami.js https://cdn.splitbee.io/sb.js https://cdn.commento.io/js/commento.js"
|
||||
Content-Security-Policy = "script-src 'self' 'unsafe-inline' https://*.seviche.cc https://giscus.app https://hexoverc.vercel.app/umami.js https://cdn.splitbee.io/sb.js https://plausiable.seviche.cc/js/script.js"
|
||||
Referrer-Policy = "strict-origin-when-cross-origin"
|
||||
Permissions-Policy = "usb=()"
|
||||
[[redirects]]
|
||||
from = "/.well-known/webfinger"
|
||||
to = "https://kongwoo.icu/.well-known/webfinger?resource=acct:blog@kongwoo.icu"
|
||||
status = 302
|
||||
force = true
|
||||
|
||||
[[redirects]]
|
||||
from = "/.well-known/host-meta"
|
||||
|
|
102
package.json
|
@ -12,16 +12,12 @@
|
|||
"tsc:watch": "tsc -w -p tsconfig.node.json",
|
||||
"urara:build": "node urara.js build",
|
||||
"urara:watch": "node urara.js watch",
|
||||
"kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite dev",
|
||||
"kit:build": "cross-env NODE_OPTIONS=--max_old_space_size=7680 vite build",
|
||||
"kit:dev": "cross-env NODE_OPTIONS=--max_old_space_size=11474 vite dev",
|
||||
"kit:build": "cross-env NODE_OPTIONS=--max_old_space_size=11474 vite build",
|
||||
"dev:parallel": "npm-run-all -p -r tsc:watch urara:watch \"kit:dev {@} \" --",
|
||||
"dev": "npm-run-all -s tsc \"dev:parallel {@} \" --",
|
||||
"build": "npm-run-all -s tsc urara:build kit:build clean",
|
||||
"preview": "vite preview",
|
||||
"dev:urara": "node urara.js watch",
|
||||
"dev:kit": "export NODE_OPTIONS=--max_old_space_size=8192 && MODE=development svelte-kit dev",
|
||||
"build:urara": "node urara.ts build",
|
||||
"build:kit": "export NODE_OPTIONS=--max_old_space_size=8192 && svelte-kit build",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
||||
|
@ -29,58 +25,66 @@
|
|||
"zhlint": "zhlint urara/*/*.md --fix && zhlint urara/*.md --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/heroicons-outline": "^1.1.2",
|
||||
"@iconify-json/heroicons-solid": "^1.1.2",
|
||||
"@iconify-json/ic": "^1.1.9",
|
||||
"@iconify-json/simple-icons": "1.1.21",
|
||||
"@iconify-json/material-symbols": "1.1.14",
|
||||
"@iconify-json/mdi": "^1.1.30",
|
||||
"@iconify-json/uil": "^1.1.2",
|
||||
"@sveltejs/adapter-auto": "1.0.0-next.64",
|
||||
"@sveltejs/adapter-node": "1.0.0-next.86",
|
||||
"@sveltejs/adapter-static": "1.0.0-next.39",
|
||||
"@sveltejs/kit": "1.0.0-next.405",
|
||||
"@tailwindcss/typography": "^0.5.4",
|
||||
"@types/node": "^18.7.8",
|
||||
"@iconify-json/heroicons-outline": "^1.1.6",
|
||||
"@iconify-json/heroicons-solid": "^1.1.7",
|
||||
"@iconify-json/ic": "^1.1.13",
|
||||
"@iconify-json/icon-park-twotone": "1.1.9",
|
||||
"@iconify-json/material-symbols": "1.1.41",
|
||||
"@iconify-json/mdi": "^1.1.52",
|
||||
"@iconify-json/simple-icons": "1.1.52",
|
||||
"@iconify-json/uil": "^1.1.4",
|
||||
"@sveltejs/adapter-netlify": "^2.0.7",
|
||||
"@sveltejs/adapter-static": "^2.0.2",
|
||||
"@sveltejs/adapter-vercel": "2.4.3",
|
||||
"@sveltejs/kit": "^1.19.0",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/unist": "^2.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"chalk": "^5.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
||||
"@typescript-eslint/parser": "^5.59.7",
|
||||
"@unocss/extractor-svelte": "^0.51.13",
|
||||
"@vite-pwa/sveltekit": "^0.1.3",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^5.1.13",
|
||||
"daisyui": "^2.24.0",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"daisyui": "^2.51.6",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"fenceparser": "^2.2.0",
|
||||
"fff-flavored-frontmatter": "~0.2.2",
|
||||
"github-slugger": "^1.4.0",
|
||||
"mdast-util-to-string": "^3.1.0",
|
||||
"fff-flavored-frontmatter": "~0.5.3",
|
||||
"github-slugger": "^2.0.0",
|
||||
"mdast-util-to-string": "^3.2.0",
|
||||
"mdsvex": "^0.10.6",
|
||||
"netlify-cli": "^16.3.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.16",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"postcss": "^8.4.23",
|
||||
"postcss-lightningcss": "^0.7.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-svelte": "^2.10.0",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
"rehype-external-links": "^2.0.0",
|
||||
"rehype-slug": "^5.0.1",
|
||||
"remark": "^14.0.2",
|
||||
"rehype-external-links": "^2.1.0",
|
||||
"rehype-slug": "^5.1.0",
|
||||
"remark": "^14.0.3",
|
||||
"remark-fff": "~0.5.3",
|
||||
"remark-footnotes": "~2.0.0",
|
||||
"shiki-twoslash": "^3.1.0",
|
||||
"svelte": "^3.49.0",
|
||||
"rollup": "^3.23.0",
|
||||
"shiki-twoslash": "^3.1.2",
|
||||
"svelte": "^3.59.1",
|
||||
"svelte-bricks": "^0.1.7",
|
||||
"svelte-check": "^2.8.1",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte-typeahead": "^4.2.4",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "^4.7.4",
|
||||
"unist-util-visit": "^4.1.0",
|
||||
"unocss": "^0.45.8",
|
||||
"vite": "^3.0.9",
|
||||
"vite-plugin-pwa": "^0.12.3",
|
||||
"workbox-window": "^6.5.4"
|
||||
"svelte-check": "^3.4.3",
|
||||
"svelte-preprocess": "^5.0.4",
|
||||
"svelte-typeahead": "^4.4.1",
|
||||
"sveltekit-embed": "^0.0.12",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"tslib": "^2.5.2",
|
||||
"typescript": "^5.0.4",
|
||||
"unist-util-visit": "^4.1.2",
|
||||
"unocss": "^0.51.13",
|
||||
"vite": "^4.3.9",
|
||||
"vite-imagetools": "^4.0.19",
|
||||
"vite-plugin-pwa": "^0.14.7",
|
||||
"workbox-build": "^6.6.0",
|
||||
"workbox-window": "^6.6.0"
|
||||
}
|
||||
}
|
17281
pnpm-lock.yaml
11
src/app.d.ts
vendored
|
@ -1,8 +1,9 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
import { FFFBase, FFFExtra } from 'fff-flavored-frontmatter'
|
||||
import type { FFFBase, FFFMention } from 'fff-flavored-frontmatter'
|
||||
|
||||
interface ImportMetaEnv extends Readonly<Record<string, string>> {
|
||||
readonly URARA_SITE_PROTOCOL?: 'http://' | 'https://'
|
||||
readonly URARA_SITE_DOMAIN?: string
|
||||
}
|
||||
|
||||
|
@ -14,8 +15,8 @@ interface ImportMeta {
|
|||
declare global {
|
||||
namespace Urara {
|
||||
namespace Post {
|
||||
type Frontmatter = Omit<FFFBase, 'created' | 'updated' | 'image' | 'audio' | 'video' | 'flags'> &
|
||||
Pick<FFFExtra, 'in_reply_to'> & {
|
||||
type Frontmatter = Omit<FFFBase, 'flags'> &
|
||||
Pick<FFFMention, 'in_reply_to'> & {
|
||||
/**
|
||||
* post type.
|
||||
* @remarks auto-generated
|
||||
|
@ -50,6 +51,10 @@ declare global {
|
|||
* @remarks auto-generated or set manually
|
||||
*/
|
||||
updated: string
|
||||
/**
|
||||
* the published date of the post.
|
||||
*/
|
||||
published?: string
|
||||
/**
|
||||
* the featured image for article, or image for "photo" / "multi-photo" posts.
|
||||
* @remarks currently only supports string
|
||||
|
|
|
@ -13,5 +13,6 @@
|
|||
|
||||
<body itemscope itemtype="https://schema.org/WebPage">
|
||||
%sveltekit.body%
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -56,7 +56,12 @@ html {
|
|||
/* .urara-prose a */
|
||||
|
||||
.urara-prose :is(p, li) > a {
|
||||
@apply bg-[length:100%_0.2em] hover:bg-[length:100%_100%] bg-[position:0_88%] bg-gradient-to-t from-secondary/50 to-secondary/40 bg-no-repeat transition-all ease-in-out !no-underline;
|
||||
@apply underline
|
||||
font-normal
|
||||
hover:decoration-red-700/50
|
||||
hover:text-red-700
|
||||
decoration-2
|
||||
underline-offset-4 decoration-gray-700/30;
|
||||
}
|
||||
|
||||
/* .urara-prose misc */
|
||||
|
@ -188,9 +193,9 @@ pre.twoslash data-lsp:hover::before {
|
|||
|
||||
.urara-prose blockquote:before {
|
||||
vertical-align: -0.4em;
|
||||
@apply mr-2 text-5xl leading-3 italic font-serif opacity-25;
|
||||
@apply mr-2 text-5xl mt-4 leading-3 italic font-serif opacity-25 float-left;
|
||||
}
|
||||
|
||||
.urara-prose blockquote p {
|
||||
@apply inline opacity-80 before:content-[''] after:content-[''];
|
||||
@apply opacity-80 before:content-[''] after:content-[''];
|
||||
}
|
7
src/hooks.server.ts
Normal file
|
@ -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'}">`)
|
||||
})
|
5
src/lib/components/actions/1-comment.svelte
Normal 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>
|
|
@ -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>
|
|
@ -3,10 +3,12 @@
|
|||
export let post: Urara.Post
|
||||
</script>
|
||||
|
||||
<button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Translate">
|
||||
<a
|
||||
href={`https://translate.google.com/translate?sl=auto&tl=${
|
||||
navigator.languages ? navigator.languages[0] : navigator.language
|
||||
}&u=${site.protocol + site.domain + post.path}`}
|
||||
class="btn btn-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" />
|
||||
</a>
|
||||
</button>
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
export let post: Urara.Post
|
||||
</script>
|
||||
|
||||
<button class="tooltip tooltip-left opacity-60 hover:opacity-100" data-tip="Share">
|
||||
<a
|
||||
href={`https://www.addtoany.com/share#url=${site.protocol + site.domain + post.path}&title=${encodeURI(
|
||||
post.title ?? post.path.slice(1)
|
||||
)}`}
|
||||
class="btn btn-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" />
|
||||
</a>
|
||||
</button>
|
||||
|
|
63
src/lib/components/comments/remark42.svelte
Normal 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" />
|
|
@ -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> -->
|
|
@ -74,6 +74,36 @@
|
|||
</script>
|
||||
|
||||
<div class="flex flex-col gap-8">
|
||||
{#if config?.form === true}
|
||||
<form id="webmention-form" method="post" action="https://webmention.io/{config.username}/webmention">
|
||||
<input type="hidden" name="target" value={site.protocol + site.domain + post.path} />
|
||||
<div class="label gap-4">
|
||||
<span class="label-text">send webmentions here:</span>
|
||||
<!-- {#if config?.commentParade === true}
|
||||
<span class="label-text-alt text-right">
|
||||
or <a
|
||||
class="hover:!text-primary"
|
||||
href="https://quill.p3k.io/?dontask=1&me=https://commentpara.de/&reply={encodeURI(
|
||||
site.protocol + site.domain + post.path
|
||||
)}">
|
||||
comment anonymously
|
||||
</a>
|
||||
</span>
|
||||
{/if} -->
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="input input-bordered focus:input-primary w-full"
|
||||
type="text"
|
||||
id="reply-url"
|
||||
name="source"
|
||||
placeholder="https://example.com/my-post" />
|
||||
</div>
|
||||
<button class="btn btn-primary flex-none mt-auto" type="submit" id="webmention-submit">Send</button>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
<div class="flex">
|
||||
<p class="flex-1 m-auto italic opacity-50">
|
||||
<!-- {`Sort by=${config?.sortBy ?? 'Created'}&sort-dir=${sortDirUp ? 'up' : 'down'}`} -->
|
||||
|
@ -172,34 +202,4 @@
|
|||
{:else}
|
||||
<button id="webmention-loading" class="btn btn-lg btn-block flex btn-ghost loading" />
|
||||
{/if}
|
||||
{#if config?.form === true}
|
||||
<form id="webmention-form" method="post" action="https://webmention.io/{config.username}/webmention">
|
||||
<input type="hidden" name="target" value={site.protocol + site.domain + post.path} />
|
||||
<div class="label gap-4">
|
||||
<span class="label-text">send webmentions here:</span>
|
||||
{#if config?.commentParade === true}
|
||||
<span class="label-text-alt text-right">
|
||||
or <a
|
||||
class="hover:!text-primary"
|
||||
href="https://quill.p3k.io/?dontask=1&me=https://commentpara.de/&reply={encodeURI(
|
||||
site.protocol + site.domain + post.path
|
||||
)}">
|
||||
comment anonymously
|
||||
</a>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="input input-bordered focus:input-primary w-full"
|
||||
type="text"
|
||||
id="reply-url"
|
||||
name="source"
|
||||
placeholder="https://example.com/my-post" />
|
||||
</div>
|
||||
<button class="btn btn-primary flex-none mt-auto" type="submit" id="webmention-submit">Send</button>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
.then(
|
||||
({ links }) => links.find((link: { rel: string }) => link.rel === 'http://ostatus.org/schema/1.0/subscribe').template
|
||||
)
|
||||
.then(template => (window.location.href = template.replace('{uri}', `sevichecc@kongwoo.icu`)))
|
||||
.then(template => (window.location.href = template.replace('{uri}', `blog@seviche.cc`)))
|
||||
.catch(error => console.error(error))
|
||||
$: if (input)
|
||||
input.length < 5 ? (status = '') : input.includes('@') && input.includes('.') ? (status = 'success') : (status = 'warning')
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let user = undefined
|
||||
export let repo = undefined
|
||||
export let user = ''
|
||||
export let repo = ''
|
||||
let info: {
|
||||
html_url: string
|
||||
description: string
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { dev } from '$app/env'
|
||||
import { dev } from '$app/environment'
|
||||
let className = undefined
|
||||
export { className as class }
|
||||
export let src = undefined
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
<div class="rounded-full border-2 border-white shadow-xl w-16 h-16">
|
||||
<img
|
||||
class="hover:rotate-[360deg] transition-transform duration-1000 ease-in-out m-0"
|
||||
src={avatar ?? site.author.avatar}
|
||||
alt={name ?? site.author.name}
|
||||
loading="lazy"
|
||||
decoding="async" />
|
||||
decoding="async"
|
||||
src={avatar ?? site.author.avatar} />
|
||||
</div>
|
||||
</div>
|
||||
{#if subname}
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
<script lang="ts">
|
||||
export let id = undefined
|
||||
export let list = undefined
|
||||
export let playlist = undefined
|
||||
export let start = undefined
|
||||
export let autoplay = false
|
||||
export let disablekb = false
|
||||
export let controls = true
|
||||
export let id: string
|
||||
export let list: boolean | undefined = undefined
|
||||
export let playlist: string | undefined = undefined
|
||||
export let start: string | undefined = undefined
|
||||
export let autoplay: boolean = false
|
||||
export let disablekb: boolean = false
|
||||
export let controls: boolean = true
|
||||
export let fs = true
|
||||
export let loop = false
|
||||
|
||||
const src = `https://www.youtube.com/embed/${id}?${list ? `listType=playlist&list=${list}&` : ''}${
|
||||
playlist ? `playlist=${playlist}&` : ''
|
||||
}${start ? `start=${start}` : ''}${autoplay ? 'autoplay=1&' : ''}${disablekb ? 'disablekb=1&' : ''}${
|
||||
controls ? '' : 'controls=0&'
|
||||
}${fs ? '' : 'fs=0&'}${loop ? 'loop=1' : ''}`
|
||||
const src = `https://www.youtube.com/embed/${id}?${new URLSearchParams({
|
||||
...(list ? { listType: 'playlist', list: 'true' } : {}),
|
||||
...(playlist ? { playlist } : {}),
|
||||
...(start ? { start } : {}),
|
||||
autoplay: autoplay ? '1' : '0',
|
||||
disablekb: disablekb ? '1' : '0',
|
||||
controls: controls ? '1' : '0',
|
||||
fs: fs ? '1' : '0',
|
||||
loop: loop ? '1' : '0'
|
||||
}).toString()}`
|
||||
</script>
|
||||
|
||||
<div class="relative pb-[56.25%] mb-2">
|
||||
<div class="relative pb-[56.25%] mb-4">
|
||||
<iframe
|
||||
{src}
|
||||
class="absolute w-full h-full"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<p>
|
||||
{#if footerConfig.nav}
|
||||
{#each footerConfig.nav as { text, link }, i}
|
||||
<a href={link} rel="noopener external" target="_blank">{text}</a>
|
||||
<a href={link} rel="noopener noreferrer external" target="_blank">{text}</a>
|
||||
{#if i + 1 < footerConfig.nav.length}
|
||||
<span class="mr-1">·</span>
|
||||
{/if}
|
||||
|
@ -30,7 +30,7 @@
|
|||
<br />
|
||||
Powered by
|
||||
<a
|
||||
rel="noopener external"
|
||||
rel="noopener noreferrer external"
|
||||
target="_blank"
|
||||
class="tooltip tooltip-secondary hover:text-secondary"
|
||||
data-tip="🌸 [δ] - Based on MDsveX & SvelteKit 🌸"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { dev } from '$app/env'
|
||||
import { dev } from '$app/environment'
|
||||
import { head } from '$lib/config/general'
|
||||
import { site } from '$lib/config/site'
|
||||
import OpenGraph from '$lib/components/head_opengraph.svelte'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { browser, dev } from '$app/env'
|
||||
import { browser, dev } from '$app/environment'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { site } from '$lib/config/site'
|
||||
import { theme } from '$lib/config/general'
|
||||
|
@ -41,7 +41,8 @@
|
|||
|
||||
if (browser)
|
||||
currentTheme =
|
||||
localStorage.getItem('theme') ?? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'night' : 'lemonade')
|
||||
localStorage.getItem('theme') ??
|
||||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? theme?.[1].name : theme[0].name ?? theme[0].name)
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -54,34 +55,32 @@
|
|||
id="header"
|
||||
class:-translate-y-32={!pin && scrollY > 0}
|
||||
class="fixed z-50 w-screen transition-all duration-500 ease-in-out border-b-2 border-transparent max-h-[4.125rem] {scrollY >
|
||||
32 && 'backdrop-blur border-base-content/10 bg-base-100/30 md:bg-base-200/30'}">
|
||||
32 && 'backdrop-blur !border-base-content/10 bg-base-100/30 md:bg-base-200/30'}">
|
||||
{#if !search}
|
||||
<div in:fly={{ x: -50, duration: 300, delay: 300 }} out:fly={{ x: -50, duration: 300 }} class="navbar">
|
||||
<div class="navbar-start">
|
||||
{#if headerConfig.nav}
|
||||
<Nav {path} {title} {pin} {scrollY} nav={headerConfig.nav} />
|
||||
{/if}
|
||||
<a href="/" 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 class="navbar-end">
|
||||
<!-- {#if headerConfig.search} -->
|
||||
<!-- The button to open modal -->
|
||||
<!-- <label for="search-modal" class="btn btn-square btn-ghost ml-2"><span class="i-heroicons-outline-search" /></label> -->
|
||||
<!-- <button
|
||||
on:click={() => {
|
||||
search = !search
|
||||
}}
|
||||
type="submit"
|
||||
class="btn btn-square btn-ghost ml-2">
|
||||
{#if headerConfig.search}
|
||||
<button aria-label="search" on:click={() => (search = !search)} tabindex="0" class="btn btn-square btn-ghost">
|
||||
<span class="i-heroicons-outline-search" />
|
||||
</button> -->
|
||||
<!-- {/if} -->
|
||||
</button>
|
||||
{/if}
|
||||
<div id="change-theme" class="dropdown dropdown-end">
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
|
||||
<div tabindex="0" class="btn btn-square btn-ghost">
|
||||
<span class="i-heroicons-outline-color-swatch" />
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="flex 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}>
|
||||
{#each theme as { name, text }}
|
||||
<button
|
||||
|
@ -92,7 +91,7 @@
|
|||
}}
|
||||
class:border-2={currentTheme === name}
|
||||
class:border-primary={currentTheme === name}
|
||||
class="btn btn-ghost hover:bg-primary group rounded-lg flex bg-base-100 p-2 transition-all">
|
||||
class="btn btn-ghost w-full hover:bg-primary group rounded-lg flex bg-base-100 p-2 transition-all">
|
||||
<p class="flex-1 text-left text-base-content group-hover:text-primary-content transition-color">
|
||||
{text ?? name}
|
||||
</p>
|
||||
|
@ -108,6 +107,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div in:fly={{ x: 50, duration: 300, delay: 300 }} out:fly={{ x: 50, duration: 300 }} class="navbar">
|
||||
<Search />
|
||||
<button on:click={() => (search = !search)} tabindex="0" class="btn btn-square btn-ghost">
|
||||
<span class="i-heroicons-outline-x" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
<button
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
export let pin: boolean
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- reference: https://github.com/saadeghi/daisyui/issues/1285 -->
|
||||
<div class="dropdown lg:hidden">
|
||||
<label for="navbar-dropdown" tabindex="0" class="btn btn-square btn-ghost">
|
||||
<span class="i-heroicons-outline-menu-alt-1" />
|
||||
|
@ -14,11 +16,12 @@
|
|||
id="navbar-dropdown"
|
||||
tabindex="0"
|
||||
class:hidden={!pin}
|
||||
class="menu menu-compact dropdown-content bg-base-100 text-base-content shadow-lg rounded-box max-w-52 p-2">
|
||||
class="menu menu-compact dropdown-content bg-base-100 text-base-content shadow-lg rounded-box min-w-max max-w-52 p-2
|
||||
">
|
||||
{#each nav as { text, link, children }}
|
||||
{#if link && !children}
|
||||
<li>
|
||||
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
|
||||
<a class:font-bold={link === path} href={link}>{text}</a>
|
||||
</li>
|
||||
{:else if children}
|
||||
<li tabindex="0">
|
||||
|
@ -29,7 +32,7 @@
|
|||
<ul class="bg-base-100 text-base-content shadow-lg p-2">
|
||||
{#each children as { text, link }}
|
||||
<li>
|
||||
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
|
||||
<a class:font-bold={link === path} href={link}>{text}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
@ -49,18 +52,19 @@
|
|||
{#each nav as { text, link, children }}
|
||||
{#if link && !children}
|
||||
<li>
|
||||
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
|
||||
<a class="!rounded-btn" class:font-bold={link === path} href={link}>{text}</a>
|
||||
</li>
|
||||
{:else if children}
|
||||
<li tabindex="0">
|
||||
<span class:font-bold={children.some(({ link }) => link === path)} class="gap-1">
|
||||
<li>
|
||||
<span class:font-bold={children.some(({ link }) => link === path)} class="!rounded-btn gap-1">
|
||||
{text}
|
||||
<span class="i-heroicons-solid-chevron-down -mr-1" />
|
||||
</span>
|
||||
<ul class="bg-base-100 text-base-content shadow-lg p-2">
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<ul tabindex="0" class="menu rounded-box bg-base-100 text-base-content shadow-lg p-2">
|
||||
{#each children as { text, link }}
|
||||
<li>
|
||||
<a sveltekit:prefetch class:font-bold={link === path} href={link}>{text}</a>
|
||||
<a class:font-bold={link === path} href={link}>{text}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
|
|
@ -1,102 +1,21 @@
|
|||
<script lang="ts">
|
||||
import { onMount, createEventDispatcher } from 'svelte'
|
||||
import { site } from '$lib/config/site'
|
||||
import { header as headerConfig } from '$lib/config/general'
|
||||
import Typeahead from 'svelte-typeahead'
|
||||
import { page } from '$app/stores'
|
||||
// ref : https://github.com/saadeghi/daisyui/blob/master/src/docs/src/components/Search.svelte
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<input type="checkbox" id="search-modal" class="modal-toggle " />
|
||||
<label for="search-modal" class="modal cursor-pointer w-full items-start pt-16 ">
|
||||
<label class="modal-box w-11/12 max-w-4xl " for="">
|
||||
<div class="form-control">
|
||||
<span
|
||||
class="i-heroicons-outline-search text-base-content pointer-events-none absolute z-10 my-2 ml-3 stroke-current opacity-60 w-5" />
|
||||
</div>
|
||||
<Typeahead placeholder="Search is not avaible …" limit={8} label="Search" inputAfterSelect="clear">
|
||||
<div class="py-1 text-sm" />
|
||||
</Typeahead>
|
||||
<div class="pointer-events-none absolute right-14 top-8 gap-1 opacity-50 hidden lg:flex">
|
||||
<kbd class="kbd kbd-sm">ESC</kbd>
|
||||
</div>
|
||||
</label>
|
||||
</label>
|
||||
<form
|
||||
action={headerConfig?.search?.provider === 'duckduckgo' ? '//duckduckgo.com/' : '//google.com/search'}
|
||||
method="get"
|
||||
class="flex-1">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
class="input input-ghost input-bordered xl:bg-base-100 xl:text-base-content transition-all w-full h-12" />
|
||||
<input
|
||||
type="hidden"
|
||||
name={headerConfig?.search?.provider === 'duckduckgo' ? 'sites' : 'sitesearch'}
|
||||
value={site.protocol + site.domain} />
|
||||
<button type="submit" class="btn btn-square btn-ghost ml-2">
|
||||
<span class="i-heroicons-outline-search" />
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- <script lang="ts">
|
||||
import { onMount, createEventDispatcher } from "svelte"
|
||||
import { page } from "$app/stores"
|
||||
import { goto } from "$app/navigation"
|
||||
import Typeahead from "svelte-typeahead"
|
||||
import { pages } from "@src/lib/data.js"
|
||||
const dispatch = createEventDispatcher()
|
||||
let searchIndex = []
|
||||
pages.forEach((group) => {
|
||||
group.items.forEach((item) => {
|
||||
searchIndex.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
let seachboxEl
|
||||
function handleKeydown(e) {
|
||||
if ((e.keyCode === 75 && e.metaKey) || (e.keyCode === 75 && e.ctrlKey)) {
|
||||
e.preventDefault()
|
||||
seachboxEl.querySelector("input[type=search]").focus()
|
||||
dispatch("focus")
|
||||
}
|
||||
}
|
||||
function onSelect({ detail }) {
|
||||
goto(searchIndex[detail.originalIndex].href)
|
||||
dispatch("search", detail)
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
-->
|
||||
<style global>
|
||||
.searchbox [data-svelte-typeahead] {
|
||||
background: none;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
[data-svelte-search] label {
|
||||
display: none;
|
||||
}
|
||||
[data-svelte-search] input {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
border-radius: 0.5em;
|
||||
padding-left: 2em;
|
||||
}
|
||||
[data-svelte-search] input::placeholder {
|
||||
color: inherit;
|
||||
}
|
||||
[data-svelte-search] input:focus {
|
||||
outline-color: hsla(var(--bc) / 0.2);
|
||||
background-color: hsl(var(--b1));
|
||||
color: hsla(var(--bc));
|
||||
}
|
||||
[data-svelte-typeahead] .svelte-typeahead-list {
|
||||
transform: translateY(0.5em);
|
||||
background: hsl(var(--b1));
|
||||
border-radius: var(--rounded-btn);
|
||||
overflow: hidden;
|
||||
}
|
||||
[data-svelte-typeahead] .svelte-typeahead-list .selected,
|
||||
[data-svelte-typeahead] .svelte-typeahead-list .selected:hover {
|
||||
background: hsl(var(--n));
|
||||
color: hsl(var(--nc));
|
||||
}
|
||||
[data-svelte-typeahead] .svelte-typeahead-list li {
|
||||
color: hsl(var(--bc));
|
||||
}
|
||||
[data-svelte-typeahead] .svelte-typeahead-list li:hover {
|
||||
background: hsl(var(--b2));
|
||||
color: hsl(var(--bc));
|
||||
}
|
||||
[data-svelte-typeahead] .svelte-typeahead-list li:not(:last-of-type) {
|
||||
border-bottom-color: hsla(var(--bc) / 0.1);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<script lang="ts">
|
||||
export let post: Urara.Post
|
||||
const actions = import.meta.glob<{ default: unknown }>('/src/lib/components/actions/*.svelte', { eager: true })
|
||||
const actions = import.meta.glob<any>('/src/lib/components/actions/*.svelte', { eager: true, import: 'default' })
|
||||
</script>
|
||||
|
||||
<div class="sticky top-24 hidden xl:flex flex-col gap-4 w-fit h-[calc(100vh-12rem)] ml-auto mr-8 my-8 justify-center">
|
||||
<div class="sticky top-24 hidden xl:flex flex-col gap-4 w-fit max-h-[calc(100vh-12rem)] ml-auto mr-6 my-8 justify-center">
|
||||
{#if Object.keys(actions).length}
|
||||
{#each Object.values(actions) as action}
|
||||
<svelte:component this={action.default} {post} />
|
||||
<svelte:component this={action} {post} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { browser } from '$app/env'
|
||||
import { browser } from '$app/environment'
|
||||
import { post as postConfig } from '$lib/config/post'
|
||||
import { posts as storedPosts } from '$lib/stores/posts'
|
||||
import { title as storedTitle } from '$lib/stores/title'
|
||||
|
@ -35,11 +35,10 @@
|
|||
itemprop="blogPost"
|
||||
class:md:mb-8={!preview}
|
||||
class:lg:mb-16={!preview}
|
||||
class:h-entry={preview}
|
||||
class:group={preview}
|
||||
class:image-full={preview && post.type === 'article' && post.image}
|
||||
class:before:!rounded-none={preview && post.image}
|
||||
class="card bg-base-100 rounded-none md:rounded-box md:shadow-xl z-10">
|
||||
class="h-entry card bg-base-100 rounded-none md:rounded-box md:shadow-lg md:shadow-grey-10 overflow-hidden z-10">
|
||||
{#if !preview && postConfig.bridgy}
|
||||
<div id="bridgy" class="hidden">
|
||||
{#each post.flags?.some( flag => flag.startsWith('bridgy') ) ? post.flags.flatMap( flag => (flag.startsWith('bridgy') ? flag.slice(7) : []) ) : [...(postConfig.bridgy.post ?? []), ...(postConfig.bridgy[post.type] ?? [])] as target}
|
||||
|
@ -73,9 +72,10 @@
|
|||
<div class="flex flex-col gap-2">
|
||||
{#if post.image && !preview}
|
||||
<figure
|
||||
class={`md:order-last mb-4 ${post.type === 'article' ? 'flex-col gap-2 -mx-4 -mt-8 md:mt-0' : 'flex-col -mx-8'}`}>
|
||||
class={`md:order-last rounded-lg mb-4 ${post.type === 'article' ? 'flex-col gap-2 -mt-8 md:mt-0' : 'flex-col -mx-8'}'
|
||||
}`}>
|
||||
<Image
|
||||
class={`${post.type === 'article' ? 'u-featured rounded-box shadow-xl' : 'u-photo'}`}
|
||||
class={`${post.type === 'article' ? 'u-featured' : 'u-photo'}`}
|
||||
src={post.image}
|
||||
alt={post.image}
|
||||
{loading}
|
||||
|
@ -91,7 +91,7 @@
|
|||
<a itemprop="url" class="u-url p-name" href={post.path}>{post.title ?? post.path.slice(1)}</a>
|
||||
</h2>
|
||||
{:else}
|
||||
<h1 itemprop="name headline" class="card-title text-3xl mb-8 p-name">{post.title ?? post.path.slice(1)}</h1>
|
||||
<h1 itemprop="name headline" class="card-title text-2xl mb-8 p-name">{post.title ?? post.path.slice(1)}</h1>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if post.summary}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { toSnake } from '$lib/utils/case'
|
||||
export let post: Urara.Post
|
||||
export let config: CommentConfig
|
||||
const comments = import.meta.glob<{ default: unknown }>('/src/lib/components/comments/*.svelte', { eager: true })
|
||||
const comments = import.meta.glob<any>('/src/lib/components/comments/*.svelte', { eager: true, import: 'default' })
|
||||
let currentComment: string | undefined = undefined
|
||||
let currentConfig: unknown | undefined = undefined
|
||||
currentComment = localStorage.getItem('comment') ?? toSnake(config.use[0])
|
||||
|
@ -14,8 +14,9 @@
|
|||
{#if config?.use.length > 0}
|
||||
<div id="post-comment" class="card card-body">
|
||||
{#if config.use.length > 1}
|
||||
<div class="tabs w-full mb-8" class:tabs-boxed={config?.['style'] === 'boxed'}>
|
||||
<div class="tabs w-full" class:tabs-boxed={config?.['style'] === 'boxed'}>
|
||||
{#each config.use as name}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<span
|
||||
on:click={() => {
|
||||
currentComment = toSnake(name)
|
||||
|
@ -33,7 +34,7 @@
|
|||
{#if currentComment}
|
||||
{#key currentComment}
|
||||
<svelte:component
|
||||
this={comments[`/src/lib/components/comments/${currentComment}.svelte`].default}
|
||||
this={comments[`/src/lib/components/comments/${currentComment}.svelte`]}
|
||||
{post}
|
||||
config={currentConfig} />
|
||||
{/key}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition'
|
||||
import { browser } from '$app/env'
|
||||
import { browser } from '$app/environment'
|
||||
import Card from '$lib/components/post_card.svelte'
|
||||
import Head from '$lib/components/head.svelte'
|
||||
import Toc from '$lib/components/post_toc.svelte'
|
||||
|
@ -22,7 +22,7 @@
|
|||
<div
|
||||
in:fly={{ x: 25, duration: 300, delay: 500 }}
|
||||
out:fly={{ x: 25, duration: 300 }}
|
||||
class="flex-1 w-full max-w-screen-md order-first ease-out transform mx-auto xl:mr-0">
|
||||
class="flex-1 w-full order-first ease-out transform mx-auto xl:mr-0 xl:ml-0">
|
||||
{#if browser}
|
||||
<Action {post} />
|
||||
{/if}
|
||||
|
@ -30,7 +30,7 @@
|
|||
<div
|
||||
in:fly={{ x: -25, duration: 300, delay: 500 }}
|
||||
out:fly={{ x: -25, duration: 300 }}
|
||||
class="flex-1 w-full max-w-screen-md xl:order-last ease-out transform mx-auto xl:mr-0">
|
||||
class="flex-1 w-full xl:order-last ease-out transform mx-auto xl:ml-0 xl:mr-0">
|
||||
{#if browser && post.toc}
|
||||
<div class="h-full hidden xl:block">
|
||||
<Toc toc={post.toc} />
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
<nav class="flex flex-col md:flex-row flex-warp justify-evenly">
|
||||
{#if prev}
|
||||
<div
|
||||
href={prev.path}
|
||||
class:image-full={prev['image']}
|
||||
class:md:rounded-r-box={next && !next['image']}
|
||||
class="flex-1 card group rounded-none before:!rounded-none">
|
||||
class="flex-1 card group rounded-none before:!rounded-none overflow-hidden">
|
||||
{#if prev['image']}
|
||||
<figure class="!block">
|
||||
<Image
|
||||
|
@ -34,10 +33,9 @@
|
|||
{/if}
|
||||
{#if next}
|
||||
<div
|
||||
href={next.path}
|
||||
class:image-full={next['image']}
|
||||
class:md:rounded-l-box={prev && !prev['image']}
|
||||
class="flex-1 card group rounded-none before:!rounded-none">
|
||||
class="flex-1 card group rounded-none before:!rounded-none overflow-hidden">
|
||||
{#if next['image']}
|
||||
<figure class="!block">
|
||||
<Image
|
||||
|
|
|
@ -6,25 +6,12 @@
|
|||
|
||||
<div class="flex flex-wrap gap-2 rounded-box outline outline-neutral/10 p-4 {className}">
|
||||
<span class="flex-none font-bold uppercase opacity-30">Reply to: </span>
|
||||
{#if Array.isArray(in_reply_to)}
|
||||
{#each in_reply_to as reply}
|
||||
<a
|
||||
href={reply}
|
||||
rel="noopener external"
|
||||
target="_blank"
|
||||
class="flex-none flex rounded-badge bg-base-200 hover:bg-base-300 transition-all gap-2 px-4 u-in-reply-to">
|
||||
<span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
|
||||
{reply}
|
||||
</a>
|
||||
{/each}
|
||||
{:else}
|
||||
<a
|
||||
href={in_reply_to}
|
||||
rel="noopener external"
|
||||
rel="noopener noreferrer external"
|
||||
target="_blank"
|
||||
class="ml-auto flex-none flex rounded-badge bg-base-200 hover:bg-base-300 transition-all gap-2 px-4 u-in-reply-to">
|
||||
<span class="i-heroicons-outline-reply my-auto !w-4 !h-4" />
|
||||
{in_reply_to}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
{site.author.name}
|
||||
</a>
|
||||
<span class:hidden={preview} class="opacity-50">/</span>
|
||||
<a href={post.path} class="swap hover:swap-active u-url u-uid">
|
||||
<a href={post.path} class="u-url u-uid swap group/time">
|
||||
<time
|
||||
class="swap-off font-semibold opacity-75 duration-500 ease-in-out mr-auto dt-published"
|
||||
class="group-hover/time:opacity-0 font-semibold opacity-75 duration-500 ease-in-out mr-auto dt-published"
|
||||
datetime={jsonPublished}
|
||||
itemprop="datePublished">
|
||||
{stringPublished}
|
||||
</time>
|
||||
<time
|
||||
class="swap-on font-semibold text-primary duration-500 ease-in-out mr-auto dt-updated"
|
||||
class="opacity-0 group-hover/time:opacity-100 font-semibold text-primary duration-500 ease-in-out mr-auto dt-updated"
|
||||
datetime={jsonUpdated}
|
||||
itemprop="dateModified">
|
||||
{stringUpdated}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
import Tree from '$lib/components/post_toc_tree.svelte'
|
||||
export let toc: Urara.Post.Toc[]
|
||||
|
||||
let intersecting: string[] = []
|
||||
|
@ -34,7 +33,7 @@
|
|||
// @ts-ignore: Cannot find name 'headingsObserver'
|
||||
if (typeof headingsObserver !== 'undefined') headingsObserver.disconnect()
|
||||
// @ts-ignore: Cannot find name 'articleObserver'
|
||||
if (typeof headingsObserver !== 'undefined') articleObserver.disconnect()
|
||||
if (typeof articleObserver !== 'undefined') articleObserver.disconnect()
|
||||
})
|
||||
|
||||
$: if (intersecting.length > 0) bordered = intersecting
|
||||
|
@ -53,16 +52,29 @@
|
|||
aria-label="TableOfContent"
|
||||
dir="rtl"
|
||||
class="max-h-[calc(100vh-12rem)] overflow-y-hidden hover:overflow-y-auto">
|
||||
<Tree
|
||||
toc={toc.reduce(
|
||||
(acc, heading) => {
|
||||
let parent = acc
|
||||
// @ts-ignore Type 'Toc | undefined' is not assignable to type 'Toc.' ts(2322)
|
||||
while (parent.depth + 1 < heading.depth) parent = parent.children.at(-1)
|
||||
parent.children = [...(parent.children ?? []), { ...heading, children: [] }]
|
||||
return acc
|
||||
},
|
||||
{ depth: toc[0].depth - 1, children: [] }
|
||||
)} />
|
||||
<ul dir="ltr" id="toc-list-root">
|
||||
{#each toc as { depth, title, slug }}
|
||||
<li id={`toc-item-${slug}`} class="flex flex-col">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<span
|
||||
dir="ltr"
|
||||
on:click={() =>
|
||||
// @ts-ignore Object is possibly 'null'. ts(2531)
|
||||
document.getElementById(slug).scrollIntoView({ behavior: 'smooth' })}
|
||||
id={`toc-link-${slug}`}
|
||||
class="cursor-pointer border-l-4 border-transparent transition-all hover:border-primary hover:bg-base-content hover:bg-opacity-10 active:bg-primary active:text-primary-content active:font-bold pr-4 {depth <=
|
||||
2
|
||||
? 'py-3'
|
||||
: 'py-2'}"
|
||||
class:pl-4={depth <= 2}
|
||||
class:pl-8={depth === 3}
|
||||
class:pl-12={depth === 4}
|
||||
class:pl-16={depth === 5}
|
||||
class:pl-20={depth === 6}>
|
||||
{title}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
|
|
|
@ -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}
|
|
@ -1,10 +1,37 @@
|
|||
<script lang="ts">
|
||||
/* @see {@link https://github.com/sveltejs/kit/issues/241#issuecomment-1363621896} */
|
||||
|
||||
type Image = {
|
||||
src: string
|
||||
w: number
|
||||
h: number
|
||||
}
|
||||
|
||||
const sources = import.meta.glob<Image[]>(['/src/static/**/*.{jpg,jpeg,png,webp,avif}', '!/src/static/assets'], {
|
||||
query: {
|
||||
format: 'avif',
|
||||
quality: '80',
|
||||
width: '736',
|
||||
source: ''
|
||||
},
|
||||
import: 'default',
|
||||
eager: true
|
||||
})
|
||||
|
||||
let className: string | undefined = undefined
|
||||
export { className as class }
|
||||
export let src: string
|
||||
export let alt: string = src
|
||||
export let loading: 'eager' | 'lazy' = 'lazy'
|
||||
export let decoding: 'async' | 'sync' | 'auto' = 'async'
|
||||
let source: Image[] | undefined = sources[`/src/static${src}`]
|
||||
</script>
|
||||
|
||||
{#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}
|
||||
|
|
13
src/lib/components/transition.svelte
Normal 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}
|
|
@ -57,14 +57,14 @@ export const friends: Friend[] = [
|
|||
rel: 'friend',
|
||||
name: '夏诤',
|
||||
title: 'SummberBlue',
|
||||
link: 'https://summerblue.space/',
|
||||
link: 'https://blog.summerrrrrr.blue',
|
||||
descr: '早睡早起身体好'
|
||||
},
|
||||
{
|
||||
id: 'loikin',
|
||||
rel: 'friend',
|
||||
name: 'Loikin',
|
||||
title: '此生未命名',
|
||||
title: '浣心',
|
||||
link: 'https://blog.loikein.one/',
|
||||
descr: '用爱和理性对抗荒谬',
|
||||
avatar: '/assets/loikin.png'
|
||||
|
@ -74,8 +74,42 @@ export const friends: Friend[] = [
|
|||
rel: 'friend',
|
||||
name: '鲨',
|
||||
title: '一只脆脆鲨',
|
||||
link: 'http://blog.sharktale.xyz/',
|
||||
link: 'https://woods.sharktale.xyz/',
|
||||
descr: '遇见一只脆脆鲨',
|
||||
avatar: 'https://s2.loli.net/2022/03/30/xwOzn9G8TIqFPvR.jpg'
|
||||
},
|
||||
{
|
||||
id: 'kwaa',
|
||||
rel: 'friend',
|
||||
name: '藍 +85CD',
|
||||
title: './kwaa.dev',
|
||||
link: 'https://kwaa.dev',
|
||||
descr: '[DATA EXPUNGED]',
|
||||
avatar: 'https://kwaa.dev/assets/any@512.webp'
|
||||
},
|
||||
{
|
||||
id: 'debula',
|
||||
rel: 'friend',
|
||||
title: '秘密花园',
|
||||
name: '本宝宝',
|
||||
link: 'https://blog.debula.ml',
|
||||
descr: '月亮一直跟着我走,它迷路了吗?',
|
||||
avatar: 'https://blog.debula.ml/usr/uploads/violet.jpg'
|
||||
},
|
||||
{
|
||||
id: 'zhuzi',
|
||||
rel: 'friend',
|
||||
title: 'Bambooom',
|
||||
name: '竹子',
|
||||
link: 'https://zhuzi.dev',
|
||||
descr: 'Blah Blah Booooom'
|
||||
},
|
||||
{
|
||||
id: 'litomore',
|
||||
rel: 'friend',
|
||||
title: "LitoMore's Mind",
|
||||
name: 'LitoMore',
|
||||
link: 'https://litomore.me',
|
||||
avatar: 'https://litomore.me/favicon.svg'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,121 +1,61 @@
|
|||
import type { ThemeConfig, HeadConfig, HeaderConfig, FooterConfig, DateConfig, FeedConfig } from '$lib/types/general'
|
||||
|
||||
export const theme: ThemeConfig = [
|
||||
{
|
||||
name: 'lemonade',
|
||||
text: 'Light'
|
||||
},
|
||||
{
|
||||
name: 'night',
|
||||
text: 'Dark'
|
||||
},
|
||||
{
|
||||
name: 'cupcake',
|
||||
text: 'Cupcake'
|
||||
},
|
||||
{
|
||||
name: 'bumblebee',
|
||||
text: 'Bumblebee'
|
||||
},
|
||||
{
|
||||
name: 'emerald',
|
||||
text: 'Emerald'
|
||||
},
|
||||
{
|
||||
name: 'corporate',
|
||||
text: 'Corporate'
|
||||
},
|
||||
{
|
||||
name: 'valentine',
|
||||
text: 'Valentine'
|
||||
},
|
||||
{
|
||||
name: 'synthwave',
|
||||
text: 'Synthwave'
|
||||
},
|
||||
{
|
||||
name: 'retro',
|
||||
text: 'Retro'
|
||||
},
|
||||
{
|
||||
name: 'cyberpunk',
|
||||
text: 'Cyberpunk'
|
||||
},
|
||||
{
|
||||
name: 'halloween',
|
||||
text: 'Halloween'
|
||||
},
|
||||
{
|
||||
name: 'garden',
|
||||
text: 'Garden'
|
||||
},
|
||||
{
|
||||
name: 'forest',
|
||||
text: 'Forest'
|
||||
},
|
||||
{
|
||||
name: 'aqua',
|
||||
text: 'Aqua'
|
||||
},
|
||||
{
|
||||
name: 'lofi',
|
||||
text: 'Lo-Fi'
|
||||
},
|
||||
{
|
||||
name: 'pastel',
|
||||
text: 'Pastel'
|
||||
},
|
||||
{
|
||||
name: 'fantasy',
|
||||
text: 'Fantasy'
|
||||
},
|
||||
{
|
||||
name: 'wirefream',
|
||||
text: 'Wireframe'
|
||||
},
|
||||
{
|
||||
name: 'black',
|
||||
text: 'Black'
|
||||
},
|
||||
{
|
||||
name: 'luxury',
|
||||
text: 'Luxury'
|
||||
text: 'Light'
|
||||
},
|
||||
{
|
||||
name: 'dracula',
|
||||
text: 'Dracula'
|
||||
},
|
||||
{
|
||||
name: 'cmyk',
|
||||
text: 'CMYK'
|
||||
},
|
||||
{
|
||||
name: 'autumn',
|
||||
text: 'Autumn'
|
||||
},
|
||||
{
|
||||
name: 'business',
|
||||
text: 'Business'
|
||||
},
|
||||
{
|
||||
name: 'acid',
|
||||
text: 'Acid'
|
||||
},
|
||||
// {
|
||||
// name: 'lemonade',
|
||||
// text: 'Lemonade'
|
||||
// },
|
||||
// {
|
||||
// name: 'night',
|
||||
// text: '🌃 Night'
|
||||
// },
|
||||
{
|
||||
name: 'coffee',
|
||||
text: 'Coffee'
|
||||
},
|
||||
{
|
||||
name: 'winter',
|
||||
text: 'Winter'
|
||||
name: 'cupcake',
|
||||
text: 'Cupcake'
|
||||
},
|
||||
{
|
||||
name: 'valentine',
|
||||
text: 'Valentine'
|
||||
},
|
||||
{
|
||||
name: 'aqua',
|
||||
text: 'Aqua'
|
||||
},
|
||||
{
|
||||
name: 'synthwave',
|
||||
text: 'Synthwave'
|
||||
},
|
||||
{
|
||||
name: 'night',
|
||||
text: 'Night'
|
||||
},
|
||||
// {
|
||||
// name: 'lofi',
|
||||
// text: 'Lo-Fi'
|
||||
// },
|
||||
{
|
||||
name: 'garden',
|
||||
text: 'Garden'
|
||||
},
|
||||
{
|
||||
name: 'lemonade',
|
||||
text: 'Lemonade'
|
||||
},
|
||||
{
|
||||
name: 'cmyk',
|
||||
text: 'CMYK'
|
||||
},
|
||||
{
|
||||
name: 'retro',
|
||||
text: 'Retro'
|
||||
},
|
||||
{
|
||||
name: 'black',
|
||||
text: 'Black'
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -160,12 +100,20 @@ export const header: HeaderConfig = {
|
|||
{
|
||||
text: 'About',
|
||||
link: '/about'
|
||||
},
|
||||
{
|
||||
text: 'etc',
|
||||
children: [
|
||||
{
|
||||
text: 'Bookmarks',
|
||||
link: 'https://airtable.com/shrpftxf6JgRomP2X'
|
||||
},
|
||||
{
|
||||
text: 'Daily Notes',
|
||||
link: 'https://x.seviche.cc'
|
||||
}
|
||||
]
|
||||
}
|
||||
// ,
|
||||
// {
|
||||
// text: 'Notes',
|
||||
// link: '/notes'
|
||||
// }
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -180,30 +128,11 @@ export const footer: FooterConfig = {
|
|||
link: '/privacy'
|
||||
}
|
||||
],
|
||||
html: '<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>'
|
||||
html: '<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>',
|
||||
since: '2021'
|
||||
}
|
||||
|
||||
export const date: DateConfig = {
|
||||
// toPublishedString: {
|
||||
// locales: 'en-US',
|
||||
// options: {
|
||||
// year: 'numeric',
|
||||
// weekday: 'short',
|
||||
// month: 'short',
|
||||
// day: 'numeric',
|
||||
// timeZone: 'Asia/Shanghai'
|
||||
// }
|
||||
// },
|
||||
// toUpdatedString: {
|
||||
// locales: 'en-US',
|
||||
// options: {
|
||||
// year: 'numeric',
|
||||
// weekday: 'short',
|
||||
// month: 'short',
|
||||
// day: 'numeric',
|
||||
// timeZone: 'Asia/Shanghai'
|
||||
// }
|
||||
// },
|
||||
locales: 'en-US',
|
||||
options: {
|
||||
year: 'numeric',
|
||||
|
|
|
@ -5,14 +5,14 @@ export const post: PostConfig = {
|
|||
post: ['mastodon']
|
||||
},
|
||||
comment: {
|
||||
use: ['Webmention', 'Giscus'],
|
||||
use: ['Remark42','Webmention', 'Giscus'],
|
||||
style: 'boxed',
|
||||
webmention: {
|
||||
username: 'seviche.cc',
|
||||
username: 'sevic.me',
|
||||
sortBy: 'created',
|
||||
sortDir: 'down',
|
||||
form: true,
|
||||
commentParade: true
|
||||
commentParade: false
|
||||
},
|
||||
giscus: {
|
||||
// src: 'https://giscus.kwaa.dev/client.js',
|
||||
|
@ -22,16 +22,10 @@ export const post: PostConfig = {
|
|||
categoryID: 'DIC_kwDOHSra4c4CO9ua',
|
||||
theme: 'light',
|
||||
lang: 'en'
|
||||
}
|
||||
// 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']
|
||||
// }
|
||||
},
|
||||
remark42: {
|
||||
host: 'https://remark42.seviche.cc',
|
||||
no_footer: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,53 @@ export const projects: Project[] = [
|
|||
// img: 'https://usc1.contabostorage.com/cc0b816231a841b1b0232d5ef0c6deb1:image/2022/06/d4d2489936e4f647c25df6982c6ef924.png',
|
||||
// link: 'https://haibian.seviche.cc'
|
||||
// },
|
||||
{
|
||||
id: 'Raycast-NeoDB',
|
||||
name: 'Raycast - NeoDB',
|
||||
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
|
||||
description: 'Search NeoDB items and view item details',
|
||||
feature: 'React',
|
||||
img: 'https://github.com/raycast/extensions/raw/f7cf284a8c14e38aee758adb00120de827a144fb/extensions/neodb//metadata/neodb-1.png',
|
||||
link: 'https://www.raycast.com/SevicheCC/neodb'
|
||||
},
|
||||
{
|
||||
id: 'Raycast-Mastodon',
|
||||
name: 'Raycast - Mastodon',
|
||||
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
|
||||
description: 'Publish status from Raycast to Mastodon, and view your bookmarked status',
|
||||
feature: 'React',
|
||||
img: 'https://github.com/raycast/extensions/raw/1824339d4b3b404efb53e4fb09ac79d190437773/extensions/mastodon//media/command.png',
|
||||
link: 'https://www.raycast.com/SevicheCC/mastodon'
|
||||
},
|
||||
|
||||
{
|
||||
id: 'Raycast-miniflux',
|
||||
name: 'Raycast - Miniflux',
|
||||
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
|
||||
description: 'Search RSS entries from Raycast, and more features',
|
||||
feature: 'React',
|
||||
img: 'https://github.com/raycast/extensions/raw/3fdad375dd06b7f390b629235c6a10c37d05fc79/extensions/miniflux//media/commands.png',
|
||||
link: 'https://www.raycast.com/SevicheCC/miniflux'
|
||||
},
|
||||
{
|
||||
id: 'Raycast-Akkoma',
|
||||
name: 'Raycast - Akkoma',
|
||||
tags: ['React', 'React Hooks', 'Fediverse', 'TypeScript'],
|
||||
description: 'Publish status from Raycast to Akkoma or Pleroma, and view your bookmarked status',
|
||||
feature: 'React',
|
||||
img: 'https://github.com/raycast/extensions/raw/42e765bc6bf970054fd69abfdc6ab3dd2ea4942d/extensions/akkoma//media/command.png',
|
||||
link: 'https://www.raycast.com/SevicheCC/akkoma'
|
||||
},
|
||||
{
|
||||
id: 'miniflux-injector',
|
||||
name: 'Miniflux-injector',
|
||||
tags: ['Svelte', 'Browser Extension', 'Miniflux', 'RSS'],
|
||||
description:
|
||||
"Browser extension for the self-hosted miniflux bookmark service. Fork from <a href='https://github.com/Fivefold/linkding-injector' target='_blank'>linkding-injector</a>",
|
||||
feature: 'Svelte',
|
||||
img: 'https://usc1.contabostorage.com/cc0b816231a841b1b0232d5ef0c6deb1:image/2022/12/7ae29e6a539895491fbb88a28c95aed7.png',
|
||||
link: 'https://github.com/Sevichecc/miniflux-injector'
|
||||
},
|
||||
{
|
||||
id: 'fokify',
|
||||
name: 'Fokify ',
|
||||
|
|
|
@ -1,36 +1,32 @@
|
|||
import type { SiteConfig } from '$lib/types/site'
|
||||
|
||||
export const site: SiteConfig = {
|
||||
protocol: 'https://',
|
||||
domain: 'seviche.cc',
|
||||
title: 'Seviche.cc',
|
||||
subtitle: 'Tech / Code / Random Life',
|
||||
protocol: import.meta.env.URARA_SITE_PROTOCOL ?? import.meta.env.DEV ? 'http://' : 'https://',
|
||||
domain: 'sevic.me',
|
||||
title: 'sevic.me',
|
||||
subtitle: 'Random Frontend-Developer',
|
||||
lang: 'zh',
|
||||
description: 'Tech / Code / Random Life',
|
||||
description: 'Random Frontend-Developer',
|
||||
author: {
|
||||
name: '酸橘汁腌鱼',
|
||||
avatar: '/assets/avatar.jpg',
|
||||
name: 'Sevi.C',
|
||||
avatar: '/assets/avatar.png',
|
||||
status: '🖤',
|
||||
bio: ' Code / Tech <br> Living a Random Life ',
|
||||
bio: 'Full-stack wizard.',
|
||||
metadata: [
|
||||
{
|
||||
text: '',
|
||||
icon: 'i-mdi-github',
|
||||
link: 'https://github.com/sevichecc'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
icon: 'i-simple-icons-matrix',
|
||||
link: 'https://matrix.to/#/@seviche:kongwoo.icu'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
icon: 'i-heroicons-solid-key',
|
||||
link: 'https://keys.openpgp.org/vks/v1/by-fingerprint/76DF9F9CC0C3619AA12CB914AFF18B986818D8AD',
|
||||
link: '/assets/DDDDDDDD.asc',
|
||||
rel: 'pgpkey'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
icon: 'i-ic-twotone-rss-feed',
|
||||
link: '/atom.xml',
|
||||
rel: 'rss'
|
||||
|
@ -44,6 +40,6 @@ export const site: SiteConfig = {
|
|||
// }
|
||||
]
|
||||
},
|
||||
keywords: ['Tech', 'Code', 'Random Life'],
|
||||
keywords: ['Tech', 'Code', 'Seviche CC', 'Frondend Developer', 'Programming'],
|
||||
themeColor: '#3D4451'
|
||||
}
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
import type { WalineEmojiInfo } from '@waline/client'
|
||||
type WalineImageUploader = (image: File) => Promise<string>
|
||||
|
||||
type WalineHighlighter = (code: string, lang: string) => string
|
||||
|
||||
type WalineTexRenderer = (blockMode: boolean, tex: string) => string
|
||||
|
||||
export type PostConfig = {
|
||||
bridgy?: {
|
||||
[kind: string]: ('fed' | 'mastodon' | 'flickr' | 'github' | 'twitter')[]
|
||||
|
@ -22,8 +15,7 @@ export type CommentConfig = {
|
|||
giscus?: GiscusConfig
|
||||
/** Utterances config, more at https://utteranc.es */
|
||||
utterances?: UtterancesConfig
|
||||
/** Waline config, more at https://waline.js.org/en/reference/component.html#texrenderer */
|
||||
waline?: WalineConfig
|
||||
remark42?: Remark42Config
|
||||
}
|
||||
|
||||
export type WebmentionConfig = {
|
||||
|
@ -81,39 +73,35 @@ export type UtterancesConfig = {
|
|||
theme?: string
|
||||
}
|
||||
|
||||
export type DisqusConfig = {
|
||||
shortname: string
|
||||
lang?: string
|
||||
}
|
||||
|
||||
// Ref:https://waline.js.org/reference/component.html
|
||||
export type WalineConfig = {
|
||||
/** Waline server address url */
|
||||
serverURL: string
|
||||
/** Article path id*/
|
||||
path?: string
|
||||
/** Display language. */
|
||||
lang?: string
|
||||
/** Emoji settings, for details see https://waline.js.org/en/guide/client/emoji.html */
|
||||
emoji?: (string | WalineEmojiInfo)[] | false
|
||||
/** Darkmode support */
|
||||
dark?: string | boolean
|
||||
/** Reviewer attributes. Optional values: 'nick', 'mail', 'link' */
|
||||
meta?: string[]
|
||||
/** Set required fields*/
|
||||
requiredMeta?: string[]
|
||||
/** login mode status */
|
||||
login?: string
|
||||
/** Comment word s limit. */
|
||||
wordLimit?: number | [number, number]
|
||||
/**number of comments per page. */
|
||||
pageSize?: number
|
||||
/** Custom image upload method. */
|
||||
imageUploader?: WalineImageUploader | false
|
||||
/** Code highlighting, use hanabi by default */
|
||||
highlighter?: WalineHighlighter | false
|
||||
/** Customize \TeX rendering */
|
||||
texRender?: WalineTexRenderer | false
|
||||
/** Whether show copyright and version in footer. */
|
||||
copyright?: boolean
|
||||
export type Remark42Config = {
|
||||
/** hostname of Remark42 server, same as REMARK_URL in backend config, e.g. "https://demo.remark42.com" */
|
||||
host: string
|
||||
/** the SITE that you passed to Remark42 instance on start of backend. (default: remark) */
|
||||
site_id?: string
|
||||
/** url to the page with comments*/
|
||||
url?: string
|
||||
/** an array of widgets that should be rendered on a page (default: ['embed'] )*/
|
||||
components?: ['embed' | 'last-comments' | 'counter']
|
||||
/** maximum number of comments that is rendered on mobile version (default: 15 )*/
|
||||
max_shown_comments?: number
|
||||
/** maximum number of comments in the last comments widget (default: 15 )*/
|
||||
max_last_comments?: number
|
||||
/** changes UI theme, (default: light )*/
|
||||
theme?: 'light' | 'dark'
|
||||
/** title for current comments page (default: document.title)*/
|
||||
page_title?: string
|
||||
/**
|
||||
* interface localization,
|
||||
* English (en), Belarusian (be), Brazilian Portuguese (bp), Bulgarian (bg), Chinese (zh), Finnish (fi), French (fr), German (de), Japanese (ja), Korean (ko), Polish (pl), Russian (ru), Spanish (es), Turkish (tr), Ukrainian (ua), Italian (it) and Vietnamese (vi)
|
||||
* default: en
|
||||
*/
|
||||
locale?: 'en' | 'be' | 'bp' | 'bg' | 'zh' | 'fi' | 'fr' | 'de' | 'ja' | 'ko' | 'pl' | 'ru' | 'es' | 'tr' | 'ua' | 'it' | 'vi'
|
||||
/** enables email subscription (default: true) */
|
||||
show_email_subscription?: boolean
|
||||
/** enables RSS subscription, (default: true) */
|
||||
show_rss_subscription?: boolean
|
||||
/** minimized UI with basic info only, (default: false) */
|
||||
simple_view?: boolean
|
||||
/** hides footer with signature and links to Remark42,(default: false) */
|
||||
no_footer?: boolean
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import type { FFFAuthor } from 'fff-flavored-frontmatter'
|
||||
|
||||
export type SiteConfig = {
|
||||
/** @deprecated - use `description` instead */
|
||||
descr?: string
|
||||
/** site protocol. for example: `https://` */
|
||||
protocol: string
|
||||
/** site domain. for example: `example.com` */
|
||||
|
|
40
src/routes/+layout.svelte
Normal file
|
@ -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
|
@ -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())
|
||||
})
|
|
@ -2,15 +2,14 @@
|
|||
import { onMount } from 'svelte'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { page } from '$app/stores'
|
||||
import { browser } from '$app/env'
|
||||
import { browser } from '$app/environment'
|
||||
import { goto } from '$app/navigation'
|
||||
import { posts as storedPosts, tags as storedTags } from '$lib/stores/posts'
|
||||
import { title as storedTitle } from '$lib/stores/title'
|
||||
import Head from '$lib/components/head.svelte'
|
||||
import Footer from '$lib/components/footer.svelte'
|
||||
import Post from '$lib/components/post_card.svelte'
|
||||
// import Post from '$lib/components/index_post.svelte'
|
||||
import Profile from '$lib/components/index_profile.svelte'
|
||||
import RemoteFollow from '$lib/components/extra/follow.svelte'
|
||||
|
||||
let allPosts: Urara.Post[]
|
||||
let allTags: string[]
|
||||
|
@ -19,9 +18,7 @@
|
|||
|
||||
storedTitle.set('')
|
||||
|
||||
$: storedPosts.subscribe(
|
||||
storedPosts => (allPosts = (storedPosts as Urara.Post[]).filter(post => !post.flags?.includes('unlisted')))
|
||||
)
|
||||
$: storedPosts.subscribe(storedPosts => (allPosts = storedPosts.filter(post => !post.flags?.includes('unlisted'))))
|
||||
|
||||
$: storedTags.subscribe(storedTags => (allTags = storedTags as string[]))
|
||||
|
||||
|
@ -30,7 +27,7 @@
|
|||
$: if (tags) {
|
||||
posts = !tags ? allPosts : allPosts.filter(post => tags.every(tag => post.tags?.includes(tag)))
|
||||
if (browser && window.location.pathname === '/')
|
||||
window.history.replaceState({}, '', tags.length > 0 ? `?tags=${tags.toString()}` : `/`)
|
||||
goto(tags.length > 0 ? `?tags=${tags.toString()}` : `/`, { replaceState: true })
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
@ -125,5 +122,3 @@
|
|||
{/key}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RemoteFollow />
|
|
@ -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>
|
|
@ -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}
|
|
@ -1,12 +1,11 @@
|
|||
import type { RequestHandler } from '@sveltejs/kit'
|
||||
import type { RequestHandler } from './$types'
|
||||
import { site } from '$lib/config/site'
|
||||
import { feed } from '$lib/config/general'
|
||||
import { favicon } from '$lib/config/icon'
|
||||
import { genPosts, genTags } from '$lib/utils/posts'
|
||||
|
||||
const render = async (
|
||||
posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })
|
||||
): Promise<string> => `<?xml version='1.0' encoding='utf-8'?>
|
||||
const render = (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })): string =>
|
||||
`<?xml version='1.0' encoding='utf-8'?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>${site.protocol + site.domain}/</id>
|
||||
<title><![CDATA[${site.title}]]></title>${site.subtitle ? `\n <subtitle><![CDATA[${site.subtitle}]]></subtitle>` : ''}${
|
||||
|
@ -39,11 +38,13 @@ const render = async (
|
|||
</entry>`
|
||||
)
|
||||
.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: {
|
||||
'Content-Type': 'application/atom+xml; charset=utf-8'
|
||||
},
|
||||
body: await render()
|
||||
'content-type': 'application/atom+xml; charset=utf-8'
|
||||
}
|
||||
})
|
|
@ -1,10 +1,11 @@
|
|||
import type { RequestHandler } from '@sveltejs/kit'
|
||||
import type { RequestHandler } from './$types'
|
||||
import { json } from '@sveltejs/kit'
|
||||
import { site } from '$lib/config/site'
|
||||
import { feed } from '$lib/config/general'
|
||||
import { favicon, any } from '$lib/config/icon'
|
||||
import { genPosts } from '$lib/utils/posts'
|
||||
|
||||
const render = async (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })) => ({
|
||||
const render = (posts = genPosts({ postHtml: true, postLimit: feed.limit, filterUnlisted: true })) => ({
|
||||
version: 'https://jsonfeed.org/version/1.1',
|
||||
title: site.title,
|
||||
home_page_url: site.protocol + site.domain,
|
||||
|
@ -41,9 +42,11 @@ const render = async (posts = genPosts({ postHtml: true, postLimit: feed.limit,
|
|||
}))
|
||||
})
|
||||
|
||||
export const GET: RequestHandler = async () => ({
|
||||
export const prerender = true
|
||||
export const trailingSlash = 'never'
|
||||
export const GET: RequestHandler = async () =>
|
||||
json(render(), {
|
||||
headers: {
|
||||
'Content-Type': 'application/feed+json; charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(await render(), null, 2)
|
||||
'content-type': 'application/feed+json; charset=utf-8'
|
||||
}
|
||||
})
|
|
@ -1,9 +1,10 @@
|
|||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import Masonry from 'svelte-bricks'
|
||||
import type { Friend } from '$lib/config/friends'
|
||||
import { friends as allFriends } from '$lib/config/friends'
|
||||
import { title as storedTitle } from '$lib/stores/title'
|
||||
import Head from '$lib/components/head.svelte'
|
||||
import Masonry from 'svelte-bricks'
|
||||
import FriendComponent from '$lib/components/extra/friend.svelte'
|
||||
|
||||
const rnd = Math.random()
|
||||
|
@ -16,7 +17,7 @@
|
|||
storedTitle.set('')
|
||||
</script>
|
||||
|
||||
<Head />
|
||||
<Head page={{ title: 'Friends', path: '/friends' }} />
|
||||
|
||||
<Masonry
|
||||
{items}
|
|
@ -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
|
||||
)
|
||||
})
|
37
src/routes/manifest.webmanifest/+server.ts
Normal 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'
|
||||
}
|
||||
}
|
||||
)
|
|
@ -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)
|
||||
})
|
7
src/routes/posts.json/+server.ts
Normal 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())
|
|
@ -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()
|
||||
})
|
36
src/routes/sitemap.xml/+server.ts
Normal 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'
|
||||
}
|
||||
})
|
|
@ -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)
|
||||
})
|
7
src/routes/tags.json/+server.ts
Normal 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()))
|
|
@ -1,29 +1,35 @@
|
|||
// sveltekit config type
|
||||
import type { Config } from '@sveltejs/kit'
|
||||
// svelte preprocess
|
||||
import preprocess from 'svelte-preprocess'
|
||||
import adapterAuto from '@sveltejs/adapter-auto'
|
||||
import adapterNode from '@sveltejs/adapter-node'
|
||||
// svelte adapter
|
||||
import adapterVercel from '@sveltejs/adapter-vercel'
|
||||
import adapterNetlify from '@sveltejs/adapter-netlify'
|
||||
import adapterStatic from '@sveltejs/adapter-static'
|
||||
// svelte preprocessor
|
||||
import { mdsvex } from 'mdsvex'
|
||||
import mdsvexConfig from './mdsvex.config.js'
|
||||
import { vitePreprocess } from '@sveltejs/kit/vite'
|
||||
|
||||
const defineConfig = (config: Config) => config
|
||||
|
||||
export default defineConfig({
|
||||
export default {
|
||||
extensions: ['.svelte', ...(mdsvexConfig.extensions as string[])],
|
||||
preprocess: [mdsvex(mdsvexConfig), preprocess()],
|
||||
preprocess: [mdsvex(mdsvexConfig), vitePreprocess()],
|
||||
kit: {
|
||||
adapter: Object.keys(process.env).some(key => ['VERCEL', 'CF_PAGES', 'NETLIFY'].includes(key))
|
||||
? adapterAuto()
|
||||
: process.env.ADAPTER === 'node'
|
||||
? adapterNode({ out: 'build' })
|
||||
adapter: Object.keys(process.env).some(key => key === 'VERCEL')
|
||||
? adapterVercel()
|
||||
: Object.keys(process.env).some(key => key === 'NETLIFY')
|
||||
? adapterNetlify()
|
||||
: adapterStatic({
|
||||
pages: 'build',
|
||||
assets: 'build',
|
||||
fallback: undefined
|
||||
}),
|
||||
csp: { mode: 'auto' },
|
||||
prerender: { default: true }
|
||||
prerender: {
|
||||
handleMissingId: 'warn'
|
||||
},
|
||||
csp: {
|
||||
mode: 'auto',
|
||||
directives: {
|
||||
'style-src': ['self', 'unsafe-inline', 'https://giscus.app']
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} as Config
|
||||
|
|
|
@ -1,63 +1,12 @@
|
|||
// tailwind config type
|
||||
import type { TailwindConfig } from 'tailwindcss/tailwind-config'
|
||||
// @ts-ignore TS2305: Module 'tailwindcss/plugin' has no exported member 'TailwindPluginWithoutOptions'.
|
||||
import type { TailwindPluginWithoutOptions } from 'tailwindcss/plugin'
|
||||
// tailwind plugins
|
||||
import { theme } from './src/lib/config/general'
|
||||
// @ts-ignore Could not find a declaration file for module '@tailwindcss/typography'.
|
||||
import typography from '@tailwindcss/typography'
|
||||
// @ts-ignore Could not find a declaration file for module 'daisyui'.
|
||||
import daisyui from 'daisyui'
|
||||
|
||||
interface Config extends TailwindConfig {
|
||||
daisyui?: {
|
||||
styled?: boolean
|
||||
themes?: boolean | string[]
|
||||
base?: boolean
|
||||
utils?: boolean
|
||||
logs?: boolean
|
||||
rtl?: boolean
|
||||
darkTheme?: string
|
||||
prefix?: string
|
||||
}
|
||||
}
|
||||
|
||||
const defineConfig = (config: Config) => config
|
||||
|
||||
export default defineConfig({
|
||||
export default {
|
||||
content: ['./src/**/*.{html,md,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
plugins: [typography as TailwindPluginWithoutOptions, daisyui as TailwindPluginWithoutOptions],
|
||||
daisyui: {
|
||||
themes: [
|
||||
'light',
|
||||
'dark',
|
||||
'cupcake',
|
||||
'bumblebee',
|
||||
'emerald',
|
||||
'corporate',
|
||||
'synthwave',
|
||||
'retro',
|
||||
'cyberpunk',
|
||||
'valentine',
|
||||
'halloween',
|
||||
'garden',
|
||||
'forest',
|
||||
'aqua',
|
||||
'lofi',
|
||||
'pastel',
|
||||
'fantasy',
|
||||
'wireframe',
|
||||
'black',
|
||||
'luxury',
|
||||
'dracula',
|
||||
'cmyk',
|
||||
'autumn',
|
||||
'business',
|
||||
'acid',
|
||||
'lemonade',
|
||||
'night',
|
||||
'coffee',
|
||||
'winter'
|
||||
]
|
||||
theme: { extend: {} },
|
||||
plugins: [typography, daisyui],
|
||||
daisyui: { themes: theme.map(({ name }) => name) }
|
||||
}
|
||||
})
|
||||
|
|
4
urara.ts
|
@ -9,7 +9,7 @@ import chokidar from 'chokidar'
|
|||
import chalk from 'chalk'
|
||||
|
||||
const config = {
|
||||
extensions: ['svelte', 'md', 'js', 'ts'],
|
||||
extensions: ['md'],
|
||||
catch: ['ENOENT', 'EEXIST']
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ const clean = () => {
|
|||
switch (process.argv[2]) {
|
||||
case 'watch':
|
||||
{
|
||||
let watcher = chokidar.watch('urara', {
|
||||
const watcher = chokidar.watch('urara', {
|
||||
ignored: (file: string) => path.basename(file).startsWith('.')
|
||||
})
|
||||
watcher
|
||||
|
|
27
urara/.well-known/webfinger
Normal 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"
|
||||
}
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 70 KiB |
|
@ -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) 来解决,它可以列出最近用过的网页,按站点分类,查找起来很方便
|
||||
|
|
@ -2,16 +2,9 @@
|
|||
title: Miniflux · 保存文章到 Pocket 以及 RSS
|
||||
summary: 将 Miniflux 上的文章到保存到 Pocket/Instapaper,以及 RSS 相关文章和资源
|
||||
created: 2022-03-10T16:24:38.663Z
|
||||
preview: ''
|
||||
draft: ''
|
||||
tags:
|
||||
- RSS
|
||||
- Miniflux
|
||||
changelogs:
|
||||
- tag: '202203011'
|
||||
summary:
|
||||
- 添加了`instapaper`的连接方式
|
||||
- 添加了Pocket按钮嵌入方式
|
||||
lastmod: 2022-04-07T07:38:52.406Z
|
||||
---
|
||||
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
@ -1,87 +0,0 @@
|
|||
---
|
||||
title: Git · 常用操作笔记
|
||||
created: 2022-05-25
|
||||
summary: 每次更新博客进行的操作以及常见错误处理
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
|
||||
**资料:**
|
||||
|
||||
- [GIT CHEAT SHEET](https://education.github.com/git-cheat-sheet-education.pdf)
|
||||
- [45 个 Git 经典操作场景,专治不会合代码](https://mp.weixin.qq.com/s/BzdgZXyM1UaNCUCXySL9Rw)
|
||||
- [版本控制(Git) - 计算机教育中缺失的一课](https://missing-semester-cn.github.io/2020/version-control/)
|
||||
- [战壕里面的 Git(Git In The Trenches)](http://cbx33.github.io/gitt/intro.html)
|
||||
|
||||
## 每次更新博客进行的操作
|
||||
|
||||
### 1. 追踪所有文件
|
||||
|
||||
(除了 gitignore 里面的),也可以单独加
|
||||
|
||||
`git add -A`
|
||||
|
||||
### 2. 提交上传信息
|
||||
|
||||
`git commit -m '一些信息,如fixed something etc'`
|
||||
|
||||
### 3. push 到 Github
|
||||
|
||||
`git push origin main`
|
||||
|
||||
等待一会儿就好了,如果不行,换个网或者关掉 VPN 看看
|
||||
|
||||
## 常用 Git 操作
|
||||
|
||||
- `.gitignore`: 放不想传到 git repo 的文件/文件夹
|
||||
- 当内容改动很多的时候,最好开一个 branch
|
||||
- VSCode 文件后面的字母:
|
||||
- U:untrack
|
||||
- M: modified
|
||||
- A : on track
|
||||
- 一般不在`main` 或`master` 修改代码,而是开一个 branch,确定好后再 merge
|
||||
- 下载叫做 pull,上传是 push
|
||||
|
||||
| 命令 | 作用 |
|
||||
| :----------------------------------------------------------- | ------------------------------------------------- |
|
||||
| `git config --global user.name 名字` | 设置名字 |
|
||||
| `git config --global user.email 邮箱` | 设置邮件 |
|
||||
| `git init` | 初始化 |
|
||||
| `git add -A` | 追踪所有文件(除了 gitignore 里面的),也可以单独加 |
|
||||
| `git commit -m` | m 代表信息,后面要写 commit 相关信息 |
|
||||
| `git status` | 查看 git 状态/信息 |
|
||||
| `git log` | 查看 commit 日志,按 Q 才可以退出 |
|
||||
| `git reset hard (commit的id)` | 回到特定版本 |
|
||||
| `git reset hard --HEAD` | 返回上一次改动 (还没有 commit) |
|
||||
| `git branch` | 列出现在有的 branch,按 Q 退出 |
|
||||
| `git branch (branch'name)` | 创建新 branch |
|
||||
| `git merge (branch'name)` | 合并 branch 到 main |
|
||||
| `git checkout (branch's name)` | 切换 branch |
|
||||
| `git remote add origin https://github.com/用户名/仓库名.git` | 链接到 remote repo |
|
||||
| `git pull` | 拉更新 |
|
||||
| `git push origin (branch'name)` | push 到 remote repo |
|
||||
|
||||
## 常见问题
|
||||
|
||||
下面是一些我看过的文章
|
||||
|
||||
### 版本回滚
|
||||
|
||||
- [项目中 git 怎么回退到之前的版本 & git 放弃本地修改,强制拉取更新](https://mp.weixin.qq.com/s/MCtCQg7rcokf6IrZVINF4w)
|
||||
- [Git 学习笔记:版本回退](https://mp.weixin.qq.com/s/98wEvWU6OYVkPauWn-XXng)
|
||||
- [如果你还不会用 git 回滚代码,那你一定要来看看](https://mp.weixin.qq.com/s/FPiSyeivTKhoAgJmORZFog)
|
||||
|
||||
### 报错处理
|
||||
|
||||
- [git push 错误 failed to push some refs to 解决方法](https://blog.csdn.net/qq_39416311/article/details/102219428)
|
||||
- [git 上传忽略 node_modules](https://blog.csdn.net/jiandan1127/article/details/81205530)
|
||||
|
||||
### 博客相关
|
||||
|
||||
- [GitHub Pages 绑定来自阿里云的域名](https://blog.csdn.net/qq_29232943/article/details/52786603)
|
||||
- [Hexo 发布到 Github 丢失 readme 和 CNAME 解决方案](https://www.cnblogs.com/LandWind/articles/8269636.html)
|
||||
- [把 HUGO 博客托管到 GITHUB 上](https://www.freesion.com/article/37111127345/)
|
||||
|
||||
### 其他
|
||||
|
||||
- [Github 上如何添加 LICENSE 文件?](https://www.cnblogs.com/chenmingjun/p/8555906.html)
|