@sp-days-framework/slidev-theme-sykehuspartner 1.1.0-beta3 → 1.1.1-beta1
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/docs/advanced-configuration.mdx +31 -0
- package/docs/changelog.mdx +52 -11
- package/package.json +2 -1
- package/setup/vite-plugins.ts +153 -0
- package/uno.config.ts +90 -21
- package/utils/layoutHelper.ts +40 -6
|
@@ -32,6 +32,37 @@ Layouts with images support:
|
|
|
32
32
|
| `imagePosition` | string | varies | Position: `'left'` or `'right'` |
|
|
33
33
|
| `imageBackgroundMode` | boolean | varies | Background vs foreground mode |
|
|
34
34
|
|
|
35
|
+
### Image Path Resolution
|
|
36
|
+
|
|
37
|
+
The theme automatically resolves image paths in frontmatter, so you can use different path formats:
|
|
38
|
+
|
|
39
|
+
| Path Format | Example | Description |
|
|
40
|
+
|-------------|---------|-------------|
|
|
41
|
+
| **Relative** | `./image.png` | Relative to the markdown file |
|
|
42
|
+
| **Parent relative** | `../assets/img.png` | Navigate to parent directories |
|
|
43
|
+
| **Same directory** | `image.png` | File in same folder as markdown |
|
|
44
|
+
| **Public directory** | `/image.png` | Absolute path from `/public` folder |
|
|
45
|
+
| **External URL** | `https://...` | Remote images |
|
|
46
|
+
|
|
47
|
+
:::tip Relative Paths Recommended
|
|
48
|
+
Using relative paths (e.g., `./assets/diagram.png`) is recommended when working with the `docusaurus-plugin-slidev` integration. The theme's Vite plugin automatically resolves these paths and ensures images are correctly bundled during build.
|
|
49
|
+
:::
|
|
50
|
+
|
|
51
|
+
```markdown title="Example: Using relative image paths"
|
|
52
|
+
---
|
|
53
|
+
layout: image-left
|
|
54
|
+
imageSrc: ./assets/architecture.png
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
# Architecture Overview
|
|
58
|
+
|
|
59
|
+
This diagram shows our system design.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
:::note Public Directory
|
|
63
|
+
For images in the `/public` directory, use absolute paths starting with `/`. These are served as-is without processing.
|
|
64
|
+
:::
|
|
65
|
+
|
|
35
66
|
## Global Theme Configuration
|
|
36
67
|
|
|
37
68
|
Configure theme-wide settings in your presentation frontmatter:
|
package/docs/changelog.mdx
CHANGED
|
@@ -19,32 +19,73 @@ All packages within `@sp-days-framework` use the same version number. In some ca
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## Version 1.1.
|
|
22
|
+
## Version 1.1.1-beta1 
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Asset handling improvements for theme components
|
|
25
25
|
|
|
26
26
|
<details>
|
|
27
|
-
<summary><strong>Details</strong> (
|
|
27
|
+
<summary><strong>Beta Details</strong> (2026 January 12)</summary>
|
|
28
28
|
|
|
29
|
-
###
|
|
29
|
+
### New in Beta 1
|
|
30
30
|
|
|
31
|
-
-
|
|
32
|
-
- **two-cols-header**: Fixed h2 and h3 heading margins to be consistent with other layouts
|
|
33
|
-
- **end layout**: Fixed text centering so content is properly horizontally centered
|
|
31
|
+
- Enhanced asset handling to support improved resource management in Slidev presentations
|
|
34
32
|
|
|
35
33
|
</details>
|
|
36
34
|
|
|
37
35
|
---
|
|
38
36
|
|
|
39
|
-
## Version 1.1.
|
|
37
|
+
## Version 1.1.1-beta1 
|
|
38
|
+
|
|
39
|
+
Automatic relative image path resolution for image-based layouts
|
|
40
|
+
|
|
41
|
+
<details open>
|
|
42
|
+
<summary><strong>Details</strong> (2026 January 12)</summary>
|
|
43
|
+
|
|
44
|
+
### New Features
|
|
45
|
+
|
|
46
|
+
- **Relative Image Paths**: Image-based layouts (`image`, `image-left`, `image-right`, `intro`, `about-me`) now support relative paths in frontmatter (e.g., `imageSrc: ./assets/diagram.png`)
|
|
47
|
+
- **Vite Plugin**: Added `setup/vite-plugins.ts` that automatically transforms relative image paths into proper imports during build
|
|
48
|
+
- **Build Compatibility**: Images referenced with relative paths are now correctly bundled and hashed in production builds
|
|
49
|
+
|
|
50
|
+
### How It Works
|
|
51
|
+
|
|
52
|
+
The theme includes a Vite plugin that intercepts frontmatter and transforms relative image paths:
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
| Path Type | Example | Processed? |
|
|
55
|
+
|-----------|---------|------------|
|
|
56
|
+
| Relative | `./image.png`, `../assets/img.png` | ✅ Yes |
|
|
57
|
+
| Same directory | `image.png` | ✅ Yes |
|
|
58
|
+
| Absolute (public) | `/image.png` | ❌ No (served from public) |
|
|
59
|
+
| External URL | `https://...` | ❌ No |
|
|
60
|
+
| Data URI | `data:image/...` | ❌ No |
|
|
61
|
+
|
|
62
|
+
### Migration
|
|
63
|
+
|
|
64
|
+
No changes required. Existing presentations using `/public` directory paths continue to work. You can now also use relative paths for better portability.
|
|
65
|
+
|
|
66
|
+
</details>
|
|
42
67
|
|
|
43
68
|
---
|
|
44
69
|
|
|
45
|
-
## Version 1.1.0
|
|
70
|
+
## Version 1.1.0 
|
|
71
|
+
|
|
72
|
+
Bug fixes for VSCode icons and layout improvements
|
|
73
|
+
|
|
74
|
+
<details>
|
|
75
|
+
<summary><strong>Details</strong> (2026 January 07)</summary>
|
|
46
76
|
|
|
47
|
-
|
|
77
|
+
### Bug Fixes
|
|
78
|
+
|
|
79
|
+
- **uno.config.ts**: Fixed codeblock icon scanning to work correctly when the theme is installed as a dependency in other projects
|
|
80
|
+
- **uno.config.ts**: Fixed VSCode icons not appearing when built through `docusaurus-plugin-slidev` by adding support for `SLIDEV_ORIGINAL_SOURCE` and `SLIDEV_ORIGINAL_SOURCE_DIR` environment variables
|
|
81
|
+
- **two-cols-header**: Fixed h2 and h3 heading margins to be consistent with other layouts
|
|
82
|
+
- **end layout**: Fixed text centering so content is properly horizontally centered
|
|
83
|
+
|
|
84
|
+
### Improvements
|
|
85
|
+
|
|
86
|
+
- **Package Documentation**: Documentation is now bundled with the npm package for easier reference during development
|
|
87
|
+
|
|
88
|
+
</details>
|
|
48
89
|
|
|
49
90
|
---
|
|
50
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sp-days-framework/slidev-theme-sykehuspartner",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-beta1",
|
|
4
4
|
"description": "A Slidev theme for Sykehuspartner presentations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@slidev/types": "^52.9.1"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
+
"@iconify-json/vscode-icons": "^1.2.0",
|
|
40
41
|
"@slidev/cli": ">=52.0.0",
|
|
41
42
|
"@slidev/types": ">=52.0.0"
|
|
42
43
|
},
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite Plugin Setup for Sykehuspartner Slidev Theme
|
|
3
|
+
*
|
|
4
|
+
* This plugin automatically resolves relative image paths in frontmatter
|
|
5
|
+
* so they work correctly after build. Without this, images referenced in
|
|
6
|
+
* frontmatter like `imageSrc: ./image.png` would break after build because
|
|
7
|
+
* Vite can't statically analyze frontmatter values.
|
|
8
|
+
*
|
|
9
|
+
* The plugin intercepts the frontmatter virtual modules generated by Slidev
|
|
10
|
+
* and transforms relative image paths into proper imports.
|
|
11
|
+
*/
|
|
12
|
+
import { defineVitePluginsSetup } from '@slidev/types'
|
|
13
|
+
import type { Plugin } from 'vite'
|
|
14
|
+
import { resolve, dirname, isAbsolute } from 'node:path'
|
|
15
|
+
import { existsSync } from 'node:fs'
|
|
16
|
+
|
|
17
|
+
// Image properties that should be resolved in frontmatter
|
|
18
|
+
const IMAGE_PROPS = [
|
|
19
|
+
'imageSrc',
|
|
20
|
+
'background',
|
|
21
|
+
'image',
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
// Supported image extensions
|
|
25
|
+
const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'avif', 'ico']
|
|
26
|
+
const IMAGE_EXT_PATTERN = IMAGE_EXTENSIONS.join('|')
|
|
27
|
+
|
|
28
|
+
export default defineVitePluginsSetup((options) => {
|
|
29
|
+
const { userRoot, data } = options
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Plugin that transforms frontmatter image paths into imports
|
|
33
|
+
*/
|
|
34
|
+
const frontmatterImagePlugin: Plugin = {
|
|
35
|
+
name: 'slidev-theme-sykehuspartner:frontmatter-images',
|
|
36
|
+
enforce: 'post', // Run after Slidev's loader generates the frontmatter module
|
|
37
|
+
|
|
38
|
+
transform(code, id) {
|
|
39
|
+
// Only process frontmatter virtual modules from Slidev
|
|
40
|
+
if (!id.includes('__slidev_') || !id.endsWith('.frontmatter')) {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Find the slide's markdown file path to resolve relative images
|
|
45
|
+
const slideMatch = id.match(/(.+?)__slidev_(\d+)\.frontmatter$/)
|
|
46
|
+
if (!slideMatch) return null
|
|
47
|
+
|
|
48
|
+
const mdFilePath = slideMatch[1]
|
|
49
|
+
const mdDir = dirname(mdFilePath)
|
|
50
|
+
|
|
51
|
+
// Regex to find relative image paths in frontmatter properties
|
|
52
|
+
// Matches: "imageSrc": "./image.png" or 'imageSrc': './image.png'
|
|
53
|
+
// Also matches paths without ./ prefix like "image.png"
|
|
54
|
+
const relativePathRegex = new RegExp(
|
|
55
|
+
`(["'])((?:\\.\\/|\\.\\.\\/|(?![/]|https?:|data:))[^"']*\\.(${IMAGE_EXT_PATTERN}))\\1`,
|
|
56
|
+
'gi'
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
const matches = [...code.matchAll(relativePathRegex)]
|
|
60
|
+
|
|
61
|
+
if (matches.length === 0) {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Track unique imports to avoid duplicates
|
|
66
|
+
const imports: Map<string, string> = new Map()
|
|
67
|
+
let importIndex = 0
|
|
68
|
+
let newCode = code
|
|
69
|
+
|
|
70
|
+
for (const match of matches) {
|
|
71
|
+
const fullMatch = match[0]
|
|
72
|
+
const quote = match[1]
|
|
73
|
+
const relativePath = match[2]
|
|
74
|
+
|
|
75
|
+
// Resolve the absolute path to check if file exists
|
|
76
|
+
const absolutePath = resolve(mdDir, relativePath)
|
|
77
|
+
|
|
78
|
+
// Only transform if the file actually exists
|
|
79
|
+
if (!existsSync(absolutePath)) {
|
|
80
|
+
console.warn(`[slidev-theme-sykehuspartner] Image not found: ${relativePath} (resolved to ${absolutePath})`)
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get or create import variable name for this path
|
|
85
|
+
let varName = imports.get(relativePath)
|
|
86
|
+
if (!varName) {
|
|
87
|
+
varName = `__spImg${importIndex++}`
|
|
88
|
+
imports.set(relativePath, varName)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Replace the string path with the import variable
|
|
92
|
+
// "imageSrc": "./image.png" becomes "imageSrc": __spImg0
|
|
93
|
+
newCode = newCode.replace(fullMatch, varName)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (imports.size === 0) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Generate import statements
|
|
101
|
+
const importStatements = Array.from(imports.entries())
|
|
102
|
+
.map(([path, varName]) => `import ${varName} from "${path}"`)
|
|
103
|
+
.join('\n')
|
|
104
|
+
|
|
105
|
+
// Prepend imports to the module code
|
|
106
|
+
const transformedCode = importStatements + '\n' + newCode
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
code: transformedCode,
|
|
110
|
+
map: null, // Source map not needed for this transformation
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Plugin that ensures images referenced in layouts are resolved correctly
|
|
117
|
+
* This handles the case where images are passed as props to layout components
|
|
118
|
+
*/
|
|
119
|
+
const layoutImagePlugin: Plugin = {
|
|
120
|
+
name: 'slidev-theme-sykehuspartner:layout-images',
|
|
121
|
+
enforce: 'pre',
|
|
122
|
+
|
|
123
|
+
async resolveId(source, importer) {
|
|
124
|
+
// Only process if importer is a markdown slide file
|
|
125
|
+
if (!importer || !importer.includes('__slidev_')) {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check if this looks like a relative image path
|
|
130
|
+
const isRelativePath = source.startsWith('./') || source.startsWith('../')
|
|
131
|
+
const isImageFile = new RegExp(`\\.(${IMAGE_EXT_PATTERN})$`, 'i').test(source)
|
|
132
|
+
|
|
133
|
+
if (isRelativePath && isImageFile) {
|
|
134
|
+
// Find the original markdown file path
|
|
135
|
+
const mdMatch = importer.match(/(.+?)__slidev_\d+/)
|
|
136
|
+
if (mdMatch) {
|
|
137
|
+
const mdDir = dirname(mdMatch[1])
|
|
138
|
+
const resolved = resolve(mdDir, source)
|
|
139
|
+
if (existsSync(resolved)) {
|
|
140
|
+
return resolved
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return null
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return [
|
|
150
|
+
frontmatterImagePlugin,
|
|
151
|
+
layoutImagePlugin,
|
|
152
|
+
]
|
|
153
|
+
})
|
package/uno.config.ts
CHANGED
|
@@ -1,48 +1,117 @@
|
|
|
1
1
|
import { defineConfig } from 'unocss'
|
|
2
2
|
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
3
4
|
import { globSync } from 'glob'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Scans markdown files for VSCode icon patterns used in code blocks.
|
|
8
|
+
* Icons are referenced with syntax: ~i-vscode-icons:file-type-name~
|
|
9
|
+
*
|
|
10
|
+
* When built through docusaurus-plugin-slidev, uses environment variables:
|
|
11
|
+
* - SLIDEV_ORIGINAL_SOURCE: Path to the original markdown file
|
|
12
|
+
* - SLIDEV_ORIGINAL_SOURCE_DIR: Directory containing the source file
|
|
13
|
+
* - SLIDEV_SITE_DIR: The Docusaurus site directory
|
|
14
|
+
*/
|
|
15
|
+
function scanFilesForIcons(): string[] {
|
|
7
16
|
try {
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
// Try multiple strategies to find markdown files
|
|
18
|
+
const searchRoots: string[] = [
|
|
19
|
+
process.cwd(),
|
|
20
|
+
path.resolve(process.cwd(), 'slidev'),
|
|
21
|
+
path.resolve(process.cwd(), '..'),
|
|
22
|
+
path.resolve(process.cwd(), '.docusaurus'),
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// Add paths from docusaurus-plugin-slidev environment variables
|
|
26
|
+
if (process.env.SLIDEV_ORIGINAL_SOURCE_DIR) {
|
|
27
|
+
searchRoots.push(process.env.SLIDEV_ORIGINAL_SOURCE_DIR)
|
|
28
|
+
}
|
|
29
|
+
if (process.env.SLIDEV_SITE_DIR) {
|
|
30
|
+
searchRoots.push(process.env.SLIDEV_SITE_DIR)
|
|
31
|
+
searchRoots.push(path.resolve(process.env.SLIDEV_SITE_DIR, 'slidev'))
|
|
32
|
+
}
|
|
11
33
|
|
|
12
34
|
// Pattern to match icon references like ~i-vscode-icons:file-type-ansible~
|
|
13
35
|
const iconPattern = /~(i-[a-zA-Z0-9-]+:[a-zA-Z0-9-]+)~/g
|
|
14
36
|
|
|
15
|
-
// Set to store unique icons
|
|
16
|
-
const icons = new Set([
|
|
37
|
+
// Set to store unique icons - include common defaults
|
|
38
|
+
const icons = new Set([
|
|
39
|
+
'i-vscode-icons:file-type-docker',
|
|
40
|
+
'i-vscode-icons:file-type-python',
|
|
41
|
+
'i-vscode-icons:file-type-typescript-official',
|
|
42
|
+
'i-vscode-icons:file-type-js-official',
|
|
43
|
+
'i-vscode-icons:file-type-yaml',
|
|
44
|
+
'i-vscode-icons:file-type-json',
|
|
45
|
+
'i-vscode-icons:file-type-markdown',
|
|
46
|
+
'i-vscode-icons:file-type-vue',
|
|
47
|
+
'i-vscode-icons:file-type-html',
|
|
48
|
+
'i-vscode-icons:file-type-css',
|
|
49
|
+
'i-vscode-icons:file-type-shell',
|
|
50
|
+
'i-vscode-icons:file-type-powershell',
|
|
51
|
+
'i-vscode-icons:file-type-git',
|
|
52
|
+
'i-vscode-icons:file-type-ansible',
|
|
53
|
+
'i-vscode-icons:file-type-terraform',
|
|
54
|
+
'i-vscode-icons:file-type-kubernetes',
|
|
55
|
+
])
|
|
17
56
|
|
|
18
|
-
//
|
|
19
|
-
|
|
57
|
+
// Read the original source file directly if available (from docusaurus-plugin-slidev)
|
|
58
|
+
if (process.env.SLIDEV_ORIGINAL_SOURCE && fs.existsSync(process.env.SLIDEV_ORIGINAL_SOURCE)) {
|
|
20
59
|
try {
|
|
21
|
-
const content = fs.readFileSync(
|
|
60
|
+
const content = fs.readFileSync(process.env.SLIDEV_ORIGINAL_SOURCE, 'utf-8')
|
|
22
61
|
let match
|
|
23
62
|
while ((match = iconPattern.exec(content)) !== null) {
|
|
24
63
|
if (match[1]) {
|
|
25
64
|
icons.add(match[1])
|
|
26
65
|
}
|
|
27
66
|
}
|
|
28
|
-
} catch
|
|
29
|
-
|
|
67
|
+
} catch {
|
|
68
|
+
// Silently ignore read errors
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Scan from each root
|
|
73
|
+
for (const searchRoot of searchRoots) {
|
|
74
|
+
try {
|
|
75
|
+
if (!fs.existsSync(searchRoot)) continue
|
|
76
|
+
|
|
77
|
+
// Find all markdown files, excluding node_modules but INCLUDE .docusaurus
|
|
78
|
+
const slideFiles = globSync('**/*.md', {
|
|
79
|
+
absolute: true,
|
|
80
|
+
cwd: searchRoot,
|
|
81
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'],
|
|
82
|
+
dot: true
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Scan each file for icon patterns
|
|
86
|
+
slideFiles.forEach((file: string) => {
|
|
87
|
+
try {
|
|
88
|
+
const content = fs.readFileSync(file, 'utf-8')
|
|
89
|
+
let match
|
|
90
|
+
while ((match = iconPattern.exec(content)) !== null) {
|
|
91
|
+
if (match[1]) {
|
|
92
|
+
icons.add(match[1])
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Silently ignore read errors
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
} catch {
|
|
100
|
+
// Silently ignore scan errors
|
|
30
101
|
}
|
|
31
|
-
}
|
|
102
|
+
}
|
|
32
103
|
|
|
33
|
-
return Array.from(icons)
|
|
34
|
-
} catch
|
|
35
|
-
|
|
36
|
-
return ['i-vscode-icons:file-type-docker']
|
|
104
|
+
return Array.from(icons) as string[]
|
|
105
|
+
} catch {
|
|
106
|
+
// Return default icon on error
|
|
107
|
+
return ['i-vscode-icons:file-type-docker']
|
|
37
108
|
}
|
|
38
109
|
}
|
|
39
110
|
|
|
40
111
|
export default defineConfig({
|
|
41
112
|
safelist: [
|
|
42
|
-
// Static icons that should always be included
|
|
43
|
-
'i-vscode-icons:file-type-docker',
|
|
44
|
-
|
|
45
113
|
// Dynamically scan for icons in slide files
|
|
46
|
-
|
|
114
|
+
// This returns an array of icon class names that should be included
|
|
115
|
+
...scanFilesForIcons()
|
|
47
116
|
],
|
|
48
117
|
})
|
package/utils/layoutHelper.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import type { CSSProperties } from "vue";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Resolve image paths for use in layouts.
|
|
5
|
+
*
|
|
6
|
+
* This function handles multiple types of image paths:
|
|
7
|
+
* - Already resolved paths (from Vite plugin transformation) - returned as-is
|
|
8
|
+
* - Full URLs (http/https) - returned as-is
|
|
9
|
+
* - Data URLs (data:) - returned as-is
|
|
10
|
+
* - Blob URLs (blob:) - returned as-is
|
|
11
|
+
* - Root-relative paths (/path) - returned as-is
|
|
12
|
+
* - Colors (#hex, rgb) - returned as-is
|
|
13
|
+
* - Relative paths (./path, path) - converted to root-relative
|
|
14
|
+
*
|
|
15
|
+
* When the vite-plugins.ts is active, relative paths in frontmatter are
|
|
16
|
+
* automatically transformed into resolved import URLs before reaching
|
|
17
|
+
* this function, so they'll be handled by the "already resolved" case.
|
|
6
18
|
*/
|
|
7
19
|
export function getImageUrl(path?: string): string {
|
|
8
20
|
if (!path) return "";
|
|
@@ -10,14 +22,36 @@ export function getImageUrl(path?: string): string {
|
|
|
10
22
|
// If it's a color, don't process it
|
|
11
23
|
if (path.startsWith("#") || path.startsWith("rgb")) return path;
|
|
12
24
|
|
|
13
|
-
// If it's a
|
|
14
|
-
|
|
25
|
+
// If it's already a resolved URL (from Vite import), use as-is
|
|
26
|
+
// This includes:
|
|
27
|
+
// - Data URLs: data:image/...
|
|
28
|
+
// - Blob URLs: blob:...
|
|
29
|
+
// - Full URLs: http:// or https://
|
|
30
|
+
// - Vite asset URLs: /assets/image.hash.png or /@fs/...
|
|
31
|
+
if (
|
|
32
|
+
path.startsWith("data:") ||
|
|
33
|
+
path.startsWith("blob:") ||
|
|
34
|
+
path.match(/^https?:\/\//) ||
|
|
35
|
+
path.startsWith("/@fs/") ||
|
|
36
|
+
path.match(/^\/assets\//)
|
|
37
|
+
) {
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
15
40
|
|
|
16
41
|
// If it's a root-relative path (starts with /), use it as is
|
|
17
42
|
if (path.startsWith("/")) return path;
|
|
18
43
|
|
|
19
|
-
//
|
|
20
|
-
|
|
44
|
+
// For relative paths, try to use the base URL if available
|
|
45
|
+
// This handles the case where images are in the public folder
|
|
46
|
+
const baseUrl = typeof import.meta !== 'undefined'
|
|
47
|
+
? (import.meta.env?.BASE_URL || '/')
|
|
48
|
+
: '/';
|
|
49
|
+
|
|
50
|
+
// Remove ./ prefix if present
|
|
51
|
+
const cleanPath = path.startsWith("./") ? path.slice(2) : path;
|
|
52
|
+
|
|
53
|
+
// Return with base URL
|
|
54
|
+
return `${baseUrl}${cleanPath}`;
|
|
21
55
|
}
|
|
22
56
|
|
|
23
57
|
/**
|