🚀 release: v1.3.0 - Unified Control Bar, 2026 Models, & Independent G…#14
🚀 release: v1.3.0 - Unified Control Bar, 2026 Models, & Independent G…#14NaviAndrei merged 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Release-oriented update that refreshes the app’s UI control surface (search + filters + view toggle), introduces a shared 2026 model list, and updates styling/UX micro-interactions to support the v1.3.0 release.
Changes:
- Added a global
LLM_MODELSconstant and integrated it into prompt creation/editing and model filtering. - Reworked the main search/filter/view controls into a unified “control bar” with new CSS and UX tweaks.
- Bumped package version and updated release notes/dependencies.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/index.css | Adds unified control bar styles, search icon styling, card/grid tweaks, and new animations (but introduces conflicting duplicate selectors). |
| src/constants.ts | Introduces LLM_MODELS shared list. |
| src/components/StorageUsage.tsx | Enhances online badge + progress fill animation hooks (CSS classes). |
| src/components/SearchBar.tsx | Adds a Lucide search icon and accessibility label. |
| src/components/PromptForm.tsx | Switches model entry to a <select> backed by LLM_MODELS. |
| src/App.tsx | Implements unified control bar and revamped model/date filtering UI. |
| package.json | Version bump to 1.3.0; adds react-datepicker and types. |
| package-lock.json | Lockfile updated for new deps but version is not bumped to 1.3.0. |
| CHANGELOG.md | Adds 1.3.0 release notes. |
đź’ˇ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| transform: translateY(-2px); | ||
| } | ||
|
|
||
| .search-input:focus + .search-icon { |
There was a problem hiding this comment.
.search-input:focus + .search-icon won’t match the current SearchBar markup because the icon is rendered before the input. As a result, the focus styling for the icon never applies. Consider switching to a selector that works with the DOM order (e.g. :focus-within on the container or a general sibling selector), or render the icon after the input.
| .search-input:focus + .search-icon { | |
| *:has(> .search-input:focus) > .search-icon { |
| .prompt-list.grid { | ||
| display: grid; | ||
| grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); | ||
| gap: 1.5rem; | ||
| align-items: start; /* CRITICAL: Allows cards to have independent heights! */ | ||
| } |
There was a problem hiding this comment.
There are now two conflicting definitions of .prompt-list.grid in this file (the newly added CSS Grid rules earlier, and an existing multi-column layout later). This makes the layout unpredictable (e.g., column-count/break-inside rules won’t behave as intended on a grid container). Consolidate into a single approach by removing/rewriting the older .prompt-list.grid column rules or the new grid rules.
| .prompt-list.grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); | |
| gap: 1.5rem; | |
| align-items: start; /* CRITICAL: Allows cards to have independent heights! */ | |
| } | |
| /* Layout for .prompt-list.grid is defined later in the file; keep a single layout model there. */ |
| .model-badge { | ||
| background: rgba(59, 130, 246, 0.1); | ||
| color: var(--primary-color); | ||
| border-radius: 99px; | ||
| padding: 4px 12px; | ||
| font-size: 0.7rem; | ||
| font-weight: 600; | ||
| margin-bottom: 0.75rem; |
There was a problem hiding this comment.
.model-badge is defined multiple times in index.css (one here and another later in the file). The later rule will override parts of this styling, which can make the new badge design ineffective. Consider merging these rules into a single .model-badge definition or scoping one of them more specifically.
| .prompt-header h4 { | ||
| font-size: 1.1rem; | ||
| line-height: 1.4; | ||
| margin-bottom: 0.5rem; | ||
| height: 3rem; /* Fixed height for title to align cards */ | ||
| display: -webkit-box; | ||
| -webkit-line-clamp: 2; | ||
| -webkit-box-orient: vertical; | ||
| overflow: hidden; |
There was a problem hiding this comment.
.prompt-header h4 is also defined later in the file, which likely overrides the new fixed height + line-clamp styling intended to align card titles. To ensure the intended behavior, remove the duplicate later rule or make this rule more specific so it wins consistently.
| justify-content: flex-start; | ||
| flex-wrap: nowrap; /* Keep it on one line for desktop */ | ||
| } | ||
|
|
There was a problem hiding this comment.
.filter-row is forced to flex-wrap: nowrap with no responsive override. On smaller viewports this will cause the filter controls to overflow horizontally. Add a small-screen media rule to allow wrapping (or provide horizontal scrolling) so the control bar remains usable on mobile.
| @media (max-width: 768px) { | |
| .filter-row { | |
| flex-wrap: wrap; | |
| } | |
| } |
| onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')} | ||
| title={theme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode'} | ||
| > | ||
| <button className="btn-icon" onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> |
There was a problem hiding this comment.
The theme toggle is an icon-only button and previously had a title for an accessible name/tooltip. After this change it has neither aria-label nor title, which makes it harder to discover and inaccessible to screen readers. Add an aria-label (and optionally restore a title).
| <button className="btn-icon" onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> | |
| <button | |
| className="btn-icon" | |
| onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')} | |
| aria-label={theme === 'light' ? 'Switch to dark theme' : 'Switch to light theme'} | |
| title={theme === 'light' ? 'Switch to dark theme' : 'Switch to light theme'} | |
| > |
| const handleMovePromptToWorkspace = (promptId: string, workspaceId: string | null) => { | ||
| const targetPrompt = prompts.find(p => p.id === promptId); | ||
| if (!targetPrompt) return; | ||
|
|
||
| // Do nothing if the prompt is already in the target workspace | ||
| if (targetPrompt.workspaceId === (workspaceId || undefined)) return; | ||
|
|
||
| const updatedPrompts = prompts.map(p => | ||
| p.id === promptId ? { ...p, workspaceId: workspaceId || undefined, updatedAt: new Date().toISOString() } : p | ||
| ); | ||
|
|
||
| const updatedPrompts = prompts.map(p => p.id === promptId ? { ...p, workspaceId: workspaceId || undefined, updatedAt: new Date().toISOString() } : p); | ||
| setPrompts(updatedPrompts); | ||
|
|
||
| const wsName = workspaceId ? workspaces.find(w => w.id === workspaceId)?.name : 'All Prompts'; | ||
| toast.success(`Prompt "${targetPrompt.title}" moved to ${wsName}`); | ||
| }; |
There was a problem hiding this comment.
handleMovePromptToWorkspace no longer checks whether the prompt is already in the target workspace. This will update updatedAt and show a “moved” toast even when nothing actually changed, causing noisy history and unnecessary writes. Reintroduce an early return when targetPrompt.workspaceId already matches the requested destination.
| <input type="date" className="minimal-date" onChange={e => setDateRange(prev => ({ ...prev, start: e.target.value ? new Date(e.target.value) : null }))}/> | ||
| </div> | ||
|
|
||
| <div className="filter-item"> | ||
| <label className="label-text">To:</label> | ||
| <input type="date" className="minimal-date" onChange={e => setDateRange(prev => ({ ...prev, end: e.target.value ? new Date(e.target.value) : null }))}/> |
There was a problem hiding this comment.
The date filter inputs are uncontrolled (no value bound to dateRange). When clicking “Reset Filters”, state clears but the inputs will keep showing the previous dates, making the UI inconsistent with the active filters. Bind each input’s value to dateRange.start/end (formatted as YYYY-MM-DD) so resets and programmatic changes reflect in the fields.
| <input type="date" className="minimal-date" onChange={e => setDateRange(prev => ({ ...prev, start: e.target.value ? new Date(e.target.value) : null }))}/> | |
| </div> | |
| <div className="filter-item"> | |
| <label className="label-text">To:</label> | |
| <input type="date" className="minimal-date" onChange={e => setDateRange(prev => ({ ...prev, end: e.target.value ? new Date(e.target.value) : null }))}/> | |
| <input | |
| type="date" | |
| className="minimal-date" | |
| value={dateRange.start ? dateRange.start.toISOString().split('T')[0] : ''} | |
| onChange={e => setDateRange(prev => ({ ...prev, start: e.target.value ? new Date(e.target.value) : null }))} | |
| /> | |
| </div> | |
| <div className="filter-item"> | |
| <label className="label-text">To:</label> | |
| <input | |
| type="date" | |
| className="minimal-date" | |
| value={dateRange.end ? dateRange.end.toISOString().split('T')[0] : ''} | |
| onChange={e => setDateRange(prev => ({ ...prev, end: e.target.value ? new Date(e.target.value) : null }))} | |
| /> |
| "@types/react-datepicker": "^6.2.0", | ||
| "@types/react-window": "^1.8.8", | ||
| "flexsearch": "^0.7.43", | ||
| "lucide-react": "^1.7.0", | ||
| "react": "^19.2.4", | ||
| "react-datepicker": "^9.1.0", |
There was a problem hiding this comment.
react-datepicker (and @types/react-datepicker) are added as dependencies, but there are no imports/usages of react-datepicker in src/ (the app still uses native <input type="date">). If this PR isn’t actually introducing the component, consider removing these deps to avoid extra bundle size and dependency surface area.
| "@types/react-datepicker": "^6.2.0", | |
| "@types/react-window": "^1.8.8", | |
| "flexsearch": "^0.7.43", | |
| "lucide-react": "^1.7.0", | |
| "react": "^19.2.4", | |
| "react-datepicker": "^9.1.0", | |
| "@types/react-window": "^1.8.8", | |
| "flexsearch": "^0.7.43", | |
| "lucide-react": "^1.7.0", | |
| "react": "^19.2.4", |
| ### Fixed | ||
| - **Variable Detection**: Enhanced regex support for hints and placeholders `{{name:hint}}`. | ||
| - **Search Bar Contrast**: Fixed dark mode visibility and icon alignment issues. | ||
| - **Date Filter UX**: Improved contrast and focus states for consistent theme-aware filtering. |
There was a problem hiding this comment.
The 1.3.0 changelog lists fixes (e.g. “Variable Detection” and “Search Bar Contrast/icon alignment”) that don’t appear to be implemented in this PR’s code changes, and the current CSS still has a broken focus selector for the search icon. Please align the 1.3.0 release notes with the actual changes included in this PR (or include the missing code changes).
…rid Expansion