fix: address lint issues and type errors

This commit is contained in:
vgcman16 2025-06-05 19:07:41 -05:00
parent 4350bf66c3
commit f23482db2f
9 changed files with 52 additions and 31 deletions

View File

@ -288,8 +288,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
const handleFileUpload = () => {
const input = document.createElement('input');
input.type = 'file';
input.accept =
'image/*,.pdf,.docx,.txt,.md,.js,.ts,.tsx,.html,.css,.json';
input.accept = 'image/*,.pdf,.docx,.txt,.md,.js,.ts,.tsx,.html,.css,.json';
input.onchange = async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
@ -297,6 +296,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
if (file) {
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (ev) => {
const base64Image = ev.target?.result as string;
setUploadedFiles?.([...uploadedFiles, file]);
@ -326,11 +326,16 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
for (const item of items) {
if (item.kind === 'file') {
const file = item.getAsFile();
if (!file) continue;
if (!file) {
continue;
}
e.preventDefault();
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (ev) => {
const base64Image = ev.target?.result as string;
setUploadedFiles?.([...uploadedFiles, file]);

View File

@ -449,6 +449,7 @@ function FileContextMenu({
}
const success = workbenchStore.targetFile(fullPath);
if (success) {
toast.success(`File targeted`);
}
@ -465,6 +466,7 @@ function FileContextMenu({
}
const success = workbenchStore.unTargetFile(fullPath);
if (success) {
toast.success(`File un-targeted`);
}
@ -761,9 +763,7 @@ function File({
title={'File is locked'}
/>
)}
{isTargeted && (
<span className="shrink-0 i-ph:crosshair text-green-500 scale-80" title="Targeted file" />
)}
{isTargeted && <span className="shrink-0 i-ph:crosshair text-green-500 scale-80" title="Targeted file" />}
{unsavedChanges && <span className="i-ph:circle-fill scale-68 shrink-0 text-orange-500" />}
</div>
</div>

View File

@ -47,6 +47,7 @@ export function usePromptEnhancer() {
const decoder = new TextDecoder();
_input = '';
let _error;
try {

View File

@ -12,6 +12,7 @@ function getChatSet(chatId: string, create = false): Set<string> | undefined {
if (create && !targetedFilesMap.has(chatId)) {
targetedFilesMap.set(chatId, new Set());
}
return targetedFilesMap.get(chatId);
}
@ -19,17 +20,22 @@ function initializeCache(): TargetedFile[] {
if (targetedFilesCache !== null) {
return targetedFilesCache;
}
try {
if (typeof localStorage !== 'undefined') {
const json = localStorage.getItem(TARGETED_FILES_KEY);
if (json) {
const items = JSON.parse(json) as TargetedFile[];
targetedFilesCache = items;
rebuildLookup(items);
return items;
}
}
targetedFilesCache = [];
return [];
} catch {
targetedFilesCache = [];
@ -39,12 +45,15 @@ function initializeCache(): TargetedFile[] {
function rebuildLookup(items: TargetedFile[]): void {
targetedFilesMap.clear();
for (const item of items) {
let set = targetedFilesMap.get(item.chatId);
if (!set) {
set = new Set();
targetedFilesMap.set(item.chatId, set);
}
set.add(item.path);
}
}
@ -52,6 +61,7 @@ function rebuildLookup(items: TargetedFile[]): void {
export function saveTargetedFiles(items: TargetedFile[]): void {
targetedFilesCache = [...items];
rebuildLookup(items);
try {
if (typeof localStorage !== 'undefined') {
localStorage.setItem(TARGETED_FILES_KEY, JSON.stringify(items));
@ -67,6 +77,7 @@ export function addTargetedFile(chatId: string, path: string): void {
const files = getTargetedFiles();
const set = getChatSet(chatId, true)!;
set.add(path);
const filtered = files.filter((f) => !(f.chatId === chatId && f.path === path));
filtered.push({ chatId, path });
saveTargetedFiles(filtered);
@ -75,20 +86,28 @@ export function addTargetedFile(chatId: string, path: string): void {
export function removeTargetedFile(chatId: string, path: string): void {
const files = getTargetedFiles();
const set = getChatSet(chatId);
if (set) set.delete(path);
if (set) {
set.delete(path);
}
const filtered = files.filter((f) => !(f.chatId === chatId && f.path === path));
saveTargetedFiles(filtered);
}
export function isFileTargeted(chatId: string, path: string): boolean {
initializeCache();
const set = getChatSet(chatId);
return set ? set.has(path) : false;
}
export function getTargetedFilesForChat(chatId: string): string[] {
initializeCache();
const set = getChatSet(chatId);
return set ? Array.from(set) : [];
}

View File

@ -20,11 +20,7 @@ import {
migrateLegacyLocks,
clearCache,
} from '~/lib/persistence/lockedFiles';
import {
getTargetedFilesForChat,
addTargetedFile,
removeTargetedFile,
} from '~/lib/persistence/targetedFiles';
import { getTargetedFilesForChat, addTargetedFile, removeTargetedFile } from '~/lib/persistence/targetedFiles';
import { getCurrentChatId } from '~/utils/fileLocks';
const logger = createScopedLogger('FilesStore');
@ -101,6 +97,7 @@ export class FilesStore {
// Load locked files from localStorage
this.#loadLockedFiles();
// Load targeted files from localStorage
this.#loadTargetedFiles();
@ -377,6 +374,7 @@ export class FilesStore {
this.files.setKey(filePath, { ...file, isTargeted: true });
addTargetedFile(currentChatId, filePath);
return true;
}
@ -394,6 +392,7 @@ export class FilesStore {
this.files.setKey(filePath, { ...file, isTargeted: false });
removeTargetedFile(currentChatId, filePath);
return true;
}

View File

@ -7,10 +7,7 @@ import { Header } from '~/components/header/Header';
import BackgroundRays from '~/components/ui/BackgroundRays';
export const meta: MetaFunction = () => {
return [
{ title: 'Bolt' },
{ name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' },
];
return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }];
};
export async function loader(args: LoaderFunctionArgs) {

View File

@ -8,9 +8,11 @@ import { escapeBoltTags } from './projectCommands';
*/
function extractFileKey(url: string): string {
const match = url.match(/file\/(\w+)/);
if (!match) {
throw new Error('Invalid Figma URL');
}
return match[1];
}
@ -26,8 +28,9 @@ function collectFrames(node: any, frames: any[]) {
if (node.type === 'FRAME') {
frames.push(node);
}
if (Array.isArray(node.children)) {
node.children.forEach((child) => collectFrames(child, frames));
node.children.forEach((child: any) => collectFrames(child, frames));
}
}
@ -35,6 +38,7 @@ function figmaFramesToComponents(frames: any[]): GeneratedComponent[] {
return frames.map((frame) => {
const name = frame.name.replace(/[^a-zA-Z0-9]/g, '') || 'Component';
const code = `export function ${name}() {\n return <div>${frame.name}</div>;\n}`;
return { name, code };
});
}
@ -42,10 +46,7 @@ function figmaFramesToComponents(frames: any[]): GeneratedComponent[] {
/**
* Create chat messages from a Figma design
*/
export async function createChatFromFigma(
figmaUrl: string,
token: string,
): Promise<Message[]> {
export async function createChatFromFigma(figmaUrl: string, token: string): Promise<Message[]> {
const fileKey = extractFileKey(figmaUrl);
const res = await fetch(`https://api.figma.com/v1/files/${fileKey}`, {
headers: { 'X-Figma-Token': token },
@ -55,14 +56,14 @@ export async function createChatFromFigma(
throw new Error(`Failed to fetch Figma file: ${res.status}`);
}
const data = await res.json();
const data = (await res.json()) as { document: unknown };
const frames: any[] = [];
collectFrames(data.document, frames);
collectFrames((data as any).document, frames);
const components = figmaFramesToComponents(frames);
const componentActions = components
.map(
(c) =>
`<boltAction type="file" filePath="app/components/${c.name}.tsx">${escapeBoltTags(c.code)}</boltAction>`,
(c) => `<boltAction type="file" filePath="app/components/${c.name}.tsx">${escapeBoltTags(c.code)}</boltAction>`,
)
.join('\n');

View File

@ -9,21 +9,23 @@ export async function extractTextFromFile(file: File): Promise<string> {
const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const texts: string[] = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
texts.push(content.items.map((item: any) => item.str).join(' '));
}
return texts.join('\n');
}
if (
file.type ===
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
file.name.toLowerCase().endsWith('.docx')
) {
const arrayBuffer = await file.arrayBuffer();
const result = await mammoth.extractRawText({ arrayBuffer });
return result.value;
}

View File

@ -120,10 +120,7 @@ ${files[filePath].content}
`;
};
export const uploadedFilesToArtifacts = (
files: { [path: string]: string },
id: string,
): string => {
export const uploadedFilesToArtifacts = (files: { [path: string]: string }, id: string): string => {
return `
<boltArtifact id="${id}" title="Uploaded Files">
${Object.keys(files)