diff --git a/apps/browser-extension/utils/memory-popup.ts b/apps/browser-extension/utils/memory-popup.ts deleted file mode 100644 index ba2d2a1c..00000000 --- a/apps/browser-extension/utils/memory-popup.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Memory Popup Utilities - * Standardized popup positioning and styling for memory display across platforms - */ - -export interface MemoryPopupConfig { - memoriesData: string - onClose: () => void - onRemove?: () => void -} - -export function createMemoryPopup(config: MemoryPopupConfig): HTMLElement { - const popup = document.createElement("div") - popup.style.cssText = ` - position: fixed; - bottom: 80px; - left: 50%; - transform: translateX(-50%); - background: #1a1a1a; - color: white; - padding: 0; - border-radius: 12px; - font-size: 13px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; - max-width: 500px; - max-height: 400px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); - z-index: 999999; - display: none; - overflow: hidden; - ` - - const header = document.createElement("div") - header.style.cssText = ` - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; - border-bottom: 1px solid #333; - opacity: 0.8; - ` - header.innerHTML = ` - INCLUDED MEMORIES -
- ${config.onRemove ? '' : ""} - -
- ` - - const content = document.createElement("div") - content.style.cssText = ` - padding: 8px; - max-height: 300px; - overflow-y: auto; - line-height: 1.4; - ` - content.textContent = config.memoriesData - - const closeBtn = header.querySelector("#close-popup-btn") - closeBtn?.addEventListener("click", config.onClose) - - const removeBtn = header.querySelector("#remove-memories-btn") - if (removeBtn && config.onRemove) { - removeBtn.addEventListener("click", config.onRemove) - } - - popup.appendChild(header) - popup.appendChild(content) - - return popup -} - -export function showMemoryPopup(popup: HTMLElement): void { - popup.style.display = "block" - - setTimeout(() => { - if (popup.style.display === "block") { - hideMemoryPopup(popup) - } - }, 10000) -} - -export function hideMemoryPopup(popup: HTMLElement): void { - popup.style.display = "none" -} - -export function toggleMemoryPopup(popup: HTMLElement): void { - if (popup.style.display === "none" || popup.style.display === "") { - showMemoryPopup(popup) - } else { - hideMemoryPopup(popup) - } -} diff --git a/packages/lib/glass-effect-manager.ts b/packages/lib/glass-effect-manager.ts deleted file mode 100644 index 291a30aa..00000000 --- a/packages/lib/glass-effect-manager.ts +++ /dev/null @@ -1,308 +0,0 @@ -// Singleton WebGL context manager for glass effects -class GlassEffectManager { - private static instance: GlassEffectManager | null = null - private canvas: HTMLCanvasElement | null = null - private gl: WebGLRenderingContext | null = null - private program: WebGLProgram | null = null - private uniforms: Record = {} - private effects: Map = new Map() - private animationFrame: number | null = null - private startTime: number = performance.now() - private mousePositions: Map = new Map() - - static getInstance(): GlassEffectManager { - if (!GlassEffectManager.instance) { - GlassEffectManager.instance = new GlassEffectManager() - } - return GlassEffectManager.instance - } - - private constructor() { - this.initializeContext() - } - - private initializeContext() { - // Create offscreen canvas - this.canvas = document.createElement("canvas") - this.canvas.width = 1024 // Default size, will be adjusted - this.canvas.height = 1024 - - this.gl = this.canvas.getContext("webgl", { - alpha: true, - premultipliedAlpha: false, - preserveDrawingBuffer: true, - }) - - if (!this.gl) { - console.error("WebGL not supported") - return - } - - this.setupShaders() - this.startRenderLoop() - } - - private setupShaders() { - if (!this.gl) return - - const vsSource = ` - attribute vec2 position; - void main() { - gl_Position = vec4(position, 0.0, 1.0); - } - ` - - const fsSource = ` - precision mediump float; - - uniform vec2 iResolution; - uniform float iTime; - uniform vec2 iMouse; - uniform float iExpanded; - - float noise(vec2 p) { - return sin(p.x * 10.0) * sin(p.y * 10.0); - } - - void main() { - vec2 uv = gl_FragCoord.xy / iResolution.xy; - vec2 mouse = iMouse / iResolution.xy; - - float dist = length(uv - mouse); - - vec2 distortion = vec2( - sin(iTime * 2.0 + uv.y * 10.0) * 0.0025, - cos(iTime * 1.5 + uv.x * 10.0) * 0.0025 - ); - - vec2 refractedUV = uv + distortion * (1.0 - dist); - - vec3 glassColor = mix( - vec3(0.1, 0.1, 0.12), - vec3(0.16, 0.16, 0.19), - 1.0 - length(uv - vec2(0.5)) - ); - - float glow = exp(-dist * 5.0) * 0.35; - glassColor += vec3(glow); - - float edge = 1.0 - smoothstep(0.0, 0.02, min( - min(uv.x, 1.0 - uv.x), - min(uv.y, 1.0 - uv.y) - )); - glassColor += edge * 0.3; - - float edgeGlow = 1.0 - smoothstep(0.0, 0.05, min( - min(uv.x, 1.0 - uv.x), - min(uv.y, 1.0 - uv.y) - )); - glassColor += vec3(edgeGlow * 0.1, edgeGlow * 0.1, edgeGlow * 0.2); - - float n = noise(refractedUV * 50.0 + vec2(iTime)) * 0.025; - glassColor += vec3(n); - - float alpha = 0.25 + edge * 0.2 + glow * 0.2; - alpha *= mix(0.8, 1.0, iExpanded); - - gl_FragColor = vec4(glassColor, alpha); - } - ` - - const createShader = (type: number, source: string) => { - const shader = this.gl!.createShader(type) - if (!shader) return null - - this.gl!.shaderSource(shader, source) - this.gl!.compileShader(shader) - - if (!this.gl!.getShaderParameter(shader, this.gl!.COMPILE_STATUS)) { - console.error("Shader error:", this.gl!.getShaderInfoLog(shader)) - this.gl!.deleteShader(shader) - return null - } - return shader - } - - const vs = createShader(this.gl.VERTEX_SHADER, vsSource) - const fs = createShader(this.gl.FRAGMENT_SHADER, fsSource) - if (!vs || !fs) return - - this.program = this.gl.createProgram() - if (!this.program) return - - this.gl.attachShader(this.program, vs) - this.gl.attachShader(this.program, fs) - this.gl.linkProgram(this.program) - // biome-ignore lint/correctness/useHookAtTopLevel: Well, not a hook - this.gl.useProgram(this.program) - - // Buffer setup - const buffer = this.gl.createBuffer() - this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer) - this.gl.bufferData( - this.gl.ARRAY_BUFFER, - new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), - this.gl.STATIC_DRAW, - ) - - const position = this.gl.getAttribLocation(this.program, "position") - this.gl.enableVertexAttribArray(position) - this.gl.vertexAttribPointer(position, 2, this.gl.FLOAT, false, 0, 0) - - // Store uniform locations - this.uniforms = { - resolution: this.gl.getUniformLocation(this.program, "iResolution"), - time: this.gl.getUniformLocation(this.program, "iTime"), - mouse: this.gl.getUniformLocation(this.program, "iMouse"), - expanded: this.gl.getUniformLocation(this.program, "iExpanded"), - } - - // Enable blending - this.gl.enable(this.gl.BLEND) - this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA) - } - - registerEffect( - id: string, - targetCanvas: HTMLCanvasElement, - isExpanded: boolean, - ): () => void { - // Ensure minimum dimensions - const width = Math.max(1, targetCanvas.width) - const height = Math.max(1, targetCanvas.height) - - const effect: EffectInstance = { - id, - targetCanvas, - isExpanded, - width, - height, - } - - this.effects.set(id, effect) - this.mousePositions.set(id, { x: 0, y: 0 }) - - // Return cleanup function - return () => { - this.effects.delete(id) - this.mousePositions.delete(id) - if (this.effects.size === 0 && this.animationFrame) { - cancelAnimationFrame(this.animationFrame) - this.animationFrame = null - } - } - } - - updateMousePosition(id: string, x: number, y: number) { - this.mousePositions.set(id, { x, y }) - } - - updateExpanded(id: string, isExpanded: boolean) { - const effect = this.effects.get(id) - if (effect) { - effect.isExpanded = isExpanded - } - } - - updateSize(id: string, width: number, height: number) { - const effect = this.effects.get(id) - if (effect) { - // Ensure minimum dimensions - effect.width = Math.max(1, width) - effect.height = Math.max(1, height) - } - } - - private startRenderLoop() { - const render = () => { - if (!this.gl || !this.program || this.effects.size === 0) { - this.animationFrame = requestAnimationFrame(render) - return - } - - const currentTime = (performance.now() - this.startTime) / 1000 - - // Render each effect - for (const [id, effect] of Array.from(this.effects)) { - const mousePos = this.mousePositions.get(id) || { x: 0, y: 0 } - - // Skip rendering if dimensions are invalid - if (effect.width <= 0 || effect.height <= 0) { - continue - } - - // Set canvas size if needed - if ( - this.canvas!.width !== effect.width || - this.canvas!.height !== effect.height - ) { - this.canvas!.width = effect.width - this.canvas!.height = effect.height - this.gl.viewport(0, 0, effect.width, effect.height) - } - - // Clear and render - this.gl.clearColor(0, 0, 0, 0) - this.gl.clear(this.gl.COLOR_BUFFER_BIT) - - // Set uniforms - if (this.uniforms.resolution) { - this.gl.uniform2f( - this.uniforms.resolution, - effect.width, - effect.height, - ) - } - if (this.uniforms.time) { - this.gl.uniform1f(this.uniforms.time, currentTime) - } - if (this.uniforms.mouse) { - this.gl.uniform2f(this.uniforms.mouse, mousePos.x, mousePos.y) - } - if (this.uniforms.expanded) { - this.gl.uniform1f( - this.uniforms.expanded, - effect.isExpanded ? 1.0 : 0.0, - ) - } - - // Draw - this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4) - - // Copy to target canvas - const targetCtx = effect.targetCanvas.getContext("2d") - if (targetCtx) { - targetCtx.clearRect(0, 0, effect.width, effect.height) - targetCtx.drawImage(this.canvas!, 0, 0) - } - } - - this.animationFrame = requestAnimationFrame(render) - } - - render() - } - - // Clean up method (optional, for when the app unmounts) - destroy() { - if (this.animationFrame) { - cancelAnimationFrame(this.animationFrame) - } - if (this.gl && this.program) { - this.gl.deleteProgram(this.program) - } - this.effects.clear() - this.mousePositions.clear() - GlassEffectManager.instance = null - } -} - -interface EffectInstance { - id: string - targetCanvas: HTMLCanvasElement - isExpanded: boolean - width: number - height: number -} - -export default GlassEffectManager diff --git a/packages/lib/queries.ts b/packages/lib/queries.ts index fc234b0a..968681e5 100644 --- a/packages/lib/queries.ts +++ b/packages/lib/queries.ts @@ -1,12 +1,3 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query" -import { toast } from "sonner" -import type { z } from "zod" -import type { DocumentsWithMemoriesResponseSchema } from "../validation/api" -import { $fetch } from "./api" - -type DocumentsResponse = z.infer -type DocumentWithMemories = DocumentsResponse["documents"][0] - export const PLAN_TIERS = [ "api_pro", "api_max", @@ -93,91 +84,3 @@ export function getCanceledSubscription( endsAt: sub.currentPeriodEnd ?? sub.expiresAt ?? null, } } - -export const useDeleteDocument = (selectedProject: string) => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async (documentId: string) => { - // context for LLM: delete/memories/:documentId is documents delete endpoint not memories delete endpoint - const response = await $fetch(`@delete/documents/${documentId}`) - if (response.error) { - throw new Error(response.error?.message || "Failed to delete document") - } - return response.data - }, - onMutate: async (documentId: string) => { - await queryClient.cancelQueries({ - queryKey: ["documents-with-memories", selectedProject], - }) - - const previousData = queryClient.getQueryData([ - "documents-with-memories", - selectedProject, - ]) - - queryClient.setQueryData( - ["documents-with-memories", selectedProject], - (old: unknown) => { - if (!old || typeof old !== "object") return old - - // Handle Infinite Query structure (TanStack Query v5 uses 'pages') - if ( - "pages" in old && - Array.isArray((old as Record).pages) - ) { - const typedOld = old as { - pages: Array<{ documents?: DocumentWithMemories[] }> - } - return { - ...typedOld, - pages: typedOld.pages.map((page) => ({ - ...page, - documents: page.documents?.filter( - (doc: DocumentWithMemories) => doc.id !== documentId, - ), - })), - } - } - - // Handle Standard Query structure - if ( - "documents" in old && - Array.isArray((old as Record).documents) - ) { - const typedOld = old as { documents: DocumentWithMemories[] } - return { - ...typedOld, - documents: typedOld.documents.filter( - (doc: DocumentWithMemories) => doc.id !== documentId, - ), - } - } - - return old - }, - ) - - return { previousData } - }, - onSuccess: () => { - toast.success("Memory deleted successfully") - }, - onError: (error, _documentId, context) => { - if (context?.previousData) { - queryClient.setQueryData( - ["documents-with-memories", selectedProject], - context.previousData, - ) - } - toast.error("Failed to delete memory", { - description: error instanceof Error ? error.message : "Unknown error", - }) - }, - onSettled: () => { - queryClient.invalidateQueries({ - queryKey: ["documents-with-memories", selectedProject], - }) - }, - }) -}