From 0b543bb1d67782bca624362e4efd49791d6b2763 Mon Sep 17 00:00:00 2001 From: Dhravya Date: Thu, 4 Jul 2024 10:49:42 -0500 Subject: [PATCH] better-extension --- apps/extension/background.ts | 11 + apps/extension/components.json | 18 + apps/extension/content/ContentApp.tsx | 142 +++-- apps/extension/content/base.css | 4 - apps/extension/content/content.tsx | 13 +- apps/extension/content/ui/shadcn/popover.tsx | 38 ++ apps/extension/content/ui/shadcn/toast.tsx | 129 ++++ apps/extension/content/ui/shadcn/toaster.tsx | 35 ++ apps/extension/content/ui/shadcn/tooltip.tsx | 30 + apps/extension/content/ui/shadcn/use-toast.ts | 191 ++++++ apps/extension/content/utils.ts | 6 + apps/extension/package.json | 22 +- apps/extension/public/output.css | 572 +++++++----------- apps/extension/tailwind.config.js | 6 - apps/extension/tailwind.config.ts | 1 + apps/web/app/(auth)/auth-buttons.tsx | 15 - apps/web/app/(auth)/signin/page.tsx | 8 +- apps/web/app/(dash)/chat/chatWindow.tsx | 4 +- apps/web/app/(dash)/home/page.tsx | 9 +- apps/web/tsconfig.json | 2 +- package.json | 1 + packages/tailwind-config/globals.css | 34 +- packages/tailwind-config/tailwind.config.ts | 4 +- 23 files changed, 840 insertions(+), 455 deletions(-) create mode 100644 apps/extension/components.json create mode 100644 apps/extension/content/ui/shadcn/popover.tsx create mode 100644 apps/extension/content/ui/shadcn/toast.tsx create mode 100644 apps/extension/content/ui/shadcn/toaster.tsx create mode 100644 apps/extension/content/ui/shadcn/tooltip.tsx create mode 100644 apps/extension/content/ui/shadcn/use-toast.ts create mode 100644 apps/extension/content/utils.ts delete mode 100644 apps/extension/tailwind.config.js create mode 100644 apps/extension/tailwind.config.ts delete mode 100644 apps/web/app/(auth)/auth-buttons.tsx diff --git a/apps/extension/background.ts b/apps/extension/background.ts index 1102b764..97bb341c 100644 --- a/apps/extension/background.ts +++ b/apps/extension/background.ts @@ -311,7 +311,18 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }).then((ers) => console.log(ers.status)); }); })(); + + return true; } else if (request.type === "batchImportAll") { batchImportAll(); } }); + +chrome.runtime.onInstalled.addListener(function (details) { + if (details.reason === "install") { + chrome.tabs.create({ + url: "https://supermemory.ai/signin?extension=true", + active: true, + }); + } +}); diff --git a/apps/extension/components.json b/apps/extension/components.json new file mode 100644 index 00000000..d3099362 --- /dev/null +++ b/apps/extension/components.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "../../packages/tailwind-config/globals.css", + "baseColor": "stone", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "content/ui/components", + "utils": "content/utils", + "ui": "content/ui/shadcn" + } +} diff --git a/apps/extension/content/ContentApp.tsx b/apps/extension/content/ContentApp.tsx index 4fe2bc66..c1af1dfc 100644 --- a/apps/extension/content/ContentApp.tsx +++ b/apps/extension/content/ContentApp.tsx @@ -1,8 +1,25 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { Readability } from "@mozilla/readability"; import tailwindBg from "../public/tailwind_bg.png"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "./ui/shadcn/tooltip"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/shadcn/popover"; +import { Toaster } from "./ui/shadcn/toaster"; +import { useToast } from "./ui/shadcn/use-toast"; -export default function ContentApp({ token }: { token: string | undefined }) { +const BACKEND_URL = "https://supermemory.ai"; + +export default function ContentApp({ + token, + shadowRoot, +}: { + token: string | undefined; + shadowRoot: ShadowRoot; +}) { const [text, setText] = useState(""); const [hover, setHover] = useState(false); @@ -11,6 +28,12 @@ export default function ContentApp({ token }: { token: string | undefined }) { const [importedCount, setImportedCount] = useState(0); const [isImporting, setIsImporting] = useState(false); + const [portalContainer, setPortalContainer] = useState( + null, + ); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const { toast } = useToast(); + useEffect(() => { document.addEventListener("mousemove", (e) => { const percentageX = (e.clientX / window.innerWidth) * 100; @@ -24,16 +47,7 @@ export default function ContentApp({ token }: { token: string | undefined }) { }); const getUserData = () => { - const NO_JWT = [ - "supermemory.ai", - "beta.supermemory.ai", - "localhost:3000", - ]; chrome.runtime.sendMessage({ type: "getJwt" }, (response) => { - if (!response.jwt && !NO_JWT.includes(window.location.host)) { - window.location.href = "https://supermemory.ai/signin"; - } - console.log("jwt", response.jwt); }); }; @@ -54,10 +68,15 @@ export default function ContentApp({ token }: { token: string | undefined }) { } }); + const portalDiv = document.createElement("div"); + portalDiv.id = "popover-portal"; + shadowRoot.appendChild(portalDiv); + setPortalContainer(portalDiv); + return () => { document.removeEventListener("mousemove", () => {}); }; - }, []); + }, [document.getElementById("supermemory-extension-host")]); function sendUrlToAPI(spaces: number[]) { setLoading(true); @@ -100,55 +119,60 @@ export default function ContentApp({ token }: { token: string | undefined }) { } } - return ( -
- + if (!shadowRoot || !portalContainer) { + return null; + } - {isImporting && ( -
-
-
-
- -
-
-
-

- Your twitter bookmarks are being imported. -

-

- This is done completely locally, so please keep this tab open! -

-
- Imported {importedCount} bookmarks + return ( +
+ + + + + + + + {loading ? ( +
Saving...
+ ) : ( + + + + )} +
+
+ +

Add to supermemory.ai

+
+
+
+ +
+

Select a space

+ +
-
- )} + + {(window.location.host === "twitter.com" || window.location.host === "x.com") && ( diff --git a/apps/extension/content/base.css b/apps/extension/content/base.css index c8845aea..cd7633f5 100644 --- a/apps/extension/content/base.css +++ b/apps/extension/content/base.css @@ -1,7 +1,3 @@ -/* @tailwind base; -@tailwind components; -@tailwind utilities; */ - #supermemory-extension-host { position: fixed; bottom: 0; diff --git a/apps/extension/content/content.tsx b/apps/extension/content/content.tsx index bacb79c0..f44beacb 100644 --- a/apps/extension/content/content.tsx +++ b/apps/extension/content/content.tsx @@ -8,10 +8,11 @@ const TAILWIND_URL = "https://cdn.jsdelivr.net/npm/tailwindcss@^2.0/dist/tailwind.min.css"; const appendTailwindStyleData = (shadowRoot: ShadowRoot) => { - // Load and inject the local Tailwind CSS file into the shadow DOM const styleSheet = document.createElement("style"); - // Change this path to your actual Tailwind CSS file's location - fetch(TAILWIND_URL) + + const path = chrome.runtime.getURL("../public/output.css"); + + fetch(path) .then((response) => response.text()) .then((css) => { styleSheet.textContent = css; @@ -44,7 +45,7 @@ function initial() { rootDiv.id = "supermemory-extension-root"; shadowRoot.appendChild(rootDiv); - appendTailwindStyleLink(shadowRoot); + appendTailwindStyleData(shadowRoot); const root = ReactDOM.createRoot(rootDiv); @@ -52,7 +53,9 @@ function initial() { return data.jwt; }) as Promise; - jwt.then((token) => root.render()); + jwt.then((token) => + root.render(), + ); } window.addEventListener("message", (event) => { diff --git a/apps/extension/content/ui/shadcn/popover.tsx b/apps/extension/content/ui/shadcn/popover.tsx new file mode 100644 index 00000000..e896283e --- /dev/null +++ b/apps/extension/content/ui/shadcn/popover.tsx @@ -0,0 +1,38 @@ +"use client"; + +import * as React from "react"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; + +import { cn } from "../../utils"; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + container?: Element; + } +>( + ( + { className, container, align = "center", sideOffset = 4, ...props }, + ref, + ) => ( + + + + ), +); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverTrigger, PopoverContent }; diff --git a/apps/extension/content/ui/shadcn/toast.tsx b/apps/extension/content/ui/shadcn/toast.tsx new file mode 100644 index 00000000..b0f93ac4 --- /dev/null +++ b/apps/extension/content/ui/shadcn/toast.tsx @@ -0,0 +1,129 @@ +"use client"; + +import * as React from "react"; +import * as ToastPrimitives from "@radix-ui/react-toast"; +import { cva, type VariantProps } from "class-variance-authority"; +import { X } from "lucide-react"; + +import { cn } from "../../utils"; + +const ToastProvider = ToastPrimitives.Provider; + +const ToastViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; + +const toastVariants = cva( + "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", + { + variants: { + variant: { + default: "border bg-background text-foreground", + destructive: + "destructive group border-destructive bg-destructive text-destructive-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +const Toast = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, ...props }, ref) => { + return ( + + ); +}); +Toast.displayName = ToastPrimitives.Root.displayName; + +const ToastAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +ToastAction.displayName = ToastPrimitives.Action.displayName; + +const ToastClose = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +ToastClose.displayName = ToastPrimitives.Close.displayName; + +const ToastTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +ToastTitle.displayName = ToastPrimitives.Title.displayName; + +const ToastDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +ToastDescription.displayName = ToastPrimitives.Description.displayName; + +type ToastProps = React.ComponentPropsWithoutRef; + +type ToastActionElement = React.ReactElement; + +export { + type ToastProps, + type ToastActionElement, + ToastProvider, + ToastViewport, + Toast, + ToastTitle, + ToastDescription, + ToastClose, + ToastAction, +}; diff --git a/apps/extension/content/ui/shadcn/toaster.tsx b/apps/extension/content/ui/shadcn/toaster.tsx new file mode 100644 index 00000000..9b494bfd --- /dev/null +++ b/apps/extension/content/ui/shadcn/toaster.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { + Toast, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, +} from "../shadcn/toast"; +import { useToast } from "../shadcn/use-toast"; + +export function Toaster() { + const { toasts } = useToast(); + + return ( + + {toasts.map(function ({ id, title, description, action, ...props }) { + return ( + +
+ {title && {title}} + {description && ( + {description} + )} +
+ {action} + +
+ ); + })} + +
+ ); +} diff --git a/apps/extension/content/ui/shadcn/tooltip.tsx b/apps/extension/content/ui/shadcn/tooltip.tsx new file mode 100644 index 00000000..b3534220 --- /dev/null +++ b/apps/extension/content/ui/shadcn/tooltip.tsx @@ -0,0 +1,30 @@ +"use client"; + +import * as React from "react"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; + +import { cn } from "../../utils"; + +const TooltipProvider = TooltipPrimitive.Provider; + +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/apps/extension/content/ui/shadcn/use-toast.ts b/apps/extension/content/ui/shadcn/use-toast.ts new file mode 100644 index 00000000..2f3870d8 --- /dev/null +++ b/apps/extension/content/ui/shadcn/use-toast.ts @@ -0,0 +1,191 @@ +"use client"; + +// Inspired by react-hot-toast library +import * as React from "react"; + +import type { ToastActionElement, ToastProps } from "content/ui/shadcn/toast"; + +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; + +type ToasterToast = ToastProps & { + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; + +const actionTypes = { + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const; + +let count = 0; + +function genId() { + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); +} + +type ActionType = typeof actionTypes; + +type Action = + | { + type: ActionType["ADD_TOAST"]; + toast: ToasterToast; + } + | { + type: ActionType["UPDATE_TOAST"]; + toast: Partial; + } + | { + type: ActionType["DISMISS_TOAST"]; + toastId?: ToasterToast["id"]; + } + | { + type: ActionType["REMOVE_TOAST"]; + toastId?: ToasterToast["id"]; + }; + +interface State { + toasts: ToasterToast[]; +} + +const toastTimeouts = new Map>(); + +const addToRemoveQueue = (toastId: string) => { + if (toastTimeouts.has(toastId)) { + return; + } + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId); + dispatch({ + type: "REMOVE_TOAST", + toastId: toastId, + }); + }, TOAST_REMOVE_DELAY); + + toastTimeouts.set(toastId, timeout); +}; + +export const reducer = (state: State, action: Action): State => { + switch (action.type) { + case "ADD_TOAST": + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + }; + + case "UPDATE_TOAST": + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t, + ), + }; + + case "DISMISS_TOAST": { + const { toastId } = action; + + // ! Side effects ! - This could be extracted into a dismissToast() action, + // but I'll keep it here for simplicity + if (toastId) { + addToRemoveQueue(toastId); + } else { + state.toasts.forEach((toast) => { + addToRemoveQueue(toast.id); + }); + } + + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t, + ), + }; + } + case "REMOVE_TOAST": + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + }; + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + }; + } +}; + +const listeners: Array<(state: State) => void> = []; + +let memoryState: State = { toasts: [] }; + +function dispatch(action: Action) { + memoryState = reducer(memoryState, action); + listeners.forEach((listener) => { + listener(memoryState); + }); +} + +type Toast = Omit; + +function toast({ ...props }: Toast) { + const id = genId(); + + const update = (props: ToasterToast) => + dispatch({ + type: "UPDATE_TOAST", + toast: { ...props, id }, + }); + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); + + dispatch({ + type: "ADD_TOAST", + toast: { + ...props, + id, + open: true, + onOpenChange: (open) => { + if (!open) dismiss(); + }, + }, + }); + + return { + id: id, + dismiss, + update, + }; +} + +function useToast() { + const [state, setState] = React.useState(memoryState); + + React.useEffect(() => { + listeners.push(setState); + return () => { + const index = listeners.indexOf(setState); + if (index > -1) { + listeners.splice(index, 1); + } + }; + }, [state]); + + return { + ...state, + toast, + dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), + }; +} + +export { useToast, toast }; diff --git a/apps/extension/content/utils.ts b/apps/extension/content/utils.ts new file mode 100644 index 00000000..365058ce --- /dev/null +++ b/apps/extension/content/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/apps/extension/package.json b/apps/extension/package.json index f23759d5..e53d0787 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -2,19 +2,31 @@ "devDependencies": { "@types/react": "^18.0.9", "@types/react-dom": "^18.0.5", + "@webpack-cli/generators": "^3.0.7", + "extension": "latest", "react": "^18.1.0", "react-dom": "^18.1.0", "tailwindcss": "^3.4.1", "typescript": "5.3.3", - "extension": "latest" + "webpack-cli": "^5.1.4" }, "scripts": { "dev": "extension dev", "start": "extension start", - "build": "extension build" + "build": "extension build", + "style": "tailwindcss -i ../../packages/tailwind-config/globals.css -o ./public/output.css --watch" }, - "dependencies": {}, - "name": "content-shadow-dom-tailwind", + "name": "supermemory-extension", "private": true, - "version": "0.0.0" + "version": "0.0.0", + "dependencies": { + "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-tooltip": "^1.1.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.400.0", + "tailwind-merge": "^2.3.0", + "tailwindcss-animate": "^1.0.7" + } } diff --git a/apps/extension/public/output.css b/apps/extension/public/output.css index d7852ac3..038be1ea 100644 --- a/apps/extension/public/output.css +++ b/apps/extension/public/output.css @@ -564,14 +564,6 @@ video { --tw-contain-style: ; } -.\!container { - width: 100% !important; - margin-right: auto !important; - margin-left: auto !important; - padding-right: 2rem !important; - padding-left: 2rem !important; -} - .container { width: 100%; margin-right: auto; @@ -581,10 +573,6 @@ video { } @media (min-width: 1400px) { - .\!container { - max-width: 1400px !important; - } - .container { max-width: 1400px; } @@ -610,22 +598,6 @@ video { pointer-events: auto; } -.visible { - visibility: visible; -} - -.invisible { - visibility: hidden; -} - -.collapse { - visibility: collapse; -} - -.static { - position: static; -} - .fixed { position: fixed; } @@ -638,10 +610,6 @@ video { position: relative; } -.sticky { - position: sticky; -} - .inset-0 { inset: 0px; } @@ -655,30 +623,18 @@ video { bottom: 0px; } -.bottom-12 { - bottom: 3rem; +.bottom-20 { + bottom: 5rem; } -.bottom-4 { - bottom: 1rem; -} - -.left-0 { - left: 0px; -} - -.left-1\/2 { - left: 50%; +.bottom-6 { + bottom: 1.5rem; } .left-2 { left: 0.5rem; } -.left-8 { - left: 2rem; -} - .left-\[50\%\] { left: 50%; } @@ -691,10 +647,6 @@ video { right: 1rem; } -.right-8 { - right: 2rem; -} - .top-0 { top: 0px; } @@ -719,36 +671,23 @@ video { z-index: 10; } +.z-30 { + z-index: 30; +} + .z-50 { z-index: 50; } -.z-\[1000000\] { - z-index: 1000000; -} - -.z-\[100000\] { - z-index: 100000; -} - .z-\[100\] { z-index: 100; } -.m-2 { - margin: 0.5rem; -} - .-mx-1 { margin-left: -0.25rem; margin-right: -0.25rem; } -.mx-4 { - margin-left: 1rem; - margin-right: 1rem; -} - .mx-auto { margin-left: auto; margin-right: auto; @@ -759,11 +698,6 @@ video { margin-bottom: 0.25rem; } -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} - .mb-1 { margin-bottom: 0.25rem; } @@ -796,32 +730,10 @@ video { margin-top: auto; } -.line-clamp-1 { - overflow: hidden; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; -} - -.line-clamp-3 { - overflow: hidden; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; -} - -.\!block { - display: block !important; -} - .block { display: block; } -.inline { - display: inline; -} - .flex { display: flex; } @@ -830,35 +742,29 @@ video { display: inline-flex; } -.\!table { - display: table !important; -} - -.table { - display: table; -} - -.\!grid { - display: grid !important; -} - .grid { display: grid; } -.contents { - display: contents; -} - .hidden { display: none; } +.size-12 { + width: 3rem; + height: 3rem; +} + .size-4 { width: 1rem; height: 1rem; } +.size-8 { + width: 2rem; + height: 2rem; +} + .h-10 { height: 2.5rem; } @@ -867,10 +773,6 @@ video { height: 2.75rem; } -.h-12 { - height: 3rem; -} - .h-2 { height: 0.5rem; } @@ -931,14 +833,6 @@ video { height: 1px; } -.h-screen { - height: 100vh; -} - -.max-h-40 { - max-height: 10rem; -} - .max-h-96 { max-height: 24rem; } @@ -951,10 +845,6 @@ video { max-height: 100vh; } -.min-h-24 { - min-height: 6rem; -} - .min-h-\[80px\] { min-height: 80px; } @@ -971,10 +861,6 @@ video { width: 2.75rem; } -.w-12 { - width: 3rem; -} - .w-2 { width: 0.5rem; } @@ -1027,10 +913,6 @@ video { max-width: 16rem; } -.max-w-96 { - max-width: 24rem; -} - .max-w-lg { max-width: 32rem; } @@ -1039,24 +921,12 @@ video { flex: 1 1 0%; } -.shrink { - flex-shrink: 1; -} - .shrink-0 { flex-shrink: 0; } -.grow { - flex-grow: 1; -} - -.border-collapse { - border-collapse: collapse; -} - -.-translate-x-1\/2 { - --tw-translate-x: -50%; +.translate-x-3\/4 { + --tw-translate-x: 75%; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1076,13 +946,6 @@ video { scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.translate-y-0 { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - .translate-y-12 { --tw-translate-y: 3rem; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) @@ -1121,10 +984,6 @@ video { user-select: none; } -.resize { - resize: both; -} - .flex-col { flex-direction: column; } @@ -1161,18 +1020,10 @@ video { gap: 0.375rem; } -.gap-10 { - gap: 2.5rem; -} - .gap-2 { gap: 0.5rem; } -.gap-3 { - gap: 0.75rem; -} - .gap-4 { gap: 1rem; } @@ -1213,20 +1064,10 @@ video { overflow-x: hidden; } -.truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .whitespace-nowrap { white-space: nowrap; } -.rounded { - border-radius: 0.25rem; -} - .rounded-2xl { border-radius: 1rem; } @@ -1286,16 +1127,6 @@ video { border-top-width: 1px; } -.border-\[\#1F2428\] { - --tw-border-opacity: 1; - border-color: rgb(31 36 40 / var(--tw-border-opacity)); -} - -.border-blue-600 { - --tw-border-opacity: 1; - border-color: rgb(37 99 235 / var(--tw-border-opacity)); -} - .border-border { border-color: var(--border); } @@ -1316,6 +1147,10 @@ video { border-color: rgb(255 255 255 / 0.1); } +.border-white\/20 { + border-color: rgb(255 255 255 / 0.2); +} + .border-white\/30 { border-color: rgb(255 255 255 / 0.3); } @@ -1328,24 +1163,20 @@ video { border-top-color: transparent; } -.bg-\[\#2C3439\] { - --tw-bg-opacity: 1; - background-color: rgb(44 52 57 / var(--tw-bg-opacity)); -} - .bg-\[\#2D343A\] { --tw-bg-opacity: 1; background-color: rgb(45 52 58 / var(--tw-bg-opacity)); } -.bg-\[\#2c3439ad\] { - background-color: #2c3439ad; -} - .bg-background { background-color: var(--background); } +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + .bg-black\/20 { background-color: rgb(0 0 0 / 0.2); } @@ -1366,11 +1197,6 @@ video { background-color: hsl(var(--destructive)); } -.bg-gray-900 { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); -} - .bg-muted { background-color: hsl(var(--muted)); } @@ -1383,16 +1209,6 @@ video { background-color: var(--primary); } -.bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); -} - -.bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); -} - .bg-secondary { background-color: var(--secondary); } @@ -1406,11 +1222,6 @@ video { background-color: transparent; } -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - .bg-page-gradient { background-image: radial-gradient( ellipse 80% 50% at 50% -20%, @@ -1419,6 +1230,10 @@ video { ); } +.fill-current { + fill: currentColor; +} + .stroke-2 { stroke-width: 2; } @@ -1435,10 +1250,6 @@ video { padding: 0.5rem; } -.p-3 { - padding: 0.75rem; -} - .p-4 { padding: 1rem; } @@ -1451,11 +1262,6 @@ video { padding: 1px; } -.px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; -} - .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1569,18 +1375,14 @@ video { line-height: 1.25rem; } -.text-xl { - font-size: 1.25rem; - line-height: 1.75rem; -} - .text-xs { font-size: 0.75rem; line-height: 1rem; } -.font-extrabold { - font-weight: 800; +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; } .font-medium { @@ -1591,29 +1393,10 @@ video { font-weight: 600; } -.uppercase { - text-transform: uppercase; -} - -.lowercase { - text-transform: lowercase; -} - -.capitalize { - text-transform: capitalize; -} - .italic { font-style: italic; } -.ordinal { - --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) - var(--tw-numeric-figure) var(--tw-numeric-spacing) - var(--tw-numeric-fraction); -} - .leading-none { line-height: 1; } @@ -1626,21 +1409,6 @@ video { letter-spacing: 0.1em; } -.text-\[\#369DFD\] { - --tw-text-opacity: 1; - color: rgb(54 157 253 / var(--tw-text-opacity)); -} - -.text-\[\#989EA4\] { - --tw-text-opacity: 1; - color: rgb(152 158 164 / var(--tw-text-opacity)); -} - -.text-\[\#B3BCC5\] { - --tw-text-opacity: 1; - color: rgb(179 188 197 / var(--tw-text-opacity)); -} - .text-card-foreground { color: hsl(var(--card-foreground)); } @@ -1657,11 +1425,6 @@ video { color: var(--foreground); } -.text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - .text-muted-foreground { color: hsl(var(--muted-foreground)); } @@ -1674,11 +1437,6 @@ video { color: var(--primary); } -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - .text-zinc-200 { --tw-text-opacity: 1; color: rgb(228 228 231 / var(--tw-text-opacity)); @@ -1689,8 +1447,9 @@ video { color: rgb(113 113 122 / var(--tw-text-opacity)); } -.underline { - text-decoration-line: underline; +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); } .underline-offset-4 { @@ -1709,10 +1468,18 @@ video { opacity: 0.5; } +.opacity-60 { + opacity: 0.6; +} + .opacity-70 { opacity: 0.7; } +.opacity-75 { + opacity: 0.75; +} + .opacity-90 { opacity: 0.9; } @@ -1758,15 +1525,6 @@ video { outline-style: solid; } -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 - var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 - calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); -} - .ring-0 { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); @@ -1780,20 +1538,6 @@ video { --tw-ring-offset-color: var(--background); } -.blur { - --tw-blur: blur(8px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) - var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) - var(--tw-sepia) var(--tw-drop-shadow); -} - -.invert { - --tw-invert: invert(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) - var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) - var(--tw-sepia) var(--tw-drop-shadow); -} - .filter { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) @@ -1814,39 +1558,6 @@ video { var(--tw-backdrop-sepia); } -.\!transition { - transition-property: - color, - background-color, - border-color, - text-decoration-color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - -webkit-backdrop-filter !important; - transition-property: color, background-color, border-color, - text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, - backdrop-filter !important; - transition-property: - color, - background-color, - border-color, - text-decoration-color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter !important; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) !important; - transition-duration: 150ms !important; -} - .transition { transition-property: color, @@ -1965,18 +1676,6 @@ video { animation-duration: 200ms; } -.running { - animation-play-state: running; -} - -.paused { - animation-play-state: paused; -} - -.\[a-zA-Z0-9\:\\\\-\\\\\._\$\] { - a-z-a--z0-9: \\-\\.$; -} - .\[background\:linear-gradient\(\#2E2E32\2c \#2E2E32\)\2c linear-gradient\(120deg\2c @@ -1987,11 +1686,147 @@ video { linear-gradient(120deg, #3f3f46, rgb(63 63 70 / 0), #3f3f46); } -#supermemory-extension-host { - position: fixed; - bottom: 0; - right: 0; - z-index: 99999; +:root { + --foreground: rgba(179, 188, 197, 1); + --foreground-menu: rgba(106, 115, 125, 1); + --background: rgba(31, 36, 40, 1); + --secondary: rgb(45, 51, 58); + --primary: rgba(54, 157, 253, 1); + --border: rgba(62, 68, 73, 1); + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary-foreground: 0 0% 98%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --radius: 0.5rem; +} + +:host { + --foreground: rgba(179, 188, 197, 1); + --foreground-menu: rgba(106, 115, 125, 1); + --background: rgba(31, 36, 40, 1); + --secondary: rgb(45, 51, 58); + --primary: rgba(54, 157, 253, 1); + --border: rgba(62, 68, 73, 1); + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary-foreground: 0 0% 98%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --radius: 0.5rem; +} + +body { + color: var(--foreground); + background: var(--background); + font-size: 14px; +} + +.gradient-background { + background: linear-gradient( + 150deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0) + ); +} + +.no-scrollbar { + /* For WebKit (Safari, Chrome, etc.) */ + &::-webkit-scrollbar { + display: none; + } + /* For Firefox */ + scrollbar-width: none; + /* For IE and Edge */ + -ms-overflow-style: none; +} + +:not(pre) > code.hljs, +:not(pre) > code[class*="language-"] { + border-radius: 0.3em; + white-space: normal; +} + +.hljs-comment { + color: hsla(0, 0%, 100%, 0.5); +} + +.hljs-meta { + color: hsla(0, 0%, 100%, 0.6); +} + +.hljs-built_in, +.hljs-class .hljs-title { + color: #e9950c; +} + +.hljs-doctag, +.hljs-formula, +.hljs-keyword, +.hljs-literal { + color: #2e95d3; +} + +.hljs-addition, +.hljs-attribute, +.hljs-meta-string, +.hljs-regexp, +.hljs-string { + color: #00a67d; +} + +.hljs-attr, +.hljs-number, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-pseudo, +.hljs-template-variable, +.hljs-type, +.hljs-variable { + color: #df3079; +} + +.hljs-bullet, +.hljs-link, +.hljs-selector-id, +.hljs-symbol, +.hljs-title { + color: #f22c3d; +} + +/* no scrollbar visibility */ + +.no-scrollbar::-webkit-scrollbar { + width: 0px; +} + +::-moz-selection { + /* Code for Firefox */ + color: #369dfd; + background: #21303d; +} + +::selection { + color: #369dfd; + background: #21303d; } .file\:border-0::file-selector-button { @@ -2027,6 +1862,13 @@ video { color: hsl(var(--muted-foreground)); } +.focus-within\:translate-x-0:focus-within { + --tw-translate-x: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .group:focus-within .group-focus-within\:block { display: block; } @@ -2208,6 +2050,10 @@ video { background-color: hsl(var(--accent)); } +.data-\[state\=open\]\:bg-secondary[data-state="open"] { + background-color: var(--secondary); +} + .data-\[state\=unchecked\]\:bg-input[data-state="unchecked"] { background-color: hsl(var(--input)); } @@ -2341,6 +2187,11 @@ video { background-color: hsl(var(--accent)); } +.hover\:bg-black:hover { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + .hover\:bg-destructive\/80:hover { background-color: hsl(var(--destructive) / 0.8); } @@ -2400,6 +2251,14 @@ video { background-color: var(--foreground-menu); } +.focus\:bg-secondary:focus { + background-color: var(--secondary); +} + +.focus\:text-accent-foreground:focus { + color: hsl(var(--accent-foreground)); +} + .focus\:opacity-100:focus { opacity: 1; } @@ -2439,6 +2298,13 @@ video { --tw-ring-offset-color: #dc2626; } +.focus-visible\:translate-x-0:focus-visible { + --tw-translate-x: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .focus-visible\:outline-none:focus-visible { outline: 2px solid transparent; outline-offset: 2px; diff --git a/apps/extension/tailwind.config.js b/apps/extension/tailwind.config.js deleted file mode 100644 index 648d6d1f..00000000 --- a/apps/extension/tailwind.config.js +++ /dev/null @@ -1,6 +0,0 @@ -const defaults = require("@repo/tailwind-config/tailwind.config"); - -/** @type {import('tailwindcss').Config} */ -module.exports = { - ...defaults, -}; diff --git a/apps/extension/tailwind.config.ts b/apps/extension/tailwind.config.ts new file mode 100644 index 00000000..cf1434cf --- /dev/null +++ b/apps/extension/tailwind.config.ts @@ -0,0 +1 @@ +module.exports = require("@repo/tailwind-config/tailwind.config"); diff --git a/apps/web/app/(auth)/auth-buttons.tsx b/apps/web/app/(auth)/auth-buttons.tsx deleted file mode 100644 index 5b0ad06e..00000000 --- a/apps/web/app/(auth)/auth-buttons.tsx +++ /dev/null @@ -1,15 +0,0 @@ -"use client"; - -import { Button } from "@repo/ui/shadcn/button"; -import React from "react"; -import { signIn } from "../../server/auth"; - -function SignIn() { - return ( - - ); -} - -export default SignIn; diff --git a/apps/web/app/(auth)/signin/page.tsx b/apps/web/app/(auth)/signin/page.tsx index bfb341ff..ba4b835a 100644 --- a/apps/web/app/(auth)/signin/page.tsx +++ b/apps/web/app/(auth)/signin/page.tsx @@ -6,15 +6,21 @@ import { Google } from "@repo/ui/components/icons"; import gradientStyle from "./_components/TextGradient/gradient.module.css"; import { cn } from "@repo/ui/lib/utils"; import { redirect } from "next/navigation"; +import { toast } from "sonner"; export const runtime = "edge"; -async function Signin() { +async function Signin({ + searchParams, +}: { + searchParams: Record; +}) { const user = await auth(); if (user) { await redirect("/home"); } + return (
diff --git a/apps/web/app/(dash)/chat/chatWindow.tsx b/apps/web/app/(dash)/chat/chatWindow.tsx index 1d54e912..7cdf7bbb 100644 --- a/apps/web/app/(dash)/chat/chatWindow.tsx +++ b/apps/web/app/(dash)/chat/chatWindow.tsx @@ -207,7 +207,7 @@ function ChatWindow({ ) : (
@@ -242,7 +242,7 @@ function ChatWindow({ {/* TODO: fade out content on the right side, the fade goes away when the user scrolls */} {/* Loading state */} diff --git a/apps/web/app/(dash)/home/page.tsx b/apps/web/app/(dash)/home/page.tsx index 32cb5d8d..27f037a8 100644 --- a/apps/web/app/(dash)/home/page.tsx +++ b/apps/web/app/(dash)/home/page.tsx @@ -36,6 +36,9 @@ function Page({ const [telegramUser, setTelegramUser] = useState( searchParams.telegramUser as string, ); + const [extensionInstalled, setExtensionInstalled] = useState< + string | undefined + >(searchParams.extension as string); const { push } = useRouter(); @@ -58,6 +61,10 @@ function Page({ linkTelegram(); } + if (extensionInstalled) { + toast.success("Extension installed successfully"); + } + getSpaces().then((res) => { if (res.success && res.data) { setSpaces(res.data); @@ -72,7 +79,7 @@ function Page({ if (typeof window === "undefined") return; window.postMessage({ token: token.data }, "*"); }); - }, []); + }, [telegramUser]); return (
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 35e6a20c..e5432796 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -18,7 +18,7 @@ "**/*.tsx", ".next/types/**/*.ts", "../../packages/ui/", - "../../packages/shared-types/utils.ts", + "../../packages/shared-types", "./components" ], "exclude": ["node_modules/"] diff --git a/package.json b/package.json index 79b1f113..f8902c5e 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@auth/drizzle-adapter": "^1.1.0", "@aws-sdk/client-s3": "^3.577.0", "@aws-sdk/s3-request-presigner": "^3.577.0", + "@babel/plugin-transform-runtime": "^7.24.7", "@cloudflare/puppeteer": "^0.0.11", "@headlessui/react": "^2.0.4", "@heroicons/react": "^2.1.4", diff --git a/packages/tailwind-config/globals.css b/packages/tailwind-config/globals.css index d4f994ed..84d5bceb 100644 --- a/packages/tailwind-config/globals.css +++ b/packages/tailwind-config/globals.css @@ -35,6 +35,39 @@ --radius: 0.5rem; } +:host { + --foreground: rgba(179, 188, 197, 1); + --foreground-menu: rgba(106, 115, 125, 1); + --background: rgba(31, 36, 40, 1); + --secondary: rgb(45, 51, 58); + --primary: rgba(54, 157, 253, 1); + --border: rgba(62, 68, 73, 1); + + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + + --primary-foreground: 0 0% 98%; + + --secondary-foreground: 0 0% 9%; + + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + + --radius: 0.5rem; +} + body { color: var(--foreground); background: var(--background); @@ -127,7 +160,6 @@ body { ); } - .no-scrollbar { /* For WebKit (Safari, Chrome, etc.) */ &::-webkit-scrollbar { diff --git a/packages/tailwind-config/tailwind.config.ts b/packages/tailwind-config/tailwind.config.ts index 8e59c5e6..69d2d9f0 100644 --- a/packages/tailwind-config/tailwind.config.ts +++ b/packages/tailwind-config/tailwind.config.ts @@ -7,9 +7,9 @@ const config = { "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}", - "../../apps/extension/**/*.{js,ts,jsx,tsx}", "../../packages/ui/**/*.{js,ts,jsx,tsx}", // Add the ui package - "../../packages/ui/shadcn/**/*.{js,ts,jsx,tsx}", // Add the ui package + "./content/**/*.{js,ts,jsx,tsx}", + "./ui/**/*.{js,ts,jsx,tsx}", ], prefix: "", theme: {