diff --git a/src/App.tsx b/src/App.tsx index ce5f9b2..fa7b957 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -403,6 +403,13 @@ const TimelineSection = ({ const actionsDisabled = timelineType === "notifications"; const emptyMessage = timelineType === "notifications" ? "표시할 알림이 없습니다." : "표시할 글이 없습니다."; + useEffect(() => { + if (!timeline.error) { + return; + } + showToast(timeline.error, { tone: "error" }); + }, [showToast, timeline.error]); + useEffect(() => { const el = scrollRef.current; if (!el) { @@ -475,6 +482,13 @@ const TimelineSection = ({ refreshNotifications(); }, [notificationsOpen, refreshNotifications]); + useEffect(() => { + if (!notificationsError) { + return; + } + showToast(notificationsError, { tone: "error" }); + }, [notificationsError, showToast]); + const handleToggleFavourite = async (status: Status) => { if (!account) { onError("계정을 선택해주세요."); @@ -649,7 +663,6 @@ const TimelineSection = ({
{notificationsError}
: null} {notificationItems.length === 0 && !notificationsLoading ? (표시할 알림이 없습니다.
) : null} @@ -785,7 +798,6 @@ const TimelineSection = ({계정을 선택하면 타임라인을 불러옵니다.
: null} - {account && timeline.error ?{timeline.error}
: null} {account && timeline.items.length === 0 && !timeline.loading ? ({emptyMessage}
) : null} @@ -836,10 +848,14 @@ const TimelineSection = ({ ); }; -type ThemeMode = "default" | "christmas" | "sky-pink" | "monochrome"; +type ThemeMode = "default" | "christmas" | "sky-pink" | "monochrome" | "matcha-core"; const isThemeMode = (value: string): value is ThemeMode => - value === "default" || value === "christmas" || value === "sky-pink" || value === "monochrome"; + value === "default" || + value === "christmas" || + value === "sky-pink" || + value === "monochrome" || + value === "matcha-core"; const getStoredTheme = (): ThemeMode => { const storedTheme = localStorage.getItem("textodon.theme"); @@ -888,6 +904,7 @@ export const App = () => { const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [mobileComposeOpen, setMobileComposeOpen] = useState(false); const { services, accountsState } = useAppContext(); + const { showToast } = useToast(); const [sections, setSections] = useStateOAuth 인증 중...
: null} - {actionError ?{actionError}
: null} {route === "home" ? ({error}
: null} diff --git a/src/ui/components/ComposeBox.tsx b/src/ui/components/ComposeBox.tsx index c3c71d5..b59472b 100644 --- a/src/ui/components/ComposeBox.tsx +++ b/src/ui/components/ComposeBox.tsx @@ -3,6 +3,7 @@ import type { Account, Visibility } from "../../domain/types"; import type { MastodonApi } from "../../services/MastodonApi"; import { useEmojiManager, type EmojiItem } from "../hooks/useEmojiManager"; import { useImageZoom } from "../hooks/useImageZoom"; +import { useToast } from "../state/ToastContext"; import { calculateCharacterCount, getCharacterLimit, @@ -88,6 +89,8 @@ export const ComposeBox = ({ } = useImageZoom(imageContainerRef, imageRef); const [emojiPanelOpen, setEmojiPanelOpen] = useState(false); const [recentOpen, setRecentOpen] = useState(true); + const { showToast } = useToast(); + const lastEmojiErrorRef = useRef{followError}
: null} {profileLoading ?프로필을 불러오는 중...
: null} - {profileError ?{profileError}
: null} {bioContent ? bioContent.type === "html" ? @@ -929,7 +950,6 @@ export const ProfileModal = ({{itemsError}
: null} {itemsLoading && items.length === 0 ?게시글을 불러오는 중...
: null} {!itemsLoading && items.length === 0 ?표시할 글이 없습니다.
: null} {items.length > 0 ? ( diff --git a/src/ui/components/ReactionPicker.tsx b/src/ui/components/ReactionPicker.tsx index 3b1ea6e..18f507b 100644 --- a/src/ui/components/ReactionPicker.tsx +++ b/src/ui/components/ReactionPicker.tsx @@ -3,6 +3,7 @@ import type { Account, ReactionInput } from "../../domain/types"; import type { MastodonApi } from "../../services/MastodonApi"; import { useClickOutside } from "../hooks/useClickOutside"; import { useEmojiManager, type EmojiItem } from "../hooks/useEmojiManager"; +import { useToast } from "../state/ToastContext"; export const ReactionPicker = ({ account, @@ -21,6 +22,8 @@ export const ReactionPicker = ({ const [emojiSearchQuery, setEmojiSearchQuery] = useState(""); const buttonRef = useRef