Skip to content

feat(wireframes): align free-mode pages with app baseline#329

Merged
timini merged 1 commit intomainfrom
feat/62-firestore-persistence-foundation
Feb 23, 2026
Merged

feat(wireframes): align free-mode pages with app baseline#329
timini merged 1 commit intomainfrom
feat/62-firestore-persistence-foundation

Conversation

@timini
Copy link
Copy Markdown
Owner

@timini timini commented Feb 23, 2026

Summary

Implements Stage 1 from #323 / #325 by aligning packages/wireframes with the current Free Mode app UX baseline.

Changes

  • Reworked shared wireframe shell to mirror app structure:
    • Added persistent header + footer in layout
    • Updated progress step visuals to current style
  • Updated wireframe pages for Free Mode parity:
    • config: Free mode-first config flow with Pro mode disabled/coming-soon state
    • ensemble: provider readiness states, model selection guidance, updated summary sidebar flow
    • prompt: prompt input first, tips second, ensemble summary third
    • review: prompt -> consensus -> agreement -> responses ordering with current action layout

Validation

  • npm run lint (in packages/wireframes) ✅
  • npm run build (in packages/wireframes) ❌ fails due missing local dependency setup (tailwindcss-animate in wireframes environment)

Links

@github-actions
Copy link
Copy Markdown

🤖 Hi @timini, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@claude
Copy link
Copy Markdown

claude bot commented Feb 23, 2026

PR Review

Summary

Reworks the wireframe pages (config, ensemble, prompt, review) plus shared layout/header/footer to align with the current Free Mode app baseline. The refactor is a clear improvement — moving from hardcoded bg-gray-*/bg-blue-* styling toward semantic tokens, extracting header/footer into the layout, and restructuring page content. However, three files exceed the 200-line limit and several hardcoded Tailwind color classes with numeric suffixes remain.

Issues Found

🟠 app/ensemble/page.tsx — [200-line violation] File is 306 lines, well over the 200-line limit. The provider data definitions (types, providerLabels, providerStatus, models, presets) could be extracted to a shared data file, and the model card / sidebar could become separate components.

🟠 app/config/page.tsx — [200-line violation] File is 232 lines. The apiKeyRows data constant (lines 19–78) and the API key row rendering loop could each be extracted.

🟡 app/review/page.tsx — [200-line violation] File is 211 lines, marginally over. The responses/consensusResponse mock data at the top of the file could be extracted to bring it under the limit.

🟠 app/config/page.tsx:137,146 — [Design token violation] Uses border-sky-200 bg-sky-50 text-sky-900 for info banners. Should use semantic tokens (e.g. border-info bg-info/10 text-info-foreground or equivalent from the design system).

🟠 app/config/page.tsx:176,195,214 — [Design token violation] Uses text-emerald-600, border-emerald-300 bg-emerald-50, text-emerald-700 for valid-key styling. Should use semantic success tokens.

🟠 app/ensemble/page.tsx:122 — [Design token violation] Uses border-sky-200 bg-sky-50 text-sky-900 for info banner, same issue as config page.

🟠 app/ensemble/page.tsx:144 — [Design token violation] Uses text-emerald-600 for "Ready" status.

🟠 app/ensemble/page.tsx:169,179 — [Design token violation] Uses border-orange-500 bg-orange-50, border-orange-200 bg-orange-100 text-orange-700 for the summarizer highlight. Should map to a semantic token.

🟠 app/review/page.tsx:97,99,113 — [Design token violation] Uses text-amber-600, bg-amber-500 for agreement percentage styling.

🟡 app/review/page.tsx:180-181 — [Design token violation] Uses text-yellow-500 for star ratings. Minor since this is a common pattern for rating stars, but still a numeric-suffix color.

🟠 components/progress-steps.tsx:32,45,60 — [Design token violation] Uses bg-emerald-500 and text-emerald-600 for completed steps. Should use a semantic success/completed token.

Verdict

  • 🚫 Changes requested — Multiple 🟠 issues: three files exceed the 200-line component limit and hardcoded Tailwind colors with numeric suffixes are used throughout instead of semantic design tokens.

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

This pull request introduces a significant and well-executed refactoring of the wireframes package, successfully aligning the user experience with the new free-mode baseline. The updated pages are much cleaner, more intuitive, and the code is generally more robust and maintainable.

🔍 General Feedback

  • The use of data-driven components in config/page.tsx is a great improvement.
  • The state management in ensemble/page.tsx is a bit complex but handles the new requirements well.
  • The new persistent layout with a shared header and footer provides a much more consistent user experience.

Overall, this is a fantastic update that greatly improves the wireframes. The comments I've left are mostly minor suggestions for further refinement.

Comment on lines +214 to +217
<p className={`mt-2 text-xs ${isValid ? "text-emerald-700" : "text-muted-foreground"}`}>
{row.helperText}
</p>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 The logic for toggling the visibility of an API key can be slightly simplified. You can directly update the specific provider's visibility without spreading the previous state.

Suggested change
<p className={`mt-2 text-xs ${isValid ? "text-emerald-700" : "text-muted-foreground"}`}>
{row.helperText}
</p>
</div>
onClick={() =>
setShowApiKeys((prev) => ({
...prev,
[row.provider]: !prev[row.provider],
}))
}

Comment on lines +101 to 109
const next = prev.filter((id) => id !== model.id)
if (summarizerModel === model.id && next.length > 0) {
setSummarizerModel(next[0] as string)
}
return next
}
return [...prev, model.id]
})
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 The useMemo hook is not necessary here as the models array is a constant. The groupedModels can be calculated once outside the component or directly inside without useMemo. This avoids the overhead of the hook for a value that doesn't change.

Suggested change
const next = prev.filter((id) => id !== model.id)
if (summarizerModel === model.id && next.length > 0) {
setSummarizerModel(next[0] as string)
}
return next
}
return [...prev, model.id]
})
}
const groupedModels = models.reduce<Record<Provider, Model[]>>(
(acc, model) => {
acc[model.provider].push(model)
return acc
},
{
openai: [],
anthropic: [],
google: [],
xai: [],
deepseek: [],
perplexity: [],
},
)

{model.id === summarizerModel && (
<Badge variant="outline" className="border-primary/30 bg-primary/10 text-primary">
Summarizer
</Badge>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The 'Use preset' button appears to be missing an onClick handler, which means clicking it currently does nothing. This seems like either a bug or an incomplete feature. If the functionality is intended to be implemented later, consider adding a // TODO comment or disabling the button to avoid user confusion.

<div className="flex items-center gap-3">
<Button variant="outline" onClick={() => router.push("/prompt")}>
Back to Prompt
</Button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 For consistency with other icons on the page that are from lucide-react, consider replacing the hardcoded star character '★' with a Star icon from lucide-react. This will help maintain a uniform look and feel across the application. You can import the Star icon and use it like other icons.

Suggested change
</Button>
import { AlertCircle, Copy, Share, Star } from "lucide-react"
...
<Star className="h-5 w-5" />

@@ -0,0 +1,32 @@
import Link from "next/link"

const year = new Date().getFullYear()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Using new Date().getFullYear() will work, but it can cause issues in statically generated sites where the page is built once and served for a long time. The year might not update without a rebuild. For a wireframe, this is fine, but for production, you might consider either updating this dynamically on the client-side or simply hardcoding the year and updating it manually when needed. Since this is a wireframe, this is a very minor point.

@timini timini merged commit d6194e7 into main Feb 23, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant