Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/deploy-gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ jobs:
</html>
HTMLEOF

- name: Inject no-cache headers for staging
run: |
# Add no-cache meta tags to all HTML files for staging environment
find dist -name "*.html" -exec sed -i 's/<head>/<head>\n <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">\n <meta http-equiv="Pragma" content="no-cache">\n <meta http-equiv="Expires" content="0">/' {} \;
echo "Injected no-cache headers into $(find dist -name '*.html' | wc -l) HTML files"
Comment on lines +128 to +132
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Wrong directory: dist should be docs-dist.

The documentation is built to docs-dist/ (see lines 52, 140), but this step searches in dist/. The find command will either fail or find zero files, so no cache headers will be injected.

🐛 Proposed fix
      - name: Inject no-cache headers for staging
        run: |
          # Add no-cache meta tags to all HTML files for staging environment
-          find dist -name "*.html" -exec sed -i 's/<head>/<head>\n  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">\n  <meta http-equiv="Pragma" content="no-cache">\n  <meta http-equiv="Expires" content="0">/' {} \;
-          echo "Injected no-cache headers into $(find dist -name '*.html' | wc -l) HTML files"
+          find docs-dist -name "*.html" -exec sed -i 's/<head>/<head>\n  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">\n  <meta http-equiv="Pragma" content="no-cache">\n  <meta http-equiv="Expires" content="0">/' {} \;
+          echo "Injected no-cache headers into $(find docs-dist -name '*.html' | wc -l) HTML files"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Inject no-cache headers for staging
run: |
# Add no-cache meta tags to all HTML files for staging environment
find dist -name "*.html" -exec sed -i 's/<head>/<head>\n <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">\n <meta http-equiv="Pragma" content="no-cache">\n <meta http-equiv="Expires" content="0">/' {} \;
echo "Injected no-cache headers into $(find dist -name '*.html' | wc -l) HTML files"
- name: Inject no-cache headers for staging
run: |
# Add no-cache meta tags to all HTML files for staging environment
find docs-dist -name "*.html" -exec sed -i 's/<head>/<head>\n <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">\n <meta http-equiv="Pragma" content="no-cache">\n <meta http-equiv="Expires" content="0">/' {} \;
echo "Injected no-cache headers into $(find docs-dist -name '*.html' | wc -l) HTML files"
🤖 Prompt for AI Agents
In @.github/workflows/deploy-gh-pages.yml around lines 128 - 132, The "Inject
no-cache headers for staging" step is searching the wrong directory; change the
find invocations that reference "dist" to "docs-dist" so the sed injection and
the file count (the find ... | wc -l in the echo) operate on the built
documentation; update both the find used for sed and the find used in the echo
to use "docs-dist" (preserve the existing sed expression and step name).


- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0

Expand Down
3 changes: 2 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
]
],
"experiments": {
"typedRoutes": true
"typedRoutes": true,
"baseUrl": "/thumbcode"
},
"extra": {
"router": {
Expand Down
35 changes: 26 additions & 9 deletions app/(onboarding)/api-keys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* API Keys Screen
*
* Collects AI provider API keys (Anthropic/OpenAI).
* Uses paint daube icons for brand consistency.
*/

import { CredentialService } from '@thumbcode/core/src/credentials/CredentialService';
Expand All @@ -10,6 +11,7 @@ import { useState } from 'react';
import { ActivityIndicator, Pressable, ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StepsProgress } from '@/components/feedback';
import { CloseIcon, LightbulbIcon, SecurityIcon, SuccessIcon } from '@/components/icons';
import { Container, VStack } from '@/components/layout';
import { Input, Text } from '@/components/ui';

Expand Down Expand Up @@ -129,7 +131,9 @@ export default function ApiKeysScreen() {
}}
>
<View className="flex-row items-center mb-2">
<Text className="text-lg mr-2">🔐</Text>
<View className="mr-2">
<SecurityIcon size={20} color="teal" turbulence={0.2} />
</View>
<Text weight="semibold" className="text-teal-400">
Your Keys, Your Device
</Text>
Expand All @@ -147,8 +151,12 @@ export default function ApiKeysScreen() {
Anthropic (Claude)
</Text>
{anthropicKey.isValidating && <ActivityIndicator size="small" color="#14B8A6" />}
{anthropicKey.isValid === true && <Text className="text-teal-400">✓</Text>}
{anthropicKey.isValid === false && <Text className="text-coral-400">✕</Text>}
{anthropicKey.isValid === true && (
<SuccessIcon size={18} color="teal" turbulence={0.15} />
)}
{anthropicKey.isValid === false && (
<CloseIcon size={18} color="coral" turbulence={0.15} />
)}
</View>

<Input
Expand All @@ -171,8 +179,12 @@ export default function ApiKeysScreen() {
OpenAI (GPT-4)
</Text>
{openaiKey.isValidating && <ActivityIndicator size="small" color="#14B8A6" />}
{openaiKey.isValid === true && <Text className="text-teal-400">✓</Text>}
{openaiKey.isValid === false && <Text className="text-coral-400">✕</Text>}
{openaiKey.isValid === true && (
<SuccessIcon size={18} color="teal" turbulence={0.15} />
)}
{openaiKey.isValid === false && (
<CloseIcon size={18} color="coral" turbulence={0.15} />
)}
</View>

<Input
Expand All @@ -198,10 +210,15 @@ export default function ApiKeysScreen() {
borderBottomLeftRadius: 10,
}}
>
<Text size="sm" className="text-neutral-400">
💡 <Text className="text-white">Tip:</Text> You can add more providers later in
Settings. At least one key is recommended to enable AI agents.
</Text>
<View className="flex-row items-start">
<View className="mr-2 mt-0.5">
<LightbulbIcon size={16} color="gold" turbulence={0.2} />
</View>
<Text size="sm" className="text-neutral-400 flex-1">
<Text className="text-white">Tip:</Text> You can add more providers later in
Settings. At least one key is recommended to enable AI agents.
</Text>
</View>
</View>
</Container>
</ScrollView>
Expand Down
56 changes: 48 additions & 8 deletions app/(onboarding)/complete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,61 @@
* Complete Screen
*
* Final onboarding screen - celebrates completion and launches main app.
* Uses paint daube icons for brand consistency.
*/

import { useRouter } from 'expo-router';
import type React from 'react';
import { useEffect, useRef } from 'react';
import { Animated, Pressable, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
AgentIcon,
CelebrateIcon,
ChatIcon,
type IconColor,
MobileIcon,
SuccessIcon,
TasksIcon,
} from '@/components/icons';
import { Container, VStack } from '@/components/layout';
import { Text } from '@/components/ui';
import { useOnboarding } from '@/contexts/onboarding';

const CAPABILITIES = [
{ icon: '🤖', title: 'AI Agent Teams', description: 'Multi-agent collaboration ready' },
{ icon: '📱', title: 'Mobile Git', description: 'Clone, commit, push from your phone' },
{ icon: '💬', title: 'Real-time Chat', description: 'Direct agent communication' },
{ icon: '📊', title: 'Progress Tracking', description: 'Monitor tasks and metrics' },
type CapabilityIcon = React.FC<{ size?: number; color?: IconColor; turbulence?: number }>;

interface Capability {
Icon: CapabilityIcon;
iconColor: IconColor;
title: string;
description: string;
}

const CAPABILITIES: Capability[] = [
{
Icon: AgentIcon,
iconColor: 'coral',
title: 'AI Agent Teams',
description: 'Multi-agent collaboration ready',
},
{
Icon: MobileIcon,
iconColor: 'teal',
title: 'Mobile Git',
description: 'Clone, commit, push from your phone',
},
{
Icon: ChatIcon,
iconColor: 'gold',
title: 'Real-time Chat',
description: 'Direct agent communication',
},
{
Icon: TasksIcon,
iconColor: 'teal',
title: 'Progress Tracking',
description: 'Monitor tasks and metrics',
},
];

export default function CompleteScreen() {
Expand Down Expand Up @@ -69,7 +109,7 @@ export default function CompleteScreen() {
borderBottomLeftRadius: 32,
}}
>
<Text className="text-6xl">🎉</Text>
<CelebrateIcon size={64} color="gold" turbulence={0.3} />
</View>
</Animated.View>

Expand Down Expand Up @@ -108,7 +148,7 @@ export default function CompleteScreen() {
borderBottomLeftRadius: 10,
}}
>
<Text className="text-2xl">{cap.icon}</Text>
<cap.Icon size={24} color={cap.iconColor} turbulence={0.2} />
</View>
<View className="flex-1">
<Text weight="semibold" className="text-white">
Expand All @@ -118,7 +158,7 @@ export default function CompleteScreen() {
{cap.description}
</Text>
</View>
<Text className="text-teal-400">✓</Text>
<SuccessIcon size={20} color="teal" turbulence={0.2} />
</View>
))}
</VStack>
Expand Down
30 changes: 25 additions & 5 deletions app/(onboarding)/create-project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Create Project Screen
*
* Helps user create their first project by connecting a repository.
* Uses paint daube icons for brand consistency.
*/

import { CredentialService } from '@thumbcode/core/src/credentials/CredentialService';
Expand All @@ -11,6 +12,7 @@ import { useState } from 'react';
import { ActivityIndicator, Pressable, ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StepsProgress } from '@/components/feedback';
import { FolderIcon, SecurityIcon, StarIcon, SuccessIcon } from '@/components/icons';
import { Container, VStack } from '@/components/layout';
import { Input, Text } from '@/components/ui';

Expand Down Expand Up @@ -159,18 +161,36 @@ export default function CreateProjectScreen() {
}}
>
<View className="flex-row items-center mb-2">
<Text className="mr-2">{repo.isPrivate ? '🔒' : '📂'}</Text>
<View className="mr-2">
{repo.isPrivate ? (
<SecurityIcon size={18} color="warmGray" turbulence={0.15} />
) : (
<FolderIcon size={18} color="gold" turbulence={0.15} />
)}
</View>
<Text weight="semibold" className="text-white flex-1">
{repo.name}
</Text>
{selectedRepo?.id === repo.id && <Text className="text-teal-400">✓</Text>}
{selectedRepo?.id === repo.id && (
<SuccessIcon size={18} color="teal" turbulence={0.15} />
)}
</View>
<Text size="sm" className="text-neutral-400" numberOfLines={1}>
{repo.description}
</Text>
<Text size="xs" className="text-neutral-500 mt-1">
{repo.fullName} {repo.stars > 0 && `⭐ ${repo.stars}`}
</Text>
<View className="flex-row items-center mt-1">
<Text size="xs" className="text-neutral-500">
{repo.fullName}
</Text>
{repo.stars > 0 && (
<View className="flex-row items-center ml-2">
<StarIcon size={12} color="gold" turbulence={0.15} />
<Text size="xs" className="text-neutral-500 ml-1">
{repo.stars}
</Text>
</View>
)}
</View>
</Pressable>
))}
</VStack>
Expand Down
10 changes: 8 additions & 2 deletions app/(onboarding)/github-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
* GitHub Auth Screen
*
* Guides user through GitHub Device Flow authentication.
* Uses paint daube icons for brand consistency.
*/

import { useRouter } from 'expo-router';
import { useState } from 'react';
import { ActivityIndicator, Linking, Pressable, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StepsProgress } from '@/components/feedback';
import { LinkIcon, SuccessIcon } from '@/components/icons';
import { Container, VStack } from '@/components/layout';
import { Text } from '@/components/ui';

Expand Down Expand Up @@ -80,7 +82,9 @@ export default function GitHubAuthScreen() {
borderBottomLeftRadius: 12,
}}
>
<Text className="text-3xl text-center mb-4">🔗</Text>
<View className="items-center mb-4">
<LinkIcon size={40} color="teal" turbulence={0.25} />
</View>
<Text weight="semibold" className="text-white text-center mb-2">
Secure Device Flow
</Text>
Expand Down Expand Up @@ -184,7 +188,9 @@ export default function GitHubAuthScreen() {
borderBottomLeftRadius: 12,
}}
>
<Text className="text-4xl text-center mb-4">✓</Text>
<View className="items-center mb-4">
<SuccessIcon size={48} color="teal" turbulence={0.25} />
</View>
<Text weight="semibold" className="text-teal-400 text-center text-lg">
GitHub Connected!
</Text>
Expand Down
56 changes: 48 additions & 8 deletions app/(onboarding)/welcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,75 @@
* Welcome Screen
*
* First screen of onboarding flow. Introduces ThumbCode and its features.
* Uses procedural paint daube icons for brand consistency.
*/

import { useRouter } from 'expo-router';
import { Pressable, ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
AgentIcon,
type IconVariant,
LightningIcon,
MobileIcon,
SecurityIcon,
ThumbIcon,
} from '@/components/icons';
import { VStack } from '@/components/layout';
import { Text } from '@/components/ui';

const FEATURES = [
interface Feature {
icon: IconVariant;
title: string;
description: string;
color: 'coral' | 'teal' | 'gold';
}

const FEATURES: Feature[] = [
{
icon: '🤖',
icon: 'agent',
title: 'AI Agent Teams',
description: 'Architect, Implementer, Reviewer, and Tester agents work in parallel',
color: 'coral',
},
{
icon: '📱',
icon: 'mobile',
title: 'Mobile-First Git',
description: 'Full git workflow from your phone with isomorphic-git',
color: 'teal',
},
{
icon: '🔐',
icon: 'security',
title: 'Your Keys, Your Control',
description: 'API keys never leave your device - stored in secure hardware',
color: 'gold',
},
{
icon: '',
icon: 'lightning',
title: 'Zero Server Costs',
description: 'Bring your own keys - no subscriptions, no vendor lock-in',
color: 'coral',
},
];

/** Feature icon component that renders the appropriate paint daube icon */
function FeatureIcon({ variant, color }: { variant: IconVariant; color: Feature['color'] }) {
const iconProps = { size: 28, color, turbulence: 0.25 };

switch (variant) {
case 'agent':
return <AgentIcon {...iconProps} />;
case 'mobile':
return <MobileIcon {...iconProps} />;
case 'security':
return <SecurityIcon {...iconProps} />;
case 'lightning':
return <LightningIcon {...iconProps} />;
default:
return <AgentIcon {...iconProps} />;
}
}

export default function WelcomeScreen() {
const router = useRouter();
const insets = useSafeAreaInsets();
Expand All @@ -55,7 +93,7 @@ export default function WelcomeScreen() {
borderBottomLeftRadius: 20,
}}
>
<Text className="text-5xl">👍</Text>
<ThumbIcon size={48} color="charcoal" turbulence={0.2} />
</View>

<Text variant="display" size="4xl" weight="bold" className="text-coral-500 text-center">
Expand All @@ -69,7 +107,7 @@ export default function WelcomeScreen() {

{/* Features */}
<VStack spacing="md" className="mb-8">
{FEATURES.map((feature) => (
{FEATURES.map((feature, _index) => (
<View
key={feature.title}
className="bg-surface p-4 flex-row items-start"
Expand All @@ -80,7 +118,9 @@ export default function WelcomeScreen() {
borderBottomLeftRadius: 10,
}}
>
<Text className="text-2xl mr-4">{feature.icon}</Text>
<View className="mr-4">
<FeatureIcon variant={feature.icon} color={feature.color} />
</View>
<View className="flex-1">
<Text weight="semibold" className="text-white mb-1">
{feature.title}
Expand Down
Loading
Loading