Commit Graph

4006 Commits

Author SHA1 Message Date
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
Steven d1492007ab fix(store): filter inbox notifications by message type at database level
Add MessageType filter to FindInbox to exclude legacy VERSION_UPDATE
notifications from inbox queries. This resolves the issue where users
saw notification counts but no items displayed, as VERSION_UPDATE
entries cannot be rendered in the new UserNotification API.

Changes:
- Add MessageType field to FindInbox struct for database-level filtering
- Implement JSON extraction filters in SQLite, MySQL, and PostgreSQL drivers
- Update ListUserNotifications to filter MEMO_COMMENT type at store level

This approach improves performance by filtering at the database rather
than in application code, reducing unnecessary data transfer for users
with many legacy inbox entries.

Fixes #5278

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 08:43:05 +08:00
Steven 17e116b977 chore: fix linter 2025-12-01 08:27:23 +08:00
Johnny 545323d12c refactor(rss): comprehensive RSS service improvements
Major performance and standards compliance improvements to RSS feed generation:

Performance optimizations:
- Fix N+1 query problem by batch loading attachments (101 queries → 2-3)
- Add in-memory caching with 1-hour TTL and LRU eviction
- Implement ETag-based conditional requests (304 Not Modified)
- Add database-level pagination with LIMIT clause
- Clean up expired cache entries to prevent memory leaks

RSS 2.0 compliance:
- Add item titles extracted from memo content
- Include both description and content:encoded fields
- Add author information (name and email)
- Set proper Last-Modified headers
- Use specific application/rss+xml content type

Code quality:
- Fix potential index out of bounds panic in title generation
- Improve markdown heading stripping with regex (handles # to ######)
- Add proper HTTP caching headers (Cache-Control, ETag, Last-Modified)
- Thread-safe cache implementation with RWMutex
- Better error handling and edge case coverage

The RSS backend now follows industry best practices with optimal
performance, full standards compliance, and production-ready reliability.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 00:28:23 +08:00
Johnny 1a9bd32cf1 feat(auth): add PKCE support and enhance OAuth security
Implements critical OAuth 2.0 security improvements to protect against authorization code interception attacks and improve provider compatibility:

- Add PKCE (RFC 7636) support with SHA-256 code challenge/verifier
- Fix access token extraction to use standard field instead of Extra()
- Add OAuth error parameter handling (access_denied, invalid_scope, etc.)
- Maintain backward compatibility for non-PKCE flows

This brings the OAuth implementation up to modern security standards as recommended by Auth0, Okta, and the OAuth 2.0 Security Best Current Practice (RFC 8252).

Backend changes:
- Add code_verifier parameter to ExchangeToken with PKCE support
- Use token.AccessToken for better provider compatibility
- Update proto definition with optional code_verifier field

Frontend changes:
- Generate cryptographically secure PKCE parameters
- Include code_challenge in authorization requests
- Handle and display OAuth provider errors gracefully
- Pass code_verifier during token exchange

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 00:04:26 +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
Huang Youchuan 26cb357685
fix: update user session retrieval to use user.ID instead of userID (#5294)
Co-authored-by: huangyouchuan <huangyouchuan@letu.com>
2025-11-30 11:45:16 +08:00
Johnny ee9d9603ee chore: remove goreleaser 2025-11-30 11:42:46 +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 07a030ddfd fix(postgres): update tag filtering SQL to ensure proper type casting for LIKE comparisons 2025-11-26 23:04:07 +08:00
Steven 50f49fc00d chore: update demo data 2025-11-26 21:58:56 +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
김강현 ef033d21de
chore(i18n): add missing Korean translations (#5285) 2025-11-26 20:02:57 +08:00
김강현 b7c9f0e6ff
chore(i18n): improve Korean locale translations for copy and delete actions (#5280) 2025-11-26 12:34:54 +08:00
Steven 424f11f227 fix(store): fix PostgreSQL tag filtering type inference error
Resolves issue where tag filtering in PostgreSQL databases failed with "operator does not exist: jsonb ~~ unknown" error. The hierarchical tag filtering feature introduced in commit 5e47f25b generated SQL with implicit type placeholders that PostgreSQL couldn't infer.

The fix explicitly casts the LIKE comparison placeholder to text (::text) in the PostgreSQL dialect, ensuring proper type resolution for the query parameter.

Fixes #5275

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 07:40:39 +08:00
Steven 68c17469a3 fix(markdown): fix UTF-8 truncation for CJK characters in snippet generation
The truncateAtWord function was slicing strings by byte position instead of
character position. When truncating text with multi-byte UTF-8 characters
(like CJK), this could cut in the middle of a character, creating invalid
UTF-8 and causing gRPC marshaling errors.

Fixed by converting to runes before truncation to ensure we always cut at
proper character boundaries. Added test cases for CJK characters.

Fixes #5276

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 07:34:28 +08:00
Steven e17cd163c6 chore: bump version 2025-11-25 22:17:45 +08:00
Steven eb541d04cc fix(web): resolve tag sidebar filtering and reactivity issues
This fixes multiple issues with the tag sidebar and activity calendar:

1. Tag disappearing bug: When filtering by a tag, the sidebar now shows all tags instead of only the selected tag
2. Activity calendar filtering: Calendar now shows full activity history instead of filtered results
3. Auto-update on memo changes: Sidebar tags and calendar now update automatically when creating/editing memos without requiring manual page refresh

Technical changes:
- Modified useFilteredMemoStats to fetch unfiltered UserStats from backend API for Home/Profile pages
- Fixed key mismatch bug in userStore where stats were stored with inconsistent keys
- Added statsStateId update in fetchUserStats to trigger reactivity
- Updated MainLayout to pass appropriate userName based on page context
- Archived/Explore pages continue to compute from cached memos (correct behavior)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 22:17:01 +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
Johnny 1832b59190 fix(css): standardize color variable values in default-dark theme 2025-11-25 09:02:57 +08:00
Steven 5e95a77f50 chore: update color variables in default-dark theme for improved contrast 2025-11-24 21:59:24 +08:00
Steven b5de847107 chore(web): add external link icon for memo attachments 2025-11-24 21:56:14 +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 1d582e0f39 chore: upgrade dependencies 2025-11-24 20:18:52 +08:00
Richard Szegh 455eef9fa3
feat(web): add ability to delete unused attachments (#5272) 2025-11-24 11:55:53 +08:00
Johnny 60d977c0bf fix: add period to comment for golangci-lint compliance 2025-11-23 23:47:17 +08:00
Johnny b78d4c2568 refactor(markdown): use Unicode categories for tag validation
Replace custom character whitelist with Unicode standards-based validation:

- Use unicode.IsLetter/IsNumber/IsSymbol instead of hardcoded lists
- Remove manual UTF-8 byte checking for CJK punctuation
- Add proper rune-based length limiting (MAX_TAG_LENGTH = 100)
- Improve international character support (CJK, Arabic, Cyrillic, etc.)
- Add emoji support via unicode.IsSymbol

Benefits:
- Cleaner, more maintainable code (~50 lines removed)
- Standards-based approach following Unicode categories
- Better UTF-8 safety with utf8.DecodeRune
- Consistent validation between Go backend and TypeScript frontend

All existing tests pass with improved Unicode handling.
2025-11-23 23:45:10 +08:00
Steven d69435c97c chore(docs): update security policy to prevent public vulnerability disclosure
- Direct security reports to email only instead of public GitHub issues
- Set clear expectations: no CVEs during beta (v0.x) phase
- Add security best practices for self-hosted deployments
- Plan formal vulnerability disclosure program for v1.0+

Addresses #5255
2025-11-21 09:13:40 +08:00
gitkeniwo a533ba02dc
fix: add load more button and pagination to attachments page (#5258) 2025-11-21 09:04:41 +08:00
Steven edfbd6b073 fix(web): refresh sidebar tags when creating/updating memos
The sidebar tag list wasn't updating when users created new memos with tags
or modified existing memo tags. This was because useFilteredMemoStats hook
only refetched when filter/state/orderBy changed.

Now the hook observes memoStore.state.stateId, which changes whenever memos
are created, updated, or deleted. This triggers automatic refetch and the
sidebar updates immediately with the latest tag counts.

Fixes tag refresh issue in sidebar
2025-11-19 22:30:00 +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
Steven 3989100a27 fix(parser): handle additional Unicode punctuation in tag parsing 2025-11-19 22:19:56 +08:00
Steven 64e9d82d67 fix(parser): support Unicode characters in tags
Fixes #5264

Chinese, Japanese, Korean, and other Unicode characters are now
properly recognized in hashtags, following the standard hashtag
parsing conventions used by Twitter, Instagram, and GitHub.

Changes:
- Updated tag parser to allow Unicode letters and digits
- Tags stop at whitespace and punctuation (both ASCII and CJK)
- Allow dash, underscore, forward slash in tags
- Added comprehensive tests for CJK characters and emoji

Examples:
- #测试 → recognized as tag '测试'
- #日本語 → recognized as tag '日本語'
- #한국어 → recognized as tag '한국어'
- #测试。→ recognized as tag '测试' (stops at punctuation)
- #work/测试/项目 → hierarchical tag with Unicode
2025-11-19 22:06:11 +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