Spaces:
Running
Running
Commit ·
789d216
1
Parent(s): 8ae844b
design(ai): enhance speed dial labels clarity and implement responsive positioning clamping
Browse files
webapp/tipitaka-web/src/components/ai/AIFloatingMenu.tsx
CHANGED
|
@@ -133,7 +133,7 @@ const AIFloatingMenu: React.FC = () => {
|
|
| 133 |
onClick={() => handleAction(act.prompt, act.isPrompt)}
|
| 134 |
>
|
| 135 |
{/* Label Pill */}
|
| 136 |
-
<span className={`mr-3 px-
|
| 137 |
{act.label}
|
| 138 |
</span>
|
| 139 |
|
|
|
|
| 133 |
onClick={() => handleAction(act.prompt, act.isPrompt)}
|
| 134 |
>
|
| 135 |
{/* Label Pill */}
|
| 136 |
+
<span className={`mr-3 px-4 py-1.5 rounded-xl text-sm md:text-[15px] font-extrabold border shadow-md whitespace-nowrap transition-all duration-200 group-hover:scale-105 group-hover:border-[#0d9488] group-hover:text-[#0d9488] dark:group-hover:text-[#14b8a6] dark:group-hover:border-[#14b8a6] ${s.labelBg}`}>
|
| 137 |
{act.label}
|
| 138 |
</span>
|
| 139 |
|
webapp/tipitaka-web/src/components/ai/AIPopup.tsx
CHANGED
|
@@ -52,27 +52,54 @@ const AIPopup: React.FC = () => {
|
|
| 52 |
|
| 53 |
// Restore saved position + width/height on mount
|
| 54 |
useEffect(() => {
|
| 55 |
-
|
| 56 |
-
|
| 57 |
const savedW = localStorage.getItem('tipitaka-ai-panel-width');
|
| 58 |
if (savedW) {
|
| 59 |
const w = parseInt(savedW, 10);
|
| 60 |
if (w >= 300 && w <= window.innerWidth * 0.95) {
|
|
|
|
| 61 |
setWidth(w);
|
| 62 |
setPanelWidth(w);
|
| 63 |
}
|
| 64 |
}
|
| 65 |
|
|
|
|
| 66 |
const savedH = localStorage.getItem('tipitaka-ai-panel-height');
|
| 67 |
if (savedH) {
|
| 68 |
const h = parseInt(savedH, 10);
|
| 69 |
if (h >= 200 && h <= window.innerHeight * 0.9) {
|
|
|
|
| 70 |
setHeight(h);
|
| 71 |
setPanelHeight(h);
|
| 72 |
}
|
| 73 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
}, []);
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
|
| 78 |
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
|
|
| 52 |
|
| 53 |
// Restore saved position + width/height on mount
|
| 54 |
useEffect(() => {
|
| 55 |
+
let currentW = panelWidth;
|
|
|
|
| 56 |
const savedW = localStorage.getItem('tipitaka-ai-panel-width');
|
| 57 |
if (savedW) {
|
| 58 |
const w = parseInt(savedW, 10);
|
| 59 |
if (w >= 300 && w <= window.innerWidth * 0.95) {
|
| 60 |
+
currentW = w;
|
| 61 |
setWidth(w);
|
| 62 |
setPanelWidth(w);
|
| 63 |
}
|
| 64 |
}
|
| 65 |
|
| 66 |
+
let currentH = panelHeight;
|
| 67 |
const savedH = localStorage.getItem('tipitaka-ai-panel-height');
|
| 68 |
if (savedH) {
|
| 69 |
const h = parseInt(savedH, 10);
|
| 70 |
if (h >= 200 && h <= window.innerHeight * 0.9) {
|
| 71 |
+
currentH = h;
|
| 72 |
setHeight(h);
|
| 73 |
setPanelHeight(h);
|
| 74 |
}
|
| 75 |
}
|
| 76 |
+
|
| 77 |
+
if (dragPos) {
|
| 78 |
+
const clampedX = Math.max(0, Math.min(dragPos.x, window.innerWidth - currentW));
|
| 79 |
+
const clampedY = Math.max(0, Math.min(dragPos.y, window.innerHeight - currentH));
|
| 80 |
+
setPos({ x: clampedX, y: clampedY });
|
| 81 |
+
}
|
| 82 |
}, []);
|
| 83 |
|
| 84 |
+
// Clamp position when window size changes to prevent window from going off-screen
|
| 85 |
+
useEffect(() => {
|
| 86 |
+
const handleResize = () => {
|
| 87 |
+
if (window.innerWidth < 768) {
|
| 88 |
+
setPos(null);
|
| 89 |
+
return;
|
| 90 |
+
}
|
| 91 |
+
setPos(prev => {
|
| 92 |
+
const targetPos = prev || dragPos;
|
| 93 |
+
if (!targetPos) return null;
|
| 94 |
+
const clampedX = Math.max(0, Math.min(targetPos.x, window.innerWidth - width));
|
| 95 |
+
const clampedY = Math.max(0, Math.min(targetPos.y, window.innerHeight - height));
|
| 96 |
+
return { x: clampedX, y: clampedY };
|
| 97 |
+
});
|
| 98 |
+
};
|
| 99 |
+
window.addEventListener('resize', handleResize);
|
| 100 |
+
return () => window.removeEventListener('resize', handleResize);
|
| 101 |
+
}, [width, height, dragPos]);
|
| 102 |
+
|
| 103 |
|
| 104 |
|
| 105 |
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
webapp/tipitaka-web/src/stores/aiStore.ts
CHANGED
|
@@ -45,7 +45,14 @@ export const useAIStore = create<AIState>((set, get) => ({
|
|
| 45 |
ragReady: false,
|
| 46 |
ragChecking: false,
|
| 47 |
ragLoading: false,
|
| 48 |
-
dragPos:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
viewMode: 'chat',
|
| 50 |
panelWidth: 400,
|
| 51 |
panelHeight: 550,
|
|
|
|
| 45 |
ragReady: false,
|
| 46 |
ragChecking: false,
|
| 47 |
ragLoading: false,
|
| 48 |
+
dragPos: (() => {
|
| 49 |
+
try {
|
| 50 |
+
const pos = localStorage.getItem('tipitaka-ai-drag-pos');
|
| 51 |
+
return pos ? JSON.parse(pos) : null;
|
| 52 |
+
} catch {
|
| 53 |
+
return null;
|
| 54 |
+
}
|
| 55 |
+
})(),
|
| 56 |
viewMode: 'chat',
|
| 57 |
panelWidth: 400,
|
| 58 |
panelHeight: 550,
|