diff --git a/docker/README.md b/docker/README.md index 649b1699..45b80ff2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -78,6 +78,11 @@ resolves consistently in native captures; the approved JSON weights stay unchang Nav, picker names, labels and pill weights use that same mapping. Nav label colour fades for 200 ms ease-out; the blob retains its critically damped spring. +Settings pills have a separate 1 dp stroke (2 px on the stage), not a focus ring. +The stroke is inset within the fixed 20 dp / 40 px height; horizontal border-box +padding includes it. The 6 px dash / 4 px gap follows the browser's 3:2 stroke-width +ratios. Resting borders are white at 22% opacity; focused borders use ink at 40%. + The small gear under the final person opens Settings with Requests focused. Settings groups hand off to existing upstream pages; the Requests entry explicitly has no request data yet. **Advanced settings → Wolfskin screens** is the persistent diff --git a/wolfskin-design/shell-tokens.json b/wolfskin-design/shell-tokens.json index d5e0c688..b24e8e97 100644 --- a/wolfskin-design/shell-tokens.json +++ b/wolfskin-design/shell-tokens.json @@ -215,6 +215,32 @@ "dp": 20.0, "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" }, + "settingsPillStroke": { + "$type": "dimension", + "px": 2, + "dp": 1.0, + "source": "index.html:122; pill border 2 px inside its 40 px border-box" + }, + "settingsPillDashRatio": { + "$type": "number", + "$value": 3, + "source": "st-091 frozen browser top border: 6 px dashes at 2 px stroke width" + }, + "settingsPillDashGapRatio": { + "$type": "number", + "$value": 2, + "source": "st-091 frozen browser top border: 4 px gaps at 2 px stroke width" + }, + "settingsPillBorder": { + "$type": "color", + "$value": "#ffffff38", + "source": "index.html:122; white at 22 percent opacity, rounded to 8-bit alpha" + }, + "settingsPillFocusedBorder": { + "$type": "color", + "$value": "#0b0b1066", + "source": "index.html:328; focused pill ink at 40 percent opacity" + }, "settingsPillPadding": { "$type": "dimension", "px": 16, diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt index 9823c319..91bf3bb3 100644 --- a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt @@ -24,8 +24,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalDensity @@ -108,10 +110,19 @@ fun SettingsRow(group: SettingsGroup, focused: Boolean, openRequests: Int?, modi @Composable private fun SettingsPill(label: String, focused: Boolean) { val foreground = if (focused) C.onFocus else C.dim - Box(Modifier.height(S.settingsPillHeight).drawBehind { - val stroke = WolfskinTokens.Focus.ringButtonRing.toPx() - drawRoundRect(foreground.copy(alpha = .4f), cornerRadius = CornerRadius(WolfskinTokens.Radius.pill.toPx()), style = Stroke(stroke, pathEffect = PathEffect.dashPathEffect(floatArrayOf(stroke * 2, stroke * 2)))) - }.padding(horizontal = S.settingsPillPadding), contentAlignment = Alignment.Center) { + val border = if (focused) S.settingsPillFocusedBorder else S.settingsPillBorder + Box(Modifier.height(S.settingsPillHeight).drawWithCache { + val stroke = S.settingsPillStroke.toPx() + val inset = Offset(stroke / 2, stroke / 2) + val bounds = Size(size.width - stroke, size.height - stroke) + val outline = Stroke(stroke, pathEffect = PathEffect.dashPathEffect( + floatArrayOf(stroke * S.settingsPillDashRatio, stroke * S.settingsPillDashGapRatio), + )) + val radius = CornerRadius(WolfskinTokens.Radius.pill.toPx()) + onDrawBehind { + drawRoundRect(border, topLeft = inset, size = bounds, cornerRadius = radius, style = outline) + } + }.padding(horizontal = S.settingsPillPadding + S.settingsPillStroke), contentAlignment = Alignment.Center) { Text(label, color = foreground, style = WolfskinTokens.Type.caption.copy(fontWeight = WolfskinTokens.Type.label.fontWeight)) } } diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt index d936c34d..43f58aec 100644 --- a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt @@ -266,6 +266,11 @@ object WolfskinTokens { val settingsRowGap = 12.0.dp val settingsIcon = 18.0.dp val settingsPillHeight = 20.0.dp + val settingsPillStroke = 1.0.dp + const val settingsPillDashRatio = 3.0f + const val settingsPillDashGapRatio = 2.0f + val settingsPillBorder = ComposeColor(0x38FFFFFF) + val settingsPillFocusedBorder = ComposeColor(0x660B0B10) val settingsPillPadding = 8.0.dp val settingsPillGap = 6.0.dp val settingsChevron = 15.0.dp diff --git a/wolfskin-design/tokens.css b/wolfskin-design/tokens.css index 202d1d24..3221a4b7 100644 --- a/wolfskin-design/tokens.css +++ b/wolfskin-design/tokens.css @@ -163,6 +163,9 @@ --shell-settingsRowGap: 24.0px; --shell-settingsIcon: 36.0px; --shell-settingsPillHeight: 40.0px; + --shell-settingsPillStroke: 2.0px; + --shell-settingsPillBorder: #ffffff38; + --shell-settingsPillFocusedBorder: #0b0b1066; --shell-settingsPillPadding: 16.0px; --shell-settingsPillGap: 12.0px; --shell-settingsChevron: 30.0px; diff --git a/wolfskin-design/tokens.sha256 b/wolfskin-design/tokens.sha256 index 579c9cbf..a9a2a837 100644 --- a/wolfskin-design/tokens.sha256 +++ b/wolfskin-design/tokens.sha256 @@ -1,6 +1,6 @@ 28f6f7bb878b8388ce04293cd2819bc1cb684da34925c9ddcded78fcddf6d1dd generate_tokens.py 73398fc0d3d6b780170fa6d7ef9246f788c800c499981fde092fe790330c8ad1 home-tokens.json -6d1d19656b40e6a442cb548bb238bb12244adb6b3b717ed9e564af61119559c8 shell-tokens.json -6e0fc478d40589aa552b880a91940361e9f6c85ef720103ffa8eb87358e296ac src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt -7c8bc2d2db273e67a0b45cacdbbe9046bb4f4224b05d83f8e103dedb95138888 tokens.css +408b7c3f4db2028deda97ac0570a57a4da4877917fd0980b2bfa5afe8f8fa790 shell-tokens.json +3ff67d4867c2735ed2ad7ffc66bbfb04dad5f0000072daa2f5e98ed1b7059dde src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt +7ded358afa758c8b0dd191d650d06dc0bcfc8dcc2baebba2c07a3e70c435ff5a tokens.css 5b939f1f3eb90b428008fda75720f6e3a4e844c486668931db3d52bffb987b53 tokens.json