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:
@@ -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