feat: PNG logo, og:image/favicon, dashboard-driven demo/repo links
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,9 +10,13 @@
|
|||||||
<meta property="og:description" content="We build AI agents, automation & enterprise systems that work 24/7." />
|
<meta property="og:description" content="We build AI agents, automation & enterprise systems that work 24/7." />
|
||||||
<meta property="og:url" content="https://auraajenticai.cloud" />
|
<meta property="og:url" content="https://auraajenticai.cloud" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:image" content="https://auraajenticai.cloud/logo.png" />
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content="Aura Agentic AI" />
|
<meta name="twitter:title" content="Aura Agentic AI" />
|
||||||
<meta name="twitter:description" content="AI agents, automation & full-stack development — Dhaka, Bangladesh." />
|
<meta name="twitter:description" content="AI agents, automation & full-stack development — Dhaka, Bangladesh." />
|
||||||
|
<meta name="twitter:image" content="https://auraajenticai.cloud/logo.png" />
|
||||||
|
<link rel="icon" type="image/png" href="logo.png" />
|
||||||
|
<link rel="apple-touch-icon" href="logo.png" />
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
|||||||
+16
-11
@@ -43,17 +43,22 @@ const Icons = {
|
|||||||
Send: (p) => <Icon {...p}><path d="m22 2-7 20-4-9-9-4 20-7z" /></Icon>,
|
Send: (p) => <Icon {...p}><path d="m22 2-7 20-4-9-9-4 20-7z" /></Icon>,
|
||||||
Globe: (p) => <Icon {...p}><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></Icon>,
|
Globe: (p) => <Icon {...p}><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></Icon>,
|
||||||
Terminal: (p) => <Icon {...p}><path d="m4 17 6-6-6-6M12 19h8" /></Icon>,
|
Terminal: (p) => <Icon {...p}><path d="m4 17 6-6-6-6M12 19h8" /></Icon>,
|
||||||
Logo: ({ size = 28 }) => (
|
Logo: ({ size = 28, full = false }) => (
|
||||||
<svg width={size} height={size} viewBox="0 0 32 32" fill="none">
|
<img
|
||||||
<defs>
|
src="logo.png"
|
||||||
<linearGradient id="logoG" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
width={full ? size * 4 : size}
|
||||||
<stop stopColor="var(--accent)" />
|
height={size}
|
||||||
<stop offset="1" stopColor="var(--accent-2)" />
|
alt="Aura Agentic AI"
|
||||||
</linearGradient>
|
style={{
|
||||||
</defs>
|
objectFit: "contain",
|
||||||
<rect x="2" y="2" width="28" height="28" rx="8" fill="none" stroke="url(#logoG)" strokeWidth="1.5" />
|
objectPosition: "center",
|
||||||
<path d="M10 22 L16 8 L22 22 M12.5 17 H19.5" stroke="url(#logoG)" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" fill="none" />
|
borderRadius: full ? 0 : 4,
|
||||||
</svg>
|
mixBlendMode: "screen",
|
||||||
|
display: "block",
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
onError={e => { e.currentTarget.style.display = "none"; }}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+34
-5
@@ -35,9 +35,36 @@ const PageHero = ({ eyebrow, title, sub, children }) => (
|
|||||||
|
|
||||||
// ─── SERVICES PAGE ────────────────────────────────────────────────────────────
|
// ─── SERVICES PAGE ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const DASHBOARD_API = 'https://aura.auraajenticai.cloud';
|
||||||
|
|
||||||
const ServicesPage = ({ lang }) => {
|
const ServicesPage = ({ lang }) => {
|
||||||
const D = PORTFOLIO_DATA;
|
const D = PORTFOLIO_DATA;
|
||||||
const [active, setActive] = React.useState(null);
|
const [active, setActive] = React.useState(null);
|
||||||
|
const [svcLinks, setSvcLinks] = React.useState({});
|
||||||
|
|
||||||
|
// Fetch demo/repo overrides from Dashboard (stale-while-revalidate)
|
||||||
|
React.useEffect(() => {
|
||||||
|
const CACHE_KEY = 'aura_svc_links';
|
||||||
|
const CACHE_TTL = 10 * 60 * 1000;
|
||||||
|
try {
|
||||||
|
const cached = sessionStorage.getItem(CACHE_KEY);
|
||||||
|
if (cached) {
|
||||||
|
const { data, ts } = JSON.parse(cached);
|
||||||
|
if (Date.now() - ts < CACHE_TTL) { setSvcLinks(data); return; }
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
fetch(`${DASHBOARD_API}/api/public/services`, { signal: AbortSignal.timeout(3000) })
|
||||||
|
.then(r => r.ok ? r.json() : null)
|
||||||
|
.then(data => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const map = {};
|
||||||
|
data.forEach(s => { if (s.id) map[s.id] = { demo: s.demo, repo: s.repo }; });
|
||||||
|
setSvcLinks(map);
|
||||||
|
sessionStorage.setItem(CACHE_KEY, JSON.stringify({ data: map, ts: Date.now() }));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
@@ -53,6 +80,8 @@ const ServicesPage = ({ lang }) => {
|
|||||||
{D.services.map((svc, i) => {
|
{D.services.map((svc, i) => {
|
||||||
const c = COLOR_MAP[svc.color] || COLOR_MAP.violet;
|
const c = COLOR_MAP[svc.color] || COLOR_MAP.violet;
|
||||||
const isOpen = active === svc.id;
|
const isOpen = active === svc.id;
|
||||||
|
const demo = (svcLinks[svc.id]?.demo) || svc.demo;
|
||||||
|
const repo = (svcLinks[svc.id]?.repo) || svc.repo;
|
||||||
const isNew = !!svc.badge;
|
const isNew = !!svc.badge;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -144,11 +173,11 @@ const ServicesPage = ({ lang }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Demo / Repo links */}
|
{/* Demo / Repo links */}
|
||||||
{(svc.demo || svc.repo) && (
|
{(demo || repo) && (
|
||||||
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
|
||||||
{svc.demo && (
|
{demo && (
|
||||||
<a
|
<a
|
||||||
href={svc.demo}
|
href={demo}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
@@ -167,9 +196,9 @@ const ServicesPage = ({ lang }) => {
|
|||||||
Live Demo
|
Live Demo
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{svc.repo && (
|
{repo && (
|
||||||
<a
|
<a
|
||||||
href={svc.repo}
|
href={repo}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
|
|||||||
Reference in New Issue
Block a user