Skip to content

Commit d62e211

Browse files
authored
Merge pull request #1122 from Stijnus/FEAT_BoltDYI_PREVIEW_V3
fix: for Open preview in a new tab.
2 parents 6ae1ac2 + 031e679 commit d62e211

File tree

3 files changed

+115
-85
lines changed

3 files changed

+115
-85
lines changed

README.md

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# bolt.diy (Previously oTToDev)
1+
# bolt.diy (Previously oTToDev)
2+
23
[![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy)
34

45
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
6768
- ✅ Together Integration (@mouimet-infinisoft)
6869
- ✅ Mobile friendly (@qwikode)
6970
- ✅ Better prompt enhancing (@SujalXplores)
70-
- ✅ Attach images to prompts (@atrokhym)
71+
- ✅ Attach images to prompts (@atrokhym)(@stijnus)
7172
- ✅ Added Git Clone button (@thecodacus)
7273
- ✅ Git Import from url (@thecodacus)
7374
- ✅ 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
8889
- ⬜ Voice prompting
8990
- ⬜ Azure Open AI API Integration
9091
- ⬜ Vertex AI Integration
91-
- ⬜ Granite Integration
92-
- ⬜ Popout Window for Web Container
92+
- ⬜ Granite Integration
93+
- ✅ Popout Window for Web Container(@stijnus)
94+
- ✅ Ability to change Popout window size (@stijnus)
9395

9496
## Features
9597

@@ -101,21 +103,18 @@ project, please check the [project management guide](./PROJECT.md) to get starte
101103
- **Download projects as ZIP** for easy portability.
102104
- **Integration-ready Docker support** for a hassle-free setup.
103105

104-
## Setup
106+
## Setup
105107

106-
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.
108+
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.
107109

108110
Let's get you up and running with the stable version of Bolt.DIY!
109111

110112
## Quick Download
111113

112-
[![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!
114+
[![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!
113115

114116
- Next **click source.zip**
115117

116-
117-
118-
119118
## Prerequisites
120119

121120
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
148147
### Option 1: Direct Installation (Recommended for Beginners)
149148

150149
1. **Install Package Manager (pnpm)**:
150+
151151
```bash
152152
npm install -g pnpm
153153
```
154154

155155
2. **Install Project Dependencies**:
156+
156157
```bash
157158
pnpm install
158159
```
159160

160161
3. **Start the Application**:
162+
161163
```bash
162164
pnpm run dev
163165
```
@@ -169,11 +171,13 @@ You have two options for running Bolt.DIY: directly on your machine or using Doc
169171
This option requires some familiarity with Docker but provides a more isolated environment.
170172

171173
#### Additional Prerequisite
174+
172175
- Install Docker: [Download Docker](https://www.docker.com/)
173176

174177
#### Steps:
175178

176179
1. **Build the Docker Image**:
180+
177181
```bash
178182
# Using npm script:
179183
npm run dockerbuild
@@ -187,9 +191,6 @@ This option requires some familiarity with Docker but provides a more isolated e
187191
docker compose --profile development up
188192
```
189193

190-
191-
192-
193194
## Configuring API Keys and Providers
194195

195196
### Adding Your API Keys
@@ -218,30 +219,35 @@ For providers that support custom base URLs (such as Ollama or LM Studio), follo
218219
> **Note**: Custom base URLs are particularly useful when running local instances of AI models or using custom API endpoints.
219220

220221
### Supported Providers
222+
221223
- Ollama
222224
- LM Studio
223225
- OpenAILike
224226

225227
## Setup Using Git (For Developers only)
226228

227229
This method is recommended for developers who want to:
230+
228231
- Contribute to the project
229232
- Stay updated with the latest changes
230233
- Switch between different versions
231234
- Create custom modifications
232235

233236
#### Prerequisites
237+
234238
1. Install Git: [Download Git](https://git-scm.com/downloads)
235239

236240
#### Initial Setup
237241

238242
1. **Clone the Repository**:
243+
239244
```bash
240245
# Using HTTPS
241246
git clone https://github.com/stackblitz-labs/bolt.diy.git
242247
```
243248

244249
2. **Navigate to Project Directory**:
250+
245251
```bash
246252
cd bolt.diy
247253
```
@@ -251,6 +257,7 @@ This method is recommended for developers who want to:
251257
git checkout main
252258
```
253259
4. **Install Dependencies**:
260+
254261
```bash
255262
pnpm install
256263
```
@@ -265,16 +272,19 @@ This method is recommended for developers who want to:
265272
To get the latest changes from the repository:
266273

267274
1. **Save Your Local Changes** (if any):
275+
268276
```bash
269277
git stash
270278
```
271279

272280
2. **Pull Latest Updates**:
281+
273282
```bash
274283
git pull origin main
275284
```
276285

277286
3. **Update Dependencies**:
287+
278288
```bash
279289
pnpm install
280290
```
@@ -289,6 +299,7 @@ To get the latest changes from the repository:
289299
If you encounter issues:
290300

291301
1. **Clean Installation**:
302+
292303
```bash
293304
# Remove node modules and lock files
294305
rm -rf node_modules pnpm-lock.yaml

app/components/workbench/Preview.tsx

Lines changed: 89 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ interface WindowSize {
1111
name: string;
1212
width: number;
1313
height: number;
14+
icon: string;
1415
}
1516

1617
const WINDOW_SIZES: WindowSize[] = [
17-
{ name: 'Mobile (375x667)', width: 375, height: 667 },
18-
{ name: 'Tablet (768x1024)', width: 768, height: 1024 },
19-
{ name: 'Laptop (1366x768)', width: 1366, height: 768 },
20-
{ name: 'Desktop (1920x1080)', width: 1920, height: 1080 },
18+
{ name: 'Mobile', width: 375, height: 667, icon: 'i-ph:device-mobile' },
19+
{ name: 'Tablet', width: 768, height: 1024, icon: 'i-ph:device-tablet' },
20+
{ name: 'Laptop', width: 1366, height: 768, icon: 'i-ph:laptop' },
21+
{ name: 'Desktop', width: 1920, height: 1080, icon: 'i-ph:monitor' },
2122
];
2223

2324
export const Preview = memo(() => {
@@ -249,14 +250,17 @@ export const Preview = memo(() => {
249250
{isPortDropdownOpen && (
250251
<div className="z-iframe-overlay w-full h-full absolute" onClick={() => setIsPortDropdownOpen(false)} />
251252
)}
252-
<div className="bg-bolt-elements-background-depth-2 p-2 flex items-center gap-1.5">
253-
<IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} />
254-
<IconButton
255-
icon="i-ph:selection"
256-
onClick={() => setIsSelectionMode(!isSelectionMode)}
257-
className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''}
258-
/>
259-
<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">
253+
<div className="bg-bolt-elements-background-depth-2 p-2 flex items-center gap-2">
254+
<div className="flex items-center gap-2">
255+
<IconButton icon="i-ph:arrow-clockwise" onClick={reloadPreview} />
256+
<IconButton
257+
icon="i-ph:selection"
258+
onClick={() => setIsSelectionMode(!isSelectionMode)}
259+
className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''}
260+
/>
261+
</div>
262+
263+
<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">
260264
<input
261265
title="URL"
262266
ref={inputRef}
@@ -278,68 +282,80 @@ export const Preview = memo(() => {
278282
/>
279283
</div>
280284

281-
{previews.length > 1 && (
282-
<PortDropdown
283-
activePreviewIndex={activePreviewIndex}
284-
setActivePreviewIndex={setActivePreviewIndex}
285-
isDropdownOpen={isPortDropdownOpen}
286-
setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)}
287-
setIsDropdownOpen={setIsPortDropdownOpen}
288-
previews={previews}
285+
<div className="flex items-center gap-2">
286+
{previews.length > 1 && (
287+
<PortDropdown
288+
activePreviewIndex={activePreviewIndex}
289+
setActivePreviewIndex={setActivePreviewIndex}
290+
isDropdownOpen={isPortDropdownOpen}
291+
setHasSelectedPreview={(value) => (hasSelectedPreview.current = value)}
292+
setIsDropdownOpen={setIsPortDropdownOpen}
293+
previews={previews}
294+
/>
295+
)}
296+
297+
<IconButton
298+
icon="i-ph:devices"
299+
onClick={toggleDeviceMode}
300+
title={isDeviceModeOn ? 'Switch to Responsive Mode' : 'Switch to Device Mode'}
289301
/>
290-
)}
291-
292-
<IconButton
293-
icon="i-ph:devices"
294-
onClick={toggleDeviceMode}
295-
title={isDeviceModeOn ? 'Switch to Responsive Mode' : 'Switch to Device Mode'}
296-
/>
297-
298-
<IconButton
299-
icon="i-ph:layout-light"
300-
onClick={() => setIsPreviewOnly(!isPreviewOnly)}
301-
title={isPreviewOnly ? 'Show Full Interface' : 'Show Preview Only'}
302-
/>
303-
304-
<IconButton
305-
icon={isFullscreen ? 'i-ph:arrows-in' : 'i-ph:arrows-out'}
306-
onClick={toggleFullscreen}
307-
title={isFullscreen ? 'Exit Full Screen' : 'Full Screen'}
308-
/>
309-
310-
<div className="relative">
302+
311303
<IconButton
312-
icon="i-ph:arrow-square-out"
313-
onClick={() => openInNewWindow(selectedWindowSize)}
314-
title={`Open Preview in ${selectedWindowSize.name} Window`}
304+
icon="i-ph:layout-light"
305+
onClick={() => setIsPreviewOnly(!isPreviewOnly)}
306+
title={isPreviewOnly ? 'Show Full Interface' : 'Show Preview Only'}
315307
/>
308+
316309
<IconButton
317-
icon="i-ph:caret-down"
318-
onClick={() => setIsWindowSizeDropdownOpen(!isWindowSizeDropdownOpen)}
319-
className="ml-1"
320-
title="Select Window Size"
310+
icon={isFullscreen ? 'i-ph:arrows-in' : 'i-ph:arrows-out'}
311+
onClick={toggleFullscreen}
312+
title={isFullscreen ? 'Exit Full Screen' : 'Full Screen'}
321313
/>
322314

323-
{isWindowSizeDropdownOpen && (
324-
<>
325-
<div className="fixed inset-0 z-50" onClick={() => setIsWindowSizeDropdownOpen(false)} />
326-
<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">
327-
{WINDOW_SIZES.map((size) => (
328-
<button
329-
key={size.name}
330-
className="w-full px-4 py-2 text-left hover:bg-bolt-elements-background-depth-3 text-sm whitespace-nowrap"
331-
onClick={() => {
332-
setSelectedWindowSize(size);
333-
setIsWindowSizeDropdownOpen(false);
334-
openInNewWindow(size);
335-
}}
336-
>
337-
{size.name}
338-
</button>
339-
))}
340-
</div>
341-
</>
342-
)}
315+
<div className="flex items-center relative">
316+
<IconButton
317+
icon="i-ph:arrow-square-out"
318+
onClick={() => openInNewWindow(selectedWindowSize)}
319+
title={`Open Preview in ${selectedWindowSize.name} Window`}
320+
/>
321+
<IconButton
322+
icon="i-ph:caret-down"
323+
onClick={() => setIsWindowSizeDropdownOpen(!isWindowSizeDropdownOpen)}
324+
className="ml-1"
325+
title="Select Window Size"
326+
/>
327+
328+
{isWindowSizeDropdownOpen && (
329+
<>
330+
<div className="fixed inset-0 z-50" onClick={() => setIsWindowSizeDropdownOpen(false)} />
331+
<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">
332+
{WINDOW_SIZES.map((size) => (
333+
<button
334+
key={size.name}
335+
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"
336+
onClick={() => {
337+
setSelectedWindowSize(size);
338+
setIsWindowSizeDropdownOpen(false);
339+
openInNewWindow(size);
340+
}}
341+
>
342+
<div
343+
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`}
344+
/>
345+
<div className="flex flex-col">
346+
<span className="font-medium group-hover:text-[#6D28D9] dark:group-hover:text-[#6D28D9] transition-colors duration-200">
347+
{size.name}
348+
</span>
349+
<span className="text-xs text-[#6B7280] dark:text-gray-400 group-hover:text-[#6D28D9] dark:group-hover:text-[#6D28D9] transition-colors duration-200">
350+
{size.width} × {size.height}
351+
</span>
352+
</div>
353+
</button>
354+
))}
355+
</div>
356+
</>
357+
)}
358+
</div>
343359
</div>
344360
</div>
345361

@@ -349,7 +365,7 @@ export const Preview = memo(() => {
349365
width: isDeviceModeOn ? `${widthPercent}%` : '100%',
350366
height: '100%',
351367
overflow: 'visible',
352-
background: '#fff',
368+
background: 'var(--bolt-elements-background-depth-1)',
353369
position: 'relative',
354370
display: 'flex',
355371
}}
@@ -359,7 +375,7 @@ export const Preview = memo(() => {
359375
<iframe
360376
ref={iframeRef}
361377
title="preview"
362-
className="border-none w-full h-full bg-white"
378+
className="border-none w-full h-full bg-bolt-elements-background-depth-1"
363379
src={iframeUrl}
364380
sandbox="allow-scripts allow-forms allow-popups allow-modals allow-storage-access-by-user-activation allow-same-origin"
365381
allow="cross-origin-isolated"
@@ -371,7 +387,9 @@ export const Preview = memo(() => {
371387
/>
372388
</>
373389
) : (
374-
<div className="flex w-full h-full justify-center items-center bg-white">No preview available</div>
390+
<div className="flex w-full h-full justify-center items-center bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary">
391+
No preview available
392+
</div>
375393
)}
376394

377395
{isDeviceModeOn && (

app/lib/modules/llm/providers/github.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export default class GithubProvider extends BaseProvider {
1111
config = {
1212
apiTokenKey: 'GITHUB_API_KEY',
1313
};
14-
// find more in https://github.com/marketplace?type=models
14+
15+
// find more in https://github.com/marketplace?type=models
1516
staticModels: ModelInfo[] = [
1617
{ name: 'gpt-4o', label: 'GPT-4o', provider: 'Github', maxTokenAllowed: 8000 },
1718
{ name: 'o1', label: 'o1-preview', provider: 'Github', maxTokenAllowed: 100000 },

0 commit comments

Comments
 (0)