🏡 index : ~doyle/chartered.git

import React = require('react');

import { useState, useEffect } from 'react';

import { Link } from "react-router-dom";
import { useAuth } from '../useAuth';
import Nav from "../sections/Nav";
import { Box, HouseDoor, Book, Building, PersonPlus } from 'react-bootstrap-icons';
import { useParams } from "react-router-dom";
import { authenticatedEndpoint } 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';

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

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

    useEffect(async () => {
        let res = await fetch(authenticatedEndpoint(auth, `crates/${crate}`));
        let json = await res.json();
        setCrateInfo(json);
    }, []);

    if (!crateInfo) {
        return (<div>Loading...</div>);
    }

    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: any }) {
    return <div className="grid" style={{ gridTemplateColumns: '1fr 1fr 1fr' }}>
        <div className="g-col-4 g-col-lg-1 d-flex align-items-center">
            <img src="http://placekitten.com/96/96" className="rounded-circle" />

            <div className="ms-2">
                <strong>Johnny Davidson</strong> <em>(that's you!)</em><br />
                Owner
            </div>
        </div>

        <div className="g-col-4 g-col-lg-1 d-flex align-items-center mt-2">
            <img src="http://placekitten.com/96/96" className="rounded-circle" />

            <div className="ms-2">
                <strong>Will Woodwood</strong><br />
                <select className="form-select form-select-sm" aria-label="Default select example">
                    <option value="1">Consumer</option>
                    <option value="2">Maintainer</option>
                    <option value="3">Owner</option>
                </select>
            </div>
        </div>

        <div className="g-col-4 g-col-lg-1 d-flex align-items-center mt-2">
            <img src="http://placekitten.com/96/96" className="rounded-circle" />

            <div className="ms-2">
                <strong>Ben Dover</strong><br />
                <select className="form-select form-select-sm" aria-label="Default select example">
                    <option value="1">Consumer</option>
                    <option value="2" selected>Maintainer</option>
                    <option value="3">Owner</option>
                </select>
            </div>
        </div>

        <div className="g-col-4 g-col-lg-1 d-flex align-items-center mt-2">
            <img src="http://placekitten.com/96/96" className="rounded-circle" />

            <div className="ms-2">
                <strong>Eline Dover</strong><br />
                <select className="form-select form-select-sm" aria-label="Default select example">
                    <option value="1">Consumer</option>
                    <option value="2">Maintainer</option>
                    <option value="3" selected>Owner</option>
                </select>
            </div>
        </div>

        <div className="g-col-4 g-col-lg-1 mt-2 d-flex align-items-center justify-content-center rounded-circle"
            style={{ width: '96px', height: '96px', background: '#DEDEDE', fontSize: '2rem' }}>
            <PersonPlus />
        </div>
    </div>;
}