Merge branch 'staging' of https://github.com/mazeincoding/AppCut into staging

This commit is contained in:
Maze Winther
2025-08-17 18:50:25 +02:00
2 changed files with 61 additions and 12 deletions
@@ -80,25 +80,25 @@ export function StickersView() {
<Separator className="my-4" /> <Separator className="my-4" />
<TabsContent <TabsContent
value="all" value="all"
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0" className="px-3 pt-0 mt-0 flex-1 flex flex-col min-h-0"
> >
<StickersContentView category="all" /> <StickersContentView category="all" />
</TabsContent> </TabsContent>
<TabsContent <TabsContent
value="general" value="general"
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0" className="px-3 pt-0 mt-0 flex-1 flex flex-col min-h-0"
> >
<StickersContentView category="general" /> <StickersContentView category="general" />
</TabsContent> </TabsContent>
<TabsContent <TabsContent
value="brands" value="brands"
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0" className="px-3 pt-0 mt-0 flex-1 flex flex-col min-h-0"
> >
<StickersContentView category="brands" /> <StickersContentView category="brands" />
</TabsContent> </TabsContent>
<TabsContent <TabsContent
value="emoji" value="emoji"
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0" className="px-3 pt-0 mt-0 flex-1 flex flex-col min-h-0"
> >
<StickersContentView category="emoji" /> <StickersContentView category="emoji" />
</TabsContent> </TabsContent>
@@ -111,16 +111,22 @@ function StickerGrid({
icons, icons,
onAdd, onAdd,
addingSticker, addingSticker,
capSize = false,
}: { }: {
icons: string[]; icons: string[];
onAdd: (iconName: string) => void; onAdd: (iconName: string) => void;
addingSticker: string | null; addingSticker: string | null;
capSize?: boolean;
}) { }) {
return ( return (
<div <div
className="grid gap-2" className="grid gap-2"
style={{ style={{
gridTemplateColumns: "repeat(auto-fill, 112px)", gridTemplateColumns: capSize
? "repeat(auto-fill, minmax(var(--sticker-min, 96px), var(--sticker-max, 160px)))"
: "repeat(auto-fit, minmax(var(--sticker-min, 96px), 1fr))",
["--sticker-min" as any]: "96px",
...(capSize ? ({ ["--sticker-max"]: "160px" } as any) : {}),
}} }}
> >
{icons.map((iconName) => ( {icons.map((iconName) => (
@@ -129,6 +135,7 @@ function StickerGrid({
iconName={iconName} iconName={iconName}
onAdd={onAdd} onAdd={onAdd}
isAdding={addingSticker === iconName} isAdding={addingSticker === iconName}
capSize={capSize}
/> />
))} ))}
</div> </div>
@@ -148,7 +155,7 @@ function CollectionGrid({
onSelectCollection: (prefix: string) => void; onSelectCollection: (prefix: string) => void;
}) { }) {
return ( return (
<div className="grid grid-cols-1 gap-2 h-full overflow-hidden"> <div className="grid grid-cols-1 gap-2">
{collections.map((collection) => ( {collections.map((collection) => (
<CollectionItem <CollectionItem
key={collection.prefix} key={collection.prefix}
@@ -198,6 +205,7 @@ function StickersContentView({ category }: { category: StickerCategory }) {
searchStickers, searchStickers,
downloadSticker, downloadSticker,
clearRecentStickers, clearRecentStickers,
setSelectedCategory,
} = useStickersStore(); } = useStickersStore();
const [addingSticker, setAddingSticker] = useState<string | null>(null); const [addingSticker, setAddingSticker] = useState<string | null>(null);
@@ -363,7 +371,15 @@ function StickersContentView({ category }: { category: StickerCategory }) {
setSelectedCollection(null); setSelectedCollection(null);
} }
}} }}
placeholder="Search icons..." placeholder={
category === "all"
? "Search all stickers"
: category === "general"
? "Search icons"
: category === "brands"
? "Search brands"
: "Search Emojis"
}
value={localSearchQuery} value={localSearchQuery}
onChange={setLocalSearchQuery} onChange={setLocalSearchQuery}
/> />
@@ -401,6 +417,7 @@ function StickersContentView({ category }: { category: StickerCategory }) {
icons={recentStickers.slice(0, 12)} icons={recentStickers.slice(0, 12)}
onAdd={handleAddSticker} onAdd={handleAddSticker}
addingSticker={addingSticker} addingSticker={addingSticker}
capSize
/> />
</div> </div>
)} )}
@@ -442,12 +459,32 @@ function StickersContentView({ category }: { category: StickerCategory }) {
icons={iconsToDisplay} icons={iconsToDisplay}
onAdd={handleAddSticker} onAdd={handleAddSticker}
addingSticker={addingSticker} addingSticker={addingSticker}
capSize
/> />
</> </>
) : searchQuery ? ( ) : searchQuery ? (
<div className="flex flex-col items-center justify-center py-8 gap-3">
<EmptyView <EmptyView
message={`No stickers found for "${searchQuery}"`} message={`No stickers found for "${searchQuery}"`}
/> />
{category !== "all" && (
<Button
variant="outline"
onClick={() => {
const q = localSearchQuery || searchQuery;
if (q) {
setSearchQuery(q);
}
setSelectedCategory("all");
if (q) {
searchStickers(q);
}
}}
>
Search in all icons
</Button>
)}
</div>
) : null} ) : null}
</div> </div>
)} )}
@@ -525,9 +562,10 @@ interface StickerItemProps {
iconName: string; iconName: string;
onAdd: (iconName: string) => void; onAdd: (iconName: string) => void;
isAdding?: boolean; isAdding?: boolean;
capSize?: boolean;
} }
function StickerItem({ iconName, onAdd, isAdding }: StickerItemProps) { function StickerItem({ iconName, onAdd, isAdding, capSize = false }: StickerItemProps) {
const [imageError, setImageError] = useState(false); const [imageError, setImageError] = useState(false);
const [hostIndex, setHostIndex] = useState(0); const [hostIndex, setHostIndex] = useState(0);
@@ -561,6 +599,11 @@ function StickerItem({ iconName, onAdd, isAdding }: StickerItemProps) {
width={64} width={64}
height={64} height={64}
className="w-full h-full object-contain" className="w-full h-full object-contain"
style={
capSize
? { maxWidth: "var(--sticker-max, 160px)", maxHeight: "var(--sticker-max, 160px)" }
: undefined
}
onError={() => { onError={() => {
const next = hostIndex + 1; const next = hostIndex + 1;
if (next < ICONIFY_HOSTS.length) { if (next < ICONIFY_HOSTS.length) {
@@ -598,6 +641,7 @@ function StickerItem({ iconName, onAdd, isAdding }: StickerItemProps) {
rounded={true} rounded={true}
variant="card" variant="card"
className="" className=""
containerClassName="w-full"
isDraggable={false} isDraggable={false}
/> />
{isAdding && ( {isAdding && (
@@ -21,6 +21,7 @@ export interface DraggableMediaItemProps {
onAddToTimeline?: (currentTime: number) => void; onAddToTimeline?: (currentTime: number) => void;
aspectRatio?: number; aspectRatio?: number;
className?: string; className?: string;
containerClassName?: string;
showPlusOnDrag?: boolean; showPlusOnDrag?: boolean;
showLabel?: boolean; showLabel?: boolean;
rounded?: boolean; rounded?: boolean;
@@ -36,6 +37,7 @@ export function DraggableMediaItem({
onAddToTimeline, onAddToTimeline,
aspectRatio = 16 / 9, aspectRatio = 16 / 9,
className = "", className = "",
containerClassName,
showPlusOnDrag = true, showPlusOnDrag = true,
showLabel = true, showLabel = true,
rounded = true, rounded = true,
@@ -95,7 +97,10 @@ export function DraggableMediaItem({
return ( return (
<> <>
{variant === "card" ? ( {variant === "card" ? (
<div ref={dragRef} className="relative group w-28 h-28"> <div
ref={dragRef}
className={cn("relative group", containerClassName ?? "w-28 h-28")}
>
<div <div
className={`flex flex-col gap-1 p-0 h-auto w-full relative cursor-default ${className}`} className={`flex flex-col gap-1 p-0 h-auto w-full relative cursor-default ${className}`}
> >