Ezmary commited on
Commit
288545c
·
verified ·
1 Parent(s): 6ee0e44

Update src/App.tsx

Browse files
Files changed (1) hide show
  1. src/App.tsx +35 -24
src/App.tsx CHANGED
@@ -1,4 +1,16 @@
1
- // ... (ایمپورت‌ها، myCustomInstruction, initialAppConfig, SvgHumanIcon, SvgReferenceMicrophoneIcon، AppInternalLogic بدون تغییر) ...
 
 
 
 
 
 
 
 
 
 
 
 
2
  import React, { useEffect, useRef, useState } from "react";
3
  import './App.scss';
4
  import { LiveAPIProvider, useLiveAPIContext } from "./contexts/LiveAPIContext";
@@ -106,7 +118,21 @@ const SvgReferenceMicrophoneIcon = () => (
106
  </svg>
107
  );
108
 
109
- const AppInternalLogic: React.FC<{ /* ...props... */ }> = ({ /* ...props... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  isMicActive, isCamActive, setIsMicActive, setIsCamActive, createLogoFunction,
111
  videoRef, notificationPopoverRef, notificationButtonRef, isNotificationOpen, setIsNotificationOpen
112
  }) => {
@@ -116,7 +142,6 @@ const AppInternalLogic: React.FC<{ /* ...props... */ }> = ({ /* ...props... */
116
  return (
117
  <div className="w-full flex flex-col items-center justify-center min-h-screen text-foreground antialiased">
118
  <div className="main-wrapper max-w-3xl w-full flex flex-col items-center justify-center h-full relative">
119
- {/* Header and Popover ... */}
120
  <div className="header-controls">
121
  <div id="notification-trigger-container">
122
  <button ref={notificationButtonRef} id="notification-button" aria-label="Notifications" className="header-button" onClick={(e) => { e.stopPropagation(); setIsNotificationOpen(!isNotificationOpen); }}>
@@ -134,17 +159,15 @@ const AppInternalLogic: React.FC<{ /* ...props... */ }> = ({ /* ...props... */
134
  <div className="notification-popover-text-content"> مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید. </div>
135
  </div>
136
  </div>
137
-
138
  <div className="media-area w-full flex flex-col items-center justify-center flex-grow relative">
139
  <video id="video-feed" ref={videoRef} autoPlay playsInline className={cn("absolute top-0 left-0 w-full h-full object-cover scale-x-[-1]", { "hidden": !isCamActive })} />
140
- {/* *** MODIFIED: Ensure large logo is displayed correctly *** */}
141
  {isMicActive && !isCamActive && (
142
  <div id="large-logo-container" className="large-logo-container-style">
143
  {createLogoFunction(false, true, 'human', false)}
144
  </div>
145
  )}
146
  </div>
147
- <ControlTray /* ...props... */
148
  videoRef={videoRef} supportsVideo={true} onVideoStreamChange={() => {}}
149
  isAppMicActive={isMicActive} onAppMicToggle={setIsMicActive}
150
  isAppCamActive={isCamActive} onAppCamToggle={setIsCamActive}
@@ -156,13 +179,13 @@ const AppInternalLogic: React.FC<{ /* ...props... */ }> = ({ /* ...props... */
156
  );
157
  };
158
 
159
- const logoColorConfig = { /* ... (بدون تغییر) ... */
160
  blue: { ping: "bg-blue-200 dark:bg-blue-700", outer: "bg-blue-200 dark:bg-blue-700", mid: "bg-blue-300 dark:bg-blue-600", inner: "bg-blue-400 dark:bg-blue-500", },
161
  green: { ping: "bg-green-200 dark:bg-green-700", outer: "bg-green-200 dark:bg-green-700", mid: "bg-green-300 dark:bg-green-600", inner: "bg-green-400 dark:bg-green-500", },
162
  gray: { ping: "bg-gray-200 dark:bg-gray-700", outer: "bg-gray-200 dark:bg-gray-700", mid: "bg-gray-300 dark:bg-gray-600", inner: "bg-gray-400 dark:bg-gray-500", }
163
  };
164
 
165
- function App() { /* ... (state ها و useEffect ها بدون تغییر) ... */
166
  const videoRef = useRef<HTMLVideoElement>(null);
167
  const [showIOSModal, setShowIOSModal] = useState(false);
168
  const [isAllowedOrigin, setIsAllowedOrigin] = useState<boolean | null>(null);
@@ -175,35 +198,23 @@ function App() { /* ... (state ها و useEffect ها بدون تغییر) ... *
175
  useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (isNotificationOpen && notificationPopoverRef.current && !notificationPopoverRef.current.contains(event.target as Node) && notificationButtonRef.current && !notificationButtonRef.current.contains(event.target as Node)) { setIsNotificationOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [isNotificationOpen]);
176
  if (isAllowedOrigin === null) { return <div style={{ padding: '20px', textAlign: 'center' }}>در حال بررسی دسترسی...</div>; }
177
 
178
- // *** MODIFIED createLogoFunction for complete animation ***
179
  const createLogoFunction = (isMini: boolean, isActive: boolean, type: 'human' | 'ai' = 'human', forFooter: boolean = false) => {
180
  if (!isActive) return null;
181
-
182
  const colorKey = type === 'human' ? 'blue' : (type === 'ai' ? 'green' : 'gray');
183
  const currentColors = logoColorConfig[colorKey as keyof typeof logoColorConfig] || logoColorConfig.gray;
184
-
185
  const size = isMini ? 80 : 200;
186
  const iconDisplaySize = isMini ? 35 : 70;
187
  const iconInset = (size - iconDisplaySize) / 2;
188
-
189
- // مقادیر inset برای حلقه‌ها از HTML مرجع شما (مهم)
190
- // این مقادیر باید فاصله حلقه‌ها از لبه کانتینر اصلی لوگو باشند
191
- const insetsForRings = isMini
192
- ? { ping: 10, outer: 0, mid: 5, inner: 12 } // مقادیر HTML برای لوگوی کوچک
193
- : { ping: 40, outer: 0, mid: 20, inner: 50 }; // مقادیر HTML برای لوگوی بزرگ
194
-
195
  const IconComponent = type === 'human' ? SvgHumanIcon : null;
196
-
197
  return (
198
- // کلاس logo-animation-wrapper در App.scss استایل‌های position:relative و flex را دارد
199
  <div className={cn("logo-animation-wrapper", {"for-footer": forFooter})} style={{ width: `${size}px`, height: `${size}px` }}>
200
- {/* حلقه‌های انیمیشن با inset های صحیح */}
201
  <div className={`absolute rounded-full opacity-50 animate-ping ${currentColors.ping}`} style={{ inset: `${insetsForRings.ping}px` }}></div>
202
  <div className={`absolute rounded-full opacity-50 ${currentColors.outer}`} style={{ inset: `${insetsForRings.outer}px` }}></div>
203
  <div className={`absolute rounded-full opacity-50 ${currentColors.mid}`} style={{ inset: `${insetsForRings.mid}px` }}></div>
204
  <div className={`absolute rounded-full opacity-50 ${currentColors.inner}`} style={{ inset: `${insetsForRings.inner}px` }}></div>
205
-
206
- {/* کانتینر آیکون */}
207
  <div className="z-10 absolute flex items-center justify-center" style={{ inset: `${iconInset}px`, width: `${iconDisplaySize}px`, height: `${iconDisplaySize}px` }}>
208
  {IconComponent && <IconComponent />}
209
  </div>
@@ -213,7 +224,7 @@ function App() { /* ... (state ها و useEffect ها بدون تغییر) ... *
213
 
214
  return (
215
  <LiveAPIProvider initialConfig={initialAppConfig}>
216
- <AppInternalLogic /* ...props... */
217
  isMicActive={isMicActive} setIsMicActive={setIsMicActive}
218
  isCamActive={isCamActive} setIsCamActive={setIsCamActive}
219
  createLogoFunction={createLogoFunction}
 
1
+ /**
2
+ Copyright 2024 Google LLC
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+
14
  import React, { useEffect, useRef, useState } from "react";
15
  import './App.scss';
16
  import { LiveAPIProvider, useLiveAPIContext } from "./contexts/LiveAPIContext";
 
118
  </svg>
119
  );
120
 
121
+ // *** MODIFIED: تعریف دقیق پراپ‌ها برای AppInternalLogic ***
122
+ interface AppInternalLogicProps {
123
+ isMicActive: boolean;
124
+ isCamActive: boolean;
125
+ setIsMicActive: React.Dispatch<React.SetStateAction<boolean>>;
126
+ setIsCamActive: React.Dispatch<React.SetStateAction<boolean>>;
127
+ createLogoFunction: (isMini: boolean, isActive: boolean, type?: 'human' | 'ai', forFooter?: boolean) => React.ReactNode;
128
+ videoRef: React.RefObject<HTMLVideoElement>;
129
+ notificationPopoverRef: React.RefObject<HTMLDivElement>;
130
+ notificationButtonRef: React.RefObject<HTMLButtonElement>;
131
+ isNotificationOpen: boolean;
132
+ setIsNotificationOpen: React.Dispatch<React.SetStateAction<boolean>>;
133
+ }
134
+
135
+ const AppInternalLogic: React.FC<AppInternalLogicProps> = ({
136
  isMicActive, isCamActive, setIsMicActive, setIsCamActive, createLogoFunction,
137
  videoRef, notificationPopoverRef, notificationButtonRef, isNotificationOpen, setIsNotificationOpen
138
  }) => {
 
142
  return (
143
  <div className="w-full flex flex-col items-center justify-center min-h-screen text-foreground antialiased">
144
  <div className="main-wrapper max-w-3xl w-full flex flex-col items-center justify-center h-full relative">
 
145
  <div className="header-controls">
146
  <div id="notification-trigger-container">
147
  <button ref={notificationButtonRef} id="notification-button" aria-label="Notifications" className="header-button" onClick={(e) => { e.stopPropagation(); setIsNotificationOpen(!isNotificationOpen); }}>
 
159
  <div className="notification-popover-text-content"> مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید. </div>
160
  </div>
161
  </div>
 
162
  <div className="media-area w-full flex flex-col items-center justify-center flex-grow relative">
163
  <video id="video-feed" ref={videoRef} autoPlay playsInline className={cn("absolute top-0 left-0 w-full h-full object-cover scale-x-[-1]", { "hidden": !isCamActive })} />
 
164
  {isMicActive && !isCamActive && (
165
  <div id="large-logo-container" className="large-logo-container-style">
166
  {createLogoFunction(false, true, 'human', false)}
167
  </div>
168
  )}
169
  </div>
170
+ <ControlTray
171
  videoRef={videoRef} supportsVideo={true} onVideoStreamChange={() => {}}
172
  isAppMicActive={isMicActive} onAppMicToggle={setIsMicActive}
173
  isAppCamActive={isCamActive} onAppCamToggle={setIsCamActive}
 
179
  );
180
  };
181
 
182
+ const logoColorConfig = {
183
  blue: { ping: "bg-blue-200 dark:bg-blue-700", outer: "bg-blue-200 dark:bg-blue-700", mid: "bg-blue-300 dark:bg-blue-600", inner: "bg-blue-400 dark:bg-blue-500", },
184
  green: { ping: "bg-green-200 dark:bg-green-700", outer: "bg-green-200 dark:bg-green-700", mid: "bg-green-300 dark:bg-green-600", inner: "bg-green-400 dark:bg-green-500", },
185
  gray: { ping: "bg-gray-200 dark:bg-gray-700", outer: "bg-gray-200 dark:bg-gray-700", mid: "bg-gray-300 dark:bg-gray-600", inner: "bg-gray-400 dark:bg-gray-500", }
186
  };
187
 
188
+ function App() {
189
  const videoRef = useRef<HTMLVideoElement>(null);
190
  const [showIOSModal, setShowIOSModal] = useState(false);
191
  const [isAllowedOrigin, setIsAllowedOrigin] = useState<boolean | null>(null);
 
198
  useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (isNotificationOpen && notificationPopoverRef.current && !notificationPopoverRef.current.contains(event.target as Node) && notificationButtonRef.current && !notificationButtonRef.current.contains(event.target as Node)) { setIsNotificationOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [isNotificationOpen]);
199
  if (isAllowedOrigin === null) { return <div style={{ padding: '20px', textAlign: 'center' }}>در حال بررسی دسترسی...</div>; }
200
 
 
201
  const createLogoFunction = (isMini: boolean, isActive: boolean, type: 'human' | 'ai' = 'human', forFooter: boolean = false) => {
202
  if (!isActive) return null;
 
203
  const colorKey = type === 'human' ? 'blue' : (type === 'ai' ? 'green' : 'gray');
204
  const currentColors = logoColorConfig[colorKey as keyof typeof logoColorConfig] || logoColorConfig.gray;
 
205
  const size = isMini ? 80 : 200;
206
  const iconDisplaySize = isMini ? 35 : 70;
207
  const iconInset = (size - iconDisplaySize) / 2;
208
+ const insetsForRings = isMini
209
+ ? { ping: 10, outer: 0, mid: 5, inner: 12 }
210
+ : { ping: 40, outer: 0, mid: 20, inner: 50 };
 
 
 
 
211
  const IconComponent = type === 'human' ? SvgHumanIcon : null;
 
212
  return (
 
213
  <div className={cn("logo-animation-wrapper", {"for-footer": forFooter})} style={{ width: `${size}px`, height: `${size}px` }}>
 
214
  <div className={`absolute rounded-full opacity-50 animate-ping ${currentColors.ping}`} style={{ inset: `${insetsForRings.ping}px` }}></div>
215
  <div className={`absolute rounded-full opacity-50 ${currentColors.outer}`} style={{ inset: `${insetsForRings.outer}px` }}></div>
216
  <div className={`absolute rounded-full opacity-50 ${currentColors.mid}`} style={{ inset: `${insetsForRings.mid}px` }}></div>
217
  <div className={`absolute rounded-full opacity-50 ${currentColors.inner}`} style={{ inset: `${insetsForRings.inner}px` }}></div>
 
 
218
  <div className="z-10 absolute flex items-center justify-center" style={{ inset: `${iconInset}px`, width: `${iconDisplaySize}px`, height: `${iconDisplaySize}px` }}>
219
  {IconComponent && <IconComponent />}
220
  </div>
 
224
 
225
  return (
226
  <LiveAPIProvider initialConfig={initialAppConfig}>
227
+ <AppInternalLogic
228
  isMicActive={isMicActive} setIsMicActive={setIsMicActive}
229
  isCamActive={isCamActive} setIsCamActive={setIsCamActive}
230
  createLogoFunction={createLogoFunction}