refactor(mascot): replace ChibiMascot SVG with MascotImage PNG and simplify empty states
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { cardItem, cardStagger } from "../../shared/hooks/useFramerStagger";
|
import { cardItem, cardStagger } from "../../shared/hooks/useFramerStagger";
|
||||||
import { EmptyStateMascot } from "../../widgets/mascot/ChibiMascot";
|
import { EmptyStateMascot } from "../../shared/ui";
|
||||||
import { ActivityChart } from "./components/ActivityChart";
|
import { ActivityChart } from "./components/ActivityChart";
|
||||||
import { ControlBar } from "./components/ControlBar";
|
import { ControlBar } from "./components/ControlBar";
|
||||||
import { Heatmap } from "./components/Heatmap";
|
import { Heatmap } from "./components/Heatmap";
|
||||||
@@ -53,12 +53,7 @@ export function AnalyticsPanel({ guildId, guildName }: AnalyticsPanelProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!guildId) {
|
if (!guildId) {
|
||||||
return (
|
return <EmptyStateMascot />;
|
||||||
<EmptyStateMascot
|
|
||||||
variant="thinking"
|
|
||||||
message="Menunggu konfigurasi guild..."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
Input,
|
Input,
|
||||||
|
MascotImage,
|
||||||
} from "../../shared/ui";
|
} from "../../shared/ui";
|
||||||
import { ChibiMascot } from "../../widgets/mascot/ChibiMascot";
|
|
||||||
|
|
||||||
interface AuthOverlayProps {
|
interface AuthOverlayProps {
|
||||||
onAuthenticated: () => void;
|
onAuthenticated: () => void;
|
||||||
@@ -50,7 +50,7 @@ export function AuthOverlay({ onAuthenticated }: AuthOverlayProps) {
|
|||||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
|
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||||
<Lock className="h-6 w-6" />
|
<Lock className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<ChibiMascot variant="peeking" size="sm" />
|
<MascotImage size="sm" />
|
||||||
</div>
|
</div>
|
||||||
<CardTitle>Admin Access Required</CardTitle>
|
<CardTitle>Admin Access Required</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ interface ActiveSpeakersProps {
|
|||||||
|
|
||||||
export function ActiveSpeakers({ speakers }: ActiveSpeakersProps) {
|
export function ActiveSpeakers({ speakers }: ActiveSpeakersProps) {
|
||||||
if (speakers.length === 0) {
|
if (speakers.length === 0) {
|
||||||
return (
|
return <EmptyStateMascot />;
|
||||||
<EmptyStateMascot variant="sleeping" message="No active speakers~" />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export function RecordingsSubPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (recordings.length === 0) {
|
if (recordings.length === 0) {
|
||||||
return <EmptyStateMascot variant="sleeping" message="No recordings yet~" />;
|
return <EmptyStateMascot />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { parseMetadata } from "../../../entities/message/types";
|
import { parseMetadata } from "../../../entities/message/types";
|
||||||
import type { MessageRecord } from "../../../shared/api/client";
|
import type { MessageRecord } from "../../../shared/api/client";
|
||||||
import { EmptyStateMascot } from "../../../widgets/mascot/ChibiMascot";
|
import { EmptyStateMascot } from "../../../shared/ui";
|
||||||
|
|
||||||
interface ImageItem {
|
interface ImageItem {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -68,7 +68,7 @@ export function ImageGrid({ messages }: { messages: MessageRecord[] }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (images.length === 0) {
|
if (images.length === 0) {
|
||||||
return <EmptyStateMascot variant="thinking" message="No images yet~" />;
|
return <EmptyStateMascot />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { motion } from "framer-motion";
|
|||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import type { MessageRecord } from "../../../shared/api/client";
|
import type { MessageRecord } from "../../../shared/api/client";
|
||||||
import { cardItem, cardStagger } from "../../../shared/hooks/useFramerStagger";
|
import { cardItem, cardStagger } from "../../../shared/hooks/useFramerStagger";
|
||||||
import { ScrollArea } from "../../../shared/ui";
|
import { ScrollArea, EmptyStateMascot } from "../../../shared/ui";
|
||||||
import { EmptyStateMascot } from "../../../widgets/mascot/ChibiMascot";
|
|
||||||
import { MessageCard, MessageCardSkeleton } from "./MessageCard";
|
import { MessageCard, MessageCardSkeleton } from "./MessageCard";
|
||||||
|
|
||||||
export interface MessageFeedProps {
|
export interface MessageFeedProps {
|
||||||
@@ -84,7 +83,7 @@ export function MessageFeed({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
return <EmptyStateMascot variant="waving" message={emptyText} />;
|
return <EmptyStateMascot />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// ─── Shared UI barrel export ────────────────────────────────────────────────
|
// ─── Shared UI barrel export ────────────────────────────────────────────────
|
||||||
|
|
||||||
export { EmptyStateMascot } from "../../widgets/mascot/ChibiMascot";
|
export { EmptyStateMascot, MascotImage } from "../../widgets/mascot/MascotImage";
|
||||||
export { Badge } from "./badge";
|
export { Badge } from "./badge";
|
||||||
export { Button } from "./button";
|
export { Button } from "./button";
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { motion } from "framer-motion";
|
|||||||
import { BarChart3, MessageSquare, Radio } from "lucide-react";
|
import { BarChart3, MessageSquare, Radio } from "lucide-react";
|
||||||
import type { DashboardTab } from "../entities/ui/types";
|
import type { DashboardTab } from "../entities/ui/types";
|
||||||
import { cn } from "../shared/lib/utils";
|
import { cn } from "../shared/lib/utils";
|
||||||
import { ChibiMascot } from "./mascot/ChibiMascot";
|
import { MascotImage } from "./mascot/MascotImage";
|
||||||
|
|
||||||
const navItems: Array<{ id: DashboardTab; label: string; icon: typeof Radio }> =
|
const navItems: Array<{ id: DashboardTab; label: string; icon: typeof Radio }> =
|
||||||
[
|
[
|
||||||
@@ -84,9 +84,9 @@ export function Sidebar({
|
|||||||
{/* Spacer pushes mascot to bottom */}
|
{/* Spacer pushes mascot to bottom */}
|
||||||
<div className="flex-1" />
|
<div className="flex-1" />
|
||||||
|
|
||||||
{/* Chibi mascot */}
|
{/* Mascot PNG */}
|
||||||
<div className="flex justify-center pb-4">
|
<div className="flex justify-center pb-4">
|
||||||
<ChibiMascot size="sm" variant="idle" />
|
<MascotImage size="sm" />
|
||||||
</div>
|
</div>
|
||||||
</motion.nav>
|
</motion.nav>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* MascotImage — Anime mascot PNG from GitHub CDN
|
||||||
|
* Replaces ChibiMascot SVG component with external PNG asset
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface MascotImageProps {
|
||||||
|
size?: "sm" | "md" | "lg";
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sizeMap = {
|
||||||
|
sm: "w-16 h-auto",
|
||||||
|
md: "w-32 h-auto",
|
||||||
|
lg: "w-48 h-auto",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function MascotImage({ size = "md", className = "" }: MascotImageProps) {
|
||||||
|
const sizeClass = sizeMap[size];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src="https://raw.githubusercontent.com/IMPHNEN/imphnen-frontend-service/develop/apps/dimentorin/public/image/mascot-1.png"
|
||||||
|
alt="Mascot"
|
||||||
|
className={`object-contain drop-shadow-md ${sizeClass} ${className}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EmptyStateMascot — Mascot for empty states
|
||||||
|
* Replaces ChibiMascot when showing empty data states
|
||||||
|
*/
|
||||||
|
export function EmptyStateMascot() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center gap-4 py-12">
|
||||||
|
<MascotImage size="md" className="opacity-60" />
|
||||||
|
<p className="text-sm text-muted-foreground">No data to display</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user