From 3d851ae4f0e19388e3451b79c235db9ef07b1c6d Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Tue, 1 Jul 2025 13:28:58 -0700 Subject: add fallbacks for optional environment variables --- site/src/components/NewsFeed.tsx | 213 ++++++++++++++++++++++++++++++--------- 1 file changed, 166 insertions(+), 47 deletions(-) (limited to 'site/src/components') diff --git a/site/src/components/NewsFeed.tsx b/site/src/components/NewsFeed.tsx index 62d4420..ebfcc28 100644 --- a/site/src/components/NewsFeed.tsx +++ b/site/src/components/NewsFeed.tsx @@ -26,27 +26,47 @@ interface NewsFeedProps { export const NewsFeed: React.FC = ({ newsItems }) => { const [showEnglish, setShowEnglish] = useState>({}); const [expanded, setExpanded] = useState>({}); - const [currentImageIndex, setCurrentImageIndex] = useState>({}); - const [loadingImages, setLoadingImages] = useState>({}); + const [currentImageIndex, setCurrentImageIndex] = useState< + Record + >({}); + const [loadingImages, setLoadingImages] = useState>( + {}, + ); const [searchParams] = useSearchParams(); const isMoe = searchParams.has("moe"); + const pfpBaseUrl = import.meta.env.VITE_PFP_BASE_URL; + const middlewareBase = import.meta.env.VITE_MIDDLEWARE_BASE_URL; - const toggleLanguage = (id: string) => setShowEnglish((prev) => ({ ...prev, [id]: !prev[id] })); - const toggleExpand = (id: string) => setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); + const toggleLanguage = (id: string) => + setShowEnglish((prev) => ({ ...prev, [id]: !prev[id] })); + const toggleExpand = (id: string) => + setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); const changeImage = (id: string, i: number) => { - if (currentImageIndex[id] == i) - return + if (currentImageIndex[id] == i) return; setCurrentImageIndex((p) => ({ ...p, [id]: i })); setLoadingImages((p) => ({ ...p, [id]: true })); }; - const handleImageLoad = (id: string) => setLoadingImages((p) => ({ ...p, [id]: false })); + const handleImageLoad = (id: string) => + setLoadingImages((p) => ({ ...p, [id]: false })); const PREVIEW_CHAR_LIMIT = 600; useEffect(() => { const initialImageIndex: Record = {}; newsItems.forEach((news) => { - const contentHash = news.content.split('').reduce((hash, char) => ((hash << 5) + hash) + char.charCodeAt(0), 5381) >>> 0; - const headlineHash = (news.headline || 'null').split('').reduce((hash, char) => ((hash << 5) + hash) + char.charCodeAt(0), 5381) >>> 0; + const contentHash = + news.content + .split("") + .reduce( + (hash, char) => (hash << 5) + hash + char.charCodeAt(0), + 5381, + ) >>> 0; + const headlineHash = + (news.headline || "null") + .split("") + .reduce( + (hash, char) => (hash << 5) + hash + char.charCodeAt(0), + 5381, + ) >>> 0; const newsId = `${news.identifier}-${news.timestamp}-${contentHash.toString(16)}-${headlineHash.toString(16)}`; initialImageIndex[newsId] = 0; }); @@ -55,12 +75,11 @@ export const NewsFeed: React.FC = ({ newsItems }) => { useEffect(() => { const fragment = window.location.hash.slice(1); - if(fragment){ + if (fragment) { const el = document.getElementById(fragment); - if(el){ - el.scrollIntoView({behavior: "smooth", block: "start"}); - } - else{ + if (el) { + el.scrollIntoView({ behavior: "smooth", block: "start" }); + } else { alert("News Post doesn't or no longer exists..."); } } @@ -69,55 +88,131 @@ export const NewsFeed: React.FC = ({ newsItems }) => { return (
{newsItems.map((news) => { - const date = new Date(news.timestamp * 1000).toLocaleDateString("ja-JP", { year: "numeric", month: "2-digit", day: "2-digit" }); - const contentHash = news.content.split('').reduce((hash, char) => ((hash << 5) + hash) + char.charCodeAt(0), 5381) >>> 0; - const headlineHash = (news.headline || 'null').split('').reduce((hash, char) => ((hash << 5) + hash) + char.charCodeAt(0), 5381) >>> 0; + const date = new Date(news.timestamp * 1000).toLocaleDateString( + "ja-JP", + { year: "numeric", month: "2-digit", day: "2-digit" }, + ); + const contentHash = + news.content + .split("") + .reduce( + (hash, char) => (hash << 5) + hash + char.charCodeAt(0), + 5381, + ) >>> 0; + const headlineHash = + (news.headline || "null") + .split("") + .reduce( + (hash, char) => (hash << 5) + hash + char.charCodeAt(0), + 5381, + ) >>> 0; const newsId = `${news.identifier}-${news.timestamp}-${contentHash.toString(16)}-${headlineHash.toString(16)}`; const isEnglish = !!showEnglish[newsId]; const hasTranslation = news.en_headline || news.en_content; - const displayHeadline = isEnglish && news.en_headline ? news.en_headline : news.headline; - const displayContent = isEnglish && news.en_content ? news.en_content : news.content; + const displayHeadline = + isEnglish && news.en_headline ? news.en_headline : news.headline; + const displayContent = + isEnglish && news.en_content ? news.en_content : news.content; const isLong = displayContent.length > PREVIEW_CHAR_LIMIT; const isExpanded = !!expanded[newsId]; - const contentToShow = isLong && !isExpanded ? displayContent.slice(0, PREVIEW_CHAR_LIMIT) + "…" : displayContent; + const contentToShow = + isLong && !isExpanded + ? displayContent.slice(0, PREVIEW_CHAR_LIMIT) + "…" + : displayContent; return ( -
+
{hasTranslation && ( - )}
- {displayHeadline &&

{displayHeadline}

} + {displayHeadline && ( +

{displayHeadline}

+ )}

- {contentToShow.split(/(\[.*?\]\(.*?\)|https?:\/\/[^\s]+)/g).map((part, idx) => { - const m = part.match(/\[(.*?)\]\((.*?)\)/); - const u = part.match(/https?:\/\/[^\s]+/); - if (m) return {m[1]}; - if (u) return {u[0]}; - return part; - })} + {contentToShow + .split(/(\[.*?\]\(.*?\)|https?:\/\/[^\s]+)/g) + .map((part, idx) => { + const m = part.match(/\[(.*?)\]\((.*?)\)/); + const u = part.match(/https?:\/\/[^\s]+/); + if (m) + return ( + + {m[1]} + + ); + if (u) + return ( + + {u[0]} + + ); + return part; + })}

{isLong && ( - )} @@ -129,10 +224,17 @@ export const NewsFeed: React.FC = ({ newsItems }) => { href={`#${newsId}`} onClick={(e) => { e.preventDefault(); - const pathname = window.location.pathname === '/' ? '/news' : window.location.pathname.replace(/^\/game/, ''); - const url = `https://ac.moekyun.me${pathname}?post=${newsId}`; + const pathname = + window.location.pathname === "/" + ? "/news" + : window.location.pathname.replace(/^\/game/, ""); + const url = middlewareBase + ? `${middlewareBase}${pathname}?post=${newsId}` + : `${window.location.origin}${pathname === "/news" ? "" : pathname}#${newsId}`; navigator.clipboard.writeText(url); - alert("Copied Direct Link to Post (Older news are automatically culled after some time)"); + alert( + "Copied Direct Link to Post (Older news are automatically culled after some time)", + ); }} title="Copy permalink" className="text-xs text-blue-400 hover:underline cursor-pointer" @@ -143,15 +245,21 @@ export const NewsFeed: React.FC = ({ newsItems }) => { {/* AI Disclaimer */} {news.is_ai_summary && ( -
- The information above is written by AI / 上記の情報はAIによって生成されました。 +
+ The information above is written by AI / + 上記の情報はAIによって生成されました。
)} {/* Machine TL Disclaimer */} - {hasTranslation && isEnglish && ( -
- The information above is machine translated and may contain inaccuracies + {hasTranslation && isEnglish && ( +
+ The information above is machine translated and may contain + inaccuracies
)} @@ -187,8 +295,12 @@ export const NewsFeed: React.FC = ({ newsItems }) => { onClick={() => changeImage(newsId, idx)} className={`w-9 h-9 flex-shrink-0 rounded-sm flex items-center justify-center ${ currentImageIndex[newsId] === idx - ? isMoe ? "bg-pink-500 text-white" : "bg-blue-600 text-white" - : isMoe ? "bg-pink-200 text-pink-800 hover:bg-pink-300" : "bg-gray-700 text-gray-300 hover:bg-gray-600" + ? isMoe + ? "bg-pink-500 text-white" + : "bg-blue-600 text-white" + : isMoe + ? "bg-pink-200 text-pink-800 hover:bg-pink-300" + : "bg-gray-700 text-gray-300 hover:bg-gray-600" }`} > {idx + 1} @@ -201,8 +313,15 @@ export const NewsFeed: React.FC = ({ newsItems }) => { )} {news.url && ( -
- + -- cgit v1.2.3