From 176462b61e9ddb7b0548ee492e1ace65a472ae68 Mon Sep 17 00:00:00 2001 From: Brittney Lilly <185453450+brittneylilly@users.noreply.github.com> Date: Thu, 27 Nov 2025 21:37:51 -0500 Subject: [PATCH 1/2] Dynamically change sidebar text color to adapt to lightness adjustments --- scratchpad.md | 472 --------------------------- src/gui/src/css/style.css | 2 +- src/gui/src/services/ThemeService.js | 2 + 3 files changed, 3 insertions(+), 473 deletions(-) delete mode 100644 scratchpad.md diff --git a/scratchpad.md b/scratchpad.md deleted file mode 100644 index b39c509622..0000000000 --- a/scratchpad.md +++ /dev/null @@ -1,472 +0,0 @@ -# Puter Codebase Research Guide - -## Project Overview - -**Puter** is an open-source Internet OS - a desktop environment in the browser. It's structured as a full-stack application with: -- **Frontend (GUI)**: `src/gui/` - Browser-based desktop environment -- **Backend**: `src/backend/` - Node.js/Express API server -- **SDK**: `src/puter-js/` - JavaScript SDK for apps -- **Additional modules**: Terminal, Git, Emulator, etc. - ---- - -## Architecture Overview - -### Frontend (GUI) - `src/gui/src/` - -#### Entry Point & Initialization -- **`index.js`**: Main entry point, defines `window.gui()` function -- **`initgui.js`**: Initializes GUI, launches services, sets up desktop -- **`init_sync.js`** / **`init_async.js`**: Synchronous and asynchronous initialization - -#### UI Rendering System -- **`UI/`** directory contains all UI components: - - **`UIDesktop.js`**: Main desktop container (wallpaper, taskbar, windows) - - **`UIWindow.js`**: Window component (draggable, resizable windows) - - **`UIComponentWindow.js`**: Wrapper for rendering React-like components in windows - - **`UIElement.js`**: Base UI element class - - **`UI/*.js`**: Various UI components (Login, Settings, Alerts, etc.) - -**How UI is rendered:** -1. HTML strings are generated in UI functions (e.g., `UIWindow`, `UIDesktop`) -2. Components return HTML strings that are inserted into the DOM -3. Event handlers are attached after DOM insertion -4. Components can use `Placeholder` for dynamic content - -**Example flow:** -```javascript -// UIWindow creates HTML string -const win = await UIWindow({ title: "My Window", body_content: html }); - -// Components can be rendered in windows -const win = await UIComponentWindow({ component: myComponent }); -``` - -#### Event Handling - -**Frontend Events:** -- **IPC Events**: `src/gui/src/IPC.js` - Handles inter-process communication - - Listens to `window.addEventListener('message', ...)` - - Routes messages to registered handlers via `window.ipc_handlers` - - Handles app-to-GUI communication - -- **Service Events**: Services use event emitters - - `BroadcastService`: Cross-window communication - - `ProcessService`: Process lifecycle events - - `ThemeService`: Theme change events - -- **DOM Events**: jQuery-based event handling - - Event listeners attached after DOM insertion - - Custom jQuery event handlers in UI components - -**Event Registration Pattern:** -```javascript -// In IPC.js - handlers registered globally -window.ipc_handlers['my-action'] = { - handler: async (params, context) => { /* handle */ } -}; - -// Services emit/listen via globalThis.services -services.emit('event.name', data); -``` - -#### Services Architecture - -**Frontend Services** (`src/gui/src/services/`): -- **`ProcessService.js`**: Manages app processes/windows -- **`IPCService.js`**: Inter-process communication -- **`ThemeService.js`**: Theme management -- **`BroadcastService.js`**: Cross-window messaging -- **`LocaleService.js`**: Internationalization -- **`SettingsService.js`**: User settings -- **`AntiCSRFService.js`**: Security tokens -- **`ExecService.js`**: Execute commands -- **`DebugService.js`**: Debugging utilities - -**Service Pattern:** -```javascript -// Services are registered in initgui.js -register('service-name', new ServiceClass()); - -// Accessed via globalThis.services -const svc = globalThis.services.get('service-name'); -``` - ---- - -### Backend - `src/backend/src/` - -#### Entry Point -- **`index.js`**: Bootstraps the backend -- **`Kernel.js`**: Core kernel that manages services -- **`CoreModule.js`**: Core module installation - -#### API Routing System - -**Route Registration:** -- Routes are registered in **Service classes** via `['__on_install.routes']` method -- Services extend `BaseService` and hook into the service lifecycle -- Routes use Express.js with custom `eggspress` wrapper - -**Key Services that register routes:** -- **`PuterAPIService.js`**: Main API endpoints (auth, filesystem, apps) -- **`FilesystemAPIService.js`**: Filesystem operations -- **`PermissionAPIService.js`**: Permission management -- **`UserProtectedEndpointsService.js`**: User-protected endpoints - -**Route Definition Pattern:** -```javascript -// In a Service class -async ['__on_install.routes'] () { - const { app } = this.services.get('web-server'); - app.use(require('../routers/my-route')); -} - -// Router file uses Endpoint() helper -const Endpoint = require('../util/expressutil').Endpoint; -module.exports = Endpoint({ - route: '/api/my-endpoint', - methods: ['GET', 'POST'], - handler: async (req, res) => { /* ... */ } -}); -``` - -#### Backend Services - -**Service Architecture:** -- Services extend `BaseService` -- Lifecycle hooks: `_construct()`, `_init()`, `['__on_*']` methods -- Services accessed via `this.services.get('service-name')` - -**Key Backend Services:** -- **`WebServerService.js`**: Express server setup -- **`FilesystemService.js`**: Filesystem operations -- **`EventService.js`**: Event emission/listening -- **`PuterHomepageService.js`**: Serves initial HTML page -- **`ExtensionService.js`**: Extension system - -**Service Location:** `src/backend/src/services/` - -#### Event System - -**Backend Events:** -- **`EventService.js`**: Central event system - - `emit(key, data, meta)`: Emit events - - `on(key, callback)`: Listen to events - - Supports wildcard patterns (`event.*`) - -**Event Pattern:** -```javascript -// Emit event -await services.emit('install.routes', { app }); - -// Listen to event -svc_event.on('install.routes', async (key, data, meta) => { - // Handle event -}); -``` - ---- - -## How to Research a Feature - -### Step 1: Identify the Feature Domain - -Determine which part of the system your feature touches: -- **UI/Desktop**: Look in `src/gui/src/UI/` -- **Backend API**: Look in `src/backend/src/routers/` and `src/backend/src/services/` -- **Filesystem**: Look in `src/backend/src/filesystem/` -- **Apps/Processes**: Look at `ProcessService` and IPC system -- **Authentication**: Look in `src/backend/src/routers/auth/` - -### Step 2: Find Similar Features - -**For UI Features:** -1. Search for similar UI components in `src/gui/src/UI/` -2. Look at how they're structured (HTML generation, event handling) -3. Check how they're launched (from desktop, menu, etc.) -4. See what services they use - -**For Backend Features:** -1. Search for similar routes in `src/backend/src/routers/` -2. Check which service registers them -3. See what middleware they use -4. Look at error handling patterns - -**Search Strategy:** -```bash -# Use codebase_search to find similar features -# Example: "How does file upload work?" -# Example: "How are windows created and displayed?" -# Example: "How are API endpoints authenticated?" -``` - -### Step 3: Trace the Flow - -**For UI Features:** -1. **Entry Point**: Where is the UI triggered? (menu, button, IPC message) -2. **UI Component**: Which UI component renders it? (`UIWindow`, `UIDesktop`, etc.) -3. **Event Handlers**: Where are events registered? (in component, IPC.js, services) -4. **API Calls**: What backend endpoints are called? (check `puter.*` SDK calls) -5. **State Management**: How is state stored? (services, KV store, DOM) - -**For Backend Features:** -1. **Route Registration**: Which service registers the route? -2. **Middleware**: What middleware runs? (auth, validation, etc.) -3. **Handler**: What does the handler do? -4. **Services Used**: Which backend services are called? -5. **Database/Storage**: How is data persisted? - -### Step 4: Understand Dependencies - -**Frontend Dependencies:** -- **SDK**: `puter.*` API calls (from `src/puter-js/`) -- **Services**: `globalThis.services.get('service-name')` -- **IPC**: `window.ipc_handlers` for app communication -- **Libraries**: jQuery, Socket.io, etc. - -**Backend Dependencies:** -- **Services**: `this.services.get('service-name')` -- **Database**: Entity storage, SQL queries -- **Filesystem**: `FilesystemService` for file operations -- **Events**: `EventService` for cross-service communication - -### Step 5: Document Your Findings - -Create a summary with: -- **Feature Location**: Files involved -- **Data Flow**: Request → Handler → Response -- **UI Flow**: Trigger → Component → Events → API → Update -- **Services Used**: Which services are involved -- **Similar Patterns**: How similar features work -- **Key Functions**: Important functions to understand - ---- - -## Key Directories Reference - -### Frontend (`src/gui/src/`) - -| Directory | Purpose | -|-----------|---------| -| `UI/` | All UI components (windows, dialogs, desktop) | -| `services/` | Frontend services (process, theme, IPC, etc.) | -| `helpers/` | Utility functions for UI operations | -| `i18n/` | Internationalization/translations | -| `IPC.js` | Inter-process communication handler | -| `initgui.js` | GUI initialization and service setup | -| `index.js` | Entry point, defines `window.gui()` | - -### Backend (`src/backend/src/`) - -| Directory | Purpose | -|-----------|---------| -| `routers/` | API route handlers | -| `services/` | Backend services (filesystem, auth, etc.) | -| `modules/` | Feature modules (web, core, puterai, etc.) | -| `filesystem/` | Filesystem operations and strategies | -| `middleware/` | Express middleware (auth, CSRF, etc.) | -| `api/` | API utilities (eggspress, validators) | -| `entities/` | Database entities | -| `om/` | Object mapping/ORM system | - -### SDK (`src/puter-js/src/`) - -| Directory | Purpose | -|-----------|---------| -| `services/` | SDK services (XDIncoming, etc.) | -| `lib/` | SDK libraries and utilities | - ---- - -## Common Patterns - -### Pattern 1: Creating a New UI Window - -```javascript -// 1. Create UI component in src/gui/src/UI/UIWindowMyFeature.js -async function UIWindowMyFeature(options) { - let html = ''; - // Generate HTML - html += `
...
`; - - const win = await UIWindow({ - title: "My Feature", - body_content: html, - width: 600, - height: 400 - }); - - // Attach event handlers after DOM insertion - $(win).on('click', '.my-button', async () => { - // Handle click - }); - - return win; -} - -// 2. Export and use -export default UIWindowMyFeature; -// Import and call: await UIWindowMyFeature({ ... }); -``` - -### Pattern 2: Creating a Backend API Endpoint - -```javascript -// 1. Create router in src/backend/src/routers/my-feature.js -const Endpoint = require('../util/expressutil').Endpoint; - -module.exports = Endpoint({ - route: '/api/my-feature', - methods: ['POST'], - handler: async (req, res) => { - const { services } = req.ctx; - // Use services - const result = await doSomething(); - res.json({ success: true, data: result }); - } -}); - -// 2. Register in a Service -// In src/backend/src/services/MyService.js -async ['__on_install.routes'] () { - const { app } = this.services.get('web-server'); - app.use(require('../routers/my-feature')); -} -``` - -### Pattern 3: Using Services - -**Frontend:** -```javascript -// Get service -const svc_process = globalThis.services.get('process'); - -// Use service methods -const process = svc_process.get_by_uuid(uuid); -``` - -**Backend:** -```javascript -// In a service method -const { services } = this; -const svc_fs = services.get('filesystem'); -const result = await svc_fs.read(path); -``` - -### Pattern 4: Event Handling - -**Frontend Events:** -```javascript -// Listen to IPC messages -window.ipc_handlers['my-action'] = { - handler: async (params, { ipc_context }) => { - // Handle message - } -}; - -// Use BroadcastService for cross-window -const svc_broadcast = globalThis.services.get('broadcast'); -svc_broadcast.emit('event-name', data); -``` - -**Backend Events:** -```javascript -// Emit event -await services.emit('my.event', { data: 'value' }); - -// Listen to event (in a service) -svc_event.on('my.event', async (key, data, meta) => { - // Handle event -}); -``` - ---- - -## Research Checklist - -Before implementing a feature, answer these questions: - -### UI Features -- [ ] Where is similar UI code located? -- [ ] How is the UI component structured? (HTML generation, event handlers) -- [ ] How is the component launched/triggered? -- [ ] What services does it use? -- [ ] How does it communicate with backend? (API calls, IPC) -- [ ] How is state managed? (services, KV store, DOM) -- [ ] What events are involved? (user actions, IPC, broadcasts) - -### Backend Features -- [ ] Where are similar API endpoints located? -- [ ] Which service registers the route? -- [ ] What middleware is used? (auth, validation, etc.) -- [ ] What services are called in the handler? -- [ ] How is data validated? -- [ ] How are errors handled? -- [ ] How is data persisted? (database, filesystem) - -### Integration -- [ ] How does frontend call the backend? -- [ ] What data format is used? (JSON, form data, etc.) -- [ ] How are errors communicated back? -- [ ] Are there any security considerations? (CSRF, auth, validation) - ---- - -## Example: Researching a File Upload Feature - -### Step 1: Find Similar Features -- Search: "How does file upload work?" -- Found: `src/gui/src/helpers/download.js` (opposite direction) -- Found: `src/backend/src/routers/writeFile/` (file writing) - -### Step 2: Trace the Flow -1. **UI Trigger**: User drags file or clicks upload button -2. **UI Component**: File picker or drag-drop handler -3. **API Call**: `puter.fs.write()` or direct API call -4. **Backend Route**: `/api/filesystem/write` or similar -5. **Handler**: Validates, processes, saves file -6. **Response**: Success/error back to frontend -7. **UI Update**: Refresh file list, show notification - -### Step 3: Key Files -- Frontend: `src/gui/src/helpers/` (upload helpers) -- Backend: `src/backend/src/routers/writeFile/` -- Service: `src/backend/src/services/FilesystemService.js` -- SDK: `src/puter-js/src/` (SDK methods) - -### Step 4: Services Used -- `FilesystemService`: File operations -- `ProcessService`: If app-based upload -- `AntiCSRFService`: Security tokens - ---- - -## Tips for Effective Research - -1. **Use Semantic Search**: Use `codebase_search` with descriptive questions -2. **Follow Imports**: Trace `import`/`require` statements to understand dependencies -3. **Check Service Lifecycle**: Understand when services are initialized -4. **Look for Patterns**: Similar features follow similar patterns -5. **Read Comments**: Code comments often explain architecture decisions -6. **Check Tests**: Tests show expected behavior -7. **Trace Data Flow**: Follow data from UI → API → Database and back - ---- - -## Next Steps - -When you're ready to implement a feature: - -1. **Create a TODO list** with specific tasks -2. **Start with similar code** as a template -3. **Implement incrementally** - UI first, then backend, then integration -4. **Test each layer** independently -5. **Follow existing patterns** for consistency -6. **Update this document** with your findings - ---- - -*Last updated: [Current Date]* -*Use this guide as a living document - update it as you learn more about the codebase!* - diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 4c7d1637e2..a1edcfa762 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1243,7 +1243,7 @@ span.header-sort-icon img { margin-top: 2px; padding: 4px; border-radius: 3px; - color: #444444; + color: var(--window-sidebar-title-color); font-size: 13px; cursor: pointer; transition: 0.15s background-color; diff --git a/src/gui/src/services/ThemeService.js b/src/gui/src/services/ThemeService.js index b49d41e684..4fc08b76d5 100644 --- a/src/gui/src/services/ThemeService.js +++ b/src/gui/src/services/ThemeService.js @@ -121,6 +121,8 @@ export class ThemeService extends Service { this.root.style.setProperty('--primary-lightness', s.lig + '%'); this.root.style.setProperty('--primary-alpha', s.alpha); this.root.style.setProperty('--primary-color', s.light_text ? 'white' : '#373e44'); + // window sidebar title color + this.root.style.setProperty('--window-sidebar-title-color', s.lig <= 50.00 ? 'white' : 'black'); // TODO: Should we debounce this to reduce traffic? this.#broadcastService.sendBroadcast('themeChanged', { From 22b06205d4f7612b981ec66dc3e952a7bb8f3bdb Mon Sep 17 00:00:00 2001 From: Brittney Lilly <185453450+brittneylilly@users.noreply.github.com> Date: Tue, 2 Dec 2025 20:45:05 -0500 Subject: [PATCH 2/2] Fix unreadability of sidebar header text color Sidebar header text in file explorer windows becomes unreadable at certain lightness settings controlled by the UI colors lightness setting under the personalization options. Removed the hard coded color of the sidebar header text. The text color now dynamically adjusts with the lightness settings and stays readable at the full range of lightness settings. Resolves: Issue #2 --- src/gui/src/css/style.css | 2 +- src/gui/src/services/ThemeService.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index a1edcfa762..22431f6fbe 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1255,7 +1255,7 @@ span.header-sort-icon img { } .window-sidebar-item-active, .window-sidebar-item-drag-active, .window-sidebar-item-active:hover { - background-color: #fefeff; + background-color: #535153; } .window-sidebar-item-placeholder { diff --git a/src/gui/src/services/ThemeService.js b/src/gui/src/services/ThemeService.js index 4fc08b76d5..6d994546d0 100644 --- a/src/gui/src/services/ThemeService.js +++ b/src/gui/src/services/ThemeService.js @@ -123,6 +123,7 @@ export class ThemeService extends Service { this.root.style.setProperty('--primary-color', s.light_text ? 'white' : '#373e44'); // window sidebar title color this.root.style.setProperty('--window-sidebar-title-color', s.lig <= 50.00 ? 'white' : 'black'); + // TODO: Should we debounce this to reduce traffic? this.#broadcastService.sendBroadcast('themeChanged', {