astro-pure 1.4.1 → 1.4.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.
@@ -19,3 +19,9 @@ const { content, class: className, ...props } = Astro.props
19
19
  if (!qrcodeContainer) throw new Error('qrcode container not found')
20
20
  loadQRcode(qrcodeContainer)
21
21
  </script>
22
+
23
+ <style>
24
+ #qrcode-container :global(canvas) {
25
+ width: 100%;
26
+ }
27
+ </style>
@@ -25,7 +25,6 @@ const footerLink1 = footerConf.links?.filter(({ pos }) => pos === 1) || []
25
25
  <div>
26
26
  {footerLink1.map(({ title, link, style }, index) => (
27
27
  <>
28
- <!- prettier-ignore -->
29
28
  <a href={link} target='_blank' class={style}>{title}</a>
30
29
  {index < footerLink1.length - 1 && <span class='mx-1'>•</span>}
31
30
  </>
@@ -27,6 +27,7 @@ import { Icon } from '../user'
27
27
  href={item.link}
28
28
  class='w-full flex-none grow py-2 text-right font-medium transition-none hover:text-primary sm:w-fit sm:px-3'
29
29
  aria-label='Nav menu item'
30
+ data-astro-prefetch
30
31
  >
31
32
  {item.title}
32
33
  </a>
@@ -5,7 +5,7 @@ const { header: headerName, content: contentName, needPercent = true } = Astro.p
5
5
  ---
6
6
 
7
7
  <div
8
- class='z-10 group fixed bottom-8 end-4 transition-all flex flex-col gap-y-4 sm:end-8'
8
+ class='z-10 md:z-50 group fixed bottom-8 end-4 transition-all flex flex-col gap-y-4 sm:end-8'
9
9
  id='action-buttons'
10
10
  >
11
11
  <slot name='other-icons' />
@@ -43,7 +43,7 @@ const shares = {
43
43
  {/* title & link */}
44
44
  <div class='flex flex-col'>
45
45
  <div class='font-medium text-foreground'>{title}</div>
46
- <div class='text-sm'>{Astro.url}</div>
46
+ <div class='text-sm line-clamp-1'>{Astro.url}</div>
47
47
  </div>
48
48
 
49
49
  {/* common info */}
@@ -127,7 +127,7 @@ const shares = {
127
127
  <style>
128
128
  #qrcode-container.expanded {
129
129
  max-height: 11rem;
130
- transform: translateY(4px);
130
+ transform: translateY(6px);
131
131
  opacity: 100;
132
132
  }
133
133
  </style>
@@ -17,21 +17,21 @@ import '@pagefind/default-ui/css/ui.css'
17
17
  </site-search>
18
18
 
19
19
  <script>
20
+ // const shouldStrip = this.dataset.stripTrailingSlash !== undefined
21
+ // const stripTrailingSlash = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
22
+ // const formatURL = shouldStrip ? stripTrailingSlash : (path: string) => path
23
+ const formatURL = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
24
+
20
25
  class SiteSearch extends HTMLElement {
21
26
  constructor() {
22
27
  super()
23
- // const shouldStrip = this.dataset.stripTrailingSlash !== undefined
24
- // const stripTrailingSlash = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
25
- // const formatURL = shouldStrip ? stripTrailingSlash : (path: string) => path
26
- const formatURL = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2')
27
-
28
28
  window.addEventListener('DOMContentLoaded', () => {
29
29
  // if (import.meta.env.DEV) return
30
30
  const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1))
31
31
  onIdle(async () => {
32
32
  // @ts-expect-error — Missing types for @pagefind/default-ui package.
33
33
  const { PagefindUI } = await import('@pagefind/default-ui')
34
- new PagefindUI({
34
+ const pagefindUI = new PagefindUI({
35
35
  element: '#site-search',
36
36
  baseUrl: import.meta.env.BASE_URL,
37
37
  bundlePath: `${import.meta.env.BASE_URL.replace(/\/$/, '')}/pagefind/`,
@@ -139,11 +139,15 @@ const postDate = data.updatedDate ?? data.publishDate
139
139
  }
140
140
  }
141
141
  .cover-image {
142
+ -webkit-mask-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
143
+ -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
142
144
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
143
145
  }
144
146
 
145
147
  @media (max-width: 768px) {
146
148
  .cover-image {
149
+ -webkit-mask-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
150
+ -webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
147
151
  mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
148
152
  }
149
153
  }
package/index.ts CHANGED
@@ -3,13 +3,14 @@ import { dirname, relative } from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  // Astro
5
5
  import type { AstroIntegration, RehypePlugins, RemarkPlugins } from 'astro'
6
- import { AstroError } from 'astro/errors'
7
6
  // Integrations
8
7
  import mdx from '@astrojs/mdx'
9
8
  import sitemap from '@astrojs/sitemap'
9
+ import { AstroError } from 'astro/errors'
10
10
  import UnoCSS from 'unocss/astro'
11
11
 
12
12
  import rehypeExternalLinks from './plugins/rehype-external-links'
13
+ import rehypeImageCaption from './plugins/rehype-image-caption'
13
14
  import rehypeTable from './plugins/rehype-table'
14
15
  import { remarkAddZoomable, remarkReadingTime } from './plugins/remark-plugins'
15
16
  import { vitePluginUserConfig } from './plugins/virtual-user-config'
@@ -64,6 +65,8 @@ export default function AstroPureIntegration(opts: UserInputConfig): AstroIntegr
64
65
  ])
65
66
  // Make table scrollable on overflow
66
67
  rehypePlugins.push(rehypeTable)
68
+ // Add image caption support
69
+ if (userConfig.content.imageCaption) rehypePlugins.push(rehypeImageCaption)
67
70
 
68
71
  // Add Starlight directives restoration integration at the end of the list so that remark
69
72
  // plugins injected by Starlight plugins through Astro integrations can handle text and
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "astro-pure",
3
3
  "type": "module",
4
4
  "description": "A simple, clean but powerful blog theme build by astro.",
5
- "version": "1.4.1",
5
+ "version": "1.4.3",
6
6
  "homepage": "https://astro-pure.js.org/",
7
7
  "author": "CWorld",
8
8
  "license": "Apache-2.0",
@@ -37,14 +37,17 @@
37
37
  "./libs": "./libs/index.ts"
38
38
  },
39
39
  "dependencies": {
40
- "@astrojs/mdx": "^4.3.13",
41
- "@astrojs/sitemap": "^3.6.0",
42
- "@pagefind/default-ui": "^1.4.0",
43
- "@unocss/reset": "^66.5.10",
44
- "astro": "^5.16.6",
40
+ "@astrojs/mdx": "5.0.3",
41
+ "@astrojs/sitemap": "3.7.2",
42
+ "@pagefind/default-ui": "^1.5.0",
43
+ "astro": "6.1.3",
45
44
  "hast-util-select": "^6.0.4",
46
- "node-html-parser": "^7.0.1",
47
- "pagefind": "^1.4.0",
48
- "unocss": "^66.5.10"
45
+ "node-html-parser": "^7.1.0",
46
+ "pagefind": "^1.5.0"
47
+ },
48
+ "devDependencies": {
49
+ "@unocss/astro": "^66.6.8",
50
+ "@unocss/reset": "^66.6.7",
51
+ "unocss": "^66.6.8"
49
52
  }
50
53
  }
@@ -89,14 +89,14 @@ async function parseOpenGraph(pageUrl: string) {
89
89
  const description = getMetaProperty('og:description') || getMetaName('description')
90
90
  const image = urlOrNull(
91
91
  getMetaProperty('og:image:secure_url') ||
92
- getMetaProperty('og:image:url') ||
93
- getMetaProperty('og:image')
92
+ getMetaProperty('og:image:url') ||
93
+ getMetaProperty('og:image')
94
94
  )
95
95
  const imageAlt = getMetaProperty('og:image:alt')
96
96
  const video = urlOrNull(
97
97
  getMetaProperty('og:video:secure_url') ||
98
- getMetaProperty('og:video:url') ||
99
- getMetaProperty('og:video')
98
+ getMetaProperty('og:video:url') ||
99
+ getMetaProperty('og:video')
100
100
  )
101
101
  const videoType = getMetaProperty('og:video:type')
102
102
  const url =
@@ -0,0 +1,42 @@
1
+ // https://github.com/Saramanda9988/blog-pure/blob/luna-pure/packages/pure/plugins/rehype-image-caption.ts
2
+ import type { Element, Root } from 'hast'
3
+ import type { Plugin } from 'unified'
4
+ import { visit } from 'unist-util-visit'
5
+
6
+ /**
7
+ * Rehype plugin to wrap images with alt text in a figure element with figcaption
8
+ */
9
+ const rehypeImageCaption: Plugin<[], Root> = () => {
10
+ return (tree) => {
11
+ visit(tree, 'element', (node, index, parent) => {
12
+ // Only process <img> elements that have alt text
13
+ if (
14
+ node.tagName === 'img' &&
15
+ typeof node.properties?.alt === 'string' &&
16
+ node.properties.alt.trim() !== '' &&
17
+ parent &&
18
+ typeof index === 'number'
19
+ ) {
20
+ const altText = node.properties.alt as string
21
+ // Create figcaption element
22
+ const figcaption: Element = {
23
+ type: 'element',
24
+ tagName: 'figcaption',
25
+ properties: {},
26
+ children: [{ type: 'text', value: altText }]
27
+ }
28
+ // Create figure element wrapping the image
29
+ const figure: Element = {
30
+ type: 'element',
31
+ tagName: 'figure',
32
+ properties: { style: 'text-align:center' },
33
+ children: [node, figcaption]
34
+ }
35
+ // Replace the img node with the figure node
36
+ parent.children[index] = figure
37
+ }
38
+ })
39
+ }
40
+ }
41
+
42
+ export default rehypeImageCaption
@@ -63,17 +63,17 @@ module.exports = (args, opts) => {
63
63
  })
64
64
  })
65
65
 
66
- ;[]
67
- .concat(opts.string)
68
- .filter(Boolean)
69
- .forEach((key) => {
70
- flags.strings[key] = true
71
- if (aliases[key]) {
72
- ;[].concat(aliases[key]).forEach((k) => {
73
- flags.strings[k] = true
74
- })
75
- }
76
- })
66
+ ;[]
67
+ .concat(opts.string)
68
+ .filter(Boolean)
69
+ .forEach((key) => {
70
+ flags.strings[key] = true
71
+ if (aliases[key]) {
72
+ ;[].concat(aliases[key]).forEach((k) => {
73
+ flags.strings[k] = true
74
+ })
75
+ }
76
+ })
77
77
 
78
78
  var defaults = opts.default || {}
79
79
 
@@ -145,9 +145,9 @@ module.exports = (args, opts) => {
145
145
  key.split('.'),
146
146
  value
147
147
  )
148
- ;(aliases[key] || []).forEach((x) => {
149
- setKey(argv, x.split('.'), value)
150
- })
148
+ ; (aliases[key] || []).forEach((x) => {
149
+ setKey(argv, x.split('.'), value)
150
+ })
151
151
  }
152
152
 
153
153
  Object.keys(flags.bools).forEach((key) => {
@@ -164,8 +164,6 @@ module.exports = (args, opts) => {
164
164
  var i, arg, key, next, m, value, letters, broken, j
165
165
  for (i = 0; i < args.length; i++) {
166
166
  arg = args[i]
167
- key
168
- next
169
167
 
170
168
  if (/^--.+=/.test(arg)) {
171
169
  // Using [\s\S] instead of . because js doesn't support the
@@ -264,9 +262,9 @@ module.exports = (args, opts) => {
264
262
  if (!hasKey(argv, k.split('.'))) {
265
263
  setKey(argv, k.split('.'), defaults[k])
266
264
 
267
- ;(aliases[k] || []).forEach((x) => {
268
- setKey(argv, x.split('.'), defaults[k])
269
- })
265
+ ; (aliases[k] || []).forEach((x) => {
266
+ setKey(argv, x.split('.'), defaults[k])
267
+ })
270
268
  }
271
269
  })
272
270
 
@@ -184,7 +184,10 @@ export const ThemeConfigSchema = () =>
184
184
  blogPageSize: z.number().optional().default(8),
185
185
 
186
186
  /** Share buttons to show */
187
- share: ShareSchema()
187
+ share: ShareSchema(),
188
+
189
+ /** Enable image captions (default false) */
190
+ imageCaption: z.boolean().default(false).describe('Enable image captions')
188
191
  })
189
192
  })
190
193
 
@@ -89,7 +89,7 @@ const errorMap: z.ZodErrorMap = (baseError, ctx) => {
89
89
  .map(([key, error]) =>
90
90
  key === baseErrorPath
91
91
  ? // Avoid printing the key again if it's a base error
92
- `> ${getTypeOrLiteralMsg(error)}`
92
+ `> ${getTypeOrLiteralMsg(error)}`
93
93
  : `> ${prefix(key, getTypeOrLiteralMsg(error))}`
94
94
  )
95
95
 
package/virtual.d.ts CHANGED
@@ -1 +1,4 @@
1
- /// <reference path="./types/module.d.ts" />
1
+ declare module 'virtual:config' {
2
+ const Config: import('./types/user-config').UserConfig
3
+ export default Config
4
+ }
package/types/module.d.ts DELETED
@@ -1,4 +0,0 @@
1
- declare module 'virtual:config' {
2
- const Config: import('./user-config').UserConfig
3
- export default Config
4
- }