astro-pure 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/bun.lockb +0 -0
- package/components/advanced/Comment.astro +2 -2
- package/components/advanced/GithubCard.astro +14 -8
- package/components/basic/Footer.astro +1 -1
- package/components/basic/ThemeProvider.astro +2 -1
- package/components/pages/ArticleBottom.astro +0 -1
- package/components/pages/BackToTop.astro +6 -5
- package/components/pages/Copyright.astro +7 -7
- package/components/pages/PFSearch.astro +70 -0
- package/components/pages/PostPreview.astro +0 -1
- package/components/pages/index.ts +1 -0
- package/components/user/Aside.astro +6 -7
- package/components/user/Icon.astro +4 -4
- package/components/user/MdxRepl.astro +48 -0
- package/components/user/Svg.astro +41 -0
- package/components/user/index.ts +3 -1
- package/index.ts +2 -1
- package/libs/icons.ts +30 -1
- package/package.json +5 -2
- package/plugins/override-svg-attributes.ts +41 -0
- package/plugins/remark-plugins.ts +17 -0
- package/schemas/social.ts +7 -16
- package/scripts/index.js +3 -3
- package/types/constants.ts +20 -0
- package/types/index.ts +2 -0
- package/types/integrations-config.ts +1 -1
- package/types/theme-config.ts +1 -1
- package/utils/index.ts +6 -1
- package/utils/mdast-util-to-string.ts +36 -0
- package/utils/reading-time.ts +79 -0
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
# Astro Theme Pure
|
|
2
|
-
|
|
3
|
-
[](https://github.com/cworld1/astro-theme-pure/commits)
|
|
4
|
-
[](https://github.com/cworld1/astro-theme-pure/stargazers)
|
|
5
|
-
[](#)
|
|
6
|
-
[](https://github.com/cworld1/astro-theme-pure/blob/main/LICENSE)
|
|
1
|
+
# Astro Theme Pure (Integration Package)
|
|
7
2
|
|
|
8
3
|
A simple, fast and powerful blog theme built by Astro.
|
|
9
4
|
|
|
5
|
+
[](https://astro-pure.js.org/)
|
|
6
|
+
[](https://www.npmjs.com/package/astro-pure)
|
|
7
|
+
[](https://github.com/cworld1/astro-theme-pure/blob/main/LICENSE)
|
|
8
|
+
|
|
10
9
|

|
|
11
10
|
|
|
12
11
|
## Usage
|
package/bun.lockb
CHANGED
|
Binary file
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
import config from 'virtual:config'
|
|
3
3
|
|
|
4
|
+
import '@waline/client/style'
|
|
5
|
+
|
|
4
6
|
import { cn } from '../../utils'
|
|
5
7
|
|
|
6
8
|
const { class: className } = Astro.props
|
|
@@ -21,8 +23,6 @@ const { class: className } = Astro.props
|
|
|
21
23
|
import type { WalineEmojiPresets } from '@waline/client'
|
|
22
24
|
import config from 'virtual:config'
|
|
23
25
|
|
|
24
|
-
import '@waline/client/style'
|
|
25
|
-
|
|
26
26
|
const walineConfig = config.integ.waline
|
|
27
27
|
|
|
28
28
|
class Comment extends HTMLElement {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { Icon } from '../user'
|
|
3
|
+
|
|
2
4
|
const { repo: repoRaw } = Astro.props
|
|
3
5
|
|
|
4
6
|
// Remove 'https://github.com/' headings from the repo string
|
|
@@ -21,26 +23,30 @@ const [owner, repoName] = repo.split('/')
|
|
|
21
23
|
<span class='text-lg font-bold transition-colors'>{repoName}</span>
|
|
22
24
|
</div>
|
|
23
25
|
<div class='rounded-full bg-primary-foreground p-1'>
|
|
24
|
-
<
|
|
25
|
-
<use href='/icons/social.svg#mingcute-github-line'></use>
|
|
26
|
-
</svg>
|
|
26
|
+
<Icon name='github' />
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
29
29
|
<p id='gh-description' class='gh-text'>Waiting for api.github.com...</p>
|
|
30
30
|
<div class='flex items-center justify-between'>
|
|
31
31
|
<div class='gh-text flex flex-wrap items-center gap-x-5'>
|
|
32
32
|
<div class='flex items-center gap-x-2'>
|
|
33
|
-
|
|
33
|
+
{/* mingcute:star-line */}
|
|
34
|
+
<!-- prettier-ignore -->
|
|
35
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M10.92 2.868a1.25 1.25 0 0 1 2.16 0l2.795 4.798l5.428 1.176a1.25 1.25 0 0 1 .667 2.054l-3.7 4.141l.56 5.525a1.25 1.25 0 0 1-1.748 1.27L12 19.592l-5.082 2.24a1.25 1.25 0 0 1-1.748-1.27l.56-5.525l-3.7-4.14a1.25 1.25 0 0 1 .667-2.055l5.428-1.176zM12 4.987L9.687 8.959a1.25 1.25 0 0 1-.816.592l-4.492.973l3.062 3.427c.234.262.347.61.312.959l-.463 4.573l4.206-1.854a1.25 1.25 0 0 1 1.008 0l4.206 1.854l-.463-4.573a1.25 1.25 0 0 1 .311-.959l3.063-3.427l-4.492-.973a1.25 1.25 0 0 1-.816-.592z"/></g></svg>
|
|
34
36
|
<span id='gh-stars' class='leading-tight'>???</span>
|
|
35
37
|
</div>
|
|
38
|
+
|
|
36
39
|
<div class='flex items-center gap-x-2'>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
>
|
|
40
|
+
{/* mingcute:git-branch-line */}
|
|
41
|
+
<!-- prettier-ignore -->
|
|
42
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M18 3a3 3 0 0 1 1 5.83V9a4 4 0 0 1-4 4H9a2 2 0 0 0-2 2v.17a3.001 3.001 0 1 1-2 0V8.83a3.001 3.001 0 1 1 2 0v2.705A4 4 0 0 1 9 11h6a2 2 0 0 0 2-2v-.17A3.001 3.001 0 0 1 18 3M6 17a1 1 0 1 0 0 2a1 1 0 0 0 0-2M6 5a1 1 0 1 0 0 2a1 1 0 0 0 0-2m12 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2"/></g></svg>
|
|
40
43
|
<span id='gh-forks' class='leading-tight'>???</span>
|
|
41
44
|
</div>
|
|
45
|
+
|
|
42
46
|
<div class='flex items-center gap-x-2'>
|
|
43
|
-
|
|
47
|
+
{/* mingcute:balance-line */}
|
|
48
|
+
<!-- prettier-ignore -->
|
|
49
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M12 3a1 1 0 0 1 1 1v1h.764a2 2 0 0 1 .894.211L16.236 6H20a1 1 0 1 1 0 2h-.382l2.276 4.553c.07.139.106.292.106.447a4 4 0 0 1-8 0c0-.155.036-.308.106-.447L16.382 8h-.146a2 2 0 0 1-.894-.211L13.764 7H13v12h3a1 1 0 1 1 0 2H8a1 1 0 1 1 0-2h3V7h-.764l-1.578.789A2 2 0 0 1 7.764 8h-.146l2.276 4.553A1 1 0 0 1 10 13a4 4 0 0 1-8 0a1 1 0 0 1 .106-.447L4.382 8H4a1 1 0 0 1 0-2h3.764l1.578-.789A2 2 0 0 1 10.236 5H11V4a1 1 0 0 1 1-1M6 9.236l-1.989 3.977a2 2 0 0 0 3.978 0zm12 0l-1.989 3.977a2 2 0 0 0 3.955.157l.023-.156z"/></g></svg>
|
|
44
50
|
<span id='gh-license' class='leading-tight'>???</span>
|
|
45
51
|
</div>
|
|
46
52
|
</div>
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
22
|
<script>
|
|
23
|
+
import { Icons } from '../../libs/icons'
|
|
23
24
|
import { listenThemeChange } from '../../utils'
|
|
24
25
|
|
|
25
26
|
// Listen for theme change event
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
const toast = document.createElement('div')
|
|
31
32
|
toast.className =
|
|
32
33
|
'animate fixed bottom-8 z-20 px-4 py-2 bg-muted text-foreground rounded-lg border border-border shadow-lg flex items-center gap-2'
|
|
33
|
-
toast.innerHTML = `<svg
|
|
34
|
+
toast.innerHTML = `<svg width='22' height='22' viewBox='0 0 24 24' fill='currentColor'>${Icons.info}</svg> <span>${message}</span>`
|
|
34
35
|
document.body.appendChild(toast)
|
|
35
36
|
setTimeout(() => {
|
|
36
37
|
toast.remove()
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { Icon } from '../user'
|
|
3
|
+
|
|
2
4
|
const { header: headerName, content: contentName, needPercent = true } = Astro.props
|
|
3
5
|
---
|
|
4
6
|
|
|
@@ -14,11 +16,10 @@ const { header: headerName, content: contentName, needPercent = true } = Astro.p
|
|
|
14
16
|
<span class='text'>10</span>
|
|
15
17
|
<span class='text-xs'>%</span>
|
|
16
18
|
</div>
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</svg>
|
|
19
|
+
<Icon
|
|
20
|
+
name='up'
|
|
21
|
+
class='opacity-0 transition-opacity group-hover:opacity-100 group-[.ended]:opacity-100'
|
|
22
|
+
/>
|
|
22
23
|
</button>
|
|
23
24
|
|
|
24
25
|
<script is:inline define:vars={{ headerName, contentName, needPercent }}>
|
|
@@ -90,13 +90,13 @@ const shares = {
|
|
|
90
90
|
</button>
|
|
91
91
|
{
|
|
92
92
|
config.content.share.map((share) => (
|
|
93
|
-
<a
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
<a
|
|
94
|
+
href={shares[share].link}
|
|
95
|
+
target='_blank'
|
|
96
|
+
id={`share-${share}`}
|
|
97
|
+
class='group rounded-full bg-muted p-1 text-muted-foreground transition-colors hover:text-primary sm:p-1.5'
|
|
98
|
+
>
|
|
99
|
+
<Icon class='size-5' name={share} />
|
|
100
100
|
</a>
|
|
101
101
|
))
|
|
102
102
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
import '@pagefind/default-ui/css/ui.css'
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<site-search>
|
|
6
|
+
<aside class='form my-4'>
|
|
7
|
+
{
|
|
8
|
+
import.meta.env.DEV ? (
|
|
9
|
+
<div class='w-full rounded-xl border-2 bg-transparent px-4 py-2 pe-3 outline-none focus:border-foreground'>
|
|
10
|
+
You are in Dev mode, the search is disabled.
|
|
11
|
+
</div>
|
|
12
|
+
) : (
|
|
13
|
+
<div id='site-search' />
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
</aside>
|
|
17
|
+
</site-search>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
class SiteSearch extends HTMLElement {
|
|
21
|
+
constructor() {
|
|
22
|
+
super()
|
|
23
|
+
|
|
24
|
+
// const shouldStrip = this.dataset.stripTrailingSlash !== undefined
|
|
25
|
+
// const stripTrailingSlash = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
|
|
26
|
+
// const formatURL = shouldStrip ? stripTrailingSlash : (path: string) => path
|
|
27
|
+
const formatURL = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
|
|
28
|
+
|
|
29
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
30
|
+
// if (import.meta.env.DEV) return
|
|
31
|
+
const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1))
|
|
32
|
+
onIdle(async () => {
|
|
33
|
+
// @ts-expect-error — Missing types for @pagefind/default-ui package.
|
|
34
|
+
const { PagefindUI } = await import('@pagefind/default-ui')
|
|
35
|
+
new PagefindUI({
|
|
36
|
+
element: '#site-search',
|
|
37
|
+
baseUrl: import.meta.env.BASE_URL,
|
|
38
|
+
bundlePath: import.meta.env.BASE_URL.replace(/\/$/, '') + '/pagefind/',
|
|
39
|
+
showImages: false,
|
|
40
|
+
showSubResults: true,
|
|
41
|
+
processResult: (result: { url: string; sub_results: Array<{ url: string }> }) => {
|
|
42
|
+
result.url = formatURL(result.url)
|
|
43
|
+
result.sub_results = result.sub_results.map((sub_result) => {
|
|
44
|
+
sub_result.url = formatURL(sub_result.url)
|
|
45
|
+
return sub_result
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
customElements.define('site-search', SiteSearch)
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
#site-search {
|
|
58
|
+
--pagefind-ui-scale: 0.8;
|
|
59
|
+
--pagefind-ui-primary: hsl(var(--primary) / var(--tw-bg-opacity, 1));
|
|
60
|
+
--pagefind-ui-text: hsl(var(--foreground) / var(--tw-text-opacity, 1));
|
|
61
|
+
--pagefind-ui-background: hsl(var(--muted) / var(--tw-bg-opacity, 1));
|
|
62
|
+
--pagefind-ui-border: hsl(var(--border) / var(--tw-border-opacity, 1));
|
|
63
|
+
--pagefind-ui-tag: hsl(var(--muted-foreground) / var(--tw-text-opacity, 1));
|
|
64
|
+
--pagefind-ui-border-width: 2px;
|
|
65
|
+
--pagefind-ui-border-radius: calc(var(--radius) + 2px);
|
|
66
|
+
--pagefind-ui-image-border-radius: calc(var(--radius) + 2px);
|
|
67
|
+
--pagefind-ui-image-box-ratio: 3 / 2;
|
|
68
|
+
--pagefind-ui-font: sans-serif;
|
|
69
|
+
}
|
|
70
|
+
</style>
|
|
@@ -7,3 +7,4 @@ export { default as Paginator } from './Paginator.astro'
|
|
|
7
7
|
export { default as PostPreview } from './PostPreview.astro'
|
|
8
8
|
export { default as TOC } from './TOC.astro'
|
|
9
9
|
export { default as TOCHeading } from './TOCHeading.astro'
|
|
10
|
+
export { default as PFSearch } from './PFSearch.astro'
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
import { AstroError } from 'astro/errors'
|
|
4
4
|
|
|
5
5
|
import { cn } from '../../utils'
|
|
6
|
+
import Icon from './Icon.astro'
|
|
6
7
|
|
|
7
8
|
const asideVariants = ['note', 'tip', 'caution', 'danger'] as const
|
|
8
9
|
const icons = {
|
|
9
|
-
note: '
|
|
10
|
-
tip: '
|
|
11
|
-
caution: '
|
|
12
|
-
danger: '
|
|
10
|
+
note: 'info',
|
|
11
|
+
tip: 'bulb',
|
|
12
|
+
caution: 'alert',
|
|
13
|
+
danger: 'octangon'
|
|
13
14
|
} as const
|
|
14
15
|
|
|
15
16
|
interface Props {
|
|
@@ -37,9 +38,7 @@ if (!title) {
|
|
|
37
38
|
class={cn('aside-container border-l-8 border-primary px-4 py-3 bg-primary', `aside-${type}`)}
|
|
38
39
|
>
|
|
39
40
|
<p class='not-prose flex items-center gap-x-2 font-medium text-primary' aria-hidden='true'>
|
|
40
|
-
<
|
|
41
|
-
<use href={`/icons/${icons[type]}`}></use>
|
|
42
|
-
</svg>
|
|
41
|
+
<Icon name={icons[type]} />
|
|
43
42
|
{title}
|
|
44
43
|
</p>
|
|
45
44
|
<div class='aside-content mt-2'>
|
|
@@ -16,8 +16,8 @@ const a11yAttrs = label ? ({ 'aria-label': label } as const) : ({ 'aria-hidden':
|
|
|
16
16
|
<svg
|
|
17
17
|
{...a11yAttrs}
|
|
18
18
|
class={className}
|
|
19
|
-
width='
|
|
20
|
-
height='
|
|
19
|
+
width='22'
|
|
20
|
+
height='22'
|
|
21
21
|
viewBox='0 0 24 24'
|
|
22
22
|
fill='currentColor'
|
|
23
23
|
set:html={Icons[name]}
|
|
@@ -28,7 +28,7 @@ const a11yAttrs = label ? ({ 'aria-label': label } as const) : ({ 'aria-hidden':
|
|
|
28
28
|
svg {
|
|
29
29
|
color: var(--sl-icon-color);
|
|
30
30
|
font-size: var(--sl-icon-size, 1em);
|
|
31
|
-
width:
|
|
32
|
-
height:
|
|
31
|
+
width: 1.5em;
|
|
32
|
+
height: 1.5em;
|
|
33
33
|
}
|
|
34
34
|
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
width?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { width } = Astro.props
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<div class='mdx-repl overflow-hidden rounded-xl border'>
|
|
10
|
+
<div class='mdx-repl-container flex flex-col items-center justify-center p-4'>
|
|
11
|
+
<slot />
|
|
12
|
+
</div>
|
|
13
|
+
<div class='bg-muted'>
|
|
14
|
+
<slot name='desc' />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<style define:vars={{ width }}>
|
|
19
|
+
.mdx-repl {
|
|
20
|
+
background: linear-gradient(
|
|
21
|
+
135deg,
|
|
22
|
+
hsl(var(--primary) / 0.05) 0%,
|
|
23
|
+
hsl(var(--muted) / 0.2) 100%
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Container */
|
|
28
|
+
.mdx-repl-container > :global(*) {
|
|
29
|
+
width: var(--width);
|
|
30
|
+
}
|
|
31
|
+
.mdx-repl-container > :global(*):first-child {
|
|
32
|
+
margin-top: 0;
|
|
33
|
+
}
|
|
34
|
+
.mdx-repl-container > :global(*):last-child {
|
|
35
|
+
margin-bottom: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Desc especial adaption */
|
|
39
|
+
/* Code */
|
|
40
|
+
.mdx-repl :global(.astro-code) {
|
|
41
|
+
margin: 0;
|
|
42
|
+
border-radius: 0;
|
|
43
|
+
}
|
|
44
|
+
/* Tabs */
|
|
45
|
+
.mdx-repl :global(div[role='tabpanel']) {
|
|
46
|
+
margin-top: 0;
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
// https://github.com/jasikpark/astro-svg-loader/blob/main/src/components/Svg/Svg.astro
|
|
3
|
+
import { overrideSvgAttributes, type SVGAttributes } from '../../plugins/override-svg-attributes'
|
|
4
|
+
|
|
5
|
+
// accepts SVG attributes which will override the ones in the original SVG
|
|
6
|
+
export interface Props extends SVGAttributes {
|
|
7
|
+
/** pass an `import("*.svg?raw")` to `Svg` for the svg file to use */
|
|
8
|
+
src: Promise<typeof import('*.svg?raw')>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { src, ...attributeOverrides } = Astro.props as Props
|
|
12
|
+
|
|
13
|
+
const SVG_NOT_FOUND = 'Could not find an SVG at the provided `src`'
|
|
14
|
+
const ALT_NOT_ALLOWED =
|
|
15
|
+
'`alt` is not a valid prop for svg, perhaps you mean `aria-label` or `aria-hidden`?'
|
|
16
|
+
|
|
17
|
+
const svgImport = await src
|
|
18
|
+
|
|
19
|
+
if (!svgImport) {
|
|
20
|
+
throw new Error(SVG_NOT_FOUND)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const svgSource = svgImport.default
|
|
24
|
+
|
|
25
|
+
if (!svgSource) {
|
|
26
|
+
throw new Error(SVG_NOT_FOUND)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ('alt' in attributeOverrides) {
|
|
30
|
+
throw new Error(ALT_NOT_ALLOWED)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!svgSource.trimStart().toLowerCase().startsWith('<svg')) {
|
|
34
|
+
throw new Error(`${SVG_NOT_FOUND}, provided: ${svgSource.slice(0, 23)}
|
|
35
|
+
maybe you need to add '?raw' to the end of the import?`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const contents = overrideSvgAttributes(svgSource, attributeOverrides)
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
<Fragment set:html={contents} />
|
package/components/user/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Container
|
|
2
2
|
export { default as Card } from './Card.astro'
|
|
3
3
|
export { default as Collapse } from './Collapse.astro'
|
|
4
4
|
export { default as Aside } from './Aside.astro'
|
|
5
5
|
export { default as Tabs } from './Tabs.astro'
|
|
6
6
|
export { default as TabItem } from './TabItem.astro'
|
|
7
|
+
export { default as MdxRepl } from './MdxRepl.astro'
|
|
7
8
|
|
|
8
9
|
// List
|
|
9
10
|
export { default as CardList } from './CardList.astro'
|
|
@@ -15,6 +16,7 @@ export { default as Button } from './Button.astro'
|
|
|
15
16
|
export { default as Spoiler } from './Spoiler.astro'
|
|
16
17
|
export { default as FormattedDate } from './FormattedDate.astro'
|
|
17
18
|
export { default as Label } from './Label.astro'
|
|
19
|
+
export { default as Svg } from './Svg.astro'
|
|
18
20
|
|
|
19
21
|
// Sources
|
|
20
22
|
export { default as Icon } from './Icon.astro'
|
package/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ import sitemap from '@astrojs/sitemap'
|
|
|
9
9
|
import tailwind from '@astrojs/tailwind'
|
|
10
10
|
import rehypeExternalLinks from 'rehype-external-links'
|
|
11
11
|
|
|
12
|
-
import { remarkAddZoomable } from './plugins/remark-plugins'
|
|
12
|
+
import { remarkAddZoomable, remarkReadingTime } from './plugins/remark-plugins'
|
|
13
13
|
import { vitePluginUserConfig } from './plugins/virtual-user-config'
|
|
14
14
|
import { UserConfigSchema, type UserInputConfig } from './types/user-config'
|
|
15
15
|
import { parseWithFriendlyErrors } from './utils/error-map'
|
|
@@ -44,6 +44,7 @@ export default function AstroPureIntegration(opts: UserInputConfig): AstroIntegr
|
|
|
44
44
|
// Add supported remark plugins based on user config.
|
|
45
45
|
if (userConfig.integ.mediumZoom.enable)
|
|
46
46
|
remarkPlugins.push([remarkAddZoomable, userConfig.integ.mediumZoom.options])
|
|
47
|
+
remarkPlugins.push(remarkReadingTime)
|
|
47
48
|
|
|
48
49
|
// Add supported rehype plugins based on user config.
|
|
49
50
|
rehypePlugins.push([
|
package/libs/icons.ts
CHANGED
|
@@ -40,6 +40,18 @@ export const BuiltInIcons = {
|
|
|
40
40
|
// tabler:brand-steam
|
|
41
41
|
steam:
|
|
42
42
|
'<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M16.5 5a4.5 4.5 0 1 1-.653 8.953L11.5 16.962V17a3 3 0 0 1-2.824 3H8.5a3 3 0 0 1-2.94-2.402L3 16.5V13l3.51 1.755a2.99 2.99 0 0 1 2.834-.635l2.727-3.818A4.5 4.5 0 0 1 16.5 5"/><circle cx="16.5" cy="9.5" r="1" fill="currentColor"/></g>',
|
|
43
|
+
// ri:bilibili-line
|
|
44
|
+
bilibili:
|
|
45
|
+
'<path fill="currentColor" d="M7.172 2.757L10.414 6h3.171l3.243-3.242a1 1 0 1 1 1.415 1.415L16.414 6H18.5A3.5 3.5 0 0 1 22 9.5v8a3.5 3.5 0 0 1-3.5 3.5h-13A3.5 3.5 0 0 1 2 17.5v-8A3.5 3.5 0 0 1 5.5 6h2.085L5.757 4.171a1 1 0 0 1 1.415-1.415M18.5 8h-13a1.5 1.5 0 0 0-1.493 1.356L4 9.5v8a1.5 1.5 0 0 0 1.356 1.493L5.5 19h13a1.5 1.5 0 0 0 1.493-1.355L20 17.5v-8A1.5 1.5 0 0 0 18.5 8M8 11a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0v-2a1 1 0 0 1 1-1m8 0a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0v-2a1 1 0 0 1 1-1"/>',
|
|
46
|
+
// ri:zhihu-line
|
|
47
|
+
zhihu:
|
|
48
|
+
'<path fill="currentColor" d="m12.345 17.963l-1.688 1.074l-2.132-3.35c-.44 1.402-1.171 2.665-2.138 3.825c-.402.483-.82.918-1.301 1.376c-.155.146-.775.716-.878.82l-1.414-1.415c.139-.139.787-.735.914-.856c.43-.408.796-.79 1.143-1.205C6.117 16.712 6.88 15.02 6.988 13H3v-2h4V7h-.868c-.689 1.266-1.558 2.222-2.618 2.858L2.486 8.143c1.396-.838 2.426-2.603 3.039-5.36l1.952.434q-.21.95-.489 1.783h4.513v2H9v4h2.5v2H9.186zm3.838-.07L17.3 17h1.702V7h-4v10h.736zM13.001 5h8v14h-3l-2.5 2l-1-2H13z"/>',
|
|
49
|
+
// iconfont:coolapk
|
|
50
|
+
coolapk:
|
|
51
|
+
'<path transform="scale(0.031, 0.031) translate(-120, -100)" d="M315.2 343.093c53.547-12.8 111.52-1.92 158.72 25.76 34.987 21.12 65.44 48.64 97.493 73.707-17.706 12-35.253 24.16-53.173 35.84-32.747-24.693-62.933-54.88-102.56-68.48-36.373-12.533-78.827-14.4-113.387 4.64-35.413 18.773-59.733 57.333-59.68 97.653-1.066 40.48 22.667 79.734 57.76 99.414 37.814 21.76 86.08 18.88 124.534 0.32 47.626-23.307 80.32-67.147 109.653-109.814 31.52-48.96 59.573-100.053 90.293-149.493 6.72-12.533 22.507-19.253 36-14.133 12.534 4 17.92 16.96 23.894 27.466 47.466 85.6 95.52 170.827 143.573 256.054 7.52 13.653 18.507 27.84 13.867 44.48-3.52 20.533-30.827 27.573-46.4 16-66.24-49.067-132.8-97.814-198.934-147.147 16.374-13.707 34.934-24.533 52.374-36.8 22.933 17.013 45.866 34.08 68.906 50.933-22.026-40.853-45.6-80.8-67.893-121.493-42.613 66.08-77.387 138.773-135.04 193.653-41.387 41.12-98.453 69.227-157.813 65.974-92.054 4.213-175.414-78.774-174.614-170.347-3.84-79.68 55.04-156 132.427-174.187z" fill="currentColor"></path>',
|
|
52
|
+
// ri:netease-cloud-music-line
|
|
53
|
+
netease:
|
|
54
|
+
'<path fill="currentColor" d="M10.422 11.375c-.294 1.028.012 2.065.784 2.653c1.061.81 2.565.3 2.874-.995c.08-.337.103-.722.027-1.056c-.23-1.001-.521-1.988-.792-2.996c-1.33.154-2.543 1.172-2.893 2.394m5.548-.287c.273 1.012.285 2.017-.127 3c-1.128 2.69-4.722 3.14-6.573.826c-1.302-1.627-1.28-3.961.06-5.734c.78-1.032 1.804-1.707 3.048-2.054l.379-.104c-.084-.415-.188-.816-.243-1.224c-.176-1.317.512-2.503 1.744-3.04c1.226-.535 2.708-.216 3.53.76c.406.479.395 1.08-.025 1.464c-.412.377-.997.346-1.435-.09c-.247-.246-.51-.44-.877-.436c-.525.006-.987.418-.945.937c.037.468.172.93.3 1.386c.022.078.216.135.338.153c1.333.197 2.504.731 3.472 1.676c2.558 2.493 2.861 6.531.672 9.44c-1.529 2.032-3.61 3.169-6.127 3.409c-4.621.44-8.664-2.53-9.7-7.058C2.516 10.255 4.84 5.831 8.796 4.25c.586-.234 1.143-.031 1.371.498c.232.537-.019 1.086-.61 1.35c-2.368 1.06-3.817 2.855-4.215 5.424c-.533 3.433 1.656 6.776 5 7.72c2.723.77 5.658-.166 7.308-2.33c1.586-2.08 1.4-5.099-.427-6.873A4 4 0 0 0 15.4 9.026c.198.716.389 1.388.57 2.062"/>',
|
|
43
55
|
|
|
44
56
|
// === Copyright & share & sponsor ===
|
|
45
57
|
// mingcute:link-2-line
|
|
@@ -84,6 +96,13 @@ export const BuiltInIcons = {
|
|
|
84
96
|
// mingcute:hashtag-line
|
|
85
97
|
hashtag:
|
|
86
98
|
'<g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M10.124 3.008a1 1 0 0 1 .868 1.116L10.508 8h3.984l.516-4.124a1 1 0 1 1 1.984.248L16.508 8H20a1 1 0 1 1 0 2h-3.742l-.5 4H19.5a1 1 0 1 1 0 2h-3.992l-.516 4.124a1 1 0 1 1-1.984-.248L13.492 16H9.508l-.516 4.124a1 1 0 1 1-1.984-.248L7.492 16H4.5a1 1 0 1 1 0-2h3.242l.5-4H5a1 1 0 0 1 0-2h3.492l.516-4.124a1 1 0 0 1 1.116-.868M13.742 14l.5-4h-3.984l-.5 4z"/></g>',
|
|
99
|
+
// mingcute:information-line
|
|
100
|
+
info: '<g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m-.01 6c.558 0 1.01.452 1.01 1.01v5.124A1 1 0 0 1 12.5 18h-.49A1.01 1.01 0 0 1 11 16.99V12a1 1 0 1 1 0-2zM12 7a1 1 0 1 1 0 2a1 1 0 0 1 0-2"/></g>',
|
|
101
|
+
// mingcute:up-line
|
|
102
|
+
up: '<g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M11.293 8.293a1 1 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L12 10.414l-4.95 4.95a1 1 0 0 1-1.414-1.414z"/></g>',
|
|
103
|
+
// mingcute:tag-2-line
|
|
104
|
+
'tag-2':
|
|
105
|
+
'<g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M10.238 4.827a3 3 0 0 1 2.122.878l6.485 6.486a3 3 0 0 1 0 4.242l-4.243 4.243a3 3 0 0 1-4.242 0l-6.486-6.485a3 3 0 0 1-.878-2.122V7.327a2.5 2.5 0 0 1 2.5-2.5zm0 2H5.496a.5.5 0 0 0-.5.5v4.742a1 1 0 0 0 .292.707l6.486 6.486a1 1 0 0 0 1.414 0l4.243-4.243a1 1 0 0 0 0-1.414L10.945 7.12a1 1 0 0 0-.707-.293M7.531 9.362a1.5 1.5 0 1 1 2.121 2.122a1.5 1.5 0 0 1-2.121-2.122M11.652 2a3 3 0 0 1 2.122.878l7.192 7.193a1 1 0 0 1-1.414 1.414L12.36 4.29a1 1 0 0 0-.708-.29H7a1 1 0 0 1 0-2z"/></g>',
|
|
87
106
|
|
|
88
107
|
// === Project ===
|
|
89
108
|
'github-circle':
|
|
@@ -98,7 +117,17 @@ export const BuiltInIcons = {
|
|
|
98
117
|
// === Home ===
|
|
99
118
|
// mingcute:location-line
|
|
100
119
|
location:
|
|
101
|
-
'<g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M12 2a9 9 0 0 1 9 9c0 3.074-1.676 5.59-3.442 7.395a20.4 20.4 0 0 1-2.876 2.416l-.426.29l-.2.133l-.377.24l-.336.205l-.416.242a1.87 1.87 0 0 1-1.854 0l-.416-.242l-.52-.32l-.192-.125l-.41-.273a20.6 20.6 0 0 1-3.093-2.566C4.676 16.589 3 14.074 3 11a9 9 0 0 1 9-9m0 2a7 7 0 0 0-7 7c0 2.322 1.272 4.36 2.871 5.996a18 18 0 0 0 2.222 1.91l.458.326q.222.155.427.288l.39.25l.343.209l.289.169l.455-.269l.367-.23q.293-.186.627-.417l.458-.326a18 18 0 0 0 2.222-1.91C17.728 15.361 19 13.322 19 11a7 7 0 0 0-7-7m0 3a4 4 0 1 1 0 8a4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4a2 2 0 0 0 0-4"/></g>'
|
|
120
|
+
'<g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M12 2a9 9 0 0 1 9 9c0 3.074-1.676 5.59-3.442 7.395a20.4 20.4 0 0 1-2.876 2.416l-.426.29l-.2.133l-.377.24l-.336.205l-.416.242a1.87 1.87 0 0 1-1.854 0l-.416-.242l-.52-.32l-.192-.125l-.41-.273a20.6 20.6 0 0 1-3.093-2.566C4.676 16.589 3 14.074 3 11a9 9 0 0 1 9-9m0 2a7 7 0 0 0-7 7c0 2.322 1.272 4.36 2.871 5.996a18 18 0 0 0 2.222 1.91l.458.326q.222.155.427.288l.39.25l.343.209l.289.169l.455-.269l.367-.23q.293-.186.627-.417l.458-.326a18 18 0 0 0 2.222-1.91C17.728 15.361 19 13.322 19 11a7 7 0 0 0-7-7m0 3a4 4 0 1 1 0 8a4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4a2 2 0 0 0 0-4"/></g>',
|
|
121
|
+
|
|
122
|
+
// === Aside ===
|
|
123
|
+
// mingcute:bulb-line
|
|
124
|
+
bulb: '<g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M13 20a1 1 0 1 1 0 2h-2a1 1 0 1 1 0-2zM12 2c4.41 0 8 3.543 8 7.933c0 3.006-1.522 5.196-2.78 6.494l-.284.283l-.27.252l-.252.22l-.33.27l-.328.244c-.196.138-.34.329-.466.535l-.145.251l-.141.252c-.24.412-.518.766-1.111.766h-3.786c-.593 0-.871-.354-1.11-.766l-.213-.378c-.145-.253-.305-.494-.54-.66l-.232-.171l-.199-.155l-.227-.188l-.252-.22l-.27-.252l-.285-.283C5.522 15.129 4 12.939 4 9.933C4 5.543 7.59 2 12 2m0 2C8.677 4 6 6.665 6 9.933c0 2.624 1.533 4.494 2.593 5.471l.245.218l.22.182l.27.208l.072.052c.315.222.549.531.762.854l.373.582h2.93l.373-.582c.213-.323.447-.632.762-.854l.243-.182l.206-.165l.233-.2C16.342 14.576 18 12.662 18 9.933C18 6.665 15.323 4 12 4m.293 2.293a1 1 0 0 1 1.497 1.32l-.083.094L12.414 9l1.286 1.286c.364.364.392.937.084 1.333l-.084.095l-1.993 1.993a1 1 0 0 1-1.497-1.32l.083-.094L11.586 11L10.3 9.714a1.01 1.01 0 0 1-.084-1.333l.084-.095z"/></g>',
|
|
125
|
+
// mingcute:alert-line
|
|
126
|
+
alert:
|
|
127
|
+
'<g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="m13.299 3.148l8.634 14.954a1.5 1.5 0 0 1-1.299 2.25H3.366a1.5 1.5 0 0 1-1.299-2.25l8.634-14.954c.577-1 2.02-1 2.598 0M12 4.898L4.232 18.352h15.536zM12 15a1 1 0 1 1 0 2a1 1 0 0 1 0-2m0-7a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V9a1 1 0 0 1 1-1"/></g>',
|
|
128
|
+
// mingcute:alert-octagon-line
|
|
129
|
+
octangon:
|
|
130
|
+
'<g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M15.314 2a2 2 0 0 1 1.414.586l4.686 4.686A2 2 0 0 1 22 8.686v6.628a2 2 0 0 1-.586 1.414l-4.686 4.686a2 2 0 0 1-1.414.586H8.686a2 2 0 0 1-1.414-.586l-4.686-4.686A2 2 0 0 1 2 15.314V8.686a2 2 0 0 1 .586-1.414l4.686-4.686A2 2 0 0 1 8.686 2zm0 2H8.686L4 8.686v6.628L8.686 20h6.628L20 15.314V8.686zM12 15a1 1 0 1 1 0 2a1 1 0 0 1 0-2m0-9a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0V7a1 1 0 0 1 1-1"/></g>'
|
|
102
131
|
}
|
|
103
132
|
|
|
104
133
|
export const Icons = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-pure",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "A simple, clean but powerful blog theme build by astro.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "CWorld",
|
|
@@ -35,10 +35,13 @@
|
|
|
35
35
|
"./libs": "./libs/index.ts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@astrojs/mdx": "^4.0.
|
|
38
|
+
"@astrojs/mdx": "^4.0.3",
|
|
39
39
|
"@astrojs/sitemap": "^3.2.1",
|
|
40
40
|
"@astrojs/tailwind": "^5.1.3",
|
|
41
|
+
"@pagefind/default-ui": "^1.3.0",
|
|
41
42
|
"astro": "^5.0.3",
|
|
43
|
+
"hast-util-select": "^6.0.3",
|
|
44
|
+
"node-html-parser": "^7.0.1",
|
|
42
45
|
"pagefind": "^1.2.0",
|
|
43
46
|
"rehype-external-links": "^3.0.0",
|
|
44
47
|
"tailwind-merge": "^2.5.5"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference types="astro/astro-jsx" />
|
|
2
|
+
|
|
3
|
+
import { parse, render, type DocumentNode, type Node } from 'ultrahtml'
|
|
4
|
+
|
|
5
|
+
export type SVGAttributes = Omit<
|
|
6
|
+
astroHTML.JSX.SVGAttributes,
|
|
7
|
+
'client:list' | 'set:text' | 'set:html' | 'is:raw'
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
const EMPTY_STRING_ERR = '`svgSource` must have content'
|
|
11
|
+
const MUST_START_WITH_SVG = '`svgSource` must begin with `<svg`'
|
|
12
|
+
|
|
13
|
+
export async function overrideSvgAttributes(
|
|
14
|
+
svgSource: string,
|
|
15
|
+
attributeOverrides: SVGAttributes = {}
|
|
16
|
+
): Promise<string> {
|
|
17
|
+
if (!svgSource) {
|
|
18
|
+
throw new Error(EMPTY_STRING_ERR)
|
|
19
|
+
}
|
|
20
|
+
if (!svgSource.trimStart().toLowerCase().startsWith('<svg')) {
|
|
21
|
+
throw new Error(MUST_START_WITH_SVG)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const doc = parse(svgSource) as DocumentNode
|
|
25
|
+
|
|
26
|
+
const firstSVGNode = doc.children.find(({ type, name }: Node) => type === 1 && /svg/i.test(name))
|
|
27
|
+
|
|
28
|
+
const mergedAttributes = Object.fromEntries(
|
|
29
|
+
Object.entries({
|
|
30
|
+
...firstSVGNode.attributes,
|
|
31
|
+
...attributeOverrides
|
|
32
|
+
}).filter(([, value]) => !!value)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const updatedSVG = {
|
|
36
|
+
...firstSVGNode,
|
|
37
|
+
attributes: mergedAttributes
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return render(updatedSVG)
|
|
41
|
+
}
|
|
@@ -2,6 +2,10 @@ import type { Node, Root } from 'mdast'
|
|
|
2
2
|
import type { Plugin } from 'unified'
|
|
3
3
|
import { visit } from 'unist-util-visit'
|
|
4
4
|
|
|
5
|
+
// Cannot use '../utils' for plugin absolute path
|
|
6
|
+
import mdastToString from '../utils/mdast-util-to-string'
|
|
7
|
+
import getReadingTime from '../utils/reading-time'
|
|
8
|
+
|
|
5
9
|
export const remarkAddZoomable: Plugin<[{ className?: string }], Root> = function ({
|
|
6
10
|
className = 'zoomable'
|
|
7
11
|
}) {
|
|
@@ -11,3 +15,16 @@ export const remarkAddZoomable: Plugin<[{ className?: string }], Root> = functio
|
|
|
11
15
|
})
|
|
12
16
|
}
|
|
13
17
|
}
|
|
18
|
+
|
|
19
|
+
export const remarkReadingTime: Plugin<[], Root> = function () {
|
|
20
|
+
return function (tree, { data }) {
|
|
21
|
+
const textOnPage = mdastToString(tree)
|
|
22
|
+
const readingTime = getReadingTime(textOnPage)
|
|
23
|
+
// readingTime.text will give us minutes read as a friendly string,
|
|
24
|
+
// i.e. "3 min read"
|
|
25
|
+
if (data.astro && data.astro.frontmatter) {
|
|
26
|
+
data.astro.frontmatter.minutesRead = readingTime.text
|
|
27
|
+
data.astro.frontmatter.words = readingTime.words
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
package/schemas/social.ts
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
import { z } from 'astro/zod'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
'github',
|
|
5
|
-
'gitlab',
|
|
6
|
-
'discord',
|
|
7
|
-
'youtube',
|
|
8
|
-
'instagram',
|
|
9
|
-
'x',
|
|
10
|
-
'telegram',
|
|
11
|
-
'rss',
|
|
12
|
-
'email',
|
|
13
|
-
'reddit',
|
|
14
|
-
'bluesky',
|
|
15
|
-
'tiktok',
|
|
16
|
-
'steam'
|
|
17
|
-
] as const
|
|
3
|
+
import { socialLinks } from '../types/constants'
|
|
18
4
|
|
|
19
5
|
export const SocialLinksSchema = () =>
|
|
20
6
|
z
|
|
@@ -42,7 +28,12 @@ export const SocialLinksSchema = () =>
|
|
|
42
28
|
reddit: 'Reddit',
|
|
43
29
|
bluesky: 'BlueSky',
|
|
44
30
|
tiktok: 'TikTok',
|
|
45
|
-
|
|
31
|
+
weibo: 'Weibo',
|
|
32
|
+
steam: 'Steam',
|
|
33
|
+
bilibili: 'Bilibili',
|
|
34
|
+
zhihu: 'Zhihu',
|
|
35
|
+
coolapk: 'Coolapk',
|
|
36
|
+
netease: 'NetEase'
|
|
46
37
|
}[key]
|
|
47
38
|
labelledLinks[key] = { label, url }
|
|
48
39
|
}
|
package/scripts/index.js
CHANGED
|
@@ -21,9 +21,9 @@ switch (args._[0]) {
|
|
|
21
21
|
console.log()
|
|
22
22
|
console.log('\x1b[46m%s\x1b[0m', ' Astro Theme Pure ')
|
|
23
23
|
console.log('\nInformation:')
|
|
24
|
-
console.log(`- Package
|
|
25
|
-
console.log(`- Node.js
|
|
26
|
-
console.log(`- Platform
|
|
24
|
+
console.log(`- Package:\t${packageJson.version}`)
|
|
25
|
+
console.log(`- Node.js:\t${process.version}`)
|
|
26
|
+
console.log(`- Platform:\t${process.platform}`)
|
|
27
27
|
break
|
|
28
28
|
case 'help':
|
|
29
29
|
console.log('Usage:')
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const socialLinks = [
|
|
2
|
+
'github',
|
|
3
|
+
'gitlab',
|
|
4
|
+
'discord',
|
|
5
|
+
'youtube',
|
|
6
|
+
'instagram',
|
|
7
|
+
'x',
|
|
8
|
+
'telegram',
|
|
9
|
+
'rss',
|
|
10
|
+
'email',
|
|
11
|
+
'reddit',
|
|
12
|
+
'bluesky',
|
|
13
|
+
'tiktok',
|
|
14
|
+
'weibo',
|
|
15
|
+
'steam',
|
|
16
|
+
'bilibili',
|
|
17
|
+
'zhihu',
|
|
18
|
+
'coolapk',
|
|
19
|
+
'netease'
|
|
20
|
+
] as const
|
package/types/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export const IntegrationConfigSchema = () =>
|
|
|
7
7
|
links: FriendLinksSchema(),
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Define whether
|
|
10
|
+
* Define whether default site search provider Pagefind is enabled.
|
|
11
11
|
* Set to `false` to disable indexing your site with Pagefind.
|
|
12
12
|
* This will also hide the default search UI if in use.
|
|
13
13
|
*/
|
package/types/theme-config.ts
CHANGED
|
@@ -117,7 +117,7 @@ export const ThemeConfigSchema = () =>
|
|
|
117
117
|
menu: HeaderMenuSchema()
|
|
118
118
|
}),
|
|
119
119
|
|
|
120
|
-
/** Configure the
|
|
120
|
+
/** Configure the footer of your site. */
|
|
121
121
|
footer: z.object({
|
|
122
122
|
/** Registration information for ICP (optional) */
|
|
123
123
|
registration: z.object({
|
package/utils/index.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type Options = {
|
|
2
|
+
includeImageAlt?: boolean
|
|
3
|
+
includeHtml?: boolean
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default function toString(value: unknown, options?: Options): string {
|
|
7
|
+
const { includeImageAlt = true, includeHtml = true } = options || {}
|
|
8
|
+
return serialize(value, includeImageAlt, includeHtml)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function serialize(value: unknown, includeImageAlt: boolean, includeHtml: boolean): string {
|
|
12
|
+
if (isNode(value)) {
|
|
13
|
+
if ('value' in value) {
|
|
14
|
+
return value.type === 'html' && !includeHtml ? '' : (value.value as string)
|
|
15
|
+
}
|
|
16
|
+
if (includeImageAlt && 'alt' in value && value.alt) {
|
|
17
|
+
return value.alt as string
|
|
18
|
+
}
|
|
19
|
+
if ('children' in value) {
|
|
20
|
+
return serializeAll(value.children as unknown[], includeImageAlt, includeHtml)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return serializeAll(value, includeImageAlt, includeHtml)
|
|
26
|
+
}
|
|
27
|
+
return ''
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function serializeAll(values: unknown[], includeImageAlt: boolean, includeHtml: boolean): string {
|
|
31
|
+
return values.map((value) => serialize(value, includeImageAlt, includeHtml)).join('')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isNode(value: unknown): value is Record<string, unknown> {
|
|
35
|
+
return Boolean(value && typeof value === 'object')
|
|
36
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a character is a CJK character
|
|
5
|
+
* @param {string} char - The character to check
|
|
6
|
+
* @returns {boolean} - Returns true if the character is CJK, otherwise false
|
|
7
|
+
*/
|
|
8
|
+
function isCJK(char: string): boolean {
|
|
9
|
+
const charCode = char.charCodeAt(0)
|
|
10
|
+
return (
|
|
11
|
+
(charCode >= 0x4e00 && charCode <= 0x9fff) || // CJK Unified Ideographs
|
|
12
|
+
(charCode >= 0x3400 && charCode <= 0x4dbf) || // CJK Unified Ideographs Extension A
|
|
13
|
+
(charCode >= 0x20000 && charCode <= 0x2a6df) || // CJK Unified Ideographs Extension B
|
|
14
|
+
(charCode >= 0x2a700 && charCode <= 0x2b73f) || // CJK Unified Ideographs Extension C
|
|
15
|
+
(charCode >= 0x2b740 && charCode <= 0x2b81f) || // CJK Unified Ideographs Extension D
|
|
16
|
+
(charCode >= 0x2b820 && charCode <= 0x2ceaf) || // CJK Unified Ideographs Extension E
|
|
17
|
+
(charCode >= 0xf900 && charCode <= 0xfaff) || // CJK Compatibility Ideographs
|
|
18
|
+
(charCode >= 0x2f800 && charCode <= 0x2fa1f) // CJK Compatibility Ideographs Supplement
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface ReadingTimeResult {
|
|
23
|
+
text: string
|
|
24
|
+
minutes: number
|
|
25
|
+
time: number
|
|
26
|
+
words: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Calculates the reading time of a text
|
|
31
|
+
* @param {string} text - The text to calculate
|
|
32
|
+
* @param {number} wordsPerMinute - The number of words read per minute, default is 200
|
|
33
|
+
* @returns {ReadingTimeResult} - An object containing the reading time
|
|
34
|
+
*/
|
|
35
|
+
export function getReadingTime(text: string, wordsPerMinute: number = 200): ReadingTimeResult {
|
|
36
|
+
let words = 0
|
|
37
|
+
const length = text.length
|
|
38
|
+
|
|
39
|
+
// Normalize text by adding a space at the end
|
|
40
|
+
const normalizedText = text + ' '
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < length; i++) {
|
|
43
|
+
const char = normalizedText[i]
|
|
44
|
+
|
|
45
|
+
// If the character is CJK, count it as a word
|
|
46
|
+
if (isCJK(char)) {
|
|
47
|
+
words++
|
|
48
|
+
// Skip subsequent punctuation and whitespace characters
|
|
49
|
+
while (i < length && (normalizedText[i + 1] === ' ' || isCJK(normalizedText[i + 1]))) {
|
|
50
|
+
i++
|
|
51
|
+
}
|
|
52
|
+
} else if (char === ' ' || char === '\n' || char === '\r') {
|
|
53
|
+
// Count the end of a word when encountering whitespace characters
|
|
54
|
+
if (
|
|
55
|
+
i > 0 &&
|
|
56
|
+
normalizedText[i - 1] !== ' ' &&
|
|
57
|
+
normalizedText[i - 1] !== '\n' &&
|
|
58
|
+
normalizedText[i - 1] !== '\r'
|
|
59
|
+
) {
|
|
60
|
+
words++
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Calculate reading time
|
|
66
|
+
const minutes = words / wordsPerMinute
|
|
67
|
+
const time = Math.round(minutes * 60 * 1000) // Convert to milliseconds
|
|
68
|
+
const displayed = Math.ceil(minutes)
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
text: displayed + ' min read',
|
|
72
|
+
minutes: minutes,
|
|
73
|
+
time: time,
|
|
74
|
+
words: words
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Export module
|
|
79
|
+
export default getReadingTime
|