mirror of
https://github.com/stackblitz/bolt.new
synced 2025-02-06 04:48:04 +00:00
added backdrop and loading screen
This commit is contained in:
parent
9f002279b6
commit
b304749b21
@ -8,6 +8,8 @@ import { Chat } from '~/components/chat/Chat.client';
|
|||||||
import { useGit } from '~/lib/hooks/useGit';
|
import { useGit } from '~/lib/hooks/useGit';
|
||||||
import { useChatHistory } from '~/lib/persistence';
|
import { useChatHistory } from '~/lib/persistence';
|
||||||
import { createCommandsMessage, detectProjectCommands } from '~/utils/projectCommands';
|
import { createCommandsMessage, detectProjectCommands } from '~/utils/projectCommands';
|
||||||
|
import { LoadingOverlay } from '~/components/ui/LoadingOverlay';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
const IGNORE_PATTERNS = [
|
const IGNORE_PATTERNS = [
|
||||||
'node_modules/**',
|
'node_modules/**',
|
||||||
@ -38,6 +40,7 @@ export function GitUrlImport() {
|
|||||||
const { ready: historyReady, importChat } = useChatHistory();
|
const { ready: historyReady, importChat } = useChatHistory();
|
||||||
const { ready: gitReady, gitClone } = useGit();
|
const { ready: gitReady, gitClone } = useGit();
|
||||||
const [imported, setImported] = useState(false);
|
const [imported, setImported] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const importRepo = async (repoUrl?: string) => {
|
const importRepo = async (repoUrl?: string) => {
|
||||||
if (!gitReady && !historyReady) {
|
if (!gitReady && !historyReady) {
|
||||||
@ -109,9 +112,23 @@ ${file.content}
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
importRepo(url);
|
importRepo(url).catch((error) => {
|
||||||
|
console.error('Error importing repo:', error);
|
||||||
|
toast.error('Failed to import repository');
|
||||||
|
setLoading(false);
|
||||||
|
window.location.href = '/';
|
||||||
|
});
|
||||||
setImported(true);
|
setImported(true);
|
||||||
}, [searchParams, historyReady, gitReady, imported]);
|
}, [searchParams, historyReady, gitReady, imported]);
|
||||||
|
|
||||||
return <ClientOnly fallback={<BaseChat />}>{() => <Chat />}</ClientOnly>;
|
return (
|
||||||
|
<ClientOnly fallback={<BaseChat />}>
|
||||||
|
{() => (
|
||||||
|
<>
|
||||||
|
<Chat />
|
||||||
|
{loading && <LoadingOverlay message="Please wait while we clone the repository..." />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ClientOnly>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
14
app/components/ui/LoadingOverlay.tsx
Normal file
14
app/components/ui/LoadingOverlay.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export const LoadingOverlay = ({ message = 'Loading...' }) => {
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 flex items-center justify-center bg-black/80 z-50 backdrop-blur-sm">
|
||||||
|
{/* Loading content */}
|
||||||
|
<div className="relative flex flex-col items-center gap-4 p-8 rounded-lg bg-bolt-elements-background-depth-2 shadow-lg">
|
||||||
|
<div
|
||||||
|
className={'i-svg-spinners:90-ring-with-bg text-bolt-elements-loader-progress'}
|
||||||
|
style={{ fontSize: '2rem' }}
|
||||||
|
></div>
|
||||||
|
<p className="text-lg text-bolt-elements-textTertiary">{message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -10,7 +10,6 @@ import { toast } from 'react-toastify';
|
|||||||
import { useNavigate } from '@remix-run/react';
|
import { useNavigate } from '@remix-run/react';
|
||||||
import commit from '~/commit.json';
|
import commit from '~/commit.json';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { SettingsSlider } from './SettingsSlider';
|
|
||||||
import '~/styles/components/SettingsSlider.scss';
|
import '~/styles/components/SettingsSlider.scss';
|
||||||
import '~/styles/components/Settings.scss';
|
import '~/styles/components/Settings.scss';
|
||||||
|
|
||||||
@ -219,9 +218,7 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
<button
|
<button
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
onClick={() => setActiveTab(tab.id)}
|
onClick={() => setActiveTab(tab.id)}
|
||||||
className={classNames(
|
className={classNames(activeTab === tab.id ? 'active' : '')}
|
||||||
activeTab === tab.id ? 'active' : ''
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div className={tab.icon} />
|
<div className={tab.icon} />
|
||||||
{tab.label}
|
{tab.label}
|
||||||
@ -250,7 +247,9 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col p-8 bg-gray-50 dark:bg-gray-800">
|
<div className="flex-1 flex flex-col p-8 bg-gray-50 dark:bg-gray-800">
|
||||||
<DialogTitle className="flex-shrink-0 text-lg font-semibold text-bolt-elements-textPrimary">Settings</DialogTitle>
|
<DialogTitle className="flex-shrink-0 text-lg font-semibold text-bolt-elements-textPrimary">
|
||||||
|
Settings
|
||||||
|
</DialogTitle>
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
{activeTab === 'chat-history' && (
|
{activeTab === 'chat-history' && (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
@ -304,14 +303,20 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
checked={provider.isEnabled}
|
checked={provider.isEnabled}
|
||||||
onChange={() => handleToggleProvider(provider.name)}
|
onChange={() => handleToggleProvider(provider.name)}
|
||||||
/>
|
/>
|
||||||
<div className={classNames(
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__track',
|
'settings-toggle__track',
|
||||||
provider.isEnabled ? 'settings-toggle__track--enabled' : 'settings-toggle__track--disabled'
|
provider.isEnabled
|
||||||
)}></div>
|
? 'settings-toggle__track--enabled'
|
||||||
<div className={classNames(
|
: 'settings-toggle__track--disabled',
|
||||||
|
)}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__thumb',
|
'settings-toggle__thumb',
|
||||||
provider.isEnabled ? 'settings-toggle__thumb--enabled' : ''
|
provider.isEnabled ? 'settings-toggle__thumb--enabled' : '',
|
||||||
)}></div>
|
)}
|
||||||
|
></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{/* Base URL input for configurable providers */}
|
{/* Base URL input for configurable providers */}
|
||||||
@ -343,14 +348,18 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
checked={isDebugEnabled}
|
checked={isDebugEnabled}
|
||||||
onChange={() => setIsDebugEnabled(!isDebugEnabled)}
|
onChange={() => setIsDebugEnabled(!isDebugEnabled)}
|
||||||
/>
|
/>
|
||||||
<div className={classNames(
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__track',
|
'settings-toggle__track',
|
||||||
isDebugEnabled ? 'settings-toggle__track--enabled' : 'settings-toggle__track--disabled'
|
isDebugEnabled ? 'settings-toggle__track--enabled' : 'settings-toggle__track--disabled',
|
||||||
)}></div>
|
)}
|
||||||
<div className={classNames(
|
></div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__thumb',
|
'settings-toggle__thumb',
|
||||||
isDebugEnabled ? 'settings-toggle__thumb--enabled' : ''
|
isDebugEnabled ? 'settings-toggle__thumb--enabled' : '',
|
||||||
)}></div>
|
)}
|
||||||
|
></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -367,14 +376,18 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
checked={isJustSayEnabled}
|
checked={isJustSayEnabled}
|
||||||
onChange={() => setIsJustSayEnabled(!isJustSayEnabled)}
|
onChange={() => setIsJustSayEnabled(!isJustSayEnabled)}
|
||||||
/>
|
/>
|
||||||
<div className={classNames(
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__track',
|
'settings-toggle__track',
|
||||||
isJustSayEnabled ? 'settings-toggle__track--enabled' : 'settings-toggle__track--disabled'
|
isJustSayEnabled ? 'settings-toggle__track--enabled' : 'settings-toggle__track--disabled',
|
||||||
)}></div>
|
)}
|
||||||
<div className={classNames(
|
></div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
'settings-toggle__thumb',
|
'settings-toggle__thumb',
|
||||||
isJustSayEnabled ? 'settings-toggle__thumb--enabled' : ''
|
isJustSayEnabled ? 'settings-toggle__thumb--enabled' : '',
|
||||||
)}></div>
|
)}
|
||||||
|
></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -408,7 +421,9 @@ export const Settings = ({ open, onClose }: SettingsProps) => {
|
|||||||
<ul>
|
<ul>
|
||||||
<li className="text-bolt-elements-textSecondary">Ollama: {process.env.REACT_APP_OLLAMA_URL}</li>
|
<li className="text-bolt-elements-textSecondary">Ollama: {process.env.REACT_APP_OLLAMA_URL}</li>
|
||||||
<li className="text-bolt-elements-textSecondary">OpenAI: {process.env.REACT_APP_OPENAI_URL}</li>
|
<li className="text-bolt-elements-textSecondary">OpenAI: {process.env.REACT_APP_OPENAI_URL}</li>
|
||||||
<li className="text-bolt-elements-textSecondary">LM Studio: {process.env.REACT_APP_LM_STUDIO_URL}</li>
|
<li className="text-bolt-elements-textSecondary">
|
||||||
|
LM Studio: {process.env.REACT_APP_LM_STUDIO_URL}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h4 className="text-md font-medium text-bolt-elements-textPrimary mt-4">Version Information</h4>
|
<h4 className="text-md font-medium text-bolt-elements-textPrimary mt-4">Version Information</h4>
|
||||||
|
@ -27,7 +27,7 @@ export const SettingsSlider = memo(<T,>({ selected, options, setSelected }: Sett
|
|||||||
<motion.div
|
<motion.div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'settings-slider__thumb',
|
'settings-slider__thumb',
|
||||||
isLeftSelected ? 'settings-slider__thumb--left' : 'settings-slider__thumb--right'
|
isLeftSelected ? 'settings-slider__thumb--left' : 'settings-slider__thumb--right',
|
||||||
)}
|
)}
|
||||||
initial={false}
|
initial={false}
|
||||||
animate={{
|
animate={{
|
||||||
@ -44,7 +44,7 @@ export const SettingsSlider = memo(<T,>({ selected, options, setSelected }: Sett
|
|||||||
onClick={() => setSelected?.(options.left.value)}
|
onClick={() => setSelected?.(options.left.value)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'settings-slider__button',
|
'settings-slider__button',
|
||||||
isLeftSelected ? 'settings-slider__button--selected' : 'settings-slider__button--unselected'
|
isLeftSelected ? 'settings-slider__button--selected' : 'settings-slider__button--unselected',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{options.left.text}
|
{options.left.text}
|
||||||
@ -53,7 +53,7 @@ export const SettingsSlider = memo(<T,>({ selected, options, setSelected }: Sett
|
|||||||
onClick={() => setSelected?.(options.right.value)}
|
onClick={() => setSelected?.(options.right.value)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'settings-slider__button',
|
'settings-slider__button',
|
||||||
!isLeftSelected ? 'settings-slider__button--selected' : 'settings-slider__button--unselected'
|
!isLeftSelected ? 'settings-slider__button--selected' : 'settings-slider__button--unselected',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{options.right.text}
|
{options.right.text}
|
||||||
|
Loading…
Reference in New Issue
Block a user