mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
feat: add webcontainer connect route and new preview functionality
- Add new route `webcontainer.connect.$id.tsx` for WebContainer connection - Implement `openInNewTab` function in `Preview.tsx` for opening previews in new tabs - Update GitHub template fetching logic to include lock files for improved install times - Add new Expo starter template to constants - Extend prompts with mobile app development instructions -Templates now use Releases from github as a work around for rate limits
This commit is contained in:
@@ -565,6 +565,12 @@ export const Preview = memo(() => {
|
||||
}
|
||||
};
|
||||
|
||||
const openInNewTab = () => {
|
||||
if (activePreview?.baseUrl) {
|
||||
window.open(activePreview?.baseUrl, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
// Function to get the correct frame padding based on orientation
|
||||
const getFramePadding = useCallback(() => {
|
||||
if (!selectedWindowSize) {
|
||||
@@ -767,8 +773,17 @@ export const Preview = memo(() => {
|
||||
<span className="text-sm font-medium text-[#111827] dark:text-gray-300">Device Options</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
className={`flex w-full justify-between items-center text-start bg-transparent text-xs text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary`}
|
||||
onClick={() => {
|
||||
openInNewTab();
|
||||
}}
|
||||
>
|
||||
<span>Open in new tab</span>
|
||||
<div className='i-ph:arrow-square-out h-5 w-4'/>
|
||||
</button>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-[#6B7280] dark:text-gray-400">Show Device Frame</span>
|
||||
<span className="text-xs text-bolt-elements-textTertiary">Show Device Frame</span>
|
||||
<button
|
||||
className={`w-10 h-5 rounded-full transition-colors duration-200 ${
|
||||
showDeviceFrame ? 'bg-[#6D28D9]' : 'bg-gray-300 dark:bg-gray-700'
|
||||
@@ -786,7 +801,7 @@ export const Preview = memo(() => {
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-[#6B7280] dark:text-gray-400">Landscape Mode</span>
|
||||
<span className="text-xs text-bolt-elements-textTertiary">Landscape Mode</span>
|
||||
<button
|
||||
className={`w-10 h-5 rounded-full transition-colors duration-200 ${
|
||||
isLandscape ? 'bg-[#6D28D9]' : 'bg-gray-300 dark:bg-gray-700'
|
||||
|
||||
@@ -476,6 +476,238 @@ Here are some examples of correct usage of artifacts:
|
||||
</assistant_response>
|
||||
</example>
|
||||
</examples>
|
||||
|
||||
<mobile_app_instructions>
|
||||
The following instructions guide how you should handle mobile app development using Expo and React Native.
|
||||
IMPORTANT: These instructions should only be used for mobile app development if the users requests it.
|
||||
|
||||
<core_requirements>
|
||||
- Version: 2025
|
||||
- Platform: Web-first with mobile compatibility
|
||||
- Expo SDK: 52.0.30
|
||||
- Expo Router: 4.0.20
|
||||
- Type: Expo Managed Workflow
|
||||
- You have been given an example package.json below you dont need to add every dependency to the package.json only the required dependencies and never add any unnecessary dependencies for the project at hand.
|
||||
|
||||
<design_philosophy>
|
||||
- All designs MUST be beautiful and professional, not cookie cutter
|
||||
- Apps MUST be fully featured and production-ready
|
||||
- Implement unique, thoughtful user experiences
|
||||
- Focus on clean, maintainable code structure
|
||||
- Every component must be properly typed with TypeScript
|
||||
- All UI must be responsive and work across all screen sizes
|
||||
</design_philosophy>
|
||||
</core_requirements>
|
||||
|
||||
<project_structure>
|
||||
/app # All routes must be here
|
||||
├── _layout.tsx # Root layout (required)
|
||||
├── +not-found.tsx # 404 handler
|
||||
└── (tabs)/ # Tab-based navigation group
|
||||
├── _layout.tsx # Tab configuration
|
||||
└── [tab].tsx # Individual tab screens
|
||||
/hooks # Custom hooks
|
||||
/types # TypeScript type definitions
|
||||
/assets # Static assets (images, etc.)
|
||||
</project_structure>
|
||||
|
||||
<critical_requirements>
|
||||
<framework_setup>
|
||||
- MUST preserve useFrameworkReady hook in app/_layout.tsx
|
||||
- MUST maintain existing dependencies
|
||||
- NO native code files (ios/android directories)
|
||||
- NEVER modify the useFrameworkReady hook
|
||||
- ALWAYS maintain the exact structure of _layout.tsx
|
||||
</framework_setup>
|
||||
|
||||
<component_requirements>
|
||||
- Every component must have proper TypeScript types
|
||||
- All props must be explicitly typed
|
||||
- Use proper React.FC typing for functional components
|
||||
- Implement proper loading and error states
|
||||
- Handle edge cases and empty states
|
||||
</component_requirements>
|
||||
|
||||
<navigation_architecture>
|
||||
<primary_navigation>
|
||||
- Tab-based Navigation via expo-router
|
||||
- Main sections accessible through tabs
|
||||
</primary_navigation>
|
||||
|
||||
<secondary_navigation>
|
||||
- Stack Navigation: For hierarchical flows
|
||||
- Modal Navigation: For overlays
|
||||
- Drawer Navigation: For additional menus
|
||||
</secondary_navigation>
|
||||
</navigation_architecture>
|
||||
|
||||
<styling_guidelines>
|
||||
- Use StyleSheet.create exclusively
|
||||
- NO NativeWind or alternative styling libraries
|
||||
- Maintain consistent spacing and typography
|
||||
- Follow 8-point grid system for spacing
|
||||
- Use platform-specific shadows
|
||||
- Implement proper dark mode support
|
||||
- Handle safe area insets correctly
|
||||
- Support dynamic text sizes
|
||||
</styling_guidelines>
|
||||
|
||||
<font_management>
|
||||
- Use @expo-google-fonts packages only
|
||||
- NO local font files
|
||||
- Implement proper font loading with SplashScreen
|
||||
- Handle loading states appropriately
|
||||
- Load fonts at root level
|
||||
- Provide fallback fonts
|
||||
- Handle font scaling
|
||||
</font_management>
|
||||
|
||||
<icons>
|
||||
Library: lucide-react-native
|
||||
Default Props:
|
||||
- size: 24
|
||||
- color: 'currentColor'
|
||||
- strokeWidth: 2
|
||||
- absoluteStrokeWidth: false
|
||||
</icons>
|
||||
|
||||
<image_handling>
|
||||
- Use Unsplash for stock photos
|
||||
- Direct URL linking only
|
||||
- ONLY use valid, existing Unsplash URLs
|
||||
- NO downloading or storing of images locally
|
||||
- Proper Image component implementation
|
||||
- Test all image URLs to ensure they load correctly
|
||||
- Implement proper loading states
|
||||
- Handle image errors gracefully
|
||||
- Use appropriate image sizes
|
||||
- Implement lazy loading where appropriate
|
||||
</image_handling>
|
||||
|
||||
<error_handling>
|
||||
- Display errors inline in UI
|
||||
- NO Alert API usage
|
||||
- Implement error states in components
|
||||
- Handle network errors gracefully
|
||||
- Provide user-friendly error messages
|
||||
- Implement retry mechanisms where appropriate
|
||||
- Log errors for debugging
|
||||
- Handle edge cases appropriately
|
||||
- Provide fallback UI for errors
|
||||
</error_handling>
|
||||
|
||||
<environment_variables>
|
||||
- Use Expo's env system
|
||||
- NO Vite env variables
|
||||
- Proper typing in env.d.ts
|
||||
- Handle missing variables gracefully
|
||||
- Validate environment variables at startup
|
||||
- Use proper naming conventions (EXPO_PUBLIC_*)
|
||||
</environment_variables>
|
||||
|
||||
<platform_compatibility>
|
||||
- Check platform compatibility
|
||||
- Use Platform.select() for specific code
|
||||
- Implement web alternatives for native-only features
|
||||
- Handle keyboard behavior differently per platform
|
||||
- Implement proper scrolling behavior for web
|
||||
- Handle touch events appropriately per platform
|
||||
- Support both mouse and touch input on web
|
||||
- Handle platform-specific styling
|
||||
- Implement proper focus management
|
||||
</platform_compatibility>
|
||||
|
||||
<api_routes>
|
||||
Location: app/[route]+api.ts
|
||||
Features:
|
||||
- Secure server code
|
||||
- Custom endpoints
|
||||
- Request/Response handling
|
||||
- Error management
|
||||
- Proper validation
|
||||
- Rate limiting
|
||||
- CORS handling
|
||||
- Security headers
|
||||
</api_routes>
|
||||
|
||||
<animation_libraries>
|
||||
Preferred:
|
||||
- react-native-reanimated over Animated
|
||||
- react-native-gesture-handler over PanResponder
|
||||
</animation_libraries>
|
||||
|
||||
<performance_optimization>
|
||||
- Implement proper list virtualization
|
||||
- Use memo and useCallback appropriately
|
||||
- Optimize re-renders
|
||||
- Implement proper image caching
|
||||
- Handle memory management
|
||||
- Clean up resources properly
|
||||
- Implement proper error boundaries
|
||||
- Use proper loading states
|
||||
- Handle offline functionality
|
||||
- Implement proper data caching
|
||||
</performance_optimization>
|
||||
|
||||
<security_best_practices>
|
||||
- Implement proper authentication
|
||||
- Handle sensitive data securely
|
||||
- Validate all user input
|
||||
- Implement proper session management
|
||||
- Use secure storage for sensitive data
|
||||
- Implement proper CORS policies
|
||||
- Handle API keys securely
|
||||
- Implement proper error handling
|
||||
- Use proper security headers
|
||||
- Handle permissions properly
|
||||
</security_best_practices>
|
||||
|
||||
<accessibility>
|
||||
- Implement proper ARIA labels
|
||||
- Support screen readers
|
||||
- Handle focus management
|
||||
- Provide proper contrast
|
||||
- Support keyboard navigation
|
||||
- Handle reduced motion
|
||||
- Implement proper semantic markup
|
||||
- Support dynamic text sizing
|
||||
- Handle color blindness
|
||||
- Provide alternative text
|
||||
</accessibility>
|
||||
</critical_requirements>
|
||||
|
||||
<development_workflow>
|
||||
1. Start with root layout
|
||||
2. Implement navigation structure
|
||||
3. Create reusable components
|
||||
4. Add proper error handling
|
||||
5. Implement platform-specific code
|
||||
6. Add proper loading states
|
||||
7. Test cross-platform compatibility
|
||||
8. Implement proper security
|
||||
9. Add proper accessibility
|
||||
10. Optimize performance
|
||||
</development_workflow>
|
||||
|
||||
<common_pitfalls>
|
||||
- Removing useFrameworkReady hook
|
||||
- Using native-only APIs without web alternatives
|
||||
- Improper font loading implementation
|
||||
- Missing platform-specific checks
|
||||
- Not handling keyboard behavior properly
|
||||
- Improper safe area handling
|
||||
- Missing loading states
|
||||
- Poor error handling
|
||||
- Incomplete type definitions
|
||||
- Not cleaning up resources properly
|
||||
- Improper memory management
|
||||
- Missing accessibility features
|
||||
- Poor performance optimization
|
||||
- Insecure data handling
|
||||
- Missing validation
|
||||
- Improper error boundaries
|
||||
</common_pitfalls>
|
||||
</mobile_app_instructions>
|
||||
`;
|
||||
|
||||
export const CONTINUE_PROMPT = stripIndents`
|
||||
|
||||
93
app/routes/api.github-template.ts
Normal file
93
app/routes/api.github-template.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { json } from '@remix-run/cloudflare';
|
||||
import JSZip from 'jszip';
|
||||
|
||||
export async function loader({ request }: { request: Request }) {
|
||||
const url = new URL(request.url);
|
||||
const repo = url.searchParams.get('repo');
|
||||
|
||||
if (!repo) {
|
||||
return json({ error: 'Repository name is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
const baseUrl = 'https://api.github.com';
|
||||
|
||||
// Get the latest release
|
||||
const releaseResponse = await fetch(`${baseUrl}/repos/${repo}/releases/latest`, {
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
// Add GitHub token if available in environment variables
|
||||
...(process.env.GITHUB_TOKEN ? { 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}` } : {})
|
||||
}
|
||||
});
|
||||
|
||||
if (!releaseResponse.ok) {
|
||||
throw new Error(`GitHub API error: ${releaseResponse.status}`);
|
||||
}
|
||||
|
||||
const releaseData = await releaseResponse.json() as any;
|
||||
const zipballUrl = releaseData.zipball_url;
|
||||
|
||||
// Fetch the zipball
|
||||
const zipResponse = await fetch(zipballUrl, {
|
||||
headers: {
|
||||
...(process.env.GITHUB_TOKEN ? { 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}` } : {})
|
||||
}
|
||||
});
|
||||
|
||||
if (!zipResponse.ok) {
|
||||
throw new Error(`Failed to fetch release zipball: ${zipResponse.status}`);
|
||||
}
|
||||
|
||||
// Get the zip content as ArrayBuffer
|
||||
const zipArrayBuffer = await zipResponse.arrayBuffer();
|
||||
|
||||
// Use JSZip to extract the contents
|
||||
const zip = await JSZip.loadAsync(zipArrayBuffer);
|
||||
|
||||
// Process the zip contents
|
||||
const files: { name: string; path: string; content: string }[] = [];
|
||||
|
||||
// Find the root folder name
|
||||
let rootFolderName = '';
|
||||
zip.forEach((relativePath, zipEntry) => {
|
||||
if (!rootFolderName && relativePath.includes('/')) {
|
||||
rootFolderName = relativePath.split('/')[0];
|
||||
}
|
||||
});
|
||||
|
||||
// Extract all files
|
||||
const promises = Object.keys(zip.files).map(async (filename) => {
|
||||
const zipEntry = zip.files[filename];
|
||||
|
||||
// Skip directories
|
||||
if (zipEntry.dir) return null;
|
||||
|
||||
// Skip the root folder itself
|
||||
if (filename === rootFolderName) return null;
|
||||
|
||||
// Remove the root folder from the path
|
||||
let normalizedPath = filename;
|
||||
if (rootFolderName && filename.startsWith(rootFolderName + '/')) {
|
||||
normalizedPath = filename.substring(rootFolderName.length + 1);
|
||||
}
|
||||
|
||||
// Get the file content
|
||||
const content = await zipEntry.async('string');
|
||||
|
||||
return {
|
||||
name: normalizedPath.split('/').pop() || '',
|
||||
path: normalizedPath,
|
||||
content,
|
||||
};
|
||||
});
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
const fileList = results.filter(Boolean) as { name: string; path: string; content: string }[];
|
||||
|
||||
return json(fileList);
|
||||
} catch (error) {
|
||||
console.error('Error processing GitHub template:', error);
|
||||
return json({ error: 'Failed to fetch template files' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
32
app/routes/webcontainer.connect.$id.tsx
Normal file
32
app/routes/webcontainer.connect.$id.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { type LoaderFunction } from '@remix-run/cloudflare';
|
||||
|
||||
export const loader: LoaderFunction = async ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const editorOrigin = url.searchParams.get('editorOrigin') || 'https://stackblitz.com';
|
||||
console.log('editorOrigin', editorOrigin);
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Connect to WebContainer</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
(async () => {
|
||||
const { setupConnect } = await import('https://cdn.jsdelivr.net/npm/@webcontainer/api@latest/dist/connect.js');
|
||||
setupConnect({
|
||||
editorOrigin: '${editorOrigin}'
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return new Response(htmlContent, {
|
||||
headers: { 'Content-Type': 'text/html' },
|
||||
});
|
||||
};
|
||||
@@ -25,11 +25,19 @@ PROVIDER_LIST.forEach((provider) => {
|
||||
// starter Templates
|
||||
|
||||
export const STARTER_TEMPLATES: Template[] = [
|
||||
{
|
||||
name: 'bolt-expo-app',
|
||||
label: 'Expo App',
|
||||
description: 'Expo starter template for building cross-platform mobile apps',
|
||||
githubRepo: 'xKevIsDev/bolt-expo-template',
|
||||
tags: ['mobile', 'expo', 'mobile-app', 'mobile app', 'android', 'iphone'],
|
||||
icon: 'i-bolt:expo',
|
||||
},
|
||||
{
|
||||
name: 'bolt-astro-basic',
|
||||
label: 'Astro Basic',
|
||||
description: 'Lightweight Astro starter template for building fast static websites',
|
||||
githubRepo: 'thecodacus/bolt-astro-basic-template',
|
||||
githubRepo: 'xKevIsDev/bolt-astro-basic-template',
|
||||
tags: ['astro', 'blog', 'performance'],
|
||||
icon: 'i-bolt:astro',
|
||||
},
|
||||
@@ -37,7 +45,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-nextjs-shadcn',
|
||||
label: 'Next.js with shadcn/ui',
|
||||
description: 'Next.js starter fullstack template integrated with shadcn/ui components and styling system',
|
||||
githubRepo: 'thecodacus/bolt-nextjs-shadcn-template',
|
||||
githubRepo: 'xKevIsDev/bolt-nextjs-shadcn-template',
|
||||
tags: ['nextjs', 'react', 'typescript', 'shadcn', 'tailwind'],
|
||||
icon: 'i-bolt:nextjs',
|
||||
},
|
||||
@@ -45,7 +53,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-qwik-ts',
|
||||
label: 'Qwik TypeScript',
|
||||
description: 'Qwik framework starter with TypeScript for building resumable applications',
|
||||
githubRepo: 'thecodacus/bolt-qwik-ts-template',
|
||||
githubRepo: 'xKevIsDev/bolt-qwik-ts-template',
|
||||
tags: ['qwik', 'typescript', 'performance', 'resumable'],
|
||||
icon: 'i-bolt:qwik',
|
||||
},
|
||||
@@ -53,7 +61,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-remix-ts',
|
||||
label: 'Remix TypeScript',
|
||||
description: 'Remix framework starter with TypeScript for full-stack web applications',
|
||||
githubRepo: 'thecodacus/bolt-remix-ts-template',
|
||||
githubRepo: 'xKevIsDev/bolt-remix-ts-template',
|
||||
tags: ['remix', 'typescript', 'fullstack', 'react'],
|
||||
icon: 'i-bolt:remix',
|
||||
},
|
||||
@@ -61,7 +69,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-slidev',
|
||||
label: 'Slidev Presentation',
|
||||
description: 'Slidev starter template for creating developer-friendly presentations using Markdown',
|
||||
githubRepo: 'thecodacus/bolt-slidev-template',
|
||||
githubRepo: 'xKevIsDev/bolt-slidev-template',
|
||||
tags: ['slidev', 'presentation', 'markdown'],
|
||||
icon: 'i-bolt:slidev',
|
||||
},
|
||||
@@ -77,7 +85,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'vanilla-vite',
|
||||
label: 'Vanilla + Vite',
|
||||
description: 'Minimal Vite starter template for vanilla JavaScript projects',
|
||||
githubRepo: 'thecodacus/vanilla-vite-template',
|
||||
githubRepo: 'xKevIsDev/vanilla-vite-template',
|
||||
tags: ['vite', 'vanilla-js', 'minimal'],
|
||||
icon: 'i-bolt:vite',
|
||||
},
|
||||
@@ -85,7 +93,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-vite-react',
|
||||
label: 'React + Vite + typescript',
|
||||
description: 'React starter template powered by Vite for fast development experience',
|
||||
githubRepo: 'thecodacus/bolt-vite-react-ts-template',
|
||||
githubRepo: 'xKevIsDev/bolt-vite-react-ts-template',
|
||||
tags: ['react', 'vite', 'frontend'],
|
||||
icon: 'i-bolt:react',
|
||||
},
|
||||
@@ -93,7 +101,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-vite-ts',
|
||||
label: 'Vite + TypeScript',
|
||||
description: 'Vite starter template with TypeScript configuration for type-safe development',
|
||||
githubRepo: 'thecodacus/bolt-vite-ts-template',
|
||||
githubRepo: 'xKevIsDev/bolt-vite-ts-template',
|
||||
tags: ['vite', 'typescript', 'minimal'],
|
||||
icon: 'i-bolt:typescript',
|
||||
},
|
||||
@@ -101,7 +109,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-vue',
|
||||
label: 'Vue.js',
|
||||
description: 'Vue.js starter template with modern tooling and best practices',
|
||||
githubRepo: 'thecodacus/bolt-vue-template',
|
||||
githubRepo: 'xKevIsDev/bolt-vue-template',
|
||||
tags: ['vue', 'typescript', 'frontend'],
|
||||
icon: 'i-bolt:vue',
|
||||
},
|
||||
@@ -109,7 +117,7 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
name: 'bolt-angular',
|
||||
label: 'Angular Starter',
|
||||
description: 'A modern Angular starter template with TypeScript support and best practices configuration',
|
||||
githubRepo: 'thecodacus/bolt-angular-template',
|
||||
githubRepo: 'xKevIsDev/bolt-angular-template',
|
||||
tags: ['angular', 'typescript', 'frontend', 'spa'],
|
||||
icon: 'i-bolt:angular',
|
||||
},
|
||||
|
||||
@@ -115,77 +115,19 @@ const getGitHubRepoContent = async (
|
||||
repoName: string,
|
||||
path: string = '',
|
||||
): Promise<{ name: string; path: string; content: string }[]> => {
|
||||
const baseUrl = 'https://api.github.com';
|
||||
|
||||
try {
|
||||
const token = Cookies.get('githubToken') || import.meta.env.VITE_GITHUB_ACCESS_TOKEN;
|
||||
|
||||
const headers: HeadersInit = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
};
|
||||
|
||||
// Add your GitHub token if needed
|
||||
if (token) {
|
||||
headers.Authorization = 'Bearer ' + token;
|
||||
}
|
||||
|
||||
// Fetch contents of the path
|
||||
const response = await fetch(`${baseUrl}/repos/${repoName}/contents/${path}`, {
|
||||
headers,
|
||||
});
|
||||
|
||||
// Instead of directly fetching from GitHub, use our own API endpoint as a proxy
|
||||
const response = await fetch(`/api/github-template?repo=${encodeURIComponent(repoName)}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data: any = await response.json();
|
||||
|
||||
// If it's a single file, return its content
|
||||
if (!Array.isArray(data)) {
|
||||
if (data.type === 'file') {
|
||||
// If it's a file, get its content
|
||||
const content = atob(data.content); // Decode base64 content
|
||||
return [
|
||||
{
|
||||
name: data.name,
|
||||
path: data.path,
|
||||
content,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Process directory contents recursively
|
||||
const contents = await Promise.all(
|
||||
data.map(async (item: any) => {
|
||||
if (item.type === 'dir') {
|
||||
// Recursively get contents of subdirectories
|
||||
return await getGitHubRepoContent(repoName, item.path);
|
||||
} else if (item.type === 'file') {
|
||||
// Fetch file content
|
||||
const fileResponse = await fetch(item.url, {
|
||||
headers,
|
||||
});
|
||||
const fileData: any = await fileResponse.json();
|
||||
const content = atob(fileData.content); // Decode base64 content
|
||||
|
||||
return [
|
||||
{
|
||||
name: item.name,
|
||||
path: item.path,
|
||||
content,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}),
|
||||
);
|
||||
|
||||
// Flatten the array of contents
|
||||
return contents.flat();
|
||||
|
||||
// Our API will return the files in the format we need
|
||||
const files = await response.json() as any;
|
||||
return files;
|
||||
} catch (error) {
|
||||
console.error('Error fetching repo contents:', error);
|
||||
console.error('Error fetching release contents:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -209,8 +151,9 @@ export async function getTemplates(templateName: string, title?: string) {
|
||||
filteredFiles = filteredFiles.filter((x) => x.path.startsWith('.git') == false);
|
||||
|
||||
// exclude lock files
|
||||
const comminLockFiles = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'];
|
||||
filteredFiles = filteredFiles.filter((x) => comminLockFiles.includes(x.name) == false);
|
||||
// WE NOW INCLUDE LOCK FILES FOR IMPROVED INSTALL TIMES
|
||||
{/*const comminLockFiles = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'];
|
||||
filteredFiles = filteredFiles.filter((x) => comminLockFiles.includes(x.name) == false);*/}
|
||||
|
||||
// exclude .bolt
|
||||
filteredFiles = filteredFiles.filter((x) => x.path.startsWith('.bolt') == false);
|
||||
@@ -255,7 +198,6 @@ ${file.content}
|
||||
TEMPLATE INSTRUCTIONS:
|
||||
${templatePromptFile.content}
|
||||
|
||||
IMPORTANT: Dont Forget to install the dependencies before running the app
|
||||
---
|
||||
`;
|
||||
}
|
||||
@@ -296,6 +238,8 @@ edit only the files that need to be changed, and you can create new files as nee
|
||||
NO NOT EDIT/WRITE ANY FILES THAT ALREADY EXIST IN THE PROJECT AND DOES NOT NEED TO BE MODIFIED
|
||||
---
|
||||
Now that the Template is imported please continue with my original request
|
||||
|
||||
IMPORTANT: Dont Forget to install the dependencies before running the app by using \`npm install && npm run dev\`
|
||||
`;
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user