fix: resolve toast message visibility and deployment success notifications
## Issues Fixed - Toast messages appearing in background/blurred due to z-index conflicts - Missing success toast notifications for deployment completions - Scoped ToastContainer limiting toast visibility to chat component only ## Changes Made ### Global Toast System - Move ToastContainer from Chat.client.tsx to root.tsx for global availability - Add highest z-index (1000) to ensure toasts appear above all UI elements - Remove duplicate ToastContainer from chat component ### Z-Index System Updates - Add .z-toast class with z-index: $zIndexMax + 1 (1000) - Apply toast z-index to .Toastify__toast-container in toast.scss - Ensure proper layering hierarchy for all toast messages ### Deployment Success Notifications - Add missing toast.success() calls to all deployment services: - NetlifyDeploy: "🚀 Netlify deployment completed successfully!" - VercelDeploy: "🚀 Vercel deployment completed successfully!" - GitHubDeploy: "🚀 GitHub deployment preparation completed successfully!" - GitLabDeploy: "🚀 GitLab deployment preparation completed successfully!" ## Result - All toast messages now appear in foreground with proper z-index - Deployment success notifications are clearly visible to users - Consistent toast behavior across the entire application - No more blurred or background toast messages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import type { Message } from 'ai';
|
|||||||
import { useChat } from '@ai-sdk/react';
|
import { useChat } from '@ai-sdk/react';
|
||||||
import { useAnimate } from 'framer-motion';
|
import { useAnimate } from 'framer-motion';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useMessageParser, usePromptEnhancer, useShortcuts } from '~/lib/hooks';
|
import { useMessageParser, usePromptEnhancer, useShortcuts } from '~/lib/hooks';
|
||||||
import { description, useChatHistory } from '~/lib/persistence';
|
import { description, useChatHistory } from '~/lib/persistence';
|
||||||
import { chatStore } from '~/lib/stores/chat';
|
import { chatStore } from '~/lib/stores/chat';
|
||||||
@@ -29,11 +29,6 @@ import type { TextUIPart, FileUIPart, Attachment } from '@ai-sdk/ui-utils';
|
|||||||
import { useMCPStore } from '~/lib/stores/mcp';
|
import { useMCPStore } from '~/lib/stores/mcp';
|
||||||
import type { LlmErrorAlertType } from '~/types/actions';
|
import type { LlmErrorAlertType } from '~/types/actions';
|
||||||
|
|
||||||
const toastAnimation = cssTransition({
|
|
||||||
enter: 'animated fadeInRight',
|
|
||||||
exit: 'animated fadeOutRight',
|
|
||||||
});
|
|
||||||
|
|
||||||
const logger = createScopedLogger('Chat');
|
const logger = createScopedLogger('Chat');
|
||||||
|
|
||||||
export function Chat() {
|
export function Chat() {
|
||||||
@@ -56,34 +51,6 @@ export function Chat() {
|
|||||||
importChat={importChat}
|
importChat={importChat}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ToastContainer
|
|
||||||
closeButton={({ closeToast }) => {
|
|
||||||
return (
|
|
||||||
<button className="Toastify__close-button" onClick={closeToast}>
|
|
||||||
<div className="i-ph:x text-lg" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
icon={({ type }) => {
|
|
||||||
/**
|
|
||||||
* @todo Handle more types if we need them. This may require extra color palettes.
|
|
||||||
*/
|
|
||||||
switch (type) {
|
|
||||||
case 'success': {
|
|
||||||
return <div className="i-ph:check-bold text-bolt-elements-icon-success text-2xl" />;
|
|
||||||
}
|
|
||||||
case 'error': {
|
|
||||||
return <div className="i-ph:warning-circle-bold text-bolt-elements-icon-error text-2xl" />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}}
|
|
||||||
position="bottom-right"
|
|
||||||
pauseOnFocusLoss
|
|
||||||
transition={toastAnimation}
|
|
||||||
autoClose={3000}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ export function useGitHubDeploy() {
|
|||||||
source: 'github',
|
source: 'github',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 GitHub deployment preparation completed successfully!`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
files: fileContents,
|
files: fileContents,
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ export function useGitLabDeploy() {
|
|||||||
source: 'gitlab',
|
source: 'gitlab',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 GitLab deployment preparation completed successfully!`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
files: fileContents,
|
files: fileContents,
|
||||||
|
|||||||
@@ -224,6 +224,9 @@ export function useNetlifyDeploy() {
|
|||||||
source: 'netlify',
|
source: 'netlify',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 Netlify deployment completed successfully!`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Deploy error:', error);
|
console.error('Deploy error:', error);
|
||||||
|
|||||||
@@ -213,6 +213,9 @@ export function useVercelDeploy() {
|
|||||||
source: 'vercel',
|
source: 'vercel',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 Vercel deployment completed successfully!`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Vercel deploy error:', err);
|
console.error('Vercel deploy error:', err);
|
||||||
|
|||||||
31
app/root.tsx
31
app/root.tsx
@@ -9,6 +9,7 @@ import { useEffect } from 'react';
|
|||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import { ClientOnly } from 'remix-utils/client-only';
|
import { ClientOnly } from 'remix-utils/client-only';
|
||||||
|
import { cssTransition, ToastContainer } from 'react-toastify';
|
||||||
|
|
||||||
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
||||||
import globalStyles from './styles/index.scss?url';
|
import globalStyles from './styles/index.scss?url';
|
||||||
@@ -16,6 +17,11 @@ import xtermStyles from '@xterm/xterm/css/xterm.css?url';
|
|||||||
|
|
||||||
import 'virtual:uno.css';
|
import 'virtual:uno.css';
|
||||||
|
|
||||||
|
const toastAnimation = cssTransition({
|
||||||
|
enter: 'animated fadeInRight',
|
||||||
|
exit: 'animated fadeOutRight',
|
||||||
|
});
|
||||||
|
|
||||||
export const links: LinksFunction = () => [
|
export const links: LinksFunction = () => [
|
||||||
{
|
{
|
||||||
rel: 'icon',
|
rel: 'icon',
|
||||||
@@ -75,6 +81,31 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ClientOnly>{() => <DndProvider backend={HTML5Backend}>{children}</DndProvider>}</ClientOnly>
|
<ClientOnly>{() => <DndProvider backend={HTML5Backend}>{children}</DndProvider>}</ClientOnly>
|
||||||
|
<ToastContainer
|
||||||
|
closeButton={({ closeToast }) => {
|
||||||
|
return (
|
||||||
|
<button className="Toastify__close-button" onClick={closeToast}>
|
||||||
|
<div className="i-ph:x text-lg" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
icon={({ type }) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'success': {
|
||||||
|
return <div className="i-ph:check-bold text-bolt-elements-icon-success text-2xl" />;
|
||||||
|
}
|
||||||
|
case 'error': {
|
||||||
|
return <div className="i-ph:warning-circle-bold text-bolt-elements-icon-error text-2xl" />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}}
|
||||||
|
position="bottom-right"
|
||||||
|
pauseOnFocusLoss
|
||||||
|
transition={toastAnimation}
|
||||||
|
autoClose={3000}
|
||||||
|
/>
|
||||||
<ScrollRestoration />
|
<ScrollRestoration />
|
||||||
<Scripts />
|
<Scripts />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
@use '../z-index';
|
||||||
|
|
||||||
|
.Toastify__toast-container {
|
||||||
|
@extend .z-toast;
|
||||||
|
}
|
||||||
|
|
||||||
.Toastify__toast {
|
.Toastify__toast {
|
||||||
--at-apply: shadow-md;
|
--at-apply: shadow-md;
|
||||||
|
|
||||||
|
|||||||
@@ -31,3 +31,7 @@ $zIndexMax: 999;
|
|||||||
.z-max {
|
.z-max {
|
||||||
z-index: $zIndexMax;
|
z-index: $zIndexMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.z-toast {
|
||||||
|
z-index: $zIndexMax + 1;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user