more ui tweaks

This commit is contained in:
tobiadefami
2024-12-28 06:42:11 +01:00
parent a73e4cae0e
commit 776c5d43c3
4 changed files with 146 additions and 62 deletions

View File

@@ -1,5 +1,5 @@
"use client";
import { X, Minus, Maximize2, MessageCircle } from "lucide-react";
import dynamic from "next/dynamic";
import ChatBox from "@/components/ChatBox";
import { useState, useEffect } from "react";
@@ -7,8 +7,7 @@ import {
SpreadsheetProvider,
useSpreadsheet,
} from "@/context/SpreadsheetContext";
import { MessageCircle } from "lucide-react";
import { CellUpdate, ChatMessage } from "@/types/api";
const Spreadsheet = dynamic(() => import("@/components/Spreadsheet"), {
ssr: false,
loading: () => (
@@ -18,13 +17,6 @@ const Spreadsheet = dynamic(() => import("@/components/Spreadsheet"), {
),
});
interface ChatMessage {
id: string;
text: string;
response: string;
timestamp: Date;
}
const SpreadsheetApp = () => {
const [spreadsheetData, setSpreadsheetData] = useState<any[][]>([]);
const { setFormulas } = useSpreadsheet();
@@ -103,10 +95,6 @@ const SpreadsheetApp = () => {
}, []);
const handleSend = async (message: string) => {
console.log("Environment check:", {
isElectron,
hasElectronAPI: electronAPIAvailable,
});
try {
let updates;
@@ -133,25 +121,22 @@ const SpreadsheetApp = () => {
updates = await response.json();
}
console.log("Received updates:", updates);
const formattedResponse = Array.isArray(updates)
? updates
.map((update) => `${update.target}: ${update.formula}`)
.join("\n")
: "No updates available";
if (Array.isArray(updates)) {
setFormulas(updates);
const formattedResponse = updates
.map((update) => `${update.target}: ${update.formula}`)
.join("\n");
const newMessage: ChatMessage = {
id: Date.now().toString(),
text: message,
response: formattedResponse,
timestamp: new Date(),
};
setChatHistory((prev) => [...prev, newMessage]);
}
const newMessage: ChatMessage = {
id: Date.now().toString(),
text: message,
response: formattedResponse,
timestamp: new Date(),
status: "pending",
updates: updates,
};
setChatHistory((prev) => [...prev, newMessage]);
return updates;
} catch (error) {
console.error("Error in handleSend:", error);
@@ -168,6 +153,21 @@ const SpreadsheetApp = () => {
}
};
const handleAccept = (updates: CellUpdate[], messageId: string) => {
setFormulas(updates);
setChatHistory((prev) =>
prev.map((msg) =>
msg.id === messageId ? { ...msg, status: "accepted" } : msg,
),
);
};
const handleReject = (messageId: string) => {
setChatHistory((prev) =>
prev.map((msg) =>
msg.id === messageId ? { ...msg, status: "rejected" } : msg,
),
);
};
const handleClearHistory = () => {
setChatHistory([]);
localStorage.removeItem("chatHistory");
@@ -178,18 +178,33 @@ const SpreadsheetApp = () => {
};
return (
<main className="h-screen w-screen bg-gray-50 overflow-hidden">
<div className="h-full p-4 flex flex-col">
<h1 className="text-2xl font-bold mb-4 text-gray-800">
<main className="h-screen w-screen flex flex-col bg-gray-50">
{/* Header Bar */}
<div className="h-10 border-b border-gray-200 bg-white flex items-center justify-between px-4">
<div className="text-sm font-medium text-gray-600">
Magic Spreadsheet
</h1>
<div className="flex gap-4 flex-1 relative">
</div>
<div className="flex items-center gap-2">
<button className="p-1.5 hover:bg-gray-100 rounded">
<Minus size={16} />
</button>
<button className="p-1.5 hover:bg-gray-100 rounded">
<Maximize2 size={16} />
</button>
<button className="p-1.5 hover:bg-gray-100 rounded text-red-500">
<X size={16} />
</button>
</div>
</div>
{/* Main Content */}
<div className="flex-1 p-4 overflow-hidden">
<div className="flex gap-4 h-full relative">
<div className="flex-1 bg-white rounded-lg shadow-sm">
<Spreadsheet onDataChange={handleDataChange} />
</div>
{/* Updated ChatBox container */}
<div
className={`fixed right-4 top-[5.5rem] bottom-4 w-96 transition-transform duration-300 transform ${
className={`fixed right-4 top-[5.5rem] bottom-16 w-96 transition-transform duration-300 transform ${
isChatOpen ? "translate-x-0" : "translate-x-full"
}`}
style={{
@@ -202,17 +217,26 @@ const SpreadsheetApp = () => {
onSend={handleSend}
chatHistory={chatHistory}
clearHistory={handleClearHistory}
onAccept={handleAccept}
onReject={handleReject}
/>
</div>
</div>
</div>
<button
onClick={() => setIsChatOpen((prev) => !prev)}
className="fixed bottom-4 right-4 p-3 rounded-full shadow-lg bg-blue-500 hover:bg-blue-600 text-white transition-colors z-50"
title="Toggle Chat (Ctrl+Shift+/)"
>
<MessageCircle size={24} />
</button>
{/* Footer Bar */}
<div className="h-12 border-t border-gray-200 bg-white flex items-center justify-between px-4">
<div className="flex items-center gap-2">
{/* Add other footer tools here */}
</div>
<button
onClick={() => setIsChatOpen((prev) => !prev)}
className="p-2 rounded hover:bg-gray-100 transition-colors"
title="Toggle Chat (Ctrl+Shift+/)"
>
<MessageCircle size={20} />
</button>
</div>
</main>
);
};

View File

@@ -1,21 +1,22 @@
import { useState } from "react";
import { CellUpdate } from "@/types/api";
import { Send, Trash2, Loader2 } from "lucide-react";
interface ChatMessage {
id: string;
text: string;
response: string;
timestamp: Date;
}
import { CellUpdate, ChatMessage } from "@/types/api";
import { Check, X, Send, Trash2, Loader2 } from "lucide-react";
interface ChatBoxProps {
onSend: (message: string) => Promise<CellUpdate[]>;
onAccept: (updates: CellUpdate[], messageId: string) => void;
onReject: (messageId: string) => void;
chatHistory: ChatMessage[];
clearHistory: () => void;
}
const ChatBox = ({ onSend, chatHistory, clearHistory }: ChatBoxProps) => {
const ChatBox = ({
onSend,
onAccept,
onReject,
chatHistory,
clearHistory,
}: ChatBoxProps) => {
const [message, setMessage] = useState("");
const [isLoading, setIsLoading] = useState(false);
@@ -23,7 +24,7 @@ const ChatBox = ({ onSend, chatHistory, clearHistory }: ChatBoxProps) => {
if (message.trim()) {
setIsLoading(true);
try {
await onSend(message);
const updates = await onSend(message);
} catch (error) {
console.error("Error details:", error);
} finally {
@@ -85,6 +86,39 @@ const ChatBox = ({ onSend, chatHistory, clearHistory }: ChatBoxProps) => {
<pre className="text-sm text-gray-800 whitespace-pre-wrap font-mono">
{chat.response}
</pre>
{/* Accept/Reject Buttons */}
{chat.status === "pending" && chat.updates && (
<div className="mt-2 flex gap-2">
<button
onClick={() => onAccept(chat.updates!, chat.id)}
className="px-3 py-1 bg-green-500 text-white rounded-full text-sm flex items-center gap-1 hover:bg-green-600 transition-colors"
>
<Check size={14} />
Apply
</button>
<button
onClick={() => onReject(chat.id)}
className="px-3 py-1 bg-red-500 text-white rounded-full text-sm flex items-center gap-1 hover:bg-red-600 transition-colors"
>
<X size={14} />
Reject
</button>
</div>
)}
{/* Status Indicator */}
{chat.status === "accepted" && (
<div className="mt-2 text-green-500 text-xs flex items-center gap-1">
<Check size={14} />
Applied
</div>
)}
{chat.status === "rejected" && (
<div className="mt-2 text-red-500 text-xs flex items-center gap-1">
<X size={14} />
Rejected
</div>
)}
</div>
</div>
</div>

View File

@@ -7,6 +7,7 @@ import SpreadsheetToolbar from "./SpreadsheetToolbar";
import SearchBox from "./SearchBox";
import { getInitialConfig } from "@/lib/spreadsheet/config";
import { excelCellToRowCol, readFileData } from "@/lib/spreadsheet/utils";
import { importSpreadsheet } from "@/lib/spreadsheet/import";
import {
textFormattingHandlers,
editHandlers,
@@ -42,20 +43,36 @@ const Spreadsheet = ({ onDataChange, initialData }: SpreadsheetProps) => {
const handleImport = async (file: File) => {
try {
const data = await readFileData(file);
if (hotInstanceRef.current && data) {
setCurrentData(data);
hotInstanceRef.current.updateSettings({ data }, false);
const { data, styles, mergedCells } = await importSpreadsheet(file);
if (hotInstanceRef.current) {
hotInstanceRef.current.updateSettings(
{
data,
cells: function (row, col) {
return {
className: [
styles.bold[row]?.[col] ? "htBold" : "",
`ht${styles.alignment[row]?.[col]?.charAt(0).toUpperCase()}${styles.alignment[row]?.[col]?.slice(1)}`, // htLeft, htCenter, htRight
]
.filter(Boolean)
.join(" "),
};
},
mergeCells: mergedCells,
},
false,
);
if (onDataChange) {
onDataChange(data);
}
}
} catch (error) {
console.error("Error importing file:", error);
console.error("Error importing spreadsheet:", error);
alert("Error importing file. Please try again.");
}
};
const handleExport = () => {
try {
if (hotInstanceRef.current) {

View File

@@ -1,3 +1,12 @@
export interface ChatMessage {
id: string;
text: string;
response: string;
timestamp: Date;
status: "pending" | "accepted" | "rejected" | null;
updates?: CellUpdate[];
}
export interface CellUpdate {
formula: string;
target: string;