diff --git a/README.md b/README.md index 9ac2581..3b1d282 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ [![Bolt.new: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.new) -# Bolt.new Fork by Cole Medin - oTToDev +# Bolt.diy (Previously oTToDev) -This fork of Bolt.new (oTToDev) 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. -Check the [oTToDev Docs](https://coleam00.github.io/bolt.new-any-llm/) for more information. +Check the [Bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information. This documentation is still being updated after the transfer. -## Join the community for oTToDev! +Bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMedin) but has quickly grown into a massive community effort to build the BEST open source AI coding assistant! + +## Join the community for Bolt.diy! https://thinktank.ottomator.ai @@ -56,7 +58,7 @@ https://thinktank.ottomator.ai ## Bolt.new: AI-Powered Full-Stack Web Development in the Browser -Bolt.new is an AI-powered web development agent that allows you to prompt, run, edit, and deploy full-stack applications directly from your browser—no local setup required. If you're here to build your own AI-powered web dev agent using the Bolt open source codebase, [click here to get started!](./CONTRIBUTING.md) +Bolt.new (and by extension Bolt.diy) is an AI-powered web development agent that allows you to prompt, run, edit, and deploy full-stack applications directly from your browser—no local setup required. If you're here to build your own AI-powered web dev agent using the Bolt open source codebase, [click here to get started!](./CONTRIBUTING.md) ## What Makes Bolt.new Different @@ -96,7 +98,7 @@ If you see usr/local/bin in the output then you're good to go. 3. Clone the repository (if you haven't already) by opening a Terminal window (or CMD with admin permissions) and then typing in this: ``` -git clone https://github.com/coleam00/bolt.new-any-llm.git +git clone https://github.com/stackblitz-labs/bolt.diy.git ``` 3. Rename .env.example to .env.local and add your LLM API keys. You will find this file on a Mac at "[your name]/bold.new-any-llm/.env.example". For Windows and Linux the path will be similar. @@ -225,11 +227,11 @@ pnpm run dev This will start the Remix Vite development server. You will need Google Chrome Canary to run this locally if you use Chrome! It's an easy install and a good browser for web development anyway. -## How do I contribute to oTToDev? +## How do I contribute to Bolt.diy? -[Please check out our dedicated page for contributing to oTToDev here!](CONTRIBUTING.md) +[Please check out our dedicated page for contributing to Bolt.diy here!](CONTRIBUTING.md) -## What are the future plans for oTToDev? +## What are the future plans for Bolt.diy? [Check out our Roadmap here!](https://roadmap.sh/r/ottodev-roadmap-2ovzo) @@ -237,4 +239,4 @@ Lot more updates to this roadmap coming soon! ## FAQ -[Please check out our dedicated page for FAQ's related to oTToDev here!](FAQ.md) +[Please check out our dedicated page for FAQ's related to Bolt.diy here!](FAQ.md) diff --git a/app/commit.json b/app/commit.json index 7ed2c7d..32c0842 100644 --- a/app/commit.json +++ b/app/commit.json @@ -1 +1 @@ -{ "commit": "eddf5603c3865536f96774fc3358cf24760fb613" } +{ "commit": "fd2c17c384a69ab5e7a40113342caa7de405b944" } diff --git a/app/components/chat/BaseChat.module.scss b/app/components/chat/BaseChat.module.scss index cf530a1..4908e34 100644 --- a/app/components/chat/BaseChat.module.scss +++ b/app/components/chat/BaseChat.module.scss @@ -18,82 +18,6 @@ opacity: 1; } -.RayContainer { - --gradient-opacity: 0.85; - --ray-gradient: radial-gradient(rgba(83, 196, 255, var(--gradient-opacity)) 0%, rgba(43, 166, 255, 0) 100%); - transition: opacity 0.25s linear; - position: fixed; - inset: 0; - pointer-events: none; - user-select: none; -} - -.LightRayOne { - width: 480px; - height: 680px; - transform: rotate(80deg); - top: -540px; - left: 250px; - filter: blur(110px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayTwo { - width: 110px; - height: 400px; - transform: rotate(-20deg); - top: -280px; - left: 350px; - mix-blend-mode: overlay; - opacity: 0.6; - filter: blur(60px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayThree { - width: 400px; - height: 370px; - top: -350px; - left: 200px; - mix-blend-mode: overlay; - opacity: 0.6; - filter: blur(21px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayFour { - position: absolute; - width: 330px; - height: 370px; - top: -330px; - left: 50px; - mix-blend-mode: overlay; - opacity: 0.5; - filter: blur(21px); - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayFive { - position: absolute; - width: 110px; - height: 400px; - transform: rotate(-40deg); - top: -280px; - left: -10px; - mix-blend-mode: overlay; - opacity: 0.8; - filter: blur(60px); - border-radius: 100%; - background: var(--ray-gradient); -} - .PromptEffectContainer { --prompt-container-offset: 50px; --prompt-line-stroke-width: 1px; diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index b17baf9..a77932c 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -110,8 +110,10 @@ export const BaseChat = React.forwardRef( const [recognition, setRecognition] = useState(null); const [transcript, setTranscript] = useState(''); - // Update enabled providers when cookies change - console.log(transcript); + useEffect(() => { + console.log(transcript); + }, [transcript]); + useEffect(() => { // Load API keys from cookies on component mount try { @@ -274,19 +276,9 @@ export const BaseChat = React.forwardRef( const baseChat = (
-
-
-
-
-
-
-
{() => }
@@ -336,15 +328,15 @@ export const BaseChat = React.forwardRef( gradientUnits="userSpaceOnUse" gradientTransform="rotate(-45)" > - - - - + + + + - - + + diff --git a/app/components/chat/ModelSelector.tsx b/app/components/chat/ModelSelector.tsx index 435f4ba..bd41eb4 100644 --- a/app/components/chat/ModelSelector.tsx +++ b/app/components/chat/ModelSelector.tsx @@ -121,8 +121,8 @@ export const ModelSelector = ({ > {[...modelList] .filter((e) => e.provider == provider?.name && e.name) - .map((modelOption) => ( - ))} diff --git a/app/components/header/Header.tsx b/app/components/header/Header.tsx index 8b2e81f..ce46702 100644 --- a/app/components/header/Header.tsx +++ b/app/components/header/Header.tsx @@ -10,18 +10,17 @@ export function Header() { return (
{chat.started && ( // Display ChatDescription and HeaderActionButtons only when the chat has started. diff --git a/app/components/settings/Settings.module.scss b/app/components/settings/Settings.module.scss index 6da8288..639cbbc 100644 --- a/app/components/settings/Settings.module.scss +++ b/app/components/settings/Settings.module.scss @@ -46,7 +46,7 @@ padding: 1rem; margin-bottom: 1rem; border-style: solid; - border-color: var(--bolt-elements-button-danger-backgroundHover) ; + border-color: var(--bolt-elements-button-danger-backgroundHover); border-width: thin; button { @@ -60,4 +60,4 @@ background-color: var(--bolt-elements-button-danger-backgroundHover); } } -} \ No newline at end of file +} diff --git a/app/components/settings/SettingsWindow.tsx b/app/components/settings/SettingsWindow.tsx index 8ae4a48..b7b368d 100644 --- a/app/components/settings/SettingsWindow.tsx +++ b/app/components/settings/SettingsWindow.tsx @@ -83,7 +83,7 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => { ))}
{ GitHub { + return ( +
+
+
+
+
+
+
+
+
+
+ ); +}; + +export default BackgroundRays; diff --git a/app/components/ui/BackgroundRays/styles.module.scss b/app/components/ui/BackgroundRays/styles.module.scss new file mode 100644 index 0000000..bac4c8a --- /dev/null +++ b/app/components/ui/BackgroundRays/styles.module.scss @@ -0,0 +1,246 @@ +.rayContainer { + // Theme-specific colors + --ray-color-primary: color-mix(in srgb, var(--primary-color), transparent 30%); + --ray-color-secondary: color-mix(in srgb, var(--secondary-color), transparent 30%); + --ray-color-accent: color-mix(in srgb, var(--accent-color), transparent 30%); + + // Theme-specific gradients + --ray-gradient-primary: radial-gradient(var(--ray-color-primary) 0%, transparent 70%); + --ray-gradient-secondary: radial-gradient(var(--ray-color-secondary) 0%, transparent 70%); + --ray-gradient-accent: radial-gradient(var(--ray-color-accent) 0%, transparent 70%); + + position: fixed; + inset: 0; + overflow: hidden; + animation: fadeIn 1.5s ease-out; + pointer-events: none; + z-index: 0; + // background-color: transparent; + + :global(html[data-theme='dark']) & { + mix-blend-mode: screen; + } + + :global(html[data-theme='light']) & { + mix-blend-mode: multiply; + } +} + +.lightRay { + position: absolute; + border-radius: 100%; + + :global(html[data-theme='dark']) & { + mix-blend-mode: screen; + } + + :global(html[data-theme='light']) & { + mix-blend-mode: multiply; + opacity: 0.4; + } +} + +.ray1 { + width: 600px; + height: 800px; + background: var(--ray-gradient-primary); + transform: rotate(65deg); + top: -500px; + left: -100px; + filter: blur(80px); + opacity: 0.6; + animation: float1 15s infinite ease-in-out; +} + +.ray2 { + width: 400px; + height: 600px; + background: var(--ray-gradient-secondary); + transform: rotate(-30deg); + top: -300px; + left: 200px; + filter: blur(60px); + opacity: 0.6; + animation: float2 18s infinite ease-in-out; +} + +.ray3 { + width: 500px; + height: 400px; + background: var(--ray-gradient-accent); + top: -320px; + left: 500px; + filter: blur(65px); + opacity: 0.5; + animation: float3 20s infinite ease-in-out; +} + +.ray4 { + width: 400px; + height: 450px; + background: var(--ray-gradient-secondary); + top: -350px; + left: 800px; + filter: blur(55px); + opacity: 0.55; + animation: float4 17s infinite ease-in-out; +} + +.ray5 { + width: 350px; + height: 500px; + background: var(--ray-gradient-primary); + transform: rotate(-45deg); + top: -250px; + left: 1000px; + filter: blur(45px); + opacity: 0.6; + animation: float5 16s infinite ease-in-out; +} + +.ray6 { + width: 300px; + height: 700px; + background: var(--ray-gradient-accent); + transform: rotate(75deg); + top: -400px; + left: 600px; + filter: blur(75px); + opacity: 0.45; + animation: float6 19s infinite ease-in-out; +} + +.ray7 { + width: 450px; + height: 600px; + background: var(--ray-gradient-primary); + transform: rotate(45deg); + top: -450px; + left: 350px; + filter: blur(65px); + opacity: 0.55; + animation: float7 21s infinite ease-in-out; +} + +.ray8 { + width: 380px; + height: 550px; + background: var(--ray-gradient-secondary); + transform: rotate(-60deg); + top: -380px; + left: 750px; + filter: blur(58px); + opacity: 0.6; + animation: float8 14s infinite ease-in-out; +} + +@keyframes float1 { + 0%, + 100% { + transform: rotate(65deg) translate(0, 0); + } + 25% { + transform: rotate(70deg) translate(30px, 20px); + } + 50% { + transform: rotate(60deg) translate(-20px, 40px); + } + 75% { + transform: rotate(68deg) translate(-40px, 10px); + } +} + +@keyframes float2 { + 0%, + 100% { + transform: rotate(-30deg) scale(1); + } + 33% { + transform: rotate(-25deg) scale(1.1); + } + 66% { + transform: rotate(-35deg) scale(0.95); + } +} + +@keyframes float3 { + 0%, + 100% { + transform: translate(0, 0) rotate(0deg); + } + 25% { + transform: translate(40px, 20px) rotate(5deg); + } + 75% { + transform: translate(-30px, 40px) rotate(-5deg); + } +} + +@keyframes float4 { + 0%, + 100% { + transform: scale(1) rotate(0deg); + } + 50% { + transform: scale(1.15) rotate(10deg); + } +} + +@keyframes float5 { + 0%, + 100% { + transform: rotate(-45deg) translate(0, 0); + } + 33% { + transform: rotate(-40deg) translate(25px, -20px); + } + 66% { + transform: rotate(-50deg) translate(-25px, 20px); + } +} + +@keyframes float6 { + 0%, + 100% { + transform: rotate(75deg) scale(1); + filter: blur(75px); + } + 50% { + transform: rotate(85deg) scale(1.1); + filter: blur(65px); + } +} + +@keyframes float7 { + 0%, + 100% { + transform: rotate(45deg) translate(0, 0); + opacity: 0.55; + } + 50% { + transform: rotate(40deg) translate(-30px, 30px); + opacity: 0.65; + } +} + +@keyframes float8 { + 0%, + 100% { + transform: rotate(-60deg) scale(1); + } + 25% { + transform: rotate(-55deg) scale(1.05); + } + 75% { + transform: rotate(-65deg) scale(0.95); + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 86d7340..dc1c835 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -3,6 +3,7 @@ import { ClientOnly } from 'remix-utils/client-only'; import { BaseChat } from '~/components/chat/BaseChat'; import { Chat } from '~/components/chat/Chat.client'; import { Header } from '~/components/header/Header'; +import BackgroundRays from '~/components/ui/BackgroundRays'; export const meta: MetaFunction = () => { return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }]; @@ -12,7 +13,8 @@ export const loader = () => json({}); export default function Index() { return ( -
+
+
}>{() => }
diff --git a/app/styles/index.scss b/app/styles/index.scss index 36ebac2..91a4cf8 100644 --- a/app/styles/index.scss +++ b/app/styles/index.scss @@ -12,3 +12,13 @@ body { height: 100%; width: 100%; } + +:root { + --gradient-opacity: 0.8; + --primary-color: rgba(158, 117, 240, var(--gradient-opacity)); + --secondary-color: rgba(138, 43, 226, var(--gradient-opacity)); + --accent-color: rgba(128, 59, 239, var(--gradient-opacity)); + // --primary-color: rgba(147, 112, 219, var(--gradient-opacity)); + // --secondary-color: rgba(138, 43, 226, var(--gradient-opacity)); + // --accent-color: rgba(180, 170, 220, var(--gradient-opacity)); +} diff --git a/app/utils/constants.ts b/app/utils/constants.ts index ffedee6..9d98774 100644 --- a/app/utils/constants.ts +++ b/app/utils/constants.ts @@ -1,6 +1,7 @@ import Cookies from 'js-cookie'; import type { ModelInfo, OllamaApiResponse, OllamaModel } from './types'; import type { ProviderInfo, IProviderSetting } from '~/types/model'; +import { createScopedLogger } from './logger'; export const WORK_DIR_NAME = 'project'; export const WORK_DIR = `/home/${WORK_DIR_NAME}`; @@ -10,6 +11,8 @@ export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/; export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest'; export const PROMPT_COOKIE_KEY = 'cachedPrompt'; +const logger = createScopedLogger('Constants'); + const PROVIDER_LIST: ProviderInfo[] = [ { name: 'Anthropic', @@ -386,8 +389,8 @@ async function getOllamaModels(apiKeys?: Record, settings?: IPro provider: 'Ollama', maxTokenAllowed: 8000, })); - } catch (e) { - console.error('Error getting Ollama models:', e); + } catch (e: any) { + logger.warn('Failed to get Ollama models: ', e.message || ''); return []; } } @@ -475,8 +478,8 @@ async function getLMStudioModels(_apiKeys?: Record, settings?: I label: model.id, provider: 'LMStudio', })); - } catch (e) { - console.error('Error getting LMStudio models:', e); + } catch (e: any) { + logger.warn('Failed to get LMStudio models: ', e.message || ''); return []; } } @@ -495,7 +498,7 @@ async function initializeModelList(providerSettings?: Record - + diff --git a/public/logo-dark-styled.png b/public/logo-dark-styled.png new file mode 100644 index 0000000..d410fe6 Binary files /dev/null and b/public/logo-dark-styled.png differ diff --git a/public/logo-dark.png b/public/logo-dark.png new file mode 100644 index 0000000..377fda3 Binary files /dev/null and b/public/logo-dark.png differ diff --git a/public/logo-light-styled.png b/public/logo-light-styled.png new file mode 100644 index 0000000..ef0af66 Binary files /dev/null and b/public/logo-light-styled.png differ diff --git a/public/logo-light.png b/public/logo-light.png new file mode 100644 index 0000000..6b4513e Binary files /dev/null and b/public/logo-light.png differ diff --git a/public/logo.svg b/public/logo.svg index 58d6874..d3ae1ba 100644 --- a/public/logo.svg +++ b/public/logo.svg @@ -1 +1,15 @@ - + + + + + + + + + + + + + + + diff --git a/public/social_preview_index.jpg b/public/social_preview_index.jpg index 55952e3..2f226cb 100644 Binary files a/public/social_preview_index.jpg and b/public/social_preview_index.jpg differ diff --git a/uno.config.ts b/uno.config.ts index 503e1af..2401991 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -35,17 +35,17 @@ const BASE_COLORS = { 950: '#0A0A0A', }, accent: { - 50: '#EEF9FF', - 100: '#D8F1FF', - 200: '#BAE7FF', - 300: '#8ADAFF', - 400: '#53C4FF', - 500: '#2BA6FF', - 600: '#1488FC', - 700: '#0D6FE8', - 800: '#1259BB', - 900: '#154E93', - 950: '#122F59', + 50: '#F8F5FF', + 100: '#F0EBFF', + 200: '#E1D6FF', + 300: '#CEBEFF', + 400: '#B69EFF', + 500: '#9C7DFF', + 600: '#8A5FFF', + 700: '#7645E8', + 800: '#6234BB', + 900: '#502D93', + 950: '#2D1959', }, green: { 50: '#F0FDF4',