From 7984a07b16d661ebc4f63ecc59e1133b4181c961 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Thu, 14 Nov 2024 17:50:00 +0530 Subject: [PATCH 001/249] feat(styling): added rey effects for the UI as decorative elements --- app/components/chat/BaseChat.tsx | 5 +- app/components/chat/Chat.client.tsx | 6 +- app/components/header/Header.tsx | 11 +- app/components/ui/BackgroundRays/index.tsx | 44 +++ .../ui/BackgroundRays/styles.module.scss | 251 ++++++++++++++++++ app/routes/_index.tsx | 2 + 6 files changed, 305 insertions(+), 14 deletions(-) create mode 100644 app/components/ui/BackgroundRays/index.tsx create mode 100644 app/components/ui/BackgroundRays/styles.module.scss diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index f7fe80a..c5fe705 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -156,10 +156,7 @@ export const BaseChat = React.forwardRef( return (
{() => } diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index a8f94f0..bf99797 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -92,7 +92,7 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp const { messages, isLoading, input, handleInputChange, setInput, stop, append } = useChat({ api: '/api/chat', body: { - apiKeys + apiKeys, }, onError: (error) => { logger.error('Request failed\n\n', error); @@ -263,14 +263,14 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp })} enhancePrompt={() => { enhancePrompt( - input, + input, (input) => { setInput(input); scrollTextArea(); }, model, provider, - apiKeys + apiKeys, ); }} /> diff --git a/app/components/header/Header.tsx b/app/components/header/Header.tsx index 15cf4bf..99b250f 100644 --- a/app/components/header/Header.tsx +++ b/app/components/header/Header.tsx @@ -10,13 +10,10 @@ export function Header() { return (
diff --git a/app/components/ui/BackgroundRays/index.tsx b/app/components/ui/BackgroundRays/index.tsx new file mode 100644 index 0000000..b8a200a --- /dev/null +++ b/app/components/ui/BackgroundRays/index.tsx @@ -0,0 +1,44 @@ +// PurpleRays.jsx +import React, { useEffect, useState } from 'react'; +import styles from './styles.module.scss'; + +const BackgroundRays = () => { + const [theme, setTheme] = useState('dark'); + + useEffect(() => { + // Initial theme + const currentTheme = document.documentElement.getAttribute('data-theme'); + setTheme(currentTheme || 'dark'); + + // Optional: Watch for theme changes + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'data-theme') { + const newTheme = document.documentElement.getAttribute('data-theme'); + setTheme((existingTheme) => newTheme || existingTheme); + } + }); + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-theme'], + }); + + return () => observer.disconnect(); + }, []); + 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..633d693 --- /dev/null +++ b/app/components/ui/BackgroundRays/styles.module.scss @@ -0,0 +1,251 @@ +.rayContainer { + --gradient-opacity: 0.8; + --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)); + + // 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..1c48442 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' }]; @@ -13,6 +14,7 @@ export const loader = () => json({}); export default function Index() { return (
+
}>{() => }
From dd82a3055b6a746c973a84550a7e2c78ae7f84d1 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Thu, 21 Nov 2024 01:16:45 +0530 Subject: [PATCH 002/249] flash fix --- app/routes/_index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 1c48442..d159d45 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -13,7 +13,7 @@ export const loader = () => json({}); export default function Index() { return ( -
+
}>{() => } From 45445549f12cde68abb543b8a224b5c4142f18e0 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Thu, 21 Nov 2024 01:21:39 +0530 Subject: [PATCH 003/249] another theme switch fix --- app/routes/_index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index d159d45..dc1c835 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -13,7 +13,7 @@ export const loader = () => json({}); export default function Index() { return ( -
+
}>{() => } From 7fd364d0b139538091b095fdacc720de20943b0a Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Thu, 21 Nov 2024 01:22:30 +0530 Subject: [PATCH 004/249] removed the background color from rays --- app/components/ui/BackgroundRays/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/ui/BackgroundRays/index.tsx b/app/components/ui/BackgroundRays/index.tsx index b8a200a..7f77c4c 100644 --- a/app/components/ui/BackgroundRays/index.tsx +++ b/app/components/ui/BackgroundRays/index.tsx @@ -28,7 +28,7 @@ const BackgroundRays = () => { return () => observer.disconnect(); }, []); return ( -
+
From 44bda1500aa40da39817ec682e5611d938a4a589 Mon Sep 17 00:00:00 2001 From: Diego Souza Date: Tue, 26 Nov 2024 17:39:13 -0300 Subject: [PATCH 005/249] Check the render method of SlotClone. #432 --- app/components/chat/Messages.client.tsx | 8 +- app/components/ui/IconButton.tsx | 75 ++++++++------- app/components/ui/Tooltip.tsx | 118 +++++++++++++----------- 3 files changed, 107 insertions(+), 94 deletions(-) diff --git a/app/components/chat/Messages.client.tsx b/app/components/chat/Messages.client.tsx index 4a2ac6a..2765144 100644 --- a/app/components/chat/Messages.client.tsx +++ b/app/components/chat/Messages.client.tsx @@ -69,8 +69,8 @@ export const Messages = React.forwardRef((props:
{!isUserMessage && (
- - {messageId && ( + {messageId && ( + - ); - }, + onClick?.(event); + }} + > + {children ? children :
} + + ); + }, + ), ); function getIconSize(size: IconSize) { diff --git a/app/components/ui/Tooltip.tsx b/app/components/ui/Tooltip.tsx index 4e22f54..278fa1e 100644 --- a/app/components/ui/Tooltip.tsx +++ b/app/components/ui/Tooltip.tsx @@ -1,8 +1,9 @@ import * as Tooltip from '@radix-ui/react-tooltip'; +import { forwardRef, type ForwardedRef, type ReactElement } from 'react'; interface TooltipProps { tooltip: React.ReactNode; - children: React.ReactNode; + children: ReactElement; sideOffset?: number; className?: string; arrowClassName?: string; @@ -12,62 +13,67 @@ interface TooltipProps { delay?: number; } -const WithTooltip = ({ - tooltip, - children, - sideOffset = 5, - className = '', - arrowClassName = '', - tooltipStyle = {}, - position = 'top', - maxWidth = 250, - delay = 0, -}: TooltipProps) => { - return ( - - {children} - - -
{tooltip}
- , + ) => { + return ( + + {children} + + - - - - ); -}; + sideOffset={sideOffset} + style={{ + maxWidth, + ...tooltipStyle, + }} + > +
{tooltip}
+ +
+
+
+ ); + }, +); export default WithTooltip; From 8b7e18e62795248f11c2b3cb469f92ca4795a055 Mon Sep 17 00:00:00 2001 From: Ed McConnell Date: Thu, 5 Dec 2024 17:30:45 -0500 Subject: [PATCH 006/249] Initial commit for screen cap feature --- app/components/chat/BaseChat.tsx | 11 + .../chat/ScreenshotStateManager.tsx | 33 +++ app/components/workbench/Preview.tsx | 14 +- .../workbench/ScreenshotSelector.tsx | 203 ++++++++++++++++++ 4 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 app/components/chat/ScreenshotStateManager.tsx create mode 100644 app/components/workbench/ScreenshotSelector.tsx diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 8c7589a..ed317e4 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -25,6 +25,7 @@ import { ExamplePrompts } from '~/components/chat/ExamplePrompts'; import FilePreview from './FilePreview'; import { ModelSelector } from '~/components/chat/ModelSelector'; import { SpeechRecognitionButton } from '~/components/chat/SpeechRecognition'; +import { ScreenshotStateManager } from './ScreenshotStateManager'; const TEXTAREA_MIN_HEIGHT = 76; @@ -376,6 +377,16 @@ export const BaseChat = React.forwardRef( setImageDataList?.(imageDataList.filter((_, i) => i !== index)); }} /> + + {() => ( + + )} +
void; + setImageDataList?: (dataList: string[]) => void; + uploadedFiles: File[]; + imageDataList: string[]; +} + +export const ScreenshotStateManager = ({ + setUploadedFiles, + setImageDataList, + uploadedFiles, + imageDataList, +}: ScreenshotStateManagerProps) => { + useEffect(() => { + if (setUploadedFiles && setImageDataList) { + (window as any).__BOLT_SET_UPLOADED_FILES__ = setUploadedFiles; + (window as any).__BOLT_SET_IMAGE_DATA_LIST__ = setImageDataList; + (window as any).__BOLT_UPLOADED_FILES__ = uploadedFiles; + (window as any).__BOLT_IMAGE_DATA_LIST__ = imageDataList; + } + + return () => { + delete (window as any).__BOLT_SET_UPLOADED_FILES__; + delete (window as any).__BOLT_SET_IMAGE_DATA_LIST__; + delete (window as any).__BOLT_UPLOADED_FILES__; + delete (window as any).__BOLT_IMAGE_DATA_LIST__; + }; + }, [setUploadedFiles, setImageDataList, uploadedFiles, imageDataList]); + + return null; +}; diff --git a/app/components/workbench/Preview.tsx b/app/components/workbench/Preview.tsx index 4c1877c..a866676 100644 --- a/app/components/workbench/Preview.tsx +++ b/app/components/workbench/Preview.tsx @@ -3,6 +3,7 @@ import { memo, useCallback, useEffect, useRef, useState } from 'react'; import { IconButton } from '~/components/ui/IconButton'; import { workbenchStore } from '~/lib/stores/workbench'; import { PortDropdown } from './PortDropdown'; +import { ScreenshotSelector } from './ScreenshotSelector'; export const Preview = memo(() => { const iframeRef = useRef(null); @@ -15,6 +16,7 @@ export const Preview = memo(() => { const [url, setUrl] = useState(''); const [iframeUrl, setIframeUrl] = useState(); + const [isSelectionMode, setIsSelectionMode] = useState(false); useEffect(() => { if (!activePreview) { @@ -25,7 +27,7 @@ export const Preview = memo(() => { } const { baseUrl } = activePreview; - + setUrl(baseUrl); setIframeUrl(baseUrl); }, [activePreview, iframeUrl]); @@ -78,18 +80,19 @@ export const Preview = memo(() => { )}
+ setIsSelectionMode(!isSelectionMode)} className={isSelectionMode ? 'bg-bolt-elements-background-depth-3' : ''} />
- { setUrl(event.target.value); - }} + }} onKeyDown={(event) => { if (event.key === 'Enter' && validateUrl(url)) { setIframeUrl(url); @@ -114,7 +117,10 @@ export const Preview = memo(() => {
{activePreview ? ( -