Tina Tarighian
commited on
Commit
·
7fecabc
1
Parent(s):
060842a
fixing mobile
Browse files- components/MainContent.js +2 -2
- components/PromptEditor.js +56 -47
- hooks/useDeviceAndCanvas.js +10 -1
- pages/index.js +5 -3
components/MainContent.js
CHANGED
@@ -34,7 +34,7 @@ const MainContent = ({
|
|
34 |
createPopParticles
|
35 |
}) => {
|
36 |
return (
|
37 |
-
|
38 |
{/* Conditionally render Prompt Editor based on device */}
|
39 |
{!isMobile && (
|
40 |
<PromptEditor
|
@@ -102,7 +102,7 @@ const MainContent = ({
|
|
102 |
isMobile={isMobile}
|
103 |
/>
|
104 |
)}
|
105 |
-
|
106 |
);
|
107 |
};
|
108 |
|
|
|
34 |
createPopParticles
|
35 |
}) => {
|
36 |
return (
|
37 |
+
<div className="w-full flex flex-col items-center space-y-2">
|
38 |
{/* Conditionally render Prompt Editor based on device */}
|
39 |
{!isMobile && (
|
40 |
<PromptEditor
|
|
|
102 |
isMobile={isMobile}
|
103 |
/>
|
104 |
)}
|
105 |
+
</div>
|
106 |
);
|
107 |
};
|
108 |
|
components/PromptEditor.js
CHANGED
@@ -2,15 +2,20 @@ import { useState } from 'react';
|
|
2 |
|
3 |
const PromptEditor = ({ customPrompt, setCustomPrompt, isMac, isMobile }) => {
|
4 |
const [isEditingPrompt, setIsEditingPrompt] = useState(false);
|
|
|
5 |
const [tempPrompt, setTempPrompt] = useState("");
|
6 |
|
7 |
return (
|
8 |
-
<div className={`w-full max-w-4xl ${isMobile ? 'mt-
|
9 |
<div className="flex justify-between items-center mb-1">
|
10 |
-
<label
|
11 |
-
|
|
|
|
|
|
|
|
|
12 |
</label>
|
13 |
-
{!isEditingPrompt ? (
|
14 |
<button
|
15 |
onClick={() => {
|
16 |
setTempPrompt(customPrompt);
|
@@ -26,49 +31,53 @@ const PromptEditor = ({ customPrompt, setCustomPrompt, isMac, isMobile }) => {
|
|
26 |
) : null}
|
27 |
</div>
|
28 |
|
29 |
-
{
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
72 |
)}
|
73 |
</div>
|
74 |
);
|
|
|
2 |
|
3 |
const PromptEditor = ({ customPrompt, setCustomPrompt, isMac, isMobile }) => {
|
4 |
const [isEditingPrompt, setIsEditingPrompt] = useState(false);
|
5 |
+
const [isCollapsed, setIsCollapsed] = useState(isMobile); // Collapsed by default on mobile
|
6 |
const [tempPrompt, setTempPrompt] = useState("");
|
7 |
|
8 |
return (
|
9 |
+
<div className={`w-full max-w-4xl ${isMobile ? 'mt-2 mb-4' : 'mb-4'}`}>
|
10 |
<div className="flex justify-between items-center mb-1">
|
11 |
+
<label
|
12 |
+
htmlFor="system-prompt"
|
13 |
+
className={`block ${isMobile ? 'text-xs' : 'text-sm'} font-medium text-gray-700 cursor-pointer`}
|
14 |
+
onClick={() => isMobile && setIsCollapsed(!isCollapsed)}
|
15 |
+
>
|
16 |
+
System Prompt {isMobile && (isCollapsed ? '▼' : '▲')}
|
17 |
</label>
|
18 |
+
{!isEditingPrompt && !isCollapsed ? (
|
19 |
<button
|
20 |
onClick={() => {
|
21 |
setTempPrompt(customPrompt);
|
|
|
31 |
) : null}
|
32 |
</div>
|
33 |
|
34 |
+
{!isCollapsed && (
|
35 |
+
<>
|
36 |
+
{isEditingPrompt ? (
|
37 |
+
<div>
|
38 |
+
<textarea
|
39 |
+
id="system-prompt"
|
40 |
+
value={tempPrompt}
|
41 |
+
onChange={(e) => setTempPrompt(e.target.value)}
|
42 |
+
onKeyDown={(e) => {
|
43 |
+
// Save on Ctrl+Enter or Cmd+Enter
|
44 |
+
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
45 |
+
e.preventDefault();
|
46 |
+
setCustomPrompt(tempPrompt);
|
47 |
+
setIsEditingPrompt(false);
|
48 |
+
}
|
49 |
+
}}
|
50 |
+
className={`w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 ${isMobile ? 'text-xs' : 'text-sm'}`}
|
51 |
+
rows={isMobile ? 3 : 4}
|
52 |
+
placeholder="Enter your custom prompt for Gemini..."
|
53 |
+
/>
|
54 |
+
<div className="flex justify-end mt-2 space-x-2">
|
55 |
+
<span className={`${isMobile ? 'text-xxs' : 'text-xs'} text-gray-500 self-center mr-auto`}>
|
56 |
+
Tip: Press {isMac ? '⌘' : 'Ctrl'}+Enter to save
|
57 |
+
</span>
|
58 |
+
<button
|
59 |
+
onClick={() => setIsEditingPrompt(false)}
|
60 |
+
className={`px-3 py-1 ${isMobile ? 'text-xs' : 'text-sm'} text-gray-600 border border-gray-300 rounded-md hover:bg-gray-100`}
|
61 |
+
>
|
62 |
+
Cancel
|
63 |
+
</button>
|
64 |
+
<button
|
65 |
+
onClick={() => {
|
66 |
+
setCustomPrompt(tempPrompt);
|
67 |
+
setIsEditingPrompt(false);
|
68 |
+
}}
|
69 |
+
className={`px-3 py-1 ${isMobile ? 'text-xs' : 'text-sm'} text-white bg-blue-600 rounded-md hover:bg-blue-700`}
|
70 |
+
>
|
71 |
+
Save
|
72 |
+
</button>
|
73 |
+
</div>
|
74 |
+
</div>
|
75 |
+
) : (
|
76 |
+
<div className={`p-2 bg-gray-50 border border-gray-200 rounded-lg ${isMobile ? 'text-xs' : 'text-sm'} text-gray-800 whitespace-pre-wrap ${isMobile ? 'max-h-20' : 'max-h-32'} overflow-y-auto`}>
|
77 |
+
{customPrompt}
|
78 |
+
</div>
|
79 |
+
)}
|
80 |
+
</>
|
81 |
)}
|
82 |
</div>
|
83 |
);
|
hooks/useDeviceAndCanvas.js
CHANGED
@@ -45,7 +45,16 @@ const useDeviceAndCanvas = () => {
|
|
45 |
const containerWidth = document.querySelector('.canvas-container')?.clientWidth || window.innerWidth;
|
46 |
// Set maximum width for the canvas - increased for desktop
|
47 |
const maxWidth = Math.min(containerWidth, isMobile ? 640 : 960);
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
setCanvasWidth(maxWidth);
|
51 |
setCanvasHeight(height);
|
|
|
45 |
const containerWidth = document.querySelector('.canvas-container')?.clientWidth || window.innerWidth;
|
46 |
// Set maximum width for the canvas - increased for desktop
|
47 |
const maxWidth = Math.min(containerWidth, isMobile ? 640 : 960);
|
48 |
+
let height = maxWidth / aspectRatio;
|
49 |
+
|
50 |
+
// Limit height on mobile to ensure system prompt is visible without scrolling
|
51 |
+
if (isMobile) {
|
52 |
+
const viewportHeight = window.innerHeight;
|
53 |
+
// Use a fixed height on mobile that's appropriate for most devices
|
54 |
+
// This ensures the camera and prompt are both visible without scrolling
|
55 |
+
const maxMobileHeight = Math.min(viewportHeight * 0.5, 350); // 50% of viewport or 350px max
|
56 |
+
height = Math.min(height, maxMobileHeight);
|
57 |
+
}
|
58 |
|
59 |
setCanvasWidth(maxWidth);
|
60 |
setCanvasHeight(height);
|
pages/index.js
CHANGED
@@ -11,7 +11,7 @@ const inter = Inter({ subsets: ['latin'] });
|
|
11 |
|
12 |
const Header = () => {
|
13 |
return (
|
14 |
-
<div className="sticky top-0 left-0 right-0 w-full bg-white p-
|
15 |
<div className="w-full flex justify-between items-center text-base max-w-7xl mx-auto">
|
16 |
<div className="text-gray-500">
|
17 |
<span className="text-black font-bold text-lg mr-2">HandSpew</span>
|
@@ -47,8 +47,10 @@ export default function Home() {
|
|
47 |
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" />
|
48 |
</Head>
|
49 |
<Header />
|
50 |
-
<main className="flex min-h-screen flex-col items-center justify-start p-
|
51 |
-
<
|
|
|
|
|
52 |
</main>
|
53 |
</>
|
54 |
);
|
|
|
11 |
|
12 |
const Header = () => {
|
13 |
return (
|
14 |
+
<div className="sticky top-0 left-0 right-0 w-full bg-white p-3 z-50 shadow-sm">
|
15 |
<div className="w-full flex justify-between items-center text-base max-w-7xl mx-auto">
|
16 |
<div className="text-gray-500">
|
17 |
<span className="text-black font-bold text-lg mr-2">HandSpew</span>
|
|
|
47 |
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" />
|
48 |
</Head>
|
49 |
<Header />
|
50 |
+
<main className="flex min-h-screen flex-col items-center justify-start p-3 bg-white font-['Google_Sans',sans-serif] pt-16">
|
51 |
+
<div className="w-full max-w-4xl flex flex-col items-center">
|
52 |
+
<HandDetector />
|
53 |
+
</div>
|
54 |
</main>
|
55 |
</>
|
56 |
);
|