diff --git a/src/frontend/index.scss b/src/frontend/index.scss index 1032ce2..97262cf 100644 --- a/src/frontend/index.scss +++ b/src/frontend/index.scss @@ -1,6 +1,7 @@ @import 'src/css/_colors.scss'; @import 'src/css/_excalidraw-overrides.scss'; @import 'src/css/_fonts.scss'; +@import 'src/css/_defaults.scss'; /* Makes excalidraw fill the entire screen */ #root { diff --git a/src/frontend/index.tsx b/src/frontend/index.tsx index 1401655..b01886e 100644 --- a/src/frontend/index.tsx +++ b/src/frontend/index.tsx @@ -1,34 +1,28 @@ import React, { StrictMode } from "react"; import { createRoot } from "react-dom/client"; + import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -// import posthog from "./src/lib/posthog"; -// import { PostHogProvider } from 'posthog-js/react'; - import "@atyrode/excalidraw/index.css"; import "./index.scss"; import App from "./src/App"; import AuthGate from "./src/AuthGate"; - -// Create a client const queryClient = new QueryClient(); async function initApp() { const rootElement = document.getElementById("root")!; const root = createRoot(rootElement); root.render( - // + - {/* */} - - - {/* */} + + - // , + , ); } diff --git a/src/frontend/package.json b/src/frontend/package.json index ca1f4ab..9a25094 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -26,6 +26,8 @@ }, "devDependencies": { "@types/node": "^22.14.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "typescript": "^5", "vite": "5.2.0" }, diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 977cdc9..b2d03d4 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -13,7 +13,6 @@ import { useAppConfig } from "./hooks/useAppConfig"; import DiscordButton from './ui/DiscordButton'; import { MainMenuConfig } from './ui/MainMenu'; import AuthDialog from './ui/AuthDialog'; -import SettingsDialog from './ui/SettingsDialog'; import Collab from './lib/collab/Collab'; // Utils @@ -39,15 +38,9 @@ export default function App() { leaveSharedPad } = usePadTabs(isAuthenticated); - const [showSettingsModal, setShowSettingsModal] = useState(false); const [excalidrawAPI, excalidrawRefCallback] = useCallbackRefState(); - - const handleCloseSettingsModal = () => { - setShowSettingsModal(false); - }; - - const handleOnScrollChange = (scrollX: number, scrollY: number) => { + const handleOnScrollChange = () => { lockEmbeddables(excalidrawAPI?.getAppState()); }; @@ -84,19 +77,10 @@ export default function App() { {!isLoadingAuth && !isAuthenticated && ( - { }} /> - )} - - {showSettingsModal && ( - + )} {excalidrawAPI && ( diff --git a/src/frontend/src/AuthGate.tsx b/src/frontend/src/AuthGate.tsx index d10d9c5..38a0535 100644 --- a/src/frontend/src/AuthGate.tsx +++ b/src/frontend/src/AuthGate.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from "react"; -import { useAppConfig } from "./hooks/useAppConfig"; // Import useAppConfig +import { useAppConfig } from "./hooks/useAppConfig"; import { useAuthStatus } from "./hooks/useAuthStatus"; /** diff --git a/src/frontend/src/constants.ts b/src/frontend/src/constants.ts index 9e8bf94..83275f3 100644 --- a/src/frontend/src/constants.ts +++ b/src/frontend/src/constants.ts @@ -1,3 +1,5 @@ +import { UserSettings } from "./ui/types"; + // Default app values export const INITIAL_APP_DATA = { appState: { @@ -24,3 +26,8 @@ export const HIDDEN_UI_ELEMENTS = { export const POINTER_MOVE_THROTTLE_MS = 30; // Throttle pointer move events to reduce the number of updates sent to the server export const ENABLE_PERIODIC_FULL_SYNC = false; // Set to false to disable periodic scene_update full sync export const PERIODIC_FULL_SYNC_INTERVAL_MS = 60000; // Sync scene_update every 60 seconds if ENABLE_PERIODIC_FULL_SYNC is true + +// Pad constants +export const DEFAULT_SETTINGS: UserSettings = { + embedLockDebounceTime: 350, + }; \ No newline at end of file diff --git a/src/frontend/src/css/_defaults.scss b/src/frontend/src/css/_defaults.scss new file mode 100644 index 0000000..5b4f6a1 --- /dev/null +++ b/src/frontend/src/css/_defaults.scss @@ -0,0 +1,6 @@ +:root { + --slider-thumb-size: 16px; + --range-track-filled: #{$accent}; + --range-track-unfilled: #{$grey-800}; + --range-thumb-color: #{$accent-dark}; + } \ No newline at end of file diff --git a/src/frontend/src/css/_excalidraw-overrides.scss b/src/frontend/src/css/_excalidraw-overrides.scss index 19bf3aa..659ab11 100644 --- a/src/frontend/src/css/_excalidraw-overrides.scss +++ b/src/frontend/src/css/_excalidraw-overrides.scss @@ -48,12 +48,6 @@ --color-surface-primary-container: #{$accent-light} !important; --color-selection: #{$accent-lighter} !important; - .dropdown-menu-button { - &:hover { - background-color: $accent-faded-light !important; - } - } - .dropdown-menu-group-title { color: $accent-lighter !important; } @@ -67,11 +61,6 @@ --color-surface-primary-container: #{$accent} !important; --color-selection: #{$accent-darker} !important; - .dropdown-menu-button { - &:hover { - background-color: $accent-faded-dark !important; - } - } .dropdown-menu-group-title { color: $accent-darker !important; } diff --git a/src/frontend/src/hooks/useAppConfig.ts b/src/frontend/src/hooks/useAppConfig.ts index db18e0f..bc65a06 100644 --- a/src/frontend/src/hooks/useAppConfig.ts +++ b/src/frontend/src/hooks/useAppConfig.ts @@ -32,7 +32,6 @@ export const useAppConfig = () => { gcTime: Infinity, // Renamed from cacheTime in v5 }); - console.log('data', data); return { config: data, isLoadingConfig: isLoading, diff --git a/src/frontend/src/lib/canvas.ts b/src/frontend/src/lib/canvas.ts index 3c25701..19dc833 100644 --- a/src/frontend/src/lib/canvas.ts +++ b/src/frontend/src/lib/canvas.ts @@ -1,4 +1,4 @@ -import { DEFAULT_SETTINGS } from '../types/settings'; +import { DEFAULT_SETTINGS } from '../constants'; /** * diff --git a/src/frontend/src/lib/collab/Collab.tsx b/src/frontend/src/lib/collab/Collab.tsx index f1e66b7..518f46f 100644 --- a/src/frontend/src/lib/collab/Collab.tsx +++ b/src/frontend/src/lib/collab/Collab.tsx @@ -1,4 +1,4 @@ -import React, { PureComponent } from 'react'; +import { PureComponent } from 'react'; import type { ExcalidrawImperativeAPI, AppState, SocketId, Collaborator as ExcalidrawCollaboratorType } from '@atyrode/excalidraw/types'; import type { ExcalidrawElement as ExcalidrawElementType } from '@atyrode/excalidraw/element/types'; import { @@ -490,13 +490,13 @@ class Collab extends PureComponent { if (messageData.button) pointerDataIn.button = messageData.button; this.setState(prevState => { const newCollaborators = new Map(prevState.collaborators); - const existing = newCollaborators.get(user_id); + const existing = newCollaborators.get(user_id as SocketId); const updatedCollaborator: Collaborator = { ...(existing as Collaborator), pointer: pointerDataIn, button: pointerDataIn.button }; - newCollaborators.set(user_id, updatedCollaborator); + newCollaborators.set(user_id as SocketId, updatedCollaborator); return { collaborators: newCollaborators }; }); break; diff --git a/src/frontend/src/ui/AuthDialog.scss b/src/frontend/src/ui/AuthDialog.scss index 24379f8..9658903 100644 --- a/src/frontend/src/ui/AuthDialog.scss +++ b/src/frontend/src/ui/AuthDialog.scss @@ -1,5 +1,3 @@ -/* Auth Modal Styles */ - .excalidraw .Dialog--fullscreen { &.auth-modal { .Dialog__close { diff --git a/src/frontend/src/ui/AuthDialog.tsx b/src/frontend/src/ui/AuthDialog.tsx index ae05f42..002c8a4 100644 --- a/src/frontend/src/ui/AuthDialog.tsx +++ b/src/frontend/src/ui/AuthDialog.tsx @@ -1,21 +1,21 @@ import React, { useMemo, useEffect } from "react"; + +import { Dialog } from "@atyrode/excalidraw"; + import { capture } from "../lib/posthog"; import { GoogleIcon, GithubIcon } from "../icons"; import "./AuthDialog.scss"; -import { Dialog } from "@atyrode/excalidraw"; interface AuthDialogProps { description?: React.ReactNode; - warningText?: string; - onClose?: () => void; + warningText?: React.ReactNode; children?: React.ReactNode; } export const AuthDialog = ({ description = <>Welcome to your whiteboard IDE.

Open terminals, VSCode, or Cursor in your pad, and start coding right away., warningText = <>This is an open-source project in beta.
Back up your work!, - onClose, children, }: AuthDialogProps) => { const logoMessages = [ diff --git a/src/frontend/src/ui/MainMenu.tsx b/src/frontend/src/ui/MainMenu.tsx index 5fe4ad2..10c8066 100644 --- a/src/frontend/src/ui/MainMenu.tsx +++ b/src/frontend/src/ui/MainMenu.tsx @@ -4,35 +4,39 @@ import type { ExcalidrawImperativeAPI } from '@atyrode/excalidraw/types'; import type { MainMenu as MainMenuType } from '@atyrode/excalidraw'; import { LogOut, SquarePlus, LayoutDashboard, User, Text, Settings, Terminal, FileText, FlaskConical } from 'lucide-react'; -import AccountDialog from './AccountDialog'; import md5 from 'crypto-js/md5'; + +// Components +import SettingsDialog from './SettingsDialog'; // Added import + import { useLogout } from '../hooks/useLogout'; import { useAuthStatus } from '../hooks/useAuthStatus'; + import { ExcalidrawElementFactory, PlacementMode } from '../lib/elementFactory'; -import "./MainMenu.scss"; import { INITIAL_APP_DATA } from '../constants'; import { capture } from '../lib/posthog'; +import "./MainMenu.scss"; +import AccountDialog from './AccountDialog'; + + // Function to generate gravatar URL const getGravatarUrl = (email: string, size = 32) => { const hash = md5(email.toLowerCase().trim()).toString(); return `https://www.gravatar.com/avatar/${hash}?s=${size}&d=identicon`; }; + interface MainMenuConfigProps { MainMenu: typeof MainMenuType; excalidrawAPI: ExcalidrawImperativeAPI | null; - showPadsModal: boolean; - setShowPadsModal: (show: boolean) => void; - showSettingsModal?: boolean; - setShowSettingsModal?: (show: boolean) => void; } export const MainMenuConfig: React.FC = ({ MainMenu, excalidrawAPI, - setShowPadsModal, - setShowSettingsModal = (show: boolean) => {}, }) => { const [showAccountModal, setShowAccountModal] = useState(false); + const [showSettingsModal, setShowSettingsModal] = useState(false); + const { mutate: logoutMutation, isPending: isLoggingOut } = useLogout(); const { user, isLoading, isError } = useAuthStatus(); @@ -127,13 +131,13 @@ export const MainMenuConfig: React.FC = ({ }); }; - const handleManagePadsClick = () => { - setShowPadsModal(true); - }; - const handleSettingsClick = () => { setShowSettingsModal(true); }; + + const handleCloseSettingsModal = () => { // Added handler to close settings modal + setShowSettingsModal(false); + }; const handleAccountClick = () => { setShowAccountModal(true); @@ -200,6 +204,12 @@ export const MainMenuConfig: React.FC = ({ onClose={() => setShowAccountModal(false)} /> )} + {showSettingsModal && ( // Added conditional rendering for SettingsDialog + + )}
@@ -222,12 +232,6 @@ export const MainMenuConfig: React.FC = ({ - } - onClick={handleManagePadsClick} - > - Manage pads... - diff --git a/src/frontend/src/ui/Range.scss b/src/frontend/src/ui/Range.scss index a8748c3..051c9ce 100644 --- a/src/frontend/src/ui/Range.scss +++ b/src/frontend/src/ui/Range.scss @@ -1,10 +1,3 @@ -:root { - --slider-thumb-size: 16px; - --range-track-filled: #cc6d24; - --range-track-unfilled: #525252; - --range-thumb-color: #a4571b; /* Slightly lighter than track-filled for contrast */ -} - .range { &__control-label { display: flex; @@ -25,6 +18,7 @@ width: 100%; height: 4px; -webkit-appearance: none; + appearance: none; background: var(--range-track-filled); border-radius: 2px; outline: none; diff --git a/src/frontend/src/ui/SettingsDialog.tsx b/src/frontend/src/ui/SettingsDialog.tsx index 6c67deb..6bb4c69 100644 --- a/src/frontend/src/ui/SettingsDialog.tsx +++ b/src/frontend/src/ui/SettingsDialog.tsx @@ -1,8 +1,9 @@ import React, { useState, useCallback, useEffect } from "react"; import { Dialog } from "@atyrode/excalidraw"; import { Range } from "./Range"; -import { UserSettings, DEFAULT_SETTINGS } from "../types/settings"; -// import { capture } from "../lib/posthog"; +import { UserSettings } from "./types"; +import { DEFAULT_SETTINGS } from "../constants"; + import "./SettingsDialog.scss"; interface SettingsDialogProps { diff --git a/src/frontend/src/ui/TabContextMenu.tsx b/src/frontend/src/ui/TabContextMenu.tsx index e81a3f4..2ee5478 100644 --- a/src/frontend/src/ui/TabContextMenu.tsx +++ b/src/frontend/src/ui/TabContextMenu.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from 'react'; +import React, { useRef, useEffect } from 'react'; import clsx from 'clsx'; import './TabContextMenu.scss'; diff --git a/src/frontend/src/ui/Tabs.tsx b/src/frontend/src/ui/Tabs.tsx index 809b454..d7cdcbc 100644 --- a/src/frontend/src/ui/Tabs.tsx +++ b/src/frontend/src/ui/Tabs.tsx @@ -357,7 +357,7 @@ const Tabs: React.FC = ({ children={
titleRefs.current[tab.id] = el} + ref={el => { titleRefs.current[tab.id] = el; }} className={`tab-title ${overflowMap[tab.id] ? 'tab-title-overflow' : ''}`} > {selectedTabId === tab.id && displayPadLoadingIndicator ? "..." : tab.title} @@ -379,7 +379,7 @@ const Tabs: React.FC = ({ children={
titleRefs.current[tab.id] = el} + ref={el => { titleRefs.current[tab.id] = el; }} className={`tab-title ${overflowMap[tab.id] ? 'tab-title-overflow' : ''}`} > {tab.title} diff --git a/src/frontend/src/types/settings.ts b/src/frontend/src/ui/types.ts similarity index 63% rename from src/frontend/src/types/settings.ts rename to src/frontend/src/ui/types.ts index 35e7400..2828219 100644 --- a/src/frontend/src/types/settings.ts +++ b/src/frontend/src/ui/types.ts @@ -10,7 +10,3 @@ export interface UserSettings { */ embedLockDebounceTime?: number; } - -export const DEFAULT_SETTINGS: UserSettings = { - embedLockDebounceTime: 350, // Default value from CustomEmbeddableRenderer.tsx -}; diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index c00abf4..85d8b11 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -614,6 +614,18 @@ dependencies: undici-types "~6.21.0" +"@types/react-dom@^19.0.0": + version "19.1.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.5.tgz#cdfe2c663742887372f54804b16e8dbc26bd794a" + integrity sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg== + +"@types/react@^19.0.0": + version "19.1.6" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.6.tgz#dee39f3e1e9a7d693f156a5840570b6d57f325ea" + integrity sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q== + dependencies: + csstype "^3.0.2" + "@types/unist@^2", "@types/unist@^2.0.0": version "2.0.11" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" @@ -734,6 +746,11 @@ crypto-js@^4.2.0: resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + cytoscape-cose-bilkent@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b"