Skip to content

Commit f59c962

Browse files
authored
feat(website): Custom Download URLs v0 (#747)
* feat(website): v0 of blueprint download urls * feat: correct head title
1 parent ab74ae7 commit f59c962

File tree

5 files changed

+144
-17
lines changed

5 files changed

+144
-17
lines changed

pnpm-lock.yaml

+5-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/docusaurus.config.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Config } from '@docusaurus/types'
22
import { themes as prismThemes } from 'prism-react-renderer'
33
import path from 'path'
4+
import blueprintDownloaderPlugin from './src/plugins/blueprint-downloader-plugin/blueprint-downloader-plugin.js'
45

56
// Create a custom plugin for webpack configuration
67
// the purpose of this plugin is to allow the use of the @blueprints alias
8+
// and to copy blueprint files as static assets
79
function webpackConfigPlugin() {
810
return {
911
name: 'webpack-config-plugin',
@@ -111,7 +113,7 @@ const config: Config = {
111113
},
112114
],
113115
],
114-
plugins: [webpackConfigPlugin],
116+
plugins: [webpackConfigPlugin, blueprintDownloaderPlugin],
115117
}
116118

117119
export default config

website/src/components/blueprints_docs/BlueprintImportCard.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ interface BlueprintImportCardProps {
1515

1616
function BlueprintImportCard({ category, id }: BlueprintImportCardProps) {
1717
const [copy, setCopy] = useState(false)
18-
const url = `https://github.com/EPMatt/awesome-ha-blueprints/blob/main/blueprints/${category}/${id}/${id}.yaml`
18+
// New custom URL format that will redirect to the GitHub URL
19+
const blueprintUrl = `https://epmatt.github.io/awesome-ha-blueprints/blueprints/${category}/${id}?version=latest`
20+
1921
const copyToClipboard = async () => {
20-
await navigator.clipboard.writeText(url)
22+
await navigator.clipboard.writeText(blueprintUrl)
2123
setCopy(true)
2224
}
2325
return (
@@ -32,7 +34,7 @@ function BlueprintImportCard({ category, id }: BlueprintImportCardProps) {
3234
<p>
3335
<a
3436
href={`https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=${escape(
35-
url,
37+
blueprintUrl,
3638
)}`}
3739
target='_blank'
3840
rel='noreferrer'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import glob from 'glob'
4+
5+
/**
6+
* Docusaurus plugin that generates routes for all blueprints
7+
* Routes follow the pattern: category/id
8+
*/
9+
export default function blueprintRoutesPlugin(context) {
10+
return {
11+
name: 'blueprint-routes-plugin',
12+
13+
async loadContent() {
14+
const { siteDir } = context
15+
const blueprintsDir = path.resolve(siteDir, '../blueprints')
16+
17+
const blueprintFiles = glob.sync('**/*.yaml', {
18+
cwd: blueprintsDir,
19+
absolute: true,
20+
})
21+
22+
const blueprints = []
23+
24+
for (const file of blueprintFiles) {
25+
try {
26+
// Extract category and id from file path
27+
const relativePath = path.relative(blueprintsDir, file)
28+
const pathParts = relativePath.split(path.sep)
29+
30+
// The first directory is the category
31+
const category = pathParts[0]
32+
33+
// The second directory is the blueprint ID
34+
const id = pathParts[1]
35+
36+
// Skip if not in the expected directory structure
37+
if (!category || !id) continue
38+
39+
// Read blueprint content - only get the raw content
40+
const rawContent = fs.readFileSync(file, 'utf8')
41+
42+
// Add blueprint metadata
43+
blueprints.push({
44+
id,
45+
category,
46+
path: relativePath,
47+
filePath: file,
48+
rawContent,
49+
})
50+
} catch (error) {
51+
console.error(`Error processing blueprint file ${file}:`, error)
52+
}
53+
}
54+
55+
return blueprints
56+
},
57+
58+
async contentLoaded({ content, actions }) {
59+
const { addRoute } = actions
60+
61+
// For each blueprint, create a route
62+
for (const blueprint of content) {
63+
// Add download route for this blueprint
64+
addRoute({
65+
path: `/awesome-ha-blueprints/blueprints/${blueprint.category}/${blueprint.id}`,
66+
component:
67+
'../src/plugins/blueprint-downloader-plugin/download-blueprint.tsx',
68+
exact: true,
69+
// extra props
70+
category: blueprint.category,
71+
id: blueprint.id,
72+
})
73+
}
74+
75+
console.log('Blueprint download routes created')
76+
},
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React, { useEffect } from 'react'
2+
// @ts-expect-error no types for this
3+
import { useLocation } from '@docusaurus/router'
4+
// @ts-expect-error no types for this
5+
import Head from '@docusaurus/Head'
6+
7+
export default function DownloadBlueprint(props: {
8+
route: { category: string; id: string }
9+
}) {
10+
const location = useLocation()
11+
const category = props.route.category
12+
const id = props.route.id
13+
14+
useEffect(() => {
15+
// Get query parameters
16+
const searchParams = new URLSearchParams(location.search)
17+
const version = searchParams.get('version') || 'latest'
18+
// Sanitize version - only allow 0-9, dot and a-z
19+
// eslint-disable-next-line
20+
const sanitizedVersion = version.replace(/[^0-9a-z.]/gi, '')
21+
22+
if (category && id) {
23+
// Redirect to GitHub repository
24+
const githubUrl = `https://raw.githubusercontent.com/EPMatt/awesome-ha-blueprints/main/blueprints/${category}/${id}/${id}.yaml`
25+
window.location.href = githubUrl
26+
} else {
27+
console.error(
28+
'Invalid blueprint id parameter format. Expected format: category/id',
29+
)
30+
}
31+
}, [location])
32+
33+
return (
34+
<>
35+
<Head>
36+
<title>
37+
Download {category}/{id}
38+
</title>
39+
</Head>
40+
<div
41+
style={{
42+
display: 'flex',
43+
justifyContent: 'center',
44+
alignItems: 'center',
45+
height: '50vh',
46+
fontSize: '20px',
47+
}}
48+
>
49+
<p>Downloading blueprint...</p>
50+
</div>
51+
</>
52+
)
53+
}

0 commit comments

Comments
 (0)