Skip to content

Commit

Permalink
Merge pull request #485 from LunarN0va/feature/locally-hosted-cdn-dep…
Browse files Browse the repository at this point in the history
…endency

Support locally hosted CDN dependencies
  • Loading branch information
jp7677 authored Apr 15, 2024
2 parents b9341ed + 5a2ca83 commit 71e4dd0
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 86 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,19 +256,20 @@ and limitations for this exporter.
The look and feel of the generated site can be customized with several additional view properties in the C4
architecture model:

| Property name | Description | Default | Example |
|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------------------------------------------------|
| `generatr.style.colors.primary` | Primary site color, used for header bar background and active menu background. | `#333333` | `#485fc7` |
| `generatr.style.colors.secondary` | Secondary site color, used for font color in header bar and for active menu. | `#cccccc` | `#ffffff` |
| `generatr.style.faviconPath` | Site logo location relative to the configured `assets` folder. When configured, the logo image will be place on the left side in the header bar. This requires the `--assets-dir` switch when generating the site and the corresponding file to be available in the `assets` folder. | | `site/favicon.ico` |
| `generatr.style.logoPath` | Site favicon location relative to the configured `assets` folder. When configured, the favicon will be set for all generated pages. This requires the `--assets-dir` switch when generating the site and the corresponding file to be available in the `assets` folder. | | `site/logo.png` |
| `generatr.style.customStylesheet` | URL to hosted custom stylesheet or path to custom stylesheet file (location relative to the configured `assets` folder). When configured this css file will be loaded for all pages. When using a path to a file the `--assets-dir` switch must be used when generating the site and the corresponding file is available in the `assets` folder. | | `site/custom.css` or 'https://uri.example/custom.css |
| `generatr.search.language` | Indexing/stemming language for the search index. See [Lunr language support](https://github.com/olivernn/lunr-languages) | `en` | `nl` |
| `generatr.markdown.flexmark.extensions` | Additional extensions to the markdown generator to add new markdown capabilities. [More Details](https://avisi-cloud.github.io/structurizr-site-generatr/main/extended-markdown-features/) | Tables | `Tables,Admonition` |
| `generatr.svglink.target` | Specifies the link target for element links in the exported svg | `_top` | `_self` |
| `generatr.site.exporter` | Specifies the UML exporter, can be `c4` (uses the `C4PlantUMLExporter`) or `structurizr` (uses the `StructurizrPlantUMLExporter`) | `c4` | `structurizr` |
| `generatr.site.externalTag` | Software systems containing this tag will be considered external | | |
| `generatr.site.nestGroups` | Will show software systems in the left side navigator in collapsable groups | `false` | `true` |
| Property name | Description | Default | Example |
|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|------------------------------------------------------|
| `generatr.style.colors.primary` | Primary site color, used for header bar background and active menu background. | `#333333` | `#485fc7` |
| `generatr.style.colors.secondary` | Secondary site color, used for font color in header bar and for active menu. | `#cccccc` | `#ffffff` |
| `generatr.style.faviconPath` | Site logo location relative to the configured `assets` folder. When configured, the logo image will be place on the left side in the header bar. This requires the `--assets-dir` switch when generating the site and the corresponding file to be available in the `assets` folder. | | `site/favicon.ico` |
| `generatr.style.logoPath` | Site favicon location relative to the configured `assets` folder. When configured, the favicon will be set for all generated pages. This requires the `--assets-dir` switch when generating the site and the corresponding file to be available in the `assets` folder. | | `site/logo.png` |
| `generatr.style.customStylesheet` | URL to hosted custom stylesheet or path to custom stylesheet file (location relative to the configured `assets` folder). When configured this css file will be loaded for all pages. When using a path to a file the `--assets-dir` switch must be used when generating the site and the corresponding file is available in the `assets` folder. | | `site/custom.css` or 'https://uri.example/custom.css |
| `generatr.search.language` | Indexing/stemming language for the search index. See [Lunr language support](https://github.com/olivernn/lunr-languages) | `en` | `nl` |
| `generatr.markdown.flexmark.extensions` | Additional extensions to the markdown generator to add new markdown capabilities. [More Details](https://avisi-cloud.github.io/structurizr-site-generatr/main/extended-markdown-features/) | Tables | `Tables,Admonition` |
| `generatr.svglink.target` | Specifies the link target for element links in the exported svg | `_top` | `_self` |
| `generatr.site.exporter` | Specifies the UML exporter, can be `c4` (uses the `C4PlantUMLExporter`) or `structurizr` (uses the `StructurizrPlantUMLExporter`) | `c4` | `structurizr` |
| `generatr.site.externalTag` | Software systems containing this tag will be considered external | | |
| `generatr.site.nestGroups` | Will show software systems in the left side navigator in collapsable groups | `false` | `true` |
| `generatr.site.cdn` | Specifies the CDN base location for fetching NPM packages for browser runtime dependencies. Defaults to jsDelivr, but can be changed to e.g. an on-premise location. | `https://cdn.jsdelivr.net/npm` | `https://cdn.my-company/npm` |

See the included example for usage of some those properties in the
[C4 architecture model example](https://github.com/avisi-cloud/structurizr-site-generatr/blob/main/docs/example/workspace.dsl#L163).
Expand Down
1 change: 1 addition & 0 deletions docs/example/workspace.dsl
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
"generatr.site.exporter" "c4"
"generatr.site.externalTag" "External System"
"generatr.site.nestGroups" "false"
"generatr.site.cdn" "https://cdn.jsdelivr.net/npm"
}

systemlandscape "SystemLandscape" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nl.avisi.structurizr.site.generatr.site.model

import nl.avisi.structurizr.site.generatr.includedSoftwareSystems
import nl.avisi.structurizr.site.generatr.site.GeneratorContext
import nl.avisi.structurizr.site.generatr.site.views.CDN

abstract class PageViewModel(protected val generatorContext: GeneratorContext) {
val pageTitle: String by lazy {
Expand All @@ -12,6 +13,7 @@ abstract class PageViewModel(protected val generatorContext: GeneratorContext) {
else
pageSubTitle
}
val cdn by lazy { CDN(generatorContext.workspace) }
val favicon by lazy { FaviconViewModel(generatorContext, this) }
val customStylesheet by lazy { CustomStylesheetViewModel(generatorContext, this) }
val headerBar by lazy { HeaderBarViewModel(this, generatorContext) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
package nl.avisi.structurizr.site.generatr.site.views

import com.structurizr.Workspace
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import java.lang.IllegalStateException

class CDN {
companion object {
private const val CDN_BASE = "https://cdn.jsdelivr.net/npm/"
private val json = Json { ignoreUnknownKeys = true }
class CDN(val workspace: Workspace) {
private val cdnBaseURL = getCdnBaseUrl()
private val json = Json { ignoreUnknownKeys = true }

private val packageJson = object {}.javaClass.getResource("/package.json")?.readText()
?: throw IllegalStateException("package.json not found")
private val packageJson = object {}.javaClass.getResource("/package.json")?.readText()
?: throw IllegalStateException("package.json not found")

private val dependencies = json.parseToJsonElement(packageJson).jsonObject["dependencies"]
?.jsonObject
?.map { Dependency(it.key, it.value.jsonPrimitive.content) }
?: throw IllegalStateException("dependencies element not found in package.json")
private val dependencies = json.parseToJsonElement(packageJson).jsonObject["dependencies"]
?.jsonObject
?.map { Dependency(cdnBaseURL, it.key, it.value.jsonPrimitive.content) }
?: throw IllegalStateException("dependencies element not found in package.json")

fun bulmaCss() = dependencies.single { it.name == "bulma" }.let {
"${it.baseUrl()}/css/bulma.min.css"
}
fun bulmaCss() = dependencies.single { it.name == "bulma" }.let {
"${it.baseUrl()}/css/bulma.min.css"
}

fun katexJs() = dependencies.single { it.name == "katex" }.let {
"${it.baseUrl()}/dist/katex.min.js"
}
fun katexJs() = dependencies.single { it.name == "katex" }.let {
"${it.baseUrl()}/dist/katex.min.js"
}

fun katexCss() = dependencies.single { it.name == "katex" }.let {
"${it.baseUrl()}/dist/katex.min.css"
}
fun katexCss() = dependencies.single { it.name == "katex" }.let {
"${it.baseUrl()}/dist/katex.min.css"
}

fun lunrJs() = dependencies.single { it.name == "lunr" }.let {
"${it.baseUrl()}/lunr.min.js"
}
fun lunrJs() = dependencies.single { it.name == "lunr" }.let {
"${it.baseUrl()}/lunr.min.js"
}

fun lunrLanguagesStemmerJs() = dependencies.single { it.name == "lunr-languages" }.let {
"${it.baseUrl()}/min/lunr.stemmer.support.min.js"
}
fun lunrLanguagesStemmerJs() = dependencies.single { it.name == "lunr-languages" }.let {
"${it.baseUrl()}/min/lunr.stemmer.support.min.js"
}

fun lunrLanguagesJs(language: String) = dependencies.single { it.name == "lunr-languages" }.let {
"${it.baseUrl()}/min/lunr.$language.min.js"
}
fun lunrLanguagesJs(language: String) = dependencies.single { it.name == "lunr-languages" }.let {
"${it.baseUrl()}/min/lunr.$language.min.js"
}

fun mermaidJs() = dependencies.single { it.name == "mermaid" }.let {
"${it.baseUrl()}/dist/mermaid.esm.min.mjs"
}
fun mermaidJs() = dependencies.single { it.name == "mermaid" }.let {
"${it.baseUrl()}/dist/mermaid.esm.min.mjs"
}

fun svgpanzoomJs() = dependencies.single { it.name == "svg-pan-zoom" }.let {
"${it.baseUrl()}/dist/svg-pan-zoom.min.js"
}
fun svgpanzoomJs() = dependencies.single { it.name == "svg-pan-zoom" }.let {
"${it.baseUrl()}/dist/svg-pan-zoom.min.js"
}

fun webfontloaderJs() = dependencies.single { it.name == "webfontloader" }.let {
"${it.baseUrl()}/webfontloader.js"
}
fun webfontloaderJs() = dependencies.single { it.name == "webfontloader" }.let {
"${it.baseUrl()}/webfontloader.js"
}

fun getCdnBaseUrl() = workspace.views.configuration.properties
.getOrDefault("generatr.site.cdn", "https://cdn.jsdelivr.net/npm")
.trimEnd('/')

@Serializable
data class Dependency(val name: String, val version: String) {
fun baseUrl() = "$CDN_BASE$name@$version"
data class Dependency(val cdnBaseURL: String, val name: String, val version: String) {
fun baseUrl() = "$cdnBaseURL/$name@$version"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@ fun BODY.markdownAdmonitionScript(viewModel: PageViewModel) {
) { }
}

fun HEAD.katexStylesheet() {
fun HEAD.katexStylesheet(cdn: CDN) {
// loading KaTeX as global on a webpage: https://katex.org/docs/browser.html#loading-as-global
unsafe {
raw("""
<link rel="stylesheet" href="${CDN.katexCss()}" crossorigin="anonymous">
<link rel="stylesheet" href="${cdn.katexCss()}" crossorigin="anonymous">
""")
}
}

fun HEAD.katexScript() {
fun HEAD.katexScript(cdn: CDN) {
// loading KaTeX as global on a webpage: https://katex.org/docs/browser.html#loading-as-global
unsafe {
raw("""
<script defer src="${CDN.katexJs()}" crossorigin="anonymous"></script>
<script defer src="${cdn.katexJs()}" crossorigin="anonymous"></script>
""")
}
}

fun HEAD.katexFonts() {
fun HEAD.katexFonts(cdn: CDN) {
// loading KaTeX as global on a webpage: https://katex.org/docs/browser.html#loading-as-global
unsafe {
raw("""
Expand All @@ -50,7 +50,7 @@ fun HEAD.katexFonts() {
},
};
</script>
<script defer src="${CDN.webfontloaderJs()}" crossorigin="anonymous"></script>
<script defer src="${cdn.webfontloaderJs()}" crossorigin="anonymous"></script>
""")
}
}
Expand All @@ -72,7 +72,7 @@ fun BODY.mermaidScript(viewModel: PageViewModel) {
// Simple full example, how to include Mermaid: https://mermaid.js.org/config/usage.html#simple-full-example
script(type = "module") {
unsafe {
raw("import mermaid from '${CDN.mermaidJs()}';")
raw("import mermaid from '${viewModel.cdn.mermaidJs()}';")
}
}
}
Loading

0 comments on commit 71e4dd0

Please sign in to comment.