feat(app): unify composer attachments with pill + lightbox redesign

Images and GitHub issues/PRs now live in one draft-store list (ComposerAttachment union) with cwd persisted on the draft. Paperclip becomes a + drop-up menu; queue button removed. Each pill uses a shared AttachmentPill wrapper with a corner-X that mirrors the auto-update toast spec. Pill body opens the attachment: GitHub via openExternalUrl, images via a new fullscreen AttachmentLightbox. GitHub picker auto-closes on select.
This commit is contained in:
Mohamed Boudra
2026-04-17 11:36:08 +07:00
parent 11524dc349
commit 3838a8b969
25 changed files with 2994 additions and 735 deletions
@@ -0,0 +1,72 @@
import type { ReactNode } from "react";
import { Pressable, View } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { X } from "lucide-react-native";
interface AttachmentPillProps {
onOpen: () => void;
onRemove: () => void;
openAccessibilityLabel: string;
removeAccessibilityLabel: string;
testID?: string;
children: ReactNode;
}
export function AttachmentPill({
onOpen,
onRemove,
openAccessibilityLabel,
removeAccessibilityLabel,
testID,
children,
}: AttachmentPillProps) {
const { theme } = useUnistyles();
return (
<View style={styles.wrapper}>
<Pressable
testID={testID}
onPress={onOpen}
accessibilityRole="button"
accessibilityLabel={openAccessibilityLabel}
style={styles.body}
>
{children}
</Pressable>
<Pressable
onPress={onRemove}
hitSlop={8}
accessibilityRole="button"
accessibilityLabel={removeAccessibilityLabel}
style={styles.closeButton}
>
<X size={12} color={theme.colors.foregroundMuted} />
</Pressable>
</View>
);
}
const styles = StyleSheet.create((theme) => ({
wrapper: {
position: "relative",
},
body: {
borderRadius: theme.borderRadius.md,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.borderAccent,
overflow: "hidden",
},
closeButton: {
position: "absolute",
top: -8,
left: -8,
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: theme.colors.surface2,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
alignItems: "center",
justifyContent: "center",
zIndex: 1,
},
}));