sync(upstream): ⬆️ deps, style and feat

This commit is contained in:
Hubert Chen 2023-06-05 17:53:29 +08:00
parent e7ae575f55
commit 49e7ef5da9
Signed by: trle5
GPG Key ID: 2935B4DE0D6F7720
15 changed files with 2075 additions and 2306 deletions

1
.npmrc
View File

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

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// mdsvex config type
import type { MdsvexOptions } from 'mdsvex'
@ -8,8 +10,7 @@ import rehypeExternalLinks from 'rehype-external-links'
// urara remark plugins
import type { Node, Data } from 'unist'
import { statSync } from 'fs'
import { parse, join } from 'path'
import { parse, join } from 'node:path'
import { visit } from 'unist-util-visit'
import { toString } from 'mdast-util-to-string'
import Slugger from 'github-slugger'
@ -20,31 +21,30 @@ import remarkFootnotes from 'remark-footnotes'
import { escapeSvelte } from 'mdsvex'
import { lex, parse as parseFence } from 'fenceparser'
import { renderCodeToHTML, runTwoSlash, createShikiHighlighter } from 'shiki-twoslash'
type VALUE = { [key in string | number]: VALUE } | Array<VALUE> | string | boolean | number
const remarkUraraFm =
() =>
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => {
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('/+page', '').replace('.svelte', ''))
// Generate ToC
if (data.fm.toc !== false) {
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []]
visit(tree, 'heading', (node: { depth: number }) => {
toc.push({
depth: node.depth,
title: toString(node),
slug: slugs.slug(toString(node), false)
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => {
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('/+page', '').replace('.svelte', ''))
// Generate ToC
if (data.fm.toc !== false) {
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []]
visit(tree, 'heading', (node: { depth: number }) => {
toc.push({
depth: node.depth,
title: toString(node),
slug: slugs.slug(toString(node), false)
})
})
})
if (toc.length > 0) data.fm.toc = toc
else data.fm.toc = false
if (toc.length > 0) data.fm.toc = toc
else data.fm.toc = false
}
}
}
// Better type definitions needed
const remarkUraraSpoiler = () => (tree: Node<Data>) =>
@ -59,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'
@ -71,7 +69,7 @@ export default defineConfig({
},
highlight: {
highlighter: async (code, lang, meta) => {
let fence: Record<string, VALUE> | null
let fence: any
let twoslash: any
try {
fence = parseFence(lex([lang, meta].filter(Boolean).join(' ')))
@ -93,13 +91,19 @@ export default defineConfig({
},
remarkPlugins: [
[
remarkFFF as any,
remarkFFF,
{
presets: ['hugo'],
presets: [],
target: 'mdsvex',
autofill: {
provider: 'fs',
path: (path: string) => path.replace('/src/routes/', '/urara/')
},
strict: {
media: {
type: 'string',
array: false,
}
}
}
],
@ -118,4 +122,6 @@ export default defineConfig({
}
]
]
})
} as MdsvexOptions
/* eslint-enable @typescript-eslint/no-explicit-any */

View File

@ -25,58 +25,64 @@
"format": "prettier --write --plugin-search-dir=. ."
},
"devDependencies": {
"@iconify-json/heroicons-outline": "^1.1.5",
"@iconify-json/heroicons-solid": "^1.1.6",
"@iconify-json/simple-icons": "^1.1.40",
"@sveltejs/adapter-auto": "^1.0.0",
"@sveltejs/adapter-netlify": "^1.0.0",
"@sveltejs/adapter-node": "^1.1.0",
"@sveltejs/adapter-static": "^1.0.1",
"@sveltejs/adapter-vercel": "1.0.2",
"@sveltejs/kit": "1.0.0-next.544",
"@iconify-json/heroicons-outline": "^1.1.6",
"@iconify-json/heroicons-solid": "^1.1.7",
"@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": "^18.11.18",
"@types/node": "^20.2.5",
"@types/unist": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"@vite-pwa/sveltekit": "^0.1.2",
"autoprefixer": "^10.4.13",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"@unocss/extractor-svelte": "^0.52.4",
"@vite-pwa/sveltekit": "^0.1.3",
"chalk": "^5.2.0",
"chokidar": "^3.5.3",
"cross-env": "^7.0.3",
"cssnano": "^5.1.14",
"daisyui": "^2.46.1",
"eslint": "^8.31.0",
"eslint-config-prettier": "^8.6.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.5.0",
"fff-flavored-frontmatter": "1.0.0-alpha.1",
"github-slugger": "^2.0.0",
"mdast-util-to-string": "^3.1.0",
"mdast-util-to-string": "^3.2.0",
"mdsvex": "^0.10.6",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.21",
"prettier": "^2.8.2",
"prettier-plugin-svelte": "^2.9.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.1",
"rehype-external-links": "^2.1.0",
"rehype-slug": "^5.1.0",
"remark": "^14.0.2",
"remark-fff": "~0.4.2",
"remark": "^14.0.3",
"remark-fff": "1.0.0-alpha.1",
"remark-footnotes": "~2.0.0",
"shiki-twoslash": "^3.1.0",
"svelte": "^3.55.1",
"svelte-bricks": "^0.1.7",
"svelte-check": "^3.0.2",
"svelte-preprocess": "^5.0.0",
"tailwindcss": "^3.2.4",
"tslib": "^2.4.1",
"typescript": "^4.9.4",
"unist-util-visit": "^4.1.1",
"unocss": "^0.48.4",
"vite": "^3.2.3",
"vite-plugin-pwa": "^0.14.1",
"workbox-build": "^6.5.4",
"workbox-window": "^6.5.4"
"svelte-bricks": "^0.2.0",
"shiki-twoslash": "^3.1.2",
"svelte": "^3.59.1",
"svelte-check": "^3.4.3",
"svelte-preprocess": "^5.0.4",
"sveltekit-embed": "^0.0.13",
"tailwindcss": "^3.3.2",
"tslib": "^2.5.2",
"typescript": "^4.9.5",
"unist-util-visit": "^4.1.2",
"unocss": "^0.52.4",
"vite": "^4.3.9",
"vite-plugin-pwa": "^0.14.7",
"workbox-build": "^6.6.0",
"workbox-window": "^6.6.0"
},
"pnpm": {
"overrides": {
"vite>rollup": "^3.10.0"
}
}
}

File diff suppressed because it is too large Load Diff

5
src/app.d.ts vendored
View File

@ -1,6 +1,6 @@
/// <reference types="@sveltejs/kit" />
import type { FFFBase, FFFMention } from 'fff-flavored-frontmatter'
import type { FFFBase, FFFMedia, FFFMention } from 'fff-flavored-frontmatter'
interface ImportMetaEnv extends Readonly<Record<string, string>> {
readonly URARA_SITE_PROTOCOL?: 'http://' | 'https://'
@ -16,7 +16,8 @@ declare global {
namespace Urara {
namespace Post {
type Frontmatter = Omit<FFFBase, 'flags'> &
Pick<FFFMention, 'in_reply_to'> & {
Pick<FFFMention, 'in_reply_to'> &
Pick<FFFMedia, 'alt'> & {
/**
* post type.
* @remarks auto-generated

View File

@ -36,12 +36,6 @@ html {
@apply text-primary;
}
/* .urara-prose list */
.urara-prose > ul > li > input {
@apply my-auto;
}
/* .urara-prose table */
.urara-prose div > table > thead {
@ -69,7 +63,7 @@ html {
}
.urara-prose li > input {
@apply checkbox checkbox-xs;
@apply checkbox checkbox-xs me-2 -my-0.5;
}
.urara-prose kbd {

View File

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

View File

@ -55,7 +55,7 @@
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">

View File

@ -60,7 +60,7 @@
? 'u-featured object-center h-full w-full absolute group-hover:scale-105 transition-transform duration-500 ease-in-out'
: 'u-photo rounded-xl md:rounded-b-none -mb-6 md:-mb-2'}
src={post.image}
alt={post.image}
alt={post.alt ?? post.image}
{loading}
{decoding} />
</figure>
@ -78,7 +78,7 @@
<Image
class={`${post.type === 'article' ? 'u-featured' : 'u-photo'}`}
src={post.image}
alt={post.image}
alt={post.alt ?? post.image}
{loading}
{decoding} />
</figure>

View File

@ -14,7 +14,8 @@
<figure class="!block">
<Image
class="object-center h-full w-full absolute group-hover:scale-105 transition-transform duration-500 ease-in-out"
src={prev['image']} />
src={prev['image']}
alt={prev['alt'] ?? prev['image']} />
</figure>
{/if}
<div class="card-body">
@ -40,7 +41,8 @@
<figure class="!block">
<Image
class="object-center h-full w-full absolute group-hover:scale-105 transition-transform duration-500 ease-in-out"
src={next['image']} />
src={next['image']}
alt={next['alt'] ?? next['image']} />
</figure>
{/if}
<div class="card-body">

View File

@ -15,6 +15,7 @@ export type CommentConfig = {
giscus?: GiscusConfig
/** Utterances config, more at https://utteranc.es */
utterances?: UtterancesConfig
remark42?: Remark42Config
}
export type WebmentionConfig = {
@ -71,3 +72,36 @@ export type UtterancesConfig = {
/** choose an utterances theme that matches your blog. */
theme?: string
}
export type Remark42Config = {
/** hostname of Remark42 server, same as REMARK_URL in backend config, e.g. "https://demo.remark42.com" */
host: string
/** the SITE that you passed to Remark42 instance on start of backend. (default: remark) */
site_id?: string
/** url to the page with comments*/
url?: string
/** an array of widgets that should be rendered on a page (default: ['embed'] )*/
components?: ['embed' | 'last-comments' | 'counter']
/** maximum number of comments that is rendered on mobile version (default: 15 )*/
max_shown_comments?: number
/** maximum number of comments in the last comments widget (default: 15 )*/
max_last_comments?: number
/** changes UI theme, (default: light )*/
theme?: 'light' | 'dark'
/** title for current comments page (default: document.title)*/
page_title?: string
/**
* interface localization,
* English (en), Belarusian (be), Brazilian Portuguese (bp), Bulgarian (bg), Chinese (zh), Finnish (fi), French (fr), German (de), Japanese (ja), Korean (ko), Polish (pl), Russian (ru), Spanish (es), Turkish (tr), Ukrainian (ua), Italian (it) and Vietnamese (vi)
* default: en
*/
locale?: 'en' | 'be' | 'bp' | 'bg' | 'zh' | 'fi' | 'fr' | 'de' | 'ja' | 'ko' | 'pl' | 'ru' | 'es' | 'tr' | 'ua' | 'it' | 'vi'
/** enables email subscription (default: true) */
show_email_subscription?: boolean
/** enables RSS subscription, (default: true) */
show_rss_subscription?: boolean
/** minimized UI with basic info only, (default: false) */
simple_view?: boolean
/** hides footer with signature and links to Remark42,(default: false) */
no_footer?: boolean
}

View File

@ -3,6 +3,7 @@
import { fly } from 'svelte/transition'
import { page } from '$app/stores'
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'
@ -26,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(() => {

View File

@ -1,24 +1,22 @@
// sveltekit config type
import type { Config } from '@sveltejs/kit'
// svelte adapter
import adapterAuto from '@sveltejs/adapter-auto'
import adapterNode from '@sveltejs/adapter-node'
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 preprocess from 'svelte-preprocess'
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',
@ -27,6 +25,11 @@ export default defineConfig({
prerender: {
handleMissingId: 'warn'
},
csp: { mode: 'auto' }
csp: {
mode: 'auto',
directives: {
'style-src': ['self', 'unsafe-inline', 'https://giscus.app']
}
}
}
})
} as Config

View File

@ -6,7 +6,25 @@ import daisyui from 'daisyui'
export default {
content: ['./src/**/*.{html,md,js,svelte,ts}'],
theme: { extend: {} },
theme: {
extend: {
typography: {
DEFAULT: {
css: {
'ul:has(li):has(input[type="checkbox"])': {
padding: 0
},
'ul > li:has(input[type="checkbox"])': {
listStyle: 'none'
},
'ul > li:has(input[type="checkbox"]) ul li': {
paddingLeft: 30
}
}
}
}
}
},
plugins: [typography, daisyui],
daisyui: { themes: theme.map(({ name }) => name) }
}

View File

@ -2,30 +2,26 @@
import { defineConfig } from 'vite'
// vite plugin
import UnoCSS from 'unocss/vite'
import { presetTagify, presetIcons, extractorSvelte } from 'unocss'
import { presetTagify, presetIcons } from 'unocss'
import extractorSvelte from '@unocss/extractor-svelte'
import { sveltekit as SvelteKit } from '@sveltejs/kit/vite'
import { SvelteKitPWA } from '@vite-pwa/sveltekit'
import { sveltekit } from '@sveltejs/kit/vite'
// postcss & tailwindcss
import TailwindCSS from 'tailwindcss'
import tailwindConfig from './tailwind.config'
import autoprefixer from 'autoprefixer'
import cssnano from 'cssnano'
import LightningCSS from 'postcss-lightningcss'
export default defineConfig({
envPrefix: 'URARA_',
build: {
sourcemap: false,
rollupOptions: {
cache: false
}
},
css: {
postcss: {
plugins: [
TailwindCSS(tailwindConfig),
autoprefixer(),
...(process.env.NODE_ENV === 'production'
? [
cssnano({
preset: ['default', { discardComments: { removeAll: true } }]
})
]
: [])
]
plugins: [TailwindCSS(tailwindConfig), LightningCSS()]
}
},
plugins: [
@ -39,7 +35,7 @@ export default defineConfig({
presetIcons({ scale: 1.5 })
]
}),
sveltekit(),
SvelteKit(),
SvelteKitPWA({
registerType: 'autoUpdate',
manifest: false,
@ -50,4 +46,4 @@ export default defineConfig({
}
})
]
})
})