Skip to content
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bc95a05
temp: add new layout mockup (AI-generated)
vitorvasc Apr 30, 2026
47645dd
feat(projects): add project index and frontmatter schema for initiati…
vitorvasc May 6, 2026
475e21c
chore: move design-brief and mockups to projects folder
vitorvasc May 6, 2026
af5341e
docs: initialize project overview documentation
vitorvasc May 6, 2026
1cda2c4
docs: add detailed layout plan for the home page design
vitorvasc May 6, 2026
a8a929e
docs: add initial draft for ecosystem landing pages plan
vitorvasc May 6, 2026
2985a87
docs: add initial draft for list page plan
vitorvasc May 6, 2026
9c49030
docs: add initial draft for detail page plan
vitorvasc May 6, 2026
dc0d029
docs: add initial draft for Explorer UI/UX design workspace
vitorvasc May 6, 2026
369898a
docs: add roadmap for explorer redesign and outline next steps
vitorvasc May 6, 2026
c6942f8
feat(flags): add V1 redesign feature flag for development
vitorvasc May 6, 2026
0064df0
Merge branch 'main' into feat/84-layout-mockups
vitorvasc May 6, 2026
4c5b3f1
fix file format
vitorvasc May 6, 2026
c6091b2
fix file format
vitorvasc May 6, 2026
3d20537
chore: restore DESIGN.md
vitorvasc May 6, 2026
56cf058
fix(design): clarify mockup visibility and update DESIGN.md reference
vitorvasc May 6, 2026
aaa28f4
npm run format
vitorvasc May 6, 2026
bad8f25
fix markdown linter issues
vitorvasc May 6, 2026
acce91c
Merge branch 'main' into feat/84-layout-mockups
vitorvasc May 6, 2026
a832687
docs: update roadmap; kick off PR 1
vitorvasc May 6, 2026
9625866
refactor(styles): split index.css into src/styles/ with modular partials
vitorvasc May 6, 2026
6b0fee1
refactor(theme): replace inline-style injection with typed metadata i…
vitorvasc May 6, 2026
ce275bb
refactor(theme): switch ThemeContext to mode/resolved API with persis…
vitorvasc May 6, 2026
e85a36b
feat(theme): add no-flash data-theme init script to index.html
vitorvasc May 6, 2026
5d6e993
feat(ui): add ThemeToggle component
vitorvasc May 6, 2026
3f0b741
refactor(styles): update import path for index.css to use modular styles
vitorvasc May 6, 2026
fcd8ce0
docs: update NEXT-STEPS.md
vitorvasc May 6, 2026
9fd84cc
fix(theme): fix stale resolved state in auto mode and move no-flash s…
vitorvasc May 6, 2026
0360c72
fix(docs): update last_updated dates to 2026-05-06 in multiple design…
vitorvasc May 6, 2026
5bf0a65
Merge branch 'feat/84-layout-mockups' into feat/84-pr1-theme-system
vitorvasc May 6, 2026
d4fc205
fix(theme): migrate literal-hue usages to brand primitives after prim…
vitorvasc May 6, 2026
2eb9971
Merge remote-tracking branch 'origin/main' into feat/84-pr1-theme-system
vitorvasc May 6, 2026
3d111c2
fix(icons): revert OtelLogo colors
vitorvasc May 6, 2026
58b6bbe
run prettier, fix formatting
vitorvasc May 6, 2026
a5526f3
fix(theme): address pre-merge review findings on PR 1
vitorvasc May 7, 2026
1bb6c52
Merge branch 'main' into feat/84-pr1-theme-system
vitorvasc May 7, 2026
8a1df49
Merge branch 'main' into feat/84-pr1-theme-system
vitorvasc May 8, 2026
c8c785b
Merge branch 'main' into feat/84-pr1-theme-system
vitorvasc May 8, 2026
2e2891c
Merge remote-tracking branch 'origin/main' into feat/84-pr1-theme-system
vitorvasc May 11, 2026
2a1e78e
refactor(theme): use useSyncExternalStore for system color-scheme
vitorvasc May 11, 2026
ff1f132
feat(screenshots): capture both light and dark themes
vitorvasc May 11, 2026
61bc198
chore: rewrite decision-log entries as proper single-line table rows …
vitorvasc May 11, 2026
be3ef14
refactor(theme): simplify theme detection logic in index.html
vitorvasc May 11, 2026
4dfe0d9
fix(hero): restore orange dominance in gradient and shadows
vitorvasc May 11, 2026
708905f
Merge branch 'main' into feat/84-pr1-theme-system
vitorvasc May 11, 2026
f5f0156
feat(theme): make compass and hero glow flip hue per theme
vitorvasc May 11, 2026
3cb03b1
fix(tabs): update sliding pill colors to secondary theme
vitorvasc May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions ecosystem-explorer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@
<link rel="help" type="text/plain" href="/llms.txt" />
<link rel="alternate" type="text/plain" href="/llms.txt" />
<title>OpenTelemetry Ecosystem Explorer</title>
<script>
(function () {
try {
var stored = localStorage.getItem("td-color-theme");
var resolved =
stored === "light" || stored === "dark"
? stored
: window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
document.documentElement.dataset.theme = resolved;
} catch (e) {
document.documentElement.dataset.theme = "dark";
Comment thread
vitorvasc marked this conversation as resolved.
Outdated
}
})();
</script>
</head>
<body>
<div id="root"></div>
Expand Down
131 changes: 72 additions & 59 deletions ecosystem-explorer/scripts/take-screenshots.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ const VIEWPORTS = [
{ name: "mobile", width: 390, height: 844 },
];

// Themes captured for each page/viewport. Dark first because it's the default.
const THEMES = ["dark", "light"];

async function startServer() {
return new Promise((resolve) => {
const server = http.createServer((req, res) => {
Expand Down Expand Up @@ -139,7 +142,6 @@ async function takeScreenshots() {

logTime("Launching browser...");
browser = await chromium.launch({ headless: true });
const page = await browser.newPage();

// Block external requests that can cause timeouts
const BLOCKED_HOSTS = new Set([
Expand All @@ -148,7 +150,7 @@ async function takeScreenshots() {
"fonts.googleapis.com",
"fonts.gstatic.com",
]);
await page.route("**/*", (route) => {
const blockExternal = (route) => {
try {
const hostname = new URL(route.request().url()).hostname;
if (
Expand All @@ -162,67 +164,78 @@ async function takeScreenshots() {
// If URL parsing fails, allow the request
}
route.continue();
});
};

logTime("Browser ready");

for (const viewport of VIEWPORTS) {
logTime(`Starting ${viewport.name} (${viewport.width}×${viewport.height})...`);
await page.setViewportSize({ width: viewport.width, height: viewport.height });
const p = (name) => path.join(SCREENSHOTS_DIR, `${viewport.name}-${name}.png`);

// 1. Home page
await page.goto(BASE_URL, { waitUntil: "domcontentloaded", timeout: 10000 });
await page.waitForSelector("h1", { state: "visible", timeout: 5000 });
await assertNoError(page, BASE_URL);
await page.screenshot({ path: p("home") });

// 2. Java agent instrumentation list
await page.goto(`${BASE_URL}/java-agent/instrumentation`, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, `${BASE_URL}/java-agent/instrumentation`);
await page.screenshot({ path: p("instrumentation-list") });

// 3. Java agent instrumentation detail - Details tab
const detailUrl = `${BASE_URL}/java-agent/instrumentation/${DETAIL_VERSION}/${DETAIL_NAME}`;
await page.goto(detailUrl, { waitUntil: "domcontentloaded", timeout: 10000 });
await settle(page);
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-details"), fullPage: true });

// 4. Telemetry tab (skipped gracefully if tabs aren't present in this branch)
await clickTab(page, "Telemetry");
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-telemetry"), fullPage: true });

// 5. Configuration tab (skipped gracefully if tabs aren't present in this branch)
await clickTab(page, "Configuration");
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-configuration"), fullPage: true });

// 6. Collector list
await page.goto(`${BASE_URL}/collector/components`, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, `${BASE_URL}/collector/components`);
await page.screenshot({ path: p("collector-list") });

// 7. Collector detail
const collectorDetailUrl = `${BASE_URL}/collector/components/${COLLECTOR_VERSION}/${COLLECTOR_DETAIL_ID}`;
await page.goto(collectorDetailUrl, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, collectorDetailUrl);
await page.screenshot({ path: p("collector-detail"), fullPage: true });
for (const theme of THEMES) {
logTime(`Starting theme: ${theme}`);
const context = await browser.newContext({ colorScheme: theme });
const page = await context.newPage();
await page.route("**/*", blockExternal);

logTime(`${viewport.name} done`);
try {
for (const viewport of VIEWPORTS) {
logTime(` ${theme} / ${viewport.name} (${viewport.width}×${viewport.height})...`);
await page.setViewportSize({ width: viewport.width, height: viewport.height });
const p = (name) => path.join(SCREENSHOTS_DIR, `${viewport.name}-${theme}-${name}.png`);

// 1. Home page
await page.goto(BASE_URL, { waitUntil: "domcontentloaded", timeout: 10000 });
await page.waitForSelector("h1", { state: "visible", timeout: 5000 });
await assertNoError(page, BASE_URL);
await page.screenshot({ path: p("home") });

// 2. Java agent instrumentation list
await page.goto(`${BASE_URL}/java-agent/instrumentation`, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, `${BASE_URL}/java-agent/instrumentation`);
await page.screenshot({ path: p("instrumentation-list") });

// 3. Java agent instrumentation detail - Details tab
const detailUrl = `${BASE_URL}/java-agent/instrumentation/${DETAIL_VERSION}/${DETAIL_NAME}`;
await page.goto(detailUrl, { waitUntil: "domcontentloaded", timeout: 10000 });
await settle(page);
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-details"), fullPage: true });

// 4. Telemetry tab (skipped gracefully if tabs aren't present in this branch)
await clickTab(page, "Telemetry");
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-telemetry"), fullPage: true });

// 5. Configuration tab (skipped gracefully if tabs aren't present in this branch)
await clickTab(page, "Configuration");
await assertNoError(page, detailUrl);
await page.screenshot({ path: p("detail-configuration"), fullPage: true });

// 6. Collector list
await page.goto(`${BASE_URL}/collector/components`, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, `${BASE_URL}/collector/components`);
await page.screenshot({ path: p("collector-list") });

// 7. Collector detail
const collectorDetailUrl = `${BASE_URL}/collector/components/${COLLECTOR_VERSION}/${COLLECTOR_DETAIL_ID}`;
await page.goto(collectorDetailUrl, {
waitUntil: "domcontentloaded",
timeout: 10000,
});
await settle(page);
await assertNoError(page, collectorDetailUrl);
await page.screenshot({ path: p("collector-detail"), fullPage: true });

logTime(` ${theme} / ${viewport.name} done`);
}
} finally {
await context.close();
}
}

logTime("All screenshots completed successfully!");
Expand Down
20 changes: 10 additions & 10 deletions ecosystem-explorer/src/components/icons/compass.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function Compass({ className }: { className?: string }) {
className="h-full w-full"
style={{
filter:
"drop-shadow(0 0 8px hsl(var(--primary-hsl) / 0.4)) drop-shadow(0 0 16px hsl(var(--primary-hsl) / 0.2))",
"drop-shadow(0 0 8px hsl(var(--otel-blue-hsl) / 0.4)) drop-shadow(0 0 16px hsl(var(--otel-blue-hsl) / 0.2))",
}}
>
{/* Outer ring */}
Expand All @@ -95,7 +95,7 @@ export function Compass({ className }: { className?: string }) {
cy="100"
r="95"
fill="none"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-blue-hsl))"
strokeWidth="1.5"
opacity="0.4"
/>
Expand All @@ -104,7 +104,7 @@ export function Compass({ className }: { className?: string }) {
cy="100"
r="90"
fill="none"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-blue-hsl))"
strokeWidth="0.5"
opacity="0.2"
/>
Expand All @@ -122,7 +122,7 @@ export function Compass({ className }: { className?: string }) {
y1={100 - innerR * Math.cos(angle)}
x2={100 + outerR * Math.sin(angle)}
y2={100 - outerR * Math.cos(angle)}
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-blue-hsl))"
strokeWidth={isMajor ? 1.5 : 0.5}
opacity={isMajor ? 0.7 : 0.3}
/>
Expand All @@ -140,7 +140,7 @@ export function Compass({ className }: { className?: string }) {
y={100 - r * Math.cos(angle)}
textAnchor="middle"
dominantBaseline="middle"
fill="hsl(var(--primary-hsl))"
fill="hsl(var(--otel-blue-hsl))"
className="font-mono text-sm font-bold"
>
{dir}
Expand All @@ -151,26 +151,26 @@ export function Compass({ className }: { className?: string }) {
{/* Rotating needle group */}
<g ref={needleGroupRef}>
{/* North needle */}
<polygon points="100,25 95,100 100,90 105,100" fill="hsl(var(--primary-hsl))" />
<polygon points="100,25 95,100 100,90 105,100" fill="hsl(var(--otel-blue-hsl))" />
{/* South needle */}
<polygon
points="100,175 95,100 100,110 105,100"
fill="hsl(var(--primary-hsl))"
fill="hsl(var(--otel-blue-hsl))"
opacity="0.4"
/>
</g>

{/* Center circle */}
<circle cx="100" cy="100" r="8" fill="hsl(var(--secondary-hsl))" opacity="0.6" />
<circle cx="100" cy="100" r="4" fill="hsl(var(--primary-hsl))" />
<circle cx="100" cy="100" r="8" fill="hsl(var(--otel-orange-hsl))" opacity="0.6" />
<circle cx="100" cy="100" r="4" fill="hsl(var(--otel-blue-hsl))" />

{/* Inner decorative circles */}
<circle
cx="100"
cy="100"
r="50"
fill="none"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-blue-hsl))"
strokeWidth="0.5"
opacity="0.2"
strokeDasharray="4 4"
Expand Down
41 changes: 24 additions & 17 deletions ecosystem-explorer/src/components/icons/configuration-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function ConfigurationIcon({ className }: { className?: string }) {
width="120"
height="120"
rx="8"
fill="hsl(var(--primary-hsl))"
fill="hsl(var(--otel-orange-hsl))"
opacity="0.08"
/>
<rect
Expand All @@ -38,7 +38,7 @@ export function ConfigurationIcon({ className }: { className?: string }) {
height="120"
rx="8"
fill="none"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
/>

Expand All @@ -50,7 +50,7 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="70"
x2="135"
y2="70"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.3"
/>
Expand All @@ -60,12 +60,12 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="70"
x2="95"
y2="70"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.8"
/>
{/* Knob */}
<circle cx="95" cy="70" r="8" fill="hsl(var(--primary-hsl))" />
<circle cx="95" cy="70" r="8" fill="hsl(var(--otel-orange-hsl))" />
<circle cx="95" cy="70" r="5" fill="white" opacity="0.3" />
</g>

Expand All @@ -76,7 +76,7 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="100"
x2="135"
y2="100"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.3"
/>
Expand All @@ -85,11 +85,11 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="100"
x2="120"
y2="100"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.8"
/>
<circle cx="120" cy="100" r="8" fill="hsl(var(--primary-hsl))" />
<circle cx="120" cy="100" r="8" fill="hsl(var(--otel-orange-hsl))" />
<circle cx="120" cy="100" r="5" fill="white" opacity="0.3" />
</g>

Expand All @@ -100,7 +100,7 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="130"
x2="135"
y2="130"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.3"
/>
Expand All @@ -109,23 +109,30 @@ export function ConfigurationIcon({ className }: { className?: string }) {
y1="130"
x2="80"
y2="130"
stroke="hsl(var(--primary-hsl))"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="3"
opacity="0.8"
/>
<circle cx="80" cy="130" r="8" fill="hsl(var(--primary-hsl))" />
<circle cx="80" cy="130" r="8" fill="hsl(var(--otel-orange-hsl))" />
<circle cx="80" cy="130" r="5" fill="white" opacity="0.3" />
</g>

{/* Gear icon accent in top-right */}
<g transform="translate(145, 55)">
<circle cx="0" cy="0" r="10" fill="none" stroke="hsl(var(--primary-hsl))" strokeWidth="2" />
<circle cx="0" cy="0" r="4" fill="hsl(var(--primary-hsl))" opacity="0.6" />
<circle
cx="0"
cy="0"
r="10"
fill="none"
stroke="hsl(var(--otel-orange-hsl))"
strokeWidth="2"
/>
<circle cx="0" cy="0" r="4" fill="hsl(var(--otel-orange-hsl))" opacity="0.6" />
{/* Gear teeth */}
<rect x="-2" y="-12" width="4" height="4" fill="hsl(var(--primary-hsl))" />
<rect x="-2" y="8" width="4" height="4" fill="hsl(var(--primary-hsl))" />
<rect x="-12" y="-2" width="4" height="4" fill="hsl(var(--primary-hsl))" />
<rect x="8" y="-2" width="4" height="4" fill="hsl(var(--primary-hsl))" />
<rect x="-2" y="-12" width="4" height="4" fill="hsl(var(--otel-orange-hsl))" />
<rect x="-2" y="8" width="4" height="4" fill="hsl(var(--otel-orange-hsl))" />
<rect x="-12" y="-2" width="4" height="4" fill="hsl(var(--otel-orange-hsl))" />
<rect x="8" y="-2" width="4" height="4" fill="hsl(var(--otel-orange-hsl))" />
</g>
</svg>
);
Expand Down
Loading
Loading