Add mobile overflow nav, law check feature, and favicon
Nav: "Fonctionnement" and "Flyer QR" restored on mobile via a ··· overflow dropdown (click-outside closes); other links always visible Law check: new POST /api/check-law endpoint (5/min, 20/h) calls mistral-small with a new LAW_CHECK_PROMPT to detect if a proposal is already covered by French or EU law. Informational only, non-blocking. Frontend: "Vérifier le cadre légal existant" button below textarea in home.tsx; result displayed with Scale icon; resets on content change. Favicon: replaced placeholder red square with a petrol rounded square containing a serif "V" (for Voix) in warm cream — matches brand palette Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ import {
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Loader2, PenTool, CheckCircle2, Info, AlertCircle, TrendingUp, Users, Scale,
|
||||
Share2, Printer, Copy, Flag,
|
||||
Share2, Printer, Copy, Flag, BookOpen,
|
||||
} from "lucide-react";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
@@ -143,6 +143,8 @@ export default function Home() {
|
||||
}, [countdown]);
|
||||
|
||||
const [mobileTab, setMobileTab] = React.useState<"proposer" | "synthese">("proposer");
|
||||
const [lawCheckResult, setLawCheckResult] = React.useState<string | null>(null);
|
||||
const [lawCheckLoading, setLawCheckLoading] = React.useState(false);
|
||||
|
||||
// Soumission effective après confirmation du consentement (ou si déjà consenti)
|
||||
const doActualSubmit = (data: SubmitIdeaValues) => {
|
||||
@@ -206,6 +208,26 @@ export default function Home() {
|
||||
}
|
||||
};
|
||||
|
||||
const checkLaw = async () => {
|
||||
const content = form.getValues("content")?.trim();
|
||||
if (!content || content.length < 10) return;
|
||||
setLawCheckLoading(true);
|
||||
setLawCheckResult(null);
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/check-law`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ content }),
|
||||
});
|
||||
const data = await res.json();
|
||||
setLawCheckResult(data.note || null);
|
||||
} catch {
|
||||
setLawCheckResult(null);
|
||||
} finally {
|
||||
setLawCheckLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleShare = () => {
|
||||
if (!synthesis?.text) return;
|
||||
const date = format(new Date(), "d MMMM yyyy 'à' HH:mm", { locale: fr });
|
||||
@@ -376,6 +398,10 @@ export default function Home() {
|
||||
className="min-h-[90px] sm:min-h-[120px] resize-none font-serif text-lg bg-background border-primary/20 focus-visible:ring-primary placeholder:text-muted-foreground/50"
|
||||
data-testid="input-idea-content"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
field.onChange(e);
|
||||
if (lawCheckResult) setLawCheckResult(null);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -383,6 +409,31 @@ export default function Home() {
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Vérification cadre légal existant */}
|
||||
<div className="flex items-start gap-2 flex-wrap">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 px-2 text-xs gap-1.5 text-muted-foreground hover:text-foreground"
|
||||
disabled={lawCheckLoading || (form.getValues("content")?.trim().length ?? 0) < 10}
|
||||
onClick={checkLaw}
|
||||
title="Vérifier si cette proposition est déjà inscrite dans la loi française ou européenne"
|
||||
>
|
||||
{lawCheckLoading
|
||||
? <Loader2 className="h-3 w-3 animate-spin" />
|
||||
: <BookOpen className="h-3 w-3" />}
|
||||
{lawCheckLoading ? "Vérification…" : "Vérifier le cadre légal existant"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{lawCheckResult && (
|
||||
<div className="text-xs border border-primary/20 bg-primary/5 rounded-md px-3 py-2.5 text-foreground/80 leading-relaxed flex gap-2">
|
||||
<Scale className="h-3.5 w-3.5 text-primary flex-shrink-0 mt-0.5" />
|
||||
<span>{lawCheckResult}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-start gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
Reference in New Issue
Block a user