Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dark mode #528

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ architecture model:
| `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` |
| `generatr.site.darkMode` | Will show the dark mode button to switch between light and dark mode on the website. If turned off, the site will be shown in light mode and this button will not be shown. Defaults to true/on. | `true` | `false` |

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 @@ -186,6 +186,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
"generatr.site.externalTag" "External System"
"generatr.site.nestGroups" "false"
"generatr.site.cdn" "https://cdn.jsdelivr.net/npm"
"generatr.site.darkMode" "true"
}

systemlandscape "SystemLandscape" {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"lunr-languages": "1.14.0",
"mermaid": "10.9.1",
"svg-pan-zoom": "3.6.1",
"webfontloader": "1.6.28"
"webfontloader": "1.6.28",
"font-awesome": "4.7.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fun copySiteWideAssets(exportDir: File) {
copySiteWideAsset(exportDir, "/css/treeview.css")
copySiteWideAsset(exportDir, "/js/treeview.js")
copySiteWideAsset(exportDir, "/js/katex-render.js")
copySiteWideAsset(exportDir, "/js/toggle-theme.js")
}

private fun copySiteWideAsset(exportDir: File, asset: String) {
Expand Down Expand Up @@ -116,6 +117,12 @@ private fun generateStyle(context: GeneratorContext, branchDir: File) {
color: dimgrey!important;
background-color: white!important;
}
body.dark-theme .input.has-site-branding {
background-color: #1b212c!important;
}
i .has-site-branding {
color: $secondary!important
}
.input.has-site-branding:focus {
border-color: $secondary!important;
box-shadow: 0 0 0 0.125em $secondary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class HeaderBarViewModel(pageViewModel: PageViewModel, generatorContext: Generat
.map { BranchHomeLinkViewModel(pageViewModel, it) }
val currentBranch = generatorContext.currentBranch
val version = generatorContext.version
val showDarkModeButton = generatorContext.workspace.views.configuration.properties
.getOrDefault("generatr.site.darkMode", "true").toBoolean()

private fun logoPath(generatorContext: GeneratorContext) =
generatorContext.workspace.views.configuration.properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ abstract class PageViewModel(protected val generatorContext: GeneratorContext) {
val includedSoftwareSystems = generatorContext.workspace.includedSoftwareSystems
val configuration = generatorContext.workspace.views.configuration.properties
val includeTreeview = configuration.getOrDefault("generatr.site.nestGroups", "false").toBoolean()
val showDarkModeButton = configuration.getOrDefault("generatr.site.darkMode", "true").toBoolean()

abstract val url: String
abstract val pageSubTitle: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class CDN(val workspace: Workspace) {
"${it.baseUrl()}/webfontloader.js"
}

fun fontAwesomeCss() = dependencies.single { it.name == "font-awesome"}.let {
"${it.baseUrl()}/css/font-awesome.min.css"
}

fun getCdnBaseUrl() = workspace.views.configuration.properties
.getOrDefault("generatr.site.cdn", "https://cdn.jsdelivr.net/npm")
.trimEnd('/')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import nl.avisi.structurizr.site.generatr.site.model.PageViewModel

fun HTML.page(viewModel: PageViewModel, block: DIV.() -> Unit) {
attributes["lang"] = "en"
attributes["data-theme"] = "light"
classes = setOf("has-background-light")
if (!viewModel.showDarkModeButton) {
attributes["data-theme"] = "light"
classes = setOf("has-background-light")
}

headFragment(viewModel)
bodyFragment(viewModel, block)
Expand All @@ -19,6 +21,7 @@ private fun HTML.headFragment(viewModel: PageViewModel) {
meta(name = "viewport", content = "width=device-width, initial-scale=1")
title { +viewModel.pageTitle }
link(rel = "stylesheet", href = viewModel.cdn.bulmaCss())
link(rel = "stylesheet", href = viewModel.cdn.fontAwesomeCss())
link(rel = "stylesheet", href = "../" + "/style.css".asUrlToFile(viewModel.url))
link(rel = "stylesheet", href = "./" + "/style-branding.css".asUrlToFile(viewModel.url))
script(type = ScriptType.textJavaScript, src = "../" + "/modal.js".asUrlToFile(viewModel.url)) { }
Expand Down Expand Up @@ -59,7 +62,7 @@ private fun HTML.bodyFragment(viewModel: PageViewModel, block: DIV.() -> Unit) {
div(classes = "site-layout") {
id = "site"
menu(viewModel.menu, viewModel.includeTreeview)
div(classes = "container is-fluid has-background-white") {
div(classes = "container is-fluid") {
block()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ fun BODY.pageHeader(viewModel: HeaderBarViewModel) {
}
}
}
if (viewModel.showDarkModeButton) {
div(classes = "navbar-item") {
button(classes = "btn-toggle") {
span(classes = "icon") {
i(classes = "fa fa-xl has-site-branding") {
id = "icon-toggle"
}
}
}
script(type = ScriptType.textJavaScript, src = "/toggle-theme.js") { }
}
}
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/resources/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,19 @@ a.navbar-item:hover {
color: #485fc7;
border-bottom-color: #485fc7;
}

.fa-xl {
font-size: 24px
}

body.dark-theme .tabs li a {
border-bottom-color: #696969;
}

body.dark-theme .tabs li.is-active a {
color: #7585ff;
border-bottom-color: #7585ff;
}
body.dark-theme .text {
fill: #ebecf0
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,22 @@ class HeaderBarViewModelTest : ViewModelTest() {

assertThat(viewModel.hasLogo).isFalse()
}

@Test
fun `dark mode`() {
val viewModel = HeaderBarViewModel(pageViewModel, generatorContext)

assertThat(viewModel.showDarkModeButton).isTrue()
}

@Test
fun `no dark mode`() {
generatorContext.workspace.views.configuration.addProperty(
"generatr.site.darkMode",
"false"
)
val viewModel = HeaderBarViewModel(pageViewModel, generatorContext)

assertThat(viewModel.showDarkModeButton).isFalse()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestFactory

class CDNTest {
val workspace = Workspace("workspace name", "")
val cdn = CDN(workspace)
@TestFactory
fun `cdn locations`() {
val workspace = Workspace("workspace name", "")
val cdn = CDN(workspace)

fun `cdn locations`() : List<DynamicTest> =
listOf(
cdn.bulmaCss() to "/css/bulma.min.css",
cdn.katexJs() to "/dist/katex.min.js",
Expand All @@ -23,7 +22,8 @@ class CDNTest {
cdn.lunrLanguagesJs("en") to "/min/lunr.en.min.js",
cdn.mermaidJs() to "/dist/mermaid.esm.min.mjs",
cdn.svgpanzoomJs() to "/dist/svg-pan-zoom.min.js",
cdn.webfontloaderJs() to "/webfontloader.js"
cdn.webfontloaderJs() to "/webfontloader.js",
cdn.fontAwesomeCss() to "/css/font-awesome.min.css"
).map { (url, suffix) ->
DynamicTest.dynamicTest(url) {
assertThat(url).all {
Expand All @@ -33,7 +33,6 @@ class CDNTest {
}
}
}
}

@Test
fun `usage of default cdn url`() {
Expand Down
Loading