mobile v0.1 with deployment for ios (#191)

* stage 1: project init

* stage 2: skeleton with navigation

* step 2.5: streams list

* step 4: stream playback experience

* step 5-6: compose experience

* fix: broken record

* transcode media particles to mp4

* build: reproducible go generate

* build: rename skaffold module for particle processor worker

* infra: increase particle processor worker resources

Was dealing with OOM errors

* tweaks to mobile

* log transcode work

* view on desktop placeholder

* tweak padding

* cap video resolution to save on memory

* infra: bump memory limits as insurance

* ux improvements

* update bundle id for mobile

* config for mobile
This commit was merged in pull request #191.
This commit is contained in:
Arjun Patel
2026-04-29 17:39:11 -07:00
committed by GitHub
parent 3a11a82cd3
commit e3461dd5cd
110 changed files with 14682 additions and 22 deletions
+60
View File
@@ -0,0 +1,60 @@
import { Text, View } from "react-native";
import type { Human } from "@/api/types";
import { resolveHumanDisplay } from "@/lib/humans";
import { cn } from "@/lib/utils";
type Size = "xs" | "sm" | "md";
interface AvatarProps {
humanId: string | null | undefined;
humans: Human[] | undefined;
size?: Size;
/** True for online presence — adds a green ring (matches desktop). */
online?: boolean;
/** Background ring used to separate stacked avatars from the chrome. */
stackBg?: string;
className?: string;
}
const sizeMap: Record<Size, { box: string; text: string; ring: number }> = {
xs: { box: "h-6 w-6", text: "text-[9px]", ring: 1.5 },
sm: { box: "h-9 w-9", text: "text-xs", ring: 2 },
md: { box: "h-10 w-10", text: "text-sm", ring: 2 },
};
/**
* Initials avatar with optional online ring (green) and an optional outer
* stack ring used to visually separate overlapping avatars on a busy chrome.
* Matches desktop's avatar + presence pattern (`ring-2 ring-green-500`).
*/
export function Avatar({
humanId,
humans,
size = "sm",
online = false,
stackBg,
className,
}: AvatarProps) {
const { initials } = resolveHumanDisplay(humanId, humans);
const dims = sizeMap[size];
return (
<View
className={cn(
"bg-black/15 items-center justify-center rounded-full",
dims.box,
className,
)}
style={{
// Online ring is the priority; if not online, show the stack
// separator ring (if requested) so adjacent avatars stay distinct.
borderWidth: online ? dims.ring : stackBg ? dims.ring : 0,
borderColor: online ? "#22c55e" : stackBg ?? "transparent",
}}
>
<Text className={cn("text-white font-semibold", dims.text)}>
{initials}
</Text>
</View>
);
}