mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 16:57:39 +00:00
fix(desktop): search pill visibility, sidebar + Add Feed button
- SearchPill: fix collapsed state not rendering — removed nested Box/Surface/matchParentSize, replaced with simple if/else on expanded state within single Surface+Row - Sidebar: add "+ Add Feed" item below custom feeds in FEEDS section - Dropdown menu moves outside Surface to render properly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
55e7fcb903
commit
c69c4462b9
+9
@@ -231,6 +231,15 @@ fun MainSidebar(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// "+ Add Feed" button
|
||||
SidebarNavItem(
|
||||
icon = MaterialSymbols.Add,
|
||||
label = "Add Feed",
|
||||
isActive = false,
|
||||
expanded = expanded,
|
||||
onClick = onAddColumn,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+143
-202
@@ -47,7 +47,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
@@ -64,11 +63,6 @@ import com.vitorpamplona.amethyst.desktop.SearchHistoryStore
|
||||
import com.vitorpamplona.amethyst.desktop.platform.PlatformInfo
|
||||
import com.vitorpamplona.amethyst.desktop.ui.theme.hoverHighlight
|
||||
|
||||
/**
|
||||
* Search pill that expands inline into a text input with history dropdown.
|
||||
* Collapsed: clickable pill with search icon + shortcut hint.
|
||||
* Expanded: BasicTextField in same pill shape + dropdown below with recent/saved searches.
|
||||
*/
|
||||
@Composable
|
||||
fun SearchPill(
|
||||
onClick: () -> Unit,
|
||||
@@ -84,214 +78,161 @@ fun SearchPill(
|
||||
val savedSearches by SearchHistoryStore.savedSearches.collectAsState()
|
||||
|
||||
Surface(
|
||||
onClick = { expanded = true },
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
modifier = modifier.height(36.dp).hoverHighlight(),
|
||||
) {
|
||||
Box {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.Search,
|
||||
contentDescription = "Search",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
|
||||
if (expanded) {
|
||||
// Expanded: inline text input
|
||||
BasicTextField(
|
||||
value = textFieldValue,
|
||||
onValueChange = { textFieldValue = it },
|
||||
modifier =
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.focusRequester(focusRequester)
|
||||
.onPreviewKeyEvent { event ->
|
||||
if (event.type == KeyEventType.KeyDown && event.key == Key.Escape) {
|
||||
expanded = false
|
||||
textFieldValue = TextFieldValue("")
|
||||
focusManager.clearFocus()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
textStyle =
|
||||
MaterialTheme.typography.labelMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
),
|
||||
singleLine = true,
|
||||
decorationBox = { innerTextField ->
|
||||
Box(contentAlignment = Alignment.CenterStart) {
|
||||
if (textFieldValue.text.isEmpty()) {
|
||||
Text(
|
||||
"Search notes, profiles...",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
innerTextField()
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
"Search...",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
shortcutHint,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown below the pill when expanded
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = {
|
||||
expanded = false
|
||||
textFieldValue = TextFieldValue("")
|
||||
},
|
||||
) {
|
||||
if (history.isNotEmpty()) {
|
||||
Text(
|
||||
"Recent",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
)
|
||||
history.take(5).forEach { query ->
|
||||
val text = QuerySerializer.serialize(query)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
textFieldValue = TextFieldValue(text, TextRange(text.length))
|
||||
}.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.Search,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Icon(MaterialSymbols.History, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
BasicTextField(
|
||||
value = textFieldValue,
|
||||
onValueChange = { textFieldValue = it },
|
||||
modifier =
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.focusRequester(focusRequester)
|
||||
.onFocusChanged { state ->
|
||||
if (!state.isFocused && expanded) {
|
||||
expanded = false
|
||||
textFieldValue = TextFieldValue("")
|
||||
}
|
||||
}.onPreviewKeyEvent { event ->
|
||||
if (event.type == KeyEventType.KeyDown && event.key == Key.Escape) {
|
||||
expanded = false
|
||||
textFieldValue = TextFieldValue("")
|
||||
focusManager.clearFocus()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
textStyle =
|
||||
MaterialTheme.typography.labelMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
),
|
||||
singleLine = true,
|
||||
decorationBox = { innerTextField ->
|
||||
Box(contentAlignment = Alignment.CenterStart) {
|
||||
if (textFieldValue.text.isEmpty()) {
|
||||
Text(
|
||||
"Search notes, profiles...",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
innerTextField()
|
||||
}
|
||||
},
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
shortcutHint,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
|
||||
// Dropdown with history
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = {
|
||||
expanded = false
|
||||
textFieldValue = TextFieldValue("")
|
||||
},
|
||||
) {
|
||||
if (history.isNotEmpty()) {
|
||||
Text(
|
||||
"Recent",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
)
|
||||
history.take(5).forEach { query ->
|
||||
val text = QuerySerializer.serialize(query)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
textFieldValue = TextFieldValue(text, TextRange(text.length))
|
||||
onClick()
|
||||
}.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.History,
|
||||
null,
|
||||
Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(text, style = MaterialTheme.typography.bodySmall, maxLines = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (savedSearches.isNotEmpty()) {
|
||||
if (history.isNotEmpty()) {
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
|
||||
}
|
||||
Text(
|
||||
"Saved",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
)
|
||||
savedSearches.take(5).forEach { saved ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.Bookmark,
|
||||
null,
|
||||
Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(saved.label, style = MaterialTheme.typography.bodySmall, maxLines = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (history.isEmpty() && savedSearches.isEmpty()) {
|
||||
Text(
|
||||
"Type to search",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.AutoMirrored.OpenInNew,
|
||||
null,
|
||||
Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
"Open full search",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Collapsed: clickable pill
|
||||
Surface(
|
||||
onClick = {
|
||||
expanded = true
|
||||
},
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
) {
|
||||
Icon(
|
||||
MaterialSymbols.Search,
|
||||
contentDescription = "Search",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
"Search...",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
shortcutHint,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
Text(text, style = MaterialTheme.typography.bodySmall, maxLines = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (savedSearches.isNotEmpty()) {
|
||||
if (history.isNotEmpty()) {
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
|
||||
}
|
||||
Text(
|
||||
"Saved",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
)
|
||||
savedSearches.take(5).forEach { saved ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(MaterialSymbols.Bookmark, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(saved.label, style = MaterialTheme.typography.bodySmall, maxLines = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (history.isEmpty() && savedSearches.isEmpty()) {
|
||||
Text(
|
||||
"Type to search",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
.hoverHighlight()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
) {
|
||||
Icon(MaterialSymbols.AutoMirrored.OpenInNew, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Open full search", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
|
||||
Reference in New Issue
Block a user