mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-31 23:16:24 +00:00
Implement Handler mobile app (React Native + Expo iOS)
Build the committed 2a interactive prototype from Handler Mobile.dc.html as a real Expo app: six wired screens (Fleet, Agent detail, Answer, Spawn, Log, Settings) with the exact state logic ported from the design's renderVals(). - Port Leeworks tokens (colors light/dark, typography, spacing, radii, shadows) to typed RN values in src/theme. - Reimplement the design-system components used by the screens (Button, Badge, Icon, Switch, Select, TextField, segmented control, chip, tab bar). - Shared store mirrors the prototype's single-screen navigation and the Waiting -> Running flip when agt-7a1d is answered. - Real OS status bar / home indicator (safe-area insets) replace the mock phone chrome; dark mode follows system appearance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PdF2hHVQ4UUBFPtpeMQ81o
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import React from "react";
|
||||
import Svg, { Circle, Path } from "react-native-svg";
|
||||
|
||||
/**
|
||||
* Leeworks Icon — the Lucide subset used by the Handler screens, ported from
|
||||
* components/display/Icon.jsx. Monochrome, 1.75px stroke, `currentColor`
|
||||
* becomes the required `color` prop since RN SVG doesn't inherit it.
|
||||
*/
|
||||
|
||||
export type IconName =
|
||||
| "chevronRight"
|
||||
| "chevronDown"
|
||||
| "home"
|
||||
| "file"
|
||||
| "settings"
|
||||
| "x";
|
||||
|
||||
const paths: Record<IconName, React.ReactNode> = {
|
||||
chevronRight: <Path d="m9 18 6-6-6-6" />,
|
||||
chevronDown: <Path d="m6 9 6 6 6-6" />,
|
||||
home: (
|
||||
<>
|
||||
<Path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<Path d="M9 22V12h6v10" />
|
||||
</>
|
||||
),
|
||||
file: (
|
||||
<>
|
||||
<Path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
|
||||
<Path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
||||
</>
|
||||
),
|
||||
settings: (
|
||||
<>
|
||||
<Path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
|
||||
<Circle cx="12" cy="12" r="3" />
|
||||
</>
|
||||
),
|
||||
x: <Path d="M18 6 6 18M6 6l12 12" />,
|
||||
};
|
||||
|
||||
interface IconProps {
|
||||
name: IconName;
|
||||
size?: number;
|
||||
color: string;
|
||||
strokeWidth?: number;
|
||||
/** Degrees; the detail/answer back arrows reuse chevronRight rotated 180. */
|
||||
rotate?: number;
|
||||
}
|
||||
|
||||
export function Icon({
|
||||
name,
|
||||
size = 18,
|
||||
color,
|
||||
strokeWidth = 1.75,
|
||||
rotate,
|
||||
}: IconProps) {
|
||||
return (
|
||||
<Svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
style={rotate ? { transform: [{ rotate: `${rotate}deg` }] } : undefined}
|
||||
>
|
||||
{paths[name]}
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user