🏡 index : ~doyle/chartered.git

import React = require('react');

import { useState, useEffect } from 'react';

import { useAuth } from '../useAuth';
import Nav from "../sections/Nav";
import Loading from './Loading';
import ErrorPage from './ErrorPage';
import { Box, HouseDoor, Book, Building, PersonPlus } from 'react-bootstrap-icons';
import { useParams } from "react-router-dom";
import { authenticatedEndpoint, useAuthenticatedRequest } from '../util';

import Prism from 'react-syntax-highlighter/dist/cjs/prism';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

type Tab = 'readme' | 'versions' | 'members';

interface CrateInfo {
    versions: CrateInfoVersion[],
}

interface CrateInfoVersion {
    vers: string,
    homepage: string | null,
    description: string | null,
    documentation: string | null,
    repository: string | null,
    deps: CrateInfoVersionDependency[],
}

interface CrateInfoVersionDependency {
    name: string,
    version_req: string,
}

export default function SingleCrate() {
    const auth = useAuth();
    const { crate } = useParams();

    const [currentTab, setCurrentTab] = useState<Tab>('readme');

    const { response: crateInfo, error } = useAuthenticatedRequest<CrateInfo>({
        auth,
        endpoint: `crates/${crate}`,
    });

    if (error) {
        return <ErrorPage message={error} />;
    } else if (!crateInfo) {
        return <Loading />;
    }

    const crateVersion = crateInfo.versions[crateInfo.versions.length - 1];

    return (
        <div className="text-white">
            <Nav />

            <div className="container mt-4 pb-4">
                <div className="row align-items-stretch">
                    <div className="col-md-6">
                        <div className="card border-0 shadow-sm text-black h-100">
                            <div className="card-body">
                                <div className="d-flex flex-row align-items-center">
                                    <div className="text-white circle bg-primary bg-gradient d-inline rounded-circle d-inline-flex justify-content-center align-items-center"
                                        style={{ width: '2rem', height: '2rem' }}>
                                        <Box />
                                    </div>
                                    <h1 className="text-primary d-inline px-2">{crate}</h1>
                                    <h2 className="text-secondary m-0">{crateVersion.vers}</h2>
                                </div>

                                <p className="m-0">{crateVersion.description}</p>
                            </div>
                        </div>
                    </div>

                    <div className="col-md-6">
                        <div className="card border-0 shadow-sm text-black h-100">
                            <div className="card-body">
                                <HouseDoor /> <a href={crateVersion.homepage}>{crateVersion.homepage}</a><br />
                                <Book /> <a href={crateVersion.documentation}>{crateVersion.documentation}</a><br />
                                <Building /> <a href={crateVersion.repository}>{crateVersion.repository}</a>
                            </div>
                        </div>
                    </div>
                </div>

                <div className="row my-4">
                    <div className="col-md-9">
                        <div className="card border-0 shadow-sm text-black">
                            <div className="card-header">
                                <ul className="nav nav-pills card-header-pills">
                                    <li className="nav-item">
                                        <a className={`nav-link ${currentTab == 'readme' ? 'bg-primary bg-gradient active' : ''}`} href="#"
                                            onClick={() => setCurrentTab('readme')}>
                                            Readme
                                        </a>
                                    </li>
                                    <li className="nav-item">
                                        <a className={`nav-link ${currentTab == 'versions' ? 'bg-primary bg-gradient active' : ''}`} href="#"
                                            onClick={() => setCurrentTab('versions')}>
                                            Versions
                                            <span className={`badge rounded-pill bg-danger ms-1`}>{crateInfo.versions.length}</span>
                                        </a>
                                    </li>
                                    <li className="nav-item">
                                        <a className={`nav-link ${currentTab == 'members' ? 'bg-primary bg-gradient active' : ''}`} href="#"
                                            onClick={() => setCurrentTab('members')}>
                                            Members
                                        </a>
                                    </li>
                                </ul>
                            </div>

                            <div className="card-body">
                                {currentTab == 'readme' ? <ReadMe crateInfo={crateVersion} /> : <></>}
                                {currentTab == 'versions' ? <>Versions</> : <></>}
                                {currentTab == 'members' ? <Members crateInfo={crateVersion} /> : <></>}
                            </div>
                        </div>
                    </div>

                    <div className="col-md-3">
                        <div className="card border-0 shadow-sm text-black">
                            <div className="card-body pb-0">
                                <h5 className="card-title">Dependencies</h5>
                            </div>

                            <ul className="list-group list-group-flush mb-2">
                                {crateVersion.deps.map(dep => (
                                    <li key={`${dep.name}-${dep.version_req}`} className="list-group-item">{dep.name} = "<strong>{dep.version_req}</strong>"</li>
                                ))}
                            </ul>
                        </div>

                        <div className="card border-0 shadow-sm text-black mt-4">
                            <div className="card-body pb-0">
                                <h5 className="card-title">Dependents</h5>
                            </div>

                            <ul className="list-group list-group-flush">
                                <li className="list-group-item">An item</li>
                                <li className="list-group-item">A second item</li>
                                <li className="list-group-item">A third item</li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

function ReadMe(props: { crateInfo: any }) {
    return (
        <ReactMarkdown children={props.crateInfo.readme} remarkPlugins={[remarkGfm]} components={{
            code({node, inline, className, children, ...props}) {
                const match = /language-(\w+)/.exec(className || '')
                return !inline && match ? (
                <Prism
                    children={String(children).replace(/\n$/, '')}
                    language={match[1]}
                    PreTag="pre"
                    {...props}
                />
                ) : (
                <code className={className} {...props}>
                    {children}
                </code>
                )
            }
        }} />
    );
}

function Members(props: { crateInfo: CrateInfoVersion }) {
    const x = ["John Paul", "David Davidson", "Andrew Smith"];

    return <div className="container-fluid g-0">
        <div className="table-responsive">
            <table className="table table-striped">
                <tbody>
                    {x.map(v =>
                        <tr key={v}>
                            <td className="align-middle fit">
                                <img src="http://placekitten.com/48/48" className="rounded-circle" />
                            </td>

                            <td className="align-middle">
                                <strong>{v}</strong><br />
                                <em>(that's you!)</em>
                            </td>

                            <td className="align-middle">
                                <div className="d-flex">
                                    <div>
                                        <div className="form-check">
                                            <input className="form-check-input" type="checkbox" value="" id="visible" />
                                            <label className="form-check-label" htmlFor="visible">
                                                Visible
                                            </label>
                                        </div>

                                        <div className="form-check">
                                            <input className="form-check-input" type="checkbox" value="" id="publish_version" />
                                            <label className="form-check-label" htmlFor="visible">
                                                Publish Version
                                            </label>
                                        </div>
                                    </div>

                                    <div className="ms-3">
                                        <div className="form-check">
                                            <input className="form-check-input" type="checkbox" value="" id="visible" />
                                            <label className="form-check-label" htmlFor="visible">
                                                Yank Version
                                            </label>
                                        </div>

                                        <div className="form-check">
                                            <input className="form-check-input" type="checkbox" value="" id="publish_version" />
                                            <label className="form-check-label" htmlFor="visible">
                                                Manage Users
                                            </label>
                                        </div>
                                    </div>
                                </div>
                            </td>
                        </tr>
                    )}

                    <tr>
                        <td className="align-middle fit">
                            <div
                                className="d-flex align-items-center justify-content-center rounded-circle"
                                style={{ width: '48px', height: '48px', background: '#DEDEDE', fontSize: '1rem' }}
                            >
                                <PersonPlus />
                            </div>
                        </td>

                        <td></td>

                        <td></td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>;
}