Merge pull request #1122 from Stijnus/FEAT_BoltDYI_PREVIEW_V3
Some checks failed
Docker Publish / docker-build-publish (push) Has been cancelled
Docs CI/CD / build_docs (push) Has been cancelled
Update Stable Branch / prepare-release (push) Has been cancelled

fix: for Open preview in a new tab.
This commit is contained in:
Leex 2025-01-19 00:17:13 +01:00 committed by GitHub
commit d62e211d09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 120 additions and 90 deletions

View File

@ -1,4 +1,5 @@
# bolt.diy (Previously oTToDev) # bolt.diy (Previously oTToDev)
[![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy) [![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy)
Welcome to bolt.diy, the official open source version of Bolt.new (previously known as oTToDev and bolt.new ANY LLM), which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models. Welcome to bolt.diy, the official open source version of Bolt.new (previously known as oTToDev and bolt.new ANY LLM), which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models.
@ -67,7 +68,7 @@ project, please check the [project management guide](./PROJECT.md) to get starte
- ✅ Together Integration (@mouimet-infinisoft) - ✅ Together Integration (@mouimet-infinisoft)
- ✅ Mobile friendly (@qwikode) - ✅ Mobile friendly (@qwikode)
- ✅ Better prompt enhancing (@SujalXplores) - ✅ Better prompt enhancing (@SujalXplores)
- ✅ Attach images to prompts (@atrokhym) - ✅ Attach images to prompts (@atrokhym)(@stijnus)
- ✅ Added Git Clone button (@thecodacus) - ✅ Added Git Clone button (@thecodacus)
- ✅ Git Import from url (@thecodacus) - ✅ Git Import from url (@thecodacus)
- ✅ PromptLibrary to have different variations of prompts for different use cases (@thecodacus) - ✅ PromptLibrary to have different variations of prompts for different use cases (@thecodacus)
@ -88,8 +89,9 @@ project, please check the [project management guide](./PROJECT.md) to get starte
- ⬜ Voice prompting - ⬜ Voice prompting
- ⬜ Azure Open AI API Integration - ⬜ Azure Open AI API Integration
- ⬜ Vertex AI Integration - ⬜ Vertex AI Integration
- ⬜ Granite Integration - ⬜ Granite Integration
- ⬜ Popout Window for Web Container - ✅ Popout Window for Web Container(@stijnus)
- ✅ Ability to change Popout window size (@stijnus)
## Features ## Features
@ -101,21 +103,18 @@ project, please check the [project management guide](./PROJECT.md) to get starte
- **Download projects as ZIP** for easy portability. - **Download projects as ZIP** for easy portability.
- **Integration-ready Docker support** for a hassle-free setup. - **Integration-ready Docker support** for a hassle-free setup.
## Setup ## Setup
If you're new to installing software from GitHub, don't worry! If you encounter any issues, feel free to submit an "issue" using the provided links or improve this documentation by forking the repository, editing the instructions, and submitting a pull request. The following instruction will help you get the stable branch up and running on your local machine in no time. If you're new to installing software from GitHub, don't worry! If you encounter any issues, feel free to submit an "issue" using the provided links or improve this documentation by forking the repository, editing the instructions, and submitting a pull request. The following instruction will help you get the stable branch up and running on your local machine in no time.
Let's get you up and running with the stable version of Bolt.DIY! Let's get you up and running with the stable version of Bolt.DIY!
## Quick Download ## Quick Download
[![Download Latest Release](https://img.shields.io/github/v/release/stackblitz-labs/bolt.diy?label=Download%20Bolt&sort=semver)](https://github.com/stackblitz-labs/bolt.diy/releases/latest) ← Click here to go the the latest release version! [![Download Latest Release](https://img.shields.io/github/v/release/stackblitz-labs/bolt.diy?label=Download%20Bolt&sort=semver)](https://github.com/stackblitz-labs/bolt.diy/releases/latest) ← Click here to go the the latest release version!
- Next **click source.zip** - Next **click source.zip**
## Prerequisites ## Prerequisites
Before you begin, you'll need to install two important pieces of software: Before you begin, you'll need to install two important pieces of software:
@ -148,16 +147,19 @@ You have two options for running Bolt.DIY: directly on your machine or using Doc
### Option 1: Direct Installation (Recommended for Beginners) ### Option 1: Direct Installation (Recommended for Beginners)
1. **Install Package Manager (pnpm)**: 1. **Install Package Manager (pnpm)**:
```bash ```bash
npm install -g pnpm npm install -g pnpm
``` ```
2. **Install Project Dependencies**: 2. **Install Project Dependencies**:
```bash ```bash
pnpm install pnpm install
``` ```
3. **Start the Application**: 3. **Start the Application**:
```bash ```bash
pnpm run dev pnpm run dev
``` ```
@ -169,11 +171,13 @@ You have two options for running Bolt.DIY: directly on your machine or using Doc
This option requires some familiarity with Docker but provides a more isolated environment. This option requires some familiarity with Docker but provides a more isolated environment.
#### Additional Prerequisite #### Additional Prerequisite
- Install Docker: [Download Docker](https://www.docker.com/) - Install Docker: [Download Docker](https://www.docker.com/)
#### Steps: #### Steps:
1. **Build the Docker Image**: 1. **Build the Docker Image**:
```bash ```bash
# Using npm script: # Using npm script:
npm run dockerbuild npm run dockerbuild
@ -187,9 +191,6 @@ This option requires some familiarity with Docker but provides a more isolated e
docker compose --profile development up docker compose --profile development up
``` ```
## Configuring API Keys and Providers ## Configuring API Keys and Providers
### Adding Your API Keys ### Adding Your API Keys
@ -218,6 +219,7 @@ For providers that support custom base URLs (such as Ollama or LM Studio), follo
> **Note**: Custom base URLs are particularly useful when running local instances of AI models or using custom API endpoints. > **Note**: Custom base URLs are particularly useful when running local instances of AI models or using custom API endpoints.
### Supported Providers ### Supported Providers
- Ollama - Ollama
- LM Studio - LM Studio
- OpenAILike - OpenAILike
@ -225,23 +227,27 @@ For providers that support custom base URLs (such as Ollama or LM Studio), follo
## Setup Using Git (For Developers only) ## Setup Using Git (For Developers only)
This method is recommended for developers who want to: This method is recommended for developers who want to:
- Contribute to the project - Contribute to the project
- Stay updated with the latest changes - Stay updated with the latest changes
- Switch between different versions - Switch between different versions
- Create custom modifications - Create custom modifications
#### Prerequisites #### Prerequisites
1. Install Git: [Download Git](https://git-scm.com/downloads) 1. Install Git: [Download Git](https://git-scm.com/downloads)
#### Initial Setup #### Initial Setup
1. **Clone the Repository**: 1. **Clone the Repository**:
```bash ```bash
# Using HTTPS # Using HTTPS
git clone https://github.com/stackblitz-labs/bolt.diy.git git clone https://github.com/stackblitz-labs/bolt.diy.git
``` ```
2. **Navigate to Project Directory**: 2. **Navigate to Project Directory**:
```bash ```bash
cd bolt.diy cd bolt.diy
``` ```
@ -251,6 +257,7 @@ This method is recommended for developers who want to:
git checkout main git checkout main
``` ```
4. **Install Dependencies**: 4. **Install Dependencies**:
```bash ```bash
pnpm install pnpm install
``` ```
@ -265,16 +272,19 @@ This method is recommended for developers who want to:
To get the latest changes from the repository: To get the latest changes from the repository:
1. **Save Your Local Changes** (if any): 1. **Save Your Local Changes** (if any):
```bash ```bash
git stash git stash
``` ```
2. **Pull Latest Updates**: 2. **Pull Latest Updates**:
```bash ```bash
git pull origin main git pull origin main
``` ```
3. **Update Dependencies**: 3. **Update Dependencies**:
```bash ```bash
pnpm install pnpm install
``` ```
@ -289,6 +299,7 @@ To get the latest changes from the repository:
If you encounter issues: If you encounter issues:
1. **Clean Installation**: 1. **Clean Installation**:
```bash ```bash
# Remove node modules and lock files # Remove node modules and lock files
rm -rf node_modules pnpm-lock.yaml rm -rf node_modules pnpm-lock.yaml

View File

@ -11,13 +11,14 @@ interface WindowSize {
name: string; name: string;
width: number; width: number;
height: number; height: number;
icon: string;
} }
const WINDOW_SIZES: WindowSize[] = [ const WINDOW_SIZES: WindowSize[] = [
{ name: 'Mobile (375x667)', width: 375, height: 667 }, { name: 'Mobile', width: 375, height: 667, icon: 'i-ph:device-mobile' },
{ name: 'Tablet (768x1024)', width: 768, height: 1024 }, { name: 'Tablet', width: 768, height: 1024, icon: 'i-ph:device-tablet' },
{ name: 'Laptop (1366x768)', width: 1366, height: 768 }, { name: 'Laptop', width: 1366, height: 768, icon: 'i-ph:laptop' },
{ name: 'Desktop (1920x1080)', width: 1920, height: 1080 }, { name: 'Desktop', width: 1920, height: 1080, icon: 'i-ph:monitor' },
]; ];
export const Preview = memo(() => { export const Preview = memo(() => {
@ -249,14 +250,17 @@ export const Preview = memo(() => {
{isPortDropdownOpen && ( {isPortDropdownOpen && (
<div className="z-iframe-overlay w-full h-full absolute" onClick={() => setIsPortDropdownOpen(false)} /> <div className="z-iframe-overlay w-full h-full absolute" onClick={() => setIsPortDropdownOpen(false)} />
)} )}
<div className="bg-bolt-elements-background-depth-2 p-2 flex items-center gap-1.5"> <div className="bg-bolt-elements-background-depth-2 p-2 flex items-center gap-2">
<IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} /> <div className="flex items-center gap-2">
<IconButton <IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} />
icon="i-ph:selection" <IconButton
onClick={() => setIsSelectionMode(!isSelectionMode)} icon="i-ph:selection"
className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''} onClick={() => setIsSelectionMode(!isSelectionMode)}
/> className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''}
<div className="flex items-center gap-1 flex-grow bg-bolt-elements-preview-addressBar-background border border-bolt-elements-borderColor text-bolt-elements-preview-addressBar-text rounded-full px-3 py-1 text-sm hover:bg-bolt-elements-preview-addressBar-backgroundHover hover:focus-within:bg-bolt-elements-preview-addressBar-backgroundActive focus-within:bg-bolt-elements-preview-addressBar-backgroundActive focus-within-border-bolt-elements-borderColorActive focus-within:text-bolt-elements-preview-addressBar-textActive"> />
</div>
<div className="flex-grow flex items-center gap-1 bg-bolt-elements-preview-addressBar-background border border-bolt-elements-borderColor text-bolt-elements-preview-addressBar-text rounded-full px-3 py-1 text-sm hover:bg-bolt-elements-preview-addressBar-backgroundHover hover:focus-within:bg-bolt-elements-preview-addressBar-backgroundActive focus-within:bg-bolt-elements-preview-addressBar-backgroundActive focus-within-border-bolt-elements-borderColorActive focus-within:text-bolt-elements-preview-addressBar-textActive">
<input <input
title="URL" title="URL"
ref={inputRef} ref={inputRef}
@ -278,68 +282,80 @@ export const Preview = memo(() => {
/> />
</div> </div>
{previews.length > 1 && ( <div className="flex items-center gap-2">
<PortDropdown {previews.length > 1 && (
activePreviewIndex={activePreviewIndex} <PortDropdown
setActivePreviewIndex={setActivePreviewIndex} activePreviewIndex={activePreviewIndex}
isDropdownOpen={isPortDropdownOpen} setActivePreviewIndex={setActivePreviewIndex}
setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)} isDropdownOpen={isPortDropdownOpen}
setIsDropdownOpen={setIsPortDropdownOpen} setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)}
previews={previews} setIsDropdownOpen={setIsPortDropdownOpen}
/> previews={previews}
)} />
<IconButton
icon="i-ph:devices"
onClick={toggleDeviceMode}
title={isDeviceModeOn ? 'Switch to Responsive Mode' : 'Switch to Device Mode'}
/>
<IconButton
icon="i-ph:layout-light"
onClick={() => setIsPreviewOnly(!isPreviewOnly)}
title={isPreviewOnly ? 'Show Full Interface' : 'Show Preview Only'}
/>
<IconButton
icon={isFullscreen ? 'i-ph:arrows-in' : 'i-ph:arrows-out'}
onClick={toggleFullscreen}
title={isFullscreen ? 'Exit Full Screen' : 'Full Screen'}
/>
<div className="relative">
<IconButton
icon="i-ph:arrow-square-out"
onClick={() => openInNewWindow(selectedWindowSize)}
title={`Open Preview in ${selectedWindowSize.name} Window`}
/>
<IconButton
icon="i-ph:caret-down"
onClick={() => setIsWindowSizeDropdownOpen(!isWindowSizeDropdownOpen)}
className="ml-1"
title="Select Window Size"
/>
{isWindowSizeDropdownOpen && (
<>
<div className="fixed inset-0 z-50" onClick={() => setIsWindowSizeDropdownOpen(false)} />
<div className="absolute right-0 top-full mt-1 z-50 bg-bolt-elements-background-depth-2 rounded-lg shadow-lg border border-bolt-elements-borderColor overflow-hidden">
{WINDOW_SIZES.map((size) => (
<button
key={size.name}
className="w-full px-4 py-2 text-left hover:bg-bolt-elements-background-depth-3 text-sm whitespace-nowrap"
onClick={() => {
setSelectedWindowSize(size);
setIsWindowSizeDropdownOpen(false);
openInNewWindow(size);
}}
>
{size.name}
</button>
))}
</div>
</>
)} )}
<IconButton
icon="i-ph:devices"
onClick={toggleDeviceMode}
title={isDeviceModeOn ? 'Switch to Responsive Mode' : 'Switch to Device Mode'}
/>
<IconButton
icon="i-ph:layout-light"
onClick={() => setIsPreviewOnly(!isPreviewOnly)}
title={isPreviewOnly ? 'Show Full Interface' : 'Show Preview Only'}
/>
<IconButton
icon={isFullscreen ? 'i-ph:arrows-in' : 'i-ph:arrows-out'}
onClick={toggleFullscreen}
title={isFullscreen ? 'Exit Full Screen' : 'Full Screen'}
/>
<div className="flex items-center relative">
<IconButton
icon="i-ph:arrow-square-out"
onClick={() => openInNewWindow(selectedWindowSize)}
title={`Open Preview in ${selectedWindowSize.name} Window`}
/>
<IconButton
icon="i-ph:caret-down"
onClick={() => setIsWindowSizeDropdownOpen(!isWindowSizeDropdownOpen)}
className="ml-1"
title="Select Window Size"
/>
{isWindowSizeDropdownOpen && (
<>
<div className="fixed inset-0 z-50" onClick={() => setIsWindowSizeDropdownOpen(false)} />
<div className="absolute right-0 top-full mt-2 z-50 min-w-[240px] bg-white dark:bg-black rounded-xl shadow-2xl border border-[#E5E7EB] dark:border-[rgba(255,255,255,0.1)] overflow-hidden">
{WINDOW_SIZES.map((size) => (
<button
key={size.name}
className="w-full px-4 py-3.5 text-left text-[#111827] dark:text-gray-300 text-sm whitespace-nowrap flex items-center gap-3 group hover:bg-[#F5EEFF] dark:hover:bg-gray-900 bg-white dark:bg-black"
onClick={() => {
setSelectedWindowSize(size);
setIsWindowSizeDropdownOpen(false);
openInNewWindow(size);
}}
>
<div
className={`${size.icon} w-5 h-5 text-[#6B7280] dark:text-gray-400 group-hover:text-[#6D28D9] dark:group-hover:text-[#6D28D9] transition-colors duration-200`}
/>
<div className="flex flex-col">
<span className="font-medium group-hover:text-[#6D28D9] dark:group-hover:text-[#6D28D9] transition-colors duration-200">
{size.name}
</span>
<span className="text-xs text-[#6B7280] dark:text-gray-400 group-hover:text-[#6D28D9] dark:group-hover:text-[#6D28D9] transition-colors duration-200">
{size.width} × {size.height}
</span>
</div>
</button>
))}
</div>
</>
)}
</div>
</div> </div>
</div> </div>
@ -349,7 +365,7 @@ export const Preview = memo(() => {
width: isDeviceModeOn ? `${widthPercent}%` : '100%', width: isDeviceModeOn ? `${widthPercent}%` : '100%',
height: '100%', height: '100%',
overflow: 'visible', overflow: 'visible',
background: '#fff', background: 'var(--bolt-elements-background-depth-1)',
position: 'relative', position: 'relative',
display: 'flex', display: 'flex',
}} }}
@ -359,7 +375,7 @@ export const Preview = memo(() => {
<iframe <iframe
ref={iframeRef} ref={iframeRef}
title="preview" title="preview"
className="border-none w-full h-full bg-white" className="border-none w-full h-full bg-bolt-elements-background-depth-1"
src={iframeUrl} src={iframeUrl}
sandbox="allow-scripts allow-forms allow-popups allow-modals allow-storage-access-by-user-activation allow-same-origin" sandbox="allow-scripts allow-forms allow-popups allow-modals allow-storage-access-by-user-activation allow-same-origin"
allow="cross-origin-isolated" allow="cross-origin-isolated"
@ -371,7 +387,9 @@ export const Preview = memo(() => {
/> />
</> </>
) : ( ) : (
<div className="flex w-full h-full justify-center items-center bg-white">No preview available</div> <div className="flex w-full h-full justify-center items-center bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary">
No preview available
</div>
)} )}
{isDeviceModeOn && ( {isDeviceModeOn && (

View File

@ -11,7 +11,8 @@ export default class GithubProvider extends BaseProvider {
config = { config = {
apiTokenKey: 'GITHUB_API_KEY', apiTokenKey: 'GITHUB_API_KEY',
}; };
// find more in https://github.com/marketplace?type=models
// find more in https://github.com/marketplace?type=models
staticModels: ModelInfo[] = [ staticModels: ModelInfo[] = [
{ name: 'gpt-4o', label: 'GPT-4o', provider: 'Github', maxTokenAllowed: 8000 }, { name: 'gpt-4o', label: 'GPT-4o', provider: 'Github', maxTokenAllowed: 8000 },
{ name: 'o1', label: 'o1-preview', provider: 'Github', maxTokenAllowed: 100000 }, { name: 'o1', label: 'o1-preview', provider: 'Github', maxTokenAllowed: 100000 },