mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-01-22 10:55:34 +00:00
Merge pull request #1122 from Stijnus/FEAT_BoltDYI_PREVIEW_V3
fix: for Open preview in a new tab.
This commit is contained in:
commit
d62e211d09
37
README.md
37
README.md
@ -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)
|
||||
|
||||
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)
|
||||
- ✅ Mobile friendly (@qwikode)
|
||||
- ✅ Better prompt enhancing (@SujalXplores)
|
||||
- ✅ Attach images to prompts (@atrokhym)
|
||||
- ✅ Attach images to prompts (@atrokhym)(@stijnus)
|
||||
- ✅ Added Git Clone button (@thecodacus)
|
||||
- ✅ Git Import from url (@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
|
||||
- ⬜ Azure Open AI API Integration
|
||||
- ⬜ Vertex AI Integration
|
||||
- ⬜ Granite Integration
|
||||
- ⬜ Popout Window for Web Container
|
||||
- ⬜ Granite Integration
|
||||
- ✅ Popout Window for Web Container(@stijnus)
|
||||
- ✅ Ability to change Popout window size (@stijnus)
|
||||
|
||||
## Features
|
||||
|
||||
@ -101,21 +103,18 @@ project, please check the [project management guide](./PROJECT.md) to get starte
|
||||
- **Download projects as ZIP** for easy portability.
|
||||
- **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!
|
||||
|
||||
## 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**
|
||||
|
||||
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
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)
|
||||
|
||||
1. **Install Package Manager (pnpm)**:
|
||||
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
2. **Install Project Dependencies**:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. **Start the Application**:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
#### Additional Prerequisite
|
||||
|
||||
- Install Docker: [Download Docker](https://www.docker.com/)
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. **Build the Docker Image**:
|
||||
|
||||
```bash
|
||||
# Using npm script:
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Configuring API Keys and Providers
|
||||
|
||||
### 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.
|
||||
|
||||
### Supported Providers
|
||||
|
||||
- Ollama
|
||||
- LM Studio
|
||||
- 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)
|
||||
|
||||
This method is recommended for developers who want to:
|
||||
|
||||
- Contribute to the project
|
||||
- Stay updated with the latest changes
|
||||
- Switch between different versions
|
||||
- Create custom modifications
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
1. Install Git: [Download Git](https://git-scm.com/downloads)
|
||||
|
||||
#### Initial Setup
|
||||
|
||||
1. **Clone the Repository**:
|
||||
|
||||
```bash
|
||||
# Using HTTPS
|
||||
git clone https://github.com/stackblitz-labs/bolt.diy.git
|
||||
```
|
||||
|
||||
2. **Navigate to Project Directory**:
|
||||
|
||||
```bash
|
||||
cd bolt.diy
|
||||
```
|
||||
@ -251,6 +257,7 @@ This method is recommended for developers who want to:
|
||||
git checkout main
|
||||
```
|
||||
4. **Install Dependencies**:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
@ -265,16 +272,19 @@ This method is recommended for developers who want to:
|
||||
To get the latest changes from the repository:
|
||||
|
||||
1. **Save Your Local Changes** (if any):
|
||||
|
||||
```bash
|
||||
git stash
|
||||
```
|
||||
|
||||
2. **Pull Latest Updates**:
|
||||
|
||||
```bash
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
3. **Update Dependencies**:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
@ -289,6 +299,7 @@ To get the latest changes from the repository:
|
||||
If you encounter issues:
|
||||
|
||||
1. **Clean Installation**:
|
||||
|
||||
```bash
|
||||
# Remove node modules and lock files
|
||||
rm -rf node_modules pnpm-lock.yaml
|
||||
|
@ -11,13 +11,14 @@ interface WindowSize {
|
||||
name: string;
|
||||
width: number;
|
||||
height: number;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const WINDOW_SIZES: WindowSize[] = [
|
||||
{ name: 'Mobile (375x667)', width: 375, height: 667 },
|
||||
{ name: 'Tablet (768x1024)', width: 768, height: 1024 },
|
||||
{ name: 'Laptop (1366x768)', width: 1366, height: 768 },
|
||||
{ name: 'Desktop (1920x1080)', width: 1920, height: 1080 },
|
||||
{ name: 'Mobile', width: 375, height: 667, icon: 'i-ph:device-mobile' },
|
||||
{ name: 'Tablet', width: 768, height: 1024, icon: 'i-ph:device-tablet' },
|
||||
{ name: 'Laptop', width: 1366, height: 768, icon: 'i-ph:laptop' },
|
||||
{ name: 'Desktop', width: 1920, height: 1080, icon: 'i-ph:monitor' },
|
||||
];
|
||||
|
||||
export const Preview = memo(() => {
|
||||
@ -249,14 +250,17 @@ export const Preview = memo(() => {
|
||||
{isPortDropdownOpen && (
|
||||
<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">
|
||||
<IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} />
|
||||
<IconButton
|
||||
icon="i-ph:selection"
|
||||
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 className="bg-bolt-elements-background-depth-2 p-2 flex items-center gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} />
|
||||
<IconButton
|
||||
icon="i-ph:selection"
|
||||
onClick={() => setIsSelectionMode(!isSelectionMode)}
|
||||
className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''}
|
||||
/>
|
||||
</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
|
||||
title="URL"
|
||||
ref={inputRef}
|
||||
@ -278,68 +282,80 @@ export const Preview = memo(() => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{previews.length > 1 && (
|
||||
<PortDropdown
|
||||
activePreviewIndex={activePreviewIndex}
|
||||
setActivePreviewIndex={setActivePreviewIndex}
|
||||
isDropdownOpen={isPortDropdownOpen}
|
||||
setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)}
|
||||
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>
|
||||
</>
|
||||
<div className="flex items-center gap-2">
|
||||
{previews.length > 1 && (
|
||||
<PortDropdown
|
||||
activePreviewIndex={activePreviewIndex}
|
||||
setActivePreviewIndex={setActivePreviewIndex}
|
||||
isDropdownOpen={isPortDropdownOpen}
|
||||
setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)}
|
||||
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="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>
|
||||
|
||||
@ -349,7 +365,7 @@ export const Preview = memo(() => {
|
||||
width: isDeviceModeOn ? `${widthPercent}%` : '100%',
|
||||
height: '100%',
|
||||
overflow: 'visible',
|
||||
background: '#fff',
|
||||
background: 'var(--bolt-elements-background-depth-1)',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
}}
|
||||
@ -359,7 +375,7 @@ export const Preview = memo(() => {
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
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}
|
||||
sandbox="allow-scripts allow-forms allow-popups allow-modals allow-storage-access-by-user-activation allow-same-origin"
|
||||
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 && (
|
||||
|
@ -11,7 +11,8 @@ export default class GithubProvider extends BaseProvider {
|
||||
config = {
|
||||
apiTokenKey: 'GITHUB_API_KEY',
|
||||
};
|
||||
// find more in https://github.com/marketplace?type=models
|
||||
|
||||
// find more in https://github.com/marketplace?type=models
|
||||
staticModels: ModelInfo[] = [
|
||||
{ name: 'gpt-4o', label: 'GPT-4o', provider: 'Github', maxTokenAllowed: 8000 },
|
||||
{ name: 'o1', label: 'o1-preview', provider: 'Github', maxTokenAllowed: 100000 },
|
||||
|
Loading…
Reference in New Issue
Block a user