Files
Zakaria a46764fb1b
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
first-commit
2026-05-04 14:58:14 -04:00

224 lines
9.4 KiB
Plaintext

---
import Page from '../page';
import '../globals.css';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { heroImage } from '../image-assets';
const title = 'Open Design — Design with the agent already on your laptop.';
const description =
'The open-source alternative to Claude Design. Your existing coding agent — Claude · Codex · Cursor · Gemini · OpenCode · Qwen — becomes the design engine, driven by 31 composable skills and 72 brand-grade design systems.';
const canonical = new URL(Astro.url.pathname, Astro.site).toString();
const pageHtml = renderToStaticMarkup(createElement(Page));
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#efe7d2" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Open Design" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={heroImage} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={heroImage} />
</head>
<body>
<Fragment set:html={pageHtml} />
<script is:inline>
(() => {
const formatStars = (count) => {
if (!Number.isFinite(count) || count <= 0) return '0';
if (count < 1000) return String(count);
return `${(count / 1000).toFixed(1).replace(/\.0$/, '')}K`;
};
// Pull a clean 'v0.3.0'-style label from a GitHub release record.
// We prefer release.name (e.g. 'Open Design 0.3.0') because that's
// what we hand-author; fall back to tag_name (e.g.
// 'open-design-v0.3.0') with the project prefix stripped.
//
// Expected input shapes (release.name / release.tag_name):
// { name: 'Open Design 0.3.0', tag_name: 'v0.3.0' } → 'v0.3.0'
// { name: 'Open Design v0.3.0', tag_name: 'open-design-v0.3.0' } → 'v0.3.0'
// { name: '0.3.0-beta.1', tag_name: 'open-design_0.3.0' } → 'v0.3.0-beta.1' (name wins)
// { name: null, tag_name: 'open-design-v0.3.0' } → 'v0.3.0' (tag fallback)
// { name: null, tag_name: null } → null (caller skips)
const formatVersion = (release) => {
const fromTag = (tag) => {
if (typeof tag !== 'string') return null;
const cleaned = tag.replace(/^open-design[-_]?v?/i, '').trim();
return cleaned ? `v${cleaned.replace(/^v/, '')}` : null;
};
const fromName = (name) => {
if (typeof name !== 'string') return null;
const m = name.match(/(\d+\.\d+\.\d+(?:[-+][\w.]+)?)/);
return m ? `v${m[1]}` : null;
};
return fromName(release?.name) ?? fromTag(release?.tag_name) ?? null;
};
const enhanceHeader = () => {
const nav = document.querySelector('[data-nav-headroom]');
if (nav) {
let lastY = window.scrollY;
const showTopThreshold = 100;
const scrollDelta = 6;
window.addEventListener(
'scroll',
() => {
const y = window.scrollY;
const delta = y - lastY;
if (y <= showTopThreshold) nav.classList.remove('is-hidden');
else if (delta > scrollDelta) nav.classList.add('is-hidden');
else if (delta < -scrollDelta) nav.classList.remove('is-hidden');
lastY = y;
},
{ passive: true },
);
}
const stars = document.querySelector('[data-github-stars]');
if (stars) {
fetch('https://api.github.com/repos/nexu-io/open-design', {
headers: { Accept: 'application/vnd.github+json' },
})
.then((r) => (r.ok ? r.json() : Promise.reject(new Error('http error'))))
.then((data) => {
if (typeof data?.stargazers_count === 'number') {
stars.textContent = formatStars(data.stargazers_count);
}
})
.catch(() => {});
}
// Latest stable release powers every "v0.x.y" badge on the page
// (topbar pulse, hero CTA-foot, footer download). Hits one
// unauthenticated API call per page view; the static fallback in
// each slot keeps the layout sane if the request fails or 403s.
const versionSlots = document.querySelectorAll('[data-github-version]');
if (versionSlots.length === 0) return;
fetch('https://api.github.com/repos/nexu-io/open-design/releases/latest', {
headers: { Accept: 'application/vnd.github+json' },
})
.then((r) => (r.ok ? r.json() : Promise.reject(new Error('http error'))))
.then((data) => {
const label = formatVersion(data);
if (!label) return;
for (const slot of versionSlots) slot.textContent = label;
})
.catch(() => {});
};
const enhanceWire = () => {
const track = document.querySelector('[data-wire-contributors-track]');
const count = document.querySelector('[data-wire-contributors-count]');
if (!track) return;
const roleOverrides = {
tw93: 'kami',
op7418: 'guizang',
alchaincyf: 'huashu',
OpenCoworkAI: 'codesign',
'nexu-io': 'studio',
lewislulu: 'html-ppt',
};
const roleFor = (login, contributions) =>
roleOverrides[login] ?? `${contributions} ${contributions === 1 ? 'commit' : 'commits'}`;
const isContributor = (value) =>
value &&
typeof value.login === 'string' &&
typeof value.html_url === 'string' &&
typeof value.type === 'string' &&
typeof value.contributions === 'number';
const renderContributor = (contributor, index) => {
const link = document.createElement('a');
link.className = 'wire-item is-link';
link.href = contributor.href;
link.target = '_blank';
link.rel = 'noreferrer noopener';
link.setAttribute('aria-label', `Open ${contributor.handle} on GitHub`);
link.dataset.liveWireItem = String(index);
const dot = document.createElement('span');
dot.className = 'wire-dot';
dot.textContent = '·';
const handle = document.createElement('span');
handle.className = 'wire-handle';
handle.textContent = `@${contributor.handle}`;
const role = document.createElement('span');
role.className = 'wire-role';
role.textContent = contributor.role;
link.append(dot, handle, role);
return link;
};
fetch('https://api.github.com/repos/nexu-io/open-design/contributors?per_page=12', {
headers: { Accept: 'application/vnd.github+json' },
})
.then((r) => (r.ok ? r.json() : Promise.reject(new Error('http error'))))
.then((data) => {
if (!Array.isArray(data)) return;
const live = data
.filter(isContributor)
.filter((c) => c.type !== 'Bot' && !c.login.endsWith('[bot]'))
.slice(0, 12)
.map((c) => ({
handle: c.login,
role: roleFor(c.login, c.contributions),
href: c.html_url,
}));
if (live.length === 0) return;
live.push({
handle: 'you',
role: 'be next',
href: 'https://github.com/nexu-io/open-design/graphs/contributors',
});
if (count) count.textContent = String(Math.max(0, live.length - 1));
track.replaceChildren(
...[...live, ...live].map((contributor, index) => renderContributor(contributor, index)),
);
})
.catch(() => {});
};
const elements = document.querySelectorAll('[data-reveal]:not([data-revealed])');
enhanceHeader();
enhanceWire();
if (elements.length === 0) return;
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduceMotion || !('IntersectionObserver' in window)) {
for (const el of elements) el.dataset.revealed = 'true';
return;
}
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
entry.target.dataset.revealed = 'true';
observer.unobserve(entry.target);
}
},
{ threshold: 0.12, rootMargin: '0px 0px -8% 0px' },
);
for (const el of elements) observer.observe(el);
})();
</script>
</body>
</html>