Skip to content

Commit

Permalink
feat(docs): Enhance documentation with metadata, anchor links, TOC, a…
Browse files Browse the repository at this point in the history
…nd search functionality.
  • Loading branch information
Ayfri committed Jan 8, 2025
1 parent b6b7159 commit b346a15
Show file tree
Hide file tree
Showing 7 changed files with 683 additions and 136 deletions.
30 changes: 30 additions & 0 deletions website/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,36 @@ kobweb {

"""io.github.ayfri.kore.website.components.common.CodeBlock($text, "${code.info.takeIf { it.isNotBlank() }}")"""
}

heading.set { heading ->
val id = heading.children()
.filterIsInstance<Text>()
.map { it.literal.lowercase().replace(Regex("[^a-z0-9]+"), "-") }
.joinToString("")
val content = heading.children()
.filterIsInstance<Text>()
.map { it.literal.escapeSingleQuotedText() }
.joinToString("")
childrenOverride = emptyList()
val tag = "H${heading.level}"

val onSubtitles =
if (heading.level > 1) "classes(io.github.ayfri.kore.website.components.layouts.MarkdownLayoutStyle.heading)"
else ""

"""org.jetbrains.compose.web.dom.${tag.replaceFirstChar { it.uppercase() }}({
| attr("id", "$id")
| $onSubtitles
|}) {
| org.jetbrains.compose.web.dom.A("#$id", {
| classes(io.github.ayfri.kore.website.components.layouts.MarkdownLayoutStyle.anchor)
| }) {
| com.varabyte.kobweb.silk.components.icons.mdi.MdiLink()
| }
| org.jetbrains.compose.web.dom.Text("$content")
|}
""".trimMargin()
}
}

process = { markdownFiles ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ object GlobalStyle : StyleSheet() {
val buttonBackgroundColorHover = Color("#0597ba")
val linkColor = Color("#0597ba")
val linkColorHover = Color("#23cae8")
val inactiveLinkColor = Color("#a7b5bd")
val textColor = Color("#fff")

val scrollbarThumbColor = Color("#ffffff99")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.github.ayfri.kore.website.components.doc

import androidx.compose.runtime.Composable
import com.varabyte.kobweb.compose.css.Cursor
import com.varabyte.kobweb.compose.css.cursor
import com.varabyte.kobweb.compose.css.translateX
import com.varabyte.kobweb.compose.css.zIndex
import com.varabyte.kobweb.silk.components.icons.mdi.MdiClose
import io.github.ayfri.kore.website.GlobalStyle
import io.github.ayfri.kore.website.utils.smMax
import io.github.ayfri.kore.website.utils.smMin
import io.github.ayfri.kore.website.utils.transition
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.Button
import org.jetbrains.compose.web.dom.Div

@Composable
fun DocSidebar(revealed: Boolean, onClose: () -> Unit) {
Style(DocSidebarStyle)

Div({
classes(DocSidebarStyle.sidebar)
if (revealed) classes("reveal")
}) {
Button({
classes(DocSidebarStyle.closeButton)
onClick { onClose() }
}) {
MdiClose()
}

Search()
DocTree()
}
}

object DocSidebarStyle : StyleSheet() {
val sidebar by style {
backgroundColor(GlobalStyle.secondaryBackgroundColor)
display(DisplayStyle.Flex)
flexDirection(FlexDirection.Column)
padding(1.cssRem)
position(Position.Relative)

smMin(self) {
borderRadius(GlobalStyle.roundingButton)
}

smMax(self) {
backgroundColor(GlobalStyle.backgroundColor)
height(100.vh)
left(0.px)
paddingBottom(100.vh)
paddingTop(4.cssRem)
position(Position.Fixed)
top(0.px)
translateX((-100).percent)
transition(0.3.s, "translate")
width(100.percent)
zIndex(10)
}

self + className("reveal") style {
translateX(0.percent)
}
}

val closeButton by style {
backgroundColor(Color.transparent)
border(0.px)
color(GlobalStyle.textColor)
cursor(Cursor.Pointer)
display(DisplayStyle.None)
padding(0.5.cssRem)
position(Position.Absolute)
right(1.cssRem)
top(1.cssRem)

smMax(self) {
display(DisplayStyle.Block)
}

className("material-icons") style {
fontSize(2.cssRem)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ import com.varabyte.kobweb.compose.css.*
import com.varabyte.kobweb.core.rememberPageContext
import io.github.ayfri.kore.website.GlobalStyle
import io.github.ayfri.kore.website.docEntries
import io.github.ayfri.kore.website.utils.*
import kotlinx.browser.document
import io.github.ayfri.kore.website.utils.A
import io.github.ayfri.kore.website.utils.Span
import io.github.ayfri.kore.website.utils.transition
import org.jetbrains.compose.web.ExperimentalComposeWebApi
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.Button
import org.jetbrains.compose.web.dom.Li
import org.jetbrains.compose.web.dom.Text
import org.jetbrains.compose.web.dom.Ul
import org.w3c.dom.HTMLButtonElement
import org.jetbrains.compose.web.dom.*

private fun StyleScope.indentation(level: Int) = marginLeft(level * 2.cssRem)

Expand Down Expand Up @@ -52,145 +49,60 @@ fun DocTree() {
val entries = docEntries
val currentURL = context.path


Ul({
Div({
id("doc-tree")
classes(DocTreeStyle.list)
}) {
Button({
classes(DocTreeStyle.revealButton)

onClick {
val docTree = document.querySelector("#doc-tree")
docTree?.classList?.toggle("reveal")
it.currentTarget.unsafeCast<HTMLButtonElement>().classList.toggle("reveal")
}
}) {
Text(">")
H2 {
Text("Pages")
}

// Separate the entries that are not in a group.
val (simpleEntriesWithoutGroup, otherEntries) = entries.partition {
it.middleSlugs.isEmpty() && entries.none { entry -> entry.middleSlugs.contains(it.slugs.last()) }
}
// Display these entries first.
simpleEntriesWithoutGroup.forEach { entry ->
Entry(entry, entry.path == currentURL)
}
Ul({
classes(DocTreeStyle.list)
}) {
// Separate the entries that are not in a group.
val (simpleEntriesWithoutGroup, otherEntries) = entries.partition {
it.middleSlugs.isEmpty() && entries.none { entry -> entry.middleSlugs.contains(it.slugs.last()) }
}
// Display these entries first.
simpleEntriesWithoutGroup.forEach { entry ->
Entry(entry, entry.path == currentURL)
}

// Then group the entries by their middle slugs.
val presentedGroups = mutableSetOf<String>()
otherEntries.groupBy { it.middleSlugs.joinToString("/") }.forEach { (slug, groupEntries) ->
if (slug in presentedGroups || slug.isEmpty()) return@forEach
// Then group the entries by their middle slugs.
val presentedGroups = mutableSetOf<String>()
otherEntries.groupBy { it.middleSlugs.joinToString("/") }.forEach { (slug, groupEntries) ->
if (slug in presentedGroups || slug.isEmpty()) return@forEach

presentedGroups += slug
val slugName = slug.split("/").last()
if (slugName in entries.map { it.slugs.last() }) {
entries.find { it.slugs.last() == slug }?.let { entry ->
Entry(entry, entry.path == currentURL)
}
} else {
GroupEntry(slugName.kebabCaseToTitleCamelCase(), slug.count { it == '/' })
}

presentedGroups += slug
val slugName = slug.split("/").last()
if (slugName in entries.map { it.slugs.last() }) {
entries.find { it.slugs.last() == slug }?.let { entry ->
val sortedEntries = groupEntries.sortedBy { it.slugs.size }.filter { it.slugs.last() != slugName }
sortedEntries.forEach { entry ->
Entry(entry, entry.path == currentURL)
}
} else {
GroupEntry(slugName.kebabCaseToTitleCamelCase(), slug.count { it == '/' })
}

val sortedEntries = groupEntries.sortedBy { it.slugs.size }.filter { it.slugs.last() != slugName }
sortedEntries.forEach { entry ->
Entry(entry, entry.path == currentURL)
}
}
}
}

object DocTreeStyle : StyleSheet() {
val revealButton by style {
position(Position.Fixed)
left(100.percent)
padding(0.4.cssRem, 0.8.cssRem)
top(4.cssRem)

backgroundColor(GlobalStyle.secondaryBackgroundColor)
borderTopRightRadius(GlobalStyle.roundingButton)
borderBottomRightRadius(GlobalStyle.roundingButton)
borderStyle(LineStyle.None)
color(GlobalStyle.altTextColor)
cursor(Cursor.Pointer)
fontSize(1.2.cssRem)
fontWeight(FontWeight.Bold)
transition(0.3.s, "background-color", "color")

smMin(self) {
display(DisplayStyle.None)
}

self + after style {
content("")
position(Position.Absolute)
width(100.vw)
height(100.vh)
left(0.px)
top((-4).cssRem)
transition(0.3.s, "background-color")
pointerEvents(PointerEvents.None)
}

self + before style {
content("x")
position(Position.Absolute)
property("right", "calc(-100vw + 17rem)")
top((-150).percent)

color(Color.transparent)
fontWeight(FontWeight.Normal)
transition(0.15.s, 0.s, "color")
zIndex(10)
}

self + className("reveal") style {
backgroundColor(BackgroundColor.Transparent)
color(Color.transparent)
property("-webkit-tap-highlight-color", "transparent")

self + before style {
color(GlobalStyle.altTextColor)
transition(0.3.s, 0.2.s, "color")
}

self + after style {
backgroundColor(GlobalStyle.shadowColor)
pointerEvents(PointerEvents.Auto)
}
}
}

@OptIn(ExperimentalComposeWebApi::class)
val list by style {
listStyle(ListStyleType.None)
padding(0.8.cssRem)
marginTop(0.px)
marginRight(1.cssRem)

height(100.percent)
position(Position.Sticky)
left(0.px)

smMax(self) {
position(Position.Fixed)
top((-1).cssRem)
paddingTop(10.cssRem)
paddingBottom(100.vh)
zIndex(10)

backgroundColor(GlobalStyle.secondaryBackgroundColor)
transition(0.3.s, "transform")
transform {
translateX((-100).percent)
}

self + className("reveal") style {
transform {
translateX(0.percent)
}
}
}
}

val entry by style {
Expand Down
Loading

0 comments on commit b346a15

Please sign in to comment.