feat: design system overhaul — sidebar, AI chats, settings, brainstorm, color cleanup
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 12s

- Sidebar: dynamic brand-accent colors, brainstorm section restyled
- AI chat general: popup panel with expand/collapse, hides when contextual AI open
- AI chat contextual: tabs reordered (Actions first), X close button, height fix
- Settings: all tabs restyled, 6 new color presets (sage, terracotta, iron, etc.)
- Global color cleanup: emerald/orange hardcoded → brand-accent dynamic
- Brainstorm page: orange → brand-accent throughout
- PageEntry animation component added to key pages
- Floating AI button: bg-brand-accent instead of hardcoded black
- i18n: all 15 locales updated with new AI/billing keys
- Billing: freemium quota tracking, BYOK, stripe subscription scaffolding
- Admin: integrated into new design
- AGENTS.md + CLAUDE.md project rules added
This commit is contained in:
Antigravity
2026-05-16 12:59:30 +00:00
parent 1fcea6ed7d
commit bd495be965
2284 changed files with 395285 additions and 2327 deletions

View File

@@ -11,6 +11,7 @@ import {
import { UserPlus, Check, AlertCircle, Globe, Lock, Copy } from 'lucide-react'
import { createBrainstormShare } from '@/app/actions/brainstorm'
import { useUpdateBrainstormSettings } from '@/hooks/use-brainstorm'
import { useLanguage } from '@/lib/i18n'
interface BrainstormShareDialogProps {
open: boolean
@@ -28,15 +29,15 @@ interface UserResult {
image: string | null
}
const MESSAGES: Record<string, { text: string; type: 'success' | 'info' }> = {
invited: { text: 'Invitation envoyée !', type: 'success' },
re_invited: { text: 'Invitation renvoyée !', type: 'success' },
const FEEDBACK_BY_MESSAGE: Record<string, { key: string; type: 'success' | 'info' }> = {
invited: { key: 'brainstorm.feedbackInviteSent', type: 'success' },
re_invited: { key: 'brainstorm.feedbackInviteResent', type: 'success' },
already_shared: {
text: 'Cette personne a déjà accès à ce brainstorm.',
key: 'brainstorm.feedbackAlreadyShared',
type: 'info',
},
already_pending: {
text: 'Une invitation est déjà en attente pour cette personne.',
key: 'brainstorm.feedbackAlreadyPending',
type: 'info',
},
}
@@ -49,6 +50,7 @@ export function BrainstormShareDialog({
isPublic = false,
guestCanEdit = false,
}: BrainstormShareDialogProps) {
const { t } = useLanguage()
const [query, setQuery] = useState('')
const [results, setResults] = useState<UserResult[]>([])
const [showDropdown, setShowDropdown] = useState(false)
@@ -115,17 +117,17 @@ export function BrainstormShareDialog({
startTransition(async () => {
try {
const result = await createBrainstormShare(sessionId, query.trim())
if (result.message && MESSAGES[result.message]) {
const m = MESSAGES[result.message]
setFeedback({ text: m.text, type: m.type })
if (result.message && FEEDBACK_BY_MESSAGE[result.message]) {
const m = FEEDBACK_BY_MESSAGE[result.message]
setFeedback({ text: t(m.key), type: m.type })
} else {
setFeedback({ text: 'Invitation envoyée !', type: 'success' })
setFeedback({ text: t('brainstorm.feedbackInviteSent'), type: 'success' })
}
if (result.message === 'invited' || result.message === 're_invited') {
setQuery('')
}
} catch (err: any) {
setFeedback({ text: err.message || 'Erreur', type: 'error' })
setFeedback({ text: err.message || t('brainstorm.feedbackGenericError'), type: 'error' })
}
})
}
@@ -138,7 +140,7 @@ export function BrainstormShareDialog({
<div className="w-7 h-7 rounded-lg bg-orange-500/10 flex items-center justify-center">
<UserPlus size={14} className="text-orange-500" />
</div>
<span className="font-serif">Partager le brainstorm</span>
<span className="font-serif">{t('brainstorm.shareDialogTitle')}</span>
</DialogTitle>
<DialogDescription className="text-muted-foreground text-xs italic font-serif truncate">
{seedIdea.length > 60 ? seedIdea.substring(0, 60) + '…' : seedIdea}
@@ -148,7 +150,7 @@ export function BrainstormShareDialog({
<form onSubmit={handleShare} className="space-y-3 mt-2">
<div className="relative" ref={dropdownRef}>
<label className="text-[10px] font-bold uppercase tracking-[0.15em] text-muted-foreground mb-1.5 block">
Rechercher une personne
{t('brainstorm.shareSearchLabel')}
</label>
<input
type="text"
@@ -156,7 +158,7 @@ export function BrainstormShareDialog({
onChange={(e) => handleInputChange(e.target.value)}
onFocus={() => results.length > 0 && setShowDropdown(true)}
onBlur={() => setTimeout(() => setShowDropdown(false), 150)}
placeholder="Nom ou email…"
placeholder={t('brainstorm.shareNameOrEmailPlaceholder')}
className="w-full px-4 py-3 text-sm border border-border rounded-xl bg-transparent focus:outline-none focus:ring-2 focus:ring-orange-500/20 focus:border-orange-500/40 transition-all"
autoFocus
/>
@@ -178,7 +180,7 @@ export function BrainstormShareDialog({
</div>
<div className="min-w-0 flex-1">
<p className="text-sm font-medium text-foreground truncate">
{user.name || 'Sans nom'}
{user.name || t('brainstorm.unnamedPerson')}
</p>
<p className="text-[11px] text-muted-foreground truncate">
{user.email}
@@ -215,12 +217,12 @@ export function BrainstormShareDialog({
className="w-full py-3 bg-orange-500 hover:bg-orange-600 text-white text-[10px] font-bold uppercase tracking-[0.15em] rounded-xl disabled:opacity-50 transition-all flex items-center justify-center gap-1.5"
>
<UserPlus size={12} />
{isPending ? 'Envoi…' : 'Partager'}
{isPending ? t('brainstorm.shareSubmitting') : t('brainstorm.shareSubmit')}
</button>
</form>
<p className="text-[10px] text-muted-foreground/60 text-center mt-1">
La personne recevra une notification pour accepter ou refuser.
{t('brainstorm.shareFooterHint')}
</p>
<div className="border-t border-border mt-4 pt-4">
@@ -232,7 +234,7 @@ export function BrainstormShareDialog({
<Lock size={14} className="text-muted-foreground" />
)}
<span className="text-[10px] font-bold uppercase tracking-[0.15em] text-muted-foreground">
Lien public
{t('brainstorm.sharePublicLink')}
</span>
</div>
<button
@@ -272,7 +274,7 @@ export function BrainstormShareDialog({
<div className="flex items-center justify-between">
<span className="text-[10px] text-muted-foreground">
Autoriser les invités à modifier
{t('brainstorm.shareGuestsCanEdit')}
</span>
<button
onClick={() => {