Skip to content

Commit 53a660a

Browse files
Copilotmikepenz
andcommitted
Add code block top bar with language label and copy button
Co-authored-by: mikepenz <1476232+mikepenz@users.noreply.github.com>
1 parent 84331c0 commit 53a660a

File tree

3 files changed

+97
-5
lines changed

3 files changed

+97
-5
lines changed

multiplatform-markdown-renderer-code/src/commonMain/kotlin/com/mikepenz/markdown/compose/elements/MarkdownHighlightedCode.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ fun MarkdownHighlightedCode(
9797
MarkdownCodeBackground(
9898
color = backgroundCodeColor,
9999
shape = RoundedCornerShape(codeBackgroundCornerSize),
100-
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
100+
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
101+
showTopBar = true,
102+
language = language,
103+
code = code
101104
) {
102105
@Suppress("DEPRECATION")
103106
MarkdownBasicText(

multiplatform-markdown-renderer/src/commonMain/kotlin/com/mikepenz/markdown/compose/elements/MarkdownCode.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.foundation.background
55
import androidx.compose.foundation.border
66
import androidx.compose.foundation.horizontalScroll
77
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
89
import androidx.compose.foundation.layout.fillMaxWidth
910
import androidx.compose.foundation.layout.padding
1011
import androidx.compose.foundation.rememberScrollState
@@ -35,6 +36,7 @@ import org.intellij.markdown.ast.getTextInNode
3536
@Composable
3637
private fun MarkdownCode(
3738
code: String,
39+
language: String? = null,
3840
style: TextStyle = LocalMarkdownTypography.current.code,
3941
) {
4042
val backgroundCodeColor = LocalMarkdownColors.current.codeBackground
@@ -45,7 +47,10 @@ private fun MarkdownCode(
4547
shape = RoundedCornerShape(codeBackgroundCornerSize),
4648
modifier = Modifier
4749
.fillMaxWidth()
48-
.padding(vertical = 8.dp)
50+
.padding(vertical = 8.dp),
51+
showTopBar = true,
52+
language = language,
53+
code = code
4954
) {
5055
MarkdownBasicText(
5156
text = code,
@@ -62,7 +67,7 @@ fun MarkdownCodeFence(
6267
content: String,
6368
node: ASTNode,
6469
style: TextStyle = LocalMarkdownTypography.current.code,
65-
block: @Composable (String, String?, TextStyle) -> Unit = { code, _, style -> MarkdownCode(code = code, style = style) },
70+
block: @Composable (String, String?, TextStyle) -> Unit = { code, language, style -> MarkdownCode(code = code, language = language, style = style) },
6671
) {
6772
// CODE_FENCE_START, FENCE_LANG, EOL, {content // CODE_FENCE_CONTENT // x-times}, CODE_FENCE_END
6873
// CODE_FENCE_START, EOL, {content // CODE_FENCE_CONTENT // x-times}, EOL
@@ -85,7 +90,7 @@ fun MarkdownCodeBlock(
8590
content: String,
8691
node: ASTNode,
8792
style: TextStyle = LocalMarkdownTypography.current.code,
88-
block: @Composable (String, String?, TextStyle) -> Unit = { code, _, style -> MarkdownCode(code = code, style = style) },
93+
block: @Composable (String, String?, TextStyle) -> Unit = { code, language, style -> MarkdownCode(code = code, language = language, style = style) },
8994
) {
9095
val start = node.children[0].startOffset
9196
val end = node.children[node.children.size - 1].endOffset
@@ -100,6 +105,9 @@ fun MarkdownCodeBackground(
100105
shape: Shape = RectangleShape,
101106
border: BorderStroke? = null,
102107
elevation: Dp = 0.dp,
108+
showTopBar: Boolean = false,
109+
language: String? = null,
110+
code: String = "",
103111
content: @Composable () -> Unit,
104112
) {
105113
Box(
@@ -114,6 +122,20 @@ fun MarkdownCodeBackground(
114122
.pointerInput(Unit) {},
115123
propagateMinConstraints = true
116124
) {
117-
content()
125+
if (showTopBar) {
126+
Column {
127+
MarkdownCodeTopBar(
128+
language = language,
129+
code = code
130+
)
131+
MarkdownDivider(
132+
color = LocalMarkdownColors.current.dividerColor.copy(alpha = 0.3f),
133+
thickness = 0.5.dp
134+
)
135+
content()
136+
}
137+
} else {
138+
content()
139+
}
118140
}
119141
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.mikepenz.markdown.compose.elements
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.foundation.layout.size
10+
import androidx.compose.foundation.shape.CircleShape
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.ui.Alignment
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.draw.clip
15+
import androidx.compose.ui.platform.LocalClipboardManager
16+
import androidx.compose.ui.text.AnnotatedString
17+
import androidx.compose.ui.text.font.FontFamily
18+
import androidx.compose.ui.unit.dp
19+
import androidx.compose.ui.unit.sp
20+
import com.mikepenz.markdown.compose.LocalMarkdownColors
21+
import com.mikepenz.markdown.compose.elements.material.MarkdownBasicText
22+
23+
@Composable
24+
internal fun MarkdownCodeTopBar(
25+
language: String?,
26+
code: String,
27+
modifier: Modifier = Modifier,
28+
) {
29+
val clipboardManager = LocalClipboardManager.current
30+
val textColor = LocalMarkdownColors.current.text
31+
32+
Row(
33+
modifier = modifier
34+
.fillMaxWidth()
35+
.padding(horizontal = 8.dp, vertical = 4.dp),
36+
horizontalArrangement = Arrangement.SpaceBetween,
37+
verticalAlignment = Alignment.CenterVertically
38+
) {
39+
MarkdownBasicText(
40+
text = language?.uppercase() ?: "CODE",
41+
style = androidx.compose.ui.text.TextStyle(
42+
fontSize = 10.sp,
43+
fontFamily = FontFamily.Monospace,
44+
color = textColor.copy(alpha = 0.6f)
45+
)
46+
)
47+
48+
Box(
49+
modifier = Modifier
50+
.size(24.dp)
51+
.clip(CircleShape)
52+
.clickable {
53+
clipboardManager.setText(AnnotatedString(code))
54+
},
55+
contentAlignment = Alignment.Center
56+
) {
57+
// Simple copy icon representation using text for now
58+
MarkdownBasicText(
59+
text = "",
60+
style = androidx.compose.ui.text.TextStyle(
61+
fontSize = 14.sp,
62+
color = textColor.copy(alpha = 0.6f)
63+
)
64+
)
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)