init
This commit is contained in:
@@ -1,3 +1,15 @@
|
||||
export const API_BASE_URL =
|
||||
import.meta.env.VITE_API_BASE_URL ||
|
||||
`${window.location.protocol}//${window.location.hostname}:8010`;
|
||||
/**
|
||||
* API base URL strategy
|
||||
* - If `VITE_API_BASE_URL` is provided, always use it.
|
||||
* - In production, default to same-origin (expects Apache/Nginx reverse proxy).
|
||||
* - In dev, default to local backend.
|
||||
*/
|
||||
export const API_BASE_URL = (() => {
|
||||
const fromEnv = import.meta.env.VITE_API_BASE_URL;
|
||||
if (fromEnv) return fromEnv.replace(/\/+$/, '');
|
||||
|
||||
// Vite replaces `import.meta.env.PROD/DEV` at build time.
|
||||
if (import.meta.env.PROD) return window.location.origin;
|
||||
|
||||
return 'http://localhost:8010';
|
||||
})();
|
||||
|
||||
@@ -2,6 +2,21 @@ import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { API_BASE_URL } from '../config';
|
||||
|
||||
function normalizeExternalUrl(raw) {
|
||||
if (!raw) return '';
|
||||
const s = String(raw).trim();
|
||||
if (!s) return '';
|
||||
// already absolute
|
||||
if (/^https?:\/\//i.test(s)) return s;
|
||||
// protocol-relative
|
||||
if (s.startsWith('//')) return `https:${s}`;
|
||||
// common "missing scheme" cases from DB/meta
|
||||
if (s.startsWith('img.youtube.com/')) return `https://${s}`;
|
||||
if (s.startsWith('www.youtube.com/')) return `https://${s}`;
|
||||
if (s.startsWith('youtube.com/')) return `https://${s}`;
|
||||
return s; // leave as-is (could be relative path on same origin)
|
||||
}
|
||||
|
||||
export default function AiNewsPage() {
|
||||
const { user } = useAuth();
|
||||
const [news, setNews] = useState([]);
|
||||
@@ -101,10 +116,20 @@ export default function AiNewsPage() {
|
||||
<div key={n.id} className="card" style={{ marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
{n.meta?.image ? (
|
||||
<img src={n.meta.image} alt="thumb" style={{ width: 96, height: 96, objectFit: 'cover', borderRadius: 8 }} />
|
||||
<img
|
||||
src={normalizeExternalUrl(n.meta.image)}
|
||||
alt="thumb"
|
||||
style={{ width: 96, height: 96, objectFit: 'cover', borderRadius: 8 }}
|
||||
referrerPolicy="no-referrer"
|
||||
/>
|
||||
) : null}
|
||||
<div style={{ flex: 1 }}>
|
||||
<a href={n.meta?.url || n.url} target="_blank" rel="noreferrer" style={{ fontWeight: 600, color: '#1976d2', textDecoration: 'none' }}>
|
||||
<a
|
||||
href={normalizeExternalUrl(n.meta?.url || n.url)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{ fontWeight: 600, color: '#1976d2', textDecoration: 'none' }}
|
||||
>
|
||||
{n.meta?.title || n.url}
|
||||
</a>
|
||||
<div style={{ marginTop: 6, color: '#555', lineHeight: 1.5 }}>{n.meta?.description}</div>
|
||||
|
||||
Reference in New Issue
Block a user