Commit Graph

1614 Commits

Author SHA1 Message Date
Steven 6523891982 fix: react hooks order violation in MemoDetail when creating comments
Replace dynamic hook mapping with useMemoComments hook to fetch all comments
via listMemoComments API, ensuring consistent hook order across renders and
fixing page load failure after comment creation.
2025-12-25 23:40:42 +08:00
Steven c4dfb85400 fix: ensure dispatch is used for actions in useMemoInit hook 2025-12-25 23:17:34 +08:00
Steven d4e08ae2bd refactor(react-query): optimize config, add error boundary, and remove JSDoc
This commit combines multiple improvements to the React Query migration:

Performance Optimization:
- Increase default staleTime from 10s to 30s for better performance
- Reduces unnecessary network requests while maintaining data freshness

Error Handling:
- Add ErrorBoundary component with user-friendly error UI
- Integrated at app root level for comprehensive coverage
- Provides error details and reload option

Documentation:
- Add docs/auth-architecture.md explaining AuthContext design decisions
- Document why AuthContext is preferred over React Query for current user

Code Cleanup:
- Remove all JSDoc comments from hooks and components
- Keep essential inline comments for clarity
- Simplifies code readability

Files modified:
- src/lib/query-client.ts - Optimized staleTime
- src/main.tsx - Added ErrorBoundary wrapper
- src/components/ErrorBoundary.tsx - New component
- src/hooks/useMemoQueries.ts - Removed JSDoc
- src/hooks/useUserQueries.ts - Removed JSDoc
- src/components/PagedMemoList/PagedMemoList.tsx - Removed JSDoc
- docs/auth-architecture.md - New documentation

All changes verified with TypeScript compilation and production build.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 08:47:36 +08:00
Steven b2e2b6426c perf(react-query): fix context re-renders and improve type safety
Optimizes React Query migration with performance and consistency improvements:

Performance:
- Memoize AuthContext and InstanceContext provider values to prevent unnecessary re-renders
- Convert InstanceContext getter functions to useMemo hooks
- Fix refetchSettings to avoid state dependency that caused frequent recreations

Type Safety:
- Replace 'any' types in useAttachmentQueries with proper protobuf types
- Add Attachment and ListAttachmentsRequest type imports

Query Key Consistency:
- Replace hardcoded ["users", "stats"] with userKeys.stats() factory function
- Ensures consistent cache key management across mutations

Developer Experience:
- Rename unused useCurrentUser to useCurrentUserQuery to avoid confusion
- Add documentation explaining AuthContext-based vs React Query current user hooks
- Update internal references in useNotifications and useTagCounts

All changes verified with TypeScript compilation and build tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 08:29:34 +08:00
Johnny f87f728b0f
feat: react query migration (#5379) 2025-12-24 22:59:18 +08:00
Johnny 4109fe3245 chore(MemoEditor): enhance focus mode handling and improve editor layout 2025-12-23 20:11:38 +08:00
Johnny 595daaa163 style: organize imports in MemoView hooks 2025-12-23 19:33:31 +08:00
Johnny 0f9322ea11 fix(MemoEditor): dispatch toggleFocusMode action properly
- Wrap actions.toggleFocusMode() with dispatch() call
- Create toggleFocusMode helper function for callbacks
- Fix focus mode not toggling due to action not being dispatched
2025-12-23 19:30:38 +08:00
Johnny 201a0466e9 fix(MemoEditor): restore focus mode functionality
- Add useFocusMode hook to lock body scroll in focus mode
- Add 'f' key keyboard shortcut to toggle focus mode
- Add FocusModeExitButton inside editor
- Import and wire up all focus mode components and hooks
- Update useKeyboard to handle focus mode toggle
2025-12-23 19:20:21 +08:00
Johnny ca84241b8a fix(MemoEditor): restore focus mode styles
- Import and use FOCUS_MODE_STYLES from constants
- Apply proper fixed positioning, shadow, and spacing in focus mode
- Add transition animation for smooth mode switching
- Replace empty 'focus-mode' class with actual Tailwind utilities
2025-12-23 19:18:24 +08:00
Johnny f2bc115a1d fix(MemoEditor): restore wrapper styles removed by refactoring
- Add back Tailwind utility classes for proper layout
- Restore padding, border, background, and flex styles
- Fix missing styles on memo-editor-wrapper element
2025-12-23 19:17:00 +08:00
Johnny 735dd1fe4b style(MemoView): restore comments and formatting
- Add back descriptive comments removed by editor refactoring commit
- Restore original timestamp calculation format in MemoHeader
- Improve code readability with section comments
2025-12-23 19:05:29 +08:00
Johnny e61d594ded refactor(MemoView): improve maintainability and code organization
Complete refactoring of MemoView components for better code quality:

- Split useMemoViewState into individual hook files (useMemoActions,
  useKeyboardShortcuts, useNsfwContent, useImagePreview, useMemoCreator)
  for single responsibility principle
- Consolidate types closer to usage - move hook-specific types to
  respective files, keep only component props in shared types.ts
- Optimize context with separate static/dynamic memoization to reduce
  unnecessary re-renders
- Simplify barrel exports to only expose public API (MemoView component
  and MemoViewProps type)
- Add comprehensive JSDoc documentation to all public APIs with usage
  examples

Benefits:
- Better maintainability: each hook file has one clear purpose
- Improved performance: context optimization prevents unnecessary re-renders
- Enhanced developer experience: clear documentation and encapsulation
- Cleaner architecture: public API is minimal, internal details hidden

All automated checks pass (TypeScript compilation, linter, production build).
2025-12-23 19:01:57 +08:00
Johnny 1b11e8c841 refactor(editor): complete state machine and services migration
BREAKING CHANGE: MemoEditor internal architecture completely refactored

## Summary

Refactored MemoEditor from hooks-based state management to a three-layer
architecture (Presentation → State → Services) using useReducer pattern.

## Changes

### Architecture
- **State Layer** (5 new files): types, actions, reducer, context, barrel export
- **Service Layer** (6 new files): error, validation, upload, cache, memo services + barrel
- **Component Layer** (3 new files): EditorToolbar, EditorContent, EditorMetadata
- **Simplified Hooks** (3 new files): useMemoInit, useAutoSave, useKeyboard

### Code Reduction
- Main component: ~380 lines → ~140 lines (-63%)
- Hooks removed: 5 old hooks (useMemoEditorState, useMemoSave, etc.)
- Total lines removed: 508 lines of old code
- Utility hooks preserved: 8 hooks still in use (useLocation, useDragAndDrop, etc.)

### Improvements
-  Predictable state transitions with useReducer
-  Testable business logic in pure service functions
-  Cleaner component code (presentation only)
-  Better separation of concerns
-  Type-safe actions with discriminated unions
-  Centralized error handling

## Statistics
- Files changed: 26
- Commits created: 25 (squashed into 1)
- New files: 17
- Removed files: 5
- TypeScript errors: 0
- Lint errors: 0

## Testing
Manual testing required for:
- Editor functionality (create, edit, save)
- Drag and drop
- Focus mode
- Keyboard shortcuts (Cmd/Ctrl + Enter)
- Auto-save to localStorage
2025-12-23 08:38:02 +08:00
Johnny 8a7c976758 refactor: streamline tag sorting and update coordinate handling in MemoEditor components 2025-12-22 22:54:09 +08:00
Johnny d537591005 feat: add slash commands tooltip to InsertMenu 2025-12-22 22:42:23 +08:00
Steven f9dd7ad853 style: improve code block styling and formatting
- Adjust CodeBlock styling for better layout and spacing
- Reorganize copy button positioning with absolute positioning
- Simplify button styling and reduce icon sizes
- Wrap MermaidBlock in pre tag for consistent structure
- Format useDropdownMenuSubHoverDelay hook call for readability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-22 21:27:50 +08:00
Steven dfc0d376d1 refactor: extract submenu hover delay logic into reusable hook
- Create useDropdownMenuSubHoverDelay hook in dropdown-menu component
- Encapsulates hover delay behavior for preventing accidental submenu closure
- Eliminates code duplication at component usage sites
- Simplifies InsertMenu by removing 45 lines of timeout/state management code
- Hook provides handleTriggerEnter/Leave and handleContentEnter/Leave handlers
- Configurable closeDelay parameter (default 150ms)

This makes the hover behavior pattern reusable across any dropdown menu submenus.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-22 21:04:00 +08:00
Steven 332d32bd35 fix: render dates correctly in memo detail sidebar and link dialog
Convert protobuf Timestamp objects to Date before formatting
to prevent "[object Object]" from appearing in the UI.

Fixes #5368
2025-12-22 20:24:04 +08:00
Steven be7ef74698 fix: eliminate duplicate API requests by deduplicating user fetch calls
- Add request deduplication to getOrFetchUser using RequestDeduplicator
- Consolidates multiple simultaneous calls for same user into single API request
- Prevents duplicate 401 errors and wasted network traffic
- Matches pattern already used by fetchUsers and fetchUserStats
- Remove backwards compatibility aliases (getOrFetchUserByName, getOrFetchUserByUsername)
- Update all call sites to use canonical getOrFetchUser method

Fixes issue where PagedMemoList, useMemoViewState, MainLayout, and UserProfile
were making duplicate user fetch requests when loading user data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-22 20:12:44 +08:00
Johnny 6b0f90f355 chore: prevent sensitive data caching 2025-12-20 12:33:16 +08:00
Johnny eaef04a0a0 chore: fix linter 2025-12-20 11:55:00 +08:00
Steven d236ef1611 feat(web): add glassmorphism map controls with Google Maps integration
- Add custom zoom controls with modern glassmorphism styling
- Add "Open in Google Maps" button for location markers
- Refactor to React component architecture with proper Leaflet integration
- Create reusable GlassButton component for maintainability
- Use React 18 createRoot for portal rendering
- Replace imperative DOM manipulation with declarative React patterns
- Add coordinate display to location metadata

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 00:18:01 +08:00
Steven d0c3908168 refactor: remove deprecated Sessions and AccessTokens settings
- Remove ListSessions and RevokeSession RPC endpoints
- Remove Session message and SessionsSetting from UserSetting
- Remove ACCESS_TOKENS key and AccessTokensSetting
- Update references to use RefreshTokensUserSetting with its own ClientInfo
- Remove UserSessionsSection frontend component
- Clean up user store to remove session and access token settings
- Regenerate protobuf files

The system now uses:
- REFRESH_TOKENS for session management with sliding expiration
- PERSONAL_ACCESS_TOKENS for long-lived API tokens
2025-12-19 08:35:57 +08:00
Johnny 50606a850e fix(auth): resolve token refresh and persistence issues
- Fix cookie expiration timezone to use GMT (RFC 6265 compliance)
- Use Connect RPC client for token refresh instead of fetch
- Fix error code checking (numeric Code.Unauthenticated instead of string)
- Prevent infinite redirect loop when already on /auth page
- Fix protobuf Timestamp conversion using timestampDate helper
- Store access token in sessionStorage to avoid unnecessary refreshes on page reload
- Add refresh token cookie fallback for attachment authentication
- Improve error handling with proper type checking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 20:56:54 +08:00
Johnny 7932f6d0d0
refactor: user auth improvements (#5360) 2025-12-18 18:15:51 +08:00
Johnny 2c2ef53737 chore: fix frontend linter 2025-12-17 09:04:05 +08:00
Johnny 642271a831 feat: add iframe support for embedded videos in markdown content 2025-12-17 08:52:59 +08:00
Steven 87b8c2b2d2 refactor(web): rename grpcweb.ts to connect.ts and enable binary format
- Rename grpcweb.ts to connect.ts to reflect ConnectRPC usage
- Enable binary protobuf format for improved performance
- Update all imports across 26 files from @/grpcweb to @/connect

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 20:15:16 +08:00
Steven b1a52f20ed fix(web): add clipboard fallback for CodeBlock copy button in non-secure contexts
The CodeBlock component was refactored in v0.25.3 to use navigator.clipboard.writeText(),
which requires HTTPS or localhost. This caused the copy button to fail silently for users
accessing Memos over HTTP.

This fix adds a fallback to the copy-to-clipboard library (already used by all other
copy operations in the codebase) when the native clipboard API is unavailable or fails,
ensuring the copy button works reliably in all deployment scenarios.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 22:51:34 +08:00
Steven a2ddf05933 chore: fix linter 2025-12-15 19:58:58 +08:00
Steven 1b3318f886 refactor(web): improve ActivityCalendar maintainability and add Calendar page
- Extract shared utilities and constants to eliminate code duplication
- Create dedicated Calendar page with year view and month grid
- Add date filter navigation with bidirectional URL sync
- Fix useTodayDate memoization bug causing stale date references
- Standardize naming conventions (get vs generate functions)
- Add comprehensive type exports and proper store encapsulation
- Implement size variants for compact calendar display

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 19:47:46 +08:00
Steven 8a7e00886d fix(web): convert enum values to string names in API resource paths
Frontend was incorrectly using numeric enum values (e.g., 1, 2, 3) instead
of string names (e.g., "GENERAL", "STORAGE") when constructing API resource
paths. This caused the backend to fail with "unsupported instance setting
key: INSTANCE_SETTING_KEY_UNSPECIFIED" errors during initialization.

Changes:
- Add helper functions in store/common.ts to convert enum values to names
  - getInstanceSettingKeyName() and buildInstanceSettingName()
  - getUserSettingKeyName() and buildUserSettingName()
- Update instance store to use string enum names in API calls
- Update user store to use string enum names in API calls
- Update all components to use new helper functions for setting names

Fixes enum string conversion for:
- InstanceSetting_Key (6 locations)
- UserSetting_Key (2 locations)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 20:08:11 +08:00
Johnny edd3ced9bf
refactor: migrate to connect-rpc (#5338) 2025-12-11 19:49:07 +08:00
Steven 3dc740c752 refactor(web): improve locale/theme preference initialization
- Extract preference logic into dedicated hooks (useUserLocale, useUserTheme)
- Add applyLocaleEarly() for consistent early application
- Remove applyUserPreferences() from user store (now redundant)
- Simplify App.tsx by moving effects to custom hooks
- Make locale/theme handling consistent and reactive
- Clean up manual preference calls from sign-in flows

Fixes locale not overriding localStorage on user login.
Improves maintainability with better separation of concerns.
2025-12-11 07:59:52 +08:00
spaghetti-coder 7479205e21
fix(ui): change focus search bar shortcut overlapping with url shortcut (#5336) 2025-12-11 07:56:20 +08:00
Steven 48ce4ccc26 fix(web): disable setext header syntax (#5314)
Add custom remark plugin to prevent setext headers (headers using === or --- underlines) from being recognized by the markdown parser. The plugin disables the setextUnderline construct at the micromark parser level.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 09:07:54 +08:00
spaghetti-coder 9ea27ee61f
fix(ui): fix todo command does nothing (#5329) 2025-12-09 08:20:57 +08:00
spaghetti-coder 618db89f4f
fix(ui): remove unsupported highlight command (#5328) 2025-12-09 07:57:28 +08:00
Steven 4668c4714b refactor(web): improve MemoContent security and maintainability
Security improvements:
- Add rehype-sanitize for XSS protection in markdown content
- Remove DOMPurify and deprecated __html code block feature
- Extract sanitize schema to constants with comprehensive documentation

Maintainability improvements:
- Extract SANITIZE_SCHEMA to constants.ts for better organization
- Create utils.ts with shared code extraction utilities
- Refactor CodeBlock and MermaidBlock to use shared utilities
- Rename PreProps to CodeBlockProps for clarity
- Reduce code duplication across components

Dependency cleanup:
- Remove explicit katex dependency (now transitive via rehype-katex)
- Remove @matejmazur/react-katex (unused)
- Remove dompurify (replaced by rehype-sanitize)
- Update vite config to remove katex-vendor chunk

Changes: 7 files changed, 84 insertions(+), 100 deletions(-)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 22:45:22 +08:00
Steven d9f8bc80f0 feat(web): add LaTeX math rendering support to MemoContent
Integrates remark-math and rehype-katex plugins to enable LaTeX mathematical expressions in memos. Users can now write inline math ($...$) and display math ($$...$$) using standard LaTeX syntax.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 22:08:45 +08:00
Steven 81da20c905 refactor: simplify theme/locale to user preferences and improve initialization
Remove theme and locale from instance settings to eliminate duplication and
simplify the codebase. These are user-specific preferences and should only
exist in user settings, not instance-wide settings.

Backend changes:
- Remove theme from InstanceGeneralSetting proto
- Remove locale from InstanceCustomProfile proto
- Update instance service converters to remove theme/locale handling
- Simplify RSS feed to use static locale

Frontend changes:
- Remove theme/locale from instanceStore state
- Create unified initialization flow with clear fallback priority:
  * Theme: user setting → localStorage → system preference
  * Locale: user setting → browser language
- Add applyUserPreferences() to centralize theme/locale application
- Simplify App.tsx by removing redundant state synchronization
- Update all components to use new helper functions:
  * getThemeWithFallback() for theme resolution
  * getLocaleWithFallback() for locale resolution
- Remove theme/locale selectors from instance profile dialog

Theme utilities refactor:
- Organize code into clear sections with JSDoc comments
- Extract localStorage operations into getStoredTheme/setStoredTheme helpers
- Split DOM manipulation into focused functions
- Improve type safety with Theme and ResolvedTheme types
- Reduce code duplication and improve maintainability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 09:08:46 +08:00
Steven 8154a411a9 fix(web): allow only one active tag filter at a time
Previously, clicking multiple tags would add them all as active filters. Now clicking a new tag automatically clears any existing tag filters before applying the new one, ensuring only one tag can be filtered at a time. Clicking an already-active tag still deselects it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 08:40:43 +08:00
Steven fae5eac31b fix(web): fix infinite loop in MemoEditor and improve React/MobX integration
- Wrap all setter functions in useMemoEditorState with useCallback to ensure stable references
  This prevents infinite loops when setters are used in useEffect dependencies (fixes "Maximum update depth exceeded" error)
- Extract MobX observable values in useMemoFilters and useMemoSorting before using them in useMemo dependencies
  This prevents React from tracking MobX observables directly, improving reliability
- Add comprehensive documentation explaining the design decisions for future maintainability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 08:54:40 +08:00
Johnny a6a8997f4c chore: tweak comments 2025-11-30 13:16:02 +08:00
Johnny 07072b75a7 chore: reorganize reaction components 2025-11-30 12:48:21 +08:00
Johnny 6dcf7cc74c chore: enhance MemoView component structure 2025-11-30 12:41:24 +08:00
Johnny 7aa8262ef2 chore: streamline MemoEditor components and remove unused code 2025-11-30 12:30:00 +08:00
Johnny 2516cdf2b4 refactor: clean up MemoView and MemoEditor component architecture
This commit refactors MemoView and MemoEditor components for better
maintainability, introducing React Context, custom hooks, and improved
folder structure.

MemoView improvements:
- Introduce MemoViewContext to eliminate prop drilling
- Reduce MemoHeader props from 18 to 8
- Reduce MemoBody props from 9 to 4
- Extract custom hooks: useMemoViewDerivedState, useMemoEditor,
  useMemoHandlers for better separation of concerns
- Fix React hooks ordering bug in edit mode

MemoEditor improvements:
- Extract state management into useMemoEditorState hook
- Extract keyboard handling into useMemoEditorKeyboard hook
- Extract event handlers into useMemoEditorHandlers hook
- Extract initialization logic into useMemoEditorInit hook
- Reduce main component from 461 to 317 lines (31% reduction)

Folder structure cleanup:
- Move SortableItem to memo-metadata (correct location)
- Move ErrorBoundary to components folder
- Flatten Toolbar/InsertMenu structure (remove unnecessary nesting)
- Consolidate hooks in main hooks folder
- Consolidate types in main types folder

Benefits:
- Better separation of concerns
- Improved testability
- Easier maintenance
- Cleaner code organization
- No functionality changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 11:15:20 +08:00
Johnny bb7e0cdb79 refactor: remove enable link preview setting
- Remove enable_link_preview field from proto definitions
- Remove setting UI from MemoRelatedSettings component
- Remove translations from all 33 locale files
- Regenerate proto files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 10:34:22 +08:00
Johnny 5fb6f8eccf refactor: remove legacy disable markdown shortcuts setting
- Remove disable_markdown_shortcuts field from proto definitions
- Remove setting UI from MemoRelatedSettings component
- Enable markdown shortcuts permanently in MemoEditor
- Remove translations from all 32 locale files
- Fix TypeScript error in useMemoSave hook by using typed translation function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 10:30:55 +08:00
Johnny 2b7b70ebfe chore: fix linter 2025-11-30 10:15:20 +08:00
Johnny 1ef11f7470 refactor: implement MemoView component with subcomponents and hooks
- Added MemoView component to display a single memo card with full functionality including creator info, memo content, attachments, reactions, and comments.
- Created MemoBody and MemoHeader subcomponents to separate concerns and improve maintainability.
- Introduced custom hooks for managing memo actions, keyboard shortcuts, NSFW content visibility, and image preview.
- Implemented reaction handling with new ReactionSelector and ReactionView components.
- Added TypeScript types for better type safety and clarity.
- Established constants for memo card styling and keyboard shortcuts.
- Removed legacy ReactionSelector and ReactionView components from the previous structure.
2025-11-29 23:21:35 +08:00
Johnny 50199fe998 feat: add LocationDialog and related hooks for location management in MemoEditor
- Implemented LocationDialog component for selecting and entering location coordinates.
- Created useLocation hook to manage location state and updates.
- Added LocationState type for managing location data.
- Introduced useLinkMemo hook for linking memos with search functionality.
- Added VisibilitySelector component for selecting memo visibility.
- Refactored MemoEditor to integrate new hooks and components for improved functionality.
- Removed obsolete handlers and streamlined memo save logic with useMemoSave hook.
- Enhanced focus mode functionality with dedicated components for overlay and exit button.
2025-11-28 09:21:53 +08:00
Chriss c1765fc246
feat: add midnight theme (#5288) 2025-11-27 21:21:57 +08:00
Steven 05f7c9606b fix: add HTML sanitization and dynamic theme loading 2025-11-26 20:34:52 +08:00
Steven 363bc9f455 fix(web): add missing tag styles and unify primary color across themes
Tags were missing CSS styles, appearing as plain text. Added text-primary
styling to Tag component and updated default theme primary color to match
other themes (blue hue 250, chroma 0.08) for consistency.

Fixes #5282

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 20:25:28 +08:00
Steven 5a16f8009f fix(markdown): render single newlines as line breaks
Add remark-breaks plugin to render single newlines as <br> tags,
matching GitHub Flavored Markdown behavior.

Fixes https://github.com/usememos/memos/issues/5277

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 20:13:57 +08:00
Steven 8ec4c9ab63 fix(web): update time locale when language is changed
Pass i18n.language to time display components to ensure locale updates
when the user switches languages in UserMenu. Changes:

- MemoView: Pass i18n.language to toLocaleString() and <relative-time> lang attribute
- MonthNavigator: Wrap with observer to make component reactive to i18n.language changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:37:04 +08:00
Steven ef6456a4f5 refactor(web): restructure MemoEditor with custom hooks and improved error handling
Extract reusable logic into custom hooks (useLocalFileManager, useDragAndDrop, useDebounce, useAbortController), add ErrorBoundary for resilience, and centralize constants. Fix cursor positioning bugs, useEffect dependency issues, and add geocoding request cancellation. Improve performance with debounced localStorage writes and ref-based flags.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:29:54 +08:00
Steven 424e599980 refactor(web): optimize memo statistics fetching by using cached data from memo store 2025-11-24 21:37:12 +08:00
Steven 72f93c5379 feat(web): enhance file upload handling with local file support and preview 2025-11-24 21:31:18 +08:00
Steven cabd0d61c6 fix(web): resolve Leaflet DOM cleanup error causing app crashes
- Add MapCleanup component to properly remove Leaflet map instances on unmount
- Fix LocationMarker initialization with useRef to prevent re-initialization
- Remove problematic key prop in LocationDialog that caused unnecessary remounts
- Fix goimports formatting in tag parser

Fixes #5260
2025-11-19 22:21:01 +08:00
Neo 4de8712cb0
fix: keyboard shortcuts (#5250) 2025-11-17 08:55:57 +08:00
Johnny 357118804e feat(web): add Focus Mode UI entry in Insert Menu
Add discoverable UI entry point for Focus Mode via Insert Menu submenu:

UI Changes:
- Add "View" submenu to Insert Menu (+ button dropdown)
- Nested menu with Focus Mode option (ChatGPT-style pattern)
- Display keyboard shortcut hint (⌘⇧F) next to menu item
- Uses DropdownMenuSub components from Radix UI

User Access Methods:
1. Keyboard: Cmd/Ctrl+Shift+F (primary, power users)
2. Mouse: + menu → View → Focus Mode (discoverable)
3. Mobile: Touch-friendly menu access

Benefits:
- Improves discoverability for new users
- Doesn't clutter main editor UI
- Educates users about keyboard shortcut
- Extensible for future view options (typewriter, reading mode, etc.)
- Follows familiar UI patterns (ChatGPT, Notion)

Files Modified:
- web/src/components/MemoEditor/ActionButton/InsertMenu.tsx
  * Add DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent
  * Add View submenu with Focus Mode entry
  * Add onToggleFocusMode prop
- web/src/components/MemoEditor/index.tsx
  * Pass toggleFocusMode to InsertMenu component
- web/src/locales/en.json
  * Add "editor.view" translation key
2025-11-17 08:55:10 +08:00
Johnny c8162ff3cc feat(web): add Focus Mode for distraction-free writing
Add keyboard-activated Focus Mode to provide an immersive writing experience:

Features:
- Toggle with Cmd/Ctrl+Shift+F (matches GitHub, Google Docs)
- Exit with Escape, toggle shortcut, button click, or backdrop click
- Expands editor to ~80-90% of viewport with centered layout
- Semi-transparent backdrop with blur effect
- Maintains all editor functionality (attachments, shortcuts, etc.)
- Smooth 300ms transitions

Responsive Design:
- Mobile (< 640px): 8px margins, 50vh min-height
- Tablet (640-768px): 16px margins
- Desktop (> 768px): 32px margins, 60vh min-height, 1024px max-width

Implementation:
- Centralized constants for easy maintenance (FOCUS_MODE_STYLES)
- Extracted keyboard shortcuts and heights to named constants
- JSDoc documentation for all new functions and interfaces
- TypeScript type safety with 'as const'
- Explicit positioning (top/left/right/bottom) to avoid width overflow

Files Modified:
- web/src/components/MemoEditor/index.tsx - Main Focus Mode logic
- web/src/components/MemoEditor/Editor/index.tsx - Height adjustments
- web/src/locales/en.json - Translation keys

Design follows industry standards (GitHub Focus Mode, Notion, Obsidian)
and maintains code quality with single source of truth pattern.
2025-11-16 23:15:36 +08:00
Steven 156908c77f chore(web): migrate from ESLint+Prettier to Biome
- Install @biomejs/biome@2.3.5 as unified linter and formatter
- Remove ESLint, Prettier and all related plugins (221 packages removed)
- Migrate linting rules from ESLint to Biome configuration
- Migrate formatting rules from Prettier to Biome configuration
- Exclude auto-generated proto files from linting (src/types/proto/**)
- Exclude CSS files from Biome (Tailwind syntax not yet supported)
- Update package.json scripts:
  - lint: tsc + biome check
  - lint:fix: biome check --write
  - format: biome format --write
- Auto-fix import organization across 60+ files
- Fix duplicate key in Russian locale (ru.json)
- Update CLAUDE.md documentation to reflect Biome usage

Benefits:
- 10-100x faster linting performance
- Simplified toolchain with single configuration file
- 221 fewer npm dependencies
- Unified linting, formatting, and import organization
2025-11-14 23:58:07 +08:00
Steven dc398cf6a7 chore(web): unify metadata badge styling and fix event handling
- Remove MetadataBadge component and inline styles consistently
- Add pointer/mouse event handlers to prevent drag interference
- Fix LocationDisplay mode handling and popover interaction
- Clean up RelationList empty state logic
2025-11-10 21:53:56 +08:00
Simon bb3d808e0e
feat: allow closing image preview via backdrop click (#5243) 2025-11-10 19:12:45 +08:00
Johnny 6fc0ef7cc2 chore(web): remove redundant and minimal README files
Removed 3 markdown files that provided no useful documentation:
- web/README.md: Single line "The frontend of Memos" (redundant)
- web/src/components/kit/README.md: Single line "Base components" (minimal)
- web/MARKDOWN_STYLE_GUIDE.md: Outdated styling guide (no longer applicable)

Kept comprehensive documentation files:
- web/src/components/MasonryView/README.md (implementation details)
- web/src/themes/COLOR_GUIDE.md (design system guide)
- web/src/components/ConfirmDialog/README.md (component API docs)
- web/src/store/README.md (architecture patterns)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:21:10 +08:00
Johnny fa3e0fc7f9 fix(web): make MermaidBlock reactive to system theme changes and improve code quality
- Add system theme listener to detect OS theme changes in real-time
- Refactor to eliminate duplicate theme preference extraction
- Simplify getMermaidTheme function from switch statement to ternary
- Move render guard outside async function for better readability
- Update comments to be more concise and focused

The component now properly re-renders Mermaid diagrams when the OS theme changes while using "system" theme preference.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:19:11 +08:00
Johnny fb736c20d3
feat(web): add Mermaid diagram support in markdown (#5242)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 14:13:10 +08:00
Johnny 5925e3cfc1 chore(web): simplify command system and improve editor UX (#5242)
Streamlines the command suggestion interface and fixes list auto-completion behavior:

- Remove command descriptions for cleaner suggestion popup UI
- Replace PaperclipIcon with FileIcon for semantic accuracy
- Fix list auto-completion to avoid extra newline when exiting list mode
- Add explanatory comments for cursor offset positions
- Improve dependency array in useListAutoCompletion hook

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 13:09:50 +08:00
Johnny fc43f86571
chore(web): unify Location/Attachments/Relations components (#5241)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 07:23:31 +08:00
Johnny a2ccf6b201
feat(web): improve list auto-completion and tag insertion UX (#5240)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 01:26:29 +08:00
Johnny e8b0273473
chore(web): improve CommandSuggestions and TagSuggestions components (#5239)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 01:05:24 +08:00
Johnny bd21338fdb
fix(web): markdown list auto-completion creates new line correctly (#5238)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-08 10:47:10 +08:00
Johnny c54fcf7aa7
refactor(web): redesign Settings components (#5237)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-08 10:32:55 +08:00
Steven ef9eee19d6 fix: implement tag suggestions functionality
Backend changes:
- Fix ListAllUserStats to calculate and return tag statistics
- Previously only returned name and timestamps, missing TagCount
- Now properly aggregates tags, pinned memos, and memo type stats

Frontend changes:
- Initialize user stats on app startup to populate tag data
- Show all tags when typing just '#' (fix empty Fuse.js search)
- Auto-refresh stats after creating/updating/deleting memos
- Fix Checkbox component ref warning with forwardRef

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:15:38 +08:00
boojack 7d4d1e8517
feat(web): standardize theme system with auto sync option (#5231)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-08 00:41:21 +08:00
Steven b7215f46a6 refactor(web): use Radix Checkbox and remove memoTypeStats
- Replace native input with Radix UI Checkbox in TaskListItem for better accessibility and consistent styling
- Remove memoTypeStats tracking and display (link count, todo count, code count)
- Remove StatCard component and related type definitions
- Simplify statistics to only track activity calendar data and tags

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 08:36:15 +08:00
Steven 8f0658e90d feat(web): enhance inbox notifications and user profile layouts
- Polish inbox notification items with improved visual hierarchy
  - Add original memo snippet with left border indicator
  - Redesign comment preview with gradient background and primary accent
  - Increase spacing and improve typography with consistent sizing
  - Add ring borders to avatars and refined icon badges
  - Enhance loading and error states with better skeleton designs
  - Improve hover states and transitions throughout

- Redesign user profile header layout
  - Create full-width centered header with avatar and user info
  - Add horizontal layout for profile actions
  - Improve responsive design with proper flex wrapping
  - Allow memo list to use full width for masonry layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 08:41:30 +08:00
Steven 89b0b81bdc fix(web): add required headers for Nominatim reverse geocoding API
Nominatim's usage policy requires a User-Agent header to identify the application. Added User-Agent and Accept headers to the reverse geocoding fetch request, and improved error handling to check HTTP response status.

Fixes #5222

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 23:47:44 +08:00
Steven 4c1d1c70d1 refactor: rename workspace to instance throughout codebase
Remove work-related terminology by renaming "workspace" to "instance"
across the entire application. This change better reflects that Memos
is a self-hosted tool suitable for personal and non-work use cases.

Breaking Changes:
- API endpoints: /api/v1/workspace/* → /api/v1/instance/*
- gRPC service: WorkspaceService → InstanceService
- Proto types: WorkspaceSetting → InstanceSetting
- Frontend translation keys: workspace-section → instance-section

Backend Changes:
- Renamed proto definitions and regenerated code
- Updated all store layer methods and database drivers
- Renamed service implementations and API handlers
- Updated cache from workspaceSettingCache to instanceSettingCache

Frontend Changes:
- Renamed service client: workspaceServiceClient → instanceServiceClient
- Updated all React components and state management
- Refactored stores: workspace.ts → instance.ts
- Updated all 32 locale translation files

All tests pass and both backend and frontend build successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 23:35:35 +08:00
Steven 1d7efb1580 refactor(web): unify memo stats/filters with context-aware MainLayout
Create unified architecture for memo statistics, filters, and sorting
across all pages (Home, Explore, Archived, Profile) with proper
visibility filtering and consistent data flow.

Key changes:
- Rename HomeLayout → MainLayout to reflect broader usage
- Create useFilteredMemoStats hook for unified stats computation
- Create useMemoFilters/useMemoSorting hooks to eliminate duplication
- Refactor all pages to use unified hooks (~147 lines removed)
- Move Explore route under MainLayout (was sibling before)
- Fix masonry column calculation threshold (1024px → 688px+)

Architecture improvements:
- MainLayout computes filter/stats per route context
- Stats/tags based on same filter as memo list (consistency)
- Proper visibility filtering (PUBLIC/PROTECTED) on Explore
- MemoExplorer/StatisticsView accept stats as required props
- Eliminated optional fallbacks and redundant data fetching

Benefits:
- Single source of truth for stats computation
- Stats remain static (don't change with user filters)
- Reduced code duplication across 4 pages
- Better maintainability and type safety
- Proper security (no private memo leakage on Explore)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 08:46:52 +08:00
Steven d30ff2898f fix(web): correct task checkbox toggling in multi-section memos
Fixed a bug where clicking checkboxes in task lists would toggle the wrong
checkbox when a memo contained multiple sections with separate task lists.

The issue was that TaskListItem was counting tasks only within the immediate
parent list (ul/ol), but the toggleTaskAtIndex function counts all tasks
globally across the entire memo. This caused index misalignment.

Changes:
- Add containerRef to MemoContentContext for proper task scoping
- Pass memoContentContainerRef through context in MemoContent component
- Update TaskListItem to count all tasks within the container scope

This ensures task indices are calculated consistently with the markdown
manipulation logic, fixing checkbox toggling in complex multi-section memos.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 09:25:15 +08:00
Claude 9b72963e08 feat: replace HomeSidebar with MemoExplorer and MemoExplorerDrawer components 2025-11-02 23:31:29 +08:00
Claude fb01b49ecf feat: add VisuallyHidden component and enhance LocationDialog accessibility 2025-11-02 23:02:08 +08:00
Claude 638b22a20d chore: implement InsertMenu with file upload and memo linking functionality 2025-11-02 22:53:07 +08:00
Steven 93964827ad refactor: redesign memo editor action bar UI
- Replace multiple action buttons with unified InsertMenu dropdown
- Consolidate upload, link memo, and location into single + button
- Redesign VisibilitySelector with text-based dropdown UI
- Unify badge styling for location, attachments, and links
  - Consistent height (h-7), padding, gaps, and border styles
  - Secondary foreground text color with hover states
  - Max width with truncation for long content
- Add image thumbnails in attachment badges
- Simplify button hierarchy with ghost variant for save/cancel
- Remove obsolete components (TagSelector, MarkdownMenu, etc.)
- Extract LocationView to separate component for better organization

Fixes #5196
2025-10-31 21:29:58 +08:00
Steven bc1550e926 refactor(api): migrate inbox functionality to user notifications
- Remove standalone InboxService and move functionality to UserService
- Rename inbox to user notifications for better API consistency
- Add ListUserNotifications, UpdateUserNotification, DeleteUserNotification methods
- Update frontend components to use new notification endpoints
- Update store layer to support new notification model

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-31 08:33:09 +08:00
Steven e915e3a46b refactor(web): refactor MemoFilters component and add comprehensive filter support
- Refactored MemoFilters.tsx for better maintainability:
  * Centralized filter configuration with FILTER_CONFIGS object
  * Added TypeScript interfaces for type safety
  * Removed separate FactorIcon component
  * Extracted handleRemoveFilter function
  * Improved imports organization

- Polished MemoFilters UI styles:
  * Changed to modern pill/badge design with rounded-full
  * Enhanced spacing and color schemes
  * Added smooth transitions and hover effects
  * Improved interactive remove button with destructive color hints
  * Better text readability with font-medium

- Added comprehensive filter support to all pages:
  * Explore page: Added full filter support (was missing)
  * Archived page: Enhanced from basic to full filter support
  * UserProfile page: Enhanced from basic to full filter support
  * All pages now support: content search, tag search, pinned, hasLink, hasTaskList, hasCode, and displayTime filters

- Consistency improvements:
  * All pages using PagedMemoList now have identical filter logic
  * Respects workspace settings for display time (created/updated)
  * Unified filter behavior across Home, Explore, Archived, and UserProfile pages
2025-10-30 22:52:58 +08:00
Steven 1e954070b9 refactor(web): improve memo component skeleton and loading states 2025-10-30 22:25:19 +08:00
Steven f65633e8a9 chore: fix linter issues in backend and frontend
- Remove extra blank line in memo_service.go (goimports)
- Remove invalid fields from CreateMemoRequest call (validateOnly, requestId)
- Clean up unnecessary comments

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:41:20 +08:00
Steven 243ecf14b0 refactor(api): remove DeleteMemoTag and RenameMemoTag endpoints
BREAKING CHANGE: Removed DeleteMemoTag and RenameMemoTag API endpoints
for better API consistency. Tags should now be managed by updating memo
content directly via UpdateMemo endpoint.

Backend changes:
- Remove RenameMemoTag and DeleteMemoTag RPC methods from proto
- Remove backend implementations in memo_service.go
- Regenerate protocol buffers (Go, TypeScript, OpenAPI)

Frontend changes:
- Remove RenameTagDialog component
- Simplify TagsSection to remove rename/delete functionality
- Improve tag styling with active state highlighting
- Add smooth transitions and better hover interactions
- Polish TagTree component for consistency
- Tags now only support click-to-filter (no inline editing)

Style improvements:
- Active tags highlighted with primary color and font-medium
- Consistent hover states across flat and tree views
- Better spacing and visual hierarchy
- Improved empty state styling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:32:47 +08:00
Steven d794c0bf8b feat(web): improve loading performance with skeleton screens and parallel fetches
- Add MemoSkeleton component for smooth initial page load experience
- Integrate skeleton loader into PagedMemoList during initial fetch
- Parallelize user settings and shortcuts API calls (~50% faster session init)
- Batch-fetch memo creators in parallel to eliminate individual loading spinners
- Pass showCreator prop to Explore page for proper skeleton rendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 23:53:35 +08:00
Steven 2371bbb1b7 feat(web): add quick language and theme switchers to user menu
- Add language and theme selector submenus to UserMenu component for quick access
- Refactor shared utilities: extract THEME_OPTIONS constant and getLocaleDisplayName() function
- Update LocaleSelect and ThemeSelect to use shared utilities, eliminating code duplication
- Make UserMenu reactive with MobX observer for real-time setting updates
- Fix language switching reactivity by immediately updating workspaceStore.state.locale
- Add scrollable menu support for language selector (max-h-[90vh])
- Apply same instant locale update to PreferencesSection for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 22:32:25 +08:00
Steven d693142dd4 feat(web): enhance code blocks with copy button and fix link navigation
Add custom code block renderer with language display and copy functionality. Links now open in new windows, and clicking image links no longer triggers both link navigation and image preview.

- Add CodeBlock component with copy-to-clipboard button and language label
- Configure all markdown links to open in new windows with target="_blank"
- Fix image link behavior to prevent duplicate actions when clicked

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 22:06:07 +08:00
Steven b00df8a9d1 fix(web): remove error notifications for location geocoding failures
Remove disruptive error toasts when reverse geocoding or geolocation fails.
Instead, silently fall back to using coordinates as the location placeholder.
This improves UX for users in regions where OpenStreetMap is restricted
(e.g., China) or when CSP blocks external API calls.

Fixes #5198, #5197

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 21:28:29 +08:00
Claude f241b590a2 chore: update demo data 2025-10-27 09:20:26 +08:00