Skip to content

Commit fbb5a48

Browse files
feat: v1.1.0 - dark mode, selective AI matching, UI improvements
- Add dark mode with system/light/dark toggle defaulting to system preference - Add selective AI matching with checkbox selection on queued posts - Add individual "AI Match" button on each queued post card - Add Reset Extension button on setup wizard and settings pages - Add configurable RSS feed limits (Max RSS Items, Max Blog Items) - Add collapsible RSS Preferences and Matching Preferences sections - Remove Jump button; View button now opens post in new tab - Collapse Reply Suggestions by default; hide empty Replied/Skipped tabs - Fix post content newline preservation - Fix RSS feed host permission prompting during setup - Fix AI model default selection with vendor prefix - Fix content script injection on already-loaded LinkedIn pages - Fix AI Match processing state to wait for all API calls
1 parent 746229c commit fbb5a48

44 files changed

Lines changed: 1721 additions & 673 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.1.0] - 2025-01-19
11+
12+
### Added
13+
14+
- Selective AI matching: checkbox selection on queued posts to match only specific posts
15+
- Individual "AI Match" button on each queued post for single-post matching
16+
- Button dynamically changes from "AI Match All" to "AI Match Selected (N)" when posts are selected
17+
- Dark mode support with three-state toggle (system/light/dark) in header, defaults to system preference
18+
- Reset Extension button on setup wizard pages to abandon setup and clear any saved config values
19+
- Reset Extension section in settings to clear all settings and return to setup wizard
20+
- Configurable RSS feed limits: Max RSS Items (default 25) and Max Blog Items in AI Prompts (default 25) in Settings
21+
- RSS Preferences collapsible section for Cache Duration, Max RSS Items, and Max Blog Items in AI Prompts settings
22+
23+
### Changed
24+
25+
- Moved Matching Preferences into collapsible section within AI Model settings
26+
- Removed Jump button from post cards; View button (opens post in new tab) is now the only action
27+
- Reply Suggestions section now collapsed by default; click header with chevron to expand
28+
- Replied and Skipped tabs now hidden when empty, reducing visual clutter
29+
- Filter tabs now display count below the label instead of inline
30+
31+
### Fixed
32+
33+
- Post content now preserves newlines and paragraph breaks instead of collapsing all whitespace into single spaces
34+
- RSS feed validation now properly prompts for host permission during setup and settings, preventing CORS errors on first use
35+
- AI model now correctly selected by default on Settings page after setup wizard (fixed missing vendor prefix in default model ID)
36+
- ModelSelector now auto-selects the first available model if the stored model no longer exists or is filtered out
37+
- Post status tags now display correct labels: "Matched" tab shows "Matched" badge (was "Pending"), "Unmatched" tab shows "Unmatched" badge (was "Queued")
38+
- Side panel now detects posts when opened on already-loaded LinkedIn pages by programmatically injecting the content script if needed (previously required hard-refresh)
39+
- AI Match now waits for both matching and heat check API calls to complete before switching to the Matched tab and clearing the "Analyzing..." state; the processing UI stays visible even when queue becomes empty mid-processing
40+
1041
## [1.0.0] - 2025-01-18
1142

1243
Initial release of ReplyQueue, a Chrome extension that helps content creators find relevant social media posts and generate AI-powered reply suggestions.
@@ -19,5 +50,6 @@ Initial release of ReplyQueue, a Chrome extension that helps content creators fi
1950
- Reply suggestion generation with customizable writing style
2051
- Side panel UI with post cards, filtering, and settings
2152

22-
[Unreleased]: https://github.com/charlesjones-dev/replyqueue/compare/v1.0.0...HEAD
53+
[Unreleased]: https://github.com/charlesjones-dev/replyqueue/compare/v1.1.0...HEAD
54+
[1.1.0]: https://github.com/charlesjones-dev/replyqueue/compare/v1.0.0...v1.1.0
2355
[1.0.0]: https://github.com/charlesjones-dev/replyqueue/releases/tag/v1.0.0

CLAUDE.md

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,32 @@ Each adapter implements: `extractPost()`, `getPostUrl()`, `scrollToPost()`, `isF
4949
`src/shared/messages.ts` defines typed messages for cross-context communication:
5050

5151
- Content → Background: `POSTS_EXTRACTED`, `CONTENT_SCRIPT_READY`
52-
- Side Panel ↔ Background: `FETCH_RSS`, `AI_MATCH_POSTS`, `GENERATE_SUGGESTIONS`
52+
- Side Panel ↔ Background: `FETCH_RSS`, `AI_MATCH_POSTS`, `GENERATE_SUGGESTIONS`, `RESET_EXTENSION`
5353
- Background → Content: `SCROLL_TO_POST`, `EXTRACT_POSTS`
5454

5555
### Vue 3 Composables
5656

5757
`src/sidepanel/composables/` extracts business logic into reusable composables:
5858

59+
- `useAppState.ts` - Global app state (loading, errors)
60+
- `useClipboard.ts` - Copy-to-clipboard functionality
5961
- `useConfig.ts` - Extension configuration persistence
62+
- `useCreditsModal.ts` - Insufficient credits modal state
63+
- `useModels.ts` - OpenRouter model selection and filtering
64+
- `useNetworkStatus.ts` - Online/offline detection
6065
- `usePosts.ts` - Matched posts state with filtering
61-
- `useModels.ts` - OpenRouter model selection
66+
- `useSettingsView.ts` - Settings page state management
6267
- `useSetup.ts` - Onboarding flow logic
68+
- `useTabStatus.ts` - Content script connection status
69+
- `useTheme.ts` - Dark/light/system theme management
70+
- `useToast.ts` - Toast notification system
6371

6472
### Storage Strategy
6573

66-
- **chrome.storage.sync** - Small config synced across devices (config, cachedModels)
67-
- **chrome.storage.local** - Larger local data (extractedPosts, matchedPostsWithScore, cachedRssFeed)
74+
- **chrome.storage.sync** - Small config synced across devices (config, cachedModels, exampleComments if <8KB)
75+
- **chrome.storage.local** - Larger local data (extractedPosts, matchedPostsWithScore, cachedRssFeed, aiMatchCache, evaluatedPostIds)
76+
- **API keys** - Always stored in local storage only (never synced for security)
77+
- **Fallback** - If sync storage fails, automatically falls back to local storage
6878

6979
## Testing
7080

@@ -117,10 +127,12 @@ import { shared } from '@shared/types' // → src/shared/types
117127
118128
## Workflow
119129
130+
**IMPORTANT:** After every feature implementation or bug fix, you MUST run `pnpm build`. Chrome loads the extension from the `dist/` folder, so changes are not reflected until a build is run. The user will be testing the extension manually after each change.
131+
120132
After implementing any plan, always run preflight checks:
121133
122134
```bash
123-
pnpm build # Type check + build
135+
pnpm build # Type check + build (REQUIRED after every change)
124136
pnpm lint:fix # Auto-fix lint issues
125137
pnpm format # Auto-fix formatting
126138
pnpm test # Run tests
@@ -129,6 +141,24 @@ pnpm audit:check # Check for vulnerable dependencies
129141

130142
Fix any errors before considering the implementation complete.
131143

144+
### Changelog and Versioning
145+
146+
After preflight checks pass, use the `AskUserQuestion` tool to ask how to handle versioning:
147+
148+
- **Current version** - Add the feature/fix to the existing version section in `CHANGELOG.md`
149+
- **New version** - Increment version in `manifest.json` and `package.json`, then add a new section in `CHANGELOG.md`
150+
- **Skip** - Do nothing.
151+
152+
When incrementing versions:
153+
- Patch (x.x.X): Bug fixes, minor improvements
154+
- Minor (x.X.0): New features, non-breaking changes
155+
- Major (X.0.0): Breaking changes
156+
157+
Files to update for new versions:
158+
- `manifest.json` - Update `version` field
159+
- `package.json` - Update `version` field
160+
- `CHANGELOG.md` - Add new version section with date, update comparison links at bottom
161+
132162
## Security
133163

134164
### Security Tooling

CONTRIBUTING.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ replyqueue/
6262
│ ├── sidepanel/ # Vue 3 side panel UI
6363
│ └── shared/ # Shared utilities and types
6464
├── tests/ # Test files (mirrors src/ structure)
65-
├── public/ # Static assets
66-
└── docs/ # Documentation
65+
└── public/ # Static assets
6766
```
6867

6968
---
@@ -118,7 +117,15 @@ const doubled = computed(() => count.value * 2)
118117

119118
### Formatting
120119

121-
The project uses default Vite/TypeScript formatting. Key points:
120+
The project uses Prettier for formatting and ESLint for linting:
121+
122+
```bash
123+
pnpm lint # Check for lint errors
124+
pnpm lint:fix # Auto-fix lint issues
125+
pnpm format # Format code with Prettier
126+
```
127+
128+
Key formatting rules:
122129
- 2 spaces for indentation
123130
- Single quotes for strings
124131
- No semicolons (unless required)
@@ -217,12 +224,18 @@ Use descriptive branch names:
217224
pnpm test
218225
```
219226

220-
4. **Build the extension**
227+
4. **Lint and format**
228+
```bash
229+
pnpm lint:fix # Fix lint issues
230+
pnpm format # Format with Prettier
231+
```
232+
233+
5. **Build the extension**
221234
```bash
222235
pnpm build
223236
```
224237

225-
5. **Test manually**
238+
6. **Test manually**
226239
- Load the extension in Chrome
227240
- Test your changes in a real scenario
228241

@@ -250,7 +263,10 @@ Use descriptive branch names:
250263

251264
## Checklist
252265
- [ ] Code follows project style
253-
- [ ] Tests pass locally
266+
- [ ] Linting passes (`pnpm lint`)
267+
- [ ] Code formatted (`pnpm format`)
268+
- [ ] Tests pass locally (`pnpm test`)
269+
- [ ] Build succeeds (`pnpm build`)
254270
- [ ] Documentation updated
255271
- [ ] No console.log in production code
256272
```

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ Content creators spend hours scrolling social feeds hoping to find relevant disc
1515
- **Passive Discovery** - Extracts posts as you scroll, no extra workflow
1616
- **Smart Matching** - Keyword and AI-powered relevance scoring against your content
1717
- **Reply Suggestions** - Generates responses that match your writing style
18-
- **Jump to Post** - One click to navigate directly to matched posts
18+
- **View Post** - One click to open matched posts in a new tab
19+
- **Dark Mode** - System, light, or dark theme with one-click toggle
1920
- **Privacy-First** - No analytics, no tracking, your data stays local
2021
- **Extensible** - Platform adapter pattern makes adding new networks straightforward
2122

@@ -193,6 +194,8 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
193194
| Relevance Threshold | 30% | 10-90% | Minimum score for a post to be considered a match |
194195
| Max Posts to Show | 20 | 10, 20, 30, 50, 100 | Maximum number of matched posts to display |
195196
| RSS Cache Duration | 60 min | 15, 30, 60, 120, 240 | How long to cache RSS feed before refreshing |
197+
| Max RSS Items | 25 | 10, 25, 50, 100 | Maximum items to fetch from RSS feed |
198+
| Max Blog Items in AI Prompts | 25 | 10, 25, 50, All | Blog items included when AI evaluates posts |
196199
| Blog Content Sent to AI | 2,500 chars | 1K, 2.5K, 5K, 10K, No limit | Amount of blog content included when matching |
197200
| Social Post Content Sent to AI | 1,000 chars | 500, 1K, 2K, 3K, No limit | Amount of post content included when evaluating |
198201

manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
"manifest_version": 3,
33
"name": "ReplyQueue",
44
"description": "Side panel for finding social media posts relevant to your blog content and get AI-powered reply suggestions.",
5-
"version": "1.0.0",
5+
"version": "1.1.0",
66
"icons": {
77
"16": "icons/icon16.png",
88
"48": "icons/icon48.png",
99
"128": "icons/icon128.png"
1010
},
11-
"permissions": ["storage", "sidePanel", "activeTab"],
11+
"permissions": ["storage", "sidePanel", "activeTab", "scripting"],
1212
"host_permissions": ["https://www.linkedin.com/*", "https://linkedin.com/*", "https://openrouter.ai/*"],
1313
"optional_host_permissions": ["<all_urls>"],
1414
"content_security_policy": {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "replyqueue",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"type": "module",
55
"scripts": {
66
"dev": "vite",

privacy-policy.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Privacy Policy for ReplyQueue
22

3-
**Last Updated:** January 2025
3+
**Last Updated:** January 2026
44

55
ReplyQueue is a Chrome extension that helps content creators find social media posts relevant to their blog content and generate reply suggestions. This privacy policy explains how we handle your data.
66

@@ -21,15 +21,22 @@ All of the following data is stored locally on your device using Chrome's storag
2121

2222
| Data Type | Storage Location | Purpose |
2323
|-----------|------------------|---------|
24-
| OpenRouter API Key | chrome.storage.sync | Authenticate with AI service |
24+
| OpenRouter API Key | chrome.storage.local | Authenticate with AI service (never synced for security) |
2525
| RSS Feed URL | chrome.storage.sync | Fetch your blog content |
2626
| Selected AI Model | chrome.storage.sync | Configure AI preferences |
27-
| Matching Preferences | chrome.storage.sync | Configure relevance settings |
28-
| Writing Style Examples | chrome.storage.sync/local | Personalize reply suggestions |
27+
| Matching Preferences | chrome.storage.sync | Configure relevance settings (threshold, cache TTL) |
28+
| Model Filter Preferences | chrome.storage.sync | Filter available AI models by criteria |
29+
| Communication Preferences | chrome.storage.sync | Custom instructions for reply tone/style |
30+
| Content Char Limits | chrome.storage.sync | Configure how much content to send to AI |
31+
| RSS Limits | chrome.storage.sync | Max RSS items to fetch and include in AI prompts |
32+
| Theme Preference | chrome.storage.sync | Dark, light, or system theme setting |
33+
| Writing Style Examples | chrome.storage.local | Personalize reply suggestions |
2934
| Extracted Posts | chrome.storage.local | Store posts from social media feeds |
30-
| Matched Posts | chrome.storage.local | Cache matching results |
35+
| Matched Posts | chrome.storage.local | Cache matching results with scores |
36+
| Evaluated Post IDs | chrome.storage.local | Track which posts have been analyzed |
3137
| Cached RSS Data | chrome.storage.local | Reduce network requests |
3238
| Cached Model List | chrome.storage.local | OpenRouter model metadata |
39+
| AI Match Cache | chrome.storage.local | Cache AI matching results to avoid re-processing |
3340

3441
### What We Do NOT Collect
3542

@@ -52,12 +59,14 @@ ReplyQueue communicates with two external services. These communications only oc
5259
- When you fetch the list of available AI models
5360
- When you scan for relevant posts (AI matching)
5461
- When you generate reply suggestions
62+
- When heat check analyzes post tone/sentiment
5563

5664
**What data is sent:**
5765
- Your API key (for authentication)
58-
- Post content from your social media feed (for matching)
66+
- Post content from your social media feed (for matching and tone analysis)
5967
- RSS feed content summaries (for matching)
6068
- Your writing style examples (if provided, for reply generation)
69+
- Your communication preferences (if provided, for reply style customization)
6170

6271
**What data is NOT sent:**
6372
- Your personal information
@@ -116,6 +125,11 @@ All your data is stored locally and can be viewed:
116125
1. Open the extension's Settings panel
117126
2. Use the "Clear Cache" button
118127

128+
**Reset extension (clear all settings and data):**
129+
1. Open the extension's Settings panel
130+
2. Scroll to "Reset Extension" section
131+
3. Click "Reset Extension" to clear all data and return to setup wizard
132+
119133
### Export Your Data
120134

121135
Configuration data can be viewed in Chrome's storage inspector. Export functionality may be added in future versions.
@@ -139,6 +153,10 @@ Configuration data can be viewed in Chrome's storage inspector. Export functiona
139153
| `linkedin.com` | Extract posts from LinkedIn feeds |
140154
| `openrouter.ai` | Make API calls for AI matching and reply generation |
141155

156+
### Optional Host Permissions
157+
158+
ReplyQueue requests permission to access your RSS feed URL when you configure it. This is an optional permission that you grant during setup or when changing your RSS feed URL. The extension will prompt you to allow access to your blog's domain (e.g., `https://yourblog.com/*`) before fetching your RSS feed. Denying this permission prompt will prevent the extension from working.
159+
142160
---
143161

144162
## Children's Privacy

0 commit comments

Comments
 (0)