diff --git a/frontend/app/analytics/layout.tsx b/frontend/app/analytics/layout.tsx new file mode 100644 index 0000000..6e2add2 --- /dev/null +++ b/frontend/app/analytics/layout.tsx @@ -0,0 +1,23 @@ +// frontend/app/analytics/layout.tsx +export default function AnalyticsLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+

+ Analytics +

+

+ Player engagement overview for the Mind Block platform. +

+
+ + {children} +
+
+ ); +} \ No newline at end of file diff --git a/frontend/app/analytics/page.tsx b/frontend/app/analytics/page.tsx index 9e0a751..6011328 100644 --- a/frontend/app/analytics/page.tsx +++ b/frontend/app/analytics/page.tsx @@ -3,15 +3,9 @@ import DauMauChart from "@/components/analytics/DauMauChart"; export default function AnalyticsPage() { return ( -
-
-
-

Analytics

-

- Player engagement overview for the Mind Block platform. -

-
- +
+ {/* Full-width for now; future charts can sit alongside it in the grid */} +
diff --git a/frontend/components/analytics/DauMauChart.tsx b/frontend/components/analytics/DauMauChart.tsx index bce5f0e..60dbbae 100644 --- a/frontend/components/analytics/DauMauChart.tsx +++ b/frontend/components/analytics/DauMauChart.tsx @@ -13,7 +13,7 @@ import { Tooltip, Legend, } from "recharts"; -import { TrendingUp, CalendarRange } from "lucide-react"; +import { TrendingUp, CalendarRange, SlidersHorizontal, X } from "lucide-react"; import { getDauMauMetrics } from "@/lib/api/analyticsApi"; function formatDate(date: Date): string { @@ -37,6 +37,7 @@ export default function DauMauChart() { const defaultRange = useMemo(getDefaultRange, []); const [startDate, setStartDate] = useState(defaultRange.startDate); const [endDate, setEndDate] = useState(defaultRange.endDate); + const [filtersOpen, setFiltersOpen] = useState(false); const { data, isLoading, isFetching, isError, error, refetch } = useQuery({ queryKey: ["dau-mau", startDate, endDate], @@ -56,9 +57,46 @@ export default function DauMauChart() { const stickinessPct = data?.stickiness != null ? Math.round(data.stickiness * 100) : null; + const controls = ( +
+ {PRESETS.map((preset) => ( + + ))} + +
+ + setStartDate(e.target.value)} + className="bg-transparent text-xs text-slate-200 outline-none [color-scheme:dark]" + aria-label="Start date" + /> + + setEndDate(e.target.value)} + className="bg-transparent text-xs text-slate-200 outline-none [color-scheme:dark]" + aria-label="End date" + /> +
+
+ ); + return ( -
-
+
+

DAU / MAU

@@ -66,42 +104,31 @@ export default function DauMauChart() {

-
- {PRESETS.map((preset) => ( - - ))} - -
- - setStartDate(e.target.value)} - className="bg-transparent text-xs text-slate-200 outline-none [color-scheme:dark]" - aria-label="Start date" - /> - - setEndDate(e.target.value)} - className="bg-transparent text-xs text-slate-200 outline-none [color-scheme:dark]" - aria-label="End date" - /> -
-
+ {/* Desktop / wide tablet: controls shown inline */} +
{controls}
+ + {/* Narrow tablet & mobile: controls collapse behind this toggle */} +
+ {/* Collapsible controls panel, only rendered below md */} + {filtersOpen && ( +
+ {controls} +
+ )} + {stickinessPct !== null && hasData && (
@@ -111,7 +138,7 @@ export default function DauMauChart() {
)} -
+
{isLoading && (
Loading engagement data... @@ -144,11 +171,16 @@ export default function DauMauChart() { - - + +