feat: Sprint 3 — delight, polish, and responsive sidebar
Celebration micro-interactions: - SuccessToast: auto-dismissing pill toast (success/info/warning variants) - ConfettiBurst: pure CSS 20-particle confetti on project creation - Project wizard: confetti + toast on successful creation - Vacation approval/rejection: contextual toasts - Allocation status change: success toast - Button: active:scale-[0.97] press feedback on all variants Collapsible sidebar + responsive: - Desktop: toggle collapse (72px icons-only mode) with localStorage persistence - NavTooltip: hover labels on collapsed icons - Mobile: hamburger menu + slide-in overlay with backdrop - Auto-close sidebar on mobile navigation - Scroll-to-top on route change (smooth behavior) Hover polish + accessibility: - Table rows: animated left-border accent + hover-lift - Stat cards + widgets: hover elevation + border glow - Timeline blocks: scale(1.02) + shadow-md on hover - Smooth scroll globally with prefers-reduced-motion fallback - Filter chips: framer-motion scale+fade enter/exit - Dropdowns: scaleY origin-top reveal animation - Preferences modal: scale+fade entrance - Link underline: animated ::after width expansion on hover Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -11,6 +11,8 @@ import { SkillTagInput } from "~/components/ui/SkillTagInput.js";
|
||||
import { usePermissions } from "~/hooks/usePermissions.js";
|
||||
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
||||
import { formatCents } from "~/lib/format.js";
|
||||
import { ConfettiBurst } from "~/components/ui/ConfettiBurst.js";
|
||||
import { SuccessToast } from "~/components/ui/SuccessToast.js";
|
||||
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -1023,6 +1025,8 @@ export function ProjectWizard({ open, onClose }: ProjectWizardProps) {
|
||||
const [state, setState] = useState<WizardState>(makeDefaultState);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||||
const [showConfetti, setShowConfetti] = useState(false);
|
||||
const [showSuccessToast, setShowSuccessToast] = useState(false);
|
||||
|
||||
const createProject = trpc.project.create.useMutation();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -1139,7 +1143,12 @@ export function ProjectWizard({ open, onClose }: ProjectWizardProps) {
|
||||
await utils.project.list.invalidate();
|
||||
await utils.timeline.getEntries.invalidate();
|
||||
await utils.timeline.getEntriesView.invalidate();
|
||||
handleClose();
|
||||
setShowConfetti(true);
|
||||
setShowSuccessToast(true);
|
||||
setTimeout(() => {
|
||||
setShowConfetti(false);
|
||||
handleClose();
|
||||
}, 1200);
|
||||
} catch (err) {
|
||||
setSubmitError(err instanceof Error ? err.message : "Failed to create project");
|
||||
} finally {
|
||||
@@ -1158,7 +1167,14 @@ export function ProjectWizard({ open, onClose }: ProjectWizardProps) {
|
||||
className="fixed inset-0 bg-black/50 z-50 flex items-start justify-center overflow-y-auto py-8 px-4"
|
||||
onClick={handleBackdropClick}
|
||||
>
|
||||
<div className="bg-white rounded-xl shadow-2xl w-full max-w-2xl">
|
||||
<div className="bg-white rounded-xl shadow-2xl w-full max-w-2xl relative">
|
||||
{/* Celebration effects */}
|
||||
<ConfettiBurst trigger={showConfetti} />
|
||||
<SuccessToast
|
||||
show={showSuccessToast}
|
||||
message="Project created successfully!"
|
||||
onDone={() => setShowSuccessToast(false)}
|
||||
/>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200">
|
||||
<h2 className="text-lg font-semibold text-gray-900">New Project Wizard</h2>
|
||||
|
||||
Reference in New Issue
Block a user