A super simple static site generator written on top of kotlinx.html and standalone tailwindcss. I use this for my personal site at 0ffz/personal-site.
Shocky's goal is to provide a simple way to write individual components and programmatically combine them in templates used by markdown files. It does everything at compile time using the typesafe kotlinx.html
DSL, kotlinx.serialization
for parsing page frontmatter, and zero JavaScript required on the client.
Shocky is designed to be used with Amper, a simpler alternative to Gradle build scripts (you can still depend on it like normal in Gradle, just call Shocky
in your main class like below.)
See: https://github.com/JetBrains/amper
product: jvm/app
repositories:
- id: "mineinabyss"
url: "https://repo.mineinabyss.com/releases"
dependencies:
- "me.dvyy:shocky:x.y.z"
settings:
kotlin:
serialization: json
jvm:
release: 21
suspend fun main(args: Array<String>) = Shocky(
dest = Path("out"),
route = siteRouting(path = Path("site")) {
// Set up routing here...
},
assets = listOf(Path("site/assets")),
// If enabled, will auto download and run tailwind standalone binary
useTailwind = true,
).run(args)
The Shocky class above reads args passed to let you run the following commands:
./amper run serve
- Starts server and refreshes page when src or site are changed../amper run generate
- Generates site files to the output directory
/**
* An outlined chip for a tag list,
* FlowContent is a common superclass of div, body, etc... in kotlinx.html
*/
fun FlowContent.outlinedChip(name: String) {
div("border-2 text-nowrap border-zinc-700 text-zinc-300 text-xs font-semibold uppercase py-1 px-2 rounded-full") {
+name
}
}
@Serializable
data class CustomMeta(
val customProperty: String = "default",
)
inline fun Page.myTemplate(
crossinline init: FlowContent.() -> Unit = { markdown(content) }, // Helper function for rendering markdown pages
) = html {
val customMeta = meta<CustomMeta>()
// ...
body {
h1 { +page.title }
p { +customMeta.customProperty }
init()
}
}
suspend fun main(args: Array<String>) = Shocky(
dest = Path("out"),
route = siteRouting(path = Path("site")) {
template("default", Page::myTemplate)
includeAssets() // Include pngs etc.. in site root
pages(".") // Render all .md iles in site root
// generate example/index.html programmatically
"example" {
generate(meta = CommonFrontMatter(title = "Example")) { myTemplate() }
}
},
assets = listOf(Path("site/assets")),
).run(args)