Skip to content

Commit f9bc51f

Browse files
[JEWEL-1131] Implement badge component
1 parent a813a7f commit f9bc51f

11 files changed

Lines changed: 927 additions & 1 deletion

File tree

platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/theme/IntUiBridge.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ internal fun createBridgeComponentStyling(theme: ThemeDefinition): ComponentStyl
6969
val menuStyle = readMenuStyle()
7070

7171
return DefaultComponentStyling(
72+
badgeStyle = readBadgeStyle(),
7273
checkboxStyle = readCheckboxStyle(),
7374
chipStyle = readChipStyle(),
7475
circularProgressStyle = readCircularProgressStyle(theme.isDark),
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.jetbrains.jewel.bridge.theme
2+
3+
import androidx.compose.foundation.layout.PaddingValues
4+
import androidx.compose.foundation.shape.CornerSize
5+
import androidx.compose.ui.graphics.takeOrElse
6+
import androidx.compose.ui.unit.DpSize
7+
import androidx.compose.ui.unit.dp
8+
import org.jetbrains.jewel.bridge.createVerticalBrush
9+
import org.jetbrains.jewel.bridge.retrieveColorOrUnspecified
10+
import org.jetbrains.jewel.bridge.retrieveColorsOrUnspecified
11+
import org.jetbrains.jewel.ui.component.styling.BadgeColors
12+
import org.jetbrains.jewel.ui.component.styling.BadgeMetrics
13+
import org.jetbrains.jewel.ui.component.styling.BadgeStyle
14+
15+
// Note: there isn't a badge spec in the IntelliJ Platform LaF, so we're deriving
16+
// this from similar small promotional UI elements.
17+
// Badges are small colored elements used to display promotional text like "New", "Beta", etc.
18+
internal fun readBadgeStyle(): BadgeStyle {
19+
val normalBackground =
20+
retrieveColorsOrUnspecified("Button.startBackground", "Button.endBackground").createVerticalBrush()
21+
22+
val normalContent = retrieveColorOrUnspecified("Label.foreground")
23+
val disabledContent = retrieveColorOrUnspecified("Label.disabledForeground").takeOrElse { normalContent }
24+
25+
val colors =
26+
BadgeColors(
27+
background = normalBackground,
28+
backgroundDisabled = normalBackground,
29+
backgroundFocused = normalBackground,
30+
backgroundPressed = normalBackground,
31+
backgroundHovered = normalBackground,
32+
content = normalContent,
33+
contentDisabled = disabledContent,
34+
contentFocused = normalContent,
35+
contentPressed = normalContent,
36+
contentHovered = normalContent,
37+
)
38+
39+
return BadgeStyle(
40+
colors = colors,
41+
metrics =
42+
BadgeMetrics(
43+
cornerSize = CornerSize(0.dp),
44+
padding = PaddingValues(horizontal = 6.dp, vertical = 2.dp),
45+
minSize = DpSize(32.dp, 18.dp),
46+
),
47+
)
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.jetbrains.jewel.intui.standalone.styling
2+
3+
import androidx.compose.foundation.layout.PaddingValues
4+
import androidx.compose.foundation.shape.CornerSize
5+
import androidx.compose.ui.graphics.Brush
6+
import androidx.compose.ui.graphics.Color
7+
import androidx.compose.ui.graphics.SolidColor
8+
import androidx.compose.ui.unit.DpSize
9+
import androidx.compose.ui.unit.dp
10+
import org.jetbrains.jewel.intui.core.theme.IntUiDarkTheme
11+
import org.jetbrains.jewel.intui.core.theme.IntUiLightTheme
12+
import org.jetbrains.jewel.ui.component.styling.BadgeColors
13+
import org.jetbrains.jewel.ui.component.styling.BadgeMetrics
14+
import org.jetbrains.jewel.ui.component.styling.BadgeStyle
15+
16+
public fun BadgeStyle.Companion.light(
17+
colors: BadgeColors = BadgeColors.light(),
18+
metrics: BadgeMetrics = BadgeMetrics.defaults(),
19+
): BadgeStyle = BadgeStyle(colors = colors, metrics = metrics)
20+
21+
public fun BadgeStyle.Companion.dark(
22+
colors: BadgeColors = BadgeColors.dark(),
23+
metrics: BadgeMetrics = BadgeMetrics.defaults(),
24+
): BadgeStyle = BadgeStyle(colors = colors, metrics = metrics)
25+
26+
public fun BadgeColors.Companion.light(
27+
background: Brush = SolidColor(IntUiLightTheme.colors.blue(4)),
28+
backgroundDisabled: Brush = SolidColor(IntUiLightTheme.colors.gray(12)),
29+
backgroundFocused: Brush = SolidColor(IntUiLightTheme.colors.blue(5)),
30+
backgroundPressed: Brush = SolidColor(IntUiLightTheme.colors.blue(6)),
31+
backgroundHovered: Brush = SolidColor(IntUiLightTheme.colors.blue(5)),
32+
content: Color = IntUiLightTheme.colors.gray(14),
33+
contentDisabled: Color = IntUiLightTheme.colors.gray(8),
34+
contentFocused: Color = IntUiLightTheme.colors.gray(14),
35+
contentPressed: Color = IntUiLightTheme.colors.gray(14),
36+
contentHovered: Color = IntUiLightTheme.colors.gray(14),
37+
): BadgeColors =
38+
BadgeColors(
39+
background = background,
40+
backgroundDisabled = backgroundDisabled,
41+
backgroundFocused = backgroundFocused,
42+
backgroundPressed = backgroundPressed,
43+
backgroundHovered = backgroundHovered,
44+
content = content,
45+
contentDisabled = contentDisabled,
46+
contentFocused = contentFocused,
47+
contentPressed = contentPressed,
48+
contentHovered = contentHovered,
49+
)
50+
51+
public fun BadgeColors.Companion.dark(
52+
background: Brush = SolidColor(IntUiDarkTheme.colors.blue(6)),
53+
backgroundDisabled: Brush = SolidColor(IntUiDarkTheme.colors.gray(3)),
54+
backgroundFocused: Brush = SolidColor(IntUiDarkTheme.colors.blue(5)),
55+
backgroundPressed: Brush = SolidColor(IntUiDarkTheme.colors.blue(7)),
56+
backgroundHovered: Brush = SolidColor(IntUiDarkTheme.colors.blue(5)),
57+
content: Color = IntUiDarkTheme.colors.gray(14),
58+
contentDisabled: Color = IntUiDarkTheme.colors.gray(8),
59+
contentFocused: Color = IntUiDarkTheme.colors.gray(14),
60+
contentPressed: Color = IntUiDarkTheme.colors.gray(14),
61+
contentHovered: Color = IntUiDarkTheme.colors.gray(14),
62+
): BadgeColors =
63+
BadgeColors(
64+
background = background,
65+
backgroundDisabled = backgroundDisabled,
66+
backgroundFocused = backgroundFocused,
67+
backgroundPressed = backgroundPressed,
68+
backgroundHovered = backgroundHovered,
69+
content = content,
70+
contentDisabled = contentDisabled,
71+
contentFocused = contentFocused,
72+
contentPressed = contentPressed,
73+
contentHovered = contentHovered,
74+
)
75+
76+
public fun BadgeMetrics.Companion.defaults(
77+
cornerSize: CornerSize = CornerSize(0.dp),
78+
padding: PaddingValues = PaddingValues(horizontal = 6.dp, vertical = 2.dp),
79+
minSize: DpSize = DpSize(32.dp, 18.dp),
80+
): BadgeMetrics = BadgeMetrics(cornerSize = cornerSize, padding = padding, minSize = minSize)

platform/jewel/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/intui/standalone/theme/IntUiTheme.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.jetbrains.jewel.ui.DefaultComponentStyling
3535
import org.jetbrains.jewel.ui.LocalMenuItemShortcutHintProvider
3636
import org.jetbrains.jewel.ui.LocalMenuItemShortcutProvider
3737
import org.jetbrains.jewel.ui.LocalTypography
38+
import org.jetbrains.jewel.ui.component.styling.BadgeStyle
3839
import org.jetbrains.jewel.ui.component.styling.ButtonStyle
3940
import org.jetbrains.jewel.ui.component.styling.CheckboxStyle
4041
import org.jetbrains.jewel.ui.component.styling.ChipStyle
@@ -243,6 +244,7 @@ public fun ComponentStyling.default(): ComponentStyling = with {
243244

244245
@Suppress("UnusedReceiverParameter")
245246
public fun ComponentStyling.dark(
247+
badgeStyle: BadgeStyle = BadgeStyle.dark(),
246248
checkboxStyle: CheckboxStyle = CheckboxStyle.dark(),
247249
chipStyle: ChipStyle = ChipStyle.dark(),
248250
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.dark(),
@@ -280,6 +282,7 @@ public fun ComponentStyling.dark(
280282
searchMatchStyle: SearchMatchStyle = SearchMatchStyle.dark(),
281283
): ComponentStyling =
282284
DefaultComponentStyling(
285+
badgeStyle = badgeStyle,
283286
checkboxStyle = checkboxStyle,
284287
chipStyle = chipStyle,
285288
circularProgressStyle = circularProgressStyle,
@@ -320,6 +323,7 @@ public fun ComponentStyling.dark(
320323
@Suppress("UnusedReceiverParameter", "DEPRECATION_ERROR")
321324
@Deprecated("Use the variant with speedSearchStyle.", level = DeprecationLevel.HIDDEN)
322325
public fun ComponentStyling.dark(
326+
badgeStyle: BadgeStyle = BadgeStyle.dark(),
323327
checkboxStyle: CheckboxStyle = CheckboxStyle.dark(),
324328
chipStyle: ChipStyle = ChipStyle.dark(),
325329
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.dark(),
@@ -355,6 +359,7 @@ public fun ComponentStyling.dark(
355359
undecoratedDropdownStyle: DropdownStyle = DropdownStyle.Undecorated.dark(),
356360
): ComponentStyling =
357361
DefaultComponentStyling(
362+
badgeStyle = badgeStyle,
358363
checkboxStyle = checkboxStyle,
359364
chipStyle = chipStyle,
360365
circularProgressStyle = circularProgressStyle,
@@ -395,6 +400,7 @@ public fun ComponentStyling.dark(
395400
@Suppress("UnusedReceiverParameter", "DEPRECATION_ERROR")
396401
@Deprecated("Use the variant with transparentIconButtonStyle.", level = DeprecationLevel.HIDDEN)
397402
public fun ComponentStyling.dark(
403+
badgeStyle: BadgeStyle = BadgeStyle.dark(),
398404
checkboxStyle: CheckboxStyle = CheckboxStyle.dark(),
399405
chipStyle: ChipStyle = ChipStyle.dark(),
400406
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.dark(),
@@ -429,6 +435,7 @@ public fun ComponentStyling.dark(
429435
undecoratedDropdownStyle: DropdownStyle = DropdownStyle.Undecorated.dark(),
430436
): ComponentStyling =
431437
DefaultComponentStyling(
438+
badgeStyle = badgeStyle,
432439
checkboxStyle = checkboxStyle,
433440
chipStyle = chipStyle,
434441
circularProgressStyle = circularProgressStyle,
@@ -468,6 +475,7 @@ public fun ComponentStyling.dark(
468475

469476
@Suppress("UnusedReceiverParameter")
470477
public fun ComponentStyling.light(
478+
badgeStyle: BadgeStyle = BadgeStyle.light(),
471479
checkboxStyle: CheckboxStyle = CheckboxStyle.light(),
472480
chipStyle: ChipStyle = ChipStyle.light(),
473481
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.light(),
@@ -505,6 +513,7 @@ public fun ComponentStyling.light(
505513
searchMatchStyle: SearchMatchStyle = SearchMatchStyle.light(),
506514
): ComponentStyling =
507515
DefaultComponentStyling(
516+
badgeStyle = badgeStyle,
508517
checkboxStyle = checkboxStyle,
509518
chipStyle = chipStyle,
510519
circularProgressStyle = circularProgressStyle,
@@ -545,6 +554,7 @@ public fun ComponentStyling.light(
545554
@Suppress("UnusedReceiverParameter", "DEPRECATION_ERROR")
546555
@Deprecated("Use the variant with speedSearchStyle.", level = DeprecationLevel.HIDDEN)
547556
public fun ComponentStyling.light(
557+
badgeStyle: BadgeStyle = BadgeStyle.light(),
548558
checkboxStyle: CheckboxStyle = CheckboxStyle.light(),
549559
chipStyle: ChipStyle = ChipStyle.light(),
550560
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.light(),
@@ -580,6 +590,7 @@ public fun ComponentStyling.light(
580590
undecoratedDropdownStyle: DropdownStyle = DropdownStyle.Undecorated.light(),
581591
): ComponentStyling =
582592
DefaultComponentStyling(
593+
badgeStyle = badgeStyle,
583594
checkboxStyle = checkboxStyle,
584595
chipStyle = chipStyle,
585596
circularProgressStyle = circularProgressStyle,
@@ -620,6 +631,7 @@ public fun ComponentStyling.light(
620631
@Suppress("UnusedReceiverParameter", "DEPRECATION_ERROR")
621632
@Deprecated("Use the variant with transparentIconButtonStyle.", level = DeprecationLevel.HIDDEN)
622633
public fun ComponentStyling.light(
634+
badgeStyle: BadgeStyle = BadgeStyle.light(),
623635
checkboxStyle: CheckboxStyle = CheckboxStyle.light(),
624636
chipStyle: ChipStyle = ChipStyle.light(),
625637
circularProgressStyle: CircularProgressStyle = CircularProgressStyle.light(),
@@ -654,6 +666,7 @@ public fun ComponentStyling.light(
654666
undecoratedDropdownStyle: DropdownStyle = DropdownStyle.Undecorated.light(),
655667
): ComponentStyling =
656668
DefaultComponentStyling(
669+
badgeStyle = badgeStyle,
657670
checkboxStyle = checkboxStyle,
658671
chipStyle = chipStyle,
659672
circularProgressStyle = circularProgressStyle,

0 commit comments

Comments
 (0)