codacus commited on
Commit
7984a07
·
1 Parent(s): a081f8b

feat(styling): added rey effects for the UI as decorative elements

Browse files
app/components/chat/BaseChat.tsx CHANGED
@@ -156,10 +156,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
156
  return (
157
  <div
158
  ref={ref}
159
- className={classNames(
160
- styles.BaseChat,
161
- 'relative flex h-full w-full overflow-hidden bg-bolt-elements-background-depth-1',
162
- )}
163
  data-chat-visible={showChat}
164
  >
165
  <ClientOnly>{() => <Menu />}</ClientOnly>
 
156
  return (
157
  <div
158
  ref={ref}
159
+ className={classNames(styles.BaseChat, 'relative flex h-full w-full overflow-hidden')}
 
 
 
160
  data-chat-visible={showChat}
161
  >
162
  <ClientOnly>{() => <Menu />}</ClientOnly>
app/components/chat/Chat.client.tsx CHANGED
@@ -92,7 +92,7 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
92
  const { messages, isLoading, input, handleInputChange, setInput, stop, append } = useChat({
93
  api: '/api/chat',
94
  body: {
95
- apiKeys
96
  },
97
  onError: (error) => {
98
  logger.error('Request failed\n\n', error);
@@ -263,14 +263,14 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
263
  })}
264
  enhancePrompt={() => {
265
  enhancePrompt(
266
- input,
267
  (input) => {
268
  setInput(input);
269
  scrollTextArea();
270
  },
271
  model,
272
  provider,
273
- apiKeys
274
  );
275
  }}
276
  />
 
92
  const { messages, isLoading, input, handleInputChange, setInput, stop, append } = useChat({
93
  api: '/api/chat',
94
  body: {
95
+ apiKeys,
96
  },
97
  onError: (error) => {
98
  logger.error('Request failed\n\n', error);
 
263
  })}
264
  enhancePrompt={() => {
265
  enhancePrompt(
266
+ input,
267
  (input) => {
268
  setInput(input);
269
  scrollTextArea();
270
  },
271
  model,
272
  provider,
273
+ apiKeys,
274
  );
275
  }}
276
  />
app/components/header/Header.tsx CHANGED
@@ -10,13 +10,10 @@ export function Header() {
10
 
11
  return (
12
  <header
13
- className={classNames(
14
- 'flex items-center bg-bolt-elements-background-depth-1 p-5 border-b h-[var(--header-height)]',
15
- {
16
- 'border-transparent': !chat.started,
17
- 'border-bolt-elements-borderColor': chat.started,
18
- },
19
- )}
20
  >
21
  <div className="flex items-center gap-2 z-logo text-bolt-elements-textPrimary cursor-pointer">
22
  <div className="i-ph:sidebar-simple-duotone text-xl" />
 
10
 
11
  return (
12
  <header
13
+ className={classNames('flex items-center p-5 border-b h-[var(--header-height)]', {
14
+ 'border-transparent': !chat.started,
15
+ 'border-bolt-elements-borderColor': chat.started,
16
+ })}
 
 
 
17
  >
18
  <div className="flex items-center gap-2 z-logo text-bolt-elements-textPrimary cursor-pointer">
19
  <div className="i-ph:sidebar-simple-duotone text-xl" />
app/components/ui/BackgroundRays/index.tsx ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // PurpleRays.jsx
2
+ import React, { useEffect, useState } from 'react';
3
+ import styles from './styles.module.scss';
4
+
5
+ const BackgroundRays = () => {
6
+ const [theme, setTheme] = useState('dark');
7
+
8
+ useEffect(() => {
9
+ // Initial theme
10
+ const currentTheme = document.documentElement.getAttribute('data-theme');
11
+ setTheme(currentTheme || 'dark');
12
+
13
+ // Optional: Watch for theme changes
14
+ const observer = new MutationObserver((mutations) => {
15
+ mutations.forEach((mutation) => {
16
+ if (mutation.attributeName === 'data-theme') {
17
+ const newTheme = document.documentElement.getAttribute('data-theme');
18
+ setTheme((existingTheme) => newTheme || existingTheme);
19
+ }
20
+ });
21
+ });
22
+
23
+ observer.observe(document.documentElement, {
24
+ attributes: true,
25
+ attributeFilter: ['data-theme'],
26
+ });
27
+
28
+ return () => observer.disconnect();
29
+ }, []);
30
+ return (
31
+ <div className={`${styles.rayContainer} bg-bolt-elements-background-depth-1`}>
32
+ <div className={`${styles.lightRay} ${styles.ray1}`}></div>
33
+ <div className={`${styles.lightRay} ${styles.ray2}`}></div>
34
+ <div className={`${styles.lightRay} ${styles.ray3}`}></div>
35
+ <div className={`${styles.lightRay} ${styles.ray4}`}></div>
36
+ <div className={`${styles.lightRay} ${styles.ray5}`}></div>
37
+ <div className={`${styles.lightRay} ${styles.ray6}`}></div>
38
+ <div className={`${styles.lightRay} ${styles.ray7}`}></div>
39
+ <div className={`${styles.lightRay} ${styles.ray8}`}></div>
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export default BackgroundRays;
app/components/ui/BackgroundRays/styles.module.scss ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .rayContainer {
2
+ --gradient-opacity: 0.8;
3
+ --primary-color: rgba(147, 112, 219, var(--gradient-opacity));
4
+ --secondary-color: rgba(138, 43, 226, var(--gradient-opacity));
5
+ --accent-color: rgba(180, 170, 220, var(--gradient-opacity));
6
+
7
+ // Theme-specific colors
8
+ --ray-color-primary: color-mix(in srgb, var(--primary-color), transparent 30%);
9
+ --ray-color-secondary: color-mix(in srgb, var(--secondary-color), transparent 30%);
10
+ --ray-color-accent: color-mix(in srgb, var(--accent-color), transparent 30%);
11
+
12
+ // Theme-specific gradients
13
+ --ray-gradient-primary: radial-gradient(var(--ray-color-primary) 0%, transparent 70%);
14
+ --ray-gradient-secondary: radial-gradient(var(--ray-color-secondary) 0%, transparent 70%);
15
+ --ray-gradient-accent: radial-gradient(var(--ray-color-accent) 0%, transparent 70%);
16
+
17
+ position: fixed;
18
+ inset: 0;
19
+ overflow: hidden;
20
+ animation: fadeIn 1.5s ease-out;
21
+ pointer-events: none;
22
+ z-index: 0;
23
+ // background-color: transparent;
24
+
25
+ :global(html[data-theme='dark']) & {
26
+ mix-blend-mode: screen;
27
+ }
28
+
29
+ :global(html[data-theme='light']) & {
30
+ mix-blend-mode: multiply;
31
+ }
32
+ }
33
+
34
+ .lightRay {
35
+ position: absolute;
36
+ border-radius: 100%;
37
+
38
+ :global(html[data-theme='dark']) & {
39
+ mix-blend-mode: screen;
40
+ }
41
+
42
+ :global(html[data-theme='light']) & {
43
+ mix-blend-mode: multiply;
44
+ opacity: 0.4;
45
+ }
46
+ }
47
+
48
+ .ray1 {
49
+ width: 600px;
50
+ height: 800px;
51
+ background: var(--ray-gradient-primary);
52
+ transform: rotate(65deg);
53
+ top: -500px;
54
+ left: -100px;
55
+ filter: blur(80px);
56
+ opacity: 0.6;
57
+ animation: float1 15s infinite ease-in-out;
58
+ }
59
+
60
+ .ray2 {
61
+ width: 400px;
62
+ height: 600px;
63
+ background: var(--ray-gradient-secondary);
64
+ transform: rotate(-30deg);
65
+ top: -300px;
66
+ left: 200px;
67
+ filter: blur(60px);
68
+ opacity: 0.6;
69
+ animation: float2 18s infinite ease-in-out;
70
+ }
71
+
72
+ .ray3 {
73
+ width: 500px;
74
+ height: 400px;
75
+ background: var(--ray-gradient-accent);
76
+ top: -320px;
77
+ left: 500px;
78
+ filter: blur(65px);
79
+ opacity: 0.5;
80
+ animation: float3 20s infinite ease-in-out;
81
+ }
82
+
83
+ .ray4 {
84
+ width: 400px;
85
+ height: 450px;
86
+ background: var(--ray-gradient-secondary);
87
+ top: -350px;
88
+ left: 800px;
89
+ filter: blur(55px);
90
+ opacity: 0.55;
91
+ animation: float4 17s infinite ease-in-out;
92
+ }
93
+
94
+ .ray5 {
95
+ width: 350px;
96
+ height: 500px;
97
+ background: var(--ray-gradient-primary);
98
+ transform: rotate(-45deg);
99
+ top: -250px;
100
+ left: 1000px;
101
+ filter: blur(45px);
102
+ opacity: 0.6;
103
+ animation: float5 16s infinite ease-in-out;
104
+ }
105
+
106
+ .ray6 {
107
+ width: 300px;
108
+ height: 700px;
109
+ background: var(--ray-gradient-accent);
110
+ transform: rotate(75deg);
111
+ top: -400px;
112
+ left: 600px;
113
+ filter: blur(75px);
114
+ opacity: 0.45;
115
+ animation: float6 19s infinite ease-in-out;
116
+ }
117
+
118
+ .ray7 {
119
+ width: 450px;
120
+ height: 600px;
121
+ background: var(--ray-gradient-primary);
122
+ transform: rotate(45deg);
123
+ top: -450px;
124
+ left: 350px;
125
+ filter: blur(65px);
126
+ opacity: 0.55;
127
+ animation: float7 21s infinite ease-in-out;
128
+ }
129
+
130
+ .ray8 {
131
+ width: 380px;
132
+ height: 550px;
133
+ background: var(--ray-gradient-secondary);
134
+ transform: rotate(-60deg);
135
+ top: -380px;
136
+ left: 750px;
137
+ filter: blur(58px);
138
+ opacity: 0.6;
139
+ animation: float8 14s infinite ease-in-out;
140
+ }
141
+
142
+ @keyframes float1 {
143
+ 0%,
144
+ 100% {
145
+ transform: rotate(65deg) translate(0, 0);
146
+ }
147
+ 25% {
148
+ transform: rotate(70deg) translate(30px, 20px);
149
+ }
150
+ 50% {
151
+ transform: rotate(60deg) translate(-20px, 40px);
152
+ }
153
+ 75% {
154
+ transform: rotate(68deg) translate(-40px, 10px);
155
+ }
156
+ }
157
+
158
+ @keyframes float2 {
159
+ 0%,
160
+ 100% {
161
+ transform: rotate(-30deg) scale(1);
162
+ }
163
+ 33% {
164
+ transform: rotate(-25deg) scale(1.1);
165
+ }
166
+ 66% {
167
+ transform: rotate(-35deg) scale(0.95);
168
+ }
169
+ }
170
+
171
+ @keyframes float3 {
172
+ 0%,
173
+ 100% {
174
+ transform: translate(0, 0) rotate(0deg);
175
+ }
176
+ 25% {
177
+ transform: translate(40px, 20px) rotate(5deg);
178
+ }
179
+ 75% {
180
+ transform: translate(-30px, 40px) rotate(-5deg);
181
+ }
182
+ }
183
+
184
+ @keyframes float4 {
185
+ 0%,
186
+ 100% {
187
+ transform: scale(1) rotate(0deg);
188
+ }
189
+ 50% {
190
+ transform: scale(1.15) rotate(10deg);
191
+ }
192
+ }
193
+
194
+ @keyframes float5 {
195
+ 0%,
196
+ 100% {
197
+ transform: rotate(-45deg) translate(0, 0);
198
+ }
199
+ 33% {
200
+ transform: rotate(-40deg) translate(25px, -20px);
201
+ }
202
+ 66% {
203
+ transform: rotate(-50deg) translate(-25px, 20px);
204
+ }
205
+ }
206
+
207
+ @keyframes float6 {
208
+ 0%,
209
+ 100% {
210
+ transform: rotate(75deg) scale(1);
211
+ filter: blur(75px);
212
+ }
213
+ 50% {
214
+ transform: rotate(85deg) scale(1.1);
215
+ filter: blur(65px);
216
+ }
217
+ }
218
+
219
+ @keyframes float7 {
220
+ 0%,
221
+ 100% {
222
+ transform: rotate(45deg) translate(0, 0);
223
+ opacity: 0.55;
224
+ }
225
+ 50% {
226
+ transform: rotate(40deg) translate(-30px, 30px);
227
+ opacity: 0.65;
228
+ }
229
+ }
230
+
231
+ @keyframes float8 {
232
+ 0%,
233
+ 100% {
234
+ transform: rotate(-60deg) scale(1);
235
+ }
236
+ 25% {
237
+ transform: rotate(-55deg) scale(1.05);
238
+ }
239
+ 75% {
240
+ transform: rotate(-65deg) scale(0.95);
241
+ }
242
+ }
243
+
244
+ @keyframes fadeIn {
245
+ from {
246
+ opacity: 0;
247
+ }
248
+ to {
249
+ opacity: 1;
250
+ }
251
+ }
app/routes/_index.tsx CHANGED
@@ -3,6 +3,7 @@ import { ClientOnly } from 'remix-utils/client-only';
3
  import { BaseChat } from '~/components/chat/BaseChat';
4
  import { Chat } from '~/components/chat/Chat.client';
5
  import { Header } from '~/components/header/Header';
 
6
 
7
  export const meta: MetaFunction = () => {
8
  return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }];
@@ -13,6 +14,7 @@ export const loader = () => json({});
13
  export default function Index() {
14
  return (
15
  <div className="flex flex-col h-full w-full">
 
16
  <Header />
17
  <ClientOnly fallback={<BaseChat />}>{() => <Chat />}</ClientOnly>
18
  </div>
 
3
  import { BaseChat } from '~/components/chat/BaseChat';
4
  import { Chat } from '~/components/chat/Chat.client';
5
  import { Header } from '~/components/header/Header';
6
+ import BackgroundRays from '~/components/ui/BackgroundRays';
7
 
8
  export const meta: MetaFunction = () => {
9
  return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }];
 
14
  export default function Index() {
15
  return (
16
  <div className="flex flex-col h-full w-full">
17
+ <BackgroundRays />
18
  <Header />
19
  <ClientOnly fallback={<BaseChat />}>{() => <Chat />}</ClientOnly>
20
  </div>