gitfoss | 6a58c841a634337b5095bbfba4d656db17e11223 | app/views/HomeView.tsx βˆ™ GitFOSS
.ts
TypeScript
(application/typescript)
// 3rd-party
import React from "react";
import type { ReactView } from "@ethicdevs/react-monolith";
// import styled from "styled-components";

// app
import type { CommonProps } from "../types";
import { AppRoute } from "../routes.defs";
import { Button } from "../components/Button.styled";
import { Card } from "../components/Card.styled";
import { Grid } from "../components/Grid";
import { Layout } from "../components/Layout";
import { PageWrapper } from "../components/PageWrapper";
import { buildRouteLink } from "../utils/shared";
import { breakpoints } from "../utils/style";

export interface HomeViewProps extends CommonProps {
  foo?: boolean;
}

// ReadMe tagline for consistency
const tagline =
  "GitFOSS is a small and simple, free and open-source Git Forge built w/ Node.JS, Fastify, Prisma and React!";

type FeatureCard = {
  title: string;
  description: string;
  icon?: string;
  image?: string;
};

const features: FeatureCard[] = [
  {
    title: "Free hosted or self-hosted",
    description:
      "Free hosting for everyone, or self-hosted deployments, both free.",
    icon: "🏠",
  },
  {
    title: "MIT Licensed Open Source",
    description: "Fully Open Source Software licensed under the MIT License.",
    icon: "βš–οΈ",
  },
  {
    title: "Modern tech stack",
    description:
      "Written with React, TypeScript, Prisma, and MVC architecture.",
    icon: "🧰",
  },
  {
    title: "Git repo browser",
    description: "Files, branches, and tags are browsable in the UI.",
    icon: "πŸ—‚οΈ",
  },
  {
    title: "PRs & merges",
    description: "Comment, review, merge, and delete source branches.",
    icon: "πŸ”€",
    image: "https://i.ibb.co/7JZNpNgT/pulls.png",
  },
  {
    title: "Fork repositories",
    description: "Fork repository workflow support for collaboration.",
    icon: "🍴",
    image: "https://i.ibb.co/xKYhZWyL/fork.png",
  },
  {
    title: "Tests & Coverage UI",
    description: "Browser-based tests and coverage details.",
    icon: "βœ…",
    image: "https://i.ibb.co/46jtQdd/tests.png",
  },
  {
    title: "Builds & CI",
    description: "Pipelines, actions, and a GitFOSS runner for CI.",
    icon: "πŸ—οΈ",
    image: "https://i.ibb.co/zhx89mzK/pipelines.png",
  },
  {
    title: "Deploy",
    description: "Pipelines and continuous deployment capabilities.",
    icon: "πŸš€",
    image: "https://i.ibb.co/nMnBX9gH/deploy.png",
  },
  {
    title: "API Reference",
    description: "Auto-generated API reference from repos and docs.",
    icon: "πŸ“š",
    image: "https://i.ibb.co/vxvrXPJR/api-red.png",
  },
  {
    title: "AI assistant",
    description:
      "Small no-context model leveraging repo docs, API reference, and docs to assist.",
    icon: "πŸ€–",
    image: "https://i.ibb.co/jv9m5pCR/ai-assist.png",
  },
  {
    title: "SSH Keys management",
    description: "SSH keys management for secure access to repos.",
    icon: "πŸ”‘",
    image: "https://i.ibb.co/LhBZB0Yz/ssh-keys.png",
  },
  {
    title: "User profiles",
    description:
      "Profiles with starred/followed repos, followers, and user readmes/links.",
    icon: "πŸ§‘β€πŸ’»",
    image: "https://i.ibb.co/9kSDjNnN/user-profile.png",
  },
];

// Helper to generate a richer description for "rest" features
function generateDescription(base: string, idx: number): string {
  const extras = [
    "This feature is integrated with a modern, scalable workflow.",
    "Discover how this can accelerate your team’s productivity.",
    "Includes settings and CLI for automation.",
  ];
  const extra = extras[idx % extras.length];
  return `${base} ${extra}`;
}

const HomeView: ReactView<HomeViewProps> = (props) => {
  const { commonProps } = props;

  const primary = features.slice(0, 4); // top 4 features in cards
  const rest = features.slice(4); // remaining features in sections

  return (
    <Layout {...commonProps}>
      <PageWrapper style={{ maxWidth: 960, margin: "0 auto" }}>
        {/* Hero Section */}
        <Grid.Row fluid style={{ minHeight: "72vh", alignItems: "center" }}>
          <Grid.Col
            fluid
            nowrap
            justifyContent={"center"}
            style={{
              marginTop: 80,
              paddingRight: 20,
              minWidth: 420,
            }}
          >
            <h1 style={{ fontSize: "3rem", margin: 0, lineHeight: 1.05 }}>
              GitFOSS
            </h1>
            <p style={{ fontSize: "1.15rem", color: "#555", maxWidth: 600 }}>
              {tagline}
            </p>
            <Grid.Row fluid gap={8} style={{ marginTop: 20 }}>
              <Button as="a" href={buildRouteLink(AppRoute.AUTH_REGISTER, {})}>
                Register
              </Button>
              <Button as="a" href={buildRouteLink(AppRoute.AUTH_LOGIN, {})}>
                Login
              </Button>
              <Button
                as="a"
                href={buildRouteLink(AppRoute.REPOSITORY_EXPLORE, {})}
              >
                Explore
              </Button>
            </Grid.Row>
          </Grid.Col>
          <img
            src="https://i.ibb.co/6cCs4VgG/image.png"
            alt="GitFOSS hero illustration"
            style={{
              width: "100%",
              maxWidth: 500,
              minWidth: 375,
              height: "auto",
              marginTop: 24,
              objectFit: "contain",
              borderRadius: 24,
            }}
          />
        </Grid.Row>

        {/* Primary features: 4 cards in a row, using Card component */}
        <Grid.Row fluid gap={16} style={{ padding: "10vh 0 20vh 0" }}>
          {primary.map((f, idx) => (
            <Grid.Col key={idx} fluid nowrap>
              <Card
                themeScheme={commonProps.themeScheme}
                style={{ minHeight: 238, minWidth: 210 }}
              >
                <div
                  style={{
                    display: "flex",
                    flexDirection: "column",
                    gap: 12,
                  }}
                >
                  <div
                    className="icon"
                    aria-label={f.title}
                    style={{ fontSize: 48 }}
                  >
                    {f.icon ?? "✨"}
                  </div>
                  <div
                    className="feature-title"
                    style={{ fontWeight: 700, fontSize: 20 }}
                  >
                    {f.title}
                  </div>
                  <div className="feature-desc" style={{ color: "#777777" }}>
                    {f.description}
                  </div>
                </div>
              </Card>
            </Grid.Col>
          ))}
        </Grid.Row>

        {/* Rest features: as sections with alternating image/text */}
        {rest.map((f, idx) => {
          const genDesc = generateDescription(f.description, idx);
          const isEven = idx % 2 === 0;
          const imageSrc = f.image ?? `/assets/feature-${idx + 4}.png`;

          return (
            <section
              key={idx}
              aria-label={`Feature: ${f.title}`}
              style={{ padding: "40px 0", minHeight: "80vh" }}
            >
              <style>{`
                .feature-section {
                  display: flex;
                  width: 100%;
                  min-height: 80vh;
                  flex-direction: row;
                  align-items: center;
                  gap: 48px;
                  flex-wrap: wrap;
                }
                .is-even {
                  flex-direction: row-reverse;
                }
                .is-odd {
                  flex-direction: row;
                }
                @media (max-width: ${breakpoints.sm}) {
                  .feature-section {
                    flex-direction: column;
                  }
                  .is-even,
                  .is-odd {
                    flex-direction: column;
                  }
                }
              `}</style>
              <div
                className={`feature-section ${isEven ? "is-even" : "is-odd"}`}
              >
                <div style={{ flex: 1, minWidth: 260 }}>
                  <img
                    src={imageSrc}
                    alt={`${f.title} illustration`}
                    style={{
                      width: "100%",
                      height: "auto",
                      borderRadius: 24,
                    }}
                  />
                </div>
                <div style={{ flex: 1, minWidth: 260 }}>
                  <h1 style={{ margin: 0, fontSize: 48 }}>{f.title}</h1>
                  <h3
                    className="feature-desc"
                    style={{
                      color: "#777777",
                      lineHeight: 1.4,
                      fontWeight: "normal",
                    }}
                  >
                    {genDesc}
                  </h3>
                  <div
                    className="cta"
                    style={{ display: "flex", gap: 8, marginTop: 16 }}
                  >
                    <Button
                      as="a"
                      href={buildRouteLink(AppRoute.AUTH_REGISTER, {})}
                    >
                      Register
                    </Button>
                    <Button
                      as="a"
                      href={buildRouteLink(AppRoute.AUTH_LOGIN, {})}
                    >
                      Login
                    </Button>
                  </div>
                </div>
              </div>
            </section>
          );
        })}

        {/* Contribute section outside loop */}
        <section
          aria-label="Contribute to GitFOSS"
          style={{
            padding: "48px 0",
            borderTop: "2px dashed #4e7b50",
            borderBottom: "2px dashed #4e7b50",
            width: "100%",
          }}
        >
          <Grid.Col
            fluid
            nowrap
            justifyContent={"center"}
            alignItems={"center"}
          >
            <h1
              style={{
                margin: "0 0 8px",
                maxWidth: 400,
                fontSize: 48,
                textAlign: "center",
              }}
            >
              Contribute to GitFOSS
            </h1>
            <h3
              style={{
                color: "#555",
                margin: "16px 0",
                maxWidth: 400,
                textAlign: "center",
                fontWeight: "normal",
              }}
            >
              Help grow GitFOSS by contributing code, docs, and governance. Your
              involvement keeps the project open, fast, and secure.
            </h3>
            <Button
              as="a"
              href="/ethicdevs/gitfoss"
              style={{ width: 300, height: 60, fontSize: 24, marginTop: 24 }}
            >
              Contribute Now
            </Button>
          </Grid.Col>
        </section>
      </PageWrapper>
    </Layout>
  );
};

HomeView.displayName = "HomeView";
export default HomeView;