Improve podcast avatar display and info banner
- Avatar images now use full available width (max 280px, responsive) - Auto-collapse info banner after 8 seconds - Add 'Show tips' link to expand collapsed info - Fix image sizing to use contain instead of cover for better visibility
This commit is contained in:
@@ -160,17 +160,18 @@ export const AvatarSelector: React.FC<AvatarSelectorProps> = ({
|
|||||||
{loadingBrandAvatar ? (
|
{loadingBrandAvatar ? (
|
||||||
<CircularProgress size={32} />
|
<CircularProgress size={32} />
|
||||||
) : avatarPreview && avatarPreview === brandAvatarFromDb ? (
|
) : avatarPreview && avatarPreview === brandAvatarFromDb ? (
|
||||||
<Stack spacing={2} alignItems="center">
|
<Stack spacing={2} alignItems="center" sx={{ width: "100%", maxWidth: 280 }}>
|
||||||
<Box sx={{ position: "relative" }}>
|
<Box sx={{ position: "relative", width: "100%" }}>
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src={avatarPreviewBlobUrl || ""}
|
src={avatarPreviewBlobUrl || ""}
|
||||||
alt="Selected Brand Avatar"
|
alt="Selected Brand Avatar"
|
||||||
sx={{
|
sx={{
|
||||||
width: 160,
|
width: "100%",
|
||||||
height: 160,
|
height: "auto",
|
||||||
objectFit: "cover",
|
maxHeight: 200,
|
||||||
borderRadius: 2.5,
|
objectFit: "contain",
|
||||||
|
borderRadius: 2,
|
||||||
border: "2px solid #667eea",
|
border: "2px solid #667eea",
|
||||||
boxShadow: "0 4px 12px rgba(102, 126, 234, 0.25)",
|
boxShadow: "0 4px 12px rgba(102, 126, 234, 0.25)",
|
||||||
}}
|
}}
|
||||||
@@ -203,16 +204,17 @@ export const AvatarSelector: React.FC<AvatarSelectorProps> = ({
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
) : brandAvatarFromDb ? (
|
) : brandAvatarFromDb ? (
|
||||||
<Stack spacing={2} alignItems="center">
|
<Stack spacing={2} alignItems="center" sx={{ width: "100%", maxWidth: 280 }}>
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src={brandAvatarBlobUrl || ""}
|
src={brandAvatarBlobUrl || ""}
|
||||||
alt="Available Brand Avatar"
|
alt="Available Brand Avatar"
|
||||||
sx={{
|
sx={{
|
||||||
width: 160,
|
width: "100%",
|
||||||
height: 160,
|
height: "auto",
|
||||||
objectFit: "cover",
|
maxHeight: 200,
|
||||||
borderRadius: 2.5,
|
objectFit: "contain",
|
||||||
|
borderRadius: 2,
|
||||||
border: "1.5px solid #e2e8f0",
|
border: "1.5px solid #e2e8f0",
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
filter: "grayscale(0.3)",
|
filter: "grayscale(0.3)",
|
||||||
@@ -317,16 +319,17 @@ export const AvatarSelector: React.FC<AvatarSelectorProps> = ({
|
|||||||
<Box>
|
<Box>
|
||||||
{avatarFile && avatarPreview ? (
|
{avatarFile && avatarPreview ? (
|
||||||
<Stack spacing={2} alignItems="center" sx={{ bgcolor: "#f8fafc", borderRadius: 2, p: 2 }}>
|
<Stack spacing={2} alignItems="center" sx={{ bgcolor: "#f8fafc", borderRadius: 2, p: 2 }}>
|
||||||
<Box sx={{ position: "relative", display: "inline-block" }}>
|
<Box sx={{ position: "relative", display: "inline-block", width: "100%", maxWidth: 280 }}>
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src={avatarPreviewBlobUrl || (avatarPreview.startsWith("data:") ? avatarPreview : "")}
|
src={avatarPreviewBlobUrl || (avatarPreview.startsWith("data:") ? avatarPreview : "")}
|
||||||
alt="Selfie preview"
|
alt="Selfie preview"
|
||||||
sx={{
|
sx={{
|
||||||
width: 160,
|
width: "100%",
|
||||||
height: 160,
|
height: "auto",
|
||||||
objectFit: "cover",
|
maxHeight: 200,
|
||||||
borderRadius: 2.5,
|
objectFit: "contain",
|
||||||
|
borderRadius: 2,
|
||||||
border: "2px solid #e2e8f0",
|
border: "2px solid #e2e8f0",
|
||||||
boxShadow: "0 2px 8px rgba(15, 23, 42, 0.08)",
|
boxShadow: "0 2px 8px rgba(15, 23, 42, 0.08)",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Stack, Alert, Typography, alpha } from "@mui/material";
|
import { Stack, Alert, Typography, alpha, IconButton, Collapse } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
Info as InfoIcon,
|
Info as InfoIcon,
|
||||||
Refresh as RefreshIcon,
|
Refresh as RefreshIcon,
|
||||||
AutoAwesome as AutoAwesomeIcon,
|
AutoAwesome as AutoAwesomeIcon,
|
||||||
|
ExpandMore as ExpandMoreIcon,
|
||||||
|
ExpandLess as ExpandLessIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { PrimaryButton, SecondaryButton } from "../ui";
|
import { PrimaryButton, SecondaryButton } from "../ui";
|
||||||
|
|
||||||
@@ -20,26 +22,51 @@ export const CreateActions: React.FC<CreateActionsProps> = ({
|
|||||||
canSubmit,
|
canSubmit,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
}) => {
|
}) => {
|
||||||
|
const [showInfo, setShowInfo] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setShowInfo(false);
|
||||||
|
}, 8000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack spacing={3.5}>
|
<Stack spacing={2}>
|
||||||
{/* Info Banner */}
|
{/* Collapsible Info Banner */}
|
||||||
<Alert
|
<Collapse in={showInfo}>
|
||||||
severity="info"
|
<Alert
|
||||||
icon={<InfoIcon sx={{ color: "#6366f1", fontSize: "1.125rem" }} />}
|
severity="info"
|
||||||
sx={{
|
icon={<InfoIcon sx={{ color: "#6366f1", fontSize: "1.125rem" }} />}
|
||||||
background: alpha("#f0f4ff", 0.6),
|
onClose={() => setShowInfo(false)}
|
||||||
border: "1px solid rgba(99, 102, 241, 0.15)",
|
sx={{
|
||||||
borderRadius: 2,
|
background: alpha("#f0f4ff", 0.6),
|
||||||
boxShadow: "0 1px 3px rgba(99, 102, 241, 0.08)",
|
border: "1px solid rgba(99, 102, 241, 0.15)",
|
||||||
"& .MuiAlert-message": {
|
borderRadius: 2,
|
||||||
width: "100%",
|
boxShadow: "0 1px 3px rgba(99, 102, 241, 0.08)",
|
||||||
},
|
"& .MuiAlert-message": {
|
||||||
}}
|
width: "100%",
|
||||||
>
|
},
|
||||||
<Typography variant="body2" sx={{ fontSize: "0.875rem", color: "#475569", lineHeight: 1.6, fontWeight: 400 }}>
|
}}
|
||||||
Podcast avatar Image is required, brand avatar is Default, you can choose existing images from asset library Or Upload your Picture. If not, AI Avatar will be generated automatically.
|
>
|
||||||
</Typography>
|
<Typography variant="body2" sx={{ fontSize: "0.875rem", color: "#475569", lineHeight: 1.6, fontWeight: 400 }}>
|
||||||
</Alert>
|
Podcast avatar Image is required. Brand avatar is default. You can choose from asset library or upload your picture. If not, AI Avatar will be generated automatically.
|
||||||
|
</Typography>
|
||||||
|
</Alert>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
{!showInfo && (
|
||||||
|
<Stack direction="row" alignItems="center" spacing={1}>
|
||||||
|
<InfoIcon sx={{ fontSize: 16, color: "#6366f1" }} />
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ color: "#6366f1", cursor: "pointer", "&:hover": { textDecoration: "underline" } }}
|
||||||
|
onClick={() => setShowInfo(true)}
|
||||||
|
>
|
||||||
|
Show tips
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
|
||||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||||
<SecondaryButton onClick={reset} startIcon={<RefreshIcon />}>
|
<SecondaryButton onClick={reset} startIcon={<RefreshIcon />}>
|
||||||
|
|||||||
Reference in New Issue
Block a user