Fix time filter refresh and polish search UI
This commit is contained in:
parent
d7700b154b
commit
5cc21194a0
|
|
@ -1,10 +1,25 @@
|
|||
const API_BASE = "/api";
|
||||
function apiBase() {
|
||||
const raw =
|
||||
(import.meta?.env?.VITE_API_BASE_URL || "")
|
||||
.toString()
|
||||
.replace(/\/+$/, "");
|
||||
if (raw) return raw + "/api";
|
||||
try {
|
||||
if (typeof window !== "undefined") {
|
||||
const host = window.location.hostname || "";
|
||||
if (host.startsWith("www.")) {
|
||||
return `https://${host.replace(/^www\./, "")}/api`;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
return "/api";
|
||||
}
|
||||
|
||||
const cache = new Map(); // key -> Promise
|
||||
|
||||
export async function fetchDefaultTemplate(typeKey = "news") {
|
||||
const t = (typeKey || "news").toLowerCase().trim();
|
||||
const res = await fetch(`${API_BASE}/templates/default?type=${encodeURIComponent(t)}`, {
|
||||
const res = await fetch(`${apiBase()}/templates/default?type=${encodeURIComponent(t)}`, {
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default function TimeFilterButtons({ active, onSelect }) {
|
|||
{ code: "NOW", label: "Now", icon: "fa-solid fa-bolt" },
|
||||
{ code: "TODAY", label: "Today", icon: "fa-solid fa-sun" },
|
||||
{ code: "RECENT", label: "Recent", icon: "fa-solid fa-clock-rotate-left" },
|
||||
{ code: "PAST", label: "Past", icon: "fa-solid fa-hourglass-half" },
|
||||
{ code: "PAST", label: "Old", icon: "fa-solid fa-hourglass-half" },
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -813,7 +813,6 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
|||
<div class="sw-modal-badge">MAIN NEWS</div>
|
||||
<div class="sw-modal-meta">
|
||||
${author ? `<div class="sw-modal-author-avatar" data-username="${escapeHtml(author)}"></div>` : ""}
|
||||
${author ? `<div class="sw-inline-avatar" data-username="${escapeHtml(author)}"></div>` : ""}
|
||||
${metaLeft ? `<span class="sw-author-link" data-author="${escapeHtml(author)}" style="cursor: pointer; text-decoration: underline;">${escapeHtml(metaLeft)}</span>` : ""}
|
||||
${metaRight ? `<span>• ${escapeHtml(metaRight)}</span>` : ""}
|
||||
<span>• ${escapeHtml(relTime)}</span>
|
||||
|
|
@ -893,7 +892,6 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
|
|||
<div class="sw-modal-badge">${escapeHtml(cat)}</div>
|
||||
<div class="sw-modal-meta">
|
||||
${author ? `<div class="sw-modal-author-avatar" data-username="${escapeHtml(author)}"></div>` : ""}
|
||||
${author ? `<div class="sw-inline-avatar" data-username="${escapeHtml(author)}"></div>` : ""}
|
||||
${metaLeft ? `<span class="sw-author-link" data-author="${escapeHtml(author)}" style="cursor: pointer; text-decoration: underline;">${escapeHtml(metaLeft)}</span>` : ""}
|
||||
${metaRight ? `<span>• ${escapeHtml(metaRight)}</span>` : ""}
|
||||
<span>• ${escapeHtml(relTime)}</span>
|
||||
|
|
|
|||
|
|
@ -858,9 +858,8 @@ export function usePostsEngine({
|
|||
if (pc !== catCode) return false;
|
||||
}
|
||||
if (!matchesSubFilter(p, subFilter)) return false;
|
||||
const skipTimeFilter =
|
||||
tf === "RECENT" && lastFetchRef.current?.timeFilter === "RECENT";
|
||||
if (!skipTimeFilter && !matchesTimeFilter(effectivePostTime(p), tf)) return false;
|
||||
const postTf = (p?._swTimeFilter || "").toString();
|
||||
if (postTf !== tf && !matchesTimeFilter(effectivePostTime(p), tf)) return false;
|
||||
if (!searchResultsRef.current && !matchesSearch(p, searchQuery)) return false;
|
||||
return true;
|
||||
});
|
||||
|
|
@ -1075,6 +1074,7 @@ export function usePostsEngine({
|
|||
const normalized = normalizePostId(p);
|
||||
const key = getPostKey(normalized);
|
||||
if (!key) continue;
|
||||
if (timeFilter) normalized._swTimeFilter = timeFilter;
|
||||
const prior = byId.get(key);
|
||||
if (prior) {
|
||||
byId.set(key, { ...prior, ...normalized });
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ export default function SmartSearchBar({
|
|||
const [active, setActive] = useState(-1);
|
||||
const [err, setErr] = useState("");
|
||||
const [hasSearched, setHasSearched] = useState(false);
|
||||
const [focused, setFocused] = useState(false);
|
||||
|
||||
const abortRef = useRef(null);
|
||||
const skipSearchRef = useRef(false);
|
||||
|
|
@ -98,6 +99,7 @@ export default function SmartSearchBar({
|
|||
abortRef.current = ctrl;
|
||||
setLoading(true);
|
||||
setErr("");
|
||||
setOpen(true);
|
||||
|
||||
try {
|
||||
console.log('[SmartSearchBar] Searching for:', searchQuery);
|
||||
|
|
@ -112,6 +114,7 @@ export default function SmartSearchBar({
|
|||
console.error('[SmartSearchBar] Search error:', e);
|
||||
setErr((e && e.message) ? e.message : "Search error");
|
||||
setItems([]);
|
||||
setOpen(true);
|
||||
} finally {
|
||||
if (!ctrl.signal.aborted) setLoading(false);
|
||||
}
|
||||
|
|
@ -125,6 +128,8 @@ export default function SmartSearchBar({
|
|||
return;
|
||||
}
|
||||
|
||||
if (query) setOpen(true);
|
||||
|
||||
if (abortRef.current) abortRef.current.abort();
|
||||
|
||||
const t = setTimeout(() => {
|
||||
|
|
@ -137,7 +142,7 @@ export default function SmartSearchBar({
|
|||
};
|
||||
}, [q]);
|
||||
|
||||
const showList = open && (items.length > 0 || loading || err);
|
||||
const showList = (open || focused) && (items.length > 0 || loading || err || q.trim());
|
||||
const clearOnFocusRef = useRef(false);
|
||||
|
||||
const pick = (it, reason = "click") => {
|
||||
|
|
@ -214,6 +219,7 @@ export default function SmartSearchBar({
|
|||
}
|
||||
}}
|
||||
onFocus={() => {
|
||||
setFocused(true);
|
||||
if (clearOnFocusRef.current) {
|
||||
clearOnFocusRef.current = false;
|
||||
setQ("");
|
||||
|
|
@ -228,6 +234,9 @@ export default function SmartSearchBar({
|
|||
triggerSearch("");
|
||||
}
|
||||
}}
|
||||
onBlur={() => {
|
||||
setTimeout(() => setFocused(false), 120);
|
||||
}}
|
||||
onKeyDown={onKeyDown}
|
||||
placeholder={placeholder}
|
||||
aria-label="Search"
|
||||
|
|
|
|||
Loading…
Reference in New Issue