feat(home): add attractive home page
+ 364
- 27
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1778580625817,
+  "_generatedAtUnix": 1778587082588,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "assets": {

...
@@ -102,7 +102,7 @@
   },
   "views": {
     "HomeView": {
-      "hash": "71df46f8100afeaf8edf234ffb076740a2c8b735",
+      "hash": "e6217782009d142a7170240f5aff23b499d9cec2",
       "pathSource": "./app/views/HomeView.tsx"
     },
     "InternalErrorView": {

...
@@ -158,7 +158,7 @@
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestCreateView.tsx"
     },
     "RepositoryPullRequestDetailsView": {
-      "hash": "19899c1ff646728a0031e47e70e2aaecbbe16dde",
+      "hash": "62387edff49216a3c944101530f7904def0269dd",
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestDetailsView.tsx"
     },
     "RepositoryPullRequestsView": {

app/views/HomeView.tsx
@@ -1,48 +1,385 @@
 // 3rd-party
 import React from "react";
 import type { ReactView } from "@ethicdevs/react-monolith";
-import styled from "styled-components";
+// import styled from "styled-components";
 
 // app
 import type { CommonProps } from "../types";
 import { AppRoute } from "../routes.defs";
-import { ButtonAnchor, Layout, PageWrapper } from "../components";
+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 {} from "../components";
 import { buildRouteLink } from "../utils/shared";
 
 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/xp1bfGG/image.png",
+  },
+  {
+    title: "Fork repositories",
+    description: "Fork repository workflow support for collaboration.",
+    icon: "🍴",
+    image: "https://i.ibb.co/1Ghq4j73/image.png",
+  },
+  {
+    title: "Tests & Coverage UI",
+    description: "Browser-based tests and coverage details.",
+    icon: "βœ…",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "Builds & CI",
+    description: "Pipelines, actions, and a GitFOSS runner for CI.",
+    icon: "πŸ—οΈ",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "Deploy",
+    description: "Pipelines and continuous deployment capabilities.",
+    icon: "πŸš€",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "API Reference",
+    description: "Auto-generated API reference from repos and docs.",
+    icon: "πŸ“š",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "AI assistant",
+    description:
+      "Small no-context model leveraging repo docs, API reference, and docs to assist.",
+    icon: "πŸ€–",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "SSH Keys management",
+    description: "SSH keys management for secure access to repos.",
+    icon: "πŸ”‘",
+    image: "https://i.ibb.co/bgvkWwFh/image.png",
+  },
+  {
+    title: "User profiles",
+    description:
+      "Profiles with starred/followed repos, followers, and user readmes/links.",
+    icon: "πŸ§‘β€πŸ’»",
+    image: "https://i.ibb.co/bgvkWwFh/image.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>
-        <StyledButtonsRow>
-          <ButtonAnchor href={buildRouteLink(AppRoute.REPOSITORY_EXPLORE, {})}>
-            Explore
-          </ButtonAnchor>
-          <ButtonAnchor href={buildRouteLink(AppRoute.AUTH_REGISTER, {})}>
-            Register
-          </ButtonAnchor>
-          <ButtonAnchor href={buildRouteLink(AppRoute.AUTH_LOGIN, {})}>
-            Login
-          </ButtonAnchor>
-        </StyledButtonsRow>
+      <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={16} 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: 400,
+              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" }}
+            >
+              <div
+                style={{
+                  display: "flex",
+                  alignItems: "center",
+                  gap: 48,
+                  flexWrap: "wrap",
+                }}
+              >
+                {isEven && (
+                  <>
+                    <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: 16, marginTop: 16 }}
+                      >
+                        <Button
+                          as="a"
+                          href={buildRouteLink(AppRoute.AUTH_REGISTER, {})}
+                        >
+                          Register
+                        </Button>
+                        <Button
+                          as="a"
+                          href={buildRouteLink(AppRoute.AUTH_LOGIN, {})}
+                        >
+                          Login
+                        </Button>
+                      </div>
+                    </div>
+                  </>
+                )}
+                {!isEven && (
+                  <>
+                    <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: 16, 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 style={{ flex: 1, minWidth: 260 }}>
+                      <img
+                        src={imageSrc}
+                        alt={`${f.title} illustration`}
+                        style={{
+                          width: "100%",
+                          height: "auto",
+                          borderRadius: 24,
+                        }}
+                      />
+                    </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>
   );
 };
 
-const StyledButtonsRow = styled.div`
-  display: flex;
-  flex-flow: row wrap;
-  align-items: center;
-  justify-content: center;
-  gap: 16px;
-  margin-top: 24px;
-  width: 100%;
-`;
-
 HomeView.displayName = "HomeView";
 export default HomeView;