feat(file-explorer): add parallel thumbnail loading and file preview
- Implement parallel thumbnail queue (2 concurrent) for gallery view - Add BottomSheetModal file preview with 80% snap point - Add pull-to-refresh for directory listings - Fix image loading race conditions with Set-based in-flight tracking Also includes: - message-input: add Cmd+Shift+D dictation toggle shortcut - message: update user message bubble to darker zinc color - Add PRODUCTION.md deployment guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
edb3258ae9
commit
9d7e44851c
@@ -189,22 +189,30 @@ export function MessageInput({
|
||||
enableDuration: true,
|
||||
});
|
||||
|
||||
// Cmd+D to toggle dictation on web
|
||||
// Cmd+D to start/submit dictation, Escape to cancel
|
||||
useEffect(() => {
|
||||
if (!IS_WEB) return;
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
// Cmd+D: start dictation or submit if already dictating
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "d") {
|
||||
event.preventDefault();
|
||||
if (isDictating) {
|
||||
cancelDictation();
|
||||
sendAfterTranscriptRef.current = true;
|
||||
confirmDictation();
|
||||
} else {
|
||||
startDictation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Escape: cancel dictation
|
||||
if (event.key === "Escape" && isDictating) {
|
||||
event.preventDefault();
|
||||
cancelDictation();
|
||||
}
|
||||
}
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [isDictating, cancelDictation, startDictation]);
|
||||
}, [isDictating, cancelDictation, confirmDictation, startDictation]);
|
||||
|
||||
// Animate overlay
|
||||
useEffect(() => {
|
||||
@@ -355,17 +363,25 @@ export function MessageInput({
|
||||
if (!shouldHandleDesktopSubmit) return;
|
||||
const { shiftKey, metaKey, ctrlKey } = event.nativeEvent;
|
||||
|
||||
// Cmd+D or Ctrl+D: toggle dictation
|
||||
// Cmd+D or Ctrl+D: start dictation or submit if already dictating
|
||||
if ((metaKey || ctrlKey) && event.nativeEvent.key === "d") {
|
||||
event.preventDefault();
|
||||
if (isDictating) {
|
||||
cancelDictation();
|
||||
sendAfterTranscriptRef.current = true;
|
||||
confirmDictation();
|
||||
} else {
|
||||
startDictation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Escape: cancel dictation
|
||||
if (event.nativeEvent.key === "Escape" && isDictating) {
|
||||
event.preventDefault();
|
||||
cancelDictation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.nativeEvent.key !== "Enter") return;
|
||||
|
||||
// Shift+Enter: add newline (default behavior, don't intercept)
|
||||
@@ -561,6 +577,13 @@ const styles = StyleSheet.create(((theme: any) => ({
|
||||
xs: theme.spacing[3],
|
||||
md: theme.spacing[4],
|
||||
},
|
||||
...(IS_WEB
|
||||
? {
|
||||
transitionProperty: "border-color",
|
||||
transitionDuration: "200ms",
|
||||
transitionTimingFunction: "ease-in-out",
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
imagePreviewContainer: {
|
||||
flexDirection: "row",
|
||||
|
||||
@@ -45,7 +45,7 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
|
||||
paddingHorizontal: theme.spacing[4],
|
||||
},
|
||||
bubble: {
|
||||
backgroundColor: theme.colors.primary,
|
||||
backgroundColor: theme.colors.muted,
|
||||
borderRadius: theme.borderRadius["2xl"],
|
||||
borderTopRightRadius: theme.borderRadius.sm,
|
||||
paddingHorizontal: theme.spacing[4],
|
||||
@@ -53,7 +53,7 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
|
||||
maxWidth: "80%",
|
||||
},
|
||||
text: {
|
||||
color: theme.colors.primaryForeground,
|
||||
color: theme.colors.foreground,
|
||||
fontSize: theme.fontSize.lg,
|
||||
lineHeight: 24,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user